diff options
author | Uoti Urpala <uau@mplayer2.org> | 2011-08-21 22:47:59 +0300 |
---|---|---|
committer | Uoti Urpala <uau@mplayer2.org> | 2011-08-21 22:47:59 +0300 |
commit | 68df2b2b3f9a3310e39b509b2ed7208dc0e95123 (patch) | |
tree | 58ad6ddab5c4644de7e1c18b4f7d2b4bbfc9816c /libmpcodecs/ad_ffmpeg.c | |
parent | da2b884c703d6cf7ef6ee3d496d1ba884e62dd13 (diff) | |
download | mpv-68df2b2b3f9a3310e39b509b2ed7208dc0e95123.tar.bz2 mpv-68df2b2b3f9a3310e39b509b2ed7208dc0e95123.tar.xz |
ad_ffmpeg: handle timing for partially decoded packets better
At least the libavcodec WavPack decoder can return output for an audio
frame in multiple parts and return 0 bytes input consumed for the
initial parts. Timing info was not set correctly in this case:
sh_audio->pts and pts_bytes were reset each time when decoding more
from the packet, as if the packet had been new (ds_get_packet_pts()
has a check to return MP_NOPTS_VALUE if the packet has already been
partially read, but that didn't trigger since libavcodec returned
exactly 0 bytes read so the demuxer-visible packet state didn't
change).
Add a field to keep track of whether a packet has already been decoded
from, and don't reset timing info again if so. Adding the field
requires adding a decoder context to store it (there wasn't one
before).
BTW the WavPack decoder behavior and avcodec_decode_audio3()
documentation don't match - the documentation says the return value is
"zero if no frame data was decompressed (used) from the input
AVPacket", while the decoder DOES return some frame data which comes
from the input packet.
Diffstat (limited to 'libmpcodecs/ad_ffmpeg.c')
-rw-r--r-- | libmpcodecs/ad_ffmpeg.c | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/libmpcodecs/ad_ffmpeg.c b/libmpcodecs/ad_ffmpeg.c index cbd18fddaf..e8851cbf63 100644 --- a/libmpcodecs/ad_ffmpeg.c +++ b/libmpcodecs/ad_ffmpeg.c @@ -19,9 +19,12 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <stdbool.h> #include <libavcodec/avcodec.h> +#include "talloc.h" + #include "config.h" #include "mp_msg.h" #include "options.h" @@ -42,6 +45,11 @@ static const ad_info_t info = LIBAD_EXTERN(ffmpeg) +struct priv { + AVCodecContext *avctx; + bool old_packet; +}; + static int preinit(sh_audio_t *sh) { sh->audio_out_minsize = AVCODEC_MAX_AUDIO_FRAME_SIZE; @@ -108,8 +116,10 @@ static int init(sh_audio_t *sh_audio) return 0; } + struct priv *ctx = talloc_zero(NULL, struct priv); + sh_audio->context = ctx; lavc_context = avcodec_alloc_context(); - sh_audio->context = lavc_context; + ctx->avctx = lavc_context; lavc_context->drc_scale = opts->drc_level; lavc_context->sample_rate = sh_audio->samplerate; @@ -195,21 +205,24 @@ static int init(sh_audio_t *sh_audio) static void uninit(sh_audio_t *sh) { - AVCodecContext *lavc_context = sh->context; + struct priv *ctx = sh->context; + AVCodecContext *lavc_context = ctx->avctx; if (avcodec_close(lavc_context) < 0) mp_tmsg(MSGT_DECVIDEO, MSGL_ERR, "Could not close codec.\n"); av_freep(&lavc_context->extradata); av_freep(&lavc_context); + talloc_free(ctx); } static int control(sh_audio_t *sh, int cmd, void *arg, ...) { - AVCodecContext *lavc_context = sh->context; + struct priv *ctx = sh->context; switch (cmd) { case ADCTRL_RESYNC_STREAM: - avcodec_flush_buffers(lavc_context); + avcodec_flush_buffers(ctx->avctx); ds_clear_parser(sh->ds); + ctx->old_packet = false; return CONTROL_TRUE; } return CONTROL_UNKNOWN; @@ -218,7 +231,8 @@ static int control(sh_audio_t *sh, int cmd, void *arg, ...) static int decode_audio(sh_audio_t *sh_audio, unsigned char *buf, int minlen, int maxlen) { - AVCodecContext *avctx = sh_audio->context; + struct priv *ctx = sh_audio->context; + AVCodecContext *avctx = ctx->avctx; unsigned char *start = NULL; int y, len = -1; @@ -241,7 +255,7 @@ static int decode_audio(sh_audio_t *sh_audio, unsigned char *buf, int minlen, av_init_packet(&pkt); pkt.data = start; pkt.size = x; - if (pts != MP_NOPTS_VALUE) { + if (pts != MP_NOPTS_VALUE && !ctx->old_packet) { sh_audio->pts = pts; sh_audio->pts_bytes = 0; } @@ -253,8 +267,10 @@ static int decode_audio(sh_audio_t *sh_audio, unsigned char *buf, int minlen, mp_msg(MSGT_DECAUDIO, MSGL_V, "lavc_audio: error\n"); break; } - if (!sh_audio->parser && y < x) + if (!sh_audio->parser && y < x) { sh_audio->ds->buffer_pos += y - x; // put back data (HACK!) + ctx->old_packet = true; + } if (len2 > 0) { if (avctx->channels >= 5) { int samplesize = av_get_bits_per_sample_format( |