218 lines
9.1 KiB
Text
218 lines
9.1 KiB
Text
- 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,
|