From e3eb015ba47ace8aff8db18e80d20704e7306b66 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Mon, 26 Sep 2011 10:22:38 +0200 Subject: [PATCH] vpxenc: add private options Make libvpx support close to the libx264 one. Thanks to Jan Gerber for the support. Signed-off-by: Anton Khirnov --- libavcodec/libvpxenc.c | 63 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c index 8da5974867..1ff997eff6 100644 --- a/libavcodec/libvpxenc.c +++ b/libavcodec/libvpxenc.c @@ -29,8 +29,10 @@ #include #include "avcodec.h" +#include "internal.h" #include "libavutil/base64.h" #include "libavutil/mathematics.h" +#include "libavutil/opt.h" /** * Portion of struct vpx_codec_cx_pkt from vpx_encoder.h. @@ -48,11 +50,19 @@ struct FrameListData { }; typedef struct VP8EncoderContext { + AVClass *class; struct vpx_codec_ctx encoder; struct vpx_image rawimg; struct vpx_fixed_buf twopass_stats; unsigned long deadline; //i.e., RT/GOOD/BEST struct FrameListData *coded_frame_list; + int cpu_used; + int auto_alt_ref; + int arnr_max_frames; + int arnr_strength; + int arnr_type; + int lag_in_frames; + int error_resilient; } VP8Context; /** String mappings for enum vp8e_enc_control_id */ @@ -205,7 +215,6 @@ static av_cold int vp8_init(AVCodecContext *avctx) { VP8Context *ctx = avctx->priv_data; const struct vpx_codec_iface *iface = &vpx_codec_vp8_cx_algo; - int cpuused = 3; struct vpx_codec_enc_cfg enccfg; int res; @@ -225,6 +234,9 @@ static av_cold int vp8_init(AVCodecContext *avctx) enccfg.g_timebase.den = avctx->time_base.den; enccfg.g_threads = avctx->thread_count; + if (ctx->lag_in_frames >= 0) + enccfg.g_lag_in_frames = ctx->lag_in_frames; + if (avctx->flags & CODEC_FLAG_PASS1) enccfg.g_pass = VPX_RC_FIRST_PASS; else if (avctx->flags & CODEC_FLAG_PASS2) @@ -292,13 +304,14 @@ static av_cold int vp8_init(AVCodecContext *avctx) enccfg.rc_twopass_stats_in = ctx->twopass_stats; } - ctx->deadline = VPX_DL_GOOD_QUALITY; /* 0-3: For non-zero values the encoder increasingly optimizes for reduced complexity playback on low powered devices at the expense of encode quality. */ if (avctx->profile != FF_PROFILE_UNKNOWN) enccfg.g_profile = avctx->profile; + enccfg.g_error_resilient = ctx->error_resilient; + dump_enc_cfg(avctx, &enccfg); /* Construct Encoder Context */ res = vpx_codec_enc_init(&ctx->encoder, iface, &enccfg, 0); @@ -309,7 +322,16 @@ static av_cold int vp8_init(AVCodecContext *avctx) //codec control failures are currently treated only as warnings av_log(avctx, AV_LOG_DEBUG, "vpx_codec_control\n"); - codecctl_int(avctx, VP8E_SET_CPUUSED, cpuused); + if (ctx->cpu_used != INT_MIN) + codecctl_int(avctx, VP8E_SET_CPUUSED, ctx->cpu_used); + if (ctx->auto_alt_ref >= 0) + codecctl_int(avctx, VP8E_SET_ENABLEAUTOALTREF, ctx->auto_alt_ref); + if (ctx->arnr_max_frames >= 0) + codecctl_int(avctx, VP8E_SET_ARNR_MAXFRAMES, ctx->arnr_max_frames); + if (ctx->arnr_strength >= 0) + codecctl_int(avctx, VP8E_SET_ARNR_STRENGTH, ctx->arnr_strength); + if (ctx->arnr_type >= 0) + codecctl_int(avctx, VP8E_SET_ARNR_TYPE, ctx->arnr_type); codecctl_int(avctx, VP8E_SET_NOISE_SENSITIVITY, avctx->noise_reduction); codecctl_int(avctx, VP8E_SET_TOKEN_PARTITIONS, av_log2(avctx->slices)); codecctl_int(avctx, VP8E_SET_STATIC_THRESHOLD, avctx->mb_threshold); @@ -496,6 +518,40 @@ static int vp8_encode(AVCodecContext *avctx, uint8_t *buf, int buf_size, return coded_size; } +#define OFFSET(x) offsetof(VP8Context, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "cpu-used", "Quality/Speed ratio modifier", OFFSET(cpu_used), FF_OPT_TYPE_INT, {INT_MIN}, INT_MIN, INT_MAX, VE}, + { "auto-alt-ref", "Enable use of alternate reference " + "frames (2-pass only)", OFFSET(auto_alt_ref), FF_OPT_TYPE_INT, {-1}, -1, 1, VE}, + { "lag-in-frames", "Number of frames to look ahead for " + "alternate reference frame selection", OFFSET(lag_in_frames), FF_OPT_TYPE_INT, {-1}, -1, INT_MAX, VE}, + { "arnr-maxframes", "altref noise reduction max frame count", OFFSET(arnr_max_frames), FF_OPT_TYPE_INT, {-1}, -1, INT_MAX, VE}, + { "arnr-strength", "altref noise reduction filter strength", OFFSET(arnr_strength), FF_OPT_TYPE_INT, {-1}, -1, INT_MAX, VE}, + { "arnr-type", "altref noise reduction filter type", OFFSET(arnr_type), FF_OPT_TYPE_INT, {-1}, -1, INT_MAX, VE, "arnr_type"}, + { "backward", NULL, 0, FF_OPT_TYPE_CONST, {1}, 0, 0, VE, "arnr_type" }, + { "forward", NULL, 0, FF_OPT_TYPE_CONST, {2}, 0, 0, VE, "arnr_type" }, + { "centered", NULL, 0, FF_OPT_TYPE_CONST, {3}, 0, 0, VE, "arnr_type" }, + { "deadline", "Time to spend encoding, in microseconds.", OFFSET(deadline), FF_OPT_TYPE_INT, {VPX_DL_GOOD_QUALITY}, INT_MIN, INT_MAX, VE, "quality"}, + { "best", NULL, 0, FF_OPT_TYPE_CONST, {VPX_DL_BEST_QUALITY}, 0, 0, VE, "quality"}, + { "good", NULL, 0, FF_OPT_TYPE_CONST, {VPX_DL_GOOD_QUALITY}, 0, 0, VE, "quality"}, + { "realtime", NULL, 0, FF_OPT_TYPE_CONST, {VPX_DL_REALTIME}, 0, 0, VE, "quality"}, + { "error-resilient", "Error resilience configuration", OFFSET(error_resilient), FF_OPT_TYPE_FLAGS, {0}, INT_MIN, INT_MAX, VE, "er"}, + { "default", "Improve resiliency against losses of whole frames", 0, FF_OPT_TYPE_CONST, {VPX_ERROR_RESILIENT_DEFAULT}, 0, 0, VE, "er"}, + { "partitions", "The frame partitions are independently decodable " + "by the bool decoder, meaning that partitions can be decoded even " + "though earlier partitions have been lost. Note that intra predicition" + " is still done over the partition boundary.", 0, FF_OPT_TYPE_CONST, {VPX_ERROR_RESILIENT_PARTITIONS}, 0, 0, VE, "er"}, + { NULL } +}; + +static const AVClass class = { + .class_name = "libvpx encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVCodec ff_libvpx_encoder = { .name = "libvpx", .type = AVMEDIA_TYPE_VIDEO, @@ -507,4 +563,5 @@ AVCodec ff_libvpx_encoder = { .capabilities = CODEC_CAP_DELAY, .pix_fmts = (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE}, .long_name = NULL_IF_CONFIG_SMALL("libvpx VP8"), + .priv_class = &class, };