[FFmpeg-devel] [PATCH 06/10] spdifenc: fix byte order on big-endian systems

Anssi Hannula anssi.hannula
Wed Dec 29 06:06:39 CET 2010


There is a check for HAVE_BIGENDIAN when outputting the IEC 61937
stream. On big-endian systems the payload data is not byteswapped,
causing in effect the outputted payload data to be in a different byte
order on big-endian than on little-endian systems.

However, the IEC 61937 preamble (and the final odd byte if present) is
always outputted in the same byte order. This means that on big-endian
systems the headers have a different byte order than the payload,
preventing useful use of the output.

Fix that by outputting the data in a format suitable for sending to an
audio device in S16LE format by default. Output as big-endian (S16BE)
is added as an AVOption. This makes the muxer output the same on all
archs by default.

---

Other ways to fix this would be to
a) simply always output in little-endian format, or
b) always output in native-endian format (i.e. different muxer output
depending on arch).

Please comment if you believe that one of those would be better.

 libavformat/spdifenc.c |   26 ++++++++++++++++++++------
 1 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/libavformat/spdifenc.c b/libavformat/spdifenc.c
index a2683b9..870a543 100644
--- a/libavformat/spdifenc.c
+++ b/libavformat/spdifenc.c
@@ -76,6 +76,8 @@ typedef struct IEC958Context {
     /* AVOptions: */
     int dtshd_rate;
     int dtshd_fallback;
+#define SPDIF_FLAG_BIGENDIAN    0x01
+    int spdif_flags;
 
     /// function, which generates codec dependent header information.
     /// Sets data_type and pkt_offset, and length_code, out_bytes, out_buf if necessary
@@ -83,6 +85,8 @@ typedef struct IEC958Context {
 } IEC958Context;
 
 static const AVOption options[] = {
+{ "spdif_flags", "IEC 61937 encapsulation flags", offsetof(IEC958Context, spdif_flags), FF_OPT_TYPE_FLAGS, 0, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "spdif_flags" },
+{ "be", "output in big-endian format (for use as s16be)", 0, FF_OPT_TYPE_CONST, SPDIF_FLAG_BIGENDIAN, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "spdif_flags" },
 { "dtshd_rate", "mux complete DTS frames in HD mode at the specified IEC958 rate (in Hz, default 0=disabled)", offsetof(IEC958Context, dtshd_rate), FF_OPT_TYPE_INT, 0, 0, 768000, AV_OPT_FLAG_ENCODING_PARAM },
 { "dtshd_fallback_time", "min secs to strip HD for after an overflow (-1: till the end)", offsetof(IEC958Context, dtshd_fallback), FF_OPT_TYPE_INT, 60, -1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
 { NULL },
@@ -476,6 +480,15 @@ static int spdif_write_trailer(AVFormatContext *s)
     return 0;
 }
 
+static void spdif_put_16(struct AVFormatContext *s, unsigned int val)
+{
+    IEC958Context *ctx = s->priv_data;
+    if (ctx->spdif_flags & SPDIF_FLAG_BIGENDIAN)
+        put_be16(s->pb, val);
+    else
+        put_le16(s->pb, val);
+}
+
 static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt)
 {
     IEC958Context *ctx = s->priv_data;
@@ -500,13 +513,13 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt)
     }
 
     if (ctx->use_preamble) {
-    put_le16(s->pb, SYNCWORD1);      //Pa
-    put_le16(s->pb, SYNCWORD2);      //Pb
-    put_le16(s->pb, ctx->data_type); //Pc
-    put_le16(s->pb, ctx->length_code);//Pd
+        spdif_put_16(s, SYNCWORD1);       //Pa
+        spdif_put_16(s, SYNCWORD2);       //Pb
+        spdif_put_16(s, ctx->data_type);  //Pc
+        spdif_put_16(s, ctx->length_code);//Pd
     }
 
-    if (HAVE_BIGENDIAN ^ ctx->extra_bswap) {
+    if (ctx->extra_bswap ^ (ctx->spdif_flags & SPDIF_FLAG_BIGENDIAN)) {
     put_buffer(s->pb, ctx->out_buf, ctx->out_bytes & ~1);
     } else {
     av_fast_malloc(&ctx->buffer, &ctx->buffer_size, ctx->out_bytes + FF_INPUT_BUFFER_PADDING_SIZE);
@@ -516,8 +529,9 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt)
     put_buffer(s->pb, ctx->buffer, ctx->out_bytes & ~1);
     }
 
+    /* a final lone byte has to be MSB aligned on BE (and thus LSB on LE) */
     if (ctx->out_bytes & 1)
-        put_be16(s->pb, ctx->out_buf[ctx->out_bytes - 1]);
+        spdif_put_16(s, ctx->out_buf[ctx->out_bytes - 1] << 8);
 
     for (; padding > 0; padding--)
         put_be16(s->pb, 0);
-- 
1.7.3




More information about the ffmpeg-devel mailing list