mirror of https://git.ffmpeg.org/ffmpeg.git
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:
parent
f47d7a3b42
commit
efece4442f
|
@ -224,7 +224,7 @@ typedef struct VTEncContext {
|
||||||
int64_t require_sw;
|
int64_t require_sw;
|
||||||
|
|
||||||
bool flushing;
|
bool flushing;
|
||||||
bool has_b_frames;
|
int has_b_frames;
|
||||||
bool warned_color_range;
|
bool warned_color_range;
|
||||||
|
|
||||||
/* can't be bool type since AVOption will access it as int */
|
/* 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;
|
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,
|
static int vtenc_create_encoder(AVCodecContext *avctx,
|
||||||
CMVideoCodecType codec_type,
|
CMVideoCodecType codec_type,
|
||||||
CFStringRef profile_level,
|
CFStringRef profile_level,
|
||||||
|
@ -1025,7 +1031,9 @@ static int vtenc_create_encoder(AVCodecContext *avctx,
|
||||||
VTEncContext *vtctx = avctx->priv_data;
|
VTEncContext *vtctx = avctx->priv_data;
|
||||||
SInt32 bit_rate = avctx->bit_rate;
|
SInt32 bit_rate = avctx->bit_rate;
|
||||||
SInt32 max_rate = avctx->rc_max_rate;
|
SInt32 max_rate = avctx->rc_max_rate;
|
||||||
|
Float32 quality = avctx->global_quality / FF_QP2LAMBDA;
|
||||||
CFNumberRef bit_rate_num;
|
CFNumberRef bit_rate_num;
|
||||||
|
CFNumberRef quality_num;
|
||||||
CFNumberRef bytes_per_second;
|
CFNumberRef bytes_per_second;
|
||||||
CFNumberRef one_second;
|
CFNumberRef one_second;
|
||||||
CFArrayRef data_rate_limits;
|
CFArrayRef data_rate_limits;
|
||||||
|
@ -1056,15 +1064,33 @@ static int vtenc_create_encoder(AVCodecContext *avctx,
|
||||||
return AVERROR_EXTERNAL;
|
return AVERROR_EXTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bit_rate_num = CFNumberCreate(kCFAllocatorDefault,
|
if (avctx->flags & AV_CODEC_FLAG_QSCALE && !vtenc_qscale_enabled()) {
|
||||||
kCFNumberSInt32Type,
|
av_log(avctx, AV_LOG_ERROR, "Error: -q:v qscale not available for encoder. Use -b:v bitrate instead.\n");
|
||||||
&bit_rate);
|
return AVERROR_EXTERNAL;
|
||||||
if (!bit_rate_num) return AVERROR(ENOMEM);
|
}
|
||||||
|
|
||||||
status = VTSessionSetProperty(vtctx->session,
|
if (avctx->flags & AV_CODEC_FLAG_QSCALE) {
|
||||||
kVTCompressionPropertyKey_AverageBitRate,
|
quality = quality >= 100 ? 1.0 : quality / 100;
|
||||||
bit_rate_num);
|
quality_num = CFNumberCreate(kCFAllocatorDefault,
|
||||||
CFRelease(bit_rate_num);
|
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) {
|
if (status) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "Error setting bitrate property: %d\n", 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;
|
vtctx->codec_id = avctx->codec_id;
|
||||||
|
avctx->max_b_frames = 16;
|
||||||
|
|
||||||
if (vtctx->codec_id == AV_CODEC_ID_H264) {
|
if (vtctx->codec_id == AV_CODEC_ID_H264) {
|
||||||
vtctx->get_param_set_func = CMVideoFormatDescriptionGetH264ParameterSetAtIndex;
|
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;
|
vtctx->has_b_frames = avctx->max_b_frames > 0;
|
||||||
if(vtctx->has_b_frames && vtctx->profile == H264_PROF_BASELINE){
|
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");
|
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) {
|
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;
|
vtctx->get_param_set_func = compat_keys.CMVideoFormatDescriptionGetHEVCParameterSetAtIndex;
|
||||||
if (!vtctx->get_param_set_func) return AVERROR(EINVAL);
|
if (!vtctx->get_param_set_func) return AVERROR(EINVAL);
|
||||||
if (!get_vt_hevc_profile_level(avctx, &profile_level)) 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(
|
enc_info = CFDictionaryCreateMutable(
|
||||||
|
@ -1448,7 +1477,8 @@ static av_cold int vtenc_init(AVCodecContext *avctx)
|
||||||
|
|
||||||
if (!status && has_b_frames_cfbool) {
|
if (!status && has_b_frames_cfbool) {
|
||||||
//Some devices don't output B-frames for main profile, even if requested.
|
//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);
|
CFRelease(has_b_frames_cfbool);
|
||||||
}
|
}
|
||||||
avctx->has_b_frames = vtctx->has_b_frames;
|
avctx->has_b_frames = vtctx->has_b_frames;
|
||||||
|
@ -2356,7 +2386,7 @@ static av_cold int vtenc_frame(
|
||||||
|
|
||||||
if (vtctx->frame_ct_in == 0) {
|
if (vtctx->frame_ct_in == 0) {
|
||||||
vtctx->first_pts = frame->pts;
|
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;
|
vtctx->dts_delta = frame->pts - vtctx->first_pts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue