FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/mov_chan.c
Date: 2026-08-30 18:45:47
Exec Total Coverage
Lines: 189 259 73.0%
Functions: 11 11 100.0%
Branches: 111 184 60.3%

Line Branch Exec Source
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 <assert.h>
27 #include <stdint.h>
28
29 #include "libavutil/avassert.h"
30 #include "libavutil/channel_layout.h"
31 #include "libavutil/mem.h"
32 #include "libavcodec/codec_id.h"
33 #include "mov_chan.h"
34
35 enum {
36 c_L = AV_CHAN_FRONT_LEFT,
37 c_R = AV_CHAN_FRONT_RIGHT,
38 c_C = AV_CHAN_FRONT_CENTER,
39 c_LFE = AV_CHAN_LOW_FREQUENCY,
40 c_Rls = AV_CHAN_BACK_LEFT,
41 c_Rrs = AV_CHAN_BACK_RIGHT,
42 c_Lc = AV_CHAN_FRONT_LEFT_OF_CENTER,
43 c_Rc = AV_CHAN_FRONT_RIGHT_OF_CENTER,
44 c_Cs = AV_CHAN_BACK_CENTER,
45 c_Ls = AV_CHAN_SIDE_LEFT,
46 c_Rs = AV_CHAN_SIDE_RIGHT,
47 c_Ts = AV_CHAN_TOP_CENTER,
48 c_Vhl = AV_CHAN_TOP_FRONT_LEFT,
49 c_Vhc = AV_CHAN_TOP_FRONT_CENTER,
50 c_Vhr = AV_CHAN_TOP_FRONT_RIGHT,
51 c_Rlt = AV_CHAN_TOP_BACK_LEFT,
52 // = AV_CHAN_TOP_BACK_CENTER,
53 c_Rrt = AV_CHAN_TOP_BACK_RIGHT,
54 c_Lt = AV_CHAN_STEREO_LEFT,
55 c_Rt = AV_CHAN_STEREO_RIGHT,
56 c_Lw = AV_CHAN_WIDE_LEFT,
57 c_Rw = AV_CHAN_WIDE_RIGHT,
58 c_Lsd = AV_CHAN_SURROUND_DIRECT_LEFT,
59 c_Rsd = AV_CHAN_SURROUND_DIRECT_RIGHT,
60 c_LFE2 = AV_CHAN_LOW_FREQUENCY_2,
61 // = AV_CHAN_TOP_SIDE_LEFT,
62 // = AV_CHAN_TOP_SIDE_RIGHT,
63 // = AV_CHAN_BOTTOM_FRONT_CENTER,
64 // = AV_CHAN_BOTTOM_FRONT_LEFT,
65 // = AV_CHAN_BOTTOM_FRONT_RIGHT,
66 c_W = AV_CHAN_AMBISONIC_BASE,
67 c_Y = AV_CHAN_AMBISONIC_BASE + 1,
68 c_Z = AV_CHAN_AMBISONIC_BASE + 2,
69 c_X = AV_CHAN_AMBISONIC_BASE + 3,
70 /* The following have no exact counterparts */
71 c_LFE1 = AV_CHAN_LOW_FREQUENCY,
72 c_Csd = AV_CHAN_NONE,
73 c_HI = AV_CHAN_NONE,
74 c_VI = AV_CHAN_NONE,
75 c_Haptic = AV_CHAN_NONE,
76 };
77
78 enum {
79 iso_L = AV_CHAN_FRONT_LEFT,
80 iso_R = AV_CHAN_FRONT_RIGHT,
81 iso_C = AV_CHAN_FRONT_CENTER,
82 iso_LFE = AV_CHAN_LOW_FREQUENCY,
83 iso_Lsr = AV_CHAN_BACK_LEFT,
84 iso_Rsr = AV_CHAN_BACK_RIGHT,
85 iso_Lc = AV_CHAN_FRONT_LEFT_OF_CENTER,
86 iso_Rc = AV_CHAN_FRONT_RIGHT_OF_CENTER,
87 iso_Cs = AV_CHAN_BACK_CENTER,
88 iso_Ls = AV_CHAN_SIDE_LEFT,
89 iso_Rs = AV_CHAN_SIDE_RIGHT,
90 iso_Ts = AV_CHAN_TOP_CENTER,
91 iso_Lv = AV_CHAN_TOP_FRONT_LEFT,
92 iso_Cv = AV_CHAN_TOP_FRONT_CENTER,
93 iso_Rv = AV_CHAN_TOP_FRONT_RIGHT,
94 iso_Lvr = AV_CHAN_TOP_BACK_LEFT,
95 iso_Cvr = AV_CHAN_TOP_BACK_CENTER,
96 iso_Rvr = AV_CHAN_TOP_BACK_RIGHT,
97 // = AV_CHAN_STEREO_LEFT,
98 // = AV_CHAN_STEREO_RIGHT,
99 iso_Lw = AV_CHAN_WIDE_LEFT,
100 iso_Rw = AV_CHAN_WIDE_RIGHT,
101 iso_Lsd = AV_CHAN_SURROUND_DIRECT_LEFT,
102 iso_Rsd = AV_CHAN_SURROUND_DIRECT_RIGHT,
103 iso_LFE2 = AV_CHAN_LOW_FREQUENCY_2,
104 iso_Lvss = AV_CHAN_TOP_SIDE_LEFT,
105 iso_Rvss = AV_CHAN_TOP_SIDE_RIGHT,
106 iso_Cb = AV_CHAN_BOTTOM_FRONT_CENTER,
107 iso_Lb = AV_CHAN_BOTTOM_FRONT_LEFT,
108 iso_Rb = AV_CHAN_BOTTOM_FRONT_RIGHT,
109 iso_Lss = AV_CHAN_SIDE_SURROUND_LEFT,
110 iso_Rss = AV_CHAN_SIDE_SURROUND_RIGHT,
111 /* The following have no exact counterparts */
112 iso_Lvs = AV_CHAN_NONE,
113 iso_Rvs = AV_CHAN_NONE,
114 };
115
116 struct MovChannelLayoutMap {
117 union {
118 uint32_t tag;
119 enum AVChannel id;
120 };
121 };
122
123 #define TAG(_tag, _cnt) {.tag = _tag}
124 #define ID(_0) {.id = c_##_0}
125 #define CHLIST01(_tag, _1) CHLIST(_tag, 1, ID(_1))
126 #define CHLIST02(_tag, _1, _2) CHLIST(_tag, 2, ID(_1), ID(_2))
127 #define CHLIST03(_tag, _1, _2, _3) CHLIST(_tag, 3, ID(_1), ID(_2), ID(_3))
128 #define CHLIST04(_tag, _1, _2, _3, _4) CHLIST(_tag, 4, ID(_1), ID(_2), ID(_3), ID(_4))
129 #define CHLIST05(_tag, _1, _2, _3, _4, _5) CHLIST(_tag, 5, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5))
130 #define CHLIST06(_tag, _1, _2, _3, _4, _5, _6) CHLIST(_tag, 6, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6))
131 #define CHLIST07(_tag, _1, _2, _3, _4, _5, _6, _7) CHLIST(_tag, 7, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7))
132 #define CHLIST08(_tag, _1, _2, _3, _4, _5, _6, _7, _8) CHLIST(_tag, 8, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7), ID(_8))
133 #define CHLIST09(_tag, _1, _2, _3, _4, _5, _6, _7, _8, _9) CHLIST(_tag, 9, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7), ID(_8), ID(_9))
134 #define CHLIST16(_tag, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
135 CHLIST(_tag, 16, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7), ID(_8), ID(_9), ID(_10), \
136 ID(_11), ID(_12), ID(_13), ID(_14), ID(_15), ID(_16))
137 #define CHLIST21(_tag, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21) \
138 CHLIST(_tag, 21, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7), ID(_8), ID(_9), ID(_10), \
139 ID(_11), ID(_12), ID(_13), ID(_14), ID(_15), ID(_16), ID(_17), ID(_18), ID(_19), ID(_20), ID(_21))
140 #define CHLIST24(_tag, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24) \
141 CHLIST(_tag, 24, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7), ID(_8), ID(_9), ID(_10), \
142 ID(_11), ID(_12), ID(_13), ID(_14), ID(_15), ID(_16), ID(_17), ID(_18), ID(_19), ID(_20), \
143 ID(_21), ID(_22), ID(_23), ID(_24))
144
145 #define MOV_CH_LAYOUT_MAP \
146 CHLIST01( MOV_CH_LAYOUT_MONO, C )\
147 CHLIST02( MOV_CH_LAYOUT_STEREO, L, R )\
148 CHLIST02( MOV_CH_LAYOUT_STEREOHEADPHONES, L, R )\
149 CHLIST02( MOV_CH_LAYOUT_BINAURAL, L, R )\
150 CHLIST02( MOV_CH_LAYOUT_MIDSIDE, L, R )\
151 CHLIST02( MOV_CH_LAYOUT_XY, L, R )\
152 CHLIST02( MOV_CH_LAYOUT_MATRIXSTEREO, Lt, Rt )\
153 CHLIST02( MOV_CH_LAYOUT_AC3_1_0_1, C, LFE )\
154 CHLIST03( MOV_CH_LAYOUT_MPEG_3_0_A, L, R, C )\
155 CHLIST03( MOV_CH_LAYOUT_MPEG_3_0_B, C, L, R )\
156 CHLIST03( MOV_CH_LAYOUT_AC3_3_0, L, C, R )\
157 CHLIST03( MOV_CH_LAYOUT_ITU_2_1, L, R, Cs )\
158 CHLIST03( MOV_CH_LAYOUT_DVD_4, L, R, LFE )\
159 CHLIST04( MOV_CH_LAYOUT_AMBISONIC_B_FORMAT, W, X, Y, Z )\
160 CHLIST04( MOV_CH_LAYOUT_QUADRAPHONIC, L, R, Rls, Rrs )\
161 CHLIST04( MOV_CH_LAYOUT_MPEG_4_0_A, L, R, C, Cs )\
162 CHLIST04( MOV_CH_LAYOUT_MPEG_4_0_B, C, L, R, Cs )\
163 CHLIST04( MOV_CH_LAYOUT_AC3_3_1, L, C, R, Cs )\
164 CHLIST04( MOV_CH_LAYOUT_ITU_2_2, L, R, Ls, Rs )\
165 CHLIST04( MOV_CH_LAYOUT_DVD_5, L, R, LFE, Cs )\
166 CHLIST04( MOV_CH_LAYOUT_AC3_2_1_1, L, R, Cs, LFE )\
167 CHLIST04( MOV_CH_LAYOUT_DVD_10, L, R, C, LFE )\
168 CHLIST04( MOV_CH_LAYOUT_AC3_3_0_1, L, C, R, LFE )\
169 CHLIST04( MOV_CH_LAYOUT_DTS_3_1, C, L, R, LFE )\
170 CHLIST05( MOV_CH_LAYOUT_PENTAGONAL, L, R, Rls, Rrs, C )\
171 CHLIST05( MOV_CH_LAYOUT_MPEG_5_0_A, L, R, C, Ls, Rs )\
172 CHLIST05( MOV_CH_LAYOUT_MPEG_5_0_B, L, R, Ls, Rs, C )\
173 CHLIST05( MOV_CH_LAYOUT_MPEG_5_0_C, L, C, R, Ls, Rs )\
174 CHLIST05( MOV_CH_LAYOUT_MPEG_5_0_D, C, L, R, Ls, Rs )\
175 CHLIST05( MOV_CH_LAYOUT_DVD_6, L, R, LFE, Ls, Rs )\
176 CHLIST05( MOV_CH_LAYOUT_DVD_18, L, R, Ls, Rs, LFE )\
177 CHLIST05( MOV_CH_LAYOUT_DVD_11, L, R, C, LFE, Cs )\
178 CHLIST05( MOV_CH_LAYOUT_AC3_3_1_1, L, C, R, Cs, LFE )\
179 CHLIST05( MOV_CH_LAYOUT_DTS_4_1, C, L, R, Cs, LFE )\
180 CHLIST06( MOV_CH_LAYOUT_HEXAGONAL, L, R, Rls, Rrs, C, Cs )\
181 CHLIST06( MOV_CH_LAYOUT_DTS_6_0_C, C, Cs, L, R, Rls, Rrs )\
182 CHLIST06( MOV_CH_LAYOUT_MPEG_5_1_A, L, R, C, LFE, Ls, Rs )\
183 CHLIST06( MOV_CH_LAYOUT_MPEG_5_1_B, L, R, Ls, Rs, C, LFE )\
184 CHLIST06( MOV_CH_LAYOUT_MPEG_5_1_C, L, C, R, Ls, Rs, LFE )\
185 CHLIST06( MOV_CH_LAYOUT_MPEG_5_1_D, C, L, R, Ls, Rs, LFE )\
186 CHLIST06( MOV_CH_LAYOUT_AUDIOUNIT_6_0, L, R, Ls, Rs, C, Cs )\
187 CHLIST06( MOV_CH_LAYOUT_AAC_6_0, C, L, R, Ls, Rs, Cs )\
188 CHLIST06( MOV_CH_LAYOUT_EAC3_6_0_A, L, C, R, Ls, Rs, Cs )\
189 CHLIST06( MOV_CH_LAYOUT_DTS_6_0_A, Lc, Rc, L, R, Ls, Rs )\
190 CHLIST06( MOV_CH_LAYOUT_DTS_6_0_B, C, L, R, Rls, Rrs, Ts )\
191 CHLIST07( MOV_CH_LAYOUT_MPEG_6_1_A, L, R, C, LFE, Ls, Rs, Cs )\
192 CHLIST07( MOV_CH_LAYOUT_AAC_6_1, C, L, R, Ls, Rs, Cs, LFE )\
193 CHLIST07( MOV_CH_LAYOUT_EAC3_6_1_A, L, C, R, Ls, Rs, LFE, Cs )\
194 CHLIST07( MOV_CH_LAYOUT_DTS_6_1_D, C, L, R, Ls, Rs, LFE, Cs )\
195 CHLIST07( MOV_CH_LAYOUT_AUDIOUNIT_7_0, L, R, Ls, Rs, C, Rls, Rrs )\
196 CHLIST07( MOV_CH_LAYOUT_AAC_7_0, C, L, R, Ls, Rs, Rls, Rrs )\
197 CHLIST07( MOV_CH_LAYOUT_EAC3_7_0_A, L, C, R, Ls, Rs, Rls, Rrs )\
198 CHLIST07( MOV_CH_LAYOUT_AUDIOUNIT_7_0_FRONT, L, R, Ls, Rs, C, Lc, Rc )\
199 CHLIST07( MOV_CH_LAYOUT_DTS_7_0, Lc, C, Rc, L, R, Ls, Rs )\
200 CHLIST07( MOV_CH_LAYOUT_EAC3_6_1_B, L, C, R, Ls, Rs, LFE, Ts )\
201 CHLIST07( MOV_CH_LAYOUT_EAC3_6_1_C, L, C, R, Ls, Rs, LFE, Vhc )\
202 CHLIST07( MOV_CH_LAYOUT_DTS_6_1_A, Lc, Rc, L, R, Ls, Rs, LFE )\
203 CHLIST07( MOV_CH_LAYOUT_DTS_6_1_B, C, L, R, Rls, Rrs, Ts, LFE )\
204 CHLIST07( MOV_CH_LAYOUT_DTS_6_1_C, C, Cs, L, R, Rls, Rrs, LFE )\
205 CHLIST08( MOV_CH_LAYOUT_OCTAGONAL, L, R, Rls, Rrs, C, Cs, Ls, Rs )\
206 CHLIST08( MOV_CH_LAYOUT_AAC_OCTAGONAL, C, L, R, Ls, Rs, Rls, Rrs, Cs )\
207 CHLIST08( MOV_CH_LAYOUT_CUBE, L, R, Rls, Rrs, Vhl, Vhr, Rlt, Rrt )\
208 CHLIST08( MOV_CH_LAYOUT_MPEG_7_1_A, L, R, C, LFE, Ls, Rs, Lc, Rc )\
209 CHLIST08( MOV_CH_LAYOUT_MPEG_7_1_B, C, Lc, Rc, L, R, Ls, Rs, LFE )\
210 CHLIST08( MOV_CH_LAYOUT_EMAGIC_DEFAULT_7_1, L, R, Ls, Rs, C, LFE, Lc, Rc )\
211 CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_B, L, C, R, Ls, Rs, LFE, Lc, Rc )\
212 CHLIST08( MOV_CH_LAYOUT_DTS_7_1, Lc, C, Rc, L, R, Ls, Rs, LFE )\
213 CHLIST08( MOV_CH_LAYOUT_MPEG_7_1_C, L, R, C, LFE, Ls, Rs, Rls, Rrs )\
214 CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_A, L, C, R, Ls, Rs, LFE, Rls, Rrs )\
215 CHLIST08( MOV_CH_LAYOUT_SMPTE_DTV, L, R, C, LFE, Ls, Rs, Lt, Rt )\
216 CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_C, L, C, R, Ls, Rs, LFE, Lsd, Rsd )\
217 CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_D, L, C, R, Ls, Rs, LFE, Lw, Rw )\
218 CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_E, L, C, R, Ls, Rs, LFE, Vhl, Vhr )\
219 CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_F, L, C, R, Ls, Rs, LFE, Cs, Ts )\
220 CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_G, L, C, R, Ls, Rs, LFE, Cs, Vhc )\
221 CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_H, L, C, R, Ls, Rs, LFE, Ts, Vhc )\
222 CHLIST08( MOV_CH_LAYOUT_DTS_8_0_A, Lc, Rc, L, R, Ls, Rs, Rls, Rrs )\
223 CHLIST08( MOV_CH_LAYOUT_DTS_8_0_B, Lc, C, Rc, L, R, Ls, Cs, Rs )\
224 CHLIST09( MOV_CH_LAYOUT_DTS_8_1_A, Lc, Rc, L, R, Ls, Rs, Rls, Rrs, LFE )\
225 CHLIST09( MOV_CH_LAYOUT_DTS_8_1_B, Lc, C, Rc, L, R, Ls, Cs, Rs, LFE )\
226 CHLIST16( MOV_CH_LAYOUT_TMH_10_2_STD, L, R, C, Vhc, Lsd, Rsd, Ls, Rs, Vhl, Vhr, Lw, Rw, Csd, Cs, LFE1, LFE2 )\
227 CHLIST21( MOV_CH_LAYOUT_TMH_10_2_FULL, L, R, C, Vhc, Lsd, Rsd, Ls, Rs, Vhl, Vhr, Lw, Rw, Csd, Cs, LFE1, LFE2, Lc, Rc, HI, VI, Haptic )\
228
229 #define CHLIST(_tag, _cnt, ...) static_assert((_tag & 0xffff) == _cnt, "Channel count of " #_tag " is not " #_cnt);
230 MOV_CH_LAYOUT_MAP
231 #undef CHLIST
232 #define CHLIST(_tag, _cnt, ...) TAG(_tag, _cnt), __VA_ARGS__,
233 static const struct MovChannelLayoutMap mov_ch_layout_map[] = {
234 MOV_CH_LAYOUT_MAP
235 { {0} },
236 };
237
238 #undef ID
239 #undef TAG
240 #define ID(_0) {.id = iso_##_0}
241 #define TAG(_tag, _cnt) {.tag = (_tag << 16) | _cnt}
242
243 /* ISO/IEC 23001-8 */
244 static const struct MovChannelLayoutMap iso_ch_layout_map[] = {
245 CHLIST01( 1, C )
246 CHLIST02( 2, L, R )
247 CHLIST03( 3, C, L, R )
248 CHLIST04( 4, C, L, R, Cs )
249 CHLIST05( 5, C, L, R, Ls, Rs )
250 CHLIST06( 6, C, L, R, Ls, Rs, LFE )
251 CHLIST08( 7, C, Lc, Rc, L, R, Ls, Rs, LFE )
252 CHLIST03( 9, L, R, Cs )
253 CHLIST04( 10, L, R, Ls, Rs )
254 CHLIST07( 11, C, L, R, Ls, Rs, Cs, LFE )
255 CHLIST08( 12, C, L, R, Ls, Rs, Lsr, Rsr, LFE )
256 CHLIST24( 13, C, Lc, Rc, L, R, Lss, Rss, Lsr, Rsr, Cs, LFE, LFE2, Cv, Lv, Rv, Lvss, Rvss, Ts, Lvr, Rvr, Cvr, Cb, Lb, Rb)
257 CHLIST08( 14, C, L, R, Ls, Rs, LFE, Lv, Rv)
258 { {0} },
259 };
260
261 static const enum MovChannelLayoutTag mov_ch_layouts_aac[] = {
262 MOV_CH_LAYOUT_MONO,
263 MOV_CH_LAYOUT_STEREO,
264 MOV_CH_LAYOUT_AC3_1_0_1,
265 MOV_CH_LAYOUT_MPEG_3_0_B,
266 MOV_CH_LAYOUT_ITU_2_1,
267 MOV_CH_LAYOUT_DVD_4,
268 MOV_CH_LAYOUT_QUADRAPHONIC,
269 MOV_CH_LAYOUT_MPEG_4_0_B,
270 MOV_CH_LAYOUT_ITU_2_2,
271 MOV_CH_LAYOUT_AC3_2_1_1,
272 MOV_CH_LAYOUT_DTS_3_1,
273 MOV_CH_LAYOUT_MPEG_5_0_D,
274 MOV_CH_LAYOUT_DVD_18,
275 MOV_CH_LAYOUT_DTS_4_1,
276 MOV_CH_LAYOUT_MPEG_5_1_D,
277 MOV_CH_LAYOUT_AAC_6_0,
278 MOV_CH_LAYOUT_DTS_6_0_A,
279 MOV_CH_LAYOUT_AAC_6_1,
280 MOV_CH_LAYOUT_AAC_7_0,
281 MOV_CH_LAYOUT_DTS_6_1_A,
282 MOV_CH_LAYOUT_AAC_OCTAGONAL,
283 MOV_CH_LAYOUT_MPEG_7_1_B,
284 MOV_CH_LAYOUT_DTS_8_0_A,
285 0,
286 };
287
288 static const enum MovChannelLayoutTag mov_ch_layouts_ac3[] = {
289 MOV_CH_LAYOUT_MONO,
290 MOV_CH_LAYOUT_STEREO,
291 MOV_CH_LAYOUT_AC3_1_0_1,
292 MOV_CH_LAYOUT_AC3_3_0,
293 MOV_CH_LAYOUT_ITU_2_1,
294 MOV_CH_LAYOUT_DVD_4,
295 MOV_CH_LAYOUT_AC3_3_1,
296 MOV_CH_LAYOUT_ITU_2_2,
297 MOV_CH_LAYOUT_AC3_2_1_1,
298 MOV_CH_LAYOUT_AC3_3_0_1,
299 MOV_CH_LAYOUT_MPEG_5_0_C,
300 MOV_CH_LAYOUT_DVD_18,
301 MOV_CH_LAYOUT_AC3_3_1_1,
302 MOV_CH_LAYOUT_MPEG_5_1_C,
303 0,
304 };
305
306 static const enum MovChannelLayoutTag mov_ch_layouts_alac[] = {
307 MOV_CH_LAYOUT_MONO,
308 MOV_CH_LAYOUT_STEREO,
309 MOV_CH_LAYOUT_MPEG_3_0_B,
310 MOV_CH_LAYOUT_MPEG_4_0_B,
311 MOV_CH_LAYOUT_MPEG_5_0_D,
312 MOV_CH_LAYOUT_MPEG_5_1_D,
313 MOV_CH_LAYOUT_AAC_6_1,
314 MOV_CH_LAYOUT_MPEG_7_1_B,
315 0,
316 };
317
318 static const enum MovChannelLayoutTag mov_ch_layouts_wav[] = {
319 MOV_CH_LAYOUT_MONO,
320 MOV_CH_LAYOUT_STEREO,
321 MOV_CH_LAYOUT_MATRIXSTEREO,
322 MOV_CH_LAYOUT_MPEG_3_0_A,
323 MOV_CH_LAYOUT_QUADRAPHONIC,
324 MOV_CH_LAYOUT_MPEG_5_0_A,
325 MOV_CH_LAYOUT_MPEG_5_1_A,
326 MOV_CH_LAYOUT_MPEG_6_1_A,
327 MOV_CH_LAYOUT_MPEG_7_1_A,
328 MOV_CH_LAYOUT_MPEG_7_1_C,
329 MOV_CH_LAYOUT_SMPTE_DTV,
330 0,
331 };
332
333 static const struct {
334 enum AVCodecID codec_id;
335 const enum MovChannelLayoutTag *layouts;
336 } mov_codec_ch_layouts[] = {
337 { AV_CODEC_ID_AAC, mov_ch_layouts_aac },
338 { AV_CODEC_ID_AC3, mov_ch_layouts_ac3 },
339 { AV_CODEC_ID_ADPCM_IMA_QT, mov_ch_layouts_wav },
340 { AV_CODEC_ID_ALAC, mov_ch_layouts_alac },
341 { AV_CODEC_ID_MACE3, mov_ch_layouts_wav },
342 { AV_CODEC_ID_MACE6, mov_ch_layouts_wav },
343 { AV_CODEC_ID_PCM_ALAW, mov_ch_layouts_wav },
344 { AV_CODEC_ID_PCM_F32BE, mov_ch_layouts_wav },
345 { AV_CODEC_ID_PCM_F32LE, mov_ch_layouts_wav },
346 { AV_CODEC_ID_PCM_F64BE, mov_ch_layouts_wav },
347 { AV_CODEC_ID_PCM_F64LE, mov_ch_layouts_wav },
348 { AV_CODEC_ID_PCM_MULAW, mov_ch_layouts_wav },
349 { AV_CODEC_ID_PCM_S16BE, mov_ch_layouts_wav },
350 { AV_CODEC_ID_PCM_S16LE, mov_ch_layouts_wav },
351 { AV_CODEC_ID_PCM_S24BE, mov_ch_layouts_wav },
352 { AV_CODEC_ID_PCM_S24LE, mov_ch_layouts_wav },
353 { AV_CODEC_ID_PCM_S32BE, mov_ch_layouts_wav },
354 { AV_CODEC_ID_PCM_S32LE, mov_ch_layouts_wav },
355 { AV_CODEC_ID_PCM_S8, mov_ch_layouts_wav },
356 { AV_CODEC_ID_PCM_U8, mov_ch_layouts_wav },
357 { AV_CODEC_ID_SPEEX, mov_ch_layouts_wav },
358 { AV_CODEC_ID_NONE, NULL },
359 };
360
361 100 static const struct MovChannelLayoutMap* find_layout_map(uint32_t tag, const struct MovChannelLayoutMap *map)
362 {
363
1/2
✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
184 for (int i = 0; map[i].tag & 0xffff; i += 1 + (map[i].tag & 0xffff))
364
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 84 times.
184 if (map[i].tag == tag)
365 100 return &map[i + 1];
366 return NULL;
367 }
368
369 /**
370 * Get the channel layout for the specified non-special channel layout tag if
371 * known.
372 *
373 * @param[in,out] ch_layout channel layout
374 * @param[in] tag channel layout tag
375 * @return <0 on error
376 */
377 50 static int mov_get_channel_layout(AVChannelLayout *ch_layout, uint32_t tag, uint64_t omitted_channel_map, const struct MovChannelLayoutMap *map)
378 {
379 const struct MovChannelLayoutMap *layout_map;
380
381 /* find the channel layout for the specified layout tag */
382 50 layout_map = find_layout_map(tag, map);
383
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 if (layout_map) {
384 50 AVChannelLayout tmp = { 0 };
385 int ret;
386 50 int map_layout_nb_channels = tag & 0xFFFF;
387 50 int nb_channels = ch_layout->nb_channels;
388
389 /* Omitted channel bits must not exceed number of channels in map */
390
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (omitted_channel_map >> map_layout_nb_channels)
391 return AVERROR_INVALIDDATA;
392
393 50 ret = av_channel_layout_custom_init(&tmp, nb_channels);
394
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (ret < 0)
395 return ret;
396
397
3/4
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 85 times.
✗ Branch 3 not taken.
135 for (int i = 0, idx = 0; i < map_layout_nb_channels && idx < nb_channels; i++, omitted_channel_map >>= 1) {
398
1/2
✓ Branch 0 taken 85 times.
✗ Branch 1 not taken.
85 if (!(omitted_channel_map & 1)) {
399 85 enum AVChannel id = layout_map[i].id;
400
1/2
✓ Branch 0 taken 85 times.
✗ Branch 1 not taken.
85 tmp.u.map[idx++].id = (id != AV_CHAN_NONE ? id : AV_CHAN_UNKNOWN);
401 }
402 }
403
404 50 ret = av_channel_layout_retype(&tmp, 0, AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL);
405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (ret < 0) {
406 av_channel_layout_uninit(&tmp);
407 return ret;
408 }
409
410 50 av_channel_layout_uninit(ch_layout);
411 50 *ch_layout = tmp;
412 }
413 50 return 0;
414 }
415
416 3 static enum AVChannel mov_get_channel_id(uint32_t label)
417 {
418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (label == 0)
419 return AV_CHAN_UNUSED;
420
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (label <= 18)
421 1 return (label - 1);
422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (label == 35)
423 return AV_CHAN_WIDE_LEFT;
424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (label == 36)
425 return AV_CHAN_WIDE_RIGHT;
426
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (label == 37)
427 return AV_CHAN_LOW_FREQUENCY_2;
428
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (label == 38)
429 1 return AV_CHAN_STEREO_LEFT;
430
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (label == 39)
431 1 return AV_CHAN_STEREO_RIGHT;
432 return AV_CHAN_UNKNOWN;
433 }
434
435 2 static uint32_t mov_get_channel_label(enum AVChannel channel)
436 {
437
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (channel < 0)
438 return 0;
439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (channel <= AV_CHAN_TOP_BACK_RIGHT)
440 return channel + 1;
441
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (channel == AV_CHAN_WIDE_LEFT)
442 return 35;
443
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (channel == AV_CHAN_WIDE_RIGHT)
444 return 36;
445
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (channel == AV_CHAN_LOW_FREQUENCY_2)
446 return 37;
447
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (channel == AV_CHAN_STEREO_LEFT)
448 1 return 38;
449
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (channel == AV_CHAN_STEREO_RIGHT)
450 1 return 39;
451 return 0;
452 }
453
454 182 static int is_layout_valid_for_tag(const AVChannelLayout *ch_layout, uint32_t tag, const struct MovChannelLayoutMap *map)
455 {
456 const struct MovChannelLayoutMap *layout_map;
457 182 int channels = ch_layout->nb_channels;
458
459 /* get the layout map based on the channel count */
460
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 50 times.
182 if ((tag & 0xFFFF) != channels)
461 132 return 0;
462
463 50 layout_map = find_layout_map(tag, map);
464
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 if (layout_map) {
465 int i;
466
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 35 times.
105 for (i = 0; i < channels; i++) {
467
2/2
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 55 times.
70 if (av_channel_layout_channel_from_index(ch_layout, i) != layout_map[i].id)
468 15 break;
469 }
470
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 15 times.
50 if (i == channels)
471 35 return 1;
472 }
473 15 return 0;
474 }
475
476 39 int ff_mov_get_channel_layout_tag(const AVCodecParameters *par,
477 uint32_t *layout,
478 uint32_t *bitmap,
479 uint32_t **pchannel_desc)
480 {
481 int i;
482 39 uint32_t tag = 0;
483 39 const enum MovChannelLayoutTag *layouts = NULL;
484
485 /* find the layout list for the specified codec */
486
1/2
✓ Branch 0 taken 326 times.
✗ Branch 1 not taken.
326 for (i = 0; mov_codec_ch_layouts[i].codec_id != AV_CODEC_ID_NONE; i++) {
487
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 287 times.
326 if (mov_codec_ch_layouts[i].codec_id == par->codec_id)
488 39 break;
489 }
490
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 if (mov_codec_ch_layouts[i].codec_id != AV_CODEC_ID_NONE)
491 39 layouts = mov_codec_ch_layouts[i].layouts;
492
493
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 if (layouts) {
494 /* find the layout tag for the specified channel layout */
495
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 7 times.
131 for (i = 0; layouts[i] != 0; i++)
496
2/2
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 92 times.
124 if (is_layout_valid_for_tag(&par->ch_layout, layouts[i], mov_ch_layout_map))
497 32 break;
498
499 39 tag = layouts[i];
500 }
501
502 39 *layout = tag;
503 39 *bitmap = 0;
504 39 *pchannel_desc = NULL;
505
506 /* if no tag was found, use channel bitmap or description as a backup if possible */
507
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 32 times.
39 if (tag == 0) {
508 uint32_t *channel_desc;
509
510
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (par->ch_layout.order == AV_CHANNEL_ORDER_NATIVE) {
511 /* Parsers and encoders (e.g. AC3, AAC, ALAC) indicate/propagate the bitstream's
512 * channel configuration using "standard" layouts in AV_CHANNEL_ORDER_NATIVE but
513 * the encoded bitstream's channels are not actually in that order. Don't return
514 * a channel layout bitmap or description using a conflicting channel order, as
515 * some software will incorrectly override the bitstream-provided information
516 * using the chan atom's data instead (e.g. afinfo/afplay for AAC in MOV) */
517
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (layouts != mov_ch_layouts_wav) {
518 *layout = MOV_CH_LAYOUT_UNKNOWN;
519 return 0;
520 }
521
522
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 if (par->ch_layout.u.mask < 0x40000) {
523 5 *layout = MOV_CH_LAYOUT_USE_BITMAP;
524 5 *bitmap = (uint32_t)par->ch_layout.u.mask;
525 5 return 0;
526 }
527 } else if (par->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC)
528 return AVERROR(ENOSYS);
529
530 2 channel_desc = av_malloc_array(par->ch_layout.nb_channels, sizeof(*channel_desc));
531
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!channel_desc)
532 return AVERROR(ENOMEM);
533
534
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 for (i = 0; i < par->ch_layout.nb_channels; i++) {
535 4 channel_desc[i] =
536 2 mov_get_channel_label(av_channel_layout_channel_from_index(&par->ch_layout, i));
537
538
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (channel_desc[i] == 0) {
539 av_free(channel_desc);
540 return AVERROR(ENOSYS);
541 }
542 }
543
544 2 *pchannel_desc = channel_desc;
545 }
546
547 34 return 0;
548 }
549
550 60 int ff_mov_read_chan(AVFormatContext *s, AVIOContext *pb, AVStream *st,
551 int64_t size)
552 {
553 uint32_t layout_tag, bitmap, num_descr;
554 int ret;
555 60 AVChannelLayout *ch_layout = &st->codecpar->ch_layout;
556
557
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (size < 12)
558 return AVERROR_INVALIDDATA;
559
560 60 layout_tag = avio_rb32(pb);
561 60 bitmap = avio_rb32(pb);
562 60 num_descr = avio_rb32(pb);
563
564 60 av_log(s, AV_LOG_DEBUG, "chan: layout=%"PRIu32" "
565 "bitmap=%"PRIu32" num_descr=%"PRIu32"\n",
566 layout_tag, bitmap, num_descr);
567
568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (size < 12ULL + num_descr * 20ULL)
569 return 0;
570
571
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 57 times.
60 if (layout_tag == MOV_CH_LAYOUT_USE_DESCRIPTIONS) {
572 3 AVChannelLayout tmp = { 0 };
573 3 int nb_channels = ch_layout->nb_channels;
574
575
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (!num_descr || num_descr < nb_channels) {
576 av_log(s, AV_LOG_ERROR, "got %"PRIu32" channel descriptions when at least %d were needed\n",
577 num_descr, nb_channels);
578 return AVERROR_INVALIDDATA;
579 }
580
581
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (num_descr > nb_channels) {
582 int strict = s->strict_std_compliance >= FF_COMPLIANCE_STRICT;
583 av_log(s, strict ? AV_LOG_ERROR : AV_LOG_WARNING,
584 "got %"PRIu32" channel descriptions when number of channels is %d\n",
585 num_descr, nb_channels);
586 if (strict)
587 return AVERROR_INVALIDDATA;
588 av_log(s, AV_LOG_WARNING, "capping channel descriptions to the number of channels\n");
589 num_descr = nb_channels;
590 }
591
592 3 ret = av_channel_layout_custom_init(&tmp, nb_channels);
593
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (ret < 0)
594 goto out;
595
596
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 for (int i = 0; i < num_descr; i++) {
597 uint32_t label;
598
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (pb->eof_reached) {
599 av_log(s, AV_LOG_ERROR,
600 "reached EOF while reading channel layout\n");
601 av_channel_layout_uninit(&tmp);
602 return AVERROR_INVALIDDATA;
603 }
604 3 label = avio_rb32(pb); // mChannelLabel
605 3 avio_rb32(pb); // mChannelFlags
606 3 avio_rl32(pb); // mCoordinates[0]
607 3 avio_rl32(pb); // mCoordinates[1]
608 3 avio_rl32(pb); // mCoordinates[2]
609 3 size -= 20;
610 3 tmp.u.map[i].id = mov_get_channel_id(label);
611 }
612
613 3 ret = av_channel_layout_retype(&tmp, 0, AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL);
614
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (ret < 0) {
615 av_channel_layout_uninit(&tmp);
616 goto out;
617 }
618
619 3 av_channel_layout_uninit(ch_layout);
620 3 *ch_layout = tmp;
621
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 49 times.
57 } else if (layout_tag == MOV_CH_LAYOUT_USE_BITMAP) {
622
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 if (!ch_layout->nb_channels || av_popcount(bitmap) == ch_layout->nb_channels) {
623
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (bitmap < 0x40000) {
624 8 av_channel_layout_uninit(ch_layout);
625 8 av_channel_layout_from_mask(ch_layout, bitmap);
626 }
627 } else {
628 av_log(s, AV_LOG_WARNING, "ignoring channel layout bitmap with %d channels because number of channels is %d\n",
629 av_popcount64(bitmap), ch_layout->nb_channels);
630 }
631
1/2
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
49 } else if (layout_tag & 0xFFFF) {
632 49 int nb_channels = layout_tag & 0xFFFF;
633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
49 if (!ch_layout->nb_channels)
634 ch_layout->nb_channels = nb_channels;
635
1/2
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
49 if (nb_channels == ch_layout->nb_channels) {
636 49 ret = mov_get_channel_layout(ch_layout, layout_tag, 0, mov_ch_layout_map);
637
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
49 if (ret < 0)
638 return ret;
639 } else {
640 av_log(s, AV_LOG_WARNING, "ignoring layout tag with %d channels because number of channels is %d\n",
641 nb_channels, ch_layout->nb_channels);
642 }
643 }
644 60 ret = 0;
645
646 60 out:
647 60 avio_skip(pb, size - 12);
648
649 60 return ret;
650 }
651
652 /* ISO/IEC 23001-8, table 8 */
653 static const enum AVChannel iso_channel_position[] = {
654 [0] = AV_CHAN_FRONT_LEFT, // left front
655 [1] = AV_CHAN_FRONT_RIGHT, // right front
656 [2] = AV_CHAN_FRONT_CENTER, // centre front
657 [3] = AV_CHAN_LOW_FREQUENCY, // low frequency enhancement
658 [4] = AV_CHAN_SIDE_LEFT, // left surround
659 [5] = AV_CHAN_SIDE_RIGHT, // right surround
660 [6] = AV_CHAN_FRONT_LEFT_OF_CENTER, // left front centre
661 [7] = AV_CHAN_FRONT_RIGHT_OF_CENTER, // right front centre
662 [8] = AV_CHAN_BACK_LEFT, // rear surround left
663 [9] = AV_CHAN_BACK_RIGHT, // rear surround right
664 [10] = AV_CHAN_BACK_CENTER, // rear centre
665 [11] = AV_CHAN_SURROUND_DIRECT_LEFT, // left surround direct
666 [12] = AV_CHAN_SURROUND_DIRECT_RIGHT, // right surround direct
667 [13] = AV_CHAN_SIDE_SURROUND_LEFT, // left side surround
668 [14] = AV_CHAN_SIDE_SURROUND_RIGHT, // right side surround
669 [15] = AV_CHAN_WIDE_LEFT, // left wide front
670 [16] = AV_CHAN_WIDE_RIGHT, // right wide front
671 [17] = AV_CHAN_TOP_FRONT_LEFT, // left front vertical height
672 [18] = AV_CHAN_TOP_FRONT_RIGHT, // right front vertical height
673 [19] = AV_CHAN_TOP_FRONT_CENTER, // centre front vertical height
674 [20] = AV_CHAN_TOP_BACK_LEFT, // left surround vertical height rear
675 [21] = AV_CHAN_TOP_BACK_RIGHT, // right surround vertical height rear
676 [22] = AV_CHAN_TOP_BACK_CENTER, // centre vertical height rear
677 [23] = AV_CHAN_TOP_SIDE_LEFT, // left vertical height side surround
678 [24] = AV_CHAN_TOP_SIDE_RIGHT, // right vertical height side surround
679 [25] = AV_CHAN_TOP_CENTER, // top centre surround
680 [26] = AV_CHAN_LOW_FREQUENCY_2, // low frequency enhancement 2
681 [27] = AV_CHAN_BOTTOM_FRONT_LEFT, // left front vertical bottom
682 [28] = AV_CHAN_BOTTOM_FRONT_RIGHT, // right front vertical bottom
683 [29] = AV_CHAN_BOTTOM_FRONT_CENTER, // centre front vertical bottom
684 [30] = AV_CHAN_TOP_SURROUND_LEFT, // left vertical height surround
685 [31] = AV_CHAN_TOP_SURROUND_RIGHT, // right vertical height surround
686
687 [32] = AV_CHAN_NONE, // reserved
688 [33] = AV_CHAN_NONE, // reserved
689 [34] = AV_CHAN_NONE, // reserved
690 [35] = AV_CHAN_NONE, // reserved
691
692 [36] = AV_CHAN_NONE, // low frequency enhancement 3
693 [37] = AV_CHAN_NONE, // left edge of screen
694 [38] = AV_CHAN_NONE, // right edge of screen
695 [39] = AV_CHAN_NONE, // half-way between centre of screen and left edge of screen
696 [40] = AV_CHAN_NONE, // half-way between centre of screen and right edge of screen
697 [41] = AV_CHAN_NONE, // left back surround
698 [42] = AV_CHAN_NONE, // right back surround
699
700 // 43 - 125: reserved
701 // 126: explicit position
702 // 127: unknown /undefined
703 };
704
705 7 int ff_mov_get_channel_config_from_layout(const AVChannelLayout *layout, int *config)
706 {
707 // Set default value which means any setup in 23001-8
708 7 *config = 0;
709
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 4 times.
62 for (int i = 0; iso_ch_layout_map[i].tag & 0xffff; i += 1 + (iso_ch_layout_map[i].tag & 0xffff)) {
710
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 55 times.
58 if (is_layout_valid_for_tag(layout, iso_ch_layout_map[i].tag, &iso_ch_layout_map[i])) {
711 3 *config = iso_ch_layout_map[i].tag >> 16;
712 3 break;
713 }
714 }
715
716 7 return 0;
717 }
718
719 /**
720 * Get AVChannelLayout from ISO/IEC 23001-8 ChannelConfiguration.
721 *
722 * @return 1 if the config was unknown, layout is untouched in this case
723 * 0 if the config was found
724 * <0 on error
725 */
726 1 static int mov_get_channel_layout_from_config(int config, AVChannelLayout *layout, uint64_t omitted_channel_map)
727 {
728
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (config > 0) {
729 uint32_t layout_tag;
730 1 int nb_omitted_channels = av_popcount64(omitted_channel_map);
731
732
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (layout->nb_channels <= 0 || layout->nb_channels > UINT16_MAX - nb_omitted_channels)
733 return AVERROR_INVALIDDATA;
734
735 1 layout_tag = (config << 16) | (layout->nb_channels + nb_omitted_channels);
736 1 return mov_get_channel_layout(layout, layout_tag, omitted_channel_map, iso_ch_layout_map);
737 }
738 return 1;
739 }
740
741 4 int ff_mov_get_channel_positions_from_layout(const AVChannelLayout *layout,
742 uint8_t *position, int position_num)
743 {
744 enum AVChannel channel;
745
746
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (position_num < layout->nb_channels)
747 return AVERROR(EINVAL);
748
749
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 4 times.
24 for (int i = 0; i < layout->nb_channels; i++) {
750 20 position[i] = 127;
751 20 channel = av_channel_layout_channel_from_index(layout, i);
752
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (channel == AV_CHAN_NONE)
753 return AVERROR(EINVAL);
754
755
1/2
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
81 for (int j = 0; j < FF_ARRAY_ELEMS(iso_channel_position); j++) {
756
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 61 times.
81 if (iso_channel_position[j] == channel) {
757 20 position[i] = j;
758 20 break;
759 }
760 }
761
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (position[i] == 127)
762 return AVERROR(EINVAL);
763 }
764
765 4 return 0;
766 }
767
768 5 int ff_mov_read_chnl(AVFormatContext *s, AVIOContext *pb, AVStream *st, int version)
769 {
770 5 int stream_structure = avio_r8(pb);
771 int base_channel_count;
772 5 int obj_count = 0;
773 int ret;
774
775
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (version == 1) {
776 stream_structure >>= 4;
777 base_channel_count = avio_r8(pb);
778 }
779
780 // stream carries channels
781
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (stream_structure & 1) {
782 5 int layout = avio_r8(pb);
783
784 5 av_log(s, AV_LOG_TRACE, "'chnl' layout %d\n", layout);
785
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (!layout) {
786 4 AVChannelLayout tmp = { 0 }, *ch_layout = &st->codecpar->ch_layout;
787 4 int nb_channels = ch_layout->nb_channels;
788
789
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (version == 1) {
790 nb_channels = avio_r8(pb);
791 obj_count = base_channel_count - nb_channels;
792 if (obj_count < 0)
793 return AVERROR_INVALIDDATA;
794 }
795
796 4 ret = av_channel_layout_custom_init(&tmp, nb_channels);
797
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < 0)
798 return ret;
799
800
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 4 times.
24 for (int i = 0; i < nb_channels; i++) {
801 20 int speaker_pos = avio_r8(pb);
802 enum AVChannel channel;
803
804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (speaker_pos == 126) // explicit position
805 avio_skip(pb, 3); // azimuth, elevation
806
807
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (speaker_pos >= FF_ARRAY_ELEMS(iso_channel_position))
808 channel = AV_CHAN_NONE;
809 else
810 20 channel = iso_channel_position[speaker_pos];
811
812
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (channel == AV_CHAN_NONE) {
813 av_log(s, AV_LOG_WARNING, "speaker position %d is not implemented\n", speaker_pos);
814 channel = AV_CHAN_UNKNOWN;
815 }
816
817 20 tmp.u.map[i].id = channel;
818 }
819
820 4 ret = av_channel_layout_retype(&tmp, 0, AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL);
821
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < 0) {
822 av_channel_layout_uninit(&tmp);
823 return ret;
824 }
825 4 av_channel_layout_uninit(ch_layout);
826 4 *ch_layout = tmp;
827 } else {
828 1 uint64_t omitted_channel_map = 0;
829 1 int omitted_channel_present = 1, channel_order_definition = 0;
830
831
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (version == 1) {
832 int byte = avio_r8(pb);
833 omitted_channel_present = byte & 1;
834 channel_order_definition = (byte >> 1) & 0x7;
835 }
836
837
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (omitted_channel_present)
838 1 omitted_channel_map = avio_rb64(pb);
839
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!channel_order_definition) {
840 1 ret = mov_get_channel_layout_from_config(layout, &st->codecpar->ch_layout, omitted_channel_map);
841
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
842 return ret;
843 } else
844 av_log(s, AV_LOG_TRACE, "'chnl' with channel_order_definition %d\n", channel_order_definition);
845
846
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (version == 1)
847 obj_count = base_channel_count - st->codecpar->ch_layout.nb_channels;
848 }
849 }
850
851 // stream carries objects
852
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (stream_structure & 2) {
853 if (version == 0)
854 obj_count = avio_r8(pb);
855 av_log(s, AV_LOG_TRACE, "'chnl' with object_count %d\n", obj_count);
856 }
857
858 5 return 0;
859 }
860