]> git.sesse.net Git - vlc/blob - modules/packetizer/mlp.c
lua: remove variable callback
[vlc] / modules / packetizer / mlp.c
1 /*****************************************************************************
2  * mlp.c: packetize MLP/TrueHD audio
3  *****************************************************************************
4  * Copyright (C) 2008 Laurent Aimar
5  * $Id$
6  *
7  * Authors: Laurent Aimar < fenrir _AT videolan _DOT_ org >
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_codec.h>
34 #include <vlc_aout.h>
35 #include <vlc_block_helper.h>
36 #include <vlc_bits.h>
37 #include <assert.h>
38
39 #include "packetizer_helper.h"
40
41 /*****************************************************************************
42  * Module descriptor
43  *****************************************************************************/
44 static int  Open ( vlc_object_t * );
45 static void Close( vlc_object_t * );
46
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 ()
54
55 /*****************************************************************************
56  *
57  *****************************************************************************/
58 typedef struct
59 {
60     int i_type;
61     unsigned i_rate;
62     unsigned i_channels;
63     int i_channels_conf;
64     unsigned i_samples;
65
66     bool b_vbr;
67     unsigned  i_bitrate;
68
69     unsigned  i_substreams;
70
71 } mlp_header_t;
72
73 struct decoder_sys_t
74 {
75     /*
76      * Input properties
77      */
78     int i_state;
79
80     block_bytestream_t bytestream;
81
82     /*
83      * Common properties
84      */
85     date_t  end_date;
86
87     mtime_t i_pts;
88     int i_frame_size;
89
90     bool         b_mlp;
91     mlp_header_t mlp;
92 };
93
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)
97
98 static const uint8_t pu_start_code[3] = { 0xf8, 0x72, 0x6f };
99
100 /****************************************************************************
101  * Local prototypes
102  ****************************************************************************/
103 static block_t *Packetize( decoder_t *, block_t **pp_block );
104 static int SyncInfo( const uint8_t *p_hdr, bool *pb_mlp, mlp_header_t *p_mlp );
105 static int SyncInfoDolby( const uint8_t *p_buf );
106
107 /*****************************************************************************
108  * Open: probe the decoder/packetizer and return score
109  *****************************************************************************/
110 static int Open( vlc_object_t *p_this )
111 {
112     decoder_t *p_dec = (decoder_t*)p_this;
113     decoder_sys_t *p_sys;
114
115     if( p_dec->fmt_in.i_codec != VLC_CODEC_MLP &&
116         p_dec->fmt_in.i_codec != VLC_CODEC_TRUEHD )
117         return VLC_EGENERIC;
118
119     /* */
120     p_dec->p_sys = p_sys = malloc( sizeof(*p_sys) );
121     if( !p_sys )
122         return VLC_ENOMEM;
123
124     /* */
125     p_sys->i_state = STATE_NOSYNC;
126     date_Set( &p_sys->end_date, 0 );
127
128     block_BytestreamInit( &p_sys->bytestream );
129     p_sys->b_mlp = false;
130
131     /* Set output properties */
132     p_dec->fmt_out.i_cat = AUDIO_ES;
133     p_dec->fmt_out.i_codec = p_dec->fmt_in.i_codec;
134     p_dec->fmt_out.audio.i_rate = 0;
135
136     /* Set callback */
137     p_dec->pf_packetize = Packetize;
138     return VLC_SUCCESS;
139 }
140
141 /****************************************************************************
142  * Packetize:
143  ****************************************************************************/
144 static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
145 {
146     decoder_sys_t *p_sys = p_dec->p_sys;
147     uint8_t p_header[MLP_HEADER_SIZE];
148     block_t *p_out_buffer;
149
150     /* */
151     if( !pp_block || !*pp_block )
152         return NULL;
153
154     /* */
155     if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
156     {
157         if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED )
158         {
159             p_sys->b_mlp = false;
160             p_sys->i_state = STATE_NOSYNC;
161             block_BytestreamEmpty( &p_sys->bytestream );
162         }
163         date_Set( &p_sys->end_date, 0 );
164         block_Release( *pp_block );
165         return NULL;
166     }
167
168     if( !date_Get( &p_sys->end_date ) && !(*pp_block)->i_pts )
169     {
170         /* We've just started the stream, wait for the first PTS. */
171         block_Release( *pp_block );
172         return NULL;
173     }
174
175     block_BytestreamPush( &p_sys->bytestream, *pp_block );
176
177     for( ;; )
178     {
179         switch( p_sys->i_state )
180         {
181         case STATE_NOSYNC:
182             while( !block_PeekBytes( &p_sys->bytestream, p_header, MLP_HEADER_SIZE ) )
183             {
184                 if( SyncInfo( p_header, &p_sys->b_mlp, &p_sys->mlp ) > 0 )
185                 {
186                     p_sys->i_state = STATE_SYNC;
187                     break;
188                 }
189                 else if( SyncInfoDolby( p_header ) > 0 )
190                 {
191                     p_sys->i_state = STATE_SYNC;
192                     break;
193                 }
194                 block_SkipByte( &p_sys->bytestream );
195             }
196             if( p_sys->i_state != STATE_SYNC )
197             {
198                 block_BytestreamFlush( &p_sys->bytestream );
199
200                 /* Need more data */
201                 return NULL;
202             }
203
204         case STATE_SYNC:
205             /* New frame, set the Presentation Time Stamp */
206             p_sys->i_pts = p_sys->bytestream.p_block->i_pts;
207             if( p_sys->i_pts > VLC_TS_INVALID &&
208                 p_sys->i_pts != date_Get( &p_sys->end_date ) )
209             {
210                 date_Set( &p_sys->end_date, p_sys->i_pts );
211             }
212             p_sys->i_state = STATE_HEADER;
213
214         case STATE_HEADER:
215             /* Get a MLP header */
216             if( block_PeekBytes( &p_sys->bytestream, p_header, MLP_HEADER_SIZE ) )
217             {
218                 /* Need more data */
219                 return NULL;
220             }
221
222             /* Check if frame is valid and get frame info */
223             p_sys->i_frame_size = SyncInfoDolby( p_header );
224             if( p_sys->i_frame_size <= 0 )
225                 p_sys->i_frame_size = SyncInfo( p_header, &p_sys->b_mlp, &p_sys->mlp );
226             if( p_sys->i_frame_size <= 0 )
227             {
228                 msg_Dbg( p_dec, "emulated sync word" );
229                 block_SkipByte( &p_sys->bytestream );
230                 p_sys->b_mlp = false;
231                 p_sys->i_state = STATE_NOSYNC;
232                 break;
233             }
234             p_sys->i_state = STATE_NEXT_SYNC;
235
236         case STATE_NEXT_SYNC:
237             /* TODO: If pp_block == NULL, flush the buffer without checking the
238              * next sync word */
239
240             /* Check if next expected frame contains the sync word */
241             if( block_PeekOffsetBytes( &p_sys->bytestream,
242                                        p_sys->i_frame_size, p_header, MLP_HEADER_SIZE ) )
243             {
244                 /* Need more data */
245                 return NULL;
246             }
247
248             bool b_mlp = p_sys->b_mlp;
249             mlp_header_t mlp = p_sys->mlp;
250             if( SyncInfo( p_header, &b_mlp, &mlp ) <= 0 && SyncInfoDolby( p_header ) <= 0 )
251             {
252                 msg_Dbg( p_dec, "emulated sync word "
253                          "(no sync on following frame)" );
254                 p_sys->b_mlp = false;
255                 p_sys->i_state = STATE_NOSYNC;
256                 block_SkipByte( &p_sys->bytestream );
257                 break;
258             }
259             p_sys->i_state = STATE_SEND_DATA;
260             break;
261
262         case STATE_GET_DATA:
263             /* Make sure we have enough data.
264              * (Not useful if we went through NEXT_SYNC) */
265             if( block_WaitBytes( &p_sys->bytestream, p_sys->i_frame_size ) )
266             {
267                 /* Need more data */
268                 return NULL;
269             }
270             p_sys->i_state = STATE_SEND_DATA;
271
272         case STATE_SEND_DATA:
273             /* When we reach this point we already know we have enough
274              * data available. */
275             p_out_buffer = block_New( p_dec, p_sys->i_frame_size );
276             if( !p_out_buffer )
277                 return NULL;
278
279             /* Copy the whole frame into the buffer */
280             block_GetBytes( &p_sys->bytestream,
281                             p_out_buffer->p_buffer, p_out_buffer->i_buffer );
282
283             /* Just ignore (E)AC3 frames */
284             if( SyncInfoDolby( p_out_buffer->p_buffer ) > 0 )
285             {
286                 block_Release( p_out_buffer );
287                 p_sys->i_state = STATE_NOSYNC;
288                 break;
289             }
290
291             /* Setup output */
292             if( p_dec->fmt_out.audio.i_rate != p_sys->mlp.i_rate )
293             {
294                 msg_Info( p_dec, "MLP channels: %d samplerate: %d",
295                           p_sys->mlp.i_channels, p_sys->mlp.i_rate );
296
297                 const mtime_t i_end_date = date_Get( &p_sys->end_date );
298                 date_Init( &p_sys->end_date, p_sys->mlp.i_rate, 1 );
299                 date_Set( &p_sys->end_date, i_end_date );
300             }
301
302             p_dec->fmt_out.audio.i_rate     = p_sys->mlp.i_rate;
303             p_dec->fmt_out.audio.i_channels = p_sys->mlp.i_channels;
304             p_dec->fmt_out.audio.i_original_channels = p_sys->mlp.i_channels_conf;
305             p_dec->fmt_out.audio.i_physical_channels = p_sys->mlp.i_channels_conf & AOUT_CHAN_PHYSMASK;
306
307             p_out_buffer->i_pts = p_out_buffer->i_dts = date_Get( &p_sys->end_date );
308
309             p_out_buffer->i_length =
310                 date_Increment( &p_sys->end_date, p_sys->mlp.i_samples ) - p_out_buffer->i_pts;
311
312             /* Make sure we don't reuse the same pts twice */
313             if( p_sys->i_pts == p_sys->bytestream.p_block->i_pts )
314                 p_sys->i_pts = p_sys->bytestream.p_block->i_pts = VLC_TS_INVALID;
315
316             /* So p_block doesn't get re-added several times */
317             *pp_block = block_BytestreamPop( &p_sys->bytestream );
318
319             p_sys->i_state = STATE_NOSYNC;
320
321             return p_out_buffer;
322         }
323     }
324
325     return NULL;
326 }
327
328 /*****************************************************************************
329  * Close:
330  *****************************************************************************/
331 static void Close( vlc_object_t *p_this )
332 {
333     decoder_t *p_dec = (decoder_t*)p_this;
334     decoder_sys_t *p_sys = p_dec->p_sys;
335
336     block_BytestreamRelease( &p_sys->bytestream );
337
338     free( p_sys );
339 }
340
341 /**
342  * It parse MLP sync info.
343  *
344  * TODO handle CRC (at offset 26)
345   */
346
347 static int TrueHdChannels( int i_map )
348 {
349     static const uint8_t pu_thd[13] =
350     {
351          2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1
352     };
353     int i_count = 0;
354
355     for( int i = 0; i < 13; i++ )
356     {
357         if( i_map & (1<<i) )
358             i_count += pu_thd[i];
359     }
360     return i_count;
361 }
362
363 static int MlpParse( mlp_header_t *p_mlp, const uint8_t p_hdr[MLP_HEADER_SYNC] )
364 {
365     bs_t s;
366
367     assert( !memcmp( p_hdr, pu_start_code, 3 ) );
368
369     /* TODO Checksum ? */
370
371     /* */
372     bs_init( &s, &p_hdr[3], MLP_HEADER_SYNC - 3 );
373
374     /* Stream type */
375     p_mlp->i_type = bs_read( &s, 8 );
376     int i_rate_idx1;
377
378     if( p_mlp->i_type == 0xbb )        /* MLP */
379     {
380         static const unsigned pu_channels[32] = {
381             1, 2, 3, 4, 3, 4, 5, 3, 4, 5, 4, 5, 6, 4, 5, 4,
382             5, 6, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
383         };
384
385         bs_skip( &s, 4 + 4 );
386
387         i_rate_idx1 = bs_read( &s, 4 );
388
389         // Just skip the 4 following, since we don't use it
390         // const int i_rate_idx2 = bs_read( &s, 4 );
391         bs_skip( &s, 4 );
392
393         bs_skip( &s, 11 );
394
395         const int i_channel_idx = bs_read( &s, 5 );
396         p_mlp->i_channels = pu_channels[i_channel_idx];
397     }
398     else if( p_mlp->i_type == 0xba )   /* True HD */
399     {
400         i_rate_idx1 = bs_read( &s, 4 );
401
402         bs_skip( &s, 8 );
403
404         const int i_channel1 = bs_read( &s, 5 );
405
406         bs_skip( &s, 2 );
407
408         const int i_channel2 = bs_read( &s, 13 );
409         if( i_channel2 )
410             p_mlp->i_channels = TrueHdChannels( i_channel2 );
411         else
412             p_mlp->i_channels = TrueHdChannels( i_channel1 );
413     }
414     else
415     {
416         return VLC_EGENERIC;
417     }
418
419     if( i_rate_idx1 == 0x0f )
420         p_mlp->i_rate = 0;
421     else
422         p_mlp->i_rate = ( ( i_rate_idx1 & 0x8 ) ? 44100 : 48000 ) << (i_rate_idx1 & 0x7);
423     p_mlp->i_channels_conf = 0; /* TODO ? */
424
425     p_mlp->i_samples = 40 << ( i_rate_idx1 & 0x07 );
426
427     bs_skip( &s, 48 );
428
429     p_mlp->b_vbr = bs_read( &s, 1 );
430     p_mlp->i_bitrate = ( bs_read( &s, 15 ) * p_mlp->i_rate + 8) / 16;
431
432     p_mlp->i_substreams = bs_read( &s, 4 );
433     bs_skip( &s, 4 + 11 * 8 );
434
435     //fprintf( stderr, "i_samples = %d channels:%d rate:%d bitsrate=%d substreams=%d\n",
436     //        p_mlp->i_samples, p_mlp->i_channels, p_mlp->i_rate, p_mlp->i_bitrate, p_mlp->i_substreams );
437     return VLC_SUCCESS;
438 }
439
440 static int SyncInfo( const uint8_t *p_hdr, bool *pb_mlp, mlp_header_t *p_mlp )
441 {
442     /* Check major sync presence */
443     const bool b_has_sync = !memcmp( &p_hdr[4], pu_start_code, 3 );
444
445     /* Wait for a major sync */
446     if( !b_has_sync && !*pb_mlp )
447         return 0;
448
449     /* Parse major sync if present */
450     if( b_has_sync )
451     {
452         *pb_mlp = !MlpParse( p_mlp, &p_hdr[4] );
453
454         if( !*pb_mlp )
455             return 0;
456     }
457
458     /* Check parity TODO even with major sync */
459     if( 1 )
460     {
461         int i_tmp = 0 ^ p_hdr[0] ^ p_hdr[1] ^ p_hdr[2] ^ p_hdr[3];
462         const uint8_t *p = &p_hdr[4 + ( b_has_sync ? 28 : 0 )];
463
464         for( unsigned i = 0; i < p_mlp->i_substreams; i++ )
465         {
466             i_tmp ^= *p++;
467             i_tmp ^= *p++;
468             if( p[-2] & 0x80 )
469             {
470                 i_tmp ^= *p++;
471                 i_tmp ^= *p++;
472             }
473         }
474         i_tmp = ( i_tmp >> 4 ) ^ i_tmp;
475
476         if( ( i_tmp & 0x0f ) != 0x0f )
477             return 0;
478     }
479
480     /* */
481     const int i_word = ( ( p_hdr[0] << 8 ) | p_hdr[1] ) & 0xfff;
482     return i_word * 2;
483 }
484
485 /**
486  * It returns the size of an AC3 frame (or 0 if invalid)
487  */
488 static int GetAc3Size( const uint8_t *p_buf )
489 {
490     static const int pi_rate[] = { 32,  40,  48,  56,  64,  80,  96, 112,
491                                 128, 160, 192, 224, 256, 320, 384, 448,
492                                 512, 576, 640 };
493     /* */
494     const int i_frmsizecod = p_buf[4] & 63;
495     if( i_frmsizecod >= 38 )
496         return 0;
497
498     const int bitrate = pi_rate[i_frmsizecod >> 1];
499
500     switch( p_buf[4] & 0xc0 )
501     {
502     case 0:
503         return 4 * bitrate;
504     case 0x40:
505         return 2 * (320 * bitrate / 147 + (i_frmsizecod & 1));
506     case 0x80:
507         return 6 * bitrate;
508     default:
509         return 0;
510     }
511 }
512
513 /**
514  * It return the size of a EAC3 frame (or 0 if invalid)
515  */
516 static int GetEac3Size( const uint8_t *p_buf )
517 {
518     int i_frame_size;
519     int i_bytes;
520
521     i_frame_size = ( ( p_buf[2] << 8 ) | p_buf[3] ) & 0x7ff;
522     if( i_frame_size < 2 )
523         return 0;
524     i_bytes = 2 * ( i_frame_size + 1 );
525
526     return i_bytes;
527 }
528
529 /**
530  * It returns the size of an AC3/EAC3 frame (or 0 if invalid)
531  */
532 static int SyncInfoDolby( const uint8_t *p_buf )
533 {
534     int bsid;
535
536     /* Check synword */
537     if( p_buf[0] != 0x0b || p_buf[1] != 0x77 )
538         return 0;
539
540     /* Check bsid */
541     bsid = p_buf[5] >> 3;
542     if( bsid > 16 )
543         return 0;
544
545     if( bsid <= 10 )
546         return GetAc3Size( p_buf );
547     else
548         return GetEac3Size( p_buf );
549 }
550