tospdif: do filter even if the input is not correctly packetized
[vlc.git] / modules / audio_filter / converter / tospdif.c
blob9c077189720be009a07bbe35001c77dc4525d6c2
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 struct filter_sys_t
56 block_t *p_out_buf;
57 size_t i_out_offset;
59 union
61 struct
63 unsigned int i_nb_blocks_substream0;
64 } eac3;
65 struct
67 unsigned int i_frame_count;
68 } truehd;
69 } spec;
72 #define SPDIF_HEADER_SIZE 8
74 #define IEC61937_AC3 0x01
75 #define IEC61937_EAC3 0x15
76 #define IEC61937_TRUEHD 0x16
77 #define IEC61937_DTS1 0x0B
78 #define IEC61937_DTS2 0x0C
79 #define IEC61937_DTS3 0x0D
81 #define SPDIF_MORE_DATA 1
82 #define SPDIF_SUCCESS VLC_SUCCESS
83 #define SPDIF_ERROR VLC_EGENERIC
85 static bool is_big_endian( filter_t *p_filter, block_t *p_in_buf )
87 switch( p_filter->fmt_in.audio.i_format )
89 case VLC_CODEC_A52:
90 case VLC_CODEC_EAC3:
91 case VLC_CODEC_MLP:
92 case VLC_CODEC_TRUEHD:
93 return true;
94 case VLC_CODEC_DTS:
95 return p_in_buf->p_buffer[0] == 0x1F
96 || p_in_buf->p_buffer[0] == 0x7F;
97 default:
98 vlc_assert_unreachable();
102 static inline void write_16( filter_t *p_filter, void *p_buf, uint16_t i_val )
104 if( p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB )
105 SetWBE( p_buf, i_val );
106 else
107 SetWLE( p_buf, i_val );
110 static void write_padding( filter_t *p_filter, size_t i_size )
112 filter_sys_t *p_sys = p_filter->p_sys;
113 assert( p_sys->p_out_buf != NULL );
115 assert( p_sys->p_out_buf->i_buffer - p_sys->i_out_offset >= i_size );
117 uint8_t *p_out = &p_sys->p_out_buf->p_buffer[p_sys->i_out_offset];
118 memset( p_out, 0, i_size );
119 p_sys->i_out_offset += i_size;
122 static void write_data( filter_t *p_filter, const void *p_buf, size_t i_size,
123 bool b_input_big_endian )
125 filter_sys_t *p_sys = p_filter->p_sys;
126 assert( p_sys->p_out_buf != NULL );
128 bool b_output_big_endian =
129 p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB;
130 uint8_t *p_out = &p_sys->p_out_buf->p_buffer[p_sys->i_out_offset];
131 const uint8_t *p_in = p_buf;
133 assert( p_sys->p_out_buf->i_buffer - p_sys->i_out_offset >= i_size );
135 if( b_input_big_endian != b_output_big_endian )
136 swab( p_in, p_out, i_size & ~1 );
137 else
138 memcpy( p_out, p_in, i_size & ~1 );
139 p_sys->i_out_offset += ( i_size & ~1 );
141 if( i_size & 1 )
143 assert( p_sys->p_out_buf->i_buffer - p_sys->i_out_offset >= 2 );
144 p_out += ( i_size & ~1 );
145 write_16( p_filter, p_out, p_in[i_size - 1] << 8 );
146 p_sys->i_out_offset += 2;
150 static void write_buffer( filter_t *p_filter, block_t *p_in_buf )
152 write_data( p_filter, p_in_buf->p_buffer, p_in_buf->i_buffer,
153 is_big_endian( p_filter, p_in_buf ) );
154 p_filter->p_sys->p_out_buf->i_length += p_in_buf->i_length;
157 static int write_init( filter_t *p_filter, block_t *p_in_buf,
158 size_t i_out_size, unsigned i_nb_samples )
160 filter_sys_t *p_sys = p_filter->p_sys;
162 assert( p_sys->p_out_buf == NULL );
163 assert( i_out_size > SPDIF_HEADER_SIZE && ( i_out_size & 3 ) == 0 );
165 p_sys->p_out_buf = block_Alloc( i_out_size );
166 if( !p_sys->p_out_buf )
167 return VLC_ENOMEM;
168 p_sys->p_out_buf->i_dts = p_in_buf->i_dts;
169 p_sys->p_out_buf->i_pts = p_in_buf->i_pts;
170 p_sys->p_out_buf->i_nb_samples = i_nb_samples;
172 p_sys->i_out_offset = SPDIF_HEADER_SIZE; /* Place for the S/PDIF header */
173 return VLC_SUCCESS;
176 static void write_finalize( filter_t *p_filter, uint16_t i_data_type,
177 uint8_t i_length_mul )
179 filter_sys_t *p_sys = p_filter->p_sys;
180 assert( p_sys->p_out_buf != NULL );
181 uint8_t *p_out = p_sys->p_out_buf->p_buffer;
183 assert( p_sys->i_out_offset > SPDIF_HEADER_SIZE );
184 assert( i_data_type != 0 );
185 assert( i_length_mul == 1 || i_length_mul == 8 );
187 /* S/PDIF header */
188 write_16( p_filter, &p_out[0], 0xf872 ); /* syncword 1 */
189 write_16( p_filter, &p_out[2], 0x4e1f ); /* syncword 2 */
190 write_16( p_filter, &p_out[4], i_data_type ); /* data type */
191 /* length in bits or bytes */
192 write_16( p_filter, &p_out[6], ( p_sys->i_out_offset - SPDIF_HEADER_SIZE )
193 * i_length_mul );
195 /* 0 padding */
196 if( p_sys->i_out_offset < p_sys->p_out_buf->i_buffer )
197 write_padding( p_filter,
198 p_sys->p_out_buf->i_buffer - p_sys->i_out_offset );
201 static int write_buffer_ac3( filter_t *p_filter, block_t *p_in_buf )
203 if( unlikely( p_in_buf->i_buffer < 6
204 || p_in_buf->i_buffer > A52_FRAME_NB * 4
205 || p_in_buf->i_nb_samples != A52_FRAME_NB ) )
207 /* Input is not correctly packetizer. Try to parse the buffer in order
208 * to get the mandatory informations to play AC3 over S/PDIF */
209 vlc_a52_header_t a52;
210 if( vlc_a52_header_Parse( &a52, p_in_buf->p_buffer, p_in_buf->i_buffer )
211 != VLC_SUCCESS || a52.b_eac3 )
212 return SPDIF_ERROR;
213 p_in_buf->i_buffer = a52.i_size;
214 p_in_buf->i_nb_samples = a52.i_samples;
217 if( write_init( p_filter, p_in_buf, A52_FRAME_NB * 4, A52_FRAME_NB ) )
218 return SPDIF_ERROR;
219 write_buffer( p_filter, p_in_buf );
220 write_finalize( p_filter, IEC61937_AC3 |
221 ( ( p_in_buf->p_buffer[5] & 0x7 ) << 8 ) /* bsmod */,
222 8 /* in bits */ );
224 return SPDIF_SUCCESS;
227 static int write_buffer_eac3( filter_t *p_filter, block_t *p_in_buf )
229 filter_sys_t *p_sys = p_filter->p_sys;
231 vlc_a52_header_t a52 = { };
232 if( vlc_a52_header_Parse( &a52, p_in_buf->p_buffer, p_in_buf->i_buffer )
233 != VLC_SUCCESS )
234 return SPDIF_ERROR;
236 p_in_buf->i_buffer = a52.i_size;
237 p_in_buf->i_nb_samples = a52.i_samples;
239 if( !p_sys->p_out_buf
240 && write_init( p_filter, p_in_buf, AOUT_SPDIF_SIZE * 4, AOUT_SPDIF_SIZE ) )
241 return SPDIF_ERROR;
242 if( p_in_buf->i_buffer > p_sys->p_out_buf->i_buffer - p_sys->i_out_offset )
243 return SPDIF_ERROR;
245 write_buffer( p_filter, p_in_buf );
247 if( a52.b_eac3 )
249 if( ( a52.eac3.strmtyp == EAC3_STRMTYP_INDEPENDENT
250 || a52.eac3.strmtyp == EAC3_STRMTYP_AC3_CONVERT )
251 && a52.i_blocks_per_sync_frame != 6 )
253 /* cf. Annex E 2.3.1.2 of AC3 spec */
254 if( a52.eac3.i_substreamid == 0 )
255 p_sys->spec.eac3.i_nb_blocks_substream0
256 += a52.i_blocks_per_sync_frame;
258 if( p_sys->spec.eac3.i_nb_blocks_substream0 != 6 )
259 return SPDIF_MORE_DATA;
260 else
261 p_sys->spec.eac3.i_nb_blocks_substream0 = 0;
263 write_finalize( p_filter, IEC61937_EAC3, 1 /* in bytes */ );
264 return SPDIF_SUCCESS;
266 else
267 return SPDIF_MORE_DATA;
271 /* Adapted from libavformat/spdifenc.c:
272 * It seems Dolby TrueHD frames have to be encapsulated in MAT frames before
273 * they can be encapsulated in IEC 61937.
274 * Here we encapsulate 24 TrueHD frames in a single MAT frame, padding them
275 * to achieve constant rate.
276 * The actual format of a MAT frame is unknown, but the below seems to work.
277 * However, it seems it is not actually necessary for the 24 TrueHD frames to
278 * be in an exact alignment with the MAT frame
280 static int write_buffer_truehd( filter_t *p_filter, block_t *p_in_buf )
282 #define TRUEHD_FRAME_OFFSET 2560
284 filter_sys_t *p_sys = p_filter->p_sys;
286 if( !p_sys->p_out_buf
287 && write_init( p_filter, p_in_buf, 61440, 61440 / 16 ) )
288 return SPDIF_ERROR;
290 int i_padding = 0;
291 if( p_sys->spec.truehd.i_frame_count == 0 )
293 static const char p_mat_start_code[20] = {
294 0x07, 0x9E, 0x00, 0x03, 0x84, 0x01, 0x01, 0x01, 0x80, 0x00,
295 0x56, 0xA5, 0x3B, 0xF4, 0x81, 0x83, 0x49, 0x80, 0x77, 0xE0
297 write_data( p_filter, p_mat_start_code, 20, true );
298 /* We need to include the S/PDIF header in the first MAT frame */
299 i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - 20
300 - SPDIF_HEADER_SIZE;
302 else if( p_sys->spec.truehd.i_frame_count == 11 )
304 /* The middle mat code need to be at the ((2560 * 12) - 4) offset */
305 i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - 4;
307 else if( p_sys->spec.truehd.i_frame_count == 12 )
309 static const char p_mat_middle_code[12] = {
310 0xC3, 0xC1, 0x42, 0x49, 0x3B, 0xFA,
311 0x82, 0x83, 0x49, 0x80, 0x77, 0xE0
313 write_data( p_filter, p_mat_middle_code, 12, true );
314 i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - ( 12 - 4 );
316 else if( p_sys->spec.truehd.i_frame_count == 23 )
318 static const char p_mat_end_code[16] = {
319 0xC3, 0xC2, 0xC0, 0xC4, 0x00, 0x00, 0x00, 0x00,
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x11
323 /* The end mat code need to be at the ((2560 * 24) - 24) offset */
324 i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - 24;
326 if( i_padding < 0 || p_in_buf->i_buffer + i_padding >
327 p_sys->p_out_buf->i_buffer - p_sys->i_out_offset )
328 return SPDIF_ERROR;
330 write_buffer( p_filter, p_in_buf );
331 write_padding( p_filter, i_padding );
332 write_data( p_filter, p_mat_end_code, 16, true );
333 write_finalize( p_filter, IEC61937_TRUEHD, 1 /* in bytes */ );
334 p_sys->spec.truehd.i_frame_count = 0;
335 return SPDIF_SUCCESS;
337 else
338 i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer;
340 if( i_padding < 0 || p_in_buf->i_buffer + i_padding >
341 p_sys->p_out_buf->i_buffer - p_sys->i_out_offset )
342 return SPDIF_ERROR;
344 write_buffer( p_filter, p_in_buf );
345 write_padding( p_filter, i_padding );
346 p_sys->spec.truehd.i_frame_count++;
347 return SPDIF_MORE_DATA;
350 static int write_buffer_dts( filter_t *p_filter, block_t *p_in_buf )
352 uint16_t i_data_type;
353 if( p_in_buf->i_nb_samples == 0 )
355 /* Input is not correctly packetizer. Try to parse the buffer in order
356 * to get the mandatory informations to play DTS over S/PDIF */
357 vlc_dts_header_t header;
358 if( vlc_dts_header_Parse( &header, p_in_buf->p_buffer,
359 p_in_buf->i_buffer ) != VLC_SUCCESS )
360 return SPDIF_ERROR;
361 p_in_buf->i_nb_samples = header.i_frame_length;
362 p_in_buf->i_buffer = header.i_frame_size;
364 switch( p_in_buf->i_nb_samples )
366 case 512:
367 i_data_type = IEC61937_DTS1;
368 break;
369 case 1024:
370 i_data_type = IEC61937_DTS2;
371 break;
372 case 2048:
373 i_data_type = IEC61937_DTS3;
374 break;
375 default:
376 msg_Err( p_filter, "Frame size %d not supported",
377 p_in_buf->i_nb_samples );
378 return SPDIF_ERROR;
381 if( p_in_buf->i_buffer > p_in_buf->i_nb_samples * 4
382 || write_init( p_filter, p_in_buf, p_in_buf->i_nb_samples * 4,
383 p_in_buf->i_nb_samples ) )
384 return SPDIF_ERROR;
385 write_buffer( p_filter, p_in_buf );
386 write_finalize( p_filter, i_data_type, 8 /* in bits */ );
387 return SPDIF_SUCCESS;
390 static void Flush( filter_t *p_filter )
392 filter_sys_t *p_sys = p_filter->p_sys;
394 if( p_sys->p_out_buf != NULL )
396 block_Release( p_sys->p_out_buf );
397 p_sys->p_out_buf = NULL;
399 memset( &p_sys->spec, 0, sizeof( p_sys->spec ) );
402 static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
404 filter_sys_t *p_sys = p_filter->p_sys;
405 block_t *p_out_buf = NULL;
407 int i_ret;
408 switch( p_filter->fmt_in.audio.i_format )
410 case VLC_CODEC_A52:
411 i_ret = write_buffer_ac3( p_filter, p_in_buf );
412 break;
413 case VLC_CODEC_EAC3:
414 i_ret = write_buffer_eac3( p_filter, p_in_buf );
415 break;
416 case VLC_CODEC_MLP:
417 case VLC_CODEC_TRUEHD:
418 i_ret = write_buffer_truehd( p_filter, p_in_buf );
419 break;
420 case VLC_CODEC_DTS:
421 i_ret = write_buffer_dts( p_filter, p_in_buf );
422 break;
423 default:
424 vlc_assert_unreachable();
427 switch( i_ret )
429 case SPDIF_SUCCESS:
430 assert( p_sys->p_out_buf->i_buffer == p_sys->i_out_offset );
431 p_out_buf = p_sys->p_out_buf;
432 p_sys->p_out_buf = NULL;
433 break;
434 case SPDIF_MORE_DATA:
435 break;
436 case SPDIF_ERROR:
437 Flush( p_filter );
438 break;
441 block_Release( p_in_buf );
442 return p_out_buf;
445 static int Open( vlc_object_t *p_this )
447 filter_t *p_filter = (filter_t *)p_this;
448 filter_sys_t *p_sys;
450 if( ( p_filter->fmt_in.audio.i_format != VLC_CODEC_DTS &&
451 p_filter->fmt_in.audio.i_format != VLC_CODEC_A52 &&
452 p_filter->fmt_in.audio.i_format != VLC_CODEC_EAC3 &&
453 p_filter->fmt_in.audio.i_format != VLC_CODEC_MLP &&
454 p_filter->fmt_in.audio.i_format != VLC_CODEC_TRUEHD ) ||
455 ( p_filter->fmt_out.audio.i_format != VLC_CODEC_SPDIFL &&
456 p_filter->fmt_out.audio.i_format != VLC_CODEC_SPDIFB ) )
457 return VLC_EGENERIC;
459 p_sys = p_filter->p_sys = malloc( sizeof(filter_sys_t) );
460 if( unlikely( p_sys == NULL ) )
461 return VLC_ENOMEM;
462 p_sys->p_out_buf = NULL;
464 memset( &p_sys->spec, 0, sizeof( p_sys->spec ) );
466 p_filter->pf_audio_filter = DoWork;
467 p_filter->pf_flush = Flush;
469 return VLC_SUCCESS;
472 static void Close( vlc_object_t *p_this )
474 filter_t *p_filter = (filter_t *)p_this;
476 Flush( p_filter );
477 free( p_filter->p_sys );