Commit 57f2c9ae authored by Anssi Hannula's avatar Anssi Hannula Committed by Janne Grunau

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: 's avatarJanne Grunau <janne-ffmpeg@jannau.net>
parent 482d98f6
...@@ -76,6 +76,8 @@ typedef struct IEC61937Context { ...@@ -76,6 +76,8 @@ typedef struct IEC61937Context {
/* AVOptions: */ /* AVOptions: */
int dtshd_rate; int dtshd_rate;
int dtshd_fallback; int dtshd_fallback;
#define SPDIF_FLAG_BIGENDIAN 0x01
int spdif_flags;
/// function, which generates codec dependent header information. /// function, which generates codec dependent header information.
/// Sets data_type and pkt_offset, and length_code, out_bytes, out_buf if necessary /// Sets data_type and pkt_offset, and length_code, out_bytes, out_buf if necessary
...@@ -83,6 +85,8 @@ typedef struct IEC61937Context { ...@@ -83,6 +85,8 @@ typedef struct IEC61937Context {
} IEC61937Context; } IEC61937Context;
static const AVOption options[] = { 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_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 }, { "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 }, { NULL },
...@@ -477,6 +481,15 @@ static int spdif_write_trailer(AVFormatContext *s) ...@@ -477,6 +481,15 @@ static int spdif_write_trailer(AVFormatContext *s)
return 0; 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) static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt)
{ {
IEC61937Context *ctx = s->priv_data; IEC61937Context *ctx = s->priv_data;
...@@ -501,13 +514,13 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt) ...@@ -501,13 +514,13 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt)
} }
if (ctx->use_preamble) { if (ctx->use_preamble) {
put_le16(s->pb, SYNCWORD1); //Pa spdif_put_16(ctx, s->pb, SYNCWORD1); //Pa
put_le16(s->pb, SYNCWORD2); //Pb spdif_put_16(ctx, s->pb, SYNCWORD2); //Pb
put_le16(s->pb, ctx->data_type); //Pc spdif_put_16(ctx, s->pb, ctx->data_type); //Pc
put_le16(s->pb, ctx->length_code);//Pd 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); put_buffer(s->pb, ctx->out_buf, ctx->out_bytes & ~1);
} else { } else {
av_fast_malloc(&ctx->buffer, &ctx->buffer_size, ctx->out_bytes + FF_INPUT_BUFFER_PADDING_SIZE); 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) ...@@ -517,8 +530,9 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt)
put_buffer(s->pb, ctx->buffer, ctx->out_bytes & ~1); put_buffer(s->pb, ctx->buffer, ctx->out_bytes & ~1);
} }
/* a final lone byte has to be MSB aligned */
if (ctx->out_bytes & 1) 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); put_nbyte(s->pb, 0, padding);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment