summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRudolf Polzer <divverent@xonotic.org>2012-09-25 11:53:29 +0200
committerRudolf Polzer <divverent@alientrap.org>2012-09-29 15:02:36 +0200
commita89a6f40c7ada04db2f85869d8d50166e0e7f905 (patch)
tree2527a1e0fff447b9d5c09bd94ba8075cee598a10
parentc22482e08d4ca0514685e73b68479f0427b1f28f (diff)
downloadmpv-a89a6f40c7ada04db2f85869d8d50166e0e7f905.tar.bz2
mpv-a89a6f40c7ada04db2f85869d8d50166e0e7f905.tar.xz
encode: fix -ocopyts with certain DVD images
When timestamps jump by more than 30 seconds, assume an unexpected discontinuity. Fixes encoding aborts (i.e. no more frames written) at DVD cell switches.
-rw-r--r--libao2/ao_lavc.c66
-rw-r--r--libvo/vo_lavc.c106
2 files changed, 94 insertions, 78 deletions
diff --git a/libao2/ao_lavc.c b/libao2/ao_lavc.c
index b22cd325dc..f23f14d59e 100644
--- a/libao2/ao_lavc.c
+++ b/libao2/ao_lavc.c
@@ -56,6 +56,7 @@ struct priv {
int64_t lastpts;
int sample_size;
const void *sample_padding;
+ double expected_next_pts;
AVRational worst_time_base;
int worst_time_base_is_stream;
@@ -288,7 +289,7 @@ static void fill_with_padding(void *buf, int cnt, int sz, const void *padding)
}
// close audio device
-static int encode(struct ao *ao, int ptsvalid, double apts, void *data);
+static int encode(struct ao *ao, double apts, void *data);
static void uninit(struct ao *ao, bool cut_audio)
{
struct priv *ac = ao->priv;
@@ -302,12 +303,12 @@ static void uninit(struct ao *ao, bool cut_audio)
(ac->aframesize * ao->channels * ac->sample_size
- ao->buffer.len) / ac->sample_size,
ac->sample_size, ac->sample_padding);
- encode(ao, ao->pts != MP_NOPTS_VALUE, pts, paddingbuf);
+ encode(ao, pts, paddingbuf);
pts += ac->aframesize / (double) ao->samplerate;
talloc_free(paddingbuf);
ao->buffer.len = 0;
}
- while (encode(ao, true, pts, NULL) > 0) ;
+ while (encode(ao, pts, NULL) > 0) ;
}
ao->priv = NULL;
@@ -320,7 +321,7 @@ static int get_space(struct ao *ao)
}
// must get exactly ac->aframesize amount of data
-static int encode(struct ao *ao, int ptsvalid, double apts, void *data)
+static int encode(struct ao *ao, double apts, void *data)
{
AVFrame *frame;
AVPacket packet;
@@ -338,7 +339,7 @@ static int encode(struct ao *ao, int ptsvalid, double apts, void *data)
ac->aframesize * ao->channels, ac->sample_size);
}
- if (data && ptsvalid)
+ if (data)
ectx->audio_pts_offset = realapts - apts;
av_init_packet(&packet);
@@ -354,12 +355,9 @@ static int encode(struct ao *ao, int ptsvalid, double apts, void *data)
return -1;
}
- if (ao->encode_lavc_ctx->options->rawts) {
- // raw audio pts
- frame->pts = floor(apts * ac->stream->codec->time_base.den / ac->stream->codec->time_base.num + 0.5);
- } else if (ectx->options->copyts) {
+ if (ectx->options->rawts || ectx->options->copyts) {
// real audio pts
- frame->pts = floor((apts + ectx->discontinuity_pts_offset) * ac->stream->codec->time_base.den / ac->stream->codec->time_base.num + 0.5);
+ frame->pts = floor(apts * ac->stream->codec->time_base.den / ac->stream->codec->time_base.num + 0.5);
} else {
// audio playback time
frame->pts = floor(realapts * ac->stream->codec->time_base.den / ac->stream->codec->time_base.num + 0.5);
@@ -385,7 +383,7 @@ static int encode(struct ao *ao, int ptsvalid, double apts, void *data)
ac->savepts = frame->pts;
}
- av_free(frame);
+ av_free(frame);
}
else
{
@@ -449,6 +447,8 @@ static int play(struct ao *ao, void *data, int len, int flags)
int64_t ptsoffset;
void *paddingbuf = NULL;
double nextpts;
+ double pts = ao->pts;
+ double outpts;
len /= ac->sample_size * ao->channels;
@@ -456,6 +456,11 @@ static int play(struct ao *ao, void *data, int len, int flags)
mp_msg(MSGT_ENCODE, MSGL_WARN, "ao-lavc: NOTE: deferred initial audio frame (probably because video is not there yet)\n");
return 0;
}
+ if (pts == MP_NOPTS_VALUE) {
+ mp_msg(MSGT_ENCODE, MSGL_WARN, "ao-lavc: frame without pts, please report; synthesizing pts instead\n");
+ // synthesize pts from previous expected next pts
+ pts = ac->expected_next_pts;
+ }
if (ac->worst_time_base.den == 0) {
//if (ac->stream->codec->time_base.num / ac->stream->codec->time_base.den >= ac->stream->time_base.num / ac->stream->time_base.den)
@@ -549,26 +554,43 @@ static int play(struct ao *ao, void *data, int len, int flags)
}
}
- // fix the discontinuity pts offset
- if (ectx->discontinuity_pts_offset == MP_NOPTS_VALUE) {
- nextpts = ao->pts + ptsoffset / (double) ao->samplerate;
- ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts;
+ if (!ectx->options->rawts && ectx->options->copyts) {
+ // fix the discontinuity pts offset
+ nextpts = pts + ptsoffset / (double) ao->samplerate;
+ if (ectx->discontinuity_pts_offset == MP_NOPTS_VALUE) {
+ ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts;
+ }
+ else if (fabs(nextpts + ectx->discontinuity_pts_offset - ectx->next_in_pts) > 30) {
+ mp_msg(MSGT_ENCODE, MSGL_WARN,
+ "ao-lavc: detected an unexpected discontinuity (pts jumped by "
+ "%f seconds)\n",
+ nextpts + ectx->discontinuity_pts_offset - ectx->next_in_pts);
+ ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts;
+ }
+
+ outpts = pts + ectx->discontinuity_pts_offset;
}
+ else
+ outpts = pts;
while (len - bufpos >= ac->aframesize) {
- encode(ao, ao->pts != MP_NOPTS_VALUE,
- ao->pts + (bufpos + ptsoffset) / (double) ao->samplerate +
- encode_lavc_getoffset(ectx, ac->stream),
+ encode(ao,
+ outpts + (bufpos + ptsoffset) / (double) ao->samplerate + encode_lavc_getoffset(ectx, ac->stream),
(char *) data + ac->sample_size * bufpos * ao->channels);
bufpos += ac->aframesize;
}
talloc_free(paddingbuf);
- // set next allowed output pts value
- nextpts = ao->pts + ectx->discontinuity_pts_offset + (bufpos + ptsoffset) / (double) ao->samplerate;
- if (nextpts > ectx->next_in_pts)
- ectx->next_in_pts = nextpts;
+ // calculate expected pts of next audio frame
+ ac->expected_next_pts = pts + (bufpos + ptsoffset) / (double) ao->samplerate;
+
+ if (!ectx->options->rawts && ectx->options->copyts) {
+ // set next allowed output pts value
+ nextpts = ac->expected_next_pts + ectx->discontinuity_pts_offset;
+ if (nextpts > ectx->next_in_pts)
+ ectx->next_in_pts = nextpts;
+ }
return bufpos * ac->sample_size * ao->channels;
}
diff --git a/libvo/vo_lavc.c b/libvo/vo_lavc.c
index 4a1af15eb0..5b467f1f6a 100644
--- a/libvo/vo_lavc.c
+++ b/libvo/vo_lavc.c
@@ -47,6 +47,7 @@ struct priv {
double lastpts;
int64_t lastipts;
int64_t lastframeipts;
+ double expected_next_pts;
mp_image_t *lastimg;
int lastdisplaycount;
@@ -347,6 +348,11 @@ static void draw_image(struct vo *vo, mp_image_t *mpi, double pts)
mp_msg(MSGT_ENCODE, MSGL_WARN, "vo-lavc: NOTE: skipped initial video frame (probably because audio is not there yet)\n");
return;
}
+ if (pts == MP_NOPTS_VALUE) {
+ if (mpi)
+ mp_msg(MSGT_ENCODE, MSGL_WARN, "vo-lavc: frame without pts, please report; synthesizing pts instead\n");
+ pts = vc->expected_next_pts;
+ }
avc = vc->stream->codec;
@@ -390,65 +396,53 @@ static void draw_image(struct vo *vo, mp_image_t *mpi, double pts)
double timeunit = (double)vc->worst_time_base.num / vc->worst_time_base.den;
- // fix the discontinuity pts offset
- if (ectx->discontinuity_pts_offset == MP_NOPTS_VALUE) {
+ double outpts;
+ if (ectx->options->rawts)
+ outpts = pts;
+ else if (ectx->options->copyts) {
+ // fix the discontinuity pts offset
nextpts = pts;
- ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts;
- }
-
- // set next allowed output pts value
- nextpts = pts + ectx->discontinuity_pts_offset + timeunit;
- if (nextpts > ectx->next_in_pts)
- ectx->next_in_pts = nextpts;
-
- // vc->lastipts is MP_NOPTS_VALUE, or the start time of vc->lastframe
- if (mpi) {
- if (pts == MP_NOPTS_VALUE) {
- // NOTE: this even applies to ectx->options->copyts!
- if (vc->lastipts == MP_NOPTS_VALUE)
- frameipts = 0;
- else
- frameipts = vc->lastipts + 1;
-
- mp_msg(MSGT_ENCODE, MSGL_INFO, "vo-lavc: pts was missing, using %d - "
- "consider using -ofps or -vf fixpts\n", (int) frameipts);
-
- if (ectx->last_video_in_pts != MP_NOPTS_VALUE)
- ectx->last_video_in_pts += timeunit;
+ if (ectx->discontinuity_pts_offset == MP_NOPTS_VALUE) {
+ ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts;
+ }
+ else if (fabs(nextpts + ectx->discontinuity_pts_offset - ectx->next_in_pts) > 30) {
+ mp_msg(MSGT_ENCODE, MSGL_WARN,
+ "vo-lavc: detected an unexpected discontinuity (pts jumped by "
+ "%f seconds)\n",
+ nextpts + ectx->discontinuity_pts_offset - ectx->next_in_pts);
+ ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts;
+ }
- // calculate backwards to set vc->lastpts matchingly
- vc->lastpts = frameipts * timeunit - encode_lavc_getoffset(ectx, vc->stream);
- } else {
- double outpts;
- if (ectx->options->rawts)
- outpts = pts;
- else if (ectx->options->copyts)
- outpts = pts + ectx->discontinuity_pts_offset;
- else {
- double duration = 0;
- if (ectx->last_video_in_pts != MP_NOPTS_VALUE)
- duration = pts - ectx->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;
- ectx->last_video_in_pts = pts;
- frameipts = floor((outpts + encode_lavc_getoffset(ectx, vc->stream))
- / timeunit + 0.5);
+ outpts = pts + ectx->discontinuity_pts_offset;
+ }
+ else {
+ // adjust pts by knowledge of audio pts vs audio playback time
+ double duration = 0;
+ if (ectx->last_video_in_pts != MP_NOPTS_VALUE)
+ duration = pts - ectx->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;
}
- } else {
- if (vc->lastipts == MP_NOPTS_VALUE)
- frameipts = 0;
- else
- frameipts = vc->lastipts + 1;
- vc->lastpts = frameipts * timeunit - encode_lavc_getoffset(ectx, vc->stream);
+ }
+ vc->lastpts = outpts;
+ ectx->last_video_in_pts = pts;
+ frameipts = floor((outpts + encode_lavc_getoffset(ectx, vc->stream))
+ / timeunit + 0.5);
+
+ // calculate expected pts of next video frame
+ vc->expected_next_pts = pts + timeunit;
+
+ if (!ectx->options->rawts && ectx->options->copyts) {
+ // set next allowed output pts value
+ nextpts = vc->expected_next_pts + ectx->discontinuity_pts_offset;
+ if (nextpts > ectx->next_in_pts)
+ ectx->next_in_pts = nextpts;
}
// never-drop mode