diff options
Diffstat (limited to 'libmpcodecs/ad_pcm.c')
-rw-r--r-- | libmpcodecs/ad_pcm.c | 55 |
1 files changed, 51 insertions, 4 deletions
diff --git a/libmpcodecs/ad_pcm.c b/libmpcodecs/ad_pcm.c index 0dd50e0c65..29e78d69af 100644 --- a/libmpcodecs/ad_pcm.c +++ b/libmpcodecs/ad_pcm.c @@ -19,7 +19,9 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <stdbool.h> +#include "talloc.h" #include "config.h" #include "ad_internal.h" #include "libaf/af_format.h" @@ -33,6 +35,13 @@ static const ad_info_t info = { "" }; +struct ad_pcm_context { + unsigned char *buffer; + int buffer_pos; + int buffer_len; + int buffer_size; +}; + LIBAD_EXTERN(pcm) static int init(sh_audio_t * sh_audio) @@ -114,6 +123,7 @@ static int init(sh_audio_t * sh_audio) } if (!sh_audio->samplesize) // this would cause MPlayer to hang later sh_audio->samplesize = 2; + sh_audio->context = talloc_zero(NULL, struct ad_pcm_context); return 1; } @@ -125,12 +135,17 @@ static int preinit(sh_audio_t *sh) static void uninit(sh_audio_t *sh) { + talloc_free(sh->context); } static int control(sh_audio_t *sh, int cmd, void *arg, ...) { + struct ad_pcm_context *ctx = sh->context; int skip; switch (cmd) { + case ADCTRL_RESYNC_STREAM: + ctx->buffer_len = 0; + return true; case ADCTRL_SKIP_FRAME: skip = sh->i_bps / 16; skip = skip & (~3); @@ -143,13 +158,45 @@ 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) { - unsigned len = sh_audio->channels * sh_audio->samplesize; - len = (minlen + len - 1) / len * len; - if (len > maxlen) + int len = sh_audio->channels * sh_audio->samplesize; + minlen = (minlen + len - 1) / len * len; + if (minlen > maxlen) // if someone needs hundreds of channels adjust audio_out_minsize // based on channels in preinit() return -1; - len = demux_read_data(sh_audio->ds, buf, len); + + len = 0; + struct ad_pcm_context *ctx = sh_audio->context; + while (len < minlen) { + if (ctx->buffer_len - ctx->buffer_pos <= 0) { + double pts; + unsigned char *ptr; + int plen = ds_get_packet_pts(sh_audio->ds, &ptr, &pts); + if (plen < 0) + break; + if (ctx->buffer_size < plen) { + talloc_free(ctx->buffer); + ctx->buffer = talloc_size(ctx, plen); + ctx->buffer_size = plen; + } + memcpy(ctx->buffer, ptr, plen); + ctx->buffer_len = plen; + ctx->buffer_pos = 0; + if (pts != MP_NOPTS_VALUE) { + sh_audio->pts = pts; + sh_audio->pts_bytes = 0; + } + } + int from_stored = ctx->buffer_len - ctx->buffer_pos; + if (from_stored > minlen - len) + from_stored = minlen - len; + memcpy(buf + len, ctx->buffer + ctx->buffer_pos, from_stored); + ctx->buffer_pos += from_stored; + sh_audio->pts_bytes += from_stored; + len += from_stored; + } + if (len == 0) + len = -1; // The loop above only exits at error/EOF if (len > 0 && sh_audio->channels >= 5) { reorder_channel_nch(buf, AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT, |