diff options
author | Rudolf Polzer <divverent@xonotic.org> | 2012-09-25 11:53:29 +0200 |
---|---|---|
committer | Rudolf Polzer <divverent@alientrap.org> | 2012-09-29 15:02:36 +0200 |
commit | a89a6f40c7ada04db2f85869d8d50166e0e7f905 (patch) | |
tree | 2527a1e0fff447b9d5c09bd94ba8075cee598a10 /libao2 | |
parent | c22482e08d4ca0514685e73b68479f0427b1f28f (diff) | |
download | mpv-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.c | 66 |
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; } |