mlp: missing initializer (fixes #20494)
[vlc.git] / modules / packetizer / mlp.c
blob365d483ed9c181e255e0276f7f1afb03e38c5a41
1 /*****************************************************************************
2 * mlp.c: packetize MLP/TrueHD audio
3 *****************************************************************************
4 * Copyright (C) 2008 Laurent Aimar
5 * $Id$
7 * Authors: Laurent Aimar < fenrir _AT videolan _DOT_ org >
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_codec.h>
34 #include <vlc_block_helper.h>
35 #include <vlc_bits.h>
36 #include <assert.h>
38 #include "packetizer_helper.h"
39 #include "a52.h"
41 /*****************************************************************************
42 * Module descriptor
43 *****************************************************************************/
44 static int Open ( vlc_object_t * );
45 static void Close( vlc_object_t * );
47 vlc_module_begin ()
48 set_category( CAT_SOUT )
49 set_subcategory( SUBCAT_SOUT_PACKETIZER )
50 set_description( N_("MLP/TrueHD parser") )
51 set_capability( "packetizer", 50 )
52 set_callbacks( Open, Close )
53 vlc_module_end ()
55 /*****************************************************************************
57 *****************************************************************************/
58 typedef struct
60 int i_type;
61 unsigned i_rate;
62 unsigned i_channels;
63 int i_channels_conf;
64 unsigned i_samples;
66 bool b_vbr;
67 unsigned i_bitrate;
69 unsigned i_substreams;
71 } mlp_header_t;
73 typedef struct
76 * Input properties
78 int i_state;
80 block_bytestream_t bytestream;
83 * Common properties
85 date_t end_date;
86 bool b_discontinuity;
88 mtime_t i_pts;
89 int i_frame_size;
91 bool b_mlp;
92 mlp_header_t mlp;
93 } decoder_sys_t;
95 #define MLP_MAX_SUBSTREAMS (16)
96 #define MLP_HEADER_SYNC (28)
97 #define MLP_HEADER_SIZE (4 + MLP_HEADER_SYNC + 4 * MLP_MAX_SUBSTREAMS)
99 static const uint8_t pu_start_code[3] = { 0xf8, 0x72, 0x6f };
102 * It parse MLP sync info.
104 * TODO handle CRC (at offset 26)
106 static int TrueHdChannels( int i_map )
108 static const uint8_t pu_thd[13] =
110 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1
112 int i_count = 0;
114 for( int i = 0; i < 13; i++ )
116 if( i_map & (1<<i) )
117 i_count += pu_thd[i];
119 return i_count;
122 static int MlpParse( mlp_header_t *p_mlp, const uint8_t p_hdr[MLP_HEADER_SYNC] )
124 bs_t s;
126 assert( !memcmp( p_hdr, pu_start_code, 3 ) );
128 /* TODO Checksum ? */
130 /* */
131 bs_init( &s, &p_hdr[3], MLP_HEADER_SYNC - 3 );
133 /* Stream type */
134 p_mlp->i_type = bs_read( &s, 8 );
135 int i_rate_idx1;
137 if( p_mlp->i_type == 0xbb ) /* MLP */
139 static const unsigned pu_channels[32] = {
140 1, 2, 3, 4, 3, 4, 5, 3, 4, 5, 4, 5, 6, 4, 5, 4,
141 5, 6, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
144 bs_skip( &s, 4 + 4 );
146 i_rate_idx1 = bs_read( &s, 4 );
148 // Just skip the 4 following, since we don't use it
149 // const int i_rate_idx2 = bs_read( &s, 4 );
150 bs_skip( &s, 4 );
152 bs_skip( &s, 11 );
154 const int i_channel_idx = bs_read( &s, 5 );
155 p_mlp->i_channels = pu_channels[i_channel_idx];
157 else if( p_mlp->i_type == 0xba ) /* True HD */
159 i_rate_idx1 = bs_read( &s, 4 );
161 bs_skip( &s, 8 );
163 const int i_channel1 = bs_read( &s, 5 );
165 bs_skip( &s, 2 );
167 const int i_channel2 = bs_read( &s, 13 );
168 if( i_channel2 )
169 p_mlp->i_channels = TrueHdChannels( i_channel2 );
170 else
171 p_mlp->i_channels = TrueHdChannels( i_channel1 );
173 else
175 return VLC_EGENERIC;
178 if( i_rate_idx1 == 0x0f )
179 p_mlp->i_rate = 0;
180 else
181 p_mlp->i_rate = ( ( i_rate_idx1 & 0x8 ) ? 44100 : 48000 ) << (i_rate_idx1 & 0x7);
182 p_mlp->i_channels_conf = 0; /* TODO ? */
184 p_mlp->i_samples = 40 << ( i_rate_idx1 & 0x07 );
186 bs_skip( &s, 48 );
188 p_mlp->b_vbr = bs_read( &s, 1 );
189 p_mlp->i_bitrate = ( bs_read( &s, 15 ) * p_mlp->i_rate + 8) / 16;
191 p_mlp->i_substreams = bs_read( &s, 4 );
192 bs_skip( &s, 4 + 11 * 8 );
194 //fprintf( stderr, "i_samples = %d channels:%d rate:%d bitsrate=%d substreams=%d\n",
195 // p_mlp->i_samples, p_mlp->i_channels, p_mlp->i_rate, p_mlp->i_bitrate, p_mlp->i_substreams );
196 return VLC_SUCCESS;
199 static int SyncInfo( const uint8_t *p_hdr, bool *pb_mlp, mlp_header_t *p_mlp )
201 /* Check major sync presence */
202 const bool b_has_sync = !memcmp( &p_hdr[4], pu_start_code, 3 );
204 /* Wait for a major sync */
205 if( !b_has_sync && !*pb_mlp )
206 return 0;
208 /* Parse major sync if present */
209 if( b_has_sync )
211 *pb_mlp = !MlpParse( p_mlp, &p_hdr[4] );
213 if( !*pb_mlp )
214 return 0;
217 if( !b_has_sync )
219 int i_tmp = 0 ^ p_hdr[0] ^ p_hdr[1] ^ p_hdr[2] ^ p_hdr[3];
220 const uint8_t *p = &p_hdr[4];
222 for( unsigned i = 0; i < p_mlp->i_substreams; i++ )
224 i_tmp ^= *p++;
225 i_tmp ^= *p++;
226 if( p[-2] & 0x80 )
228 i_tmp ^= *p++;
229 i_tmp ^= *p++;
232 i_tmp = ( i_tmp >> 4 ) ^ i_tmp;
234 if( ( i_tmp & 0x0f ) != 0x0f )
235 return 0;
238 /* */
239 const int i_word = ( ( p_hdr[0] << 8 ) | p_hdr[1] ) & 0xfff;
240 return i_word * 2;
244 * It returns the size of an AC3/EAC3 frame (or 0 if invalid)
246 static int SyncInfoDolby( const uint8_t *p_buf )
248 vlc_a52_header_t a52;
249 if( vlc_a52_header_Parse( &a52, p_buf, MLP_HEADER_SIZE ) == VLC_SUCCESS )
250 return a52.i_size;
251 else
252 return 0;
255 static void Flush( decoder_t *p_dec )
257 decoder_sys_t *p_sys = p_dec->p_sys;
259 p_sys->b_mlp = false;
260 p_sys->i_state = STATE_NOSYNC;
261 p_sys->b_discontinuity = true;
262 block_BytestreamEmpty( &p_sys->bytestream );
263 date_Set( &p_sys->end_date, VLC_TS_INVALID );
266 static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
268 decoder_sys_t *p_sys = p_dec->p_sys;
269 uint8_t p_header[MLP_HEADER_SIZE];
270 block_t *p_out_buffer;
272 block_t *p_block = pp_block ? *pp_block : NULL;
274 if ( p_block )
276 if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
278 /* First always drain complete blocks before discontinuity */
279 block_t *p_drain = Packetize( p_dec, NULL );
280 if( p_drain )
281 return p_drain;
283 Flush( p_dec );
285 if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
287 block_Release( p_block );
288 return NULL;
292 if( p_block->i_pts == VLC_TS_INVALID &&
293 date_Get( &p_sys->end_date ) == VLC_TS_INVALID )
295 /* We've just started the stream, wait for the first PTS. */
296 msg_Dbg( p_dec, "waiting for PTS" );
297 block_Release( p_block );
298 return NULL;
301 block_BytestreamPush( &p_sys->bytestream, p_block );
304 for( ;; )
306 switch( p_sys->i_state )
308 case STATE_NOSYNC:
309 while( !block_PeekBytes( &p_sys->bytestream, p_header, MLP_HEADER_SIZE ) )
311 if( SyncInfo( p_header, &p_sys->b_mlp, &p_sys->mlp ) > 0 )
313 p_sys->i_state = STATE_SYNC;
314 break;
316 else if( SyncInfoDolby( p_header ) > 0 )
318 p_sys->i_state = STATE_SYNC;
319 break;
321 block_SkipByte( &p_sys->bytestream );
323 if( p_sys->i_state != STATE_SYNC )
325 block_BytestreamFlush( &p_sys->bytestream );
327 /* Need more data */
328 return NULL;
330 /* fallthrough */
332 case STATE_SYNC:
333 /* New frame, set the Presentation Time Stamp */
334 p_sys->i_pts = p_sys->bytestream.p_block->i_pts;
335 if( p_sys->i_pts != VLC_TS_INVALID &&
336 p_sys->i_pts != date_Get( &p_sys->end_date ) )
338 date_Set( &p_sys->end_date, p_sys->i_pts );
340 p_sys->i_state = STATE_HEADER;
341 /* fallthrough */
343 case STATE_HEADER:
344 /* Get a MLP header */
345 if( block_PeekBytes( &p_sys->bytestream, p_header, MLP_HEADER_SIZE ) )
347 /* Need more data */
348 return NULL;
351 /* Check if frame is valid and get frame info */
352 p_sys->i_frame_size = SyncInfoDolby( p_header );
353 if( p_sys->i_frame_size <= 0 )
354 p_sys->i_frame_size = SyncInfo( p_header, &p_sys->b_mlp, &p_sys->mlp );
355 if( p_sys->i_frame_size <= 0 )
357 msg_Dbg( p_dec, "emulated sync word" );
358 block_SkipByte( &p_sys->bytestream );
359 p_sys->b_mlp = false;
360 p_sys->i_state = STATE_NOSYNC;
361 break;
363 p_sys->i_state = STATE_NEXT_SYNC;
364 /* fallthrough */
366 case STATE_NEXT_SYNC:
367 /* Check if next expected frame contains the sync word */
368 if( block_PeekOffsetBytes( &p_sys->bytestream,
369 p_sys->i_frame_size, p_header, MLP_HEADER_SIZE ) )
371 if( p_block == NULL ) /* drain */
373 p_sys->i_state = STATE_GET_DATA;
374 break;
376 /* Need more data */
377 return NULL;
380 bool b_mlp = p_sys->b_mlp;
381 mlp_header_t mlp = p_sys->mlp;
382 if( SyncInfo( p_header, &b_mlp, &mlp ) <= 0 && SyncInfoDolby( p_header ) <= 0 )
384 msg_Dbg( p_dec, "emulated sync word "
385 "(no sync on following frame)" );
386 p_sys->b_mlp = false;
387 p_sys->i_state = STATE_NOSYNC;
388 block_SkipByte( &p_sys->bytestream );
389 break;
391 p_sys->i_state = STATE_GET_DATA;
392 break;
394 case STATE_GET_DATA:
395 /* Make sure we have enough data. */
396 if( block_WaitBytes( &p_sys->bytestream, p_sys->i_frame_size ) )
398 /* Need more data */
399 return NULL;
401 p_sys->i_state = STATE_SEND_DATA;
402 /* fallthrough */
404 case STATE_SEND_DATA:
405 /* When we reach this point we already know we have enough
406 * data available. */
407 p_out_buffer = block_Alloc( p_sys->i_frame_size );
408 if( !p_out_buffer )
409 return NULL;
411 /* Copy the whole frame into the buffer */
412 block_GetBytes( &p_sys->bytestream,
413 p_out_buffer->p_buffer, p_out_buffer->i_buffer );
415 /* Just ignore (E)AC3 frames */
416 if( SyncInfoDolby( p_out_buffer->p_buffer ) > 0 )
418 block_Release( p_out_buffer );
419 p_sys->i_state = STATE_NOSYNC;
420 break;
423 /* Setup output */
424 if( p_dec->fmt_out.audio.i_rate != p_sys->mlp.i_rate )
426 msg_Info( p_dec, "MLP channels: %d samplerate: %d",
427 p_sys->mlp.i_channels, p_sys->mlp.i_rate );
429 if( p_sys->mlp.i_rate > 0 )
430 date_Change( &p_sys->end_date, p_sys->mlp.i_rate, 1 );
433 p_dec->fmt_out.audio.i_rate = p_sys->mlp.i_rate;
434 p_dec->fmt_out.audio.i_channels = p_sys->mlp.i_channels;
435 p_dec->fmt_out.audio.i_physical_channels = p_sys->mlp.i_channels_conf;
436 p_dec->fmt_out.audio.i_bytes_per_frame = p_sys->i_frame_size;
437 p_dec->fmt_out.audio.i_frame_length = p_sys->mlp.i_samples;
439 p_out_buffer->i_pts = p_out_buffer->i_dts = date_Get( &p_sys->end_date );
440 p_out_buffer->i_nb_samples = p_sys->mlp.i_samples;
442 p_out_buffer->i_length =
443 date_Increment( &p_sys->end_date, p_sys->mlp.i_samples ) - p_out_buffer->i_pts;
445 /* Make sure we don't reuse the same pts twice */
446 if( p_sys->i_pts == p_sys->bytestream.p_block->i_pts )
447 p_sys->i_pts = p_sys->bytestream.p_block->i_pts = VLC_TS_INVALID;
449 if( p_sys->b_discontinuity )
451 p_out_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
452 p_sys->b_discontinuity = false;
455 /* So p_block doesn't get re-added several times */
456 if( pp_block )
457 *pp_block = block_BytestreamPop( &p_sys->bytestream );
459 p_sys->i_state = STATE_NOSYNC;
461 return p_out_buffer;
465 return NULL;
468 static int Open( vlc_object_t *p_this )
470 decoder_t *p_dec = (decoder_t*)p_this;
471 decoder_sys_t *p_sys;
473 if( p_dec->fmt_in.i_codec != VLC_CODEC_MLP &&
474 p_dec->fmt_in.i_codec != VLC_CODEC_TRUEHD )
475 return VLC_EGENERIC;
477 /* */
478 p_dec->p_sys = p_sys = malloc( sizeof(*p_sys) );
479 if( !p_sys )
480 return VLC_ENOMEM;
482 /* */
483 p_sys->i_state = STATE_NOSYNC;
484 date_Init( &p_sys->end_date, 1, 1 );
485 date_Set( &p_sys->end_date, VLC_TS_INVALID );
487 block_BytestreamInit( &p_sys->bytestream );
488 p_sys->b_mlp = false;
489 p_sys->b_discontinuity = false;
491 /* Set output properties (Passthrough only) */
492 p_dec->fmt_out.i_codec = p_dec->fmt_in.i_codec;
493 p_dec->fmt_out.audio.i_rate = 0;
495 /* Set callback */
496 p_dec->pf_packetize = Packetize;
497 p_dec->pf_flush = Flush;
498 return VLC_SUCCESS;
501 static void Close( vlc_object_t *p_this )
503 decoder_t *p_dec = (decoder_t*)p_this;
504 decoder_sys_t *p_sys = p_dec->p_sys;
506 block_BytestreamRelease( &p_sys->bytestream );
508 free( p_sys );