es.c 39.2 KB
Newer Older
1
/*****************************************************************************
2
 * es.c : Generic audio ES input module for vlc
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2001-2008 VLC authors and VideoLAN
5
 * $Id$
6
7
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8
 *          Gildas Bazin <gbazin@videolan.org>
9
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
10
11
12
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
13
14
15
16
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
17
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
19
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
20
21
22
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23
24
25
26
27
28
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

29
30
31
32
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

33
#include <vlc_common.h>
34
#include <vlc_plugin.h>
zorglub's avatar
zorglub committed
35
36
#include <vlc_demux.h>
#include <vlc_codec.h>
37
#include <vlc_codecs.h>
Laurent Aimar's avatar
Laurent Aimar committed
38
#include <vlc_input.h>
zorglub's avatar
zorglub committed
39

Thomas Guillem's avatar
Thomas Guillem committed
40
#include "../../packetizer/a52.h"
41
#include "../../packetizer/dts_header.h"
42
#include "../meta_engine/ID3Tag.h"
43

44
45
46
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
47
static int  OpenAudio( vlc_object_t * );
48
static int  OpenVideo( vlc_object_t * );
49
static void Close    ( vlc_object_t * );
50

51
52
53
54
#define FPS_TEXT N_("Frames per Second")
#define FPS_LONGTEXT N_("This is the frame rate used as a fallback when " \
    "playing MPEG video elementary streams.")

55
56
57
vlc_module_begin ()
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_DEMUX )
58
    set_description( N_("MPEG-I/II/4 / A52 / DTS / MLP audio" ) )
59
    set_shortname( N_("Audio ES") )
60
    set_capability( "demux", 155 )
61
    set_callbacks( OpenAudio, Close )
62

63
64
65
66
67
68
    add_shortcut( "mpga", "mp3",
                  "m4a", "mp4a", "aac",
                  "ac3", "a52",
                  "eac3",
                  "dts",
                  "mlp", "thd" )
69
70
71
72
73

    add_submodule()
    set_description( N_("MPEG-4 video" ) )
    set_capability( "demux", 0 )
    set_callbacks( OpenVideo, Close )
74
    add_float( "es-fps", 25, FPS_TEXT, FPS_LONGTEXT, false )
75
76
77

    add_shortcut( "m4v" )
    add_shortcut( "mp4v" )
78
vlc_module_end ()
79
80
81
82

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
83
84
static int Demux  ( demux_t * );
static int Control( demux_t *, int, va_list );
85

86
87
88
typedef struct
{
    vlc_fourcc_t i_codec;
89
    bool       b_use_word;
90
91
92
93
94
    const char *psz_name;
    int  (*pf_probe)( demux_t *p_demux, int64_t *pi_offset );
    int  (*pf_init)( demux_t *p_demux );
} codec_t;

95
96
97
98
99
100
101
102
typedef struct
{
    char  psz_version[10];
    int   i_lowpass;
    float pf_replay_gain[AUDIO_REPLAY_GAIN_MAX];
    float pf_replay_peak[AUDIO_REPLAY_GAIN_MAX];
} lame_extra_t;

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
typedef struct
{
    mtime_t i_time;
    uint64_t i_pos;
    bs_t br;
} sync_table_ctx_t;

typedef struct
{
    uint16_t i_frames_btw_refs;
    uint32_t i_bytes_btw_refs;
    uint32_t i_ms_btw_refs;
    uint8_t i_bits_per_bytes_dev;
    uint8_t i_bits_per_ms_dev;
    uint8_t *p_bits;
    size_t i_bits;
    sync_table_ctx_t current;
} sync_table_t;

122
123
struct demux_sys_t
{
124
    codec_t codec;
125
    vlc_fourcc_t i_original;
126

127
    es_out_id_t *p_es;
128

129
    bool  b_start;
130
    decoder_t   *p_packetizer;
131
    block_t     *p_packetized_data;
132

133
134
    mtime_t     i_pts;
    mtime_t     i_time_offset;
135
    int64_t     i_bytes;
136

137
    bool        b_big_endian;
138
    bool        b_estimate_bitrate;
139
    int         i_bitrate_avg;  /* extracted from Xing header */
zorglub's avatar
zorglub committed
140

141
    bool b_initial_sync_failed;
142

143
    int i_packet_size;
144

145
146
    int64_t i_stream_offset;

147
148
    float   f_fps;

149
150
    /* Mpga specific */
    struct
151
    {
152
153
154
155
        int i_frames;
        int i_bytes;
        int i_bitrate_avg;
        int i_frame_samples;
156
157
        lame_extra_t lame;
        bool b_lame;
158
    } xing;
159
160

    sync_table_t mllt;
161
};
162

163
164
static int MpgaProbe( demux_t *p_demux, int64_t *pi_offset );
static int MpgaInit( demux_t *p_demux );
165

166
167
168
static int AacProbe( demux_t *p_demux, int64_t *pi_offset );
static int AacInit( demux_t *p_demux );

169
static int EA52Probe( demux_t *p_demux, int64_t *pi_offset );
170
171
172
static int A52Probe( demux_t *p_demux, int64_t *pi_offset );
static int A52Init( demux_t *p_demux );

173
174
175
static int DtsProbe( demux_t *p_demux, int64_t *pi_offset );
static int DtsInit( demux_t *p_demux );

176
static int MlpProbe( demux_t *p_demux, int64_t *pi_offset );
177
static int ThdProbe( demux_t *p_demux, int64_t *pi_offset );
178
179
static int MlpInit( demux_t *p_demux );

180
static bool Parse( demux_t *p_demux, block_t **pp_output );
181
static uint64_t SeekByMlltTable( demux_t *p_demux, mtime_t *pi_time );
182

183
static const codec_t p_codecs[] = {
184
185
186
187
188
    { VLC_CODEC_MP4A, false, "mp4 audio",  AacProbe,  AacInit },
    { VLC_CODEC_MPGA, false, "mpeg audio", MpgaProbe, MpgaInit },
    { VLC_CODEC_A52, true,  "a52 audio",  A52Probe,  A52Init },
    { VLC_CODEC_EAC3, true,  "eac3 audio", EA52Probe, A52Init },
    { VLC_CODEC_DTS, false, "dts audio",  DtsProbe,  DtsInit },
189
    { VLC_CODEC_MLP, false, "mlp audio",  MlpProbe,  MlpInit },
190
    { VLC_CODEC_TRUEHD, false, "TrueHD audio",  ThdProbe,  MlpInit },
191

192
    { 0, false, NULL, NULL, NULL }
193
194
};

195
196
197
198
199
200
static int VideoInit( demux_t *p_demux );

static const codec_t codec_m4v = {
    VLC_CODEC_MP4V, false, "mp4 video", NULL,  VideoInit
};

201
/*****************************************************************************
202
 * OpenCommon: initializes demux structures
203
 *****************************************************************************/
204
205
static int OpenCommon( demux_t *p_demux,
                       int i_cat, const codec_t *p_codec, int64_t i_bs_offset )
206
{
Laurent Aimar's avatar
Laurent Aimar committed
207
    demux_sys_t *p_sys;
208

209
    es_format_t fmt;
210

211
    DEMUX_INIT_COMMON(); p_sys = p_demux->p_sys;
212
    memset( p_sys, 0, sizeof( demux_sys_t ) );
213
    p_sys->codec = *p_codec;
214
    p_sys->p_es = NULL;
215
    p_sys->b_start = true;
216
    p_sys->i_stream_offset = i_bs_offset;
217
    p_sys->b_estimate_bitrate = true;
218
    p_sys->i_bitrate_avg = 0;
219
    p_sys->b_big_endian = false;
220
    p_sys->f_fps = var_InheritFloat( p_demux, "es-fps" );
221
    p_sys->p_packetized_data = NULL;
222

223
    if( vlc_stream_Seek( p_demux->s, p_sys->i_stream_offset ) )
224
    {
225
226
        free( p_sys );
        return VLC_EGENERIC;
227
228
    }

229
    if( p_sys->codec.pf_init( p_demux ) )
230
    {
231
232
        free( p_sys );
        return VLC_EGENERIC;
233
234
    }

235
236
    msg_Dbg( p_demux, "detected format %4.4s", (const char*)&p_sys->codec.i_codec );

237
    /* Load the audio packetizer */
238
    es_format_Init( &fmt, i_cat, p_sys->codec.i_codec );
239
    fmt.i_original_fourcc = p_sys->i_original;
240
    p_sys->p_packetizer = demux_PacketizerNew( p_demux, &fmt, p_sys->codec.psz_name );
241
242
243
244
245
    if( !p_sys->p_packetizer )
    {
        free( p_sys );
        return VLC_EGENERIC;
    }
246

247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
    if( p_sys->xing.b_lame )
    {
        lame_extra_t *p_lame = &p_sys->xing.lame;
        es_format_t *p_fmt = &p_sys->p_packetizer->fmt_out;

        for( int i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
        {
            if ( p_lame->pf_replay_gain[i] != 0 )
            {
                p_fmt->audio_replay_gain.pb_gain[i] = true;
                p_fmt->audio_replay_gain.pf_gain[i] = p_lame->pf_replay_gain[i];
            }
            if ( p_lame->pf_replay_peak[i] != 0 )
            {
                p_fmt->audio_replay_gain.pb_peak[i] = true;
                p_fmt->audio_replay_gain.pf_peak[i] = p_lame->pf_replay_peak[i];
            }
        }
    }

267
    for( ;; )
268
269
270
271
272
273
    {
        if( Parse( p_demux, &p_sys->p_packetized_data ) )
            break;
        if( p_sys->p_packetized_data )
            break;
    }
274

Laurent Aimar's avatar
Laurent Aimar committed
275
    return VLC_SUCCESS;
276
}
277
278
279
280
281
282
283
284
285
286
287
static int OpenAudio( vlc_object_t *p_this )
{
    demux_t *p_demux = (demux_t*)p_this;
    for( int i = 0; p_codecs[i].i_codec != 0; i++ )
    {
        int64_t i_offset;
        if( !p_codecs[i].pf_probe( p_demux, &i_offset ) )
            return OpenCommon( p_demux, AUDIO_ES, &p_codecs[i], i_offset );
    }
    return VLC_EGENERIC;
}
288
289
290
291
292
293
294
295
296
297
static int OpenVideo( vlc_object_t *p_this )
{
    demux_t *p_demux = (demux_t*)p_this;

    /* Only m4v is supported for the moment */
    bool b_m4v_ext    = demux_IsPathExtension( p_demux, ".m4v" );
    bool b_m4v_forced = demux_IsForced( p_demux, "m4v" ) ||
                        demux_IsForced( p_demux, "mp4v" );
    if( !b_m4v_ext && !b_m4v_forced )
        return VLC_EGENERIC;
298

299
    const uint8_t *p_peek;
300
    if( vlc_stream_Peek( p_demux->s, &p_peek, 4 ) < 4 )
301
302
303
304
305
306
307
308
309
310
        return VLC_EGENERIC;
    if( p_peek[0] != 0x00 || p_peek[1] != 0x00 || p_peek[2] != 0x01 )
    {
        if( !b_m4v_forced)
            return VLC_EGENERIC;
        msg_Warn( p_demux,
                  "this doesn't look like an MPEG ES stream, continuing anyway" );
    }
    return OpenCommon( p_demux, VIDEO_ES, &codec_m4v, 0 );
}
311
312
313
314
315
/*****************************************************************************
 * Demux: reads and demuxes data packets
 *****************************************************************************
 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
316
static int Demux( demux_t *p_demux )
317
{
318
    int ret = 1;
Laurent Aimar's avatar
Laurent Aimar committed
319
    demux_sys_t *p_sys = p_demux->p_sys;
320

321
322
323
    block_t *p_block_out = p_sys->p_packetized_data;
    if( p_block_out )
        p_sys->p_packetized_data = NULL;
324
325
    else
        ret = Parse( p_demux, &p_block_out ) ? 0 : 1;
326

327
    while( p_block_out )
328
    {
329
        block_t *p_next = p_block_out->p_next;
330

331
332
        /* Correct timestamp */
        if( p_sys->p_packetizer->fmt_out.i_cat == VIDEO_ES )
333
        {
334
335
336
337
338
339
340
341
342
343
            if( p_block_out->i_pts <= VLC_TS_INVALID &&
                p_block_out->i_dts <= VLC_TS_INVALID )
                p_block_out->i_dts = VLC_TS_0 + p_sys->i_pts + 1000000 / p_sys->f_fps;
            if( p_block_out->i_dts > VLC_TS_INVALID )
                p_sys->i_pts = p_block_out->i_dts - VLC_TS_0;
        }
        else
        {
            p_sys->i_pts = p_block_out->i_pts - VLC_TS_0;
        }
344

345
346
347
348
349
350
351
352
353
354
355
356
357
        if( p_block_out->i_pts > VLC_TS_INVALID )
        {
            p_block_out->i_pts += p_sys->i_time_offset;
        }
        if( p_block_out->i_dts > VLC_TS_INVALID )
        {
            p_block_out->i_dts += p_sys->i_time_offset;
            es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block_out->i_dts );
        }
        /* Re-estimate bitrate */
        if( p_sys->b_estimate_bitrate && p_sys->i_pts > INT64_C(500000) )
            p_sys->i_bitrate_avg = 8*INT64_C(1000000)*p_sys->i_bytes/(p_sys->i_pts-1);
        p_sys->i_bytes += p_block_out->i_buffer;
358

359

360
361
        p_block_out->p_next = NULL;
        es_out_Send( p_demux->out, p_sys->p_es, p_block_out );
362

363
        p_block_out = p_next;
364
    }
365
    return ret;
366
367
368
369
370
371
372
}

/*****************************************************************************
 * Close: frees unused data
 *****************************************************************************/
static void Close( vlc_object_t * p_this )
{
Laurent Aimar's avatar
Laurent Aimar committed
373
374
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys = p_demux->p_sys;
375

376
377
    if( p_sys->p_packetized_data )
        block_ChainRelease( p_sys->p_packetized_data );
378
379
    if( p_sys->mllt.p_bits )
        free( p_sys->mllt.p_bits );
380
    demux_PacketizerDestroy( p_sys->p_packetizer );
381
382
383
    free( p_sys );
}

Laurent Aimar's avatar
Laurent Aimar committed
384
385
386
387
388
389
/*****************************************************************************
 * Control:
 *****************************************************************************/
static int Control( demux_t *p_demux, int i_query, va_list args )
{
    demux_sys_t *p_sys  = p_demux->p_sys;
390
    int64_t *pi64;
391
    bool *pb_bool;
392
    int i_ret;
zorglub's avatar
zorglub committed
393
394
395

    switch( i_query )
    {
396
        case DEMUX_HAS_UNSUPPORTED_META:
397
398
            pb_bool = (bool*)va_arg( args, bool* );
            *pb_bool = true;
399
400
            return VLC_SUCCESS;

401
402
        case DEMUX_GET_TIME:
            pi64 = (int64_t*)va_arg( args, int64_t * );
403
            *pi64 = p_sys->i_pts + p_sys->i_time_offset;
404
405
            return VLC_SUCCESS;

406
        case DEMUX_GET_LENGTH:
407
408
409
410
411
412
413
414
        {
            va_list ap;

            va_copy ( ap, args );
            i_ret = demux_vaControlHelper( p_demux->s, p_sys->i_stream_offset,
                                    -1, p_sys->i_bitrate_avg, 1, i_query, ap );
            va_end( ap );

415
416
            /* No bitrate, we can't have it precisely, but we can compute
             * a raw approximation with time/position */
417
            if( i_ret && !p_sys->i_bitrate_avg )
418
            {
419
                float f_pos = (double)(uint64_t)( vlc_stream_Tell( p_demux->s ) ) /
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
420
                              (double)(uint64_t)( stream_Size( p_demux->s ) );
421
422
                /* The first few seconds are guaranteed to be very whacky,
                 * don't bother trying ... Too bad */
423
                if( f_pos < 0.01f ||
424
                    (p_sys->i_pts + p_sys->i_time_offset) < 8000000 )
ivoire's avatar
ivoire committed
425
                {
426
                    return VLC_EGENERIC;
ivoire's avatar
ivoire committed
427
                }
428

429
                pi64 = (int64_t *)va_arg( args, int64_t * );
430
431
432
                *pi64 = (p_sys->i_pts + p_sys->i_time_offset) / f_pos;
                return VLC_SUCCESS;
            }
433
            return i_ret;
434
        }
435

436
        case DEMUX_SET_TIME:
437
438
439
440
441
442
443
        {
            if( p_sys->mllt.p_bits )
            {
                int64_t i_time = va_arg(args, int64_t);
                uint64_t i_pos = SeekByMlltTable( p_demux, &i_time );
                int i_ret = vlc_stream_Seek( p_demux->s, p_sys->i_stream_offset + i_pos );
                if( i_ret != VLC_SUCCESS )
444
                    return i_ret;
445
446
447
448
449
450
451
                p_sys->i_time_offset = i_time - p_sys->i_pts;
                /* And reset buffered data */
                if( p_sys->p_packetized_data )
                    block_ChainRelease( p_sys->p_packetized_data );
                p_sys->p_packetized_data = NULL;
                return VLC_SUCCESS;
            }
452
453
            /* FIXME TODO: implement a high precision seek (with mp3 parsing)
             * needed for multi-input */
454
        }
455
        default:
456
            i_ret = demux_vaControlHelper( p_demux->s, p_sys->i_stream_offset, -1,
457
458
                                            p_sys->i_bitrate_avg, 1, i_query,
                                            args );
459
            if( !i_ret && p_sys->i_bitrate_avg > 0 &&
460
                (i_query == DEMUX_SET_POSITION || i_query == DEMUX_SET_TIME) )
461
            {
462
                int64_t i_time = INT64_C(8000000) * ( vlc_stream_Tell(p_demux->s) - p_sys->i_stream_offset ) /
463
                    p_sys->i_bitrate_avg;
464

465
                /* Fix time_offset */
466
467
                if( i_time >= 0 )
                    p_sys->i_time_offset = i_time - p_sys->i_pts;
468
469
470
471
                /* And reset buffered data */
                if( p_sys->p_packetized_data )
                    block_ChainRelease( p_sys->p_packetized_data );
                p_sys->p_packetized_data = NULL;
472
473
            }
            return i_ret;
zorglub's avatar
zorglub committed
474
    }
Laurent Aimar's avatar
Laurent Aimar committed
475
}
476

477
/*****************************************************************************
478
479
 * Makes a link list of buffer of parsed data
 * Returns true if EOF
480
 *****************************************************************************/
481
static bool Parse( demux_t *p_demux, block_t **pp_output )
482
483
484
485
486
487
488
489
490
{
    demux_sys_t *p_sys = p_demux->p_sys;
    block_t *p_block_in, *p_block_out;

    *pp_output = NULL;

    if( p_sys->codec.b_use_word )
    {
        /* Make sure we are word aligned */
491
492
        int64_t i_pos = vlc_stream_Tell( p_demux->s );
        if( (i_pos & 1) && vlc_stream_Read( p_demux->s, NULL, 1 ) != 1 )
493
            return true;
494
495
    }

496
    p_block_in = vlc_stream_Block( p_demux->s, p_sys->i_packet_size );
497
    bool b_eof = p_block_in == NULL;
498

499
    if( p_block_in )
500
    {
501
502
503
504
505
        if( p_sys->codec.b_use_word && !p_sys->b_big_endian && p_block_in->i_buffer > 0 )
        {
            /* Convert to big endian */
            swab( p_block_in->p_buffer, p_block_in->p_buffer, p_block_in->i_buffer );
        }
506

507
508
        p_block_in->i_pts = p_block_in->i_dts = p_sys->b_start || p_sys->b_initial_sync_failed ? VLC_TS_0 : VLC_TS_INVALID;
    }
509
510
    p_sys->b_initial_sync_failed = p_sys->b_start; /* Only try to resync once */

511
    while( ( p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, p_block_in ? &p_block_in : NULL ) ) )
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
    {
        p_sys->b_initial_sync_failed = false;
        while( p_block_out )
        {
            if( !p_sys->p_es )
            {
                p_sys->p_packetizer->fmt_out.b_packetized = true;
                p_sys->p_es = es_out_Add( p_demux->out,
                                          &p_sys->p_packetizer->fmt_out);


                /* Try the xing header */
                if( p_sys->xing.i_bytes && p_sys->xing.i_frames &&
                    p_sys->xing.i_frame_samples )
                {
                    p_sys->i_bitrate_avg = p_sys->xing.i_bytes * INT64_C(8) *
                        p_sys->p_packetizer->fmt_out.audio.i_rate /
                        p_sys->xing.i_frames / p_sys->xing.i_frame_samples;

                    if( p_sys->i_bitrate_avg > 0 )
                        p_sys->b_estimate_bitrate = false;
                }
                /* Use the bitrate as initual value */
                if( p_sys->b_estimate_bitrate )
                    p_sys->i_bitrate_avg = p_sys->p_packetizer->fmt_out.i_bitrate;
            }

            block_t *p_next = p_block_out->p_next;
            p_block_out->p_next = NULL;

            block_ChainLastAppend( &pp_output, p_block_out );

            p_block_out = p_next;
        }
    }

    if( p_sys->b_initial_sync_failed )
        msg_Dbg( p_demux, "did not sync on first block" );
    p_sys->b_start = false;
551
552

    return b_eof;
553
554
}

555
556
557
558
559
560
561
562
563
564
565
566
567
/* Check to apply to WAVE fmt header */
static int GenericFormatCheck( int i_format, const uint8_t *p_head )
{
    if ( i_format == WAVE_FORMAT_PCM )
    {
        if( GetWLE( p_head /* nChannels */ ) != 2 )
            return VLC_EGENERIC;
        if( GetDWLE( p_head + 2 /* nSamplesPerSec */ ) != 44100 )
            return VLC_EGENERIC;
    }
    return VLC_SUCCESS;
}

Laurent Aimar's avatar
Laurent Aimar committed
568
569
570
571
/*****************************************************************************
 * Wav header skipper
 *****************************************************************************/
#define WAV_PROBE_SIZE (512*1024)
572
573
static int WavSkipHeader( demux_t *p_demux, int *pi_skip, const int pi_format[],
                          int (*pf_format_check)( int, const uint8_t * ) )
Laurent Aimar's avatar
Laurent Aimar committed
574
575
576
577
578
579
580
581
{
    const uint8_t *p_peek;
    int         i_peek = 0;

    /* */
    *pi_skip = 0;

    /* Check if we are dealing with a WAV file */
582
    if( vlc_stream_Peek( p_demux->s, &p_peek, 12+8 ) != 12 + 8 )
Laurent Aimar's avatar
Laurent Aimar committed
583
584
585
586
587
588
589
590
591
592
593
594
595
596
        return VLC_SUCCESS;

    if( memcmp( p_peek, "RIFF", 4 ) || memcmp( &p_peek[8], "WAVE", 4 ) )
        return VLC_SUCCESS;

    /* Find the wave format header */
    i_peek = 12 + 8;
    while( memcmp( p_peek + i_peek - 8, "fmt ", 4 ) )
    {
        uint32_t i_len = GetDWLE( p_peek + i_peek - 4 );
        if( i_len > WAV_PROBE_SIZE || i_peek + i_len > WAV_PROBE_SIZE )
            return VLC_EGENERIC;

        i_peek += i_len + 8;
597
        if( vlc_stream_Peek( p_demux->s, &p_peek, i_peek ) != i_peek )
Laurent Aimar's avatar
Laurent Aimar committed
598
599
600
601
602
603
604
605
606
            return VLC_EGENERIC;
    }

    /* Sanity check the wave format header */
    uint32_t i_len = GetDWLE( p_peek + i_peek - 4 );
    if( i_len > WAV_PROBE_SIZE )
        return VLC_EGENERIC;

    i_peek += i_len + 8;
607
    if( vlc_stream_Peek( p_demux->s, &p_peek, i_peek ) != i_peek )
Laurent Aimar's avatar
Laurent Aimar committed
608
609
610
611
612
613
614
615
616
617
618
        return VLC_EGENERIC;
    const int i_format = GetWLE( p_peek + i_peek - i_len - 8 /* wFormatTag */ );
    int i_format_idx;
    for( i_format_idx = 0; pi_format[i_format_idx] != WAVE_FORMAT_UNKNOWN; i_format_idx++ )
    {
        if( i_format == pi_format[i_format_idx] )
            break;
    }
    if( pi_format[i_format_idx] == WAVE_FORMAT_UNKNOWN )
        return VLC_EGENERIC;

619
620
    if( pf_format_check &&
        pf_format_check( i_format, p_peek + i_peek - i_len - 6 ) != VLC_SUCCESS )
Laurent Aimar's avatar
Laurent Aimar committed
621
622
623
624
625
626
627
628
629
630
            return VLC_EGENERIC;

    /* Skip the wave header */
    while( memcmp( p_peek + i_peek - 8, "data", 4 ) )
    {
        uint32_t i_len = GetDWLE( p_peek + i_peek - 4 );
        if( i_len > WAV_PROBE_SIZE || i_peek + i_len > WAV_PROBE_SIZE )
            return VLC_EGENERIC;

        i_peek += i_len + 8;
631
        if( vlc_stream_Peek( p_demux->s, &p_peek, i_peek ) != i_peek )
Laurent Aimar's avatar
Laurent Aimar committed
632
633
634
635
636
637
638
639
            return VLC_EGENERIC;
    }
    *pi_skip = i_peek;
    return VLC_SUCCESS;
}

static int GenericProbe( demux_t *p_demux, int64_t *pi_offset,
                         const char * ppsz_name[],
640
                         int (*pf_check)( const uint8_t *, int * ), int i_check_size,
641
642
                         const int pi_wav_format[],
                         int (*pf_format_check)( int, const uint8_t * ) )
Laurent Aimar's avatar
Laurent Aimar committed
643
644
645
646
647
648
649
650
651
652
653
654
655
{
    bool   b_forced_demux;

    int64_t i_offset;
    const uint8_t *p_peek;
    int i_skip;

    b_forced_demux = false;
    for( int i = 0; ppsz_name[i] != NULL; i++ )
    {
        b_forced_demux |= demux_IsForced( p_demux, ppsz_name[i] );
    }

656
    i_offset = vlc_stream_Tell( p_demux->s );
Laurent Aimar's avatar
Laurent Aimar committed
657

658
    if( WavSkipHeader( p_demux, &i_skip, pi_wav_format, pf_format_check ) )
Laurent Aimar's avatar
Laurent Aimar committed
659
660
661
662
663
664
665
    {
        if( !b_forced_demux )
            return VLC_EGENERIC;
    }
    const bool b_wav = i_skip > 0;

    /* peek the begining
666
     * It is common that wav files have some sort of garbage at the begining
667
     * We will accept probing 0.5s of data in this case.
668
     */
669
    const int i_probe = i_skip + i_check_size + 8000 + ( b_wav ? (44000/2*2*2) : 0);
670
    const int i_peek = vlc_stream_Peek( p_demux->s, &p_peek, i_probe );
Laurent Aimar's avatar
Laurent Aimar committed
671
672
673
674
675
676
677
678
679
680
681
682
683
    if( i_peek < i_skip + i_check_size )
    {
        msg_Err( p_demux, "cannot peek" );
        return VLC_EGENERIC;
    }
    for( ;; )
    {
        if( i_skip + i_check_size > i_peek )
        {
            if( !b_forced_demux )
                return VLC_EGENERIC;
            break;
        }
684
685
        int i_samples = 0;
        int i_size = pf_check( &p_peek[i_skip], &i_samples );
Laurent Aimar's avatar
Laurent Aimar committed
686
687
        if( i_size >= 0 )
        {
688
689
            if( i_size == 0 || /* 0 sized frame ?? */
                i_skip == 0 /* exact match from start, we're not WAVE either, so skip multiple checks (would break if padding) */ )
Laurent Aimar's avatar
Laurent Aimar committed
690
691
692
                break;

            /* If we have the frame size, check the next frame for
693
694
695
696
697
             * extra robustness
             * The second test is because some .wav have paddings
             */
            bool b_ok = false;
            for( int t = 0; t < 1 + !!b_wav; t++ )
Laurent Aimar's avatar
Laurent Aimar committed
698
            {
699
                if( t == 1 )
700
701
702
                {
                    if(!i_samples)
                        break;
703
                    i_size = i_samples * 2 * 2;
704
705
                }

706
707
708
709
710
711
                if( i_skip + i_check_size + i_size <= i_peek )
                {
                    b_ok = pf_check( &p_peek[i_skip+i_size], NULL ) >= 0;
                    if( b_ok )
                        break;
                }
Laurent Aimar's avatar
Laurent Aimar committed
712
            }
713
714
            if( b_ok )
                break;
Laurent Aimar's avatar
Laurent Aimar committed
715
716
        }
        i_skip++;
717
718
        if( !b_wav && !b_forced_demux )
            return VLC_EGENERIC;
Laurent Aimar's avatar
Laurent Aimar committed
719
720
721
722
723
724
    }

    *pi_offset = i_offset + i_skip;
    return VLC_SUCCESS;
}

725
726
727
/*****************************************************************************
 * Mpeg I/II Audio
 *****************************************************************************/
728
static int MpgaCheckSync( const uint8_t *p_peek )
729
730
731
732
{
    uint32_t h = GetDWBE( p_peek );

    if( ((( h >> 21 )&0x07FF) != 0x07FF )   /* header sync */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
733
        || (((h >> 19)&0x03) == 1 )         /* valid version ID ? */
734
        || (((h >> 17)&0x03) == 0 )         /* valid layer ?*/
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
735
        || (((h >> 12)&0x0F) == 0x0F )      /* valid bitrate ?*/
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
        || (((h >> 10) & 0x03) == 0x03 )    /* valide sampling freq ? */
        || ((h & 0x03) == 0x02 ))           /* valid emphasis ? */
    {
        return false;
    }
    return true;
}

#define MPGA_VERSION( h )   ( 1 - (((h)>>19)&0x01) )
#define MPGA_MODE(h)        (((h)>> 6)&0x03)

static int MpgaGetFrameSamples( uint32_t h )
{
    const int i_layer = 3 - (((h)>>17)&0x03);
    switch( i_layer )
    {
    case 0:
        return 384;
    case 1:
        return 1152;
    case 2:
        return MPGA_VERSION(h) ? 576 : 1152;
    default:
        return 0;
    }
}

static int MpgaProbe( demux_t *p_demux, int64_t *pi_offset )
{
765
    const int pi_wav[] = { WAVE_FORMAT_MPEG, WAVE_FORMAT_MPEGLAYER3, WAVE_FORMAT_UNKNOWN };
766
767
768
769
    bool   b_forced;
    bool   b_forced_demux;
    int64_t i_offset;

770
771
    const uint8_t *p_peek;
    int i_skip;
772
773
774
775
776

    b_forced = demux_IsPathExtension( p_demux, ".mp3" );
    b_forced_demux = demux_IsForced( p_demux, "mp3" ) ||
                     demux_IsForced( p_demux, "mpga" );

777
    i_offset = vlc_stream_Tell( p_demux->s );
778

779
    if( WavSkipHeader( p_demux, &i_skip, pi_wav, NULL ) )
780
781
782
783
    {
        if( !b_forced_demux )
            return VLC_EGENERIC;

784
        return VLC_EGENERIC;
785
    }
786

787
    if( vlc_stream_Peek( p_demux->s, &p_peek, i_skip + 4 ) < i_skip + 4 )
788
789
790
        return VLC_EGENERIC;

    if( !MpgaCheckSync( &p_peek[i_skip] ) )
791
792
793
794
795
796
797
    {
        bool b_ok = false;
        int i_peek;

        if( !b_forced_demux && !b_forced )
            return VLC_EGENERIC;

798
        i_peek = vlc_stream_Peek( p_demux->s, &p_peek, i_skip + 8096 );
799
        while( i_skip + 4 < i_peek )
800
        {
801
            if( MpgaCheckSync( &p_peek[i_skip] ) )
802
803
804
805
            {
                b_ok = true;
                break;
            }
806
            i_skip++;
807
808
809
810
        }
        if( !b_ok && !b_forced_demux )
            return VLC_EGENERIC;
    }
811
    *pi_offset = i_offset + i_skip;
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
    return VLC_SUCCESS;
}

static void MpgaXingSkip( const uint8_t **pp_xing, int *pi_xing, int i_count )
{
    if(i_count > *pi_xing )
        i_count = *pi_xing;

    (*pp_xing) += i_count;
    (*pi_xing) -= i_count;
}

static uint32_t MpgaXingGetDWBE( const uint8_t **pp_xing, int *pi_xing, uint32_t i_default )
{
    if( *pi_xing < 4 )
        return i_default;

    uint32_t v = GetDWBE( *pp_xing );

    MpgaXingSkip( pp_xing, pi_xing, 4 );

    return v;
}

836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
static uint16_t MpgaXingGetWBE( const uint8_t **pp_xing, int *pi_xing, uint16_t i_default )
{
    if( *pi_xing < 2 )
        return i_default;

    uint16_t v = GetWBE( *pp_xing );

    MpgaXingSkip( pp_xing, pi_xing, 2 );

    return v;
}

static double MpgaXingLameConvertGain( uint16_t x )
{
    double gain = (x & 0x1FF) / 10.0;

    return x & 0x200 ? -gain : gain;
}

static double MpgaXingLameConvertPeak( uint32_t x )
{
    return x / 8388608.0; /* pow(2, 23) */
}

860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
static uint64_t SeekByMlltTable( demux_t *p_demux, mtime_t *pi_time )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    sync_table_ctx_t *p_cur = &p_sys->mllt.current;

    /* reset or init context */
    if( *pi_time < p_cur->i_time || !p_cur->br.p )
    {
        p_cur->i_time = 0;
        p_cur->i_pos = 0;
        bs_init(&p_cur->br, p_sys->mllt.p_bits, p_sys->mllt.i_bits);
    }

    while(bs_remain(&p_cur->br) >= p_sys->mllt.i_bits_per_bytes_dev + p_sys->mllt.i_bits_per_ms_dev)
    {
        const uint32_t i_bytesdev = bs_read(&p_cur->br, p_sys->mllt.i_bits_per_bytes_dev);
        const uint32_t i_msdev = bs_read(&p_cur->br, p_sys->mllt.i_bits_per_ms_dev);
        const mtime_t i_deltatime = (p_sys->mllt.i_ms_btw_refs + i_msdev) * INT64_C(1000);
        if( p_cur->i_time + i_deltatime > *pi_time )
            break;
        p_cur->i_time += i_deltatime;
        p_cur->i_pos += p_sys->mllt.i_bytes_btw_refs + i_bytesdev;
    }
    *pi_time = p_cur->i_time;
    return p_cur->i_pos;
}

887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
static int ID3TAG_Parse_Handler( uint32_t i_tag, const uint8_t *p_payload, size_t i_payload, void *p_priv )
{
    demux_t *p_demux = (demux_t *) p_priv;
    demux_sys_t *p_sys = p_demux->p_sys;

    if( i_tag == VLC_FOURCC('M', 'L', 'L', 'T') )
    {
        if( i_payload > 20 )
        {
            p_sys->mllt.i_frames_btw_refs = GetWBE(p_payload);
            p_sys->mllt.i_bytes_btw_refs = GetDWBE(&p_payload[1]) & 0x00FFFFFF;
            p_sys->mllt.i_ms_btw_refs = GetDWBE(&p_payload[4]) & 0x00FFFFFF;
            if( !p_sys->mllt.i_frames_btw_refs || !p_sys->mllt.i_bytes_btw_refs ||
                    !p_sys->mllt.i_ms_btw_refs ||
                    p_payload[8] > 31 || p_payload[9] > 31 || /* bits length sanity check */
                    ((p_payload[8] + p_payload[9]) % 4) || p_payload[8] + p_payload[9] < 4 )
                return VLC_EGENERIC;
            p_sys->mllt.i_bits_per_bytes_dev = p_payload[8];
            p_sys->mllt.i_bits_per_ms_dev = p_payload[9];
            p_sys->mllt.p_bits = malloc(i_payload - 10);
            if( likely(p_sys->mllt.p_bits) )
            {
                p_sys->mllt.i_bits = i_payload - 10;
                memcpy(p_sys->mllt.p_bits, &p_payload[10], p_sys->mllt.i_bits);
                msg_Dbg(p_demux, "read MLLT sync table with %zu entries",
                        (p_sys->mllt.i_bits * 8) / (p_sys->mllt.i_bits_per_bytes_dev + p_sys->mllt.i_bits_per_ms_dev) );
            }
        }
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}

921
922
static int ID3Parse( demux_t *p_demux, uint64_t i_stream_offset,
                     int (*pf_callback)(uint32_t, const uint8_t *, size_t, void *) )
923
924
925
926
{
    const uint8_t *p_peek;

    bool b_canseek;
927
    if( i_stream_offset < 10 ||
928
929
930
931
932
        vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek ) != VLC_SUCCESS ||
        !b_canseek ||
        vlc_stream_Seek( p_demux->s, 0 ) != VLC_SUCCESS )
        return VLC_EGENERIC;

933
934
    int64_t i_peek = vlc_stream_Peek( p_demux->s, &p_peek, i_stream_offset );
    if( i_peek > 0 && (uint64_t) i_peek == i_stream_offset )
935
    {
936
937
938
939
940
941
942
943
944
        while( i_peek > 0 )
        {
            size_t i_forward =  ID3TAG_Parse( p_peek, i_peek,
                                              pf_callback, (void *) p_demux );
            if(i_forward == 0)
                break;
            p_peek += i_forward;
            i_peek -= i_forward;
        }
945
946
    }

947
    return vlc_stream_Seek( p_demux->s, i_stream_offset );
948
949
}

950
951
952
953
954
955
956
957
958
959
static int MpgaInit( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;

    const uint8_t *p_peek;
    int i_peek;

    /* */
    p_sys->i_packet_size = 1024;

960
    ID3Parse( p_demux, p_sys->i_stream_offset, ID3TAG_Parse_Handler );
961

962
    /* Load a potential xing header */
963
    i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 4 + 1024 );
964
965
966
967
    if( i_peek < 4 + 21 )
        return VLC_SUCCESS;

    const uint32_t header = GetDWBE( p_peek );
968
    if( !MpgaCheckSync( p_peek ) )
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
        return VLC_SUCCESS;

    /* Xing header */
    const uint8_t *p_xing = p_peek;
    int i_xing = i_peek;
    int i_skip;

    if( MPGA_VERSION( header ) == 0 )
        i_skip = MPGA_MODE( header ) != 3 ? 36 : 21;
    else
        i_skip = MPGA_MODE( header ) != 3 ? 21 : 13;

    if( i_skip + 8 >= i_xing || memcmp( &p_xing[i_skip], "Xing", 4 ) )
        return VLC_SUCCESS;

    const uint32_t i_flags = GetDWBE( &p_xing[i_skip+4] );

    MpgaXingSkip( &p_xing, &i_xing, i_skip + 8 );

    if( i_flags&0x01 )
        p_sys->xing.i_frames = MpgaXingGetDWBE( &p_xing, &i_xing, 0 );
    if( i_flags&0x02 )
        p_sys->xing.i_bytes = MpgaXingGetDWBE( &p_xing, &i_xing, 0 );
    if( i_flags&0x04 ) /* TODO Support XING TOC to improve seeking accuracy */
        MpgaXingSkip( &p_xing, &i_xing, 100 );
    if( i_flags&0x08 )
    {
        /* FIXME: doesn't return the right bitrage average, at least
           with some MP3's */
        p_sys->xing.i_bitrate_avg = MpgaXingGetDWBE( &p_xing, &i_xing, 0 );
        msg_Dbg( p_demux, "xing vbr value present (%d)",
                 p_sys->xing.i_bitrate_avg );
    }

    if( p_sys->xing.i_frames > 0 && p_sys->xing.i_bytes > 0 )
    {
        p_sys->xing.i_frame_samples = MpgaGetFrameSamples( header );
        msg_Dbg( p_demux, "xing frames&bytes value present "
                 "(%d bytes, %d frames, %d samples/frame)",
                 p_sys->xing.i_bytes, p_sys->xing.i_frames,
                 p_sys->xing.i_frame_samples );
    }
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036

    if( i_xing >= 20 && memcmp( p_xing, "LAME", 4 ) == 0)
    {
        p_sys->xing.b_lame = true;
        lame_extra_t *p_lame = &p_sys->xing.lame;

        memcpy( p_lame->psz_version, p_xing, 9 );
        p_lame->psz_version[9] = '\0';

        MpgaXingSkip( &p_xing, &i_xing, 9 );
        MpgaXingSkip( &p_xing, &i_xing, 1 ); /* rev_method */

        p_lame->i_lowpass = (*p_xing) * 100;
        MpgaXingSkip( &p_xing, &i_xing, 1 );

        uint32_t peak  = MpgaXingGetDWBE( &p_xing, &i_xing, 0 );
        uint16_t track = MpgaXingGetWBE( &p_xing, &i_xing, 0 );
        uint16_t album = MpgaXingGetWBE( &p_xing, &i_xing, 0 );

        p_lame->pf_replay_peak[AUDIO_REPLAY_GAIN_TRACK] = (float) MpgaXingLameConvertPeak( peak );
        p_lame->pf_replay_gain[AUDIO_REPLAY_GAIN_TRACK] = (float) MpgaXingLameConvertGain( track );
        p_lame->pf_replay_gain[AUDIO_REPLAY_GAIN_ALBUM] = (float) MpgaXingLameConvertGain( album );

        MpgaXingSkip( &p_xing, &i_xing, 1 ); /* flags */
    }

1037
1038
1039
    return VLC_SUCCESS;
}

1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
/*****************************************************************************
 * AAC
 *****************************************************************************/
static int AacProbe( demux_t *p_demux, int64_t *pi_offset )
{
    bool   b_forced;
    bool   b_forced_demux;

    int64_t i_offset;
    const uint8_t *p_peek;

    b_forced = demux_IsPathExtension( p_demux, ".aac" ) ||
               demux_IsPathExtension( p_demux, ".aacp" );
    b_forced_demux = demux_IsForced( p_demux, "m4a" ) ||
                     demux_IsForced( p_demux, "aac" ) ||
                     demux_IsForced( p_demux, "mp4a" );

    if( !b_forced_demux && !b_forced )
        return VLC_EGENERIC;

1060
    i_offset = vlc_stream_Tell( p_demux->s );
1061
1062

    /* peek the begining (10 is for adts header) */
1063
    if( vlc_stream_Peek( p_demux->s, &p_peek, 10 ) < 10 )
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
    {
        msg_Err( p_demux, "cannot peek" );
        return VLC_EGENERIC;
    }
    if( !strncmp( (char *)p_peek, "ADIF", 4 ) )
    {
        msg_Err( p_demux, "ADIF file. Not yet supported. (Please report)" );
        return VLC_EGENERIC;
    }

    *pi_offset = i_offset;
    return VLC_SUCCESS;
}
static int AacInit( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;

    p_sys->i_packet_size = 4096;
1082
    p_sys->i_original = VLC_FOURCC('H','E','A','D');
1083
1084
1085
1086

    return VLC_SUCCESS;
}

1087

1088
1089
1090
/*****************************************************************************
 * A52
 *****************************************************************************/
1091
static int A52CheckSync( const uint8_t *p_peek, bool *p_big_endian, int *pi_samples, bool b_eac3 )
1092
{
1093
1094
    vlc_a52_header_t header;
    uint8_t p_tmp[VLC_A52_HEADER_SIZE];
1095

1096
1097
    *p_big_endian =  p_peek[0] == 0x0b && p_peek[1] == 0x77;
    if( !*p_big_endian )
1098
    {
1099
1100
        swab( p_peek, p_tmp, VLC_A52_HEADER_SIZE );
        p_peek = p_tmp;
1101
1102
    }

1103
1104
1105
1106
1107
    if( vlc_a52_header_Parse( &header, p_peek, VLC_A52_HEADER_SIZE ) )
        return VLC_EGENERIC;

    if( !header.b_eac3 != !b_eac3 )
        return VLC_EGENERIC;
1108
1109
    if( pi_samples )
        *pi_samples = header.i_samples;
1110
    return header.i_size;
1111
}
1112
static int EA52CheckSyncProbe( const uint8_t *p_peek, int *pi_samples )
1113
1114
{
    bool b_dummy;
1115
    return A52CheckSync( p_peek, &b_dummy, pi_samples, true );
1116
1117
1118
1119
1120
}

static int EA52Probe( demux_t *p_demux, int64_t *pi_offset )
{
    const char *ppsz_name[] = { "eac3", NULL };
1121
    const int pi_wav[] = { WAVE_FORMAT_PCM, WAVE_FORMAT_A52, WAVE_FORMAT_UNKNOWN };
1122

1123
1124
    return GenericProbe( p_demux, pi_offset, ppsz_name, EA52CheckSyncProbe,
                         VLC_A52_HEADER_SIZE, pi_wav, GenericFormatCheck );
1125
1126
}

1127
static int A52CheckSyncProbe( const uint8_t *p_peek, int *pi_samples )
1128
1129
{
    bool b_dummy;
1130
    return A52CheckSync( p_peek, &b_dummy, pi_samples, false );
1131
1132
1133
1134
1135
}

static int A52Probe( demux_t *p_demux, int64_t *pi_offset )
{
    const char *ppsz_name[] = { "a52", "ac3", NULL };
1136
    const int pi_wav[] = { WAVE_FORMAT_PCM, WAVE_FORMAT_A52, WAVE_FORMAT_UNKNOWN };
1137

1138
1139
    return GenericProbe( p_demux, pi_offset, ppsz_name, A52CheckSyncProbe,
                         VLC_A52_HEADER_SIZE, pi_wav, GenericFormatCheck );
1140
1141
}

1142
1143
1144
1145
1146
1147
1148
1149
1150
static int A52Init( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;

    p_sys->b_big_endian = false;
    p_sys->i_packet_size = 1024;

    const uint8_t *p_peek;

1151
    /* peek the begining */
1152
    if( vlc_stream_Peek( p_demux->s, &p_peek, VLC_A52_HEADER_SIZE ) >= VLC_A52_HEADER_SIZE )
1153
    {
1154
        A52CheckSync( p_peek, &p_sys->b_big_endian, NULL, true );
1155
1156
1157
1158
    }
    return VLC_SUCCESS;
}

1159
1160
1161
/*****************************************************************************
 * DTS
 *****************************************************************************/
1162
static int DtsCheckSync( const uint8_t *p_peek, int *pi_samples )
1163
{
1164
1165
    VLC_UNUSED(pi_samples);

1166
    vlc_dts_header_t dts;
1167
    if( vlc_dts_header_Parse( &dts, p_peek, VLC_DTS_HEADER_SIZE ) == VLC_SUCCESS
1168
     && dts.i_frame_size > 0 && dts.i_frame_size <= 8192 )
Thomas Guillem's avatar
Thomas Guillem committed
1169
1170
1171
    {
        if( pi_samples )
            *pi_samples = dts.i_frame_length;
1172
        return dts.i_frame_size;