summaryrefslogtreecommitdiffstats
path: root/libmpcodecs/ad_pcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmpcodecs/ad_pcm.c')
-rw-r--r--libmpcodecs/ad_pcm.c55
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,