1 /*****************************************************************************
2 * mlp.c: packetize MLP/TrueHD audio
3 *****************************************************************************
4 * Copyright (C) 2008 Laurent Aimar
6 * Authors: Laurent Aimar < fenrir _AT videolan _DOT_ org >
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_codec.h>
33 #include <vlc_block_helper.h>
37 #include "packetizer_helper.h"
40 /*****************************************************************************
42 *****************************************************************************/
43 static int Open ( vlc_object_t
* );
44 static void Close( vlc_object_t
* );
47 set_category( CAT_SOUT
)
48 set_subcategory( SUBCAT_SOUT_PACKETIZER
)
49 set_description( N_("MLP/TrueHD parser") )
50 set_capability( "packetizer", 50 )
51 set_callbacks( Open
, Close
)
54 /*****************************************************************************
56 *****************************************************************************/
68 unsigned i_substreams
;
79 block_bytestream_t bytestream
;
94 #define MLP_MAX_SUBSTREAMS (16)
95 #define MLP_HEADER_SYNC (28)
96 #define MLP_HEADER_SIZE (4 + MLP_HEADER_SYNC + 4 * MLP_MAX_SUBSTREAMS)
98 static const uint8_t pu_start_code
[3] = { 0xf8, 0x72, 0x6f };
101 * It parse MLP sync info.
103 * TODO handle CRC (at offset 26)
105 static int TrueHdChannels( int i_map
)
107 static const uint8_t pu_thd
[13] =
109 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1
113 for( int i
= 0; i
< 13; i
++ )
116 i_count
+= pu_thd
[i
];
121 static int MlpParse( mlp_header_t
*p_mlp
, const uint8_t p_hdr
[MLP_HEADER_SYNC
] )
125 assert( !memcmp( p_hdr
, pu_start_code
, 3 ) );
127 /* TODO Checksum ? */
130 bs_init( &s
, &p_hdr
[3], MLP_HEADER_SYNC
- 3 );
133 p_mlp
->i_type
= bs_read( &s
, 8 );
136 if( p_mlp
->i_type
== 0xbb ) /* MLP */
138 static const unsigned pu_channels
[32] = {
139 1, 2, 3, 4, 3, 4, 5, 3, 4, 5, 4, 5, 6, 4, 5, 4,
140 5, 6, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
143 bs_skip( &s
, 4 + 4 );
145 i_rate_idx1
= bs_read( &s
, 4 );
147 // Just skip the 4 following, since we don't use it
148 // const int i_rate_idx2 = bs_read( &s, 4 );
153 const int i_channel_idx
= bs_read( &s
, 5 );
154 p_mlp
->i_channels
= pu_channels
[i_channel_idx
];
156 else if( p_mlp
->i_type
== 0xba ) /* True HD */
158 i_rate_idx1
= bs_read( &s
, 4 );
162 const int i_channel1
= bs_read( &s
, 5 );
166 const int i_channel2
= bs_read( &s
, 13 );
168 p_mlp
->i_channels
= TrueHdChannels( i_channel2
);
170 p_mlp
->i_channels
= TrueHdChannels( i_channel1
);
177 if( i_rate_idx1
== 0x0f )
180 p_mlp
->i_rate
= ( ( i_rate_idx1
& 0x8 ) ? 44100 : 48000 ) << (i_rate_idx1
& 0x7);
181 p_mlp
->i_channels_conf
= 0; /* TODO ? */
183 p_mlp
->i_samples
= 40 << ( i_rate_idx1
& 0x07 );
187 p_mlp
->b_vbr
= bs_read( &s
, 1 );
188 p_mlp
->i_bitrate
= ( bs_read( &s
, 15 ) * p_mlp
->i_rate
+ 8) / 16;
190 p_mlp
->i_substreams
= bs_read( &s
, 4 );
191 bs_skip( &s
, 4 + 11 * 8 );
193 //fprintf( stderr, "i_samples = %d channels:%d rate:%d bitsrate=%d substreams=%d\n",
194 // p_mlp->i_samples, p_mlp->i_channels, p_mlp->i_rate, p_mlp->i_bitrate, p_mlp->i_substreams );
198 static int SyncInfo( const uint8_t *p_hdr
, bool *pb_mlp
, mlp_header_t
*p_mlp
)
200 /* Check major sync presence */
201 const bool b_has_sync
= !memcmp( &p_hdr
[4], pu_start_code
, 3 );
203 /* Wait for a major sync */
204 if( !b_has_sync
&& !*pb_mlp
)
207 /* Parse major sync if present */
210 *pb_mlp
= !MlpParse( p_mlp
, &p_hdr
[4] );
218 int i_tmp
= 0 ^ p_hdr
[0] ^ p_hdr
[1] ^ p_hdr
[2] ^ p_hdr
[3];
219 const uint8_t *p
= &p_hdr
[4];
221 for( unsigned i
= 0; i
< p_mlp
->i_substreams
; i
++ )
231 i_tmp
= ( i_tmp
>> 4 ) ^ i_tmp
;
233 if( ( i_tmp
& 0x0f ) != 0x0f )
238 const int i_word
= ( ( p_hdr
[0] << 8 ) | p_hdr
[1] ) & 0xfff;
243 * It returns the size of an AC3/EAC3 frame (or 0 if invalid)
245 static int SyncInfoDolby( const uint8_t *p_buf
)
247 vlc_a52_header_t a52
;
248 if( vlc_a52_header_Parse( &a52
, p_buf
, MLP_HEADER_SIZE
) == VLC_SUCCESS
)
254 static void Flush( decoder_t
*p_dec
)
256 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
258 p_sys
->b_mlp
= false;
259 p_sys
->i_state
= STATE_NOSYNC
;
260 p_sys
->b_discontinuity
= true;
261 block_BytestreamEmpty( &p_sys
->bytestream
);
262 date_Set( &p_sys
->end_date
, VLC_TICK_INVALID
);
265 static block_t
*Packetize( decoder_t
*p_dec
, block_t
**pp_block
)
267 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
268 uint8_t p_header
[MLP_HEADER_SIZE
];
269 block_t
*p_out_buffer
;
271 block_t
*p_block
= pp_block
? *pp_block
: NULL
;
275 if( p_block
->i_flags
& (BLOCK_FLAG_DISCONTINUITY
|BLOCK_FLAG_CORRUPTED
) )
277 /* First always drain complete blocks before discontinuity */
278 block_t
*p_drain
= Packetize( p_dec
, NULL
);
284 if( p_block
->i_flags
& BLOCK_FLAG_CORRUPTED
)
286 block_Release( p_block
);
291 if( p_block
->i_pts
== VLC_TICK_INVALID
&&
292 date_Get( &p_sys
->end_date
) == VLC_TICK_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
);
332 /* New frame, set the Presentation Time Stamp */
333 p_sys
->i_pts
= p_sys
->bytestream
.p_block
->i_pts
;
334 if( p_sys
->i_pts
!= VLC_TICK_INVALID
&&
335 p_sys
->i_pts
!= date_Get( &p_sys
->end_date
) )
337 date_Set( &p_sys
->end_date
, p_sys
->i_pts
);
339 p_sys
->i_state
= STATE_HEADER
;
343 /* Get a MLP header */
344 if( block_PeekBytes( &p_sys
->bytestream
, p_header
, MLP_HEADER_SIZE
) )
350 /* Check if frame is valid and get frame info */
351 p_sys
->i_frame_size
= SyncInfoDolby( p_header
);
352 if( p_sys
->i_frame_size
<= 0 )
353 p_sys
->i_frame_size
= SyncInfo( p_header
, &p_sys
->b_mlp
, &p_sys
->mlp
);
354 if( p_sys
->i_frame_size
<= 0 )
356 msg_Dbg( p_dec
, "emulated sync word" );
357 block_SkipByte( &p_sys
->bytestream
);
358 p_sys
->b_mlp
= false;
359 p_sys
->i_state
= STATE_NOSYNC
;
362 p_sys
->i_state
= STATE_NEXT_SYNC
;
365 case STATE_NEXT_SYNC
:
366 /* Check if next expected frame contains the sync word */
367 if( block_PeekOffsetBytes( &p_sys
->bytestream
,
368 p_sys
->i_frame_size
, p_header
, MLP_HEADER_SIZE
) )
370 if( p_block
== NULL
) /* drain */
372 p_sys
->i_state
= STATE_GET_DATA
;
379 bool b_mlp
= p_sys
->b_mlp
;
380 mlp_header_t mlp
= p_sys
->mlp
;
381 if( SyncInfo( p_header
, &b_mlp
, &mlp
) <= 0 && SyncInfoDolby( p_header
) <= 0 )
383 msg_Dbg( p_dec
, "emulated sync word "
384 "(no sync on following frame)" );
385 p_sys
->b_mlp
= false;
386 p_sys
->i_state
= STATE_NOSYNC
;
387 block_SkipByte( &p_sys
->bytestream
);
390 p_sys
->i_state
= STATE_GET_DATA
;
394 /* Make sure we have enough data. */
395 if( block_WaitBytes( &p_sys
->bytestream
, p_sys
->i_frame_size
) )
400 p_sys
->i_state
= STATE_SEND_DATA
;
403 case STATE_SEND_DATA
:
404 /* When we reach this point we already know we have enough
406 p_out_buffer
= block_Alloc( p_sys
->i_frame_size
);
410 /* Copy the whole frame into the buffer */
411 block_GetBytes( &p_sys
->bytestream
,
412 p_out_buffer
->p_buffer
, p_out_buffer
->i_buffer
);
414 /* Just ignore (E)AC3 frames */
415 if( SyncInfoDolby( p_out_buffer
->p_buffer
) > 0 )
417 block_Release( p_out_buffer
);
418 p_sys
->i_state
= STATE_NOSYNC
;
423 if( p_dec
->fmt_out
.audio
.i_rate
!= p_sys
->mlp
.i_rate
)
425 msg_Info( p_dec
, "MLP channels: %d samplerate: %d",
426 p_sys
->mlp
.i_channels
, p_sys
->mlp
.i_rate
);
428 if( p_sys
->mlp
.i_rate
> 0 )
429 date_Change( &p_sys
->end_date
, p_sys
->mlp
.i_rate
, 1 );
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_physical_channels
= p_sys
->mlp
.i_channels_conf
;
435 p_dec
->fmt_out
.audio
.i_bytes_per_frame
= p_sys
->i_frame_size
;
436 p_dec
->fmt_out
.audio
.i_frame_length
= p_sys
->mlp
.i_samples
;
438 p_out_buffer
->i_pts
= p_out_buffer
->i_dts
= date_Get( &p_sys
->end_date
);
439 p_out_buffer
->i_nb_samples
= p_sys
->mlp
.i_samples
;
441 p_out_buffer
->i_length
=
442 date_Increment( &p_sys
->end_date
, p_sys
->mlp
.i_samples
) - p_out_buffer
->i_pts
;
444 /* Make sure we don't reuse the same pts twice */
445 if( p_sys
->i_pts
== p_sys
->bytestream
.p_block
->i_pts
)
446 p_sys
->i_pts
= p_sys
->bytestream
.p_block
->i_pts
= VLC_TICK_INVALID
;
448 if( p_sys
->b_discontinuity
)
450 p_out_buffer
->i_flags
|= BLOCK_FLAG_DISCONTINUITY
;
451 p_sys
->b_discontinuity
= false;
454 /* So p_block doesn't get re-added several times */
456 *pp_block
= block_BytestreamPop( &p_sys
->bytestream
);
458 p_sys
->i_state
= STATE_NOSYNC
;
467 static int Open( vlc_object_t
*p_this
)
469 decoder_t
*p_dec
= (decoder_t
*)p_this
;
470 decoder_sys_t
*p_sys
;
472 if( p_dec
->fmt_in
.i_codec
!= VLC_CODEC_MLP
&&
473 p_dec
->fmt_in
.i_codec
!= VLC_CODEC_TRUEHD
)
477 p_dec
->p_sys
= p_sys
= malloc( sizeof(*p_sys
) );
482 p_sys
->i_state
= STATE_NOSYNC
;
483 date_Init( &p_sys
->end_date
, 1, 1 );
485 block_BytestreamInit( &p_sys
->bytestream
);
486 p_sys
->b_mlp
= false;
487 p_sys
->b_discontinuity
= false;
489 /* Set output properties (Passthrough only) */
490 p_dec
->fmt_out
.i_codec
= p_dec
->fmt_in
.i_codec
;
491 p_dec
->fmt_out
.audio
.i_rate
= 0;
494 p_dec
->pf_packetize
= Packetize
;
495 p_dec
->pf_flush
= Flush
;
496 p_dec
->pf_get_cc
= NULL
;
500 static void Close( vlc_object_t
*p_this
)
502 decoder_t
*p_dec
= (decoder_t
*)p_this
;
503 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
505 block_BytestreamRelease( &p_sys
->bytestream
);