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
, 0 );
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( !date_Get( &p_sys
->end_date
) && p_block
->i_pts
<= VLC_TS_INVALID
)
294 /* We've just started the stream, wait for the first PTS. */
295 msg_Dbg( p_dec
, "waiting for PTS" );
296 block_Release( p_block
);
300 block_BytestreamPush( &p_sys
->bytestream
, p_block
);
305 switch( p_sys
->i_state
)
308 while( !block_PeekBytes( &p_sys
->bytestream
, p_header
, MLP_HEADER_SIZE
) )
310 if( SyncInfo( p_header
, &p_sys
->b_mlp
, &p_sys
->mlp
) > 0 )
312 p_sys
->i_state
= STATE_SYNC
;
315 else if( SyncInfoDolby( p_header
) > 0 )
317 p_sys
->i_state
= STATE_SYNC
;
320 block_SkipByte( &p_sys
->bytestream
);
322 if( p_sys
->i_state
!= STATE_SYNC
)
324 block_BytestreamFlush( &p_sys
->bytestream
);
331 /* New frame, set the Presentation Time Stamp */
332 p_sys
->i_pts
= p_sys
->bytestream
.p_block
->i_pts
;
333 if( p_sys
->i_pts
> VLC_TS_INVALID
&&
334 p_sys
->i_pts
!= date_Get( &p_sys
->end_date
) )
336 date_Set( &p_sys
->end_date
, p_sys
->i_pts
);
338 p_sys
->i_state
= STATE_HEADER
;
341 /* Get a MLP header */
342 if( block_PeekBytes( &p_sys
->bytestream
, p_header
, MLP_HEADER_SIZE
) )
348 /* Check if frame is valid and get frame info */
349 p_sys
->i_frame_size
= SyncInfoDolby( p_header
);
350 if( p_sys
->i_frame_size
<= 0 )
351 p_sys
->i_frame_size
= SyncInfo( p_header
, &p_sys
->b_mlp
, &p_sys
->mlp
);
352 if( p_sys
->i_frame_size
<= 0 )
354 msg_Dbg( p_dec
, "emulated sync word" );
355 block_SkipByte( &p_sys
->bytestream
);
356 p_sys
->b_mlp
= false;
357 p_sys
->i_state
= STATE_NOSYNC
;
360 p_sys
->i_state
= STATE_NEXT_SYNC
;
362 case STATE_NEXT_SYNC
:
363 /* Check if next expected frame contains the sync word */
364 if( block_PeekOffsetBytes( &p_sys
->bytestream
,
365 p_sys
->i_frame_size
, p_header
, MLP_HEADER_SIZE
) )
367 if( p_block
== NULL
) /* drain */
369 p_sys
->i_state
= STATE_GET_DATA
;
376 bool b_mlp
= p_sys
->b_mlp
;
377 mlp_header_t mlp
= p_sys
->mlp
;
378 if( SyncInfo( p_header
, &b_mlp
, &mlp
) <= 0 && SyncInfoDolby( p_header
) <= 0 )
380 msg_Dbg( p_dec
, "emulated sync word "
381 "(no sync on following frame)" );
382 p_sys
->b_mlp
= false;
383 p_sys
->i_state
= STATE_NOSYNC
;
384 block_SkipByte( &p_sys
->bytestream
);
387 p_sys
->i_state
= STATE_GET_DATA
;
391 /* Make sure we have enough data. */
392 if( block_WaitBytes( &p_sys
->bytestream
, p_sys
->i_frame_size
) )
397 p_sys
->i_state
= STATE_SEND_DATA
;
399 case STATE_SEND_DATA
:
400 /* When we reach this point we already know we have enough
402 p_out_buffer
= block_Alloc( p_sys
->i_frame_size
);
406 /* Copy the whole frame into the buffer */
407 block_GetBytes( &p_sys
->bytestream
,
408 p_out_buffer
->p_buffer
, p_out_buffer
->i_buffer
);
410 /* Just ignore (E)AC3 frames */
411 if( SyncInfoDolby( p_out_buffer
->p_buffer
) > 0 )
413 block_Release( p_out_buffer
);
414 p_sys
->i_state
= STATE_NOSYNC
;
419 if( p_dec
->fmt_out
.audio
.i_rate
!= p_sys
->mlp
.i_rate
)
421 msg_Info( p_dec
, "MLP channels: %d samplerate: %d",
422 p_sys
->mlp
.i_channels
, p_sys
->mlp
.i_rate
);
424 if( p_sys
->mlp
.i_rate
> 0 )
426 const mtime_t i_end_date
= date_Get( &p_sys
->end_date
);
427 date_Init( &p_sys
->end_date
, p_sys
->mlp
.i_rate
, 1 );
428 date_Set( &p_sys
->end_date
, i_end_date
);
432 p_dec
->fmt_out
.audio
.i_rate
= p_sys
->mlp
.i_rate
;
433 p_dec
->fmt_out
.audio
.i_channels
= p_sys
->mlp
.i_channels
;
434 p_dec
->fmt_out
.audio
.i_original_channels
= p_sys
->mlp
.i_channels_conf
;
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_Set( &p_sys
->end_date
, 0 );
486 block_BytestreamInit( &p_sys
->bytestream
);
487 p_sys
->b_mlp
= false;
488 p_sys
->b_discontinuity
= false;
490 /* Set output properties (Passthrough only) */
491 p_dec
->fmt_out
.i_cat
= AUDIO_ES
;
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
);