summaryrefslogtreecommitdiffstats
path: root/contrib/ffmpeg/A02-truehd-channel-order.patch
blob: a3d7677554f6681b840584e1371baa55ec9835fd (plain)
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
diff --git a/libavcodec/mlp_parser.c b/libavcodec/mlp_parser.c
index d1a3dc1..31c79c9 100644
--- a/libavcodec/mlp_parser.c
+++ b/libavcodec/mlp_parser.c
@@ -126,7 +126,7 @@ static uint64_t truehd_layout(int chanmap)
 
 int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb)
 {
-    int ratebits;
+    int ratebits, channel_arrangement;
     uint16_t checksum;
 
     assert(get_bits_count(gb) == 0);
@@ -157,7 +157,9 @@ int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb)
 
         skip_bits(gb, 11);
 
-        mh->channels_mlp = get_bits(gb, 5);
+        channel_arrangement    = get_bits(gb, 5);
+        mh->channels_mlp       = mlp_channels[channel_arrangement];
+        mh->channel_layout_mlp = mlp_layout[channel_arrangement];
     } else if (mh->stream_type == 0xba) {
         mh->group1_bits = 24; // TODO: Is this information actually conveyed anywhere?
         mh->group2_bits = 0;
@@ -168,11 +170,15 @@ int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb)
 
         skip_bits(gb, 8);
 
-        mh->channels_thd_stream1 = get_bits(gb, 5);
+        channel_arrangement            = get_bits(gb, 5);
+        mh->channels_thd_stream1       = truehd_channels(channel_arrangement);
+        mh->channel_layout_thd_stream1 = truehd_layout(channel_arrangement);
 
         skip_bits(gb, 2);
 
-        mh->channels_thd_stream2 = get_bits(gb, 13);
+        channel_arrangement            = get_bits(gb, 13);
+        mh->channels_thd_stream2       = truehd_channels(channel_arrangement);
+        mh->channel_layout_thd_stream2 = truehd_layout(channel_arrangement);
     } else
         return AVERROR_INVALIDDATA;
 
@@ -316,16 +322,16 @@ static int mlp_parse(AVCodecParserContext *s,
 
         if (mh.stream_type == 0xbb) {
             /* MLP stream */
-            avctx->channels = mlp_channels[mh.channels_mlp];
-            avctx->channel_layout = mlp_layout[mh.channels_mlp];
+            avctx->channels       = mh.channels_mlp;
+            avctx->channel_layout = mh.channel_layout_mlp;
         } else { /* mh.stream_type == 0xba */
             /* TrueHD stream */
             if (mh.channels_thd_stream2) {
-                avctx->channels = truehd_channels(mh.channels_thd_stream2);
-                avctx->channel_layout = truehd_layout(mh.channels_thd_stream2);
+                avctx->channels       = mh.channels_thd_stream2;
+                avctx->channel_layout = mh.channel_layout_thd_stream2;
             } else {
-                avctx->channels = truehd_channels(mh.channels_thd_stream1);
-                avctx->channel_layout = truehd_layout(mh.channels_thd_stream1);
+                avctx->channels       = mh.channels_thd_stream1;
+                avctx->channel_layout = mh.channel_layout_thd_stream1;
             }
         }
 
diff --git a/libavcodec/mlp_parser.h b/libavcodec/mlp_parser.h
index 35bb312..e874426 100644
--- a/libavcodec/mlp_parser.h
+++ b/libavcodec/mlp_parser.h
@@ -31,25 +31,28 @@
 
 typedef struct MLPHeaderInfo
 {
-    int stream_type;            ///< 0xBB for MLP, 0xBA for TrueHD
+    int stream_type;                        ///< 0xBB for MLP, 0xBA for TrueHD
 
-    int group1_bits;            ///< The bit depth of the first substream
-    int group2_bits;            ///< Bit depth of the second substream (MLP only)
+    int group1_bits;                        ///< The bit depth of the first substream
+    int group2_bits;                        ///< Bit depth of the second substream (MLP only)
 
-    int group1_samplerate;      ///< Sample rate of first substream
-    int group2_samplerate;      ///< Sample rate of second substream (MLP only)
+    int group1_samplerate;                  ///< Sample rate of first substream
+    int group2_samplerate;                  ///< Sample rate of second substream (MLP only)
 
-    int channels_mlp;           ///< Channel arrangement for MLP streams
-    int channels_thd_stream1;   ///< Channel arrangement for substream 1 of TrueHD streams (5.1)
-    int channels_thd_stream2;   ///< Channel arrangement for substream 2 of TrueHD streams (7.1)
+    int channels_mlp;                       ///< Channel count for MLP streams
+    int channels_thd_stream1;               ///< Channel count for substream 1 of TrueHD streams ("6-channel presentation")
+    int channels_thd_stream2;               ///< Channel count for substream 2 of TrueHD streams ("8-channel presentation")
+    uint64_t channel_layout_mlp;            ///< Channel layout for MLP streams
+    uint64_t channel_layout_thd_stream1;    ///< Channel layout for substream 1 of TrueHD streams ("6-channel presentation")
+    uint64_t channel_layout_thd_stream2;    ///< Channel layout for substream 2 of TrueHD streams ("8-channel presentation")
 
-    int access_unit_size;       ///< Number of samples per coded frame
-    int access_unit_size_pow2;  ///< Next power of two above number of samples per frame
+    int access_unit_size;                   ///< Number of samples per coded frame
+    int access_unit_size_pow2;              ///< Next power of two above number of samples per frame
 
-    int is_vbr;                 ///< Stream is VBR instead of CBR
-    int peak_bitrate;           ///< Peak bitrate for VBR, actual bitrate (==peak) for CBR
+    int is_vbr;                             ///< Stream is VBR instead of CBR
+    int peak_bitrate;                       ///< Peak bitrate for VBR, actual bitrate (==peak) for CBR
 
-    int num_substreams;         ///< Number of substreams within stream
+    int num_substreams;                     ///< Number of substreams within stream
 } MLPHeaderInfo;
 
 
diff --git a/libavcodec/mlpdec.c b/libavcodec/mlpdec.c
index 3852f6e..f8c647a 100644
--- a/libavcodec/mlpdec.c
+++ b/libavcodec/mlpdec.c
@@ -28,6 +28,7 @@
 
 #include "avcodec.h"
 #include "libavutil/intreadwrite.h"
+#include "libavutil/channel_layout.h"
 #include "get_bits.h"
 #include "internal.h"
 #include "libavutil/crc.h"
@@ -56,6 +57,8 @@ typedef struct SubStream {
     uint8_t     max_matrix_channel;
     /// For each channel output by the matrix, the output channel to map it to
     uint8_t     ch_assign[MAX_CHANNELS];
+    /// The channel layout for this substream
+    uint64_t    ch_layout;
 
     /// Channel coding parameters for channels in the substream
     ChannelParams channel_params[MAX_CHANNELS];
@@ -146,6 +149,36 @@ typedef struct MLPDecodeContext {
     MLPDSPContext dsp;
 } MLPDecodeContext;
 
+static const uint64_t thd_channel_order[] = {
+    AV_CH_FRONT_LEFT, AV_CH_FRONT_RIGHT,                     // LR
+    AV_CH_FRONT_CENTER,                                      // C
+    AV_CH_LOW_FREQUENCY,                                     // LFE
+    AV_CH_SIDE_LEFT, AV_CH_SIDE_RIGHT,                       // LRs
+    AV_CH_TOP_FRONT_LEFT, AV_CH_TOP_FRONT_RIGHT,             // LRvh
+    AV_CH_FRONT_LEFT_OF_CENTER, AV_CH_FRONT_RIGHT_OF_CENTER, // LRc
+    AV_CH_BACK_LEFT, AV_CH_BACK_RIGHT,                       // LRrs
+    AV_CH_BACK_CENTER,                                       // Cs
+    AV_CH_TOP_CENTER,                                        // Ts
+    AV_CH_SURROUND_DIRECT_LEFT, AV_CH_SURROUND_DIRECT_RIGHT, // LRsd
+    AV_CH_WIDE_LEFT, AV_CH_WIDE_RIGHT,                       // LRw
+    AV_CH_TOP_FRONT_CENTER,                                  // Cvh
+    AV_CH_LOW_FREQUENCY_2,                                   // LFE2
+};
+
+static uint64_t thd_channel_layout_extract_channel(uint64_t channel_layout,
+                                                   int index)
+{
+    int i;
+
+    if (av_get_channel_layout_nb_channels(channel_layout) <= index)
+        return 0;
+
+    for (i = 0; i < FF_ARRAY_ELEMS(thd_channel_order); i++)
+        if (channel_layout & thd_channel_order[i] && !index--)
+            return thd_channel_order[i];
+    return 0;
+}
+
 static VLC huff_vlc[3];
 
 /** Initialize static data, constant between all invocations of the codec. */
@@ -325,6 +358,24 @@ static int read_major_sync(MLPDecodeContext *m, GetBitContext *gb)
     for (substr = 0; substr < MAX_SUBSTREAMS; substr++)
         m->substream[substr].restart_seen = 0;
 
+    /* Set the layout for each substream. When there's more than one, the first
+     * substream is Stereo. Subsequent substreams' layouts are indicated in the
+     * major sync. */
+    if (m->avctx->codec_id == AV_CODEC_ID_MLP) {
+        if ((substr = (mh.num_substreams > 1)))
+            m->substream[0].ch_layout = AV_CH_LAYOUT_STEREO;
+        m->substream[substr].ch_layout = mh.channel_layout_mlp;
+    } else {
+        if ((substr = (mh.num_substreams > 1)))
+            m->substream[0].ch_layout = AV_CH_LAYOUT_STEREO;
+        if (mh.num_substreams > 2)
+            if (mh.channel_layout_thd_stream2)
+                m->substream[2].ch_layout = mh.channel_layout_thd_stream2;
+            else
+                m->substream[2].ch_layout = mh.channel_layout_thd_stream1;
+        m->substream[substr].ch_layout = mh.channel_layout_thd_stream1;
+    }
+
     return 0;
 }
 
@@ -426,6 +477,12 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp,
 
     for (ch = 0; ch <= s->max_matrix_channel; ch++) {
         int ch_assign = get_bits(gbp, 6);
+        if (m->avctx->codec_id == AV_CODEC_ID_TRUEHD) {
+            uint64_t channel = thd_channel_layout_extract_channel(s->ch_layout,
+                                                                  ch_assign);
+            ch_assign = av_get_channel_layout_channel_index(s->ch_layout,
+                                                            channel);
+        }
         if (ch_assign > s->max_matrix_channel) {
             av_log_ask_for_sample(m->avctx,
                    "Assignment of matrix channel %d to invalid output channel %d.\n",