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