Web lists-archives.com

[MPlayer-dev-eng] [PATCH] ad_spdif.c: Flush output buffer after processing frame, fixes audio stutter

I'm experiencing some trouble with S/PDIF pass-through in recent
versions of mplayer. The buffering behavior of lavf's IEC61937 muxer
seems to have changed some time ago and it does now call the write
callback only when its internal buffer is completely filled. ad_spdif
allocates 64k for the buffer and this is usually more than one frame's
worth of data.

Additionally, the lavf write callback doesn't really work in the way the
code in ad_spdif.c expects it to; the write callback cannot perform a
partial write and expect lavf code to handle this situation. It must
always process the full amount of data passed to it. The current write
callback however does sometimes perform a partial write and this will
result in some data being dropped from the output data stream,
ultimately leading to badly stuttering audio.

The patch adds a call to avio_flush() after passing each audio frame to
lavf to ensure that the write callback is never asked to process more
than one frame's worth of data, which is guaranteed to completely fit
into the output buffer so partial writes do not occur.

It also changes the code in the write callback to not attempt a partial
write and instead simply return an error if the data passed to it cannot
completely fit into the output buffer. (This second change is just for
consistency, the situation should never occur in practice.)

NB. At least in my setup, this bug is only observed with DTS and TrueHD
streams. For reasons I haven't looked further into, AC3 works fine even
without this fix.


--- libmpcodecs/ad_spdif.c.orig	2014-06-22 21:49:04.810573656 +0200
+++ libmpcodecs/ad_spdif.c	2014-06-23 20:42:26.657459219 +0200
@@ -55,13 +55,13 @@
 static int write_packet(void *p, uint8_t *buf, int buf_size)
-    int len;
     struct spdifContext *ctx = p;
-    len = FFMIN(buf_size, ctx->out_buffer_size -ctx->out_buffer_len);
-    memcpy(&ctx->out_buffer[ctx->out_buffer_len], buf, len);
-    ctx->out_buffer_len += len;
-    return len;
+    if (ctx->out_buffer_size - ctx->out_buffer_len < buf_size)
+        return -1;
+    memcpy(&ctx->out_buffer[ctx->out_buffer_len], buf, buf_size);
+    ctx->out_buffer_len += buf_size;
+    return buf_size;
 static int64_t seek(void *p, int64_t offset, int whence)
@@ -266,6 +266,7 @@
             sh->pts_bytes = 0;
         ret = lavf_ctx->oformat->write_packet(lavf_ctx, &pkt);
+        avio_flush(lavf_ctx->pb);
         if (ret < 0)

Jan Andres <jandres@xxxxxxx>
MPlayer-dev-eng mailing list