1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
From a8dd9e056114a80d11c77efbdfe4b22610f452db Mon Sep 17 00:00:00 2001
From: Anssi Hannula <anssi.hannula@iki.fi>
Date: Mon, 27 Dec 2010 05:16:54 +0200
Subject: [PATCH] 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.
---
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), or
c) have two different logical muxers.
---
libavformat/spdifenc.c | 35 +++++++++++++++++++++++++++++------
1 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/libavformat/spdifenc.c b/libavformat/spdifenc.c
index 3eea31e..9b0001c 100644
--- a/libavformat/spdifenc.c
+++ b/libavformat/spdifenc.c
@@ -49,6 +49,7 @@
#include "libavcodec/ac3.h"
#include "libavcodec/dca.h"
#include "libavcodec/aacadtsdec.h"
+#include "libavutil/opt.h"
typedef struct IEC61937Context {
enum IEC61937DataType data_type;///< burst info - reference to type of payload of the data-burst
@@ -68,11 +69,22 @@ typedef struct IEC61937Context {
int hd_buf_count; ///< number of frames in the hd audio buffer
int hd_buf_filled; ///< amount of bytes in the hd audio buffer
+ /* AVOptions: */
+#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
int (*header_info) (AVFormatContext *s, AVPacket *pkt);
} 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" },
+{ NULL },
+};
+
+static const AVClass class = { "spdif", av_default_item_name, options, LIBAVUTIL_VERSION_INT };
static int spdif_header_ac3(AVFormatContext *s, AVPacket *pkt)
{
@@ -330,6 +342,15 @@ static int spdif_write_trailer(AVFormatContext *s)
return 0;
}
+static void spdif_put_16(struct AVFormatContext *s, unsigned int val)
+{
+ IEC61937Context *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)
{
IEC61937Context *ctx = s->priv_data;
@@ -354,13 +375,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);
@@ -370,8 +391,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(s, ctx->out_buf[ctx->out_bytes - 1] << 8);
put_nbyte(s->pb, 0, padding);
@@ -393,4 +415,5 @@ AVOutputFormat ff_spdif_muxer = {
spdif_write_header,
spdif_write_packet,
spdif_write_trailer,
+ .priv_class = &class,
};
--
1.7.3
|