fix, mac hwcodec decoding align use dst_align
(#8215)
Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
parent
d4dda94e2a
commit
8919ea65e3
@ -13,186 +13,6 @@ use hbb_common::{bail, log, ResultType};
|
||||
|
||||
generate_call_macro!(call_yuv, false);
|
||||
|
||||
#[cfg(feature = "hwcodec")]
|
||||
pub mod hw {
|
||||
use super::*;
|
||||
use crate::ImageFormat;
|
||||
#[cfg(target_os = "windows")]
|
||||
use hwcodec::{ffmpeg::AVPixelFormat, ffmpeg_ram::ffmpeg_linesize_offset_length};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn hw_nv12_to(
|
||||
fmt: ImageFormat,
|
||||
width: usize,
|
||||
height: usize,
|
||||
src_y: &[u8],
|
||||
src_uv: &[u8],
|
||||
src_stride_y: usize,
|
||||
src_stride_uv: usize,
|
||||
dst: &mut Vec<u8>,
|
||||
i420: &mut Vec<u8>,
|
||||
align: usize,
|
||||
) -> ResultType<()> {
|
||||
let nv12_stride_y = src_stride_y;
|
||||
let nv12_stride_uv = src_stride_uv;
|
||||
if let Ok((linesize_i420, offset_i420, i420_len)) =
|
||||
ffmpeg_linesize_offset_length(AVPixelFormat::AV_PIX_FMT_YUV420P, width, height, align)
|
||||
{
|
||||
dst.resize(width * height * 4, 0);
|
||||
let i420_stride_y = linesize_i420[0];
|
||||
let i420_stride_u = linesize_i420[1];
|
||||
let i420_stride_v = linesize_i420[2];
|
||||
i420.resize(i420_len as _, 0);
|
||||
|
||||
let i420_offset_y = unsafe { i420.as_ptr().add(0) as _ };
|
||||
let i420_offset_u = unsafe { i420.as_ptr().add(offset_i420[0] as _) as _ };
|
||||
let i420_offset_v = unsafe { i420.as_ptr().add(offset_i420[1] as _) as _ };
|
||||
call_yuv!(NV12ToI420(
|
||||
src_y.as_ptr(),
|
||||
nv12_stride_y as _,
|
||||
src_uv.as_ptr(),
|
||||
nv12_stride_uv as _,
|
||||
i420_offset_y,
|
||||
i420_stride_y,
|
||||
i420_offset_u,
|
||||
i420_stride_u,
|
||||
i420_offset_v,
|
||||
i420_stride_v,
|
||||
width as _,
|
||||
height as _,
|
||||
));
|
||||
match fmt {
|
||||
ImageFormat::ARGB => {
|
||||
call_yuv!(I420ToARGB(
|
||||
i420_offset_y,
|
||||
i420_stride_y,
|
||||
i420_offset_u,
|
||||
i420_stride_u,
|
||||
i420_offset_v,
|
||||
i420_stride_v,
|
||||
dst.as_mut_ptr(),
|
||||
(width * 4) as _,
|
||||
width as _,
|
||||
height as _,
|
||||
));
|
||||
}
|
||||
ImageFormat::ABGR => {
|
||||
call_yuv!(I420ToABGR(
|
||||
i420_offset_y,
|
||||
i420_stride_y,
|
||||
i420_offset_u,
|
||||
i420_stride_u,
|
||||
i420_offset_v,
|
||||
i420_stride_v,
|
||||
dst.as_mut_ptr(),
|
||||
(width * 4) as _,
|
||||
width as _,
|
||||
height as _,
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
bail!("unsupported image format");
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
bail!("get linesize offset failed");
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn hw_nv12_to(
|
||||
fmt: ImageFormat,
|
||||
width: usize,
|
||||
height: usize,
|
||||
src_y: &[u8],
|
||||
src_uv: &[u8],
|
||||
src_stride_y: usize,
|
||||
src_stride_uv: usize,
|
||||
dst: &mut Vec<u8>,
|
||||
_i420: &mut Vec<u8>,
|
||||
_align: usize,
|
||||
) -> ResultType<()> {
|
||||
dst.resize(width * height * 4, 0);
|
||||
match fmt {
|
||||
ImageFormat::ARGB => {
|
||||
call_yuv!(NV12ToARGB(
|
||||
src_y.as_ptr(),
|
||||
src_stride_y as _,
|
||||
src_uv.as_ptr(),
|
||||
src_stride_uv as _,
|
||||
dst.as_mut_ptr(),
|
||||
(width * 4) as _,
|
||||
width as _,
|
||||
height as _,
|
||||
));
|
||||
}
|
||||
ImageFormat::ABGR => {
|
||||
call_yuv!(NV12ToABGR(
|
||||
src_y.as_ptr(),
|
||||
src_stride_y as _,
|
||||
src_uv.as_ptr(),
|
||||
src_stride_uv as _,
|
||||
dst.as_mut_ptr(),
|
||||
(width * 4) as _,
|
||||
width as _,
|
||||
height as _,
|
||||
));
|
||||
}
|
||||
_ => bail!("unsupported image format"),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn hw_i420_to(
|
||||
fmt: ImageFormat,
|
||||
width: usize,
|
||||
height: usize,
|
||||
src_y: &[u8],
|
||||
src_u: &[u8],
|
||||
src_v: &[u8],
|
||||
src_stride_y: usize,
|
||||
src_stride_u: usize,
|
||||
src_stride_v: usize,
|
||||
dst: &mut Vec<u8>,
|
||||
) -> ResultType<()> {
|
||||
let src_y = src_y.as_ptr();
|
||||
let src_u = src_u.as_ptr();
|
||||
let src_v = src_v.as_ptr();
|
||||
dst.resize(width * height * 4, 0);
|
||||
match fmt {
|
||||
ImageFormat::ARGB => {
|
||||
call_yuv!(I420ToARGB(
|
||||
src_y,
|
||||
src_stride_y as _,
|
||||
src_u,
|
||||
src_stride_u as _,
|
||||
src_v,
|
||||
src_stride_v as _,
|
||||
dst.as_mut_ptr(),
|
||||
(width * 4) as _,
|
||||
width as _,
|
||||
height as _,
|
||||
));
|
||||
}
|
||||
ImageFormat::ABGR => {
|
||||
call_yuv!(I420ToABGR(
|
||||
src_y,
|
||||
src_stride_y as _,
|
||||
src_u,
|
||||
src_stride_u as _,
|
||||
src_v,
|
||||
src_stride_v as _,
|
||||
dst.as_mut_ptr(),
|
||||
(width * 4) as _,
|
||||
width as _,
|
||||
height as _,
|
||||
));
|
||||
}
|
||||
_ => bail!("unsupported image format"),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
pub fn convert_to_yuv(
|
||||
captured: &PixelBuffer,
|
||||
|
@ -2,7 +2,8 @@ use crate::{
|
||||
codec::{
|
||||
base_bitrate, codec_thread_num, enable_hwcodec_option, EncoderApi, EncoderCfg, Quality as Q,
|
||||
},
|
||||
hw, CodecFormat, EncodeInput, ImageFormat, ImageRgb, Pixfmt, HW_STRIDE_ALIGN,
|
||||
convert::*,
|
||||
CodecFormat, EncodeInput, ImageFormat, ImageRgb, Pixfmt, HW_STRIDE_ALIGN,
|
||||
};
|
||||
use hbb_common::{
|
||||
anyhow::{anyhow, bail, Context},
|
||||
@ -23,7 +24,7 @@ use hwcodec::{
|
||||
ffmpeg_ram::{
|
||||
decode::{DecodeContext, DecodeFrame, Decoder},
|
||||
encode::{EncodeContext, EncodeFrame, Encoder},
|
||||
CodecInfo,
|
||||
ffmpeg_linesize_offset_length, CodecInfo,
|
||||
},
|
||||
};
|
||||
|
||||
@ -32,6 +33,8 @@ pub const DEFAULT_TIME_BASE: [i32; 2] = [1, 30];
|
||||
const DEFAULT_GOP: i32 = i32::MAX;
|
||||
const DEFAULT_HW_QUALITY: Quality = Quality_Default;
|
||||
|
||||
crate::generate_call_macro!(call_yuv, false);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HwRamEncoderConfig {
|
||||
pub name: String,
|
||||
@ -237,9 +240,9 @@ impl HwRamEncoder {
|
||||
}
|
||||
}
|
||||
|
||||
fn rate_control(config: &HwRamEncoderConfig) -> RateControl {
|
||||
fn rate_control(_config: &HwRamEncoderConfig) -> RateControl {
|
||||
#[cfg(target_os = "android")]
|
||||
if config.name.contains("mediacodec") {
|
||||
if _config.name.contains("mediacodec") {
|
||||
return RC_VBR;
|
||||
}
|
||||
RC_CBR
|
||||
@ -262,15 +265,15 @@ impl HwRamEncoder {
|
||||
quality * factor
|
||||
}
|
||||
|
||||
pub fn check_bitrate_range(config: &HwRamEncoderConfig, bitrate: u32) -> u32 {
|
||||
pub fn check_bitrate_range(_config: &HwRamEncoderConfig, bitrate: u32) -> u32 {
|
||||
#[cfg(target_os = "android")]
|
||||
if config.name.contains("mediacodec") {
|
||||
if _config.name.contains("mediacodec") {
|
||||
let info = crate::android::ffi::get_codec_info();
|
||||
if let Some(info) = info {
|
||||
if let Some(codec) = info
|
||||
.codecs
|
||||
.iter()
|
||||
.find(|c| Some(c.name.clone()) == config.mc_name && c.is_encoder)
|
||||
.find(|c| Some(c.name.clone()) == _config.mc_name && c.is_encoder)
|
||||
{
|
||||
if codec.max_bitrate > codec.min_bitrate {
|
||||
if bitrate > codec.max_bitrate {
|
||||
@ -368,54 +371,100 @@ impl HwRamDecoderImage<'_> {
|
||||
// rgb [in/out] fmt and stride must be set in ImageRgb
|
||||
pub fn to_fmt(&self, rgb: &mut ImageRgb, i420: &mut Vec<u8>) -> ResultType<()> {
|
||||
let frame = self.frame;
|
||||
rgb.w = frame.width as _;
|
||||
rgb.h = frame.height as _;
|
||||
// take dst_stride into account when you convert
|
||||
let dst_stride = rgb.stride();
|
||||
let width = frame.width;
|
||||
let height = frame.height;
|
||||
rgb.w = width as _;
|
||||
rgb.h = height as _;
|
||||
let dst_align = rgb.align();
|
||||
let bytes_per_row = (rgb.w * 4 + dst_align - 1) & !(dst_align - 1);
|
||||
rgb.raw.resize(rgb.h * bytes_per_row, 0);
|
||||
match frame.pixfmt {
|
||||
AVPixelFormat::AV_PIX_FMT_NV12 => hw::hw_nv12_to(
|
||||
rgb.fmt(),
|
||||
frame.width as _,
|
||||
frame.height as _,
|
||||
&frame.data[0],
|
||||
&frame.data[1],
|
||||
frame.linesize[0] as _,
|
||||
frame.linesize[1] as _,
|
||||
&mut rgb.raw as _,
|
||||
i420,
|
||||
HW_STRIDE_ALIGN,
|
||||
)?,
|
||||
AVPixelFormat::AV_PIX_FMT_NV12 => {
|
||||
// I420ToARGB is much faster than NV12ToARGB in tests on Windows
|
||||
if cfg!(windows) {
|
||||
let Ok((linesize_i420, offset_i420, len_i420)) = ffmpeg_linesize_offset_length(
|
||||
AVPixelFormat::AV_PIX_FMT_YUV420P,
|
||||
width as _,
|
||||
height as _,
|
||||
HW_STRIDE_ALIGN,
|
||||
) else {
|
||||
bail!("failed to get i420 linesize, offset, length");
|
||||
};
|
||||
i420.resize(len_i420 as _, 0);
|
||||
let i420_offset_y = unsafe { i420.as_ptr().add(0) as _ };
|
||||
let i420_offset_u = unsafe { i420.as_ptr().add(offset_i420[0] as _) as _ };
|
||||
let i420_offset_v = unsafe { i420.as_ptr().add(offset_i420[1] as _) as _ };
|
||||
call_yuv!(NV12ToI420(
|
||||
frame.data[0].as_ptr(),
|
||||
frame.linesize[0],
|
||||
frame.data[1].as_ptr(),
|
||||
frame.linesize[1],
|
||||
i420_offset_y,
|
||||
linesize_i420[0],
|
||||
i420_offset_u,
|
||||
linesize_i420[1],
|
||||
i420_offset_v,
|
||||
linesize_i420[2],
|
||||
width,
|
||||
height,
|
||||
));
|
||||
let f = match rgb.fmt() {
|
||||
ImageFormat::ARGB => I420ToARGB,
|
||||
ImageFormat::ABGR => I420ToABGR,
|
||||
_ => bail!("unsupported format: {:?} -> {:?}", frame.pixfmt, rgb.fmt()),
|
||||
};
|
||||
call_yuv!(f(
|
||||
i420_offset_y,
|
||||
linesize_i420[0],
|
||||
i420_offset_u,
|
||||
linesize_i420[1],
|
||||
i420_offset_v,
|
||||
linesize_i420[2],
|
||||
rgb.raw.as_mut_ptr(),
|
||||
bytes_per_row as _,
|
||||
width,
|
||||
height,
|
||||
));
|
||||
} else {
|
||||
let f = match rgb.fmt() {
|
||||
ImageFormat::ARGB => NV12ToARGB,
|
||||
ImageFormat::ABGR => NV12ToABGR,
|
||||
_ => bail!("unsupported format: {:?} -> {:?}", frame.pixfmt, rgb.fmt()),
|
||||
};
|
||||
call_yuv!(f(
|
||||
frame.data[0].as_ptr(),
|
||||
frame.linesize[0],
|
||||
frame.data[1].as_ptr(),
|
||||
frame.linesize[1],
|
||||
rgb.raw.as_mut_ptr(),
|
||||
bytes_per_row as _,
|
||||
width,
|
||||
height,
|
||||
));
|
||||
}
|
||||
}
|
||||
AVPixelFormat::AV_PIX_FMT_YUV420P => {
|
||||
hw::hw_i420_to(
|
||||
rgb.fmt(),
|
||||
frame.width as _,
|
||||
frame.height as _,
|
||||
&frame.data[0],
|
||||
&frame.data[1],
|
||||
&frame.data[2],
|
||||
frame.linesize[0] as _,
|
||||
frame.linesize[1] as _,
|
||||
frame.linesize[2] as _,
|
||||
&mut rgb.raw as _,
|
||||
)?;
|
||||
let f = match rgb.fmt() {
|
||||
ImageFormat::ARGB => I420ToARGB,
|
||||
ImageFormat::ABGR => I420ToABGR,
|
||||
_ => bail!("unsupported format: {:?} -> {:?}", frame.pixfmt, rgb.fmt()),
|
||||
};
|
||||
call_yuv!(f(
|
||||
frame.data[0].as_ptr(),
|
||||
frame.linesize[0],
|
||||
frame.data[1].as_ptr(),
|
||||
frame.linesize[1],
|
||||
frame.data[2].as_ptr(),
|
||||
frame.linesize[2],
|
||||
rgb.raw.as_mut_ptr(),
|
||||
bytes_per_row as _,
|
||||
width,
|
||||
height,
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn bgra(&self, bgra: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> {
|
||||
let mut rgb = ImageRgb::new(ImageFormat::ARGB, 1);
|
||||
self.to_fmt(&mut rgb, i420)?;
|
||||
*bgra = rgb.raw;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn rgba(&self, rgba: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> {
|
||||
let mut rgb = ImageRgb::new(ImageFormat::ABGR, 1);
|
||||
self.to_fmt(&mut rgb, i420)?;
|
||||
*rgba = rgb.raw;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
|
||||
|
@ -53,7 +53,7 @@ pub mod record;
|
||||
mod vpx;
|
||||
|
||||
#[repr(usize)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum ImageFormat {
|
||||
Raw,
|
||||
ABGR,
|
||||
@ -65,17 +65,17 @@ pub struct ImageRgb {
|
||||
pub w: usize,
|
||||
pub h: usize,
|
||||
pub fmt: ImageFormat,
|
||||
pub stride: usize,
|
||||
pub align: usize,
|
||||
}
|
||||
|
||||
impl ImageRgb {
|
||||
pub fn new(fmt: ImageFormat, stride: usize) -> Self {
|
||||
pub fn new(fmt: ImageFormat, align: usize) -> Self {
|
||||
Self {
|
||||
raw: Vec::new(),
|
||||
w: 0,
|
||||
h: 0,
|
||||
fmt,
|
||||
stride,
|
||||
align,
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,13 +85,13 @@ impl ImageRgb {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn stride(&self) -> usize {
|
||||
self.stride
|
||||
pub fn align(&self) -> usize {
|
||||
self.align
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_stride(&mut self, stride: usize) {
|
||||
self.stride = stride;
|
||||
pub fn set_align(&mut self, align: usize) {
|
||||
self.align = align;
|
||||
}
|
||||
}
|
||||
|
||||
@ -378,20 +378,20 @@ pub trait GoogleImage {
|
||||
fn stride(&self) -> Vec<i32>;
|
||||
fn planes(&self) -> Vec<*mut u8>;
|
||||
fn chroma(&self) -> Chroma;
|
||||
fn get_bytes_per_row(w: usize, fmt: ImageFormat, stride: usize) -> usize {
|
||||
fn get_bytes_per_row(w: usize, fmt: ImageFormat, align: usize) -> usize {
|
||||
let bytes_per_pixel = match fmt {
|
||||
ImageFormat::Raw => 3,
|
||||
ImageFormat::ARGB | ImageFormat::ABGR => 4,
|
||||
};
|
||||
// https://github.com/lemenkov/libyuv/blob/6900494d90ae095d44405cd4cc3f346971fa69c9/source/convert_argb.cc#L128
|
||||
// https://github.com/lemenkov/libyuv/blob/6900494d90ae095d44405cd4cc3f346971fa69c9/source/convert_argb.cc#L129
|
||||
(w * bytes_per_pixel + stride - 1) & !(stride - 1)
|
||||
(w * bytes_per_pixel + align - 1) & !(align - 1)
|
||||
}
|
||||
// rgb [in/out] fmt and stride must be set in ImageRgb
|
||||
fn to(&self, rgb: &mut ImageRgb) {
|
||||
rgb.w = self.width();
|
||||
rgb.h = self.height();
|
||||
let bytes_per_row = Self::get_bytes_per_row(rgb.w, rgb.fmt, rgb.stride());
|
||||
let bytes_per_row = Self::get_bytes_per_row(rgb.w, rgb.fmt, rgb.align());
|
||||
rgb.raw.resize(rgb.h * bytes_per_row, 0);
|
||||
let stride = self.stride();
|
||||
let planes = self.planes();
|
||||
|
@ -1052,7 +1052,7 @@ impl VideoHandler {
|
||||
log::info!("new video handler for display #{_display}, format: {format:?}, luid: {luid:?}");
|
||||
VideoHandler {
|
||||
decoder: Decoder::new(format, luid),
|
||||
rgb: ImageRgb::new(ImageFormat::ARGB, crate::get_dst_stride_rgba()),
|
||||
rgb: ImageRgb::new(ImageFormat::ARGB, crate::get_dst_align_rgba()),
|
||||
texture: std::ptr::null_mut(),
|
||||
recorder: Default::default(),
|
||||
record: false,
|
||||
@ -1105,7 +1105,7 @@ impl VideoHandler {
|
||||
/// Reset the decoder, change format if it is Some
|
||||
pub fn reset(&mut self, format: Option<CodecFormat>) {
|
||||
#[cfg(target_os = "macos")]
|
||||
self.rgb.set_stride(crate::get_dst_stride_rgba());
|
||||
self.rgb.set_align(crate::get_dst_align_rgba());
|
||||
let luid = Self::get_adapter_luid();
|
||||
let format = format.unwrap_or(self.decoder.format());
|
||||
self.decoder = Decoder::new(format, luid);
|
||||
|
@ -1617,7 +1617,7 @@ fn read_custom_client_advanced_settings(
|
||||
|
||||
#[inline]
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn get_dst_stride_rgba() -> usize {
|
||||
pub fn get_dst_align_rgba() -> usize {
|
||||
// https://developer.apple.com/forums/thread/712709
|
||||
// Memory alignment should be multiple of 64.
|
||||
if crate::ui_interface::use_texture_render() {
|
||||
@ -1629,7 +1629,7 @@ pub fn get_dst_stride_rgba() -> usize {
|
||||
|
||||
#[inline]
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub fn get_dst_stride_rgba() -> usize {
|
||||
pub fn get_dst_align_rgba() -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
|
@ -445,7 +445,7 @@ impl VideoRenderer {
|
||||
rgba.raw.len() as _,
|
||||
rgba.w as _,
|
||||
rgba.h as _,
|
||||
rgba.stride() as _,
|
||||
rgba.align() as _,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ use crate::{
|
||||
common::{is_keyboard_mode_supported, make_fd_to_json},
|
||||
flutter::{
|
||||
self, session_add, session_add_existed, session_start_, sessions, try_sync_peer_option,
|
||||
FlutterHandler,
|
||||
},
|
||||
input::*,
|
||||
ui_interface::{self, *},
|
||||
|
Loading…
x
Reference in New Issue
Block a user