Message ID | 20210122202133.31519-1-simone@lisanet.de |
---|---|
State | New |
Headers | show |
Series | [FFmpeg-devel] 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. | expand |
Context | Check | Description |
---|---|---|
andriy/x86_make | success | Make finished |
andriy/x86_make_fate | success | Make fate finished |
andriy/PPC64_make | success | Make finished |
andriy/PPC64_make_fate | success | Make fate finished |
On Fri, Jan 22, 2021 at 3:28 PM <simone@lisanet.de> wrote: > From: Simone Karin Lehmann <simone@lisanet.de> > > Signed-off-by: Simone Karin Lehmann <simone@lisanet.de> > Applied > --- > libavcodec/videotoolboxenc.c | 54 ++++++++++++++++++++++++++++-------- > 1 file changed, 42 insertions(+), 12 deletions(-) > > diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c > index 400401550a..e8cbc9dd4d 100644 > --- a/libavcodec/videotoolboxenc.c > +++ b/libavcodec/videotoolboxenc.c > @@ -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; > } > > -- > 2.24.3 (Apple Git-128) > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Hi, Am 19.03.21 um 19:54 schrieb Rick Kern: > On Fri, Jan 22, 2021 at 3:28 PM <simone@lisanet.de> wrote: > >> From: Simone Karin Lehmann <simone@lisanet.de> >> >> Signed-off-by: Simone Karin Lehmann <simone@lisanet.de> >> > > Applied > >> --- >> libavcodec/videotoolboxenc.c | 54 ++++++++++++++++++++++++++++-------- >> 1 file changed, 42 insertions(+), 12 deletions(-) >> >> diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c >> index 400401550a..e8cbc9dd4d 100644 >> --- a/libavcodec/videotoolboxenc.c >> +++ b/libavcodec/videotoolboxenc.c >> @@ -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; >> +} >> + This breaks compilation for me on OSX 10.10.5 Yosemite. TARGET_OS_OSX is too new and undefined in TargetConditionals.h here. Can you test if return !TARGET_OS_OSX && TARGET_CPU_ARM64; does the same thing for you on newer OSX? (That's what I read what other projects do to avoid it) CC libavcodec/videotoolboxenc.o warning: unknown warning option '-Werror=partial-availability'; did you mean '-Werror=availability'? [-Wunknown-warning-option] warning: unknown warning option '-Wno-bool-operation'; did you mean '-Wno-bool-conversion'? [-Wunknown-warning-option] libavcodec/videotoolboxenc.c:1041:12: error: use of undeclared identifier 'TARGET_OS_OSX' return TARGET_OS_OSX && TARGET_CPU_ARM64; ^ 2 warnings and 1 error generated. make: *** [libavcodec/videotoolboxenc.o] Error 1 -Thilo >> 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; >> } >> >> -- >> 2.24.3 (Apple Git-128) >> >> _______________________________________________ >> ffmpeg-devel mailing list >> ffmpeg-devel@ffmpeg.org >> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel >> >> To unsubscribe, visit link above, or email >> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". >
diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c index 400401550a..e8cbc9dd4d 100644 --- a/libavcodec/videotoolboxenc.c +++ b/libavcodec/videotoolboxenc.c @@ -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; }