From 0cbc75c0834a4ba93b67a79467b80324b06165f4 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Sun, 9 Jun 2013 15:37:28 +0200 Subject: Option -omaxfps: limit fps when encoding Lower-fps content is left alone (NOT aligned to this fps); higher fps content is decimated to this frame rate. --- DOCS/man/en/encode.rst | 5 +++++ core/options.c | 1 + core/options.h | 1 + etc/encoding-example-profiles.conf | 6 ++++++ video/out/vo_lavc.c | 16 ++++++++++++++++ 5 files changed, 29 insertions(+) diff --git a/DOCS/man/en/encode.rst b/DOCS/man/en/encode.rst index 93b1b84f28..0676cb1479 100644 --- a/DOCS/man/en/encode.rst +++ b/DOCS/man/en/encode.rst @@ -45,6 +45,11 @@ You can encode files from one format/codec to another using this facility. specified - use --ofps or --oautofps to force CFR encoding in these cases. +--omaxfps= + Specifies the minimum distance of adjacent frames (default: 0, which means + unset). Content of lower frame rate is not readjusted to this frame rate; + content of higher frame rate is decimated to this frame rate. + --oharddup If set, the frame rate given by --ofps is attained not by skipping time codes, but by duplicating frames (constant frame rate mode). diff --git a/core/options.c b/core/options.c index 79d1370e7e..60eb86a448 100644 --- a/core/options.c +++ b/core/options.c @@ -709,6 +709,7 @@ const m_option_t mp_opts[] = { OPT_STRING("of", encode_output.format, CONF_GLOBAL), OPT_STRINGLIST("ofopts*", encode_output.fopts, CONF_GLOBAL), OPT_FLOATRANGE("ofps", encode_output.fps, CONF_GLOBAL, 0.0, 1000000.0), + OPT_FLOATRANGE("omaxfps", encode_output.maxfps, CONF_GLOBAL, 0.0, 1000000.0), OPT_STRING("ovc", encode_output.vcodec, CONF_GLOBAL), OPT_STRINGLIST("ovcopts*", encode_output.vopts, CONF_GLOBAL), OPT_STRING("oac", encode_output.acodec, CONF_GLOBAL), diff --git a/core/options.h b/core/options.h index 42955cd730..36af43e3f1 100644 --- a/core/options.h +++ b/core/options.h @@ -252,6 +252,7 @@ typedef struct MPOpts { char *format; char **fopts; float fps; + float maxfps; char *vcodec; char **vopts; char *acodec; diff --git a/etc/encoding-example-profiles.conf b/etc/encoding-example-profiles.conf index 890cbc0067..7d67a3e4e4 100644 --- a/etc/encoding-example-profiles.conf +++ b/etc/encoding-example-profiles.conf @@ -153,6 +153,7 @@ profile = enc-f-mp4 vf-add = dsize=480:360:0:2,scale=w=0:h=0,dsize=-1:-1 # native screen res, letterbox ovcopts-add = maxrate=1500k,bufsize=1000k,rc_init_occupancy=900k,refs=1,profile=baseline vf-add=noformat=444p,noformat=444p9,noformat=444p10,noformat=422p,noformat=422p9,noformat=422p10 +omaxfps = 30 [enc-to-nok-n900] profile-desc = "MP4 for Nokia N900" @@ -160,6 +161,7 @@ profile = enc-f-mp4 vf-add = dsize=800:480:0:2,scale=w=0:h=0:noup=1,scale=w=-1:h=-2:noup=1,scale=w=-2:h=-1:noup=1,dsize=-1:-1 # native screen res, letterbox ovcopts-add = profile=baseline,level=30,maxrate=10000k,bufsize=10000k,rc_init_occupancy=9000k,refs=5 vf-add=noformat=444p,noformat=444p9,noformat=444p10,noformat=422p,noformat=422p9,noformat=422p10 +omaxfps = 30 [enc-to-nok-6300] profile-desc = "3GP for Nokia 6300" @@ -186,18 +188,22 @@ profile = enc-f-mp4 oautofps = yes # iphone supports 30fps max ovcopts-add = maxrate=2500k,bufsize=1000k,rc_init_occupancy=900k,level=30,profile=baseline vf-add=noformat=444p,noformat=444p9,noformat=444p10,noformat=422p,noformat=422p9,noformat=422p10 +omaxfps = 30 [enc-to-iphone] profile-desc = "MP4 for iPhone (480x320)" profile = enc-to-iphone-noscale vf-add = dsize=480:320:1:2,scale=w=0:h=0,dsize=-1:-1 # panscan +omaxfps = 30 [enc-to-iphone-4] profile-desc = "MP4 for iPhone 4 (960x640)" profile = enc-to-iphone-noscale vf-add = dsize=960:480:1:2,scale=w=0:h=0,dsize=-1:-1 # panscan +omaxfps = 30 [enc-to-iphone-5] profile-desc = "MP4 for iPhone 5 (1136x640)" profile = enc-to-iphone-noscale vf-add = dsize=1136:480:1:2,scale=w=0:h=0,dsize=-1:-1 # panscan +omaxfps = 30 diff --git a/video/out/vo_lavc.c b/video/out/vo_lavc.c index 5140720f92..840103c0c2 100644 --- a/video/out/vo_lavc.c +++ b/video/out/vo_lavc.c @@ -48,6 +48,7 @@ struct priv { double lastpts; int64_t lastipts; int64_t lastframeipts; + int64_t mindeltapts; double expected_next_pts; mp_image_t *lastimg; int lastimg_wants_osd; @@ -317,6 +318,11 @@ static void draw_image(struct vo *vo, mp_image_t *mpi) vc->worst_time_base = vc->stream->time_base; vc->worst_time_base_is_stream = 1; } + if (ectx->options->maxfps) + vc->mindeltapts = ceil(vc->worst_time_base.den / + (vc->worst_time_base.num * ectx->options->maxfps)); + else + vc->mindeltapts = 0; // NOTE: we use the following "axiom" of av_rescale_q: // if time base A is worse than time base B, then @@ -394,6 +400,16 @@ static void draw_image(struct vo *vo, mp_image_t *mpi) vc->lastpts = frameipts * timeunit - encode_lavc_getoffset(ectx, vc->stream); } + // lastipts: pts of last vo frame + // frameipts: pts of current vo frame + // lastframeipts: pts of last ENCODED frame + // now we want to go forward in time until at least lastframeipts + mindeltapts + // so let's just assume this frame took place at this time or later + if (frameipts >= vc->lastframeipts && frameipts < vc->lastframeipts + vc->mindeltapts) { + frameipts = vc->lastframeipts + vc->mindeltapts; + vc->lastpts = frameipts * timeunit - encode_lavc_getoffset(ectx, vc->stream); + } + if (vc->lastipts != MP_NOPTS_VALUE) { frame = avcodec_alloc_frame(); -- cgit v1.2.3