Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (C) 2016 foo86 | ||
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 | #include "libavutil/opt.h" | ||
22 | #include "libavutil/channel_layout.h" | ||
23 | #include "libavutil/thread.h" | ||
24 | |||
25 | #include "codec_internal.h" | ||
26 | #include "dcadec.h" | ||
27 | #include "dcahuff.h" | ||
28 | #include "dca_syncwords.h" | ||
29 | #include "profiles.h" | ||
30 | |||
31 | #define MIN_PACKET_SIZE 16 | ||
32 | #define MAX_PACKET_SIZE 0x104000 | ||
33 | |||
34 | 2483 | int ff_dca_set_channel_layout(AVCodecContext *avctx, int *ch_remap, int dca_mask) | |
35 | { | ||
36 | static const uint8_t dca2wav_norm[28] = { | ||
37 | 2, 0, 1, 9, 10, 3, 8, 4, 5, 9, 10, 6, 7, 12, | ||
38 | 13, 14, 3, 6, 7, 11, 12, 14, 16, 15, 17, 8, 4, 5, | ||
39 | }; | ||
40 | |||
41 | static const uint8_t dca2wav_wide[28] = { | ||
42 | 2, 0, 1, 4, 5, 3, 8, 4, 5, 9, 10, 6, 7, 12, | ||
43 | 13, 14, 3, 9, 10, 11, 12, 14, 16, 15, 17, 8, 4, 5, | ||
44 | }; | ||
45 | |||
46 | 2483 | DCAContext *s = avctx->priv_data; | |
47 | |||
48 | 2483 | int dca_ch, wav_ch, nchannels = 0; | |
49 | |||
50 | 2483 | av_channel_layout_uninit(&avctx->ch_layout); | |
51 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2483 times.
|
2483 | if (s->output_channel_order == CHANNEL_ORDER_CODED) { |
52 | ✗ | for (dca_ch = 0; dca_ch < DCA_SPEAKER_COUNT; dca_ch++) | |
53 | ✗ | if (dca_mask & (1U << dca_ch)) | |
54 | ✗ | ch_remap[nchannels++] = dca_ch; | |
55 | ✗ | avctx->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; | |
56 | ✗ | avctx->ch_layout.nb_channels = nchannels; | |
57 | } else { | ||
58 | 2483 | int wav_mask = 0; | |
59 | int wav_map[18]; | ||
60 | const uint8_t *dca2wav; | ||
61 |
3/4✓ Branch 0 taken 2483 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1177 times.
✓ Branch 3 taken 1306 times.
|
2483 | if (dca_mask == DCA_SPEAKER_LAYOUT_7POINT0_WIDE || |
62 | dca_mask == DCA_SPEAKER_LAYOUT_7POINT1_WIDE) | ||
63 | 1177 | dca2wav = dca2wav_wide; | |
64 | else | ||
65 | 1306 | dca2wav = dca2wav_norm; | |
66 |
2/2✓ Branch 0 taken 69524 times.
✓ Branch 1 taken 2483 times.
|
72007 | for (dca_ch = 0; dca_ch < 28; dca_ch++) { |
67 |
2/2✓ Branch 0 taken 15431 times.
✓ Branch 1 taken 54093 times.
|
69524 | if (dca_mask & (1 << dca_ch)) { |
68 | 15431 | wav_ch = dca2wav[dca_ch]; | |
69 |
1/2✓ Branch 0 taken 15431 times.
✗ Branch 1 not taken.
|
15431 | if (!(wav_mask & (1 << wav_ch))) { |
70 | 15431 | wav_map[wav_ch] = dca_ch; | |
71 | 15431 | wav_mask |= 1 << wav_ch; | |
72 | } | ||
73 | } | ||
74 | } | ||
75 |
2/2✓ Branch 0 taken 44694 times.
✓ Branch 1 taken 2483 times.
|
47177 | for (wav_ch = 0; wav_ch < 18; wav_ch++) |
76 |
2/2✓ Branch 0 taken 15431 times.
✓ Branch 1 taken 29263 times.
|
44694 | if (wav_mask & (1 << wav_ch)) |
77 | 15431 | ch_remap[nchannels++] = wav_map[wav_ch]; | |
78 | |||
79 | 2483 | av_channel_layout_from_mask(&avctx->ch_layout, wav_mask); | |
80 | } | ||
81 | |||
82 | 2483 | return nchannels; | |
83 | } | ||
84 | |||
85 | 7 | void ff_dca_downmix_to_stereo_fixed(DCADSPContext *dcadsp, int32_t **samples, | |
86 | int *coeff_l, int nsamples, int ch_mask) | ||
87 | { | ||
88 | 7 | int pos, spkr, max_spkr = av_log2(ch_mask); | |
89 | 7 | int *coeff_r = coeff_l + av_popcount(ch_mask); | |
90 | |||
91 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | av_assert0(DCA_HAS_STEREO(ch_mask)); |
92 | |||
93 | // Scale left and right channels | ||
94 | 7 | pos = (ch_mask & DCA_SPEAKER_MASK_C); | |
95 | 7 | dcadsp->dmix_scale(samples[DCA_SPEAKER_L], coeff_l[pos ], nsamples); | |
96 | 7 | dcadsp->dmix_scale(samples[DCA_SPEAKER_R], coeff_r[pos + 1], nsamples); | |
97 | |||
98 | // Downmix remaining channels | ||
99 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 7 times.
|
49 | for (spkr = 0; spkr <= max_spkr; spkr++) { |
100 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if (!(ch_mask & (1U << spkr))) |
101 | ✗ | continue; | |
102 | |||
103 |
4/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 7 times.
|
42 | if (*coeff_l && spkr != DCA_SPEAKER_L) |
104 | 7 | dcadsp->dmix_add(samples[DCA_SPEAKER_L], samples[spkr], | |
105 | *coeff_l, nsamples); | ||
106 | |||
107 |
4/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 7 times.
|
42 | if (*coeff_r && spkr != DCA_SPEAKER_R) |
108 | 7 | dcadsp->dmix_add(samples[DCA_SPEAKER_R], samples[spkr], | |
109 | *coeff_r, nsamples); | ||
110 | |||
111 | 42 | coeff_l++; | |
112 | 42 | coeff_r++; | |
113 | } | ||
114 | 7 | } | |
115 | |||
116 | 7 | void ff_dca_downmix_to_stereo_float(AVFloatDSPContext *fdsp, float **samples, | |
117 | int *coeff_l, int nsamples, int ch_mask) | ||
118 | { | ||
119 | 7 | int pos, spkr, max_spkr = av_log2(ch_mask); | |
120 | 7 | int *coeff_r = coeff_l + av_popcount(ch_mask); | |
121 | 7 | const float scale = 1.0f / (1 << 15); | |
122 | |||
123 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | av_assert0(DCA_HAS_STEREO(ch_mask)); |
124 | |||
125 | // Scale left and right channels | ||
126 | 7 | pos = (ch_mask & DCA_SPEAKER_MASK_C); | |
127 | 7 | fdsp->vector_fmul_scalar(samples[DCA_SPEAKER_L], samples[DCA_SPEAKER_L], | |
128 | 7 | coeff_l[pos ] * scale, nsamples); | |
129 | 7 | fdsp->vector_fmul_scalar(samples[DCA_SPEAKER_R], samples[DCA_SPEAKER_R], | |
130 | 7 | coeff_r[pos + 1] * scale, nsamples); | |
131 | |||
132 | // Downmix remaining channels | ||
133 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 7 times.
|
49 | for (spkr = 0; spkr <= max_spkr; spkr++) { |
134 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if (!(ch_mask & (1U << spkr))) |
135 | ✗ | continue; | |
136 | |||
137 |
4/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 7 times.
|
42 | if (*coeff_l && spkr != DCA_SPEAKER_L) |
138 | 7 | fdsp->vector_fmac_scalar(samples[DCA_SPEAKER_L], samples[spkr], | |
139 | 7 | *coeff_l * scale, nsamples); | |
140 | |||
141 |
4/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 7 times.
|
42 | if (*coeff_r && spkr != DCA_SPEAKER_R) |
142 | 7 | fdsp->vector_fmac_scalar(samples[DCA_SPEAKER_R], samples[spkr], | |
143 | 7 | *coeff_r * scale, nsamples); | |
144 | |||
145 | 42 | coeff_l++; | |
146 | 42 | coeff_r++; | |
147 | } | ||
148 | 7 | } | |
149 | |||
150 | 2483 | static int dcadec_decode_frame(AVCodecContext *avctx, AVFrame *frame, | |
151 | int *got_frame_ptr, AVPacket *avpkt) | ||
152 | { | ||
153 | 2483 | DCAContext *s = avctx->priv_data; | |
154 | 2483 | const uint8_t *input = avpkt->data; | |
155 | 2483 | int input_size = avpkt->size; | |
156 | 2483 | int i, ret, prev_packet = s->packet; | |
157 | uint32_t mrk; | ||
158 | |||
159 |
2/4✓ Branch 0 taken 2483 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2483 times.
|
2483 | if (input_size < MIN_PACKET_SIZE || input_size > MAX_PACKET_SIZE) { |
160 | ✗ | av_log(avctx, AV_LOG_ERROR, "Invalid packet size\n"); | |
161 | ✗ | return AVERROR_INVALIDDATA; | |
162 | } | ||
163 | |||
164 | // Convert input to BE format | ||
165 | 2483 | mrk = AV_RB32(input); | |
166 |
3/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 2471 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
2483 | if (mrk != DCA_SYNCWORD_CORE_BE && mrk != DCA_SYNCWORD_SUBSTREAM) { |
167 | ✗ | av_fast_padded_malloc(&s->buffer, &s->buffer_size, input_size); | |
168 | ✗ | if (!s->buffer) | |
169 | ✗ | return AVERROR(ENOMEM); | |
170 | |||
171 | ✗ | for (i = 0, ret = AVERROR_INVALIDDATA; i < input_size - MIN_PACKET_SIZE + 1 && ret < 0; i++) | |
172 | ✗ | ret = avpriv_dca_convert_bitstream(input + i, input_size - i, s->buffer, s->buffer_size); | |
173 | |||
174 | ✗ | if (ret < 0) { | |
175 | ✗ | av_log(avctx, AV_LOG_ERROR, "Not a valid DCA frame\n"); | |
176 | ✗ | return ret; | |
177 | } | ||
178 | |||
179 | ✗ | input = s->buffer; | |
180 | ✗ | input_size = ret; | |
181 | } | ||
182 | |||
183 | 2483 | s->packet = 0; | |
184 | |||
185 | // Parse backward compatible core sub-stream | ||
186 |
2/2✓ Branch 0 taken 2471 times.
✓ Branch 1 taken 12 times.
|
2483 | if (AV_RB32(input) == DCA_SYNCWORD_CORE_BE) { |
187 | int frame_size; | ||
188 | |||
189 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2471 times.
|
2471 | if ((ret = ff_dca_core_parse(&s->core, input, input_size)) < 0) |
190 | ✗ | return ret; | |
191 | |||
192 | 2471 | s->packet |= DCA_PACKET_CORE; | |
193 | |||
194 | // EXXS data must be aligned on 4-byte boundary | ||
195 | 2471 | frame_size = FFALIGN(s->core.frame_size, 4); | |
196 |
2/2✓ Branch 0 taken 1401 times.
✓ Branch 1 taken 1070 times.
|
2471 | if (input_size - 4 > frame_size) { |
197 | 1401 | input += frame_size; | |
198 | 1401 | input_size -= frame_size; | |
199 | } | ||
200 | } | ||
201 | |||
202 |
1/2✓ Branch 0 taken 2483 times.
✗ Branch 1 not taken.
|
2483 | if (!s->core_only) { |
203 | 2483 | DCAExssAsset *asset = NULL; | |
204 | |||
205 | // Parse extension sub-stream (EXSS) | ||
206 |
2/2✓ Branch 0 taken 1413 times.
✓ Branch 1 taken 1070 times.
|
2483 | if (AV_RB32(input) == DCA_SYNCWORD_SUBSTREAM) { |
207 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1413 times.
|
1413 | if ((ret = ff_dca_exss_parse(&s->exss, input, input_size)) < 0) { |
208 | ✗ | if (avctx->err_recognition & AV_EF_EXPLODE) | |
209 | ✗ | return ret; | |
210 | } else { | ||
211 | 1413 | s->packet |= DCA_PACKET_EXSS; | |
212 | 1413 | asset = &s->exss.assets[0]; | |
213 | } | ||
214 | } | ||
215 | |||
216 | // Parse XLL component in EXSS | ||
217 |
4/4✓ Branch 0 taken 1413 times.
✓ Branch 1 taken 1070 times.
✓ Branch 2 taken 1357 times.
✓ Branch 3 taken 56 times.
|
2483 | if (asset && (asset->extension_mask & DCA_EXSS_XLL)) { |
218 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1357 times.
|
1357 | if ((ret = ff_dca_xll_parse(&s->xll, input, asset)) < 0) { |
219 | // Conceal XLL synchronization error | ||
220 | ✗ | if (ret == AVERROR(EAGAIN)) { | |
221 | ✗ | if ((prev_packet & DCA_PACKET_XLL) && (s->packet & DCA_PACKET_CORE)) | |
222 | ✗ | s->packet |= DCA_PACKET_XLL | DCA_PACKET_RECOVERY; | |
223 | ✗ | } else if (ret == AVERROR(ENOMEM) || (avctx->err_recognition & AV_EF_EXPLODE)) | |
224 | ✗ | return ret; | |
225 | } else { | ||
226 | 1357 | s->packet |= DCA_PACKET_XLL; | |
227 | } | ||
228 | } | ||
229 | |||
230 | // Parse LBR component in EXSS | ||
231 |
3/4✓ Branch 0 taken 1413 times.
✓ Branch 1 taken 1070 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1413 times.
|
2483 | if (asset && (asset->extension_mask & DCA_EXSS_LBR)) { |
232 | ✗ | if ((ret = ff_dca_lbr_parse(&s->lbr, input, asset)) < 0) { | |
233 | ✗ | if (ret == AVERROR(ENOMEM) || (avctx->err_recognition & AV_EF_EXPLODE)) | |
234 | ✗ | return ret; | |
235 | } else { | ||
236 | ✗ | s->packet |= DCA_PACKET_LBR; | |
237 | } | ||
238 | } | ||
239 | |||
240 | // Parse core extensions in EXSS or backward compatible core sub-stream | ||
241 |
2/2✓ Branch 0 taken 2471 times.
✓ Branch 1 taken 12 times.
|
2483 | if ((s->packet & DCA_PACKET_CORE) |
242 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2471 times.
|
2471 | && (ret = ff_dca_core_parse_exss(&s->core, input, asset)) < 0) |
243 | ✗ | return ret; | |
244 | } | ||
245 | |||
246 | // Filter the frame | ||
247 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2483 times.
|
2483 | if (s->packet & DCA_PACKET_LBR) { |
248 | ✗ | if ((ret = ff_dca_lbr_filter_frame(&s->lbr, frame)) < 0) | |
249 | ✗ | return ret; | |
250 |
2/2✓ Branch 0 taken 1357 times.
✓ Branch 1 taken 1126 times.
|
2483 | } else if (s->packet & DCA_PACKET_XLL) { |
251 |
2/2✓ Branch 0 taken 1345 times.
✓ Branch 1 taken 12 times.
|
1357 | if (s->packet & DCA_PACKET_CORE) { |
252 | 1345 | int x96_synth = -1; | |
253 | |||
254 | // Enable X96 synthesis if needed | ||
255 |
3/4✓ Branch 0 taken 84 times.
✓ Branch 1 taken 1261 times.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
|
1345 | if (s->xll.chset[0].freq == 96000 && s->core.sample_rate == 48000) |
256 | 84 | x96_synth = 1; | |
257 | |||
258 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1345 times.
|
1345 | if ((ret = ff_dca_core_filter_fixed(&s->core, x96_synth)) < 0) |
259 | ✗ | return ret; | |
260 | |||
261 | // Force lossy downmixed output on the first core frame filtered. | ||
262 | // This prevents audible clicks when seeking and is consistent with | ||
263 | // what reference decoder does when there are multiple channel sets. | ||
264 |
3/4✓ Branch 0 taken 54 times.
✓ Branch 1 taken 1291 times.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
|
1345 | if (!(prev_packet & DCA_PACKET_RESIDUAL) && s->xll.nreschsets > 0 |
265 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 18 times.
|
54 | && s->xll.nchsets > 1) { |
266 | 36 | av_log(avctx, AV_LOG_VERBOSE, "Forcing XLL recovery mode\n"); | |
267 | 36 | s->packet |= DCA_PACKET_RECOVERY; | |
268 | } | ||
269 | |||
270 | // Set 'residual ok' flag for the next frame | ||
271 | 1345 | s->packet |= DCA_PACKET_RESIDUAL; | |
272 | } | ||
273 | |||
274 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1357 times.
|
1357 | if ((ret = ff_dca_xll_filter_frame(&s->xll, frame)) < 0) { |
275 | // Fall back to core unless hard error | ||
276 | ✗ | if (!(s->packet & DCA_PACKET_CORE)) | |
277 | ✗ | return ret; | |
278 | ✗ | if (ret != AVERROR_INVALIDDATA || (avctx->err_recognition & AV_EF_EXPLODE)) | |
279 | ✗ | return ret; | |
280 | ✗ | if ((ret = ff_dca_core_filter_frame(&s->core, frame)) < 0) | |
281 | ✗ | return ret; | |
282 | } | ||
283 |
1/2✓ Branch 0 taken 1126 times.
✗ Branch 1 not taken.
|
1126 | } else if (s->packet & DCA_PACKET_CORE) { |
284 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1126 times.
|
1126 | if ((ret = ff_dca_core_filter_frame(&s->core, frame)) < 0) |
285 | ✗ | return ret; | |
286 |
2/2✓ Branch 0 taken 519 times.
✓ Branch 1 taken 607 times.
|
1126 | if (s->core.filter_mode & DCA_FILTER_MODE_FIXED) |
287 | 519 | s->packet |= DCA_PACKET_RESIDUAL; | |
288 | } else { | ||
289 | ✗ | av_log(avctx, AV_LOG_ERROR, "No valid DCA sub-stream found\n"); | |
290 | ✗ | if (s->core_only) | |
291 | ✗ | av_log(avctx, AV_LOG_WARNING, "Consider disabling 'core_only' option\n"); | |
292 | ✗ | return AVERROR_INVALIDDATA; | |
293 | } | ||
294 | |||
295 | 2483 | *got_frame_ptr = 1; | |
296 | |||
297 | 2483 | return avpkt->size; | |
298 | } | ||
299 | |||
300 | ✗ | static av_cold void dcadec_flush(AVCodecContext *avctx) | |
301 | { | ||
302 | ✗ | DCAContext *s = avctx->priv_data; | |
303 | |||
304 | ✗ | ff_dca_core_flush(&s->core); | |
305 | ✗ | ff_dca_xll_flush(&s->xll); | |
306 | ✗ | ff_dca_lbr_flush(&s->lbr); | |
307 | |||
308 | ✗ | s->packet &= DCA_PACKET_MASK; | |
309 | ✗ | } | |
310 | |||
311 | 99 | static av_cold int dcadec_close(AVCodecContext *avctx) | |
312 | { | ||
313 | 99 | DCAContext *s = avctx->priv_data; | |
314 | |||
315 | 99 | ff_dca_core_close(&s->core); | |
316 | 99 | ff_dca_xll_close(&s->xll); | |
317 | 99 | ff_dca_lbr_close(&s->lbr); | |
318 | |||
319 | 99 | av_freep(&s->buffer); | |
320 | 99 | s->buffer_size = 0; | |
321 | |||
322 | 99 | return 0; | |
323 | } | ||
324 | |||
325 | 54 | static av_cold void dcadec_init_static(void) | |
326 | { | ||
327 | 54 | ff_dca_lbr_init_tables(); | |
328 | 54 | ff_dca_init_vlcs(); | |
329 | 54 | } | |
330 | |||
331 | 99 | static av_cold int dcadec_init(AVCodecContext *avctx) | |
332 | { | ||
333 | static AVOnce init_static_once = AV_ONCE_INIT; | ||
334 | 99 | DCAContext *s = avctx->priv_data; | |
335 | |||
336 | 99 | s->avctx = avctx; | |
337 | 99 | s->core.avctx = avctx; | |
338 | 99 | s->exss.avctx = avctx; | |
339 | 99 | s->xll.avctx = avctx; | |
340 | 99 | s->lbr.avctx = avctx; | |
341 | |||
342 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
|
99 | if (ff_dca_core_init(&s->core) < 0) |
343 | ✗ | return AVERROR(ENOMEM); | |
344 | |||
345 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
|
99 | if (ff_dca_lbr_init(&s->lbr) < 0) |
346 | ✗ | return AVERROR(ENOMEM); | |
347 | |||
348 | 99 | ff_dcadsp_init(&s->dcadsp); | |
349 | 99 | s->core.dcadsp = &s->dcadsp; | |
350 | 99 | s->xll.dcadsp = &s->dcadsp; | |
351 | 99 | s->lbr.dcadsp = &s->dcadsp; | |
352 | |||
353 | 99 | s->crctab = av_crc_get_table(AV_CRC_16_CCITT); | |
354 | |||
355 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 55 times.
|
99 | if (s->downmix_layout.nb_channels) { |
356 |
3/4✓ Branch 1 taken 22 times.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 22 times.
|
66 | if (!av_channel_layout_compare(&s->downmix_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO) || |
357 | 22 | !av_channel_layout_compare(&s->downmix_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO_DOWNMIX)) { | |
358 | 22 | s->request_channel_layout = DCA_SPEAKER_LAYOUT_STEREO; | |
359 | 22 | av_channel_layout_uninit(&avctx->ch_layout); | |
360 | 22 | avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; | |
361 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
|
22 | } else if (!av_channel_layout_compare(&s->downmix_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT0)) { |
362 | ✗ | s->request_channel_layout = DCA_SPEAKER_LAYOUT_5POINT0; | |
363 | ✗ | av_channel_layout_uninit(&avctx->ch_layout); | |
364 | ✗ | avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT0; | |
365 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | } else if (!av_channel_layout_compare(&s->downmix_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT1)) { |
366 | 22 | s->request_channel_layout = DCA_SPEAKER_LAYOUT_5POINT1; | |
367 | 22 | av_channel_layout_uninit(&avctx->ch_layout); | |
368 | 22 | avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT1; | |
369 | } | ||
370 | else | ||
371 | ✗ | av_log(avctx, AV_LOG_WARNING, "Invalid downmix layout\n"); | |
372 | } | ||
373 | |||
374 | 99 | ff_thread_once(&init_static_once, dcadec_init_static); | |
375 | |||
376 | 99 | return 0; | |
377 | } | ||
378 | |||
379 | #define OFFSET(x) offsetof(DCAContext, x) | ||
380 | #define PARAM AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM | ||
381 | |||
382 | static const AVOption dcadec_options[] = { | ||
383 | { "core_only", "Decode core only without extensions", OFFSET(core_only), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, PARAM }, | ||
384 | |||
385 | { "channel_order", "Order in which the channels are to be exported", | ||
386 | OFFSET(output_channel_order), AV_OPT_TYPE_INT, | ||
387 | { .i64 = CHANNEL_ORDER_DEFAULT }, 0, 1, PARAM, .unit = "channel_order" }, | ||
388 | { "default", "normal libavcodec channel order", 0, AV_OPT_TYPE_CONST, | ||
389 | { .i64 = CHANNEL_ORDER_DEFAULT }, .flags = PARAM, .unit = "channel_order" }, | ||
390 | { "coded", "order in which the channels are coded in the bitstream", | ||
391 | 0, AV_OPT_TYPE_CONST, { .i64 = CHANNEL_ORDER_CODED }, .flags = PARAM, .unit = "channel_order" }, | ||
392 | |||
393 | { "downmix", "Request a specific channel layout from the decoder", OFFSET(downmix_layout), | ||
394 | AV_OPT_TYPE_CHLAYOUT, {.str = NULL}, .flags = PARAM }, | ||
395 | |||
396 | { NULL } | ||
397 | }; | ||
398 | |||
399 | static const AVClass dcadec_class = { | ||
400 | .class_name = "DCA decoder", | ||
401 | .item_name = av_default_item_name, | ||
402 | .option = dcadec_options, | ||
403 | .version = LIBAVUTIL_VERSION_INT, | ||
404 | .category = AV_CLASS_CATEGORY_DECODER, | ||
405 | }; | ||
406 | |||
407 | const FFCodec ff_dca_decoder = { | ||
408 | .p.name = "dca", | ||
409 | CODEC_LONG_NAME("DCA (DTS Coherent Acoustics)"), | ||
410 | .p.type = AVMEDIA_TYPE_AUDIO, | ||
411 | .p.id = AV_CODEC_ID_DTS, | ||
412 | .priv_data_size = sizeof(DCAContext), | ||
413 | .init = dcadec_init, | ||
414 | FF_CODEC_DECODE_CB(dcadec_decode_frame), | ||
415 | .close = dcadec_close, | ||
416 | .flush = dcadec_flush, | ||
417 | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, | ||
418 | .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, | ||
419 | AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, | ||
420 | .p.priv_class = &dcadec_class, | ||
421 | .p.profiles = NULL_IF_CONFIG_SMALL(ff_dca_profiles), | ||
422 | .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, | ||
423 | }; | ||
424 |