ports/graphics/ffmpeg/patches/patch-libavcodec_libaomenc_c

219 lines
9.1 KiB
Text
Raw Normal View History

2023-08-16 22:26:55 +00:00
- lavc/aomenc: Force default qmax of 0 if crf was set to 0
- avcodec/libaomenc: Avoid copying data, allow user-supplied buffers
- lavc/libaomenc: Show encoder config as a warning in case of failed initialization
- avcodec/libaomenc: use ctx->usage to get default cfg
- avcodec/libaomenc: remove the redundant initialization
- avcodec/libaomenc: Add unmet target level warning
- avcodec/libaomenc: Expose the allintra usage mode
- avcodec/libaomenc: Get number of operating points
Index: libavcodec/libaomenc.c
--- libavcodec/libaomenc.c.orig
+++ libavcodec/libaomenc.c
@@ -36,6 +36,7 @@
#include "av1.h"
#include "avcodec.h"
+#include "encode.h"
#include "internal.h"
#include "packet_internal.h"
#include "profiles.h"
@@ -194,6 +195,15 @@ static const char *const ctlidstr[] = {
[AV1E_SET_ENABLE_SMOOTH_INTERINTRA] = "AV1E_SET_ENABLE_SMOOTH_INTERINTRA",
[AV1E_SET_ENABLE_REF_FRAME_MVS] = "AV1E_SET_ENABLE_REF_FRAME_MVS",
#endif
+#ifdef AOM_CTRL_AV1E_GET_NUM_OPERATING_POINTS
+ [AV1E_GET_NUM_OPERATING_POINTS] = "AV1E_GET_NUM_OPERATING_POINTS",
+#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
};
static av_cold void log_encoder_error(AVCodecContext *avctx, const char *desc)
@@ -208,10 +218,10 @@ static av_cold void log_encoder_error(AVCodecContext *
}
static av_cold void dump_enc_cfg(AVCodecContext *avctx,
- const struct aom_codec_enc_cfg *cfg)
+ const struct aom_codec_enc_cfg *cfg,
+ int level)
{
int width = -30;
- int level = AV_LOG_DEBUG;
av_log(avctx, level, "aom_codec_enc_cfg\n");
av_log(avctx, level, "generic settings\n"
@@ -319,10 +329,73 @@ static av_cold int codecctl_int(AVCodecContext *avctx,
return 0;
}
+#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)
+static av_cold int codecctl_intp(AVCodecContext *avctx,
+#ifdef UENUM1BYTE
+ aome_enc_control_id id,
+#else
+ enum aome_enc_control_id id,
+#endif
+ int* ptr)
+{
+ AOMContext *ctx = avctx->priv_data;
+ char buf[80];
+ int width = -30;
+ int res;
+
+ snprintf(buf, sizeof(buf), "%s:", ctlidstr[id]);
+ av_log(avctx, AV_LOG_DEBUG, " %*s%d\n", width, buf, *ptr);
+
+ res = aom_codec_control(&ctx->encoder, id, ptr);
+ if (res != AOM_CODEC_OK) {
+ snprintf(buf, sizeof(buf), "Failed to set %s codec control",
+ ctlidstr[id]);
+ log_encoder_error(avctx, buf);
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+#endif
+
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 (!(avctx->flags & AV_CODEC_FLAG_PASS1)) {
+ int num_operating_points;
+ int levels[32];
+ int target_levels[32];
+
+ if (!codecctl_intp(avctx, AV1E_GET_NUM_OPERATING_POINTS,
+ &num_operating_points) &&
+ !codecctl_intp(avctx, AV1E_GET_SEQ_LEVEL_IDX, levels) &&
+ !codecctl_intp(avctx, AV1E_GET_TARGET_SEQ_LEVEL_IDX,
+ target_levels)) {
+ for (int i = 0; i < num_operating_points; i++) {
+ if (levels[i] > target_levels[i]) {
+ // Warn when the target level was not met
+ av_log(avctx, AV_LOG_WARNING,
+ "Could not encode to target level %d.%d for "
+ "operating point %d. The output level is %d.%d.\n",
+ 2 + (target_levels[i] >> 2), target_levels[i] & 3,
+ i, 2 + (levels[i] >> 2), levels[i] & 3);
+ } else if (target_levels[i] < 31) {
+ // Log the encoded level if a target level was given
+ av_log(avctx, AV_LOG_INFO,
+ "Output level for operating point %d is %d.%d.\n",
+ i, 2 + (levels[i] >> 2), levels[i] & 3);
+ }
+ }
+ }
+ }
+#endif
+
aom_codec_destroy(&ctx->encoder);
av_freep(&ctx->twopass_stats.buf);
av_freep(&avctx->stats_out);
@@ -596,7 +669,7 @@ static av_cold int aom_init(AVCodecContext *avctx,
av_log(avctx, AV_LOG_INFO, "%s\n", aom_codec_version_str());
av_log(avctx, AV_LOG_VERBOSE, "%s\n", aom_codec_build_config());
- if ((res = aom_codec_enc_config_default(iface, &enccfg, 0)) != AOM_CODEC_OK) {
+ if ((res = aom_codec_enc_config_default(iface, &enccfg, ctx->usage)) != AOM_CODEC_OK) {
av_log(avctx, AV_LOG_ERROR, "Failed to get config: %s\n",
aom_codec_err_to_string(res));
return AVERROR(EINVAL);
@@ -611,7 +684,7 @@ static av_cold int aom_init(AVCodecContext *avctx,
return AVERROR(EINVAL);
}
- dump_enc_cfg(avctx, &enccfg);
+ dump_enc_cfg(avctx, &enccfg, AV_LOG_DEBUG);
enccfg.g_w = avctx->width;
enccfg.g_h = avctx->height;
@@ -620,8 +693,6 @@ static av_cold int aom_init(AVCodecContext *avctx,
enccfg.g_threads =
FFMIN(avctx->thread_count ? avctx->thread_count : av_cpu_count(), 64);
- enccfg.g_usage = ctx->usage;
-
if (ctx->lag_in_frames >= 0)
enccfg.g_lag_in_frames = ctx->lag_in_frames;
@@ -654,8 +725,11 @@ static av_cold int aom_init(AVCodecContext *avctx,
if (avctx->qmin >= 0)
enccfg.rc_min_quantizer = avctx->qmin;
- if (avctx->qmax >= 0)
+ if (avctx->qmax >= 0) {
enccfg.rc_max_quantizer = avctx->qmax;
+ } else if (!ctx->crf) {
+ enccfg.rc_max_quantizer = 0;
+ }
if (enccfg.rc_end_usage == AOM_CQ || enccfg.rc_end_usage == AOM_Q) {
if (ctx->crf < enccfg.rc_min_quantizer || ctx->crf > enccfg.rc_max_quantizer) {
@@ -742,13 +816,14 @@ static av_cold int aom_init(AVCodecContext *avctx,
if (res < 0)
return res;
- dump_enc_cfg(avctx, &enccfg);
/* Construct Encoder Context */
res = aom_codec_enc_init(&ctx->encoder, iface, &enccfg, flags);
if (res != AOM_CODEC_OK) {
+ dump_enc_cfg(avctx, &enccfg, AV_LOG_WARNING);
log_encoder_error(avctx, "Failed to initialize encoder");
return AVERROR(EINVAL);
}
+ dump_enc_cfg(avctx, &enccfg, AV_LOG_DEBUG);
// codec control failures are currently treated only as warnings
av_log(avctx, AV_LOG_DEBUG, "aom_codec_control\n");
@@ -943,7 +1018,6 @@ static inline void cx_pktcpy(AOMContext *ctx,
dst->sz = src->data.frame.sz;
dst->buf = src->data.frame.buf;
#ifdef AOM_FRAME_IS_INTRAONLY
- dst->have_sse = 0;
dst->frame_number = ++ctx->frame_number;
dst->have_sse = ctx->have_sse;
if (ctx->have_sse) {
@@ -967,7 +1041,7 @@ static int storeframe(AVCodecContext *avctx, struct Fr
{
AOMContext *ctx = avctx->priv_data;
int av_unused pict_type;
- int ret = ff_alloc_packet2(avctx, pkt, cx_frame->sz, 0);
+ int ret = ff_get_encode_buffer(avctx, pkt, cx_frame->sz, 0);
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR,
"Error getting output packet of size %"SIZE_SPECIFIER".\n", cx_frame->sz);
@@ -1282,6 +1356,7 @@ static const AVOption options[] = {
{ "usage", "Quality and compression efficiency vs speed trade-off", OFFSET(usage), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, VE, "usage"},
{ "good", "Good quality", 0, AV_OPT_TYPE_CONST, {.i64 = 0 /* AOM_USAGE_GOOD_QUALITY */}, 0, 0, VE, "usage"},
{ "realtime", "Realtime encoding", 0, AV_OPT_TYPE_CONST, {.i64 = 1 /* AOM_USAGE_REALTIME */}, 0, 0, VE, "usage"},
+ { "allintra", "All Intra encoding", 0, AV_OPT_TYPE_CONST, {.i64 = 2 /* AOM_USAGE_ALL_INTRA */}, 0, 0, VE, "usage"},
{ "tune", "The metric that the encoder tunes for. Automatically chosen by the encoder by default", OFFSET(tune), AV_OPT_TYPE_INT, {.i64 = -1}, -1, AOM_TUNE_SSIM, VE, "tune"},
{ "psnr", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AOM_TUNE_PSNR}, 0, 0, VE, "tune"},
{ "ssim", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AOM_TUNE_SSIM}, 0, 0, VE, "tune"},
@@ -1341,11 +1416,12 @@ AVCodec ff_libaom_av1_encoder = {
.long_name = NULL_IF_CONFIG_SMALL("libaom AV1"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_AV1,
+ .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
+ AV_CODEC_CAP_OTHER_THREADS,
.priv_data_size = sizeof(AOMContext),
.init = av1_init,
.encode2 = aom_encode,
.close = aom_free,
- .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS,
.caps_internal = FF_CODEC_CAP_AUTO_THREADS,
.profiles = NULL_IF_CONFIG_SMALL(ff_av1_profiles),
.priv_class = &class_aom,