From 57f2c9aed9fecbb1e6798ec33613141afe74fd31 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 12 Feb 2011 15:57:01 +0200 Subject: spdifenc: fix byte order on big-endian systems 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. Signed-off-by: Janne Grunau --- libavformat/spdifenc.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'libavformat/spdifenc.c') diff --git a/libavformat/spdifenc.c b/libavformat/spdifenc.c index 3c6fd73dbe..adc245a331 100644 --- a/libavformat/spdifenc.c +++ b/libavformat/spdifenc.c @@ -76,6 +76,8 @@ typedef struct IEC61937Context { /* 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 IEC61937Context { } IEC61937Context; static const AVOption options[] = { +{ "spdif_flags", "IEC 61937 encapsulation flags", offsetof(IEC61937Context, 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(IEC61937Context, 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, default 60)", offsetof(IEC61937Context, dtshd_fallback), FF_OPT_TYPE_INT, 60, -1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, { NULL }, @@ -477,6 +481,15 @@ static int spdif_write_trailer(AVFormatContext *s) return 0; } +static av_always_inline void spdif_put_16(IEC61937Context *ctx, + ByteIOContext *pb, unsigned int val) +{ + if (ctx->spdif_flags & SPDIF_FLAG_BIGENDIAN) + put_be16(pb, val); + else + put_le16(pb, val); +} + static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt) { IEC61937Context *ctx = s->priv_data; @@ -501,13 +514,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(ctx, s->pb, SYNCWORD1); //Pa + spdif_put_16(ctx, s->pb, SYNCWORD2); //Pb + spdif_put_16(ctx, s->pb, ctx->data_type); //Pc + spdif_put_16(ctx, s->pb, 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); @@ -517,8 +530,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 */ if (ctx->out_bytes & 1) - put_be16(s->pb, ctx->out_buf[ctx->out_bytes - 1]); + spdif_put_16(ctx, s->pb, ctx->out_buf[ctx->out_bytes - 1] << 8); put_nbyte(s->pb, 0, padding); -- cgit v1.2.3