dts.c 25.3 KB
Newer Older
Jon Lech Johansen's avatar
Jon Lech Johansen committed
1
/*****************************************************************************
gbazin's avatar
   
gbazin committed
2
 * dts.c: parse DTS audio sync info and packetize the stream
Jon Lech Johansen's avatar
Jon Lech Johansen committed
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2003-2009 the VideoLAN team
5
 * $Id$
Jon Lech Johansen's avatar
Jon Lech Johansen committed
6
7
 *
 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
gbazin's avatar
   
gbazin committed
8
 *          Gildas Bazin <gbazin@netcourrier.com>
Jon Lech Johansen's avatar
Jon Lech Johansen committed
9
10
11
12
13
14
15
16
17
18
19
20
21
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (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
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Jon Lech Johansen's avatar
Jon Lech Johansen committed
23
24
25
26
27
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
28

29
30
31
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
32
#include <assert.h>
33

34
#include <vlc_common.h>
35
#include <vlc_plugin.h>
zorglub's avatar
zorglub committed
36
37
38
#include <vlc_codec.h>
#include <vlc_aout.h>
#include <vlc_block_helper.h>
39
#include <vlc_bits.h>
Jon Lech Johansen's avatar
Jon Lech Johansen committed
40

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  OpenDecoder   ( vlc_object_t * );
static int  OpenPacketizer( vlc_object_t * );
static void CloseCommon   ( vlc_object_t * );

vlc_module_begin ()
    set_description( N_("DTS parser") )
    set_capability( "decoder", 100 )
    set_callbacks( OpenDecoder, CloseCommon )

    add_submodule ()
    set_description( N_("DTS audio packetizer") )
    set_capability( "packetizer", 10 )
    set_callbacks( OpenPacketizer, CloseCommon )
vlc_module_end ()
gbazin's avatar
   
gbazin committed
58

Jon Lech Johansen's avatar
Jon Lech Johansen committed
59
/*****************************************************************************
gbazin's avatar
   
gbazin committed
60
 * decoder_sys_t : decoder descriptor
Jon Lech Johansen's avatar
Jon Lech Johansen committed
61
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
62
struct decoder_sys_t
Jon Lech Johansen's avatar
Jon Lech Johansen committed
63
{
gbazin's avatar
   
gbazin committed
64
    /* Module mode */
65
    bool b_packetizer;
gbazin's avatar
   
gbazin committed
66

Jon Lech Johansen's avatar
Jon Lech Johansen committed
67
    /*
gbazin's avatar
   
gbazin committed
68
     * Input properties
Jon Lech Johansen's avatar
Jon Lech Johansen committed
69
     */
gbazin's avatar
   
gbazin committed
70
    int i_state;
gbazin's avatar
   
gbazin committed
71

gbazin's avatar
   
gbazin committed
72
    block_bytestream_t bytestream;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
73
74

    /*
gbazin's avatar
   
gbazin committed
75
     * Common properties
Jon Lech Johansen's avatar
Jon Lech Johansen committed
76
     */
77
    date_t  end_date;
gbazin's avatar
   
gbazin committed
78
79
80

    mtime_t i_pts;

81
    bool         b_dts_hd;  /* Is the current frame a DTS HD one */
82
83
84
85
86
87
    unsigned int i_bit_rate;
    unsigned int i_frame_size;
    unsigned int i_frame_length;
    unsigned int i_rate;
    unsigned int i_channels;
    unsigned int i_channels_conf;
gbazin's avatar
   
gbazin committed
88
89
90
91
92
93
94
};

enum {

    STATE_NOSYNC,
    STATE_SYNC,
    STATE_HEADER,
gbazin's avatar
   
gbazin committed
95
96
97
    STATE_NEXT_SYNC,
    STATE_GET_DATA,
    STATE_SEND_DATA
gbazin's avatar
   
gbazin committed
98
};
Jon Lech Johansen's avatar
Jon Lech Johansen committed
99

100
101
#define DTS_HEADER_SIZE 14

Jon Lech Johansen's avatar
Jon Lech Johansen committed
102
103
104
/****************************************************************************
 * Local prototypes
 ****************************************************************************/
105
106
static int OpenCommon( vlc_object_t *, bool b_packetizer );
static void *DecodeBlock( decoder_t *, block_t ** );
Jon Lech Johansen's avatar
Jon Lech Johansen committed
107

gbazin's avatar
   
gbazin committed
108
static inline int SyncCode( const uint8_t * );
109
static int  SyncInfo( const uint8_t *, bool *, unsigned int *, unsigned int *,
110
                      unsigned int *, unsigned int *, unsigned int * );
Jon Lech Johansen's avatar
Jon Lech Johansen committed
111

gbazin's avatar
   
gbazin committed
112
113
114
static uint8_t       *GetOutBuffer ( decoder_t *, void ** );
static aout_buffer_t *GetAoutBuffer( decoder_t * );
static block_t       *GetSoutBuffer( decoder_t * );
Jon Lech Johansen's avatar
Jon Lech Johansen committed
115
116

/*****************************************************************************
117
 * OpenDecoder: probe the decoder
Jon Lech Johansen's avatar
Jon Lech Johansen committed
118
 *****************************************************************************/
119
120
121
122
123
static int OpenDecoder( vlc_object_t *p_this )
{
    /* HACK: Don't use this codec if we don't have an dts audio filter */
    if( !module_exists( "dtstofloat32" ) )
        return VLC_EGENERIC;
124

125
126
    return OpenCommon( p_this, false );
}
Jon Lech Johansen's avatar
Jon Lech Johansen committed
127
128

/*****************************************************************************
129
 * OpenPacketizer: probe the packetizer
Jon Lech Johansen's avatar
Jon Lech Johansen committed
130
 *****************************************************************************/
131
132
133
134
135
136
137
138
139
static int OpenPacketizer( vlc_object_t *p_this )
{
    return OpenCommon( p_this, true );
}

/*****************************************************************************
 * OpenCommon:
 *****************************************************************************/
static int OpenCommon( vlc_object_t *p_this, bool b_packetizer )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
140
{
gbazin's avatar
   
gbazin committed
141
    decoder_t *p_dec = (decoder_t*)p_this;
gbazin's avatar
   
gbazin committed
142
    decoder_sys_t *p_sys;
gbazin's avatar
   
gbazin committed
143

144
    if( p_dec->fmt_in.i_codec != VLC_CODEC_DTS )
gbazin's avatar
   
gbazin committed
145
146
147
        return VLC_EGENERIC;

    /* Allocate the memory needed to store the decoder's structure */
148
    if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
149
        return VLC_ENOMEM;
gbazin's avatar
   
gbazin committed
150
151

    /* Misc init */
152
    p_sys->b_packetizer = b_packetizer;
gbazin's avatar
   
gbazin committed
153
    p_sys->i_state = STATE_NOSYNC;
154
    date_Set( &p_sys->end_date, 0 );
155
    p_sys->b_dts_hd = false;
156
    p_sys->i_pts = VLC_TS_INVALID;
gbazin's avatar
   
gbazin committed
157

158
    p_sys->bytestream = block_BytestreamInit();
gbazin's avatar
   
gbazin committed
159
160
161

    /* Set output properties */
    p_dec->fmt_out.i_cat = AUDIO_ES;
162
    p_dec->fmt_out.i_codec = VLC_CODEC_DTS;
163
    p_dec->fmt_out.audio.i_rate = 0; /* So end_date gets initialized */
gbazin's avatar
   
gbazin committed
164
165
166
167
168
169

    /* Set callback */
    p_dec->pf_decode_audio = (aout_buffer_t *(*)(decoder_t *, block_t **))
        DecodeBlock;
    p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
        DecodeBlock;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
170
171
172
173

    return VLC_SUCCESS;
}

gbazin's avatar
   
gbazin committed
174
/****************************************************************************
gbazin's avatar
   
gbazin committed
175
 * DecodeBlock: the whole thing
gbazin's avatar
   
gbazin committed
176
 ****************************************************************************/
gbazin's avatar
   
gbazin committed
177
static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
gbazin's avatar
   
gbazin committed
178
179
{
    decoder_sys_t *p_sys = p_dec->p_sys;
gbazin's avatar
   
gbazin committed
180
181
182
    uint8_t p_header[DTS_HEADER_SIZE];
    uint8_t *p_buf;
    void *p_out_buffer;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
183

184
185
    if( !pp_block || !*pp_block )
        return NULL;
gbazin's avatar
   
gbazin committed
186

187
    if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
gbazin's avatar
   
gbazin committed
188
    {
189
190
191
        if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED )
        {
            p_sys->i_state = STATE_NOSYNC;
192
            block_BytestreamEmpty( &p_sys->bytestream );
193
        }
194
        date_Set( &p_sys->end_date, 0 );
gbazin's avatar
   
gbazin committed
195
196
197
198
        block_Release( *pp_block );
        return NULL;
    }

199
    if( !date_Get( &p_sys->end_date ) && (*pp_block)->i_pts <= VLC_TS_INVALID )
gbazin's avatar
   
gbazin committed
200
    {
201
202
203
        /* We've just started the stream, wait for the first PTS. */
        block_Release( *pp_block );
        return NULL;
gbazin's avatar
   
gbazin committed
204
205
206
207
208
    }

    block_BytestreamPush( &p_sys->bytestream, *pp_block );

    while( 1 )
gbazin's avatar
   
gbazin committed
209
210
    {
        switch( p_sys->i_state )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
211
        {
gbazin's avatar
   
gbazin committed
212
        case STATE_NOSYNC:
gbazin's avatar
   
gbazin committed
213
214
            /* Look for sync code - should be 0x7ffe8001 */
            while( block_PeekBytes( &p_sys->bytestream, p_header, 6 )
gbazin's avatar
   
gbazin committed
215
                   == VLC_SUCCESS )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
216
            {
gbazin's avatar
   
gbazin committed
217
                if( SyncCode( p_header ) == VLC_SUCCESS )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
218
                {
gbazin's avatar
   
gbazin committed
219
                    p_sys->i_state = STATE_SYNC;
gbazin's avatar
   
gbazin committed
220
                    break;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
221
                }
gbazin's avatar
   
gbazin committed
222
223
224
225
226
                block_SkipByte( &p_sys->bytestream );
            }
            if( p_sys->i_state != STATE_SYNC )
            {
                block_BytestreamFlush( &p_sys->bytestream );
gbazin's avatar
   
gbazin committed
227

gbazin's avatar
   
gbazin committed
228
229
                /* Need more data */
                return NULL;
gbazin's avatar
   
gbazin committed
230
231
232
233
            }

        case STATE_SYNC:
            /* New frame, set the Presentation Time Stamp */
gbazin's avatar
   
gbazin committed
234
            p_sys->i_pts = p_sys->bytestream.p_block->i_pts;
235
            if( p_sys->i_pts > VLC_TS_INVALID &&
236
                p_sys->i_pts != date_Get( &p_sys->end_date ) )
gbazin's avatar
   
gbazin committed
237
            {
238
                date_Set( &p_sys->end_date, p_sys->i_pts );
Jon Lech Johansen's avatar
Jon Lech Johansen committed
239
            }
gbazin's avatar
   
gbazin committed
240
            p_sys->i_state = STATE_HEADER;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
241

gbazin's avatar
   
gbazin committed
242
243
        case STATE_HEADER:
            /* Get DTS frame header (DTS_HEADER_SIZE bytes) */
gbazin's avatar
   
gbazin committed
244
245
            if( block_PeekBytes( &p_sys->bytestream, p_header,
                                 DTS_HEADER_SIZE ) != VLC_SUCCESS )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
246
            {
gbazin's avatar
   
gbazin committed
247
248
                /* Need more data */
                return NULL;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
249
250
            }

gbazin's avatar
   
gbazin committed
251
252
            /* Check if frame is valid and get frame info */
            p_sys->i_frame_size = SyncInfo( p_header,
253
                                            &p_sys->b_dts_hd,
gbazin's avatar
   
gbazin committed
254
255
256
257
258
259
260
261
262
263
                                            &p_sys->i_channels,
                                            &p_sys->i_channels_conf,
                                            &p_sys->i_rate,
                                            &p_sys->i_bit_rate,
                                            &p_sys->i_frame_length );
            if( !p_sys->i_frame_size )
            {
                msg_Dbg( p_dec, "emulated sync word" );
                block_SkipByte( &p_sys->bytestream );
                p_sys->i_state = STATE_NOSYNC;
gbazin's avatar
   
gbazin committed
264
                break;
gbazin's avatar
   
gbazin committed
265
266
267
268
269
270
            }
            p_sys->i_state = STATE_NEXT_SYNC;

        case STATE_NEXT_SYNC:
            /* TODO: If pp_block == NULL, flush the buffer without checking the
             * next sync word */
gbazin's avatar
   
gbazin committed
271

gbazin's avatar
   
gbazin committed
272
273
            /* Check if next expected frame contains the sync word */
            if( block_PeekOffsetBytes( &p_sys->bytestream,
gbazin's avatar
   
gbazin committed
274
                                       p_sys->i_frame_size, p_header, 6 )
gbazin's avatar
   
gbazin committed
275
                != VLC_SUCCESS )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
276
            {
gbazin's avatar
   
gbazin committed
277
278
                /* Need more data */
                return NULL;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
279
280
            }

281
282
283
284
285
286
287
288
            if( p_sys->b_packetizer &&
                p_header[0] == 0 && p_header[1] == 0 )
            {
                /* DTS wav files and audio CD's use stuffing */
                p_sys->i_state = STATE_SEND_DATA;
                break;
            }

gbazin's avatar
   
gbazin committed
289
            if( SyncCode( p_header ) != VLC_SUCCESS )
gbazin's avatar
   
gbazin committed
290
            {
gbazin's avatar
   
gbazin committed
291
                msg_Dbg( p_dec, "emulated sync word "
bigben's avatar
bigben committed
292
                         "(no sync on following frame): %2.2x%2.2x%2.2x%2.2x",
gbazin's avatar
   
gbazin committed
293
294
                         (int)p_header[0], (int)p_header[1],
                         (int)p_header[2], (int)p_header[3] );
gbazin's avatar
   
gbazin committed
295
                p_sys->i_state = STATE_NOSYNC;
gbazin's avatar
   
gbazin committed
296
                block_SkipByte( &p_sys->bytestream );
gbazin's avatar
   
gbazin committed
297
298
                break;
            }
gbazin's avatar
   
gbazin committed
299
            p_sys->i_state = STATE_SEND_DATA;
gbazin's avatar
   
gbazin committed
300
301
            break;

gbazin's avatar
   
gbazin committed
302
303
304
305
306
        case STATE_GET_DATA:
            /* Make sure we have enough data.
             * (Not useful if we went through NEXT_SYNC) */
            if( block_WaitBytes( &p_sys->bytestream,
                                 p_sys->i_frame_size ) != VLC_SUCCESS )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
307
            {
gbazin's avatar
   
gbazin committed
308
309
                /* Need more data */
                return NULL;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
310
            }
gbazin's avatar
   
gbazin committed
311
            p_sys->i_state = STATE_SEND_DATA;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
312

gbazin's avatar
   
gbazin committed
313
        case STATE_SEND_DATA:
314
315
316
317
318
319
320
321
            if( p_sys->b_dts_hd  )
            {
                /* Ignore DTS-HD */
                block_SkipBytes( &p_sys->bytestream, p_sys->i_frame_size );
                p_sys->i_state = STATE_NOSYNC;
                break;
            }

gbazin's avatar
   
gbazin committed
322
323
            if( !(p_buf = GetOutBuffer( p_dec, &p_out_buffer )) )
            {
324
                //p_dec->b_error = true;
gbazin's avatar
   
gbazin committed
325
326
                return NULL;
            }
gbazin's avatar
   
gbazin committed
327

gbazin's avatar
   
gbazin committed
328
329
330
            /* Copy the whole frame into the buffer. When we reach this point
             * we already know we have enough data available. */
            block_GetBytes( &p_sys->bytestream, p_buf, p_sys->i_frame_size );
gbazin's avatar
   
gbazin committed
331

gbazin's avatar
   
gbazin committed
332
333
            /* Make sure we don't reuse the same pts twice */
            if( p_sys->i_pts == p_sys->bytestream.p_block->i_pts )
334
                p_sys->i_pts = p_sys->bytestream.p_block->i_pts = VLC_TS_INVALID;
gbazin's avatar
   
gbazin committed
335

gbazin's avatar
   
gbazin committed
336
            p_sys->i_state = STATE_NOSYNC;
gbazin's avatar
   
gbazin committed
337

gbazin's avatar
   
gbazin committed
338
339
340
            /* So p_block doesn't get re-added several times */
            *pp_block = block_BytestreamPop( &p_sys->bytestream );

gbazin's avatar
   
gbazin committed
341
            return p_out_buffer;
gbazin's avatar
   
gbazin committed
342
343
344
        }
    }

gbazin's avatar
   
gbazin committed
345
    return NULL;
gbazin's avatar
   
gbazin committed
346
347
348
}

/*****************************************************************************
349
 * CloseCommon: clean up the decoder
gbazin's avatar
   
gbazin committed
350
 *****************************************************************************/
351
static void CloseCommon( vlc_object_t *p_this )
gbazin's avatar
   
gbazin committed
352
{
gbazin's avatar
   
gbazin committed
353
    decoder_t *p_dec = (decoder_t*)p_this;
gbazin's avatar
   
gbazin committed
354
355
    decoder_sys_t *p_sys = p_dec->p_sys;

gbazin's avatar
   
gbazin committed
356
    block_BytestreamRelease( &p_sys->bytestream );
gbazin's avatar
   
gbazin committed
357

gbazin's avatar
   
gbazin committed
358
    free( p_sys );
gbazin's avatar
   
gbazin committed
359
360
361
}

/*****************************************************************************
gbazin's avatar
   
gbazin committed
362
 * GetOutBuffer:
gbazin's avatar
   
gbazin committed
363
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
364
static uint8_t *GetOutBuffer( decoder_t *p_dec, void **pp_out_buffer )
gbazin's avatar
   
gbazin committed
365
366
{
    decoder_sys_t *p_sys = p_dec->p_sys;
gbazin's avatar
   
gbazin committed
367
    uint8_t *p_buf;
gbazin's avatar
   
gbazin committed
368

gbazin's avatar
   
gbazin committed
369
    if( p_dec->fmt_out.audio.i_rate != p_sys->i_rate )
gbazin's avatar
   
gbazin committed
370
    {
gbazin's avatar
   
gbazin committed
371
372
        msg_Info( p_dec, "DTS channels:%d samplerate:%d bitrate:%d",
                  p_sys->i_channels, p_sys->i_rate, p_sys->i_bit_rate );
gbazin's avatar
   
gbazin committed
373

374
375
        date_Init( &p_sys->end_date, p_sys->i_rate, 1 );
        date_Set( &p_sys->end_date, p_sys->i_pts );
gbazin's avatar
   
gbazin committed
376
377
    }

gbazin's avatar
   
gbazin committed
378
379
    p_dec->fmt_out.audio.i_rate     = p_sys->i_rate;
    p_dec->fmt_out.audio.i_channels = p_sys->i_channels;
gbazin's avatar
   
gbazin committed
380
381
382
    /* Hack for DTS S/PDIF filter which needs to pad the DTS frames */
    p_dec->fmt_out.audio.i_bytes_per_frame =
        __MAX( p_sys->i_frame_size, p_sys->i_frame_length * 4 );
gbazin's avatar
   
gbazin committed
383
384
385
386
387
    p_dec->fmt_out.audio.i_frame_length = p_sys->i_frame_length;

    p_dec->fmt_out.audio.i_original_channels = p_sys->i_channels_conf;
    p_dec->fmt_out.audio.i_physical_channels =
        p_sys->i_channels_conf & AOUT_CHAN_PHYSMASK;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
388

gbazin's avatar
   
gbazin committed
389
390
    p_dec->fmt_out.i_bitrate = p_sys->i_bit_rate;

gbazin's avatar
   
gbazin committed
391
    if( p_sys->b_packetizer )
gbazin's avatar
   
gbazin committed
392
    {
gbazin's avatar
   
gbazin committed
393
394
395
        block_t *p_sout_buffer = GetSoutBuffer( p_dec );
        p_buf = p_sout_buffer ? p_sout_buffer->p_buffer : NULL;
        *pp_out_buffer = p_sout_buffer;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
396
    }
gbazin's avatar
   
gbazin committed
397
    else
Jon Lech Johansen's avatar
Jon Lech Johansen committed
398
    {
gbazin's avatar
   
gbazin committed
399
400
401
        aout_buffer_t *p_aout_buffer = GetAoutBuffer( p_dec );
        p_buf = p_aout_buffer ? p_aout_buffer->p_buffer : NULL;
        *pp_out_buffer = p_aout_buffer;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
402
403
    }

gbazin's avatar
   
gbazin committed
404
    return p_buf;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
405
406
407
}

/*****************************************************************************
gbazin's avatar
   
gbazin committed
408
 * GetAoutBuffer:
Jon Lech Johansen's avatar
Jon Lech Johansen committed
409
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
410
static aout_buffer_t *GetAoutBuffer( decoder_t *p_dec )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
411
{
gbazin's avatar
   
gbazin committed
412
    decoder_sys_t *p_sys = p_dec->p_sys;
gbazin's avatar
   
gbazin committed
413
    aout_buffer_t *p_buf;
gbazin's avatar
   
gbazin committed
414

gbazin's avatar
   
gbazin committed
415
416
    /* Hack for DTS S/PDIF filter which needs to send 3 frames at a time
     * (plus a few header bytes) */
417
    p_buf = decoder_NewAudioBuffer( p_dec, p_sys->i_frame_length * 4 );
gbazin's avatar
   
gbazin committed
418
    if( p_buf == NULL ) return NULL;
gbazin's avatar
   
gbazin committed
419
    p_buf->i_nb_samples = p_sys->i_frame_length;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
420
    p_buf->i_buffer = p_sys->i_frame_size;
gbazin's avatar
   
gbazin committed
421

422
    p_buf->i_pts = date_Get( &p_sys->end_date );
423
424
    p_buf->i_length = date_Increment( &p_sys->end_date, p_sys->i_frame_length )
                      - p_buf->i_pts;
gbazin's avatar
   
gbazin committed
425

gbazin's avatar
   
gbazin committed
426
    return p_buf;
gbazin's avatar
   
gbazin committed
427
428
429
}

/*****************************************************************************
gbazin's avatar
   
gbazin committed
430
 * GetSoutBuffer:
gbazin's avatar
   
gbazin committed
431
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
432
static block_t *GetSoutBuffer( decoder_t *p_dec )
gbazin's avatar
   
gbazin committed
433
434
{
    decoder_sys_t *p_sys = p_dec->p_sys;
gbazin's avatar
   
gbazin committed
435
    block_t *p_block;
gbazin's avatar
   
gbazin committed
436

gbazin's avatar
   
gbazin committed
437
438
    p_block = block_New( p_dec, p_sys->i_frame_size );
    if( p_block == NULL ) return NULL;
gbazin's avatar
   
gbazin committed
439

440
    p_block->i_pts = p_block->i_dts = date_Get( &p_sys->end_date );
gbazin's avatar
   
gbazin committed
441

442
    p_block->i_length = date_Increment( &p_sys->end_date,
gbazin's avatar
   
gbazin committed
443
444
445
        p_sys->i_frame_length ) - p_block->i_pts;

    return p_block;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
446
447
448
449
450
}

/*****************************************************************************
 * SyncInfo: parse DTS sync info
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
451
452
static const unsigned int ppi_dts_samplerate[] =
{
gbazin's avatar
   
gbazin committed
453
    0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0,
gbazin's avatar
   
gbazin committed
454
455
456
457
458
459
460
461
462
463
    12000, 24000, 48000, 96000, 192000
};

static const unsigned int ppi_dts_bitrate[] =
{
    32000, 56000, 64000, 96000, 112000, 128000,
    192000, 224000, 256000, 320000, 384000,
    448000, 512000, 576000, 640000, 768000,
    896000, 1024000, 1152000, 1280000, 1344000,
    1408000, 1411200, 1472000, 1536000, 1920000,
gbazin's avatar
   
gbazin committed
464
    2048000, 3072000, 3840000, 1/*open*/, 2/*variable*/, 3/*lossless*/
gbazin's avatar
   
gbazin committed
465
466
467
468
469
};

static int SyncInfo16be( const uint8_t *p_buf,
                         unsigned int *pi_audio_mode,
                         unsigned int *pi_sample_rate,
470
                         unsigned int *pi_bit_rate,
gbazin's avatar
   
gbazin committed
471
                         unsigned int *pi_frame_length )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
472
473
{
    unsigned int i_frame_size;
gbazin's avatar
   
gbazin committed
474
    unsigned int i_lfe;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
475

gbazin's avatar
   
gbazin committed
476
477
478
479
480
481
482
483
    *pi_frame_length = (p_buf[4] & 0x01) << 6 | (p_buf[5] >> 2);
    i_frame_size = (p_buf[5] & 0x03) << 12 | (p_buf[6] << 4) |
                   (p_buf[7] >> 4);

    *pi_audio_mode = (p_buf[7] & 0x0f) << 2 | (p_buf[8] >> 6);
    *pi_sample_rate = (p_buf[8] >> 2) & 0x0f;
    *pi_bit_rate = (p_buf[8] & 0x03) << 3 | ((p_buf[9] >> 5) & 0x07);

gbazin's avatar
   
gbazin committed
484
485
486
    i_lfe = (p_buf[10] >> 1) & 0x03;
    if( i_lfe ) *pi_audio_mode |= 0x10000;

gbazin's avatar
   
gbazin committed
487
488
489
    return i_frame_size + 1;
}

gbazin's avatar
   
gbazin committed
490
491
492
493
494
495
496
497
498
499
500
501
static void BufLeToBe( uint8_t *p_out, const uint8_t *p_in, int i_in )
{
    int i;

    for( i = 0; i < i_in/2; i++  )
    {
        p_out[i*2] = p_in[i*2+1];
        p_out[i*2+1] = p_in[i*2];
    }
}

static int Buf14To16( uint8_t *p_out, const uint8_t *p_in, int i_in, int i_le )
gbazin's avatar
   
gbazin committed
502
503
504
505
506
507
{
    unsigned char tmp, cur = 0;
    int bits_in, bits_out = 0;
    int i, i_out = 0;

    for( i = 0; i < i_in; i++  )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
508
    {
gbazin's avatar
   
gbazin committed
509
510
511
512
513
514
515
516
517
518
        if( i%2 )
        {
            tmp = p_in[i-i_le];
            bits_in = 8;
        }
        else
        {
            tmp = p_in[i+i_le] & 0x3F;
            bits_in = 8 - 2;
        }
gbazin's avatar
   
gbazin committed
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

        if( bits_out < 8 )
        {
            int need = __MIN( 8 - bits_out, bits_in );
            cur <<= need;
            cur |= ( tmp >> (bits_in - need) );
            tmp <<= (8 - bits_in + need);
            tmp >>= (8 - bits_in + need);
            bits_in -= need;
            bits_out += need;
        }

        if( bits_out == 8 )
        {
            p_out[i_out] = cur;
            cur = 0;
            bits_out = 0;
            i_out++;
        }

        bits_out += bits_in;
        cur <<= bits_in;
        cur |= tmp;
    }

    return i_out;
}
Jon Lech Johansen's avatar
Jon Lech Johansen committed
546

gbazin's avatar
   
gbazin committed
547
548
549
550
551
552
static inline int SyncCode( const uint8_t *p_buf )
{
    /* 14 bits, little endian version of the bitstream */
    if( p_buf[0] == 0xff && p_buf[1] == 0x1f &&
        p_buf[2] == 0x00 && p_buf[3] == 0xe8 &&
        (p_buf[4] & 0xf0) == 0xf0 && p_buf[5] == 0x07 )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
553
    {
gbazin's avatar
   
gbazin committed
554
555
        return VLC_SUCCESS;
    }
gbazin's avatar
   
gbazin committed
556
557
558
559
560
561
562
    /* 14 bits, big endian version of the bitstream */
    else if( p_buf[0] == 0x1f && p_buf[1] == 0xff &&
             p_buf[2] == 0xe8 && p_buf[3] == 0x00 &&
             p_buf[4] == 0x07 && (p_buf[5] & 0xf0) == 0xf0 )
    {
        return VLC_SUCCESS;
    }
gbazin's avatar
   
gbazin committed
563
564
565
    /* 16 bits, big endian version of the bitstream */
    else if( p_buf[0] == 0x7f && p_buf[1] == 0xfe &&
             p_buf[2] == 0x80 && p_buf[3] == 0x01 )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
566
    {
gbazin's avatar
   
gbazin committed
567
        return VLC_SUCCESS;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
568
    }
gbazin's avatar
   
gbazin committed
569
570
571
572
573
574
    /* 16 bits, little endian version of the bitstream */
    else if( p_buf[0] == 0xfe && p_buf[1] == 0x7f &&
             p_buf[2] == 0x01 && p_buf[3] == 0x80 )
    {
        return VLC_SUCCESS;
    }
575
576
577
578
579
580
581
582
    /* DTS-HD */
    else if( p_buf[0] == 0x64 && p_buf[1] ==  0x58 &&
             p_buf[2] == 0x20 && p_buf[3] ==  0x25 )
    {
        return VLC_SUCCESS;
    }

    return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
583
}
Jon Lech Johansen's avatar
Jon Lech Johansen committed
584

gbazin's avatar
   
gbazin committed
585
static int SyncInfo( const uint8_t *p_buf,
586
                     bool *pb_dts_hd,
gbazin's avatar
   
gbazin committed
587
588
589
                     unsigned int *pi_channels,
                     unsigned int *pi_channels_conf,
                     unsigned int *pi_sample_rate,
590
                     unsigned int *pi_bit_rate,
gbazin's avatar
   
gbazin committed
591
592
593
                     unsigned int *pi_frame_length )
{
    unsigned int i_audio_mode;
594
    unsigned int i_frame_size;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
595

gbazin's avatar
   
gbazin committed
596
597
598
599
600
    /* 14 bits, little endian version of the bitstream */
    if( p_buf[0] == 0xff && p_buf[1] == 0x1f &&
        p_buf[2] == 0x00 && p_buf[3] == 0xe8 &&
        (p_buf[4] & 0xf0) == 0xf0 && p_buf[5] == 0x07 )
    {
gbazin's avatar
   
gbazin committed
601
602
        uint8_t conv_buf[DTS_HEADER_SIZE];
        Buf14To16( conv_buf, p_buf, DTS_HEADER_SIZE, 1 );
gbazin's avatar
   
gbazin committed
603
604
605
606
607
608
609
610
611
        i_frame_size = SyncInfo16be( conv_buf, &i_audio_mode, pi_sample_rate,
                                     pi_bit_rate, pi_frame_length );
        i_frame_size = i_frame_size * 8 / 14 * 2;
    }
    /* 14 bits, big endian version of the bitstream */
    else if( p_buf[0] == 0x1f && p_buf[1] == 0xff &&
             p_buf[2] == 0xe8 && p_buf[3] == 0x00 &&
             p_buf[4] == 0x07 && (p_buf[5] & 0xf0) == 0xf0 )
    {
gbazin's avatar
   
gbazin committed
612
613
        uint8_t conv_buf[DTS_HEADER_SIZE];
        Buf14To16( conv_buf, p_buf, DTS_HEADER_SIZE, 0 );
gbazin's avatar
   
gbazin committed
614
615
        i_frame_size = SyncInfo16be( conv_buf, &i_audio_mode, pi_sample_rate,
                                     pi_bit_rate, pi_frame_length );
gbazin's avatar
   
gbazin committed
616
        i_frame_size = i_frame_size * 8 / 14 * 2;
gbazin's avatar
   
gbazin committed
617
618
619
620
621
622
623
624
    }
    /* 16 bits, big endian version of the bitstream */
    else if( p_buf[0] == 0x7f && p_buf[1] == 0xfe &&
             p_buf[2] == 0x80 && p_buf[3] == 0x01 )
    {
        i_frame_size = SyncInfo16be( p_buf, &i_audio_mode, pi_sample_rate,
                                     pi_bit_rate, pi_frame_length );
    }
gbazin's avatar
   
gbazin committed
625
626
627
628
    /* 16 bits, little endian version of the bitstream */
    else if( p_buf[0] == 0xfe && p_buf[1] == 0x7f &&
             p_buf[2] == 0x01 && p_buf[3] == 0x80 )
    {
gbazin's avatar
   
gbazin committed
629
630
        uint8_t conv_buf[DTS_HEADER_SIZE];
        BufLeToBe( conv_buf, p_buf, DTS_HEADER_SIZE );
gbazin's avatar
   
gbazin committed
631
632
633
        i_frame_size = SyncInfo16be( p_buf, &i_audio_mode, pi_sample_rate,
                                     pi_bit_rate, pi_frame_length );
    }
634
    /* DTS-HD */
635
    else
636
    {
637
638
639
        assert( p_buf[0] == 0x64 && p_buf[1] ==  0x58 &&
                p_buf[2] == 0x20 && p_buf[3] ==  0x25 );

640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
        int i_dts_hd_size;
        bs_t s;
        bs_init( &s, &p_buf[4], DTS_HEADER_SIZE - 4 );

        bs_skip( &s, 8 + 2 );

        if( bs_read1( &s ) )
        {
            bs_skip( &s, 12 );
            i_dts_hd_size = bs_read( &s, 20 ) + 1;
        }
        else
        {
            bs_skip( &s, 8 );
            i_dts_hd_size = bs_read( &s, 16 ) + 1;
        }
        //uint16_t s0 = bs_read( &s, 16 );
        //uint16_t s1 = bs_read( &s, 16 );
        //fprintf( stderr, "DTS HD=%d : %x %x\n", i_dts_hd_size, s0, s1 );

        *pb_dts_hd = true;
        /* As we ignore the stream, do not modify those variables:
        *pi_channels = ;
        *pi_channels_conf = ;
        *pi_sample_rate = ;
        *pi_bit_rate = ;
        *pi_frame_length = ;
        */
        return i_dts_hd_size;
    }

    *pb_dts_hd = false;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
672

gbazin's avatar
   
gbazin committed
673
    switch( i_audio_mode & 0xFFFF )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
674
675
676
    {
        case 0x0:
            /* Mono */
677
            *pi_channels = 1;
gbazin's avatar
   
gbazin committed
678
            *pi_channels_conf = AOUT_CHAN_CENTER;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
679
680
681
            break;
        case 0x1:
            /* Dual-mono = stereo + dual-mono */
682
            *pi_channels = 2;
gbazin's avatar
   
gbazin committed
683
            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
Jon Lech Johansen's avatar
Jon Lech Johansen committed
684
685
686
687
688
689
                           AOUT_CHAN_DUALMONO;
            break;
        case 0x2:
        case 0x3:
        case 0x4:
            /* Stereo */
gbazin's avatar
   
gbazin committed
690
691
            *pi_channels = 2;
            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
692
693
694
            break;
        case 0x5:
            /* 3F */
gbazin's avatar
   
gbazin committed
695
696
697
            *pi_channels = 3;
            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
                                AOUT_CHAN_CENTER;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
698
699
            break;
        case 0x6:
gbazin's avatar
   
gbazin committed
700
            /* 2F/1R */
gbazin's avatar
   
gbazin committed
701
702
            *pi_channels = 3;
            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
gbazin's avatar
   
gbazin committed
703
                                AOUT_CHAN_REARCENTER;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
704
705
            break;
        case 0x7:
gbazin's avatar
   
gbazin committed
706
            /* 3F/1R */
gbazin's avatar
   
gbazin committed
707
708
            *pi_channels = 4;
            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
gbazin's avatar
   
gbazin committed
709
                                AOUT_CHAN_CENTER | AOUT_CHAN_REARCENTER;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
710
711
712
            break;
        case 0x8:
            /* 2F2R */
gbazin's avatar
   
gbazin committed
713
714
715
            *pi_channels = 4;
            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
                                AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
716
717
718
            break;
        case 0x9:
            /* 3F2R */
gbazin's avatar
   
gbazin committed
719
720
721
722
            *pi_channels = 5;
            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
                                AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
                                AOUT_CHAN_REARRIGHT;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
723
724
725
726
            break;
        case 0xA:
        case 0xB:
            /* 2F2M2R */
gbazin's avatar
   
gbazin committed
727
728
729
730
            *pi_channels = 6;
            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
                                AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT |
                                AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
731
732
733
            break;
        case 0xC:
            /* 3F2M2R */
gbazin's avatar
   
gbazin committed
734
735
736
737
738
            *pi_channels = 7;
            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
                                AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT |
                                AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_REARLEFT |
                                AOUT_CHAN_REARRIGHT;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
739
740
741
742
            break;
        case 0xD:
        case 0xE:
            /* 3F2M2R/LFE */
gbazin's avatar
   
gbazin committed
743
744
745
746
747
            *pi_channels = 8;
            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
                                AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT |
                                AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_REARLEFT |
                                AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
748
749
750
            break;

        default:
751
752
753
            if( i_audio_mode <= 63 )
            {
                /* User defined */
gbazin's avatar
   
gbazin committed
754
                *pi_channels = 0;
755
                *pi_channels_conf = 0;
756
            }
gbazin's avatar
   
gbazin committed
757
            else return 0;
758
            break;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
759
760
    }

gbazin's avatar
   
gbazin committed
761
762
763
764
765
766
    if( i_audio_mode & 0x10000 )
    {
        (*pi_channels)++;
        *pi_channels_conf |= AOUT_CHAN_LFE;
    }

gbazin's avatar
   
gbazin committed
767
768
    if( *pi_sample_rate >= sizeof( ppi_dts_samplerate ) /
                           sizeof( ppi_dts_samplerate[0] ) )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
769
    {
gbazin's avatar
   
gbazin committed
770
        return 0;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
771
    }
gbazin's avatar
   
gbazin committed
772
    *pi_sample_rate = ppi_dts_samplerate[ *pi_sample_rate ];
gbazin's avatar
   
gbazin committed
773
    if( !*pi_sample_rate ) return 0;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
774

gbazin's avatar
   
gbazin committed
775
776
    if( *pi_bit_rate >= sizeof( ppi_dts_bitrate ) /
                        sizeof( ppi_dts_bitrate[0] ) )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
777
    {
gbazin's avatar
   
gbazin committed
778
        return 0;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
779
    }
gbazin's avatar
   
gbazin committed
780
    *pi_bit_rate = ppi_dts_bitrate[ *pi_bit_rate ];
gbazin's avatar
   
gbazin committed
781
    if( !*pi_bit_rate ) return 0;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
782

gbazin's avatar
   
gbazin committed
783
    *pi_frame_length = (*pi_frame_length + 1) * 32;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
784

gbazin's avatar
   
gbazin committed
785
    return i_frame_size;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
786
}