1
0
mirror of https://github.com/mpv-player/mpv synced 2025-01-18 13:14:36 +00:00

encode: remove old timestamp handling

This effectively makes --ocopyts the default. The --ocopyts option
itself is also removed, because it's redundant.
This commit is contained in:
wm4 2018-04-29 02:55:27 +02:00 committed by Jan Ekström
parent 60dade1040
commit f18c4175ad
7 changed files with 57 additions and 291 deletions

View File

@ -3,8 +3,7 @@ General usage
:: ::
mpv infile -o outfile [-of outfileformat] [-ofopts formatoptions] \ mpv infile -o outfile [-of outfileformat] [-ofopts formatoptions] [-orawts] \
[-ofps outfps | -oautofps] [-oharddup] [-ocopyts | -orawts] [-oneverdrop] \
[(any other mpv options)] \ [(any other mpv options)] \
-ovc outvideocodec [-ovcopts outvideocodecoptions] \ -ovc outvideocodec [-ovcopts outvideocodecoptions] \
-oac outaudiocodec [-oacopts outaudiocodecoptions] -oac outaudiocodec [-oacopts outaudiocodecoptions]
@ -60,13 +59,13 @@ for.
Typical MPEG-4 Part 2 ("ASP", "DivX") encoding, AVI container:: Typical MPEG-4 Part 2 ("ASP", "DivX") encoding, AVI container::
mpv infile -o outfile.avi \ mpv infile -o outfile.avi \
-ofps 25 \ --vf=fps=25 \
-ovc mpeg4 -ovcopts qscale=4 \ -ovc mpeg4 -ovcopts qscale=4 \
-oac libmp3lame -oacopts ab=128k -oac libmp3lame -oacopts ab=128k
Note: AVI does not support variable frame rate, so -ofps must be used. The Note: AVI does not support variable frame rate, so the fps filter must be used.
frame rate should ideally match the input (25 for PAL, 24000/1001 or 30000/1001 The frame rate should ideally match the input (25 for PAL, 24000/1001 or
for NTSC) 30000/1001 for NTSC)
Typical MPEG-4 Part 10 ("AVC", "H.264") encoding, Matroska (MKV) container:: Typical MPEG-4 Part 10 ("AVC", "H.264") encoding, Matroska (MKV) container::
@ -129,7 +128,7 @@ What works
========== ==========
* Encoding at variable frame rate (default) * Encoding at variable frame rate (default)
* Encoding at constant frame rate using -ofps framerate -oharddup * Encoding at constant frame rate using --vf=fps=RATE
* 2-pass encoding (specify flags=+pass1 in the first pass's -ovcopts, specify * 2-pass encoding (specify flags=+pass1 in the first pass's -ovcopts, specify
flags=+pass2 in the second pass) flags=+pass2 in the second pass)
* Hardcoding subtitles using vobsub, ass or srt subtitle rendering (just * Hardcoding subtitles using vobsub, ass or srt subtitle rendering (just

View File

@ -94,6 +94,9 @@ Interface changes
the future. (This kind of waiting was always a feature to prevent that the future. (This kind of waiting was always a feature to prevent that
playback is started while scripts are only half-loaded.) playback is started while scripts are only half-loaded.)
- deprecate --ovoffset, --oaoffset, --ovfirst, --oafirst - deprecate --ovoffset, --oaoffset, --ovfirst, --oafirst
- remove the following encoding options: --ocopyts (now the default, old
timestamp handling is gone), --oneverdrop (now default), --oharddup (you
need to use --vf=fps=VALUE), --ofps, --oautofps, --omaxfps
- remove --video-stereo-mode. This option was broken out of laziness, and - remove --video-stereo-mode. This option was broken out of laziness, and
nobody wants to fix it. Automatic 3D down-conversion to 2D is also broken, nobody wants to fix it. Automatic 3D down-conversion to 2D is also broken,
although you can just insert the stereo3d filter manually. The obscurity although you can just insert the stereo3d filter manually. The obscurity

View File

@ -24,32 +24,6 @@ You can encode files from one format/codec to another using this facility.
``--ofopts=""`` ``--ofopts=""``
Completely empties the options list. Completely empties the options list.
``--ofps=<float value>``
Specifies the output format time base (default: 24000). Low values like 25
limit video fps by dropping frames.
``--oautofps``
Sets the output format time base to the guessed frame rate of the input
video (simulates MEncoder behavior, useful for AVI; may cause frame drops).
Note that not all codecs and not all formats support VFR encoding, and some
which do have bugs when a target bitrate is specified - use ``--ofps`` or
``--oautofps`` to force CFR encoding in these cases.
``--omaxfps=<float value>``
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).
``--oneverdrop``
If set, frames are never dropped. Instead, time codes of video are
readjusted to always increase. This may cause AV desync, though; to work
around this, use a high-fps time base using ``--ofps`` and absolutely
avoid ``--oautofps``.
``--oac=<codec>`` ``--oac=<codec>``
Specifies the output audio codec. See ``--oac=help`` for a full list of Specifies the output audio codec. See ``--oac=help`` for a full list of
supported codecs. supported codecs.
@ -113,13 +87,6 @@ You can encode files from one format/codec to another using this facility.
Force the video stream to become the first stream in the output. Force the video stream to become the first stream in the output.
By default, the order is unspecified. Deprecated. By default, the order is unspecified. Deprecated.
``--ocopyts``
Copies input pts to the output video (not supported by some output
container formats, e.g. AVI). Discontinuities are still fixed.
By default, audio pts are set to playback time and video pts are
synchronized to match audio pts, as some output formats do not support
anything else.
``--orawts`` ``--orawts``
Copies input pts to the output video (not supported by some output Copies input pts to the output video (not supported by some output
container formats, e.g. AVI). In this mode, discontinuities are not fixed container formats, e.g. AVI). In this mode, discontinuities are not fixed

View File

@ -169,7 +169,7 @@ static void uninit(struct ao *ao)
double outpts = ac->expected_next_pts; double outpts = ac->expected_next_pts;
pthread_mutex_lock(&ectx->lock); pthread_mutex_lock(&ectx->lock);
if (!ac->enc->options->rawts && ac->enc->options->copyts) if (!ac->enc->options->rawts)
outpts += ectx->discontinuity_pts_offset; outpts += ectx->discontinuity_pts_offset;
pthread_mutex_unlock(&ectx->lock); pthread_mutex_unlock(&ectx->lock);
@ -214,15 +214,7 @@ static void encode(struct ao *ao, double apts, void **data)
frame->linesize[0] = frame->nb_samples * ao->sstride; frame->linesize[0] = frame->nb_samples * ao->sstride;
if (ac->enc->options->rawts || ac->enc->options->copyts) { frame->pts = rint(apts * av_q2d(av_inv_q(encoder->time_base)));
// real audio pts
frame->pts = floor(apts * encoder->time_base.den /
encoder->time_base.num + 0.5);
} else {
// audio playback time
frame->pts = floor(realapts * encoder->time_base.den /
encoder->time_base.num + 0.5);
}
int64_t frame_pts = av_rescale_q(frame->pts, encoder->time_base, int64_t frame_pts = av_rescale_q(frame->pts, encoder->time_base,
ac->worst_time_base); ac->worst_time_base);
@ -254,7 +246,6 @@ static int play(struct ao *ao, void **data, int samples, int flags)
struct encode_lavc_context *ectx = ao->encode_lavc_ctx; struct encode_lavc_context *ectx = ao->encode_lavc_ctx;
int bufpos = 0; int bufpos = 0;
double nextpts; double nextpts;
double outpts;
int orig_samples = samples; int orig_samples = samples;
// for ectx PTS fields // for ectx PTS fields
@ -281,38 +272,9 @@ static int play(struct ao *ao, void **data, int samples, int flags)
samples = (bytelen + extralen) / ao->sstride; samples = (bytelen + extralen) / ao->sstride;
} }
if (pts == MP_NOPTS_VALUE) { double outpts = pts;
MP_WARN(ao, "frame without pts, please report; synthesizing pts instead\n"); if (!enc->options->rawts) {
// synthesize pts from previous expected next pts // Fix and apply the discontinuity pts offset.
pts = ac->expected_next_pts;
}
if (ac->worst_time_base.den == 0) {
// We don't know the muxer time_base anymore, and can't, because we
// might start encoding before the muxer is opened. (The muxer decides
// the final AVStream.time_base when opening the muxer.)
ac->worst_time_base = enc->encoder->time_base;
// NOTE: we use the following "axiom" of av_rescale_q:
// if time base A is worse than time base B, then
// av_rescale_q(av_rescale_q(x, A, B), B, A) == x
// this can be proven as long as av_rescale_q rounds to nearest, which
// it currently does
// av_rescale_q(x, A, B) * B = "round x*A to nearest multiple of B"
// and:
// av_rescale_q(av_rescale_q(x, A, B), B, A) * A
// == "round av_rescale_q(x, A, B)*B to nearest multiple of A"
// == "round 'round x*A to nearest multiple of B' to nearest multiple of A"
//
// assume this fails. Then there is a value of x*A, for which the
// nearest multiple of B is outside the range [(x-0.5)*A, (x+0.5)*A[.
// Absurd, as this range MUST contain at least one multiple of B.
}
// Fix and apply the discontinuity pts offset.
if (!enc->options->rawts && enc->options->copyts) {
// fix the discontinuity pts offset
nextpts = pts; nextpts = pts;
if (ectx->discontinuity_pts_offset == MP_NOPTS_VALUE) { if (ectx->discontinuity_pts_offset == MP_NOPTS_VALUE) {
ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts; ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts;
@ -326,8 +288,6 @@ static int play(struct ao *ao, void **data, int samples, int flags)
} }
outpts = pts + ectx->discontinuity_pts_offset; outpts = pts + ectx->discontinuity_pts_offset;
} else {
outpts = pts;
} }
pthread_mutex_unlock(&ectx->lock); pthread_mutex_unlock(&ectx->lock);
@ -349,7 +309,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
pthread_mutex_lock(&ectx->lock); pthread_mutex_lock(&ectx->lock);
// Set next allowed input pts value (input side). // Set next allowed input pts value (input side).
if (!enc->options->rawts && enc->options->copyts) { if (!enc->options->rawts) {
nextpts = ac->expected_next_pts + ectx->discontinuity_pts_offset; nextpts = ac->expected_next_pts + ectx->discontinuity_pts_offset;
if (nextpts > ectx->next_in_pts) if (nextpts > ectx->next_in_pts)
ectx->next_in_pts = nextpts; ectx->next_in_pts = nextpts;

View File

@ -34,19 +34,13 @@ struct encode_opts {
char *file; char *file;
char *format; char *format;
char **fopts; char **fopts;
float fps;
float maxfps;
char *vcodec; char *vcodec;
char **vopts; char **vopts;
char *acodec; char *acodec;
char **aopts; char **aopts;
int harddup;
float voffset; float voffset;
float aoffset; float aoffset;
int copyts;
int rawts; int rawts;
int autofps;
int neverdrop;
int video_first; int video_first;
int audio_first; int audio_first;
int copy_metadata; int copy_metadata;

View File

@ -81,21 +81,15 @@ const struct m_sub_options encode_config = {
OPT_STRING("o", file, M_OPT_FIXED | CONF_NOCFG | CONF_PRE_PARSE | M_OPT_FILE), OPT_STRING("o", file, M_OPT_FIXED | CONF_NOCFG | CONF_PRE_PARSE | M_OPT_FILE),
OPT_STRING("of", format, M_OPT_FIXED), OPT_STRING("of", format, M_OPT_FIXED),
OPT_KEYVALUELIST("ofopts", fopts, M_OPT_FIXED | M_OPT_HAVE_HELP), OPT_KEYVALUELIST("ofopts", fopts, M_OPT_FIXED | M_OPT_HAVE_HELP),
OPT_FLOATRANGE("ofps", fps, M_OPT_FIXED, 0.0, 1000000.0),
OPT_FLOATRANGE("omaxfps", maxfps, M_OPT_FIXED, 0.0, 1000000.0),
OPT_STRING("ovc", vcodec, M_OPT_FIXED), OPT_STRING("ovc", vcodec, M_OPT_FIXED),
OPT_KEYVALUELIST("ovcopts", vopts, M_OPT_FIXED | M_OPT_HAVE_HELP), OPT_KEYVALUELIST("ovcopts", vopts, M_OPT_FIXED | M_OPT_HAVE_HELP),
OPT_STRING("oac", acodec, M_OPT_FIXED), OPT_STRING("oac", acodec, M_OPT_FIXED),
OPT_KEYVALUELIST("oacopts", aopts, M_OPT_FIXED | M_OPT_HAVE_HELP), OPT_KEYVALUELIST("oacopts", aopts, M_OPT_FIXED | M_OPT_HAVE_HELP),
OPT_FLAG("oharddup", harddup, M_OPT_FIXED),
OPT_FLOATRANGE("ovoffset", voffset, M_OPT_FIXED, -1000000.0, 1000000.0, OPT_FLOATRANGE("ovoffset", voffset, M_OPT_FIXED, -1000000.0, 1000000.0,
.deprecation_message = "--audio-delay (once unbroken)"), .deprecation_message = "--audio-delay (once unbroken)"),
OPT_FLOATRANGE("oaoffset", aoffset, M_OPT_FIXED, -1000000.0, 1000000.0, OPT_FLOATRANGE("oaoffset", aoffset, M_OPT_FIXED, -1000000.0, 1000000.0,
.deprecation_message = "--audio-delay (once unbroken)"), .deprecation_message = "--audio-delay (once unbroken)"),
OPT_FLAG("ocopyts", copyts, M_OPT_FIXED),
OPT_FLAG("orawts", rawts, M_OPT_FIXED), OPT_FLAG("orawts", rawts, M_OPT_FIXED),
OPT_FLAG("oautofps", autofps, M_OPT_FIXED),
OPT_FLAG("oneverdrop", neverdrop, M_OPT_FIXED),
OPT_FLAG("ovfirst", video_first, M_OPT_FIXED, OPT_FLAG("ovfirst", video_first, M_OPT_FIXED,
.deprecation_message = "no replacement"), .deprecation_message = "no replacement"),
OPT_FLAG("oafirst", audio_first, M_OPT_FIXED, OPT_FLAG("oafirst", audio_first, M_OPT_FIXED,
@ -103,6 +97,13 @@ const struct m_sub_options encode_config = {
OPT_FLAG("ocopy-metadata", copy_metadata, M_OPT_FIXED), OPT_FLAG("ocopy-metadata", copy_metadata, M_OPT_FIXED),
OPT_KEYVALUELIST("oset-metadata", set_metadata, M_OPT_FIXED), OPT_KEYVALUELIST("oset-metadata", set_metadata, M_OPT_FIXED),
OPT_STRINGLIST("oremove-metadata", remove_metadata, M_OPT_FIXED), OPT_STRINGLIST("oremove-metadata", remove_metadata, M_OPT_FIXED),
OPT_REMOVED("ocopyts", "ocopyts is now the default"),
OPT_REMOVED("oneverdrop", "no replacement"),
OPT_REMOVED("oharddup", "use --vf-add=fps=VALUE"),
OPT_REMOVED("ofps", "no replacement (use --vf-add=fps=VALUE for CFR)"),
OPT_REMOVED("oautofps", "no replacement"),
OPT_REMOVED("omaxfps", "no replacement"),
{0} {0}
}, },
.size = sizeof(struct encode_opts), .size = sizeof(struct encode_opts),

View File

@ -38,21 +38,6 @@
struct priv { struct priv {
struct encoder_context *enc; struct encoder_context *enc;
int harddup;
double lastpts;
int64_t lastipts;
int64_t lastframeipts;
int64_t lastencodedipts;
int64_t mindeltapts;
double expected_next_pts;
mp_image_t *lastimg;
int lastdisplaycount;
double last_video_in_pts;
AVRational worst_time_base;
bool shutdown; bool shutdown;
}; };
@ -65,25 +50,21 @@ static int preinit(struct vo *vo)
if (!vc->enc) if (!vc->enc)
return -1; return -1;
talloc_steal(vc, vc->enc); talloc_steal(vc, vc->enc);
vc->harddup = vc->enc->options->harddup;
vc->last_video_in_pts = MP_NOPTS_VALUE;
return 0; return 0;
} }
static void uninit(struct vo *vo) static void uninit(struct vo *vo)
{ {
struct priv *vc = vo->priv; struct priv *vc = vo->priv;
struct encoder_context *enc = vc->enc;
if (vc->lastipts >= 0 && !vc->shutdown) if (!vc->shutdown)
draw_image(vo, NULL); encoder_encode(enc, NULL); // finish encoding
mp_image_unrefp(&vc->lastimg);
} }
static int reconfig2(struct vo *vo, struct mp_image *img) static int reconfig2(struct vo *vo, struct mp_image *img)
{ {
struct priv *vc = vo->priv; struct priv *vc = vo->priv;
struct encode_lavc_context *ctx = vo->encode_lavc_ctx;
AVCodecContext *encoder = vc->enc->encoder; AVCodecContext *encoder = vc->enc->encoder;
struct mp_image_params *params = &img->params; struct mp_image_params *params = &img->params;
@ -117,10 +98,6 @@ static int reconfig2(struct vo *vo, struct mp_image *img)
// - Second calls after reconfigure() already succeeded once return early // - Second calls after reconfigure() already succeeded once return early
// (due to the avcodec_is_open() check above). // (due to the avcodec_is_open() check above).
vc->lastipts = AV_NOPTS_VALUE;
vc->lastframeipts = AV_NOPTS_VALUE;
vc->lastencodedipts = AV_NOPTS_VALUE;
if (pix_fmt == AV_PIX_FMT_NONE) { if (pix_fmt == AV_PIX_FMT_NONE) {
MP_FATAL(vo, "Format %s not supported by lavc.\n", MP_FATAL(vo, "Format %s not supported by lavc.\n",
mp_imgfmt_to_name(params->imgfmt)); mp_imgfmt_to_name(params->imgfmt));
@ -136,27 +113,15 @@ static int reconfig2(struct vo *vo, struct mp_image *img)
AVRational tb; AVRational tb;
if (ctx->options->fps > 0) { // we want to handle:
tb = av_d2q(ctx->options->fps, ctx->options->fps * 1001 + 2); // 1/25
} else if (ctx->options->autofps && img->nominal_fps > 0) { // 1001/24000
tb = av_d2q(img->nominal_fps, img->nominal_fps * 1001 + 2); // 1001/30000
MP_INFO(vo, "option --ofps not specified " // for this we would need 120000fps...
"but --oautofps is active, using guess of %u/%u\n", // however, mpeg-4 only allows 16bit values
(unsigned)tb.num, (unsigned)tb.den); // so let's take 1001/30000 out
} else { tb.num = 24000;
// we want to handle: tb.den = 1;
// 1/25
// 1001/24000
// 1001/30000
// for this we would need 120000fps...
// however, mpeg-4 only allows 16bit values
// so let's take 1001/30000 out
tb.num = 24000;
tb.den = 1;
MP_INFO(vo, "option --ofps not specified "
"and fps could not be inferred, using guess of %u/%u\n",
(unsigned)tb.num, (unsigned)tb.den);
}
const AVRational *rates = encoder->codec->supported_framerates; const AVRational *rates = encoder->codec->supported_framerates;
if (rates && rates[0].den) if (rates && rates[0].den)
@ -199,180 +164,57 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
struct encoder_context *enc = vc->enc; struct encoder_context *enc = vc->enc;
struct encode_lavc_context *ectx = enc->encode_lavc_ctx; struct encode_lavc_context *ectx = enc->encode_lavc_ctx;
AVCodecContext *avc = enc->encoder; AVCodecContext *avc = enc->encoder;
int64_t frameipts;
double nextpts;
double pts = mpi ? mpi->pts : MP_NOPTS_VALUE; struct mp_osd_res dim = osd_res_from_image_params(vo->params);
osd_draw_on_image(vo->osd, dim, mpi->pts, OSD_DRAW_SUB_ONLY, mpi);
if (mpi) {
assert(vo->params);
struct mp_osd_res dim = osd_res_from_image_params(vo->params);
osd_draw_on_image(vo->osd, dim, mpi->pts, OSD_DRAW_SUB_ONLY, mpi);
}
if (vc->shutdown) if (vc->shutdown)
goto done; goto done;
if (pts == MP_NOPTS_VALUE) {
if (mpi)
MP_WARN(vo, "frame without pts, please report; synthesizing pts instead\n");
pts = vc->expected_next_pts;
}
if (vc->worst_time_base.den == 0) {
// We don't know the muxer time_base anymore, and can't, because we
// might start encoding before the muxer is opened. (The muxer decides
// the final AVStream.time_base when opening the muxer.)
vc->worst_time_base = avc->time_base;
if (enc->options->maxfps) {
vc->mindeltapts = ceil(vc->worst_time_base.den /
(vc->worst_time_base.num * enc->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
// av_rescale_q(av_rescale_q(x, A, B), B, A) == x
// this can be proven as long as av_rescale_q rounds to nearest, which
// it currently does
// av_rescale_q(x, A, B) * B = "round x*A to nearest multiple of B"
// and:
// av_rescale_q(av_rescale_q(x, A, B), B, A) * A
// == "round av_rescale_q(x, A, B)*B to nearest multiple of A"
// == "round 'round x*A to nearest multiple of B' to nearest multiple of A"
//
// assume this fails. Then there is a value of x*A, for which the
// nearest multiple of B is outside the range [(x-0.5)*A, (x+0.5)*A[.
// Absurd, as this range MUST contain at least one multiple of B.
}
double timeunit = (double)vc->worst_time_base.num / vc->worst_time_base.den;
// Lock for shared timestamp fields. // Lock for shared timestamp fields.
pthread_mutex_lock(&ectx->lock); pthread_mutex_lock(&ectx->lock);
double outpts; double pts = mpi->pts;
if (enc->options->rawts) { double outpts = pts;
outpts = pts; if (!enc->options->rawts) {
} else if (enc->options->copyts) {
// fix the discontinuity pts offset // fix the discontinuity pts offset
nextpts = pts;
if (ectx->discontinuity_pts_offset == MP_NOPTS_VALUE) { if (ectx->discontinuity_pts_offset == MP_NOPTS_VALUE) {
ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts; ectx->discontinuity_pts_offset = ectx->next_in_pts - pts;
} else if (fabs(nextpts + ectx->discontinuity_pts_offset - } else if (fabs(pts + ectx->discontinuity_pts_offset -
ectx->next_in_pts) > 30) ectx->next_in_pts) > 30)
{ {
MP_WARN(vo, "detected an unexpected discontinuity (pts jumped by " MP_WARN(vo, "detected an unexpected discontinuity (pts jumped by "
"%f seconds)\n", "%f seconds)\n",
nextpts + ectx->discontinuity_pts_offset - ectx->next_in_pts); pts + ectx->discontinuity_pts_offset - ectx->next_in_pts);
ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts; ectx->discontinuity_pts_offset = ectx->next_in_pts - pts;
} }
outpts = pts + ectx->discontinuity_pts_offset; outpts = pts + ectx->discontinuity_pts_offset;
} else {
// adjust pts by knowledge of audio pts vs audio playback time
double duration = 0;
if (vc->last_video_in_pts != MP_NOPTS_VALUE)
duration = pts - vc->last_video_in_pts;
if (duration < 0)
duration = timeunit; // XXX warn about discontinuity?
outpts = vc->lastpts + duration;
if (ectx->audio_pts_offset != MP_NOPTS_VALUE) {
double adj = outpts - pts - ectx->audio_pts_offset;
adj = FFMIN(adj, duration * 0.1);
adj = FFMAX(adj, -duration * 0.1);
outpts -= adj;
}
} }
vc->lastpts = outpts;
vc->last_video_in_pts = pts;
frameipts = floor((outpts + encoder_get_offset(enc)) / timeunit + 0.5);
// calculate expected pts of next video frame outpts += encoder_get_offset(enc);
vc->expected_next_pts = pts + timeunit;
if (!enc->options->rawts && enc->options->copyts) { if (!enc->options->rawts) {
// calculate expected pts of next video frame
double timeunit = av_q2d(avc->time_base);
double expected_next_pts = pts + timeunit;
// set next allowed output pts value // set next allowed output pts value
nextpts = vc->expected_next_pts + ectx->discontinuity_pts_offset; double nextpts = expected_next_pts + ectx->discontinuity_pts_offset;
if (nextpts > ectx->next_in_pts) if (nextpts > ectx->next_in_pts)
ectx->next_in_pts = nextpts; ectx->next_in_pts = nextpts;
} }
pthread_mutex_unlock(&ectx->lock); pthread_mutex_unlock(&ectx->lock);
// never-drop mode AVFrame *frame = mp_image_to_av_frame(mpi);
if (enc->options->neverdrop) { if (!frame)
int64_t step = vc->mindeltapts ? vc->mindeltapts : 1; abort();
if (frameipts < vc->lastipts + step) {
MP_INFO(vo, "--oneverdrop increased pts by %d\n",
(int) (vc->lastipts - frameipts + step));
frameipts = vc->lastipts + step;
vc->lastpts = frameipts * timeunit - encoder_get_offset(enc);
}
}
if (vc->lastipts != AV_NOPTS_VALUE) { frame->pts = rint(outpts * av_q2d(av_inv_q(avc->time_base)));
// we have a valid image in lastimg frame->pict_type = 0; // keep this at unknown/undefined
while (vc->lastimg && vc->lastipts < frameipts) { frame->quality = avc->global_quality;
int64_t thisduration = vc->harddup ? 1 : (frameipts - vc->lastipts); encoder_encode(enc, frame);
av_frame_free(&frame);
// we will ONLY encode this frame if it can be encoded at at least
// vc->mindeltapts after the last encoded frame!
int64_t skipframes = (vc->lastencodedipts == AV_NOPTS_VALUE)
? 0 : vc->lastencodedipts + vc->mindeltapts - vc->lastipts;
if (skipframes < 0)
skipframes = 0;
if (thisduration > skipframes) {
AVFrame *frame = mp_image_to_av_frame(vc->lastimg);
if (!frame)
abort();
// this is a nop, unless the worst time base is the STREAM time base
frame->pts = av_rescale_q(vc->lastipts + skipframes,
vc->worst_time_base, avc->time_base);
frame->pict_type = 0; // keep this at unknown/undefined
frame->quality = avc->global_quality;
encoder_encode(enc, frame);
av_frame_free(&frame);
vc->lastdisplaycount += 1;
vc->lastencodedipts = vc->lastipts + skipframes;
}
vc->lastipts += thisduration;
}
}
if (!mpi) {
// finish encoding
encoder_encode(enc, NULL);
} else {
if (frameipts >= vc->lastframeipts) {
if (vc->lastframeipts != AV_NOPTS_VALUE && vc->lastdisplaycount != 1)
MP_INFO(vo, "Frame at pts %d got displayed %d times\n",
(int) vc->lastframeipts, vc->lastdisplaycount);
talloc_free(vc->lastimg);
vc->lastimg = mpi;
mpi = NULL;
vc->lastframeipts = vc->lastipts = frameipts;
if (enc->options->rawts && vc->lastipts < 0) {
MP_ERR(vo, "why does this happen? DEBUG THIS! vc->lastipts = %lld\n",
(long long) vc->lastipts);
vc->lastipts = -1;
}
vc->lastdisplaycount = 0;
} else {
MP_INFO(vo, "Frame at pts %d got dropped "
"entirely because pts went backwards\n", (int) frameipts);
}
}
done: done:
talloc_free(mpi); talloc_free(mpi);