Skip to content

Commit

Permalink
fix, mac hwcodec decoding align use dst_align (rustdesk#8215)
Browse files Browse the repository at this point in the history
Signed-off-by: 21pages <[email protected]>
  • Loading branch information
21pages authored May 30, 2024
1 parent d4dda94 commit 8919ea6
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 246 deletions.
180 changes: 0 additions & 180 deletions libs/scrap/src/common/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
147 changes: 98 additions & 49 deletions libs/scrap/src/common/hwcodec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand All @@ -23,7 +24,7 @@ use hwcodec::{
ffmpeg_ram::{
decode::{DecodeContext, DecodeFrame, Decoder},
encode::{EncodeContext, EncodeFrame, Encoder},
CodecInfo,
ffmpeg_linesize_offset_length, CodecInfo,
},
};

Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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)]
Expand Down
Loading

0 comments on commit 8919ea6

Please sign in to comment.