summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-12-04 20:57:52 +0100
committerwm4 <wm4@nowhere>2013-12-04 23:12:51 +0100
commit9c2858f37ff33c72550b54270122d810284cb52b (patch)
tree2c5b15100cce8dac1d502155b9572f0b1054ebae
parent8a84da8102cb9c436627a61cd3b674a8ad3e9708 (diff)
downloadmpv-9c2858f37ff33c72550b54270122d810284cb52b.tar.bz2
mpv-9c2858f37ff33c72550b54270122d810284cb52b.tar.xz
ad_lavc: deal with arbitrary decoder delay
Normally, audio decoder don't have a decoder delay, so the code was fine. But FFmpeg supports multithreaded decoding for some audio codecs, which introduces such a delay. The delay means that we won't get decoded audio for the first few packets, and that we need to do something to get the trailing audio still buffered in the decoder when reaching EOF. Two changes are needed to deal with the delay: - If EOF is reached, pass a "flush" packet to the decoder to return the buffered audio. Such a flush packet is automatically setup when calling mp_set_av_packet() with a NULL packet. - Use the PTS returned by the decoder, instead of the packet's. This is important to get correct timestamps for decoded audio. Ignoring this would result into offsetting the audio playback time by the decoder delay. Note that we can still use the timestamp of the first packet to get the timestamp for the start of the audio.
-rw-r--r--audio/decode/ad_lavc.c40
1 files changed, 24 insertions, 16 deletions
diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c
index 3b9a48e419..b364616e73 100644
--- a/audio/decode/ad_lavc.c
+++ b/audio/decode/ad_lavc.c
@@ -321,33 +321,35 @@ static int decode_new_packet(struct dec_audio *da)
struct demux_packet *mpkt = priv->packet;
if (!mpkt)
mpkt = demux_read_packet(da->header);
- if (!mpkt)
- return -1; // error or EOF
priv->packet = talloc_steal(priv, mpkt);
- int in_len = mpkt->len;
+ int in_len = mpkt ? mpkt->len : 0;
AVPacket pkt;
mp_set_av_packet(&pkt, mpkt, NULL);
- if (mpkt->pts != MP_NOPTS_VALUE) {
+ // If we don't have a PTS yet, use the first packet PTS we can get.
+ if (da->pts == MP_NOPTS_VALUE && mpkt && mpkt->pts != MP_NOPTS_VALUE) {
da->pts = mpkt->pts;
da->pts_offset = 0;
}
+
int got_frame = 0;
int ret = avcodec_decode_audio4(avctx, priv->avframe, &got_frame, &pkt);
- // At least "shorten" decodes sub-frames, instead of the whole packet.
- // At least "mpc8" can return 0 and wants the packet again next time.
- if (ret >= 0) {
- ret = FFMIN(ret, mpkt->len); // sanity check against decoder overreads
- mpkt->buffer += ret;
- mpkt->len -= ret;
- mpkt->pts = MP_NOPTS_VALUE; // don't reset PTS next time
- }
- if (mpkt->len == 0 || ret < 0) {
- talloc_free(mpkt);
- priv->packet = NULL;
+ if (mpkt) {
+ // At least "shorten" decodes sub-frames, instead of the whole packet.
+ // At least "mpc8" can return 0 and wants the packet again next time.
+ if (ret >= 0) {
+ ret = FFMIN(ret, mpkt->len); // sanity check against decoder overreads
+ mpkt->buffer += ret;
+ mpkt->len -= ret;
+ mpkt->pts = MP_NOPTS_VALUE; // don't reset PTS next time
+ }
+ if (mpkt->len == 0 || ret < 0) {
+ talloc_free(mpkt);
+ priv->packet = NULL;
+ }
}
// LATM may need many packets to find mux info
if (ret == AVERROR(EAGAIN))
@@ -357,7 +359,7 @@ static int decode_new_packet(struct dec_audio *da)
return -1;
}
if (!got_frame)
- return 0;
+ return mpkt ? 0 : -1; // -1: eof
if (setup_format(da) < 0)
return -1;
@@ -367,6 +369,12 @@ static int decode_new_packet(struct dec_audio *da)
for (int n = 0; n < priv->frame.num_planes; n++)
priv->frame.planes[n] = priv->avframe->data[n];
+ double out_pts = mp_pts_from_av(priv->avframe->pkt_pts, NULL);
+ if (out_pts != MP_NOPTS_VALUE) {
+ da->pts = out_pts;
+ da->pts_offset = 0;
+ }
+
mp_dbg(MSGT_DECAUDIO, MSGL_DBG2, "Decoded %d -> %d samples\n", in_len,
priv->frame.samples);
return 0;