1 /*****************************************************************************
2 * mlp.c: packetize MLP/TrueHD audio
3 *****************************************************************************
4 * Copyright (C) 2008 Laurent Aimar
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 /*****************************************************************************
26 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_codec.h>
34 #include <vlc_block_helper.h>
38 #include "packetizer_helper.h"
41 /*****************************************************************************
43 *****************************************************************************/
44 static int Open ( vlc_object_t
* );
45 static void Close( vlc_object_t
* );
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
)
55 /*****************************************************************************
57 *****************************************************************************/
69 unsigned i_substreams
;
80 block_bytestream_t bytestream
;
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
114 for( int i
= 0; i
< 13; i
++ )
117 i_count
+= pu_thd
[i
];
122 static int MlpParse( mlp_header_t
*p_mlp
, const uint8_t p_hdr
[MLP_HEADER_SYNC
] )
126 assert( !memcmp( p_hdr
, pu_start_code
, 3 ) );
128 /* TODO Checksum ? */
131 bs_init( &s
, &p_hdr
[3], MLP_HEADER_SYNC
- 3 );
134 p_mlp
->i_type
= bs_read( &s
, 8 );
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 );
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 );
163 const int i_channel1
= bs_read( &s
, 5 );
167 const int i_channel2
= bs_read( &s
, 13 );
169 p_mlp
->i_channels
= TrueHdChannels( i_channel2
);
171 p_mlp
->i_channels
= TrueHdChannels( i_channel1
);
178 if( i_rate_idx1
== 0x0f )
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 );
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 );
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
)
208 /* Parse major sync if present */
211 *pb_mlp
= !MlpParse( p_mlp
, &p_hdr
[4] );
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
++ )
232 i_tmp
= ( i_tmp
>> 4 ) ^ i_tmp
;
234 if( ( i_tmp
& 0x0f ) != 0x0f )
239 const int i_word
= ( ( p_hdr
[0] << 8 ) | p_hdr
[1] ) & 0xfff;
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
)
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
;
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
);
285 if( p_block
->i_flags
& BLOCK_FLAG_CORRUPTED
)
287 block_Release( p_block
);
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
);
301 block_BytestreamPush( &p_sys
->bytestream
, p_block
);
306 switch( p_sys
->i_state
)
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
;
316 else if( SyncInfoDolby( p_header
) > 0 )
318 p_sys
->i_state
= STATE_SYNC
;
321 block_SkipByte( &p_sys
->bytestream
);
323 if( p_sys
->i_state
!= STATE_SYNC
)
325 block_BytestreamFlush( &p_sys
->bytestream
);
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
;
344 /* Get a MLP header */
345 if( block_PeekBytes( &p_sys
->bytestream
, p_header
, MLP_HEADER_SIZE
) )
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
;
363 p_sys
->i_state
= STATE_NEXT_SYNC
;
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
;
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
);
391 p_sys
->i_state
= STATE_GET_DATA
;
395 /* Make sure we have enough data. */
396 if( block_WaitBytes( &p_sys
->bytestream
, p_sys
->i_frame_size
) )
401 p_sys
->i_state
= STATE_SEND_DATA
;
404 case STATE_SEND_DATA
:
405 /* When we reach this point we already know we have enough
407 p_out_buffer
= block_Alloc( p_sys
->i_frame_size
);
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
;
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 */
457 *pp_block
= block_BytestreamPop( &p_sys
->bytestream
);
459 p_sys
->i_state
= STATE_NOSYNC
;
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
)
478 p_dec
->p_sys
= p_sys
= malloc( sizeof(*p_sys
) );
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;
496 p_dec
->pf_packetize
= Packetize
;
497 p_dec
->pf_flush
= Flush
;
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
);