mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-03-28 12:32:17 +02:00
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user