diff --git a/ffpresets/libvpx-1080p.ffpreset b/ffpresets/libvpx-1080p.ffpreset new file mode 100644 index 0000000..19ec3ff --- /dev/null +++ b/ffpresets/libvpx-1080p.ffpreset @@ -0,0 +1,18 @@ +vcodec=libvpx +g=120 +rc_lookahead=16 +quality=good +speed=0 +profile=1 +qmax=51 +qmin=11 +slices=4 +vb=2M + +#ignored unless using -pass 2 +maxrate=24M +minrate=100k +vp8flags=+altref +arnr_max_frames=7 +arnr_strength=5 +arnr_type=3 diff --git a/ffpresets/libvpx-1080p50_60.ffpreset b/ffpresets/libvpx-1080p50_60.ffpreset new file mode 100644 index 0000000..9cff038 --- /dev/null +++ b/ffpresets/libvpx-1080p50_60.ffpreset @@ -0,0 +1,18 @@ +vcodec=libvpx +g=120 +rc_lookahead=25 +quality=good +speed=0 +profile=1 +qmax=51 +qmin=11 +slices=4 +vb=2M + +#ignored unless using -pass 2 +maxrate=24M +minrate=100k +vp8flags=+altref +arnr_max_frames=7 +arnr_strength=5 +arnr_type=3 diff --git a/ffpresets/libvpx-360p.ffpreset b/ffpresets/libvpx-360p.ffpreset new file mode 100644 index 0000000..d72c66d --- /dev/null +++ b/ffpresets/libvpx-360p.ffpreset @@ -0,0 +1,17 @@ +vcodec=libvpx +g=120 +rc_lookahead=16 +quality=good +speed=0 +profile=0 +qmax=63 +qmin=0 +vb=768k + +#ignored unless using -pass 2 +maxrate=1.5M +minrate=40k +vp8flags=+altref +arnr_max_frames=7 +arnr_strength=5 +arnr_type=3 diff --git a/ffpresets/libvpx-720p.ffpreset b/ffpresets/libvpx-720p.ffpreset new file mode 100644 index 0000000..3414539 --- /dev/null +++ b/ffpresets/libvpx-720p.ffpreset @@ -0,0 +1,18 @@ +vcodec=libvpx +g=120 +rc_lookahead=16 +quality=good +speed=0 +profile=0 +qmax=51 +qmin=11 +slices=4 +vb=2M + +#ignored unless using -pass 2 +maxrate=24M +minrate=100k +vp8flags=+altref +arnr_max_frames=7 +arnr_strength=5 +arnr_type=3 diff --git a/ffpresets/libvpx-720p50_60.ffpreset b/ffpresets/libvpx-720p50_60.ffpreset new file mode 100644 index 0000000..a0a4321 --- /dev/null +++ b/ffpresets/libvpx-720p50_60.ffpreset @@ -0,0 +1,18 @@ +vcodec=libvpx +g=120 +rc_lookahead=25 +quality=good +speed=0 +profile=0 +qmax=51 +qmin=11 +slices=4 +vb=2M + +#ignored unless using -pass 2 +maxrate=24M +minrate=100k +vp8flags=+altref +arnr_max_frames=7 +arnr_strength=5 +arnr_type=3 diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c index 1cdac74..2130312 100644 --- a/libavcodec/libvpxenc.c +++ b/libavcodec/libvpxenc.c @@ -30,6 +30,7 @@ #include "avcodec.h" #include "libavutil/base64.h" +#include "libavutil/opt.h" /** * Portion of struct vpx_codec_cx_pkt from vpx_encoder.h. @@ -50,10 +51,45 @@ typedef struct VP8EncoderContext { struct vpx_codec_ctx encoder; struct vpx_image rawimg; 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; + + 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; +#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 */ static const char *ctlidstr[] = { [VP8E_UPD_ENTROPY] = "VP8E_UPD_ENTROPY", @@ -205,7 +241,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; @@ -224,6 +259,7 @@ static av_cold int vp8_init(AVCodecContext *avctx) enccfg.g_timebase.num = avctx->time_base.num; enccfg.g_timebase.den = avctx->time_base.den; 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) enccfg.g_pass = VPX_RC_FIRST_PASS; @@ -259,6 +295,7 @@ static av_cold int vp8_init(AVCodecContext *avctx) enccfg.rc_buf_initial_sz = avctx->rc_initial_buffer_occupancy * 1000LL / avctx->bit_rate; 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 if (avctx->keyint_min == avctx->gop_size) @@ -294,13 +331,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->flags & VP8F_ERROR_RESILIENT; + dump_enc_cfg(avctx, &enccfg); /* Construct Encoder Context */ res = vpx_codec_enc_init(&ctx->encoder, iface, &enccfg, 0); @@ -311,11 +349,17 @@ 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); + codecctl_int(avctx, VP8E_SET_CPUUSED, ctx->cpuused); 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); 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() vpx_img_wrap(&ctx->rawimg, VPX_IMG_FMT_I420, avctx->width, avctx->height, 1, @@ -511,4 +555,5 @@ AVCodec ff_libvpx_encoder = { 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, }; diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 767356a..17418bc 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -258,6 +258,9 @@ typedef struct AVFormatParameters { #define AVFMT_VARIABLE_FPS 0x0400 /**< Format allows variable fps. */ #define AVFMT_NODIMENSIONS 0x0800 /**< Format does not need width/height */ #define AVFMT_NOSTREAMS 0x1000 /**< Format does not require any streams */ +#define AVFMT_TS_NONSTRICT 0x2000 /**< Format does not require strictly + increasing timestamps, but they must + still be monotonic */ typedef struct AVOutputFormat { const char *name; diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 5e4552a..2c846c8 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -1199,7 +1199,7 @@ AVOutputFormat ff_webm_muxer = { mkv_write_header, mkv_write_packet, mkv_write_trailer, - .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS, + .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT, }; #endif diff --git a/libavformat/utils.c b/libavformat/utils.c index e7ce911..bc9d38f 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -2901,7 +2901,7 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt){ pkt->dts= st->pts_buffer[0]; } - if(st->cur_dts && st->cur_dts != AV_NOPTS_VALUE && st->cur_dts >= pkt->dts){ + if(st->cur_dts && st->cur_dts != AV_NOPTS_VALUE && ((!(s->oformat->flags & AVFMT_TS_NONSTRICT) && st->cur_dts >= pkt->dts) || st->cur_dts > pkt->dts)){ av_log(s, AV_LOG_ERROR, "Application provided invalid, non monotonically increasing dts to muxer in stream %d: %"PRId64" >= %"PRId64"\n", st->index, st->cur_dts, pkt->dts);