videotoolboxenc: enable constant quality with -q:v on Apple Silicon Macs and use b-frames für HEVC and H264 and b-pyramid for HEVC.

Signed-off-by: Simone Karin Lehmann <simone@lisanet.de>
Signed-off-by: Rick Kern <kernrj@gmail.com>
This commit is contained in:
Simone Karin Lehmann 2021-01-22 21:21:33 +01:00 committed by Rick Kern
parent f47d7a3b42
commit efece4442f
1 changed files with 42 additions and 12 deletions

View File

@ -224,7 +224,7 @@ typedef struct VTEncContext {
int64_t require_sw;
bool flushing;
bool has_b_frames;
int has_b_frames;
bool warned_color_range;
/* can't be bool type since AVOption will access it as int */
@ -1014,6 +1014,12 @@ static int get_cv_ycbcr_matrix(AVCodecContext *avctx, CFStringRef *matrix) {
return 0;
}
// constant quality only on Macs with Apple Silicon
static bool vtenc_qscale_enabled(void)
{
return TARGET_OS_OSX && TARGET_CPU_ARM64;
}
static int vtenc_create_encoder(AVCodecContext *avctx,
CMVideoCodecType codec_type,
CFStringRef profile_level,
@ -1025,7 +1031,9 @@ static int vtenc_create_encoder(AVCodecContext *avctx,
VTEncContext *vtctx = avctx->priv_data;
SInt32 bit_rate = avctx->bit_rate;
SInt32 max_rate = avctx->rc_max_rate;
Float32 quality = avctx->global_quality / FF_QP2LAMBDA;
CFNumberRef bit_rate_num;
CFNumberRef quality_num;
CFNumberRef bytes_per_second;
CFNumberRef one_second;
CFArrayRef data_rate_limits;
@ -1056,15 +1064,33 @@ static int vtenc_create_encoder(AVCodecContext *avctx,
return AVERROR_EXTERNAL;
}
bit_rate_num = CFNumberCreate(kCFAllocatorDefault,
kCFNumberSInt32Type,
&bit_rate);
if (!bit_rate_num) return AVERROR(ENOMEM);
if (avctx->flags & AV_CODEC_FLAG_QSCALE && !vtenc_qscale_enabled()) {
av_log(avctx, AV_LOG_ERROR, "Error: -q:v qscale not available for encoder. Use -b:v bitrate instead.\n");
return AVERROR_EXTERNAL;
}
status = VTSessionSetProperty(vtctx->session,
kVTCompressionPropertyKey_AverageBitRate,
bit_rate_num);
CFRelease(bit_rate_num);
if (avctx->flags & AV_CODEC_FLAG_QSCALE) {
quality = quality >= 100 ? 1.0 : quality / 100;
quality_num = CFNumberCreate(kCFAllocatorDefault,
kCFNumberFloat32Type,
&quality);
if (!quality_num) return AVERROR(ENOMEM);
status = VTSessionSetProperty(vtctx->session,
kVTCompressionPropertyKey_Quality,
quality_num);
CFRelease(quality_num);
} else {
bit_rate_num = CFNumberCreate(kCFAllocatorDefault,
kCFNumberSInt32Type,
&bit_rate);
if (!bit_rate_num) return AVERROR(ENOMEM);
status = VTSessionSetProperty(vtctx->session,
kVTCompressionPropertyKey_AverageBitRate,
bit_rate_num);
CFRelease(bit_rate_num);
}
if (status) {
av_log(avctx, AV_LOG_ERROR, "Error setting bitrate property: %d\n", status);
@ -1333,6 +1359,7 @@ static int vtenc_configure_encoder(AVCodecContext *avctx)
}
vtctx->codec_id = avctx->codec_id;
avctx->max_b_frames = 16;
if (vtctx->codec_id == AV_CODEC_ID_H264) {
vtctx->get_param_set_func = CMVideoFormatDescriptionGetH264ParameterSetAtIndex;
@ -1340,7 +1367,7 @@ static int vtenc_configure_encoder(AVCodecContext *avctx)
vtctx->has_b_frames = avctx->max_b_frames > 0;
if(vtctx->has_b_frames && vtctx->profile == H264_PROF_BASELINE){
av_log(avctx, AV_LOG_WARNING, "Cannot use B-frames with baseline profile. Output will not contain B-frames.\n");
vtctx->has_b_frames = false;
vtctx->has_b_frames = 0;
}
if (vtctx->entropy == VT_CABAC && vtctx->profile == H264_PROF_BASELINE) {
@ -1353,6 +1380,8 @@ static int vtenc_configure_encoder(AVCodecContext *avctx)
vtctx->get_param_set_func = compat_keys.CMVideoFormatDescriptionGetHEVCParameterSetAtIndex;
if (!vtctx->get_param_set_func) return AVERROR(EINVAL);
if (!get_vt_hevc_profile_level(avctx, &profile_level)) return AVERROR(EINVAL);
// HEVC has b-byramid
vtctx->has_b_frames = avctx->max_b_frames > 0 ? 2 : 0;
}
enc_info = CFDictionaryCreateMutable(
@ -1448,7 +1477,8 @@ static av_cold int vtenc_init(AVCodecContext *avctx)
if (!status && has_b_frames_cfbool) {
//Some devices don't output B-frames for main profile, even if requested.
vtctx->has_b_frames = CFBooleanGetValue(has_b_frames_cfbool);
// HEVC has b-pyramid
vtctx->has_b_frames = (CFBooleanGetValue(has_b_frames_cfbool) && avctx->codec_id == AV_CODEC_ID_HEVC) ? 2 : 1;
CFRelease(has_b_frames_cfbool);
}
avctx->has_b_frames = vtctx->has_b_frames;
@ -2356,7 +2386,7 @@ static av_cold int vtenc_frame(
if (vtctx->frame_ct_in == 0) {
vtctx->first_pts = frame->pts;
} else if(vtctx->frame_ct_in == 1 && vtctx->has_b_frames) {
} else if(vtctx->frame_ct_in == vtctx->has_b_frames) {
vtctx->dts_delta = frame->pts - vtctx->first_pts;
}