diff --git a/media/ffvpx/libavcodec/libaomenc.c b/media/ffvpx/libavcodec/libaomenc.c index d660afab4ecc2..b09a31bb8631f 100644 --- a/media/ffvpx/libavcodec/libaomenc.c +++ b/media/ffvpx/libavcodec/libaomenc.c @@ -25,16 +25,17 @@ #include #define AOM_DISABLE_CTRL_TYPECHECKS 1 #include #include #include "libavutil/avassert.h" +#include "libavutil/avstring.h" #include "libavutil/base64.h" #include "libavutil/common.h" #include "libavutil/cpu.h" #include "libavutil/imgutils.h" #include "libavutil/mathematics.h" #include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -130,16 +131,17 @@ typedef struct AOMEncoderContext { int enable_masked_comp; int enable_obmc; int enable_onesided_comp; int enable_reduced_reference_set; int enable_smooth_interintra; int enable_diff_wtd_comp; int enable_dist_wtd_comp; int enable_dual_filter; + AVDictionary *svc_parameters; AVDictionary *aom_params; } AOMContext; static const char *const ctlidstr[] = { [AOME_SET_CPUUSED] = "AOME_SET_CPUUSED", [AOME_SET_CQ_LEVEL] = "AOME_SET_CQ_LEVEL", [AOME_SET_ENABLEAUTOALTREF] = "AOME_SET_ENABLEAUTOALTREF", [AOME_SET_ARNR_MAXFRAMES] = "AOME_SET_ARNR_MAXFRAMES", @@ -210,16 +212,17 @@ static const char *const ctlidstr[] = { #endif #ifdef AOM_CTRL_AV1E_GET_SEQ_LEVEL_IDX [AV1E_GET_SEQ_LEVEL_IDX] = "AV1E_GET_SEQ_LEVEL_IDX", #endif #ifdef AOM_CTRL_AV1E_GET_TARGET_SEQ_LEVEL_IDX [AV1E_GET_TARGET_SEQ_LEVEL_IDX] = "AV1E_GET_TARGET_SEQ_LEVEL_IDX", #endif [AV1_GET_NEW_FRAME_IMAGE] = "AV1_GET_NEW_FRAME_IMAGE", + [AV1E_SET_SVC_PARAMS] = "AV1E_SET_SVC_PARAMS", }; static av_cold void log_encoder_error(AVCodecContext *avctx, const char *desc) { AOMContext *ctx = avctx->priv_data; const char *error = aom_codec_error(&ctx->encoder); const char *detail = aom_codec_error_detail(&ctx->encoder); @@ -391,16 +394,41 @@ static av_cold int codecctl_imgp(AVCodecContext *avctx, ctlidstr[id]); log_encoder_error(avctx, buf); return AVERROR(EINVAL); } return 0; } +static av_cold int codecctl_svcp(AVCodecContext *avctx, +#ifdef UENUM1BYTE + aome_enc_control_id id, +#else + enum aome_enc_control_id id, +#endif + aom_svc_params_t *svc_params) +{ + AOMContext *ctx = avctx->priv_data; + char buf[80]; + int res; + + snprintf(buf, sizeof(buf), "%s:", ctlidstr[id]); + + res = aom_codec_control(&ctx->encoder, id, svc_params); + if (res != AOM_CODEC_OK) { + snprintf(buf, sizeof(buf), "Failed to get %s codec control", + ctlidstr[id]); + log_encoder_error(avctx, buf); + return AVERROR(EINVAL); + } + + return 0; +} + static av_cold int aom_free(AVCodecContext *avctx) { AOMContext *ctx = avctx->priv_data; #if defined(AOM_CTRL_AV1E_GET_NUM_OPERATING_POINTS) && \ defined(AOM_CTRL_AV1E_GET_SEQ_LEVEL_IDX) && \ defined(AOM_CTRL_AV1E_GET_TARGET_SEQ_LEVEL_IDX) if (ctx->encoder.iface && !(avctx->flags & AV_CODEC_FLAG_PASS1)) { @@ -680,16 +708,28 @@ static int choose_tiling(AVCodecContext *avctx, enccfg->tile_heights[i] = tile_size + (i < rounding / 2 || i > ctx->tile_rows - 1 - (rounding + 1) / 2); } return 0; } +static void aom_svc_parse_int_array(int *dest, char *value, int max_entries) +{ + int dest_idx = 0; + char *saveptr = NULL; + char *token = av_strtok(value, ",", &saveptr); + + while (token && dest_idx < max_entries) { + dest[dest_idx++] = strtoul(token, NULL, 10); + token = av_strtok(NULL, ",", &saveptr); + } +} + static av_cold int aom_init(AVCodecContext *avctx, const struct aom_codec_iface *iface) { AOMContext *ctx = avctx->priv_data; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); struct aom_codec_enc_cfg enccfg = { 0 }; #ifdef AOM_FRAME_IS_INTRAONLY aom_codec_flags_t flags = @@ -993,16 +1033,51 @@ static av_cold int aom_init(AVCodecContext *avctx, if (ctx->row_mt >= 0) codecctl_int(avctx, AV1E_SET_ROW_MT, ctx->row_mt); #endif #ifdef AOM_CTRL_AV1E_SET_ENABLE_INTRABC if (ctx->enable_intrabc >= 0) codecctl_int(avctx, AV1E_SET_ENABLE_INTRABC, ctx->enable_intrabc); #endif + if (enccfg.rc_end_usage == AOM_CBR) { + aom_svc_params_t svc_params = {}; + svc_params.framerate_factor[0] = 1; + svc_params.number_spatial_layers = 1; + svc_params.number_temporal_layers = 1; + + AVDictionaryEntry *en = NULL; + while ((en = av_dict_get(ctx->svc_parameters, "", en, AV_DICT_IGNORE_SUFFIX))) { + if (!strlen(en->value)) + return AVERROR(EINVAL); + + if (!strcmp(en->key, "number_spatial_layers")) + svc_params.number_spatial_layers = strtoul(en->value, NULL, 10); + else if (!strcmp(en->key, "number_temporal_layers")) + svc_params.number_temporal_layers = strtoul(en->value, NULL, 10); + else if (!strcmp(en->key, "max_quantizers")) + aom_svc_parse_int_array(svc_params.max_quantizers, en->value, AOM_MAX_LAYERS); + else if (!strcmp(en->key, "min_quantizers")) + aom_svc_parse_int_array(svc_params.min_quantizers, en->value, AOM_MAX_LAYERS); + else if (!strcmp(en->key, "scaling_factor_num")) + aom_svc_parse_int_array(svc_params.scaling_factor_num, en->value, AOM_MAX_SS_LAYERS); + else if (!strcmp(en->key, "scaling_factor_den")) + aom_svc_parse_int_array(svc_params.scaling_factor_den, en->value, AOM_MAX_SS_LAYERS); + else if (!strcmp(en->key, "layer_target_bitrate")) + aom_svc_parse_int_array(svc_params.layer_target_bitrate, en->value, AOM_MAX_LAYERS); + else if (!strcmp(en->key, "framerate_factor")) + aom_svc_parse_int_array(svc_params.framerate_factor, en->value, AOM_MAX_TS_LAYERS); + } + + res = codecctl_svcp(avctx, AV1E_SET_SVC_PARAMS, &svc_params); + if (res < 0) + return res; + } + + #if AOM_ENCODER_ABI_VERSION >= 23 { AVDictionaryEntry *en = NULL; while ((en = av_dict_get(ctx->aom_params, "", en, AV_DICT_IGNORE_SUFFIX))) { int ret = aom_codec_set_option(&ctx->encoder, en->key, en->value); if (ret != AOM_CODEC_OK) { log_encoder_error(avctx, en->key); @@ -1525,16 +1600,17 @@ static const AVOption options[] = { { "enable-diff-wtd-comp", "Enable difference-weighted compound", OFFSET(enable_diff_wtd_comp), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, { "enable-dist-wtd-comp", "Enable distance-weighted compound", OFFSET(enable_dist_wtd_comp), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, { "enable-onesided-comp", "Enable one sided compound", OFFSET(enable_onesided_comp), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, { "enable-interinter-wedge", "Enable interinter wedge compound", OFFSET(enable_interinter_wedge), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, { "enable-interintra-wedge", "Enable interintra wedge compound", OFFSET(enable_interintra_wedge), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, { "enable-masked-comp", "Enable masked compound", OFFSET(enable_masked_comp), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, { "enable-interintra-comp", "Enable interintra compound", OFFSET(enable_interintra_comp), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, { "enable-smooth-interintra", "Enable smooth interintra mode", OFFSET(enable_smooth_interintra), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, + { "svc-parameters", "SVC configuration using a :-separated list of key=value parameters (only applied in CBR mode)", OFFSET(svc_parameters), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE}, #if AOM_ENCODER_ABI_VERSION >= 23 { "aom-params", "Set libaom options using a :-separated list of key=value pairs", OFFSET(aom_params), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE }, #endif { NULL }, }; static const FFCodecDefault defaults[] = { { "b", "0" }, -- 2.34.1 diff --git a/media/ffvpx/libavcodec/libaomenc.c b/media/ffvpx/libavcodec/libaomenc.c --- a/media/ffvpx/libavcodec/libaomenc.c +++ b/media/ffvpx/libavcodec/libaomenc.c @@ -1391,16 +1391,35 @@ FF_ENABLE_DEPRECATION_WARNINGS break; case AVCOL_RANGE_JPEG: rawimg->range = AOM_CR_FULL_RANGE; break; } if (frame->pict_type == AV_PICTURE_TYPE_I) flags |= AOM_EFLAG_FORCE_KF; + + AVDictionaryEntry* en = av_dict_get(frame->metadata, "temporal_id", NULL, 0); + if (en) { + aom_svc_layer_id_t layer_id = {}; + layer_id.temporal_layer_id = strtoul(en->value, NULL, 10); + av_log(avctx, AV_LOG_DEBUG, "Frame pts % " PRId64 " temporal layer id %d", + frame->pts, layer_id.temporal_layer_id); + if (!ctx->svc_parameters) { + av_log(avctx, AV_LOG_WARNING, + "Temporal SVC not enabled, but temporal layer id received."); + } + res = aom_codec_control(&ctx->encoder, AV1E_SET_SVC_LAYER_ID, &layer_id); + if (res != AOM_CODEC_OK) { + av_log(avctx, AV_LOG_ERROR, + "Error setting temporal layer id %d on frame pts % " PRId64 "\n", + layer_id.temporal_layer_id, frame->pts); + return res; + } + } } res = aom_codec_encode(&ctx->encoder, rawimg, timestamp, duration, flags); if (res != AOM_CODEC_OK) { log_encoder_error(avctx, "Error encoding frame"); return AVERROR_INVALIDDATA; } coded_size = queue_frames(avctx, pkt);