|
|
|
@ -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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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_AverageBitRate, |
|
|
|
|
bit_rate_num); |
|
|
|
|
CFRelease(bit_rate_num); |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|