use fullrange by default for yuv420p if supported (#6655)

1. Explicitly specify the color space as bt601
2. Use fullrange by default for yuv420p if supported
3. Use the pix_fmt space range format to identify codec capabilities, make i444 proto field deprecated, and cause the non-release version of 444 true color to fail.

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages
2023-12-11 22:31:01 +08:00
committed by GitHub
parent 2797a28c0d
commit 80afa98d66
15 changed files with 388 additions and 141 deletions

View File

@@ -7,8 +7,8 @@ use hbb_common::log;
use hbb_common::message_proto::{Chroma, EncodedVideoFrame, EncodedVideoFrames, VideoFrame};
use hbb_common::ResultType;
use crate::codec::{base_bitrate, codec_thread_num, EncoderApi, Quality};
use crate::{EncodeYuvFormat, GoogleImage, Pixfmt, STRIDE_ALIGN};
use crate::codec::{base_bitrate, codec_thread_num, EncoderApi, ExtraEncoderCfg, Quality};
use crate::{ColorRange, EncodeYuvFormat, GoogleImage, Pixfmt, STRIDE_ALIGN};
use super::vpx::{vp8e_enc_control_id::*, vpx_codec_err_t::*, *};
use crate::{generate_call_macro, generate_call_ptr_macro, Error, Result};
@@ -39,7 +39,7 @@ pub struct VpxEncoder {
width: usize,
height: usize,
id: VpxVideoCodecId,
i444: bool,
extra: ExtraEncoderCfg,
yuvfmt: EncodeYuvFormat,
}
@@ -48,7 +48,7 @@ pub struct VpxDecoder {
}
impl EncoderApi for VpxEncoder {
fn new(cfg: crate::codec::EncoderCfg, i444: bool) -> ResultType<Self>
fn new(cfg: crate::codec::EncoderCfg, extra: ExtraEncoderCfg) -> ResultType<Self>
where
Self: Sized,
{
@@ -102,11 +102,12 @@ impl EncoderApi for VpxEncoder {
}
// https://chromium.googlesource.com/webm/libvpx/+/refs/heads/main/vp9/common/vp9_enums.h#29
// https://chromium.googlesource.com/webm/libvpx/+/refs/heads/main/vp8/vp8_cx_iface.c#282
c.g_profile = if i444 && config.codec == VpxVideoCodecId::VP9 {
1
} else {
0
};
c.g_profile =
if extra.pixfmt == Pixfmt::YUV444P && config.codec == VpxVideoCodecId::VP9 {
1
} else {
0
};
/*
The VPX encoder supports two-pass encoding for rate control purposes.
@@ -164,6 +165,22 @@ impl EncoderApi for VpxEncoder {
VP9E_SET_TILE_COLUMNS as _,
4 as c_int
));
call_vpx!(vpx_codec_control_(
&mut ctx,
VP9E_SET_COLOR_RANGE as _,
if extra.range == ColorRange::Full {
vpx_color_range::VPX_CR_FULL_RANGE
} else {
vpx_color_range::VPX_CR_STUDIO_RANGE
}
));
call_vpx!(vpx_codec_control_(
&mut ctx,
VP9E_SET_COLOR_SPACE as _,
vpx_color_space::VPX_CS_BT_601
));
} else if config.codec == VpxVideoCodecId::VP8 {
// https://github.com/webmproject/libvpx/blob/972149cafeb71d6f08df89e91a0130d6a38c4b15/vpx/vp8cx.h#L172
// https://groups.google.com/a/webmproject.org/g/webm-discuss/c/DJhSrmfQ61M
@@ -175,8 +192,8 @@ impl EncoderApi for VpxEncoder {
width: config.width as _,
height: config.height as _,
id: config.codec,
i444,
yuvfmt: Self::get_yuvfmt(config.width, config.height, i444),
extra,
yuvfmt: Self::get_yuvfmt(config.width, config.height, &extra),
})
}
_ => Err(anyhow!("encoder type mismatch")),
@@ -230,16 +247,13 @@ impl EncoderApi for VpxEncoder {
impl VpxEncoder {
pub fn encode(&mut self, pts: i64, data: &[u8], stride_align: usize) -> Result<EncodeFrames> {
let bpp = if self.i444 { 24 } else { 12 };
let (fmt, bpp) = match self.extra.pixfmt {
Pixfmt::YUV444P => (vpx_img_fmt::VPX_IMG_FMT_I444, 24),
_ => (vpx_img_fmt::VPX_IMG_FMT_I420, 12),
};
if data.len() < self.width * self.height * bpp / 8 {
return Err(Error::FailedCall("len not enough".to_string()));
}
let fmt = if self.i444 {
vpx_img_fmt::VPX_IMG_FMT_I444
} else {
vpx_img_fmt::VPX_IMG_FMT_I420
};
let mut image = Default::default();
call_vpx_ptr!(vpx_img_wrap(
&mut image,
@@ -337,12 +351,11 @@ impl VpxEncoder {
(q_min, q_max)
}
fn get_yuvfmt(width: u32, height: u32, i444: bool) -> EncodeYuvFormat {
fn get_yuvfmt(width: u32, height: u32, extra: &ExtraEncoderCfg) -> EncodeYuvFormat {
let mut img = Default::default();
let fmt = if i444 {
vpx_img_fmt::VPX_IMG_FMT_I444
} else {
vpx_img_fmt::VPX_IMG_FMT_I420
let fmt = match extra.pixfmt {
Pixfmt::YUV444P => vpx_img_fmt::VPX_IMG_FMT_I444,
_ => vpx_img_fmt::VPX_IMG_FMT_I420,
};
unsafe {
vpx_img_wrap(
@@ -354,9 +367,9 @@ impl VpxEncoder {
0x1 as _,
);
}
let pixfmt = if i444 { Pixfmt::I444 } else { Pixfmt::I420 };
EncodeYuvFormat {
pixfmt,
pixfmt: extra.pixfmt,
range: extra.range,
w: img.w as _,
h: img.h as _,
stride: img.stride.map(|s| s as usize).to_vec(),
@@ -581,8 +594,22 @@ impl GoogleImage for Image {
fn chroma(&self) -> Chroma {
match self.inner().fmt {
vpx_img_fmt::VPX_IMG_FMT_I444 => Chroma::I444,
_ => Chroma::I420,
vpx_img_fmt::VPX_IMG_FMT_I444 => Chroma::C444,
_ => Chroma::C420,
}
}
fn pixfmt(&self) -> Pixfmt {
match self.inner().fmt {
vpx_img_fmt::VPX_IMG_FMT_I444 => Pixfmt::YUV444P,
_ => Pixfmt::YUV420P,
}
}
fn range(&self) -> ColorRange {
match self.inner().range {
vpx_color_range::VPX_CR_STUDIO_RANGE => ColorRange::Studio,
vpx_color_range::VPX_CR_FULL_RANGE => ColorRange::Full,
}
}
}