converter/tospdif: convert DTS 14bit to DTS 16bit
[vlc.git] / modules / audio_filter / converter / tospdif.c
blob21ffb1c2ac2e244493276ff7cfef16479094cf57
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
5 * $Id$
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * Stéphane Borel <stef@via.ecp.fr>
9 * Rémi Denis-Courmont
10 * Rafaël Carré
11 * Thomas Guillem
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU Lesser General Public License as published by
15 * the Free Software Foundation; either version 2.1 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this program; if not, write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <assert.h>
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
37 #include <vlc_aout.h>
38 #include <vlc_filter.h>
40 #include "../packetizer/a52.h"
41 #include "../packetizer/dts_header.h"
43 static int Open( vlc_object_t * );
44 static void Close( vlc_object_t * );
46 vlc_module_begin ()
47 set_category( CAT_AUDIO )
48 set_subcategory( SUBCAT_AUDIO_MISC )
49 set_description( N_("Audio filter for A/52/DTS->S/PDIF encapsulation") )
50 set_capability( "audio converter", 10 )
51 set_callbacks( Open, Close )
52 vlc_module_end ()
54 typedef struct
56 block_t *p_out_buf;
57 size_t i_out_offset;
59 union
61 struct
63 unsigned int i_nb_blocks;
64 } eac3;
65 struct
67 unsigned int i_frame_count;
68 } truehd;
69 struct
71 bool b_skip;
72 } dtshd;
74 } filter_sys_t;
76 #define SPDIF_HEADER_SIZE 8
78 #define IEC61937_AC3 0x01
79 #define IEC61937_EAC3 0x15
80 #define IEC61937_TRUEHD 0x16
81 #define IEC61937_DTS1 0x0B
82 #define IEC61937_DTS2 0x0C
83 #define IEC61937_DTS3 0x0D
84 #define IEC61937_DTSHD 0x11
86 #define SPDIF_MORE_DATA 1
87 #define SPDIF_SUCCESS VLC_SUCCESS
88 #define SPDIF_ERROR VLC_EGENERIC
90 static bool is_big_endian( filter_t *p_filter, block_t *p_in_buf )
92 switch( p_filter->fmt_in.audio.i_format )
94 case VLC_CODEC_A52:
95 case VLC_CODEC_EAC3:
96 case VLC_CODEC_MLP:
97 case VLC_CODEC_TRUEHD:
98 return true;
99 case VLC_CODEC_DTS:
100 return p_in_buf->p_buffer[0] == 0x1F
101 || p_in_buf->p_buffer[0] == 0x7F;
102 default:
103 vlc_assert_unreachable();
107 static void set_16( filter_t *p_filter, void *p_buf, uint16_t i_val )
109 if( p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB )
110 SetWBE( p_buf, i_val );
111 else
112 SetWLE( p_buf, i_val );
115 static void write_16( filter_t *p_filter, uint16_t i_val )
117 filter_sys_t *p_sys = p_filter->p_sys;
118 assert( p_sys->p_out_buf != NULL );
120 assert( p_sys->p_out_buf->i_buffer - p_sys->i_out_offset
121 >= sizeof( uint16_t ) );
122 set_16( p_filter, &p_sys->p_out_buf->p_buffer[p_sys->i_out_offset], i_val );
123 p_sys->i_out_offset += sizeof( uint16_t );
126 static void write_padding( filter_t *p_filter, size_t i_size )
128 filter_sys_t *p_sys = p_filter->p_sys;
129 assert( p_sys->p_out_buf != NULL );
131 assert( p_sys->p_out_buf->i_buffer - p_sys->i_out_offset >= i_size );
133 uint8_t *p_out = &p_sys->p_out_buf->p_buffer[p_sys->i_out_offset];
134 memset( p_out, 0, i_size );
135 p_sys->i_out_offset += i_size;
138 static void write_data( filter_t *p_filter, const void *p_buf, size_t i_size,
139 bool b_input_big_endian )
141 filter_sys_t *p_sys = p_filter->p_sys;
142 assert( p_sys->p_out_buf != NULL );
144 bool b_output_big_endian =
145 p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB;
146 uint8_t *p_out = &p_sys->p_out_buf->p_buffer[p_sys->i_out_offset];
147 const uint8_t *p_in = p_buf;
149 assert( p_sys->p_out_buf->i_buffer - p_sys->i_out_offset >= i_size );
151 if( b_input_big_endian != b_output_big_endian )
152 swab( p_in, p_out, i_size & ~1 );
153 else
154 memcpy( p_out, p_in, i_size & ~1 );
155 p_sys->i_out_offset += ( i_size & ~1 );
157 if( i_size & 1 )
159 assert( p_sys->p_out_buf->i_buffer - p_sys->i_out_offset >= 2 );
160 p_out += ( i_size & ~1 );
161 set_16( p_filter, p_out, p_in[i_size - 1] << 8 );
162 p_sys->i_out_offset += 2;
166 static void write_buffer( filter_t *p_filter, block_t *p_in_buf )
168 filter_sys_t *p_sys = p_filter->p_sys;
169 write_data( p_filter, p_in_buf->p_buffer, p_in_buf->i_buffer,
170 is_big_endian( p_filter, p_in_buf ) );
171 p_sys->p_out_buf->i_length += p_in_buf->i_length;
174 static int write_init( filter_t *p_filter, block_t *p_in_buf,
175 size_t i_out_size, unsigned i_nb_samples )
177 filter_sys_t *p_sys = p_filter->p_sys;
179 assert( p_sys->p_out_buf == NULL );
180 assert( i_out_size > SPDIF_HEADER_SIZE && ( i_out_size & 3 ) == 0 );
182 p_sys->p_out_buf = block_Alloc( i_out_size );
183 if( !p_sys->p_out_buf )
184 return VLC_ENOMEM;
185 p_sys->p_out_buf->i_dts = p_in_buf->i_dts;
186 p_sys->p_out_buf->i_pts = p_in_buf->i_pts;
187 p_sys->p_out_buf->i_nb_samples = i_nb_samples;
189 p_sys->i_out_offset = SPDIF_HEADER_SIZE; /* Place for the S/PDIF header */
190 return VLC_SUCCESS;
193 static void write_finalize( filter_t *p_filter, uint16_t i_data_type,
194 uint8_t i_length_mul )
196 filter_sys_t *p_sys = p_filter->p_sys;
197 assert( p_sys->p_out_buf != NULL );
198 assert( i_data_type != 0 );
199 uint8_t *p_out = p_sys->p_out_buf->p_buffer;
201 /* S/PDIF header */
202 assert( p_sys->i_out_offset > SPDIF_HEADER_SIZE );
203 assert( i_length_mul == 1 || i_length_mul == 8 );
205 set_16( p_filter, &p_out[0], 0xf872 ); /* syncword 1 */
206 set_16( p_filter, &p_out[2], 0x4e1f ); /* syncword 2 */
207 set_16( p_filter, &p_out[4], i_data_type ); /* data type */
208 /* length in bits or bytes */
209 set_16( p_filter, &p_out[6],
210 ( p_sys->i_out_offset - SPDIF_HEADER_SIZE ) * i_length_mul );
212 /* 0 padding */
213 if( p_sys->i_out_offset < p_sys->p_out_buf->i_buffer )
214 write_padding( p_filter,
215 p_sys->p_out_buf->i_buffer - p_sys->i_out_offset );
218 static int write_buffer_ac3( filter_t *p_filter, block_t *p_in_buf )
220 static const size_t a52_size = A52_FRAME_NB * 4;
222 if( unlikely( p_in_buf->i_buffer < 6
223 || p_in_buf->i_buffer > a52_size
224 || p_in_buf->i_nb_samples != A52_FRAME_NB ) )
226 /* Input is not correctly packetizer. Try to parse the buffer in order
227 * to get the mandatory informations to play AC3 over S/PDIF */
228 vlc_a52_header_t a52;
229 if( vlc_a52_header_Parse( &a52, p_in_buf->p_buffer, p_in_buf->i_buffer )
230 != VLC_SUCCESS || a52.b_eac3 || a52.i_size > p_in_buf->i_buffer )
231 return SPDIF_ERROR;
232 p_in_buf->i_buffer = a52.i_size;
233 p_in_buf->i_nb_samples = a52.i_samples;
236 if( p_in_buf->i_buffer + SPDIF_HEADER_SIZE > a52_size
237 || write_init( p_filter, p_in_buf, a52_size, A52_FRAME_NB ) )
238 return SPDIF_ERROR;
239 write_buffer( p_filter, p_in_buf );
240 write_finalize( p_filter, IEC61937_AC3 |
241 ( ( p_in_buf->p_buffer[5] & 0x7 ) << 8 ) /* bsmod */,
242 8 /* in bits */ );
244 return SPDIF_SUCCESS;
248 static int write_buffer_eac3( filter_t *p_filter, block_t *p_in_buf )
250 filter_sys_t *p_sys = p_filter->p_sys;
252 /* The input block can contain the following:
253 * a/ One EAC3 independent stream (with 1, 2, 3 or 6 audio blocks per
254 * syncframe)
255 * b/ One AC3 stream followed by one EAC3 dependent stream (with 6 audio
256 * blocks per syncframe)
257 * c/ One EAC3 independent stream followed by one EAC3 dependent stream
258 * (with 1, 2, 3 or 6 audio blocks per syncframe)
260 * One IEC61937_EAC3 frame must contain 6 audio blocks per syncframe. This
261 * function will gather input blocks until it reaches this amount of audio
262 * blocks.
264 * Example: for the c/ case with 1 audio blocks per syncframe, a
265 * IEC61937_EAC3 frame will contain 12 a52 streams: 6 independent + 6
266 * dependent EAC3 streams.
269 vlc_a52_header_t a52;
270 if( vlc_a52_header_Parse( &a52, p_in_buf->p_buffer, p_in_buf->i_buffer )
271 != VLC_SUCCESS || a52.i_size > p_in_buf->i_buffer )
272 return SPDIF_ERROR;
274 if( p_in_buf->i_buffer > a52.i_size )
276 /* Check if the next stream is an eac3 dependent one */
277 vlc_a52_header_t a52_dep;
278 const uint8_t *dep_buf = &p_in_buf->p_buffer[a52.i_size];
279 const size_t dep_size = p_in_buf->i_buffer - a52.i_size;
281 if( vlc_a52_header_Parse( &a52_dep, dep_buf, dep_size ) != VLC_SUCCESS
282 || a52_dep.i_size > dep_size
283 || !a52_dep.b_eac3 || a52_dep.eac3.strmtyp != EAC3_STRMTYP_DEPENDENT
284 || p_in_buf->i_buffer > a52.i_size + a52_dep.i_size )
285 return SPDIF_ERROR;
288 if( !p_sys->p_out_buf
289 && write_init( p_filter, p_in_buf, AOUT_SPDIF_SIZE * 4, AOUT_SPDIF_SIZE ) )
290 return SPDIF_ERROR;
291 if( p_in_buf->i_buffer > p_sys->p_out_buf->i_buffer - p_sys->i_out_offset )
292 return SPDIF_ERROR;
294 write_buffer( p_filter, p_in_buf );
296 /* cf. Annex E 2.3 of AC3 spec */
297 p_sys->eac3.i_nb_blocks += a52.i_blocks_per_sync_frame;
299 if( p_sys->eac3.i_nb_blocks < 6 )
300 return SPDIF_MORE_DATA;
301 else if ( p_sys->eac3.i_nb_blocks > 6 )
302 return SPDIF_ERROR;
304 write_finalize( p_filter, IEC61937_EAC3, 1 /* in bytes */ );
305 p_sys->eac3.i_nb_blocks = 0;
306 return SPDIF_SUCCESS;
309 /* Adapted from libavformat/spdifenc.c:
310 * It seems Dolby TrueHD frames have to be encapsulated in MAT frames before
311 * they can be encapsulated in IEC 61937.
312 * Here we encapsulate 24 TrueHD frames in a single MAT frame, padding them
313 * to achieve constant rate.
314 * The actual format of a MAT frame is unknown, but the below seems to work.
315 * However, it seems it is not actually necessary for the 24 TrueHD frames to
316 * be in an exact alignment with the MAT frame
318 static int write_buffer_truehd( filter_t *p_filter, block_t *p_in_buf )
320 #define TRUEHD_FRAME_OFFSET 2560
322 filter_sys_t *p_sys = p_filter->p_sys;
324 if( !p_sys->p_out_buf
325 && write_init( p_filter, p_in_buf, 61440, 61440 / 16 ) )
326 return SPDIF_ERROR;
328 int i_padding = 0;
329 if( p_sys->truehd.i_frame_count == 0 )
331 static const char p_mat_start_code[20] = {
332 0x07, 0x9E, 0x00, 0x03, 0x84, 0x01, 0x01, 0x01, 0x80, 0x00,
333 0x56, 0xA5, 0x3B, 0xF4, 0x81, 0x83, 0x49, 0x80, 0x77, 0xE0
335 write_data( p_filter, p_mat_start_code, 20, true );
336 /* We need to include the S/PDIF header in the first MAT frame */
337 i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - 20
338 - SPDIF_HEADER_SIZE;
340 else if( p_sys->truehd.i_frame_count == 11 )
342 /* The middle mat code need to be at the ((2560 * 12) - 4) offset */
343 i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - 4;
345 else if( p_sys->truehd.i_frame_count == 12 )
347 static const char p_mat_middle_code[12] = {
348 0xC3, 0xC1, 0x42, 0x49, 0x3B, 0xFA,
349 0x82, 0x83, 0x49, 0x80, 0x77, 0xE0
351 write_data( p_filter, p_mat_middle_code, 12, true );
352 i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - ( 12 - 4 );
354 else if( p_sys->truehd.i_frame_count == 23 )
356 static const char p_mat_end_code[16] = {
357 0xC3, 0xC2, 0xC0, 0xC4, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x11
361 /* The end mat code need to be at the ((2560 * 24) - 24) offset */
362 i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - 24;
364 if( i_padding < 0 || p_in_buf->i_buffer + i_padding >
365 p_sys->p_out_buf->i_buffer - p_sys->i_out_offset )
366 return SPDIF_ERROR;
368 write_buffer( p_filter, p_in_buf );
369 write_padding( p_filter, i_padding );
370 write_data( p_filter, p_mat_end_code, 16, true );
371 write_finalize( p_filter, IEC61937_TRUEHD, 1 /* in bytes */ );
372 p_sys->truehd.i_frame_count = 0;
373 return SPDIF_SUCCESS;
375 else
376 i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer;
378 if( i_padding < 0 || p_in_buf->i_buffer + i_padding >
379 p_sys->p_out_buf->i_buffer - p_sys->i_out_offset )
380 return SPDIF_ERROR;
382 write_buffer( p_filter, p_in_buf );
383 write_padding( p_filter, i_padding );
384 p_sys->truehd.i_frame_count++;
385 return SPDIF_MORE_DATA;
388 static int write_buffer_dts( filter_t *p_filter, block_t *p_in_buf )
390 uint16_t i_data_type;
391 filter_sys_t *p_sys = p_filter->p_sys;
393 /* Only send the DTS core part */
394 vlc_dts_header_t core;
395 if( vlc_dts_header_Parse( &core, p_in_buf->p_buffer,
396 p_in_buf->i_buffer ) != VLC_SUCCESS )
397 return SPDIF_ERROR;
398 p_in_buf->i_nb_samples = core.i_frame_length;
399 p_in_buf->i_buffer = core.i_frame_size;
401 switch( p_in_buf->i_nb_samples )
403 case 512:
404 i_data_type = IEC61937_DTS1;
405 break;
406 case 1024:
407 i_data_type = IEC61937_DTS2;
408 break;
409 case 2048:
410 i_data_type = IEC61937_DTS3;
411 break;
412 default:
413 msg_Err( p_filter, "Frame size %d not supported",
414 p_in_buf->i_nb_samples );
415 return SPDIF_ERROR;
418 if( core.b_14b )
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 #define ALIGN(x, y) (((x) + ((y) - 1)) & ~((y) - 1))
522 size_t i_align = ALIGN( i_in_size + 0x8, 0x10 ) - 0x8;
523 #undef ALIGN
524 if( i_align > i_in_size && i_align - i_in_size
525 <= p_sys->p_out_buf->i_buffer - p_sys->i_out_offset )
526 write_padding( p_filter, i_align - i_in_size );
528 write_finalize( p_filter, i_data_type, 1 /* in bytes */ );
529 return SPDIF_SUCCESS;
532 static void Flush( filter_t *p_filter )
534 filter_sys_t *p_sys = p_filter->p_sys;
536 if( p_sys->p_out_buf != NULL )
538 block_Release( p_sys->p_out_buf );
539 p_sys->p_out_buf = NULL;
541 switch( p_filter->fmt_in.audio.i_format )
543 case VLC_CODEC_TRUEHD:
544 p_sys->truehd.i_frame_count = 0;
545 break;
546 case VLC_CODEC_EAC3:
547 p_sys->eac3.i_nb_blocks = 0;
548 break;
549 default:
550 break;
554 static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
556 filter_sys_t *p_sys = p_filter->p_sys;
557 block_t *p_out_buf = NULL;
559 int i_ret;
560 switch( p_filter->fmt_in.audio.i_format )
562 case VLC_CODEC_A52:
563 i_ret = write_buffer_ac3( p_filter, p_in_buf );
564 break;
565 case VLC_CODEC_EAC3:
566 i_ret = write_buffer_eac3( p_filter, p_in_buf );
567 break;
568 case VLC_CODEC_MLP:
569 case VLC_CODEC_TRUEHD:
570 i_ret = write_buffer_truehd( p_filter, p_in_buf );
571 break;
572 case VLC_CODEC_DTS:
573 /* if the fmt_out is configured for a higher rate than 48kHz
574 * (IEC958 rate), use the DTS-HD framing to pass the DTS Core and
575 * or DTS substreams (like DTS-HD MA). */
576 if( p_filter->fmt_out.audio.i_rate > 48000 )
577 i_ret = write_buffer_dtshd( p_filter, p_in_buf );
578 else
579 i_ret = write_buffer_dts( p_filter, p_in_buf );
580 break;
581 default:
582 vlc_assert_unreachable();
585 switch( i_ret )
587 case SPDIF_SUCCESS:
588 assert( p_sys->p_out_buf->i_buffer == p_sys->i_out_offset );
589 p_out_buf = p_sys->p_out_buf;
590 p_sys->p_out_buf = NULL;
591 break;
592 case SPDIF_MORE_DATA:
593 break;
594 case SPDIF_ERROR:
595 Flush( p_filter );
596 break;
599 block_Release( p_in_buf );
600 return p_out_buf;
603 static int Open( vlc_object_t *p_this )
605 filter_t *p_filter = (filter_t *)p_this;
606 filter_sys_t *p_sys;
608 if( ( p_filter->fmt_in.audio.i_format != VLC_CODEC_DTS &&
609 p_filter->fmt_in.audio.i_format != VLC_CODEC_A52 &&
610 p_filter->fmt_in.audio.i_format != VLC_CODEC_EAC3 &&
611 p_filter->fmt_in.audio.i_format != VLC_CODEC_MLP &&
612 p_filter->fmt_in.audio.i_format != VLC_CODEC_TRUEHD ) ||
613 ( p_filter->fmt_out.audio.i_format != VLC_CODEC_SPDIFL &&
614 p_filter->fmt_out.audio.i_format != VLC_CODEC_SPDIFB ) )
615 return VLC_EGENERIC;
617 p_sys = p_filter->p_sys = calloc( 1, sizeof(filter_sys_t) );
618 if( unlikely( p_sys == NULL ) )
619 return VLC_ENOMEM;
621 p_filter->pf_audio_filter = DoWork;
622 p_filter->pf_flush = Flush;
624 return VLC_SUCCESS;
627 static void Close( vlc_object_t *p_this )
629 filter_t *p_filter = (filter_t *)p_this;
631 Flush( p_filter );
632 free( p_filter->p_sys );