1 /*
2  * Copyright (c) 2011 Justin Ruggles
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * mov 'chan' tag reading/writing.
23  * @author Justin Ruggles
24  */
25 
26 #include <stdint.h>
27 
28 #include "libavutil/channel_layout.h"
29 #include "libavcodec/codec_id.h"
30 #include "mov_chan.h"
31 
32 struct MovChannelLayoutMap {
33     uint32_t tag;
34     uint64_t layout;
35 };
36 
37 static const struct MovChannelLayoutMap mov_ch_layout_map_misc[] = {
38     { MOV_CH_LAYOUT_USE_DESCRIPTIONS,   0 },
39     { MOV_CH_LAYOUT_USE_BITMAP,         0 },
40     { MOV_CH_LAYOUT_DISCRETEINORDER,    0 },
41     { MOV_CH_LAYOUT_UNKNOWN,            0 },
42     { MOV_CH_LAYOUT_TMH_10_2_STD,       0 }, // L,   R,  C,    Vhc, Lsd, Rsd,
43                                              // Ls,  Rs, Vhl,  Vhr, Lw,  Rw,
44                                              // Csd, Cs, LFE1, LFE2
45     { MOV_CH_LAYOUT_TMH_10_2_FULL,      0 }, // L,   R,  C,    Vhc,  Lsd, Rsd,
46                                              // Ls,  Rs, Vhl,  Vhr,  Lw,  Rw,
47                                              // Csd, Cs, LFE1, LFE2, Lc,  Rc,
48                                              // HI,  VI, Haptic
49     { 0, 0 },
50 };
51 
52 static const struct MovChannelLayoutMap mov_ch_layout_map_1ch[] = {
53     { MOV_CH_LAYOUT_MONO,               AV_CH_LAYOUT_MONO }, // C
54     { 0, 0 },
55 };
56 
57 static const struct MovChannelLayoutMap mov_ch_layout_map_2ch[] = {
58     { MOV_CH_LAYOUT_STEREO,             AV_CH_LAYOUT_STEREO         }, // L, R
59     { MOV_CH_LAYOUT_STEREOHEADPHONES,   AV_CH_LAYOUT_STEREO         }, // L, R
60     { MOV_CH_LAYOUT_BINAURAL,           AV_CH_LAYOUT_STEREO         }, // L, R
61     { MOV_CH_LAYOUT_MIDSIDE,            AV_CH_LAYOUT_STEREO         }, // C, sides
62     { MOV_CH_LAYOUT_XY,                 AV_CH_LAYOUT_STEREO         }, // X (left), Y (right)
63 
64     { MOV_CH_LAYOUT_MATRIXSTEREO,       AV_CH_LAYOUT_STEREO_DOWNMIX }, // Lt, Rt
65 
66     { MOV_CH_LAYOUT_AC3_1_0_1,          AV_CH_LAYOUT_MONO |            // C, LFE
67                                         AV_CH_LOW_FREQUENCY         },
68     { 0, 0 },
69 };
70 
71 static const struct MovChannelLayoutMap mov_ch_layout_map_3ch[] = {
72     { MOV_CH_LAYOUT_MPEG_3_0_A,         AV_CH_LAYOUT_SURROUND }, // L, R, C
73     { MOV_CH_LAYOUT_MPEG_3_0_B,         AV_CH_LAYOUT_SURROUND }, // C, L, R
74     { MOV_CH_LAYOUT_AC3_3_0,            AV_CH_LAYOUT_SURROUND }, // L, C, R
75 
76     { MOV_CH_LAYOUT_ITU_2_1,            AV_CH_LAYOUT_2_1      }, // L, R, Cs
77 
78     { MOV_CH_LAYOUT_DVD_4,              AV_CH_LAYOUT_2POINT1  }, // L, R, LFE
79     { 0, 0 },
80 };
81 
82 static const struct MovChannelLayoutMap mov_ch_layout_map_4ch[] = {
83     { MOV_CH_LAYOUT_AMBISONIC_B_FORMAT, 0 },                    // W, X, Y, Z
84 
85     { MOV_CH_LAYOUT_QUADRAPHONIC,       AV_CH_LAYOUT_QUAD    }, // L, R, Rls, Rrs
86 
87     { MOV_CH_LAYOUT_MPEG_4_0_A,         AV_CH_LAYOUT_4POINT0 }, // L, R, C, Cs
88     { MOV_CH_LAYOUT_MPEG_4_0_B,         AV_CH_LAYOUT_4POINT0 }, // C, L, R, Cs
89     { MOV_CH_LAYOUT_AC3_3_1,            AV_CH_LAYOUT_4POINT0 }, // L, C, R, Cs
90 
91     { MOV_CH_LAYOUT_ITU_2_2,            AV_CH_LAYOUT_2_2     }, // L, R, Ls, Rs
92 
93     { MOV_CH_LAYOUT_DVD_5,              AV_CH_LAYOUT_2_1 |      // L, R, LFE, Cs
94                                         AV_CH_LOW_FREQUENCY  },
95     { MOV_CH_LAYOUT_AC3_2_1_1,          AV_CH_LAYOUT_2_1 |      // L, R, Cs, LFE
96                                         AV_CH_LOW_FREQUENCY  },
97 
98     { MOV_CH_LAYOUT_DVD_10,             AV_CH_LAYOUT_3POINT1 }, // L, R, C, LFE
99     { MOV_CH_LAYOUT_AC3_3_0_1,          AV_CH_LAYOUT_3POINT1 }, // L, C, R, LFE
100     { MOV_CH_LAYOUT_DTS_3_1,            AV_CH_LAYOUT_3POINT1 }, // C, L, R, LFE
101     { 0, 0 },
102 };
103 
104 static const struct MovChannelLayoutMap mov_ch_layout_map_5ch[] = {
105     { MOV_CH_LAYOUT_PENTAGONAL,         AV_CH_LAYOUT_5POINT0_BACK }, // L, R, Rls, Rrs, C
106 
107     { MOV_CH_LAYOUT_MPEG_5_0_A,         AV_CH_LAYOUT_5POINT0 },      // L, R, C,  Ls, Rs
108     { MOV_CH_LAYOUT_MPEG_5_0_B,         AV_CH_LAYOUT_5POINT0 },      // L, R, Ls, Rs, C
109     { MOV_CH_LAYOUT_MPEG_5_0_C,         AV_CH_LAYOUT_5POINT0 },      // L, C, R,  Ls, Rs
110     { MOV_CH_LAYOUT_MPEG_5_0_D,         AV_CH_LAYOUT_5POINT0 },      // C, L, R,  Ls, Rs
111 
112     { MOV_CH_LAYOUT_DVD_6,              AV_CH_LAYOUT_2_2 |           // L, R, LFE, Ls, Rs
113                                         AV_CH_LOW_FREQUENCY },
114     { MOV_CH_LAYOUT_DVD_18,             AV_CH_LAYOUT_2_2 |           // L, R, Ls, Rs, LFE
115                                         AV_CH_LOW_FREQUENCY },
116 
117     { MOV_CH_LAYOUT_DVD_11,             AV_CH_LAYOUT_4POINT1 },      // L, R, C, LFE, Cs
118     { MOV_CH_LAYOUT_AC3_3_1_1,          AV_CH_LAYOUT_4POINT1 },      // L, C, R, Cs,  LFE
119     { MOV_CH_LAYOUT_DTS_4_1,            AV_CH_LAYOUT_4POINT1 },      // C, L, R, Cs,  LFE
120     { 0, 0 },
121 };
122 
123 static const struct MovChannelLayoutMap mov_ch_layout_map_6ch[] = {
124     { MOV_CH_LAYOUT_HEXAGONAL,          AV_CH_LAYOUT_HEXAGONAL },      // L, R,  Rls, Rrs, C,   Cs
125     { MOV_CH_LAYOUT_DTS_6_0_C,          AV_CH_LAYOUT_HEXAGONAL },      // C, Cs, L,   R,   Rls, Rrs
126 
127     { MOV_CH_LAYOUT_MPEG_5_1_A,         AV_CH_LAYOUT_5POINT1 },        // L, R, C,  LFE, Ls, Rs
128     { MOV_CH_LAYOUT_MPEG_5_1_B,         AV_CH_LAYOUT_5POINT1 },        // L, R, Ls, Rs,  C,  LFE
129     { MOV_CH_LAYOUT_MPEG_5_1_C,         AV_CH_LAYOUT_5POINT1 },        // L, C, R,  Ls,  Rs, LFE
130     { MOV_CH_LAYOUT_MPEG_5_1_D,         AV_CH_LAYOUT_5POINT1 },        // C, L, R,  Ls,  Rs, LFE
131 
132     { MOV_CH_LAYOUT_AUDIOUNIT_6_0,      AV_CH_LAYOUT_6POINT0 },        // L, R, Ls, Rs, C,  Cs
133     { MOV_CH_LAYOUT_AAC_6_0,            AV_CH_LAYOUT_6POINT0 },        // C, L, R,  Ls, Rs, Cs
134     { MOV_CH_LAYOUT_EAC3_6_0_A,         AV_CH_LAYOUT_6POINT0 },        // L, C, R,  Ls, Rs, Cs
135 
136     { MOV_CH_LAYOUT_DTS_6_0_A,          AV_CH_LAYOUT_6POINT0_FRONT },  // Lc, Rc, L, R, Ls, Rs
137 
138     { MOV_CH_LAYOUT_DTS_6_0_B,          AV_CH_LAYOUT_5POINT0_BACK |    // C, L, R, Rls, Rrs, Ts
139                                         AV_CH_TOP_CENTER },
140     { 0, 0 },
141 };
142 
143 static const struct MovChannelLayoutMap mov_ch_layout_map_7ch[] = {
144     { MOV_CH_LAYOUT_MPEG_6_1_A,          AV_CH_LAYOUT_6POINT1 },        // L, R, C, LFE, Ls, Rs,  Cs
145     { MOV_CH_LAYOUT_AAC_6_1,             AV_CH_LAYOUT_6POINT1 },        // C, L, R, Ls,  Rs, Cs,  LFE
146     { MOV_CH_LAYOUT_EAC3_6_1_A,          AV_CH_LAYOUT_6POINT1 },        // L, C, R, Ls,  Rs, LFE, Cs
147     { MOV_CH_LAYOUT_DTS_6_1_D,           AV_CH_LAYOUT_6POINT1 },        // C, L, R, Ls,  Rs, LFE, Cs
148 
149     { MOV_CH_LAYOUT_AUDIOUNIT_7_0,       AV_CH_LAYOUT_7POINT0 },        // L, R, Ls, Rs, C,  Rls, Rrs
150     { MOV_CH_LAYOUT_AAC_7_0,             AV_CH_LAYOUT_7POINT0 },        // C, L, R,  Ls, Rs, Rls, Rrs
151     { MOV_CH_LAYOUT_EAC3_7_0_A,          AV_CH_LAYOUT_7POINT0 },        // L, C, R,  Ls, Rs, Rls, Rrs
152 
153     { MOV_CH_LAYOUT_AUDIOUNIT_7_0_FRONT, AV_CH_LAYOUT_7POINT0_FRONT },  // L,  R, Ls, Rs, C, Lc, Rc
154     { MOV_CH_LAYOUT_DTS_7_0,             AV_CH_LAYOUT_7POINT0_FRONT },  // Lc, C, Rc, L,  R, Ls, Rs
155 
156     { MOV_CH_LAYOUT_EAC3_6_1_B,          AV_CH_LAYOUT_5POINT1 |         // L, C, R, Ls, Rs, LFE, Ts
157                                          AV_CH_TOP_CENTER },
158 
159     { MOV_CH_LAYOUT_EAC3_6_1_C,          AV_CH_LAYOUT_5POINT1 |         // L, C, R, Ls, Rs, LFE, Vhc
160                                          AV_CH_TOP_FRONT_CENTER },
161 
162     { MOV_CH_LAYOUT_DTS_6_1_A,           AV_CH_LAYOUT_6POINT1_FRONT },  // Lc, Rc, L, R, Ls, Rs, LFE
163 
164     { MOV_CH_LAYOUT_DTS_6_1_B,           AV_CH_LAYOUT_5POINT1_BACK |    // C, L, R, Rls, Rrs, Ts, LFE
165                                          AV_CH_TOP_CENTER },
166 
167     { MOV_CH_LAYOUT_DTS_6_1_C,           AV_CH_LAYOUT_6POINT1_BACK },   // C, Cs, L, R, Rls, Rrs, LFE
168     { 0, 0 },
169 };
170 
171 static const struct MovChannelLayoutMap mov_ch_layout_map_8ch[] = {
172     { MOV_CH_LAYOUT_OCTAGONAL,           AV_CH_LAYOUT_OCTAGONAL },      // L, R, Rls, Rrs, C,  Cs,  Ls,  Rs
173     { MOV_CH_LAYOUT_AAC_OCTAGONAL,       AV_CH_LAYOUT_OCTAGONAL },      // C, L, R,   Ls,  Rs, Rls, Rrs, Cs
174 
175     { MOV_CH_LAYOUT_CUBE,                AV_CH_LAYOUT_QUAD     |        // L, R, Rls, Rrs, Vhl, Vhr, Rlt, Rrt
176                                          AV_CH_TOP_FRONT_LEFT  |
177                                          AV_CH_TOP_FRONT_RIGHT |
178                                          AV_CH_TOP_BACK_LEFT   |
179                                          AV_CH_TOP_BACK_RIGHT },
180 
181     { MOV_CH_LAYOUT_MPEG_7_1_A,          AV_CH_LAYOUT_7POINT1_WIDE },   // L,  R,  C,  LFE, Ls, Rs,  Lc, Rc
182     { MOV_CH_LAYOUT_MPEG_7_1_B,          AV_CH_LAYOUT_7POINT1_WIDE },   // C,  Lc, Rc, L,   R,  Ls,  Rs, LFE
183     { MOV_CH_LAYOUT_EMAGIC_DEFAULT_7_1,  AV_CH_LAYOUT_7POINT1_WIDE },   // L,  R,  Ls, Rs,  C,  LFE, Lc, Rc
184     { MOV_CH_LAYOUT_EAC3_7_1_B,          AV_CH_LAYOUT_7POINT1_WIDE },   // L,  C,  R,  Ls,  Rs, LFE, Lc, Rc
185     { MOV_CH_LAYOUT_DTS_7_1,             AV_CH_LAYOUT_7POINT1_WIDE },   // Lc, C,  Rc, L,   R,  Ls,  Rs, LFE
186 
187     { MOV_CH_LAYOUT_MPEG_7_1_C,          AV_CH_LAYOUT_7POINT1 },        // L, R, C, LFE, Ls, Rs,  Rls, Rrs
188     { MOV_CH_LAYOUT_EAC3_7_1_A,          AV_CH_LAYOUT_7POINT1 },        // L, C, R, Ls,  Rs, LFE, Rls, Rrs
189 
190     { MOV_CH_LAYOUT_SMPTE_DTV,           AV_CH_LAYOUT_5POINT1 |         // L, R, C, LFE, Ls, Rs, Lt, Rt
191                                          AV_CH_LAYOUT_STEREO_DOWNMIX },
192 
193     { MOV_CH_LAYOUT_EAC3_7_1_C,          AV_CH_LAYOUT_5POINT1        |  // L, C, R, Ls, Rs, LFE, Lsd, Rsd
194                                          AV_CH_SURROUND_DIRECT_LEFT  |
195                                          AV_CH_SURROUND_DIRECT_RIGHT },
196 
197     { MOV_CH_LAYOUT_EAC3_7_1_D,          AV_CH_LAYOUT_5POINT1 |         // L, C, R, Ls, Rs, LFE, Lw, Rw
198                                          AV_CH_WIDE_LEFT      |
199                                          AV_CH_WIDE_RIGHT },
200 
201     { MOV_CH_LAYOUT_EAC3_7_1_E,          AV_CH_LAYOUT_5POINT1 |         // L, C, R, Ls, Rs, LFE, Vhl, Vhr
202                                          AV_CH_TOP_FRONT_LEFT |
203                                          AV_CH_TOP_FRONT_RIGHT },
204 
205     { MOV_CH_LAYOUT_EAC3_7_1_F,          AV_CH_LAYOUT_5POINT1 |         // L, C, R, Ls, Rs, LFE, Cs, Ts
206                                          AV_CH_BACK_CENTER    |
207                                          AV_CH_TOP_CENTER },
208 
209     { MOV_CH_LAYOUT_EAC3_7_1_G,          AV_CH_LAYOUT_5POINT1 |         // L, C, R, Ls, Rs, LFE, Cs, Vhc
210                                          AV_CH_BACK_CENTER    |
211                                          AV_CH_TOP_FRONT_CENTER },
212 
213     { MOV_CH_LAYOUT_EAC3_7_1_H,          AV_CH_LAYOUT_5POINT1 |         // L, C, R, Ls, Rs, LFE, Ts, Vhc
214                                          AV_CH_TOP_CENTER     |
215                                          AV_CH_TOP_FRONT_CENTER },
216 
217     { MOV_CH_LAYOUT_DTS_8_0_A,           AV_CH_LAYOUT_2_2           |   // Lc, Rc, L, R, Ls, Rs, Rls, Rrs
218                                          AV_CH_BACK_LEFT            |
219                                          AV_CH_BACK_RIGHT           |
220                                          AV_CH_FRONT_LEFT_OF_CENTER |
221                                          AV_CH_FRONT_RIGHT_OF_CENTER },
222 
223     { MOV_CH_LAYOUT_DTS_8_0_B,           AV_CH_LAYOUT_5POINT0        |  // Lc, C, Rc, L, R, Ls, Cs, Rs
224                                          AV_CH_FRONT_LEFT_OF_CENTER  |
225                                          AV_CH_FRONT_RIGHT_OF_CENTER |
226                                          AV_CH_BACK_CENTER },
227     { 0, 0 },
228 };
229 
230 static const struct MovChannelLayoutMap mov_ch_layout_map_9ch[] = {
231     { MOV_CH_LAYOUT_DTS_8_1_A,           AV_CH_LAYOUT_2_2            | // Lc, Rc, L, R, Ls, Rs, Rls, Rrs, LFE
232                                          AV_CH_BACK_LEFT             |
233                                          AV_CH_BACK_RIGHT            |
234                                          AV_CH_FRONT_LEFT_OF_CENTER  |
235                                          AV_CH_FRONT_RIGHT_OF_CENTER |
236                                          AV_CH_LOW_FREQUENCY },
237 
238     { MOV_CH_LAYOUT_DTS_8_1_B,           AV_CH_LAYOUT_7POINT1_WIDE   | // Lc, C, Rc, L, R, Ls, Cs, Rs, LFE
239                                          AV_CH_BACK_CENTER },
240     { 0, 0 },
241 };
242 
243 static const struct MovChannelLayoutMap * const mov_ch_layout_map[] = {
244     mov_ch_layout_map_misc,
245     mov_ch_layout_map_1ch,
246     mov_ch_layout_map_2ch,
247     mov_ch_layout_map_3ch,
248     mov_ch_layout_map_4ch,
249     mov_ch_layout_map_5ch,
250     mov_ch_layout_map_6ch,
251     mov_ch_layout_map_7ch,
252     mov_ch_layout_map_8ch,
253     mov_ch_layout_map_9ch,
254 };
255 
256 static const enum MovChannelLayoutTag mov_ch_layouts_aac[] = {
257     MOV_CH_LAYOUT_MONO,
258     MOV_CH_LAYOUT_STEREO,
259     MOV_CH_LAYOUT_AC3_1_0_1,
260     MOV_CH_LAYOUT_MPEG_3_0_B,
261     MOV_CH_LAYOUT_ITU_2_1,
262     MOV_CH_LAYOUT_DVD_4,
263     MOV_CH_LAYOUT_QUADRAPHONIC,
264     MOV_CH_LAYOUT_MPEG_4_0_B,
265     MOV_CH_LAYOUT_ITU_2_2,
266     MOV_CH_LAYOUT_AC3_2_1_1,
267     MOV_CH_LAYOUT_DTS_3_1,
268     MOV_CH_LAYOUT_MPEG_5_0_D,
269     MOV_CH_LAYOUT_DVD_18,
270     MOV_CH_LAYOUT_DTS_4_1,
271     MOV_CH_LAYOUT_MPEG_5_1_D,
272     MOV_CH_LAYOUT_AAC_6_0,
273     MOV_CH_LAYOUT_DTS_6_0_A,
274     MOV_CH_LAYOUT_AAC_6_1,
275     MOV_CH_LAYOUT_AAC_7_0,
276     MOV_CH_LAYOUT_DTS_6_1_A,
277     MOV_CH_LAYOUT_AAC_OCTAGONAL,
278     MOV_CH_LAYOUT_MPEG_7_1_B,
279     MOV_CH_LAYOUT_DTS_8_0_A,
280     0,
281 };
282 
283 static const enum MovChannelLayoutTag mov_ch_layouts_ac3[] = {
284     MOV_CH_LAYOUT_MONO,
285     MOV_CH_LAYOUT_STEREO,
286     MOV_CH_LAYOUT_AC3_1_0_1,
287     MOV_CH_LAYOUT_AC3_3_0,
288     MOV_CH_LAYOUT_ITU_2_1,
289     MOV_CH_LAYOUT_DVD_4,
290     MOV_CH_LAYOUT_AC3_3_1,
291     MOV_CH_LAYOUT_ITU_2_2,
292     MOV_CH_LAYOUT_AC3_2_1_1,
293     MOV_CH_LAYOUT_AC3_3_0_1,
294     MOV_CH_LAYOUT_MPEG_5_0_C,
295     MOV_CH_LAYOUT_DVD_18,
296     MOV_CH_LAYOUT_AC3_3_1_1,
297     MOV_CH_LAYOUT_MPEG_5_1_C,
298     0,
299 };
300 
301 static const enum MovChannelLayoutTag mov_ch_layouts_alac[] = {
302     MOV_CH_LAYOUT_MONO,
303     MOV_CH_LAYOUT_STEREO,
304     MOV_CH_LAYOUT_MPEG_3_0_B,
305     MOV_CH_LAYOUT_MPEG_4_0_B,
306     MOV_CH_LAYOUT_MPEG_5_0_D,
307     MOV_CH_LAYOUT_MPEG_5_1_D,
308     MOV_CH_LAYOUT_AAC_6_1,
309     MOV_CH_LAYOUT_MPEG_7_1_B,
310     0,
311 };
312 
313 static const enum MovChannelLayoutTag mov_ch_layouts_wav[] = {
314     MOV_CH_LAYOUT_MONO,
315     MOV_CH_LAYOUT_STEREO,
316     MOV_CH_LAYOUT_MATRIXSTEREO,
317     MOV_CH_LAYOUT_MPEG_3_0_A,
318     MOV_CH_LAYOUT_QUADRAPHONIC,
319     MOV_CH_LAYOUT_MPEG_5_0_A,
320     MOV_CH_LAYOUT_MPEG_5_1_A,
321     MOV_CH_LAYOUT_MPEG_6_1_A,
322     MOV_CH_LAYOUT_MPEG_7_1_A,
323     MOV_CH_LAYOUT_MPEG_7_1_C,
324     MOV_CH_LAYOUT_SMPTE_DTV,
325     0,
326 };
327 
328 static const struct {
329     enum AVCodecID codec_id;
330     const enum MovChannelLayoutTag *layouts;
331 } mov_codec_ch_layouts[] = {
332     { AV_CODEC_ID_AAC,     mov_ch_layouts_aac      },
333     { AV_CODEC_ID_AC3,     mov_ch_layouts_ac3      },
334     { AV_CODEC_ID_ALAC,    mov_ch_layouts_alac     },
335     { AV_CODEC_ID_PCM_U8,    mov_ch_layouts_wav    },
336     { AV_CODEC_ID_PCM_S8,    mov_ch_layouts_wav    },
337     { AV_CODEC_ID_PCM_S16LE, mov_ch_layouts_wav    },
338     { AV_CODEC_ID_PCM_S16BE, mov_ch_layouts_wav    },
339     { AV_CODEC_ID_PCM_S24LE, mov_ch_layouts_wav    },
340     { AV_CODEC_ID_PCM_S24BE, mov_ch_layouts_wav    },
341     { AV_CODEC_ID_PCM_S32LE, mov_ch_layouts_wav    },
342     { AV_CODEC_ID_PCM_S32BE, mov_ch_layouts_wav    },
343     { AV_CODEC_ID_PCM_F32LE, mov_ch_layouts_wav    },
344     { AV_CODEC_ID_PCM_F32BE, mov_ch_layouts_wav    },
345     { AV_CODEC_ID_PCM_F64LE, mov_ch_layouts_wav    },
346     { AV_CODEC_ID_PCM_F64BE, mov_ch_layouts_wav    },
347     { AV_CODEC_ID_NONE,    NULL                    },
348 };
349 
350 /**
351  * Get the channel layout for the specified channel layout tag.
352  *
353  * @param[in]  tag     channel layout tag
354  * @param[out] bitmap  channel bitmap (only used if needed)
355  * @return             channel layout
356  */
mov_get_channel_layout(uint32_t tag, uint32_t bitmap)357 static uint64_t mov_get_channel_layout(uint32_t tag, uint32_t bitmap)
358 {
359     int i, channels;
360     const struct MovChannelLayoutMap *layout_map;
361 
362     /* use ff_mov_get_channel_label() to build a layout instead */
363     if (tag == MOV_CH_LAYOUT_USE_DESCRIPTIONS)
364         return 0;
365 
366     /* handle the use of the channel bitmap */
367     if (tag == MOV_CH_LAYOUT_USE_BITMAP)
368         return bitmap < 0x40000 ? bitmap : 0;
369 
370     /* get the layout map based on the channel count for the specified layout tag */
371     channels = tag & 0xFFFF;
372     if (channels > 9)
373         channels = 0;
374     layout_map = mov_ch_layout_map[channels];
375 
376     /* find the channel layout for the specified layout tag */
377     for (i = 0; layout_map[i].tag != 0; i++) {
378         if (layout_map[i].tag == tag)
379             break;
380     }
381     return layout_map[i].layout;
382 }
383 
mov_get_channel_mask(uint32_t label)384 static uint64_t mov_get_channel_mask(uint32_t label)
385 {
386     if (label == 0)
387         return 0;
388     if (label <= 18)
389         return 1U << (label - 1);
390     if (label == 35)
391         return AV_CH_WIDE_LEFT;
392     if (label == 36)
393         return AV_CH_WIDE_RIGHT;
394     if (label == 37)
395         return AV_CH_LOW_FREQUENCY_2;
396     if (label == 38)
397         return AV_CH_STEREO_LEFT;
398     if (label == 39)
399         return AV_CH_STEREO_RIGHT;
400     return 0;
401 }
402 
mov_get_channel_label(enum AVChannel channel)403 static uint32_t mov_get_channel_label(enum AVChannel channel)
404 {
405     if (channel < 0)
406         return 0;
407     if (channel <= AV_CHAN_TOP_BACK_RIGHT)
408         return channel + 1;
409     if (channel == AV_CHAN_WIDE_LEFT)
410         return 35;
411     if (channel == AV_CHAN_WIDE_RIGHT)
412         return 36;
413     if (channel == AV_CHAN_LOW_FREQUENCY_2)
414         return 37;
415     if (channel == AV_CHAN_STEREO_LEFT)
416         return 38;
417     if (channel == AV_CHAN_STEREO_RIGHT)
418         return 39;
419     return 0;
420 }
421 
ff_mov_get_channel_layout_tag(const AVCodecParameters *par, uint32_t *layout, uint32_t *bitmap, uint32_t **pchannel_desc)422 int ff_mov_get_channel_layout_tag(const AVCodecParameters *par,
423                                   uint32_t *layout,
424                                   uint32_t *bitmap,
425                                   uint32_t **pchannel_desc)
426 {
427     int i, j;
428     uint32_t tag = 0;
429     const enum MovChannelLayoutTag *layouts = NULL;
430 
431     /* find the layout list for the specified codec */
432     for (i = 0; mov_codec_ch_layouts[i].codec_id != AV_CODEC_ID_NONE; i++) {
433         if (mov_codec_ch_layouts[i].codec_id == par->codec_id)
434             break;
435     }
436     if (mov_codec_ch_layouts[i].codec_id != AV_CODEC_ID_NONE)
437         layouts = mov_codec_ch_layouts[i].layouts;
438 
439     if (layouts) {
440         int channels;
441         const struct MovChannelLayoutMap *layout_map;
442 
443         /* get the layout map based on the channel count */
444         channels = par->ch_layout.nb_channels;
445         if (channels > 9)
446             channels = 0;
447         layout_map = mov_ch_layout_map[channels];
448 
449         /* find the layout tag for the specified channel layout */
450         for (i = 0; layouts[i] != 0; i++) {
451             if ((layouts[i] & 0xFFFF) != channels)
452                 continue;
453             for (j = 0; layout_map[j].tag != 0; j++) {
454                 if (layout_map[j].tag    == layouts[i] &&
455                     (par->ch_layout.order == AV_CHANNEL_ORDER_NATIVE &&
456                      layout_map[j].layout == par->ch_layout.u.mask))
457                     break;
458             }
459             if (layout_map[j].tag)
460                 break;
461         }
462         tag = layouts[i];
463     }
464 
465     *layout = tag;
466     *bitmap = 0;
467     *pchannel_desc = NULL;
468 
469     /* if no tag was found, use channel bitmap or description as a backup if possible */
470     if (tag == 0) {
471         uint32_t *channel_desc;
472         if (par->ch_layout.order == AV_CHANNEL_ORDER_NATIVE &&
473             par->ch_layout.u.mask < 0x40000) {
474             *layout = MOV_CH_LAYOUT_USE_BITMAP;
475             *bitmap = (uint32_t)par->ch_layout.u.mask;
476             return 0;
477         } else if (par->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC)
478             return AVERROR(ENOSYS);
479 
480         channel_desc = av_malloc_array(par->ch_layout.nb_channels, sizeof(*channel_desc));
481         if (!channel_desc)
482             return AVERROR(ENOMEM);
483 
484         for (i = 0; i < par->ch_layout.nb_channels; i++) {
485             channel_desc[i] =
486                 mov_get_channel_label(av_channel_layout_channel_from_index(&par->ch_layout, i));
487 
488             if (channel_desc[i] == 0) {
489                 av_free(channel_desc);
490                 return AVERROR(ENOSYS);
491             }
492         }
493 
494         *pchannel_desc = channel_desc;
495     }
496 
497     return 0;
498 }
499 
ff_mov_read_chan(AVFormatContext *s, AVIOContext *pb, AVStream *st, int64_t size)500 int ff_mov_read_chan(AVFormatContext *s, AVIOContext *pb, AVStream *st,
501                      int64_t size)
502 {
503     uint32_t layout_tag, bitmap, num_descr;
504     uint64_t label_mask, mask = 0;
505     int i;
506 
507     if (size < 12)
508         return AVERROR_INVALIDDATA;
509 
510     layout_tag = avio_rb32(pb);
511     bitmap     = avio_rb32(pb);
512     num_descr  = avio_rb32(pb);
513 
514     av_log(s, AV_LOG_DEBUG, "chan: layout=%"PRIu32" "
515            "bitmap=%"PRIu32" num_descr=%"PRIu32"\n",
516            layout_tag, bitmap, num_descr);
517 
518     if (size < 12ULL + num_descr * 20ULL)
519         return 0;
520 
521     label_mask = 0;
522     for (i = 0; i < num_descr; i++) {
523         uint32_t label;
524         if (pb->eof_reached) {
525             av_log(s, AV_LOG_ERROR,
526                    "reached EOF while reading channel layout\n");
527             return AVERROR_INVALIDDATA;
528         }
529         label     = avio_rb32(pb);          // mChannelLabel
530         avio_rb32(pb);                      // mChannelFlags
531         avio_rl32(pb);                      // mCoordinates[0]
532         avio_rl32(pb);                      // mCoordinates[1]
533         avio_rl32(pb);                      // mCoordinates[2]
534         size -= 20;
535         if (layout_tag == 0) {
536             uint64_t mask_incr = mov_get_channel_mask(label);
537             if (mask_incr == 0) {
538                 label_mask = 0;
539                 break;
540             }
541             label_mask |= mask_incr;
542         }
543     }
544     if (layout_tag == 0) {
545         if (label_mask)
546             mask = label_mask;
547     } else
548         mask = mov_get_channel_layout(layout_tag, bitmap);
549 
550     if (mask) {
551         av_channel_layout_uninit(&st->codecpar->ch_layout);
552         av_channel_layout_from_mask(&st->codecpar->ch_layout, mask);
553     }
554     avio_skip(pb, size - 12);
555 
556     return 0;
557 }
558