summaryrefslogtreecommitdiffstats
path: root/libmpcodecs
diff options
context:
space:
mode:
authorUoti Urpala <uau@mplayer2.org>2011-08-21 22:47:59 +0300
committerUoti Urpala <uau@mplayer2.org>2011-08-21 22:47:59 +0300
commit68df2b2b3f9a3310e39b509b2ed7208dc0e95123 (patch)
tree58ad6ddab5c4644de7e1c18b4f7d2b4bbfc9816c /libmpcodecs
parentda2b884c703d6cf7ef6ee3d496d1ba884e62dd13 (diff)
downloadmpv-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')
-rw-r--r--libmpcodecs/ad_ffmpeg.c30
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(