#![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(non_upper_case_globals)] #![allow(improper_ctypes)] #![allow(dead_code)] include!(concat!(env!("OUT_DIR"), "/yuv_ffi.rs")); #[cfg(not(target_os = "ios"))] use crate::PixelBuffer; use crate::{generate_call_macro, EncodeYuvFormat, TraitPixelBuffer}; use hbb_common::{bail, log, ResultType}; generate_call_macro!(call_yuv, false); #[cfg(not(target_os = "ios"))] pub fn convert_to_yuv( captured: &PixelBuffer, dst_fmt: EncodeYuvFormat, dst: &mut Vec, mid_data: &mut Vec, ) -> ResultType<()> { let src = captured.data(); let src_stride = captured.stride(); let src_pixfmt = captured.pixfmt(); let src_width = captured.width(); let src_height = captured.height(); if src_width > dst_fmt.w || src_height > dst_fmt.h { bail!( "src rect > dst rect: ({src_width}, {src_height}) > ({},{})", dst_fmt.w, dst_fmt.h ); } if src_pixfmt == crate::Pixfmt::BGRA || src_pixfmt == crate::Pixfmt::RGBA { // stride is calculated, not real, so we need to check it if src_stride[0] < src_width * 4 { bail!( "src_stride[0] < src_width * 4: {} < {}", src_stride[0], src_width * 4 ); } if src.len() < src_stride[0] * src_height { bail!( "wrong src len, {} < {} * {}", src.len(), src_stride[0], src_height ); } } let align = |x: usize| (x + 63) / 64 * 64; match (src_pixfmt, dst_fmt.pixfmt) { (crate::Pixfmt::BGRA, crate::Pixfmt::I420) | (crate::Pixfmt::RGBA, crate::Pixfmt::I420) => { let dst_stride_y = dst_fmt.stride[0]; let dst_stride_uv = dst_fmt.stride[1]; dst.resize(dst_fmt.h * dst_stride_y * 2, 0); // waste some memory to ensure memory safety let dst_y = dst.as_mut_ptr(); let dst_u = dst[dst_fmt.u..].as_mut_ptr(); let dst_v = dst[dst_fmt.v..].as_mut_ptr(); let f = if src_pixfmt == crate::Pixfmt::BGRA { ARGBToI420 } else { ABGRToI420 }; call_yuv!(f( src.as_ptr(), src_stride[0] as _, dst_y, dst_stride_y as _, dst_u, dst_stride_uv as _, dst_v, dst_stride_uv as _, src_width as _, src_height as _, )); } (crate::Pixfmt::BGRA, crate::Pixfmt::NV12) | (crate::Pixfmt::RGBA, crate::Pixfmt::NV12) => { let dst_stride_y = dst_fmt.stride[0]; let dst_stride_uv = dst_fmt.stride[1]; dst.resize( align(dst_fmt.h) * (align(dst_stride_y) + align(dst_stride_uv / 2)), 0, ); let dst_y = dst.as_mut_ptr(); let dst_uv = dst[dst_fmt.u..].as_mut_ptr(); let f = if src_pixfmt == crate::Pixfmt::BGRA { ARGBToNV12 } else { ABGRToNV12 }; call_yuv!(f( src.as_ptr(), src_stride[0] as _, dst_y, dst_stride_y as _, dst_uv, dst_stride_uv as _, src_width as _, src_height as _, )); } (crate::Pixfmt::BGRA, crate::Pixfmt::I444) | (crate::Pixfmt::RGBA, crate::Pixfmt::I444) => { let dst_stride_y = dst_fmt.stride[0]; let dst_stride_u = dst_fmt.stride[1]; let dst_stride_v = dst_fmt.stride[2]; dst.resize( align(dst_fmt.h) * (align(dst_stride_y) + align(dst_stride_u) + align(dst_stride_v)), 0, ); let dst_y = dst.as_mut_ptr(); let dst_u = dst[dst_fmt.u..].as_mut_ptr(); let dst_v = dst[dst_fmt.v..].as_mut_ptr(); let src = if src_pixfmt == crate::Pixfmt::BGRA { src } else { mid_data.resize(src.len(), 0); call_yuv!(ABGRToARGB( src.as_ptr(), src_stride[0] as _, mid_data.as_mut_ptr(), src_stride[0] as _, src_width as _, src_height as _, )); mid_data }; call_yuv!(ARGBToI444( src.as_ptr(), src_stride[0] as _, dst_y, dst_stride_y as _, dst_u, dst_stride_u as _, dst_v, dst_stride_v as _, src_width as _, src_height as _, )); } _ => { bail!( "convert not support, {src_pixfmt:?} -> {:?}", dst_fmt.pixfmt ); } } Ok(()) }