use anyhow::{Result, bail};
use crate::encode::tuning::QsvRateControl;
use crate::frame::{PixelFormat, TransferFn};
use crate::qsv_ffi::{MfxFrameInfo, MfxInfoMfx, MfxVideoParam};
use super::ffi::{
MFX_CODEC_AV1, MFX_CODEC_AVC, MFX_CODEC_HEVC, MFX_FOURCC_NV12, MFX_FOURCC_P010,
MFX_PROFILE_AV1_MAIN, MFX_PROFILE_AVC_HIGH, MFX_PROFILE_HEVC_MAIN,
MFX_PROFILE_HEVC_MAIN10, MFX_TARGET_CHROMAFORMAT_YUV420_PLUS1,
};
pub(super) fn qsv_codec_ids(
codec: crate::frame::VideoCodec,
fmt: PixelFormat,
) -> (u32, u16) {
let ten_bit = fmt == PixelFormat::Yuv420p10le;
match codec {
crate::frame::VideoCodec::Av1 => (MFX_CODEC_AV1, MFX_PROFILE_AV1_MAIN),
crate::frame::VideoCodec::H264 => (MFX_CODEC_AVC, MFX_PROFILE_AVC_HIGH),
crate::frame::VideoCodec::H265 if ten_bit => {
(MFX_CODEC_HEVC, MFX_PROFILE_HEVC_MAIN10)
}
crate::frame::VideoCodec::H265 => (MFX_CODEC_HEVC, MFX_PROFILE_HEVC_MAIN),
}
}
pub(super) fn qsv_fourcc_for(fmt: PixelFormat) -> Result<u32> {
match fmt {
PixelFormat::Yuv420p => Ok(MFX_FOURCC_NV12),
PixelFormat::Yuv420p10le => Ok(MFX_FOURCC_P010),
other => bail!(
"QSV AV1 expects Yuv420p or Yuv420p10le, got {other:?}"
),
}
}
pub(super) const fn qsv_bit_depth_triple(fmt: PixelFormat) -> (u16, u16, u16) {
match fmt {
PixelFormat::Yuv420p10le => (10, 10, 1),
_ => (8, 8, 0),
}
}
const _: () = assert!({
let (l, c, s) = qsv_bit_depth_triple(PixelFormat::Yuv420p10le);
l == 10 && c == 10 && s == 1
});
const _: () = assert!({
let (l, c, s) = qsv_bit_depth_triple(PixelFormat::Yuv420p);
l == 8 && c == 8 && s == 0
});
const _: () = assert!(MFX_TARGET_CHROMAFORMAT_YUV420_PLUS1 == 2);
pub(super) fn transfer_to_h273(tf: TransferFn) -> u16 {
match tf {
TransferFn::Bt709 => 1,
TransferFn::Bt470Bg => 4,
TransferFn::Linear => 8,
TransferFn::St2084 => 16,
TransferFn::AribStdB67 => 18,
TransferFn::Unspecified => 1,
}
}
pub(super) fn clamp_target_usage(tp_target_usage: u16) -> u16 {
tp_target_usage.clamp(1, 7)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) struct RateSlots {
pub(super) slot0_qpi_or_delay: u16,
pub(super) slot1_qpp_or_kbps_or_icq: u16,
pub(super) slot2_qpb_or_maxkbps: u16,
}
pub(super) fn rate_slots_for_rc(
mode: QsvRateControl,
qp_i: u16,
qp_p: u16,
icq_quality: u16,
) -> RateSlots {
match mode {
QsvRateControl::Cqp => RateSlots {
slot0_qpi_or_delay: qp_i,
slot1_qpp_or_kbps_or_icq: qp_p,
slot2_qpb_or_maxkbps: qp_p, },
QsvRateControl::Icq => RateSlots {
slot0_qpi_or_delay: 0,
slot1_qpp_or_kbps_or_icq: icq_quality,
slot2_qpb_or_maxkbps: 0,
},
}
}
pub(super) fn zeroed_video_param() -> MfxVideoParam {
MfxVideoParam {
alloc_id: 0,
reserved: [0; 2],
reserved3: 0,
async_depth: 0,
mfx: MfxInfoMfx {
reserved: [0; 7],
low_power: 0,
brc_param_multiplier: 0,
frame_info: MfxFrameInfo {
reserved: [0; 4],
channel_id: 0,
bit_depth_luma: 0,
bit_depth_chroma: 0,
shift: 0,
frame_id: [0; 4],
fourcc: 0,
width: 0,
height: 0,
crop_x: 0,
crop_y: 0,
crop_w: 0,
crop_h: 0,
frame_rate_ext_n: 0,
frame_rate_ext_d: 0,
reserved3: 0,
aspect_ratio_w: 0,
aspect_ratio_h: 0,
pic_struct: 0,
chroma_format: 0,
reserved2: 0,
},
codec_id: 0,
codec_profile: 0,
codec_level: 0,
num_thread: 0,
target_usage: 0,
gop_pic_size: 0,
gop_ref_dist: 0,
gop_opt_flag: 0,
idr_interval: 0,
rate_control_method: 0,
qpi_or_delay: 0,
buffer_size_kb: 0,
qpp_or_kbps_or_icq: 0,
qpb_or_maxkbps: 0,
num_slice: 0,
num_ref_frame: 0,
encoded_order: 0,
},
_mfx_union_pad: [0; 32],
protected: 0,
io_pattern: 0,
ext_param: std::ptr::null_mut(),
num_ext_param: 0,
reserved2: 0,
}
}