Commit a138121b authored by James Zern's avatar James Zern Committed by Michael Niedermayer

webm: Additional options/presets for VP8 encodes under FFmpeg

parent 094aa84b
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "avcodec.h" #include "avcodec.h"
#include "libavutil/base64.h" #include "libavutil/base64.h"
#include "libavutil/opt.h"
/** /**
* Portion of struct vpx_codec_cx_pkt from vpx_encoder.h. * Portion of struct vpx_codec_cx_pkt from vpx_encoder.h.
...@@ -50,10 +51,45 @@ typedef struct VP8EncoderContext { ...@@ -50,10 +51,45 @@ typedef struct VP8EncoderContext {
struct vpx_codec_ctx encoder; struct vpx_codec_ctx encoder;
struct vpx_image rawimg; struct vpx_image rawimg;
struct vpx_fixed_buf twopass_stats; struct vpx_fixed_buf twopass_stats;
unsigned long deadline; //i.e., RT/GOOD/BEST int deadline; //i.e., RT/GOOD/BEST
struct FrameListData *coded_frame_list; struct FrameListData *coded_frame_list;
int cpuused;
/**
* VP8 specific flags, see VP8F_* below.
*/
int flags;
#define VP8F_ERROR_RESILIENT 0x00000001 ///< Enable measures appropriate for streaming over lossy links
#define VP8F_AUTO_ALT_REF 0x00000002 ///< Enable automatic alternate reference frame generation
int arnr_max_frames;
int arnr_strength;
int arnr_type;
} VP8Context; } VP8Context;
#define V AV_OPT_FLAG_VIDEO_PARAM
#define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[]={
{"speed", "", offsetof(VP8Context, cpuused), FF_OPT_TYPE_INT, 3, -16, 16, V|E},
{"quality", "", offsetof(VP8Context, deadline), FF_OPT_TYPE_INT, VPX_DL_GOOD_QUALITY, INT_MIN, INT_MAX, V|E, "quality"},
{"best", NULL, 0, FF_OPT_TYPE_CONST, VPX_DL_BEST_QUALITY, INT_MIN, INT_MAX, V|E, "quality"},
{"good", NULL, 0, FF_OPT_TYPE_CONST, VPX_DL_GOOD_QUALITY, INT_MIN, INT_MAX, V|E, "quality"},
{"realtime", NULL, 0, FF_OPT_TYPE_CONST, VPX_DL_REALTIME, INT_MIN, INT_MAX, V|E, "quality"},
{"vp8flags", "", offsetof(VP8Context, flags), FF_OPT_TYPE_FLAGS, 0, 0, UINT_MAX, V|E, "flags"},
{"error_resilient", "enable error resilience", 0, FF_OPT_TYPE_CONST, VP8F_ERROR_RESILIENT, INT_MIN, INT_MAX, V|E, "flags"},
{"altref", "enable use of alternate reference frames (VP8/2-pass only)", 0, FF_OPT_TYPE_CONST, VP8F_AUTO_ALT_REF, INT_MIN, INT_MAX, V|E, "flags"},
{"arnr_max_frames", "altref noise reduction max frame count", offsetof(VP8Context, arnr_max_frames), FF_OPT_TYPE_INT, 0, 0, 15, V|E},
{"arnr_strength", "altref noise reduction filter strength", offsetof(VP8Context, arnr_strength), FF_OPT_TYPE_INT, 3, 0, 6, V|E},
{"arnr_type", "altref noise reduction filter type", offsetof(VP8Context, arnr_type), FF_OPT_TYPE_INT, 3, 1, 3, V|E},
{NULL}
};
static const AVClass class = { "libvpx", av_default_item_name, options, LIBAVUTIL_VERSION_INT };
#undef V
#undef E
/** String mappings for enum vp8e_enc_control_id */ /** String mappings for enum vp8e_enc_control_id */
static const char *ctlidstr[] = { static const char *ctlidstr[] = {
[VP8E_UPD_ENTROPY] = "VP8E_UPD_ENTROPY", [VP8E_UPD_ENTROPY] = "VP8E_UPD_ENTROPY",
...@@ -205,7 +241,6 @@ static av_cold int vp8_init(AVCodecContext *avctx) ...@@ -205,7 +241,6 @@ static av_cold int vp8_init(AVCodecContext *avctx)
{ {
VP8Context *ctx = avctx->priv_data; VP8Context *ctx = avctx->priv_data;
const struct vpx_codec_iface *iface = &vpx_codec_vp8_cx_algo; const struct vpx_codec_iface *iface = &vpx_codec_vp8_cx_algo;
int cpuused = 3;
struct vpx_codec_enc_cfg enccfg; struct vpx_codec_enc_cfg enccfg;
int res; int res;
...@@ -224,6 +259,7 @@ static av_cold int vp8_init(AVCodecContext *avctx) ...@@ -224,6 +259,7 @@ static av_cold int vp8_init(AVCodecContext *avctx)
enccfg.g_timebase.num = avctx->time_base.num; enccfg.g_timebase.num = avctx->time_base.num;
enccfg.g_timebase.den = avctx->time_base.den; enccfg.g_timebase.den = avctx->time_base.den;
enccfg.g_threads = avctx->thread_count; enccfg.g_threads = avctx->thread_count;
enccfg.g_lag_in_frames= FFMIN(avctx->rc_lookahead, 25); //0-25, avoids init failure
if (avctx->flags & CODEC_FLAG_PASS1) if (avctx->flags & CODEC_FLAG_PASS1)
enccfg.g_pass = VPX_RC_FIRST_PASS; enccfg.g_pass = VPX_RC_FIRST_PASS;
...@@ -259,6 +295,7 @@ static av_cold int vp8_init(AVCodecContext *avctx) ...@@ -259,6 +295,7 @@ static av_cold int vp8_init(AVCodecContext *avctx)
enccfg.rc_buf_initial_sz = enccfg.rc_buf_initial_sz =
avctx->rc_initial_buffer_occupancy * 1000LL / avctx->bit_rate; avctx->rc_initial_buffer_occupancy * 1000LL / avctx->bit_rate;
enccfg.rc_buf_optimal_sz = enccfg.rc_buf_sz * 5 / 6; enccfg.rc_buf_optimal_sz = enccfg.rc_buf_sz * 5 / 6;
enccfg.rc_undershoot_pct = round(avctx->rc_buffer_aggressivity * 100);
//_enc_init() will balk if kf_min_dist differs from max w/VPX_KF_AUTO //_enc_init() will balk if kf_min_dist differs from max w/VPX_KF_AUTO
if (avctx->keyint_min == avctx->gop_size) if (avctx->keyint_min == avctx->gop_size)
...@@ -294,13 +331,14 @@ static av_cold int vp8_init(AVCodecContext *avctx) ...@@ -294,13 +331,14 @@ static av_cold int vp8_init(AVCodecContext *avctx)
enccfg.rc_twopass_stats_in = ctx->twopass_stats; 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 /* 0-3: For non-zero values the encoder increasingly optimizes for reduced
complexity playback on low powered devices at the expense of encode complexity playback on low powered devices at the expense of encode
quality. */ quality. */
if (avctx->profile != FF_PROFILE_UNKNOWN) if (avctx->profile != FF_PROFILE_UNKNOWN)
enccfg.g_profile = avctx->profile; enccfg.g_profile = avctx->profile;
enccfg.g_error_resilient = ctx->flags & VP8F_ERROR_RESILIENT;
dump_enc_cfg(avctx, &enccfg); dump_enc_cfg(avctx, &enccfg);
/* Construct Encoder Context */ /* Construct Encoder Context */
res = vpx_codec_enc_init(&ctx->encoder, iface, &enccfg, 0); res = vpx_codec_enc_init(&ctx->encoder, iface, &enccfg, 0);
...@@ -311,11 +349,17 @@ static av_cold int vp8_init(AVCodecContext *avctx) ...@@ -311,11 +349,17 @@ static av_cold int vp8_init(AVCodecContext *avctx)
//codec control failures are currently treated only as warnings //codec control failures are currently treated only as warnings
av_log(avctx, AV_LOG_DEBUG, "vpx_codec_control\n"); av_log(avctx, AV_LOG_DEBUG, "vpx_codec_control\n");
codecctl_int(avctx, VP8E_SET_CPUUSED, cpuused); codecctl_int(avctx, VP8E_SET_CPUUSED, ctx->cpuused);
codecctl_int(avctx, VP8E_SET_NOISE_SENSITIVITY, avctx->noise_reduction); 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_TOKEN_PARTITIONS, av_log2(avctx->slices));
codecctl_int(avctx, VP8E_SET_STATIC_THRESHOLD, avctx->mb_threshold); codecctl_int(avctx, VP8E_SET_STATIC_THRESHOLD, avctx->mb_threshold);
codecctl_int(avctx, VP8E_SET_CQ_LEVEL, (int)avctx->crf); codecctl_int(avctx, VP8E_SET_CQ_LEVEL, (int)avctx->crf);
codecctl_int(avctx, VP8E_SET_ENABLEAUTOALTREF, !!(ctx->flags & VP8F_AUTO_ALT_REF));
codecctl_int(avctx, VP8E_SET_ARNR_MAXFRAMES, ctx->arnr_max_frames);
codecctl_int(avctx, VP8E_SET_ARNR_STRENGTH, ctx->arnr_strength);
codecctl_int(avctx, VP8E_SET_ARNR_TYPE, ctx->arnr_type);
av_log(avctx, AV_LOG_DEBUG, "Using deadline: %d\n", ctx->deadline);
//provide dummy value to initialize wrapper, values will be updated each _encode() //provide dummy value to initialize wrapper, values will be updated each _encode()
vpx_img_wrap(&ctx->rawimg, VPX_IMG_FMT_I420, avctx->width, avctx->height, 1, vpx_img_wrap(&ctx->rawimg, VPX_IMG_FMT_I420, avctx->width, avctx->height, 1,
...@@ -511,4 +555,5 @@ AVCodec ff_libvpx_encoder = { ...@@ -511,4 +555,5 @@ AVCodec ff_libvpx_encoder = {
CODEC_CAP_DELAY, CODEC_CAP_DELAY,
.pix_fmts = (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE}, .pix_fmts = (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE},
.long_name = NULL_IF_CONFIG_SMALL("libvpx VP8"), .long_name = NULL_IF_CONFIG_SMALL("libvpx VP8"),
.priv_class= &class,
}; };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment