summaryrefslogtreecommitdiffstats
path: root/libao2
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 /libao2
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.
Diffstat (limited to 'libao2')
-rw-r--r--libao2/ao_lavc.c66
1 files changed, 44 insertions, 22 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;
}