sout: remove fmt storage from sout packetizers
[vlc.git] / modules / packetizer / mlp.c
blob6bc1404ff2958800ee01ab32ffbc57ef2fa25791
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 struct decoder_sys_t
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;
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, 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;
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( !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 );
297 return NULL;
300 block_BytestreamPush( &p_sys->bytestream, p_block );
303 for( ;; )
305 switch( p_sys->i_state )
307 case STATE_NOSYNC:
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;
313 break;
315 else if( SyncInfoDolby( p_header ) > 0 )
317 p_sys->i_state = STATE_SYNC;
318 break;
320 block_SkipByte( &p_sys->bytestream );
322 if( p_sys->i_state != STATE_SYNC )
324 block_BytestreamFlush( &p_sys->bytestream );
326 /* Need more data */
327 return NULL;
330 case STATE_SYNC:
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;
340 case STATE_HEADER:
341 /* Get a MLP header */
342 if( block_PeekBytes( &p_sys->bytestream, p_header, MLP_HEADER_SIZE ) )
344 /* Need more data */
345 return NULL;
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;
358 break;
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;
370 break;
372 /* Need more data */
373 return NULL;
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 );
385 break;
387 p_sys->i_state = STATE_GET_DATA;
388 break;
390 case STATE_GET_DATA:
391 /* Make sure we have enough data. */
392 if( block_WaitBytes( &p_sys->bytestream, p_sys->i_frame_size ) )
394 /* Need more data */
395 return NULL;
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
401 * data available. */
402 p_out_buffer = block_Alloc( p_sys->i_frame_size );
403 if( !p_out_buffer )
404 return NULL;
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;
415 break;
418 /* Setup output */
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 */
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_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;
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 );