qt: playlist: use item title if available
[vlc.git] / modules / audio_filter / converter / tospdif.c
blobbe01958b301e3d0e32690af76d9609539dffa083
1 /*****************************************************************************
2 * tospdif.c : encapsulates A/52 and DTS frames into S/PDIF packets
3 *****************************************************************************
4 * Copyright (C) 2002, 2006-2016 VLC authors and VideoLAN
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
7 * Stéphane Borel <stef@via.ecp.fr>
8 * Rémi Denis-Courmont
9 * Rafaël Carré
10 * Thomas Guillem
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2.1 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this program; if not, write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include <assert.h>
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
36 #include <vlc_aout.h>
37 #include <vlc_filter.h>
39 #include "../../packetizer/a52.h"
40 #include "../../packetizer/dts_header.h"
42 static int Open( vlc_object_t * );
44 vlc_module_begin ()
45 set_category( CAT_AUDIO )
46 set_subcategory( SUBCAT_AUDIO_AFILTER )
47 set_description( N_("Audio filter for A/52/DTS->S/PDIF encapsulation") )
48 set_capability( "audio converter", 10 )
49 set_callback( Open )
50 vlc_module_end ()
52 typedef struct
54 block_t *p_out_buf;
55 size_t i_out_offset;
57 union
59 struct
61 unsigned int i_nb_blocks;
62 } eac3;
63 struct
65 unsigned int i_frame_count;
66 } truehd;
67 struct
69 bool b_skip;
70 } dtshd;
72 } filter_sys_t;
74 #define SPDIF_HEADER_SIZE 8
76 #define IEC61937_AC3 0x01
77 #define IEC61937_EAC3 0x15
78 #define IEC61937_TRUEHD 0x16
79 #define IEC61937_DTS1 0x0B
80 #define IEC61937_DTS2 0x0C
81 #define IEC61937_DTS3 0x0D
82 #define IEC61937_DTSHD 0x11
84 #define SPDIF_MORE_DATA 1
85 #define SPDIF_SUCCESS VLC_SUCCESS
86 #define SPDIF_ERROR VLC_EGENERIC
88 static bool is_big_endian( filter_t *p_filter, block_t *p_in_buf )
90 switch( p_filter->fmt_in.audio.i_format )
92 case VLC_CODEC_A52:
93 case VLC_CODEC_EAC3:
94 case VLC_CODEC_MLP:
95 case VLC_CODEC_TRUEHD:
96 return true;
97 case VLC_CODEC_DTS:
98 case VLC_CODEC_DTSHD:
99 return p_in_buf->p_buffer[0] == 0x1F
100 || p_in_buf->p_buffer[0] == 0x7F;
101 default:
102 vlc_assert_unreachable();
106 static void set_16( filter_t *p_filter, void *p_buf, uint16_t i_val )
108 if( p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB )
109 SetWBE( p_buf, i_val );
110 else
111 SetWLE( p_buf, i_val );
114 static void write_16( filter_t *p_filter, uint16_t i_val )
116 filter_sys_t *p_sys = p_filter->p_sys;
117 assert( p_sys->p_out_buf != NULL );
119 assert( p_sys->p_out_buf->i_buffer - p_sys->i_out_offset
120 >= sizeof( uint16_t ) );
121 set_16( p_filter, &p_sys->p_out_buf->p_buffer[p_sys->i_out_offset], i_val );
122 p_sys->i_out_offset += sizeof( uint16_t );
125 static void write_padding( filter_t *p_filter, size_t i_size )
127 filter_sys_t *p_sys = p_filter->p_sys;
128 assert( p_sys->p_out_buf != NULL );
130 assert( p_sys->p_out_buf->i_buffer - p_sys->i_out_offset >= i_size );
132 uint8_t *p_out = &p_sys->p_out_buf->p_buffer[p_sys->i_out_offset];
133 memset( p_out, 0, i_size );
134 p_sys->i_out_offset += i_size;
137 static void write_data( filter_t *p_filter, const void *p_buf, size_t i_size,
138 bool b_input_big_endian )
140 filter_sys_t *p_sys = p_filter->p_sys;
141 assert( p_sys->p_out_buf != NULL );
143 bool b_output_big_endian =
144 p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB;
145 uint8_t *p_out = &p_sys->p_out_buf->p_buffer[p_sys->i_out_offset];
146 const uint8_t *p_in = p_buf;
148 assert( p_sys->p_out_buf->i_buffer - p_sys->i_out_offset >= i_size );
150 if( b_input_big_endian != b_output_big_endian )
151 swab( p_in, p_out, i_size & ~1 );
152 else
153 memcpy( p_out, p_in, i_size & ~1 );
154 p_sys->i_out_offset += ( i_size & ~1 );
156 if( i_size & 1 )
158 assert( p_sys->p_out_buf->i_buffer - p_sys->i_out_offset >= 2 );
159 p_out += ( i_size & ~1 );
160 set_16( p_filter, p_out, p_in[i_size - 1] << 8 );
161 p_sys->i_out_offset += 2;
165 static void write_buffer( filter_t *p_filter, block_t *p_in_buf )
167 filter_sys_t *p_sys = p_filter->p_sys;
168 write_data( p_filter, p_in_buf->p_buffer, p_in_buf->i_buffer,
169 is_big_endian( p_filter, p_in_buf ) );
170 p_sys->p_out_buf->i_length += p_in_buf->i_length;
173 static int write_init( filter_t *p_filter, block_t *p_in_buf,
174 size_t i_out_size, unsigned i_nb_samples )
176 filter_sys_t *p_sys = p_filter->p_sys;
178 assert( p_sys->p_out_buf == NULL );
179 assert( i_out_size > SPDIF_HEADER_SIZE && ( i_out_size & 3 ) == 0 );
181 p_sys->p_out_buf = block_Alloc( i_out_size );
182 if( !p_sys->p_out_buf )
183 return VLC_ENOMEM;
184 p_sys->p_out_buf->i_dts = p_in_buf->i_dts;
185 p_sys->p_out_buf->i_pts = p_in_buf->i_pts;
186 p_sys->p_out_buf->i_nb_samples = i_nb_samples;
188 p_sys->i_out_offset = SPDIF_HEADER_SIZE; /* Place for the S/PDIF header */
189 return VLC_SUCCESS;
192 static void write_finalize( filter_t *p_filter, uint16_t i_data_type,
193 uint8_t i_length_mul )
195 filter_sys_t *p_sys = p_filter->p_sys;
196 assert( p_sys->p_out_buf != NULL );
197 assert( i_data_type != 0 );
198 uint8_t *p_out = p_sys->p_out_buf->p_buffer;
200 /* S/PDIF header */
201 assert( p_sys->i_out_offset > SPDIF_HEADER_SIZE );
202 assert( i_length_mul == 1 || i_length_mul == 8 );
204 set_16( p_filter, &p_out[0], 0xf872 ); /* syncword 1 */
205 set_16( p_filter, &p_out[2], 0x4e1f ); /* syncword 2 */
206 set_16( p_filter, &p_out[4], i_data_type ); /* data type */
207 /* length in bits or bytes */
208 set_16( p_filter, &p_out[6],
209 ( p_sys->i_out_offset - SPDIF_HEADER_SIZE ) * i_length_mul );
211 /* 0 padding */
212 if( p_sys->i_out_offset < p_sys->p_out_buf->i_buffer )
213 write_padding( p_filter,
214 p_sys->p_out_buf->i_buffer - p_sys->i_out_offset );
217 static int write_buffer_ac3( filter_t *p_filter, block_t *p_in_buf )
219 static const size_t a52_size = A52_FRAME_NB * 4;
221 if( unlikely( p_in_buf->i_buffer < 6
222 || p_in_buf->i_buffer + SPDIF_HEADER_SIZE > a52_size
223 || p_in_buf->i_nb_samples != A52_FRAME_NB ) )
225 /* Input is not correctly packetizer. Try to parse the buffer in order
226 * to get the mandatory informations to play AC3 over S/PDIF */
227 vlc_a52_header_t a52;
228 if( vlc_a52_header_Parse( &a52, p_in_buf->p_buffer, p_in_buf->i_buffer )
229 != VLC_SUCCESS || a52.b_eac3 || a52.i_size > p_in_buf->i_buffer )
230 return SPDIF_ERROR;
231 p_in_buf->i_buffer = a52.i_size;
232 p_in_buf->i_nb_samples = a52.i_samples;
235 if( p_in_buf->i_buffer + SPDIF_HEADER_SIZE > a52_size
236 || write_init( p_filter, p_in_buf, a52_size, A52_FRAME_NB ) )
237 return SPDIF_ERROR;
238 write_buffer( p_filter, p_in_buf );
239 write_finalize( p_filter, IEC61937_AC3 |
240 ( ( p_in_buf->p_buffer[5] & 0x7 ) << 8 ) /* bsmod */,
241 8 /* in bits */ );
243 return SPDIF_SUCCESS;
247 static int write_buffer_eac3( filter_t *p_filter, block_t *p_in_buf )
249 filter_sys_t *p_sys = p_filter->p_sys;
251 /* The input block can contain the following:
252 * a/ One EAC3 independent stream (with 1, 2, 3 or 6 audio blocks per
253 * syncframe)
254 * b/ One AC3 stream followed by one EAC3 dependent stream (with 6 audio
255 * blocks per syncframe)
256 * c/ One EAC3 independent stream followed by one EAC3 dependent stream
257 * (with 1, 2, 3 or 6 audio blocks per syncframe)
259 * One IEC61937_EAC3 frame must contain 6 audio blocks per syncframe. This
260 * function will gather input blocks until it reaches this amount of audio
261 * blocks.
263 * Example: for the c/ case with 1 audio blocks per syncframe, a
264 * IEC61937_EAC3 frame will contain 12 a52 streams: 6 independent + 6
265 * dependent EAC3 streams.
268 vlc_a52_header_t a52;
269 if( vlc_a52_header_Parse( &a52, p_in_buf->p_buffer, p_in_buf->i_buffer )
270 != VLC_SUCCESS || a52.i_size > p_in_buf->i_buffer )
271 return SPDIF_ERROR;
273 if( p_in_buf->i_buffer > a52.i_size )
275 /* Check if the next stream is an eac3 dependent one */
276 vlc_a52_header_t a52_dep;
277 const uint8_t *dep_buf = &p_in_buf->p_buffer[a52.i_size];
278 const size_t dep_size = p_in_buf->i_buffer - a52.i_size;
280 if( vlc_a52_header_Parse( &a52_dep, dep_buf, dep_size ) != VLC_SUCCESS
281 || a52_dep.i_size > dep_size
282 || !a52_dep.b_eac3 || a52_dep.bs.eac3.strmtyp != EAC3_STRMTYP_DEPENDENT
283 || p_in_buf->i_buffer > a52.i_size + a52_dep.i_size )
284 return SPDIF_ERROR;
287 if( !p_sys->p_out_buf
288 && write_init( p_filter, p_in_buf, AOUT_SPDIF_SIZE * 4, AOUT_SPDIF_SIZE ) )
289 return SPDIF_ERROR;
290 if( p_in_buf->i_buffer > p_sys->p_out_buf->i_buffer - p_sys->i_out_offset )
291 return SPDIF_ERROR;
293 write_buffer( p_filter, p_in_buf );
295 /* cf. Annex E 2.3 of AC3 spec */
296 p_sys->eac3.i_nb_blocks += a52.i_blocks_per_sync_frame;
298 if( p_sys->eac3.i_nb_blocks < 6 )
299 return SPDIF_MORE_DATA;
300 else if ( p_sys->eac3.i_nb_blocks > 6 )
301 return SPDIF_ERROR;
303 write_finalize( p_filter, IEC61937_EAC3, 1 /* in bytes */ );
304 p_sys->eac3.i_nb_blocks = 0;
305 return SPDIF_SUCCESS;
308 /* Adapted from libavformat/spdifenc.c:
309 * It seems Dolby TrueHD frames have to be encapsulated in MAT frames before
310 * they can be encapsulated in IEC 61937.
311 * Here we encapsulate 24 TrueHD frames in a single MAT frame, padding them
312 * to achieve constant rate.
313 * The actual format of a MAT frame is unknown, but the below seems to work.
314 * However, it seems it is not actually necessary for the 24 TrueHD frames to
315 * be in an exact alignment with the MAT frame
317 static int write_buffer_truehd( filter_t *p_filter, block_t *p_in_buf )
319 #define TRUEHD_FRAME_OFFSET 2560
321 filter_sys_t *p_sys = p_filter->p_sys;
323 if( !p_sys->p_out_buf
324 && write_init( p_filter, p_in_buf, 61440, 61440 / 16 ) )
325 return SPDIF_ERROR;
327 int i_padding = 0;
328 if( p_sys->truehd.i_frame_count == 0 )
330 static const char p_mat_start_code[20] = {
331 0x07, 0x9E, 0x00, 0x03, 0x84, 0x01, 0x01, 0x01, 0x80, 0x00,
332 0x56, 0xA5, 0x3B, 0xF4, 0x81, 0x83, 0x49, 0x80, 0x77, 0xE0
334 write_data( p_filter, p_mat_start_code, 20, true );
335 /* We need to include the S/PDIF header in the first MAT frame */
336 i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - 20
337 - SPDIF_HEADER_SIZE;
339 else if( p_sys->truehd.i_frame_count == 11 )
341 /* The middle mat code need to be at the ((2560 * 12) - 4) offset */
342 i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - 4;
344 else if( p_sys->truehd.i_frame_count == 12 )
346 static const char p_mat_middle_code[12] = {
347 0xC3, 0xC1, 0x42, 0x49, 0x3B, 0xFA,
348 0x82, 0x83, 0x49, 0x80, 0x77, 0xE0
350 write_data( p_filter, p_mat_middle_code, 12, true );
351 i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - ( 12 - 4 );
353 else if( p_sys->truehd.i_frame_count == 23 )
355 static const char p_mat_end_code[16] = {
356 0xC3, 0xC2, 0xC0, 0xC4, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x11
360 /* The end mat code need to be at the ((2560 * 24) - 24) offset */
361 i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - 24;
363 if( i_padding < 0 || p_in_buf->i_buffer + i_padding >
364 p_sys->p_out_buf->i_buffer - p_sys->i_out_offset )
365 return SPDIF_ERROR;
367 write_buffer( p_filter, p_in_buf );
368 write_padding( p_filter, i_padding );
369 write_data( p_filter, p_mat_end_code, 16, true );
370 write_finalize( p_filter, IEC61937_TRUEHD, 1 /* in bytes */ );
371 p_sys->truehd.i_frame_count = 0;
372 return SPDIF_SUCCESS;
374 else
375 i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer;
377 if( i_padding < 0 || p_in_buf->i_buffer + i_padding >
378 p_sys->p_out_buf->i_buffer - p_sys->i_out_offset )
379 return SPDIF_ERROR;
381 write_buffer( p_filter, p_in_buf );
382 write_padding( p_filter, i_padding );
383 p_sys->truehd.i_frame_count++;
384 return SPDIF_MORE_DATA;
387 static int write_buffer_dts( filter_t *p_filter, block_t *p_in_buf )
389 uint16_t i_data_type;
390 filter_sys_t *p_sys = p_filter->p_sys;
392 /* Only send the DTS core part */
393 vlc_dts_header_t core;
394 if( vlc_dts_header_Parse( &core, p_in_buf->p_buffer,
395 p_in_buf->i_buffer ) != VLC_SUCCESS )
396 return SPDIF_ERROR;
397 p_in_buf->i_nb_samples = core.i_frame_length;
398 p_in_buf->i_buffer = core.i_frame_size;
400 switch( p_in_buf->i_nb_samples )
402 case 512:
403 i_data_type = IEC61937_DTS1;
404 break;
405 case 1024:
406 i_data_type = IEC61937_DTS2;
407 break;
408 case 2048:
409 i_data_type = IEC61937_DTS3;
410 break;
411 default:
412 msg_Err( p_filter, "Frame size %d not supported",
413 p_in_buf->i_nb_samples );
414 return SPDIF_ERROR;
417 if( core.syncword == DTS_SYNC_CORE_14BITS_BE ||
418 core.syncword == DTS_SYNC_CORE_14BITS_LE )
420 if( p_in_buf->i_buffer > p_in_buf->i_nb_samples * 4 )
421 return SPDIF_ERROR;
422 if( write_init( p_filter, p_in_buf, p_in_buf->i_nb_samples * 4,
423 p_in_buf->i_nb_samples ) )
424 return SPDIF_ERROR;
426 uint8_t *p_out = &p_sys->p_out_buf->p_buffer[p_sys->i_out_offset];
427 ssize_t i_size = vlc_dts_header_Convert14b16b( p_out,
428 p_sys->p_out_buf->i_buffer - p_sys->i_out_offset,
429 p_in_buf->p_buffer, p_in_buf->i_buffer,
430 p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFL );
431 if( i_size < 0 )
432 return SPDIF_ERROR;
434 p_sys->i_out_offset += i_size;
435 p_sys->p_out_buf->i_length += p_in_buf->i_length;
437 else
439 if( p_in_buf->i_buffer + SPDIF_HEADER_SIZE > p_in_buf->i_nb_samples * 4 )
440 return SPDIF_ERROR;
442 if( write_init( p_filter, p_in_buf, p_in_buf->i_nb_samples * 4,
443 p_in_buf->i_nb_samples ) )
444 return SPDIF_ERROR;
445 write_buffer( p_filter, p_in_buf );
448 write_finalize( p_filter, i_data_type, 8 /* in bits */ );
449 return SPDIF_SUCCESS;
452 /* Adapted from libavformat/spdifenc.c:
453 * DTS type IV (DTS-HD) can be transmitted with various frame repetition
454 * periods; longer repetition periods allow for longer packets and therefore
455 * higher bitrate. Longer repetition periods mean that the constant bitrate of
456 * the output IEC 61937 stream is higher.
457 * The repetition period is measured in IEC 60958 frames (4 bytes).
459 static int dtshd_get_subtype( unsigned i_frame_length )
461 switch( i_frame_length )
463 case 512: return 0x0;
464 case 1024: return 0x1;
465 case 2048: return 0x2;
466 case 4096: return 0x3;
467 case 8192: return 0x4;
468 case 16384: return 0x5;
469 default: return -1;
473 /* Adapted from libavformat/spdifenc.c: */
474 static int write_buffer_dtshd( filter_t *p_filter, block_t *p_in_buf )
476 static const char p_dtshd_start_code[10] = {
477 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe
479 static const size_t i_dtshd_start_code = sizeof( p_dtshd_start_code );
481 filter_sys_t *p_sys = p_filter->p_sys;
482 vlc_dts_header_t core;
483 if( vlc_dts_header_Parse( &core, p_in_buf->p_buffer,
484 p_in_buf->i_buffer ) != VLC_SUCCESS )
485 return SPDIF_ERROR;
486 unsigned i_period = p_filter->fmt_out.audio.i_rate
487 * core.i_frame_length / core.i_rate;
489 int i_subtype = dtshd_get_subtype( i_period );
490 if( i_subtype == -1 )
491 return SPDIF_ERROR;
493 size_t i_in_size = i_dtshd_start_code + 2 + p_in_buf->i_buffer;
494 size_t i_out_size = i_period * 4;
495 uint16_t i_data_type = IEC61937_DTSHD | i_subtype << 8;
497 if( p_sys->dtshd.b_skip
498 || i_in_size + SPDIF_HEADER_SIZE > i_out_size )
500 /* The bitrate is too high, pass only the core part */
501 p_in_buf->i_buffer = core.i_frame_size;
502 i_in_size = i_dtshd_start_code + 2 + p_in_buf->i_buffer;
503 if( i_in_size + SPDIF_HEADER_SIZE > i_out_size )
504 return SPDIF_ERROR;
506 /* Don't try to send substreams anymore. That way, we avoid to switch
507 * back and forth between DTD and DTS-HD */
508 p_sys->dtshd.b_skip = true;
511 if( write_init( p_filter, p_in_buf, i_out_size,
512 i_out_size / p_filter->fmt_out.audio.i_bytes_per_frame ) )
513 return SPDIF_ERROR;
515 write_data( p_filter, p_dtshd_start_code, i_dtshd_start_code, true );
516 write_16( p_filter, p_in_buf->i_buffer );
517 write_buffer( p_filter, p_in_buf );
519 /* Align so that (length_code & 0xf) == 0x8. This is reportedly needed
520 * with some receivers, but the exact requirement is unconfirmed. */
521 size_t i_align = vlc_align( i_in_size + 0x8, 0x10 ) - 0x8;
523 if( i_align > i_in_size && i_align - i_in_size
524 <= p_sys->p_out_buf->i_buffer - p_sys->i_out_offset )
525 write_padding( p_filter, i_align - i_in_size );
527 write_finalize( p_filter, i_data_type, 1 /* in bytes */ );
528 return SPDIF_SUCCESS;
531 static void Flush( filter_t *p_filter )
533 filter_sys_t *p_sys = p_filter->p_sys;
535 if( p_sys->p_out_buf != NULL )
537 block_Release( p_sys->p_out_buf );
538 p_sys->p_out_buf = NULL;
540 switch( p_filter->fmt_in.audio.i_format )
542 case VLC_CODEC_TRUEHD:
543 p_sys->truehd.i_frame_count = 0;
544 break;
545 case VLC_CODEC_EAC3:
546 p_sys->eac3.i_nb_blocks = 0;
547 break;
548 default:
549 break;
553 static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
555 filter_sys_t *p_sys = p_filter->p_sys;
556 block_t *p_out_buf = NULL;
558 int i_ret;
559 switch( p_filter->fmt_in.audio.i_format )
561 case VLC_CODEC_A52:
562 i_ret = write_buffer_ac3( p_filter, p_in_buf );
563 break;
564 case VLC_CODEC_EAC3:
565 i_ret = write_buffer_eac3( p_filter, p_in_buf );
566 break;
567 case VLC_CODEC_MLP:
568 case VLC_CODEC_TRUEHD:
569 i_ret = write_buffer_truehd( p_filter, p_in_buf );
570 break;
571 case VLC_CODEC_DTSHD:
572 i_ret = write_buffer_dtshd( p_filter, p_in_buf );
573 break;
574 case VLC_CODEC_DTS:
575 i_ret = write_buffer_dts( p_filter, p_in_buf );
576 break;
577 default:
578 vlc_assert_unreachable();
581 switch( i_ret )
583 case SPDIF_SUCCESS:
584 assert( p_sys->p_out_buf->i_buffer == p_sys->i_out_offset );
585 p_out_buf = p_sys->p_out_buf;
586 p_sys->p_out_buf = NULL;
587 break;
588 case SPDIF_MORE_DATA:
589 break;
590 case SPDIF_ERROR:
591 filter_Flush( p_filter );
592 break;
595 block_Release( p_in_buf );
596 return p_out_buf;
599 static void Close( filter_t *p_filter )
601 Flush( p_filter );
602 free( p_filter->p_sys );
605 static int Open( vlc_object_t *p_this )
607 filter_t *p_filter = (filter_t *)p_this;
608 filter_sys_t *p_sys;
610 if( ( p_filter->fmt_in.audio.i_format != VLC_CODEC_DTS &&
611 p_filter->fmt_in.audio.i_format != VLC_CODEC_DTSHD &&
612 p_filter->fmt_in.audio.i_format != VLC_CODEC_A52 &&
613 p_filter->fmt_in.audio.i_format != VLC_CODEC_EAC3 &&
614 p_filter->fmt_in.audio.i_format != VLC_CODEC_MLP &&
615 p_filter->fmt_in.audio.i_format != VLC_CODEC_TRUEHD ) ||
616 ( p_filter->fmt_out.audio.i_format != VLC_CODEC_SPDIFL &&
617 p_filter->fmt_out.audio.i_format != VLC_CODEC_SPDIFB ) )
618 return VLC_EGENERIC;
620 p_sys = p_filter->p_sys = calloc( 1, sizeof(filter_sys_t) );
621 if( unlikely( p_sys == NULL ) )
622 return VLC_ENOMEM;
624 static const struct vlc_filter_operations filter_ops =
626 .filter_audio = DoWork,
627 .flush = Flush,
628 .close = Close,
630 p_filter->ops = &filter_ops;
632 return VLC_SUCCESS;