Merge pull request #3477 from fufesou/fix/macos_texture_stride_align

Fix/macos texture stride align
This commit is contained in:
RustDesk 2023-03-03 11:54:20 +08:00 committed by GitHub
commit e4af52d8a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 65 additions and 52 deletions

View File

@ -1228,10 +1228,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: texture_rgba_renderer name: texture_rgba_renderer
sha256: fbb09b2c6b4ce71261927f9e7e4ea339af3e2f3f2b175f6fb921de1c66ec848d sha256: ec8d124e4c1d7dfff854ae34e95d7d9d877b8f9d291c383c67686e4b15cf538e
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.0.8" version: "0.0.12"
timing: timing:
dependency: transitive dependency: transitive
description: description:

View File

@ -92,7 +92,7 @@ dependencies:
password_strength: ^0.2.0 password_strength: ^0.2.0
flutter_launcher_icons: ^0.11.0 flutter_launcher_icons: ^0.11.0
flutter_keyboard_visibility: ^5.4.0 flutter_keyboard_visibility: ^5.4.0
texture_rgba_renderer: ^0.0.8 texture_rgba_renderer: ^0.0.12
percent_indicator: ^4.2.2 percent_indicator: ^4.2.2
dev_dependencies: dev_dependencies:

View File

@ -18,7 +18,7 @@ use webm::mux;
use webm::mux::Track; use webm::mux::Track;
use scrap::vpxcodec as vpx_encode; use scrap::vpxcodec as vpx_encode;
use scrap::{TraitCapturer, Capturer, Display, STRIDE_ALIGN}; use scrap::{TraitCapturer, Capturer, Display, STRIDE};
const USAGE: &'static str = " const USAGE: &'static str = "
Simple WebM screen capture. Simple WebM screen capture.
@ -137,7 +137,7 @@ fn main() -> io::Result<()> {
if let Ok(frame) = c.frame(Duration::from_millis(0)) { if let Ok(frame) = c.frame(Duration::from_millis(0)) {
let ms = time.as_secs() * 1000 + time.subsec_millis() as u64; let ms = time.as_secs() * 1000 + time.subsec_millis() as u64;
for frame in vpx.encode(ms as i64, &frame, STRIDE_ALIGN).unwrap() { for frame in vpx.encode(ms as i64, &frame, STRIDE).unwrap() {
vt.add_frame(frame.data, frame.pts as u64 * 1_000_000, frame.key); vt.add_frame(frame.data, frame.pts as u64 * 1_000_000, frame.key);
} }
} }

View File

@ -306,17 +306,18 @@ impl Decoder {
pub fn handle_video_frame( pub fn handle_video_frame(
&mut self, &mut self,
frame: &video_frame::Union, frame: &video_frame::Union,
stride: usize,
fmt: ImageFormat, fmt: ImageFormat,
rgb: &mut Vec<u8>, rgb: &mut Vec<u8>,
) -> ResultType<bool> { ) -> ResultType<bool> {
match frame { match frame {
video_frame::Union::Vp9s(vp9s) => { video_frame::Union::Vp9s(vp9s) => {
Decoder::handle_vp9s_video_frame(&mut self.vpx, vp9s, fmt, rgb) Decoder::handle_vp9s_video_frame(&mut self.vpx, vp9s, stride, fmt, rgb)
} }
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
video_frame::Union::H264s(h264s) => { video_frame::Union::H264s(h264s) => {
if let Some(decoder) = &mut self.hw.h264 { if let Some(decoder) = &mut self.hw.h264 {
Decoder::handle_hw_video_frame(decoder, h264s, fmt, rgb, &mut self.i420) Decoder::handle_hw_video_frame(decoder, h264s, stride, fmt, rgb, &mut self.i420)
} else { } else {
Err(anyhow!("don't support h264!")) Err(anyhow!("don't support h264!"))
} }
@ -324,7 +325,7 @@ impl Decoder {
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
video_frame::Union::H265s(h265s) => { video_frame::Union::H265s(h265s) => {
if let Some(decoder) = &mut self.hw.h265 { if let Some(decoder) = &mut self.hw.h265 {
Decoder::handle_hw_video_frame(decoder, h265s, fmt, rgb, &mut self.i420) Decoder::handle_hw_video_frame(decoder, h265s, stride, fmt, rgb, &mut self.i420)
} else { } else {
Err(anyhow!("don't support h265!")) Err(anyhow!("don't support h265!"))
} }
@ -332,7 +333,7 @@ impl Decoder {
#[cfg(feature = "mediacodec")] #[cfg(feature = "mediacodec")]
video_frame::Union::H264s(h264s) => { video_frame::Union::H264s(h264s) => {
if let Some(decoder) = &mut self.media_codec.h264 { if let Some(decoder) = &mut self.media_codec.h264 {
Decoder::handle_mediacodec_video_frame(decoder, h264s, fmt, rgb) Decoder::handle_mediacodec_video_frame(decoder, h264s, stride, fmt, rgb)
} else { } else {
Err(anyhow!("don't support h264!")) Err(anyhow!("don't support h264!"))
} }
@ -340,7 +341,7 @@ impl Decoder {
#[cfg(feature = "mediacodec")] #[cfg(feature = "mediacodec")]
video_frame::Union::H265s(h265s) => { video_frame::Union::H265s(h265s) => {
if let Some(decoder) = &mut self.media_codec.h265 { if let Some(decoder) = &mut self.media_codec.h265 {
Decoder::handle_mediacodec_video_frame(decoder, h265s, fmt, rgb) Decoder::handle_mediacodec_video_frame(decoder, h265s, stride, fmt, rgb)
} else { } else {
Err(anyhow!("don't support h265!")) Err(anyhow!("don't support h265!"))
} }
@ -352,6 +353,7 @@ impl Decoder {
fn handle_vp9s_video_frame( fn handle_vp9s_video_frame(
decoder: &mut VpxDecoder, decoder: &mut VpxDecoder,
vp9s: &EncodedVideoFrames, vp9s: &EncodedVideoFrames,
stride: usize,
fmt: ImageFormat, fmt: ImageFormat,
rgb: &mut Vec<u8>, rgb: &mut Vec<u8>,
) -> ResultType<bool> { ) -> ResultType<bool> {
@ -369,7 +371,7 @@ impl Decoder {
if last_frame.is_null() { if last_frame.is_null() {
Ok(false) Ok(false)
} else { } else {
last_frame.to(fmt, 1, rgb); last_frame.to(fmt, stride, rgb);
Ok(true) Ok(true)
} }
} }
@ -378,6 +380,7 @@ impl Decoder {
fn handle_hw_video_frame( fn handle_hw_video_frame(
decoder: &mut HwDecoder, decoder: &mut HwDecoder,
frames: &EncodedVideoFrames, frames: &EncodedVideoFrames,
stride: usize,
fmt: ImageFormat, fmt: ImageFormat,
raw: &mut Vec<u8>, raw: &mut Vec<u8>,
i420: &mut Vec<u8>, i420: &mut Vec<u8>,
@ -386,7 +389,7 @@ impl Decoder {
for h264 in frames.frames.iter() { for h264 in frames.frames.iter() {
for image in decoder.decode(&h264.data)? { for image in decoder.decode(&h264.data)? {
// TODO: just process the last frame // TODO: just process the last frame
if image.to_fmt(fmt, raw, i420).is_ok() { if image.to_fmt(stride, fmt, raw, i420).is_ok() {
ret = true; ret = true;
} }
} }
@ -398,12 +401,13 @@ impl Decoder {
fn handle_mediacodec_video_frame( fn handle_mediacodec_video_frame(
decoder: &mut MediaCodecDecoder, decoder: &mut MediaCodecDecoder,
frames: &EncodedVideoFrames, frames: &EncodedVideoFrames,
stride: usize,
fmt: ImageFormat, fmt: ImageFormat,
raw: &mut Vec<u8>, raw: &mut Vec<u8>,
) -> ResultType<bool> { ) -> ResultType<bool> {
let mut ret = false; let mut ret = false;
for h264 in frames.frames.iter() { for h264 in frames.frames.iter() {
return decoder.decode(&h264.data, fmt, raw); return decoder.decode(&h264.data, stride, fmt, raw);
} }
return Ok(false); return Ok(false);
} }

View File

@ -144,7 +144,7 @@ extern "C" {
fn get_vpx_i420_stride( fn get_vpx_i420_stride(
width: usize, width: usize,
height: usize, height: usize,
stride_align: usize, stride: usize,
) -> (usize, usize, usize, usize, usize, usize) { ) -> (usize, usize, usize, usize, usize, usize) {
let mut img = Default::default(); let mut img = Default::default();
unsafe { unsafe {
@ -153,7 +153,7 @@ fn get_vpx_i420_stride(
vpx_img_fmt::VPX_IMG_FMT_I420, vpx_img_fmt::VPX_IMG_FMT_I420,
width as _, width as _,
height as _, height as _,
stride_align as _, stride as _,
0x1 as _, 0x1 as _,
); );
} }
@ -169,7 +169,7 @@ fn get_vpx_i420_stride(
pub fn i420_to_rgb(width: usize, height: usize, src: &[u8], dst: &mut Vec<u8>) { pub fn i420_to_rgb(width: usize, height: usize, src: &[u8], dst: &mut Vec<u8>) {
let (_, _, src_stride_y, src_stride_uv, u, v) = let (_, _, src_stride_y, src_stride_uv, u, v) =
get_vpx_i420_stride(width, height, super::STRIDE_ALIGN); get_vpx_i420_stride(width, height, super::STRIDE);
let src_y = src.as_ptr(); let src_y = src.as_ptr();
let src_u = src[u..].as_ptr(); let src_u = src[u..].as_ptr();
let src_v = src[v..].as_ptr(); let src_v = src[v..].as_ptr();
@ -192,7 +192,7 @@ pub fn i420_to_rgb(width: usize, height: usize, src: &[u8], dst: &mut Vec<u8>) {
pub fn bgra_to_i420(width: usize, height: usize, src: &[u8], dst: &mut Vec<u8>) { pub fn bgra_to_i420(width: usize, height: usize, src: &[u8], dst: &mut Vec<u8>) {
let (_, h, dst_stride_y, dst_stride_uv, u, v) = let (_, h, dst_stride_y, dst_stride_uv, u, v) =
get_vpx_i420_stride(width, height, super::STRIDE_ALIGN); get_vpx_i420_stride(width, height, super::STRIDE);
dst.resize(h * dst_stride_y * 2, 0); // waste some memory to ensure memory safety dst.resize(h * dst_stride_y * 2, 0); // waste some memory to ensure memory safety
let dst_y = dst.as_mut_ptr(); let dst_y = dst.as_mut_ptr();
let dst_u = dst[u..].as_mut_ptr(); let dst_u = dst[u..].as_mut_ptr();
@ -215,7 +215,7 @@ pub fn bgra_to_i420(width: usize, height: usize, src: &[u8], dst: &mut Vec<u8>)
pub fn rgba_to_i420(width: usize, height: usize, src: &[u8], dst: &mut Vec<u8>) { pub fn rgba_to_i420(width: usize, height: usize, src: &[u8], dst: &mut Vec<u8>) {
let (_, h, dst_stride_y, dst_stride_uv, u, v) = let (_, h, dst_stride_y, dst_stride_uv, u, v) =
get_vpx_i420_stride(width, height, super::STRIDE_ALIGN); get_vpx_i420_stride(width, height, super::STRIDE);
dst.resize(h * dst_stride_y * 2, 0); // waste some memory to ensure memory safety dst.resize(h * dst_stride_y * 2, 0); // waste some memory to ensure memory safety
let dst_y = dst.as_mut_ptr(); let dst_y = dst.as_mut_ptr();
let dst_u = dst[u..].as_mut_ptr(); let dst_u = dst[u..].as_mut_ptr();
@ -246,7 +246,7 @@ pub unsafe fn nv12_to_i420(
dst: &mut Vec<u8>, dst: &mut Vec<u8>,
) { ) {
let (_, h, dst_stride_y, dst_stride_uv, u, v) = let (_, h, dst_stride_y, dst_stride_uv, u, v) =
get_vpx_i420_stride(width, height, super::STRIDE_ALIGN); get_vpx_i420_stride(width, height, super::STRIDE);
dst.resize(h * dst_stride_y * 2, 0); // waste some memory to ensure memory safety dst.resize(h * dst_stride_y * 2, 0); // waste some memory to ensure memory safety
let dst_y = dst.as_mut_ptr(); let dst_y = dst.as_mut_ptr();
let dst_u = dst[u..].as_mut_ptr(); let dst_u = dst[u..].as_mut_ptr();

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
codec::{EncoderApi, EncoderCfg}, codec::{EncoderApi, EncoderCfg},
hw, ImageFormat, HW_STRIDE_ALIGN, hw, ImageFormat, HW_STRIDE,
}; };
use hbb_common::{ use hbb_common::{
anyhow::{anyhow, Context}, anyhow::{anyhow, Context},
@ -52,7 +52,7 @@ impl EncoderApi for HwEncoder {
width: config.width as _, width: config.width as _,
height: config.height as _, height: config.height as _,
pixfmt: DEFAULT_PIXFMT, pixfmt: DEFAULT_PIXFMT,
align: HW_STRIDE_ALIGN as _, align: HW_STRIDE as _,
bitrate: config.bitrate * 1000, bitrate: config.bitrate * 1000,
timebase: DEFAULT_TIME_BASE, timebase: DEFAULT_TIME_BASE,
gop: DEFAULT_GOP, gop: DEFAULT_GOP,
@ -236,7 +236,7 @@ pub struct HwDecoderImage<'a> {
} }
impl HwDecoderImage<'_> { impl HwDecoderImage<'_> {
pub fn to_fmt(&self, fmt: ImageFormat, fmt_data: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> { pub fn to_fmt(&self, stride: usize, fmt: ImageFormat, fmt_data: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> {
let frame = self.frame; let frame = self.frame;
match frame.pixfmt { match frame.pixfmt {
AVPixelFormat::AV_PIX_FMT_NV12 => hw::hw_nv12_to( AVPixelFormat::AV_PIX_FMT_NV12 => hw::hw_nv12_to(
@ -249,7 +249,7 @@ impl HwDecoderImage<'_> {
frame.linesize[1] as _, frame.linesize[1] as _,
fmt_data, fmt_data,
i420, i420,
HW_STRIDE_ALIGN, HW_STRIDE,
), ),
AVPixelFormat::AV_PIX_FMT_YUV420P => { AVPixelFormat::AV_PIX_FMT_YUV420P => {
hw::hw_i420_to( hw::hw_i420_to(
@ -269,12 +269,12 @@ impl HwDecoderImage<'_> {
} }
} }
pub fn bgra(&self, bgra: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> { pub fn bgra(&self, stride: usize, bgra: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> {
self.to_fmt(ImageFormat::ARGB, bgra, i420) self.to_fmt(stride, ImageFormat::ARGB, bgra, i420)
} }
pub fn rgba(&self, rgba: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> { pub fn rgba(&self, stride: usize, rgba: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> {
self.to_fmt(ImageFormat::ABGR, rgba, i420) self.to_fmt(stride, ImageFormat::ABGR, rgba, i420)
} }
} }
@ -296,7 +296,7 @@ pub fn check_config() {
width: 1920, width: 1920,
height: 1080, height: 1080,
pixfmt: DEFAULT_PIXFMT, pixfmt: DEFAULT_PIXFMT,
align: HW_STRIDE_ALIGN as _, align: HW_STRIDE as _,
bitrate: 0, bitrate: 0,
timebase: DEFAULT_TIME_BASE, timebase: DEFAULT_TIME_BASE,
gop: DEFAULT_GOP, gop: DEFAULT_GOP,

View File

@ -50,7 +50,8 @@ impl MediaCodecDecoder {
MediaCodecDecoders { h264, h265 } MediaCodecDecoders { h264, h265 }
} }
pub fn decode(&mut self, data: &[u8], fmt: ImageFormat, raw: &mut Vec<u8>) -> ResultType<bool> { // to-do: apply stride to raw output data
pub fn decode(&mut self, data: &[u8], stride: usize, fmt: ImageFormat, raw: &mut Vec<u8>) -> ResultType<bool> {
match self.dequeue_input_buffer(Duration::from_millis(10))? { match self.dequeue_input_buffer(Duration::from_millis(10))? {
Some(mut input_buffer) => { Some(mut input_buffer) => {
let mut buf = input_buffer.buffer_mut(); let mut buf = input_buffer.buffer_mut();

View File

@ -37,8 +37,8 @@ pub mod hwcodec;
pub mod mediacodec; pub mod mediacodec;
pub mod vpxcodec; pub mod vpxcodec;
pub use self::convert::*; pub use self::convert::*;
pub const STRIDE_ALIGN: usize = 64; // commonly used in libvpx vpx_img_alloc caller pub const STRIDE: usize = 64; // commonly used in libvpx vpx_img_alloc caller
pub const HW_STRIDE_ALIGN: usize = 0; // recommended by av_frame_get_buffer pub const HW_STRIDE: usize = 0; // recommended by av_frame_get_buffer
pub mod record; pub mod record;
mod vpx; mod vpx;

View File

@ -6,7 +6,7 @@ use hbb_common::anyhow::{anyhow, Context};
use hbb_common::message_proto::{EncodedVideoFrame, EncodedVideoFrames, Message, VideoFrame}; use hbb_common::message_proto::{EncodedVideoFrame, EncodedVideoFrames, Message, VideoFrame};
use hbb_common::{get_time, ResultType}; use hbb_common::{get_time, ResultType};
use crate::STRIDE_ALIGN; use crate::STRIDE;
use crate::{codec::EncoderApi, ImageFormat}; use crate::{codec::EncoderApi, ImageFormat};
use super::vpx::{vp8e_enc_control_id::*, vpx_codec_err_t::*, *}; use super::vpx::{vp8e_enc_control_id::*, vpx_codec_err_t::*, *};
@ -202,7 +202,7 @@ impl EncoderApi for VpxEncoder {
fn encode_to_message(&mut self, frame: &[u8], ms: i64) -> ResultType<Message> { fn encode_to_message(&mut self, frame: &[u8], ms: i64) -> ResultType<Message> {
let mut frames = Vec::new(); let mut frames = Vec::new();
for ref frame in self for ref frame in self
.encode(ms, frame, STRIDE_ALIGN) .encode(ms, frame, STRIDE)
.with_context(|| "Failed to encode")? .with_context(|| "Failed to encode")?
{ {
frames.push(VpxEncoder::create_frame(frame)); frames.push(VpxEncoder::create_frame(frame));
@ -232,7 +232,7 @@ impl EncoderApi for VpxEncoder {
} }
impl VpxEncoder { impl VpxEncoder {
pub fn encode(&mut self, pts: i64, data: &[u8], stride_align: usize) -> Result<EncodeFrames> { pub fn encode(&mut self, pts: i64, data: &[u8], stride: usize) -> Result<EncodeFrames> {
if 2 * data.len() < 3 * self.width * self.height { if 2 * data.len() < 3 * self.width * self.height {
return Err(Error::FailedCall("len not enough".to_string())); return Err(Error::FailedCall("len not enough".to_string()));
} }
@ -243,7 +243,7 @@ impl VpxEncoder {
vpx_img_fmt::VPX_IMG_FMT_I420, vpx_img_fmt::VPX_IMG_FMT_I420,
self.width as _, self.width as _,
self.height as _, self.height as _,
stride_align as _, stride as _,
data.as_ptr() as _, data.as_ptr() as _,
)); ));
@ -539,15 +539,17 @@ impl Image {
self.inner().stride[iplane] self.inner().stride[iplane]
} }
pub fn to(&self, fmt: ImageFormat, stride_align: usize, dst: &mut Vec<u8>) { pub fn to(&self, fmt: ImageFormat, stride: usize, dst: &mut Vec<u8>) {
let h = self.height(); let h = self.height();
let mut w = self.width(); let w = self.width();
let bps = match fmt { let bytes_per_pixel = match fmt {
ImageFormat::Raw => 3, ImageFormat::Raw => 3,
ImageFormat::ARGB | ImageFormat::ABGR => 4, ImageFormat::ARGB | ImageFormat::ABGR => 4,
}; };
w = (w + stride_align - 1) & !(stride_align - 1); // https://github.com/lemenkov/libyuv/blob/6900494d90ae095d44405cd4cc3f346971fa69c9/source/convert_argb.cc#L128
dst.resize(h * w * bps, 0); // https://github.com/lemenkov/libyuv/blob/6900494d90ae095d44405cd4cc3f346971fa69c9/source/convert_argb.cc#L129
let bytes_per_row = (w * bytes_per_pixel + stride - 1) & !(stride - 1);
dst.resize(h * bytes_per_row, 0);
let img = self.inner(); let img = self.inner();
unsafe { unsafe {
match fmt { match fmt {
@ -560,7 +562,7 @@ impl Image {
img.planes[2], img.planes[2],
img.stride[2], img.stride[2],
dst.as_mut_ptr(), dst.as_mut_ptr(),
(w * bps) as _, bytes_per_row as _,
self.width() as _, self.width() as _,
self.height() as _, self.height() as _,
); );
@ -574,7 +576,7 @@ impl Image {
img.planes[2], img.planes[2],
img.stride[2], img.stride[2],
dst.as_mut_ptr(), dst.as_mut_ptr(),
(w * bps) as _, bytes_per_row as _,
self.width() as _, self.width() as _,
self.height() as _, self.height() as _,
); );
@ -588,7 +590,7 @@ impl Image {
img.planes[2], img.planes[2],
img.stride[2], img.stride[2],
dst.as_mut_ptr(), dst.as_mut_ptr(),
(w * bps) as _, bytes_per_row as _,
self.width() as _, self.width() as _,
self.height() as _, self.height() as _,
); );

View File

@ -49,7 +49,7 @@ use scrap::{
}; };
use crate::{ use crate::{
common::{self, is_keyboard_mode_supported}, common::{self, is_keyboard_mode_supported, DST_STRIDE_RGBA},
server::video_service::{SCRAP_X11_REF_URL, SCRAP_X11_REQUIRED}, server::video_service::{SCRAP_X11_REF_URL, SCRAP_X11_REQUIRED},
}; };
@ -944,12 +944,7 @@ impl VideoHandler {
} }
match &vf.union { match &vf.union {
Some(frame) => { Some(frame) => {
// windows && flutter_texture_render, fmt is ImageFormat::ABGR let res = self.decoder.handle_video_frame(frame, DST_STRIDE_RGBA, ImageFormat::ARGB, &mut self.rgb);
#[cfg(all(target_os = "windows", feature = "flutter_texture_render"))]
let fmt = ImageFormat::ABGR;
#[cfg(not(all(target_os = "windows", feature = "flutter_texture_render")))]
let fmt = ImageFormat::ARGB;
let res = self.decoder.handle_video_frame(frame, fmt, &mut self.rgb);
if self.record { if self.record {
self.recorder self.recorder
.lock() .lock()

View File

@ -39,6 +39,13 @@ pub const CLIPBOARD_INTERVAL: u64 = 333;
pub const SYNC_PEER_INFO_DISPLAYS: i32 = 1; pub const SYNC_PEER_INFO_DISPLAYS: i32 = 1;
#[cfg(all(target_os = "macos", feature = "flutter_texture_render"))]
// https://developer.apple.com/forums/thread/712709
// Memory alignment should be multiple of 64.
pub const DST_STRIDE_RGBA: usize = 64;
#[cfg(not(all(target_os = "macos", feature = "flutter_texture_render")))]
pub const DST_STRIDE_RGBA: usize = 1;
// the executable name of the portable version // the executable name of the portable version
pub const PORTABLE_APPNAME_RUNTIME_ENV_KEY: &str = "RUSTDESK_APPNAME"; pub const PORTABLE_APPNAME_RUNTIME_ENV_KEY: &str = "RUSTDESK_APPNAME";

View File

@ -154,7 +154,7 @@ pub struct FlutterHandler {
#[cfg(feature = "flutter_texture_render")] #[cfg(feature = "flutter_texture_render")]
pub type FlutterRgbaRendererPluginOnRgba = pub type FlutterRgbaRendererPluginOnRgba =
unsafe extern "C" fn(texture_rgba: *mut c_void, buffer: *const u8, width: c_int, height: c_int); unsafe extern "C" fn(texture_rgba: *mut c_void, buffer: *const u8, len: c_int, width: c_int, height: c_int, stride: c_int);
// Video Texture Renderer in Flutter // Video Texture Renderer in Flutter
#[cfg(feature = "flutter_texture_render")] #[cfg(feature = "flutter_texture_render")]
@ -206,7 +206,9 @@ impl VideoRenderer {
self.width = width; self.width = width;
self.height = height; self.height = height;
self.data_len = if width > 0 && height > 0 { self.data_len = if width > 0 && height > 0 {
(width * height * 4) as usize let sa1 = crate::common::DST_STRIDE_RGBA - 1;
let row_bytes = (width as usize * 4 + sa1) & !sa1;
row_bytes * height as usize
} else { } else {
0 0
}; };
@ -221,8 +223,10 @@ impl VideoRenderer {
func( func(
self.ptr as _, self.ptr as _,
rgba.as_ptr() as _, rgba.as_ptr() as _,
rgba.len() as _,
self.width as _, self.width as _,
self.height as _, self.height as _,
crate::common::DST_STRIDE_RGBA as _,
) )
}; };
} }