dts.c 19.7 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
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2003-2009 VLC authors and VideoLAN
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
#define VLC_MODULE_LICENSE VLC_LICENSE_GPL_2_PLUS
35
#include <vlc_common.h>
36
#include <vlc_plugin.h>
zorglub's avatar
zorglub committed
37 38
#include <vlc_codec.h>
#include <vlc_block_helper.h>
39
#include <vlc_bits.h>
40
#include <vlc_modules.h>
41
#include <vlc_cpu.h>
Jon Lech Johansen's avatar
Jon Lech Johansen committed
42

43
#include "../packetizer/packetizer_helper.h"
44
#include "dts_header.h"
45

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
/*****************************************************************************
 * 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
63

Jon Lech Johansen's avatar
Jon Lech Johansen committed
64
/*****************************************************************************
gbazin's avatar
 
gbazin committed
65
 * decoder_sys_t : decoder descriptor
Jon Lech Johansen's avatar
Jon Lech Johansen committed
66
 *****************************************************************************/
gbazin's avatar
 
gbazin committed
67
struct decoder_sys_t
Jon Lech Johansen's avatar
Jon Lech Johansen committed
68
{
gbazin's avatar
 
gbazin committed
69
    /* Module mode */
70
    bool b_packetizer;
gbazin's avatar
 
gbazin committed
71

Jon Lech Johansen's avatar
Jon Lech Johansen committed
72
    /*
gbazin's avatar
 
gbazin committed
73
     * Input properties
Jon Lech Johansen's avatar
Jon Lech Johansen committed
74
     */
gbazin's avatar
 
gbazin committed
75
    int i_state;
gbazin's avatar
 
gbazin committed
76

gbazin's avatar
 
gbazin committed
77
    block_bytestream_t bytestream;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
78 79

    /*
gbazin's avatar
 
gbazin committed
80
     * Common properties
Jon Lech Johansen's avatar
Jon Lech Johansen committed
81
     */
82
    date_t  end_date;
gbazin's avatar
 
gbazin committed
83 84 85

    mtime_t i_pts;

86
    bool         b_dts_hd;  /* Is the current frame a DTS HD one */
87 88 89 90 91 92
    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
93 94
};

Jon Lech Johansen's avatar
Jon Lech Johansen committed
95 96 97
/****************************************************************************
 * Local prototypes
 ****************************************************************************/
98
static int OpenCommon( vlc_object_t *, bool b_packetizer );
99
static block_t *DecodeBlock( decoder_t *, block_t ** );
Jon Lech Johansen's avatar
Jon Lech Johansen committed
100

101
static int  SyncInfo( const uint8_t *, bool *, unsigned int *, unsigned int *,
102
                      unsigned int *, unsigned int *, unsigned int * );
Jon Lech Johansen's avatar
Jon Lech Johansen committed
103

104 105 106
static uint8_t *GetOutBuffer ( decoder_t *, block_t ** );
static block_t *GetAoutBuffer( decoder_t * );
static block_t *GetSoutBuffer( decoder_t * );
Jon Lech Johansen's avatar
Jon Lech Johansen committed
107 108

/*****************************************************************************
109
 * OpenDecoder: probe the decoder
Jon Lech Johansen's avatar
Jon Lech Johansen committed
110
 *****************************************************************************/
111 112 113
static int OpenDecoder( vlc_object_t *p_this )
{
    /* HACK: Don't use this codec if we don't have an dts audio filter */
114
    if( !module_exists( "dtstofloat32" ) )
115
        return VLC_EGENERIC;
116

117 118
    return OpenCommon( p_this, false );
}
Jon Lech Johansen's avatar
Jon Lech Johansen committed
119 120

/*****************************************************************************
121
 * OpenPacketizer: probe the packetizer
Jon Lech Johansen's avatar
Jon Lech Johansen committed
122
 *****************************************************************************/
123 124 125 126 127 128 129 130 131
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
132
{
gbazin's avatar
 
gbazin committed
133
    decoder_t *p_dec = (decoder_t*)p_this;
gbazin's avatar
 
gbazin committed
134
    decoder_sys_t *p_sys;
gbazin's avatar
 
gbazin committed
135

136
    if( p_dec->fmt_in.i_codec != VLC_CODEC_DTS )
gbazin's avatar
 
gbazin committed
137 138 139
        return VLC_EGENERIC;

    /* Allocate the memory needed to store the decoder's structure */
140
    if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
141
        return VLC_ENOMEM;
gbazin's avatar
 
gbazin committed
142 143

    /* Misc init */
144
    p_sys->b_packetizer = b_packetizer;
gbazin's avatar
 
gbazin committed
145
    p_sys->i_state = STATE_NOSYNC;
146
    date_Set( &p_sys->end_date, 0 );
147
    p_sys->b_dts_hd = false;
148
    p_sys->i_pts = VLC_TS_INVALID;
gbazin's avatar
 
gbazin committed
149

150
    block_BytestreamInit( &p_sys->bytestream );
gbazin's avatar
 
gbazin committed
151 152 153

    /* Set output properties */
    p_dec->fmt_out.i_cat = AUDIO_ES;
154
    p_dec->fmt_out.i_codec = VLC_CODEC_DTS;
155
    p_dec->fmt_out.audio.i_rate = 0; /* So end_date gets initialized */
gbazin's avatar
 
gbazin committed
156 157

    /* Set callback */
158 159
    p_dec->pf_decode_audio = DecodeBlock;
    p_dec->pf_packetize    = DecodeBlock;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
160 161 162 163

    return VLC_SUCCESS;
}

gbazin's avatar
 
gbazin committed
164
/****************************************************************************
gbazin's avatar
 
gbazin committed
165
 * DecodeBlock: the whole thing
gbazin's avatar
 
gbazin committed
166
 ****************************************************************************/
167
static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
gbazin's avatar
 
gbazin committed
168 169
{
    decoder_sys_t *p_sys = p_dec->p_sys;
gbazin's avatar
 
gbazin committed
170 171
    uint8_t p_header[DTS_HEADER_SIZE];
    uint8_t *p_buf;
172
    block_t *p_out_buffer;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
173

174 175
    if( !pp_block || !*pp_block )
        return NULL;
gbazin's avatar
 
gbazin committed
176

177
    if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
gbazin's avatar
 
gbazin committed
178
    {
179 180 181 182 183
        if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED )
        {
            p_sys->i_state = STATE_NOSYNC;
            block_BytestreamEmpty( &p_sys->bytestream );
        }
184
        date_Set( &p_sys->end_date, 0 );
185 186
        block_Release( *pp_block );
        return NULL;
gbazin's avatar
 
gbazin committed
187 188
    }

189
    if( !date_Get( &p_sys->end_date ) && (*pp_block)->i_pts <= VLC_TS_INVALID )
gbazin's avatar
 
gbazin committed
190
    {
191 192 193
        /* We've just started the stream, wait for the first PTS. */
        block_Release( *pp_block );
        return NULL;
gbazin's avatar
 
gbazin committed
194 195 196 197 198
    }

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

    while( 1 )
gbazin's avatar
 
gbazin committed
199 200
    {
        switch( p_sys->i_state )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
201
        {
gbazin's avatar
 
gbazin committed
202
        case STATE_NOSYNC:
gbazin's avatar
 
gbazin committed
203 204
            /* Look for sync code - should be 0x7ffe8001 */
            while( block_PeekBytes( &p_sys->bytestream, p_header, 6 )
gbazin's avatar
 
gbazin committed
205
                   == VLC_SUCCESS )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
206
            {
gbazin's avatar
 
gbazin committed
207
                if( SyncCode( p_header ) == VLC_SUCCESS )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
208
                {
gbazin's avatar
 
gbazin committed
209
                    p_sys->i_state = STATE_SYNC;
gbazin's avatar
 
gbazin committed
210
                    break;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
211
                }
gbazin's avatar
 
gbazin committed
212 213 214 215 216
                block_SkipByte( &p_sys->bytestream );
            }
            if( p_sys->i_state != STATE_SYNC )
            {
                block_BytestreamFlush( &p_sys->bytestream );
gbazin's avatar
 
gbazin committed
217

gbazin's avatar
 
gbazin committed
218 219
                /* Need more data */
                return NULL;
gbazin's avatar
 
gbazin committed
220 221 222 223
            }

        case STATE_SYNC:
            /* New frame, set the Presentation Time Stamp */
gbazin's avatar
 
gbazin committed
224
            p_sys->i_pts = p_sys->bytestream.p_block->i_pts;
225
            if( p_sys->i_pts > VLC_TS_INVALID &&
226
                p_sys->i_pts != date_Get( &p_sys->end_date ) )
gbazin's avatar
 
gbazin committed
227
            {
228
                date_Set( &p_sys->end_date, p_sys->i_pts );
Jon Lech Johansen's avatar
Jon Lech Johansen committed
229
            }
gbazin's avatar
 
gbazin committed
230
            p_sys->i_state = STATE_HEADER;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
231

gbazin's avatar
 
gbazin committed
232 233
        case STATE_HEADER:
            /* Get DTS frame header (DTS_HEADER_SIZE bytes) */
gbazin's avatar
 
gbazin committed
234 235
            if( block_PeekBytes( &p_sys->bytestream, p_header,
                                 DTS_HEADER_SIZE ) != VLC_SUCCESS )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
236
            {
gbazin's avatar
 
gbazin committed
237 238
                /* Need more data */
                return NULL;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
239 240
            }

gbazin's avatar
 
gbazin committed
241 242
            /* Check if frame is valid and get frame info */
            p_sys->i_frame_size = SyncInfo( p_header,
243
                                            &p_sys->b_dts_hd,
gbazin's avatar
 
gbazin committed
244 245 246 247 248 249 250 251 252 253
                                            &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
254
                break;
gbazin's avatar
 
gbazin committed
255 256 257 258 259 260
            }
            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
261

gbazin's avatar
 
gbazin committed
262 263
            /* Check if next expected frame contains the sync word */
            if( block_PeekOffsetBytes( &p_sys->bytestream,
gbazin's avatar
 
gbazin committed
264
                                       p_sys->i_frame_size, p_header, 6 )
gbazin's avatar
 
gbazin committed
265
                != VLC_SUCCESS )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
266
            {
gbazin's avatar
 
gbazin committed
267 268
                /* Need more data */
                return NULL;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
269 270
            }

271 272 273 274 275 276 277 278
            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
279
            if( SyncCode( p_header ) != VLC_SUCCESS )
gbazin's avatar
 
gbazin committed
280
            {
gbazin's avatar
 
gbazin committed
281
                msg_Dbg( p_dec, "emulated sync word "
bigben's avatar
bigben committed
282
                         "(no sync on following frame): %2.2x%2.2x%2.2x%2.2x",
gbazin's avatar
 
gbazin committed
283 284
                         (int)p_header[0], (int)p_header[1],
                         (int)p_header[2], (int)p_header[3] );
gbazin's avatar
 
gbazin committed
285
                p_sys->i_state = STATE_NOSYNC;
gbazin's avatar
 
gbazin committed
286
                block_SkipByte( &p_sys->bytestream );
gbazin's avatar
 
gbazin committed
287 288
                break;
            }
gbazin's avatar
 
gbazin committed
289
            p_sys->i_state = STATE_SEND_DATA;
gbazin's avatar
 
gbazin committed
290 291
            break;

gbazin's avatar
 
gbazin committed
292 293 294 295 296
        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
297
            {
gbazin's avatar
 
gbazin committed
298 299
                /* Need more data */
                return NULL;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
300
            }
gbazin's avatar
 
gbazin committed
301
            p_sys->i_state = STATE_SEND_DATA;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
302

gbazin's avatar
 
gbazin committed
303
        case STATE_SEND_DATA:
304 305 306 307 308 309 310 311
            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
312 313
            if( !(p_buf = GetOutBuffer( p_dec, &p_out_buffer )) )
            {
314
                //p_dec->b_error = true;
gbazin's avatar
 
gbazin committed
315 316
                return NULL;
            }
gbazin's avatar
 
gbazin committed
317

gbazin's avatar
 
gbazin committed
318 319
            /* Copy the whole frame into the buffer. When we reach this point
             * we already know we have enough data available. */
320 321
            block_GetBytes( &p_sys->bytestream,
                            p_buf, __MIN( p_sys->i_frame_size, p_out_buffer->i_buffer ) );
gbazin's avatar
 
gbazin committed
322

gbazin's avatar
 
gbazin committed
323 324
            /* Make sure we don't reuse the same pts twice */
            if( p_sys->i_pts == p_sys->bytestream.p_block->i_pts )
325
                p_sys->i_pts = p_sys->bytestream.p_block->i_pts = VLC_TS_INVALID;
gbazin's avatar
 
gbazin committed
326

gbazin's avatar
 
gbazin committed
327
            p_sys->i_state = STATE_NOSYNC;
gbazin's avatar
 
gbazin committed
328

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

gbazin's avatar
 
gbazin committed
332
            return p_out_buffer;
gbazin's avatar
 
gbazin committed
333 334 335
        }
    }

gbazin's avatar
 
gbazin committed
336
    return NULL;
gbazin's avatar
 
gbazin committed
337 338 339
}

/*****************************************************************************
340
 * CloseCommon: clean up the decoder
gbazin's avatar
 
gbazin committed
341
 *****************************************************************************/
342
static void CloseCommon( vlc_object_t *p_this )
gbazin's avatar
 
gbazin committed
343
{
gbazin's avatar
 
gbazin committed
344
    decoder_t *p_dec = (decoder_t*)p_this;
gbazin's avatar
 
gbazin committed
345 346
    decoder_sys_t *p_sys = p_dec->p_sys;

gbazin's avatar
 
gbazin committed
347
    block_BytestreamRelease( &p_sys->bytestream );
gbazin's avatar
 
gbazin committed
348

gbazin's avatar
 
gbazin committed
349
    free( p_sys );
gbazin's avatar
 
gbazin committed
350 351 352
}

/*****************************************************************************
gbazin's avatar
 
gbazin committed
353
 * GetOutBuffer:
gbazin's avatar
 
gbazin committed
354
 *****************************************************************************/
355
static uint8_t *GetOutBuffer( decoder_t *p_dec, block_t **pp_out_buffer )
gbazin's avatar
 
gbazin committed
356 357
{
    decoder_sys_t *p_sys = p_dec->p_sys;
gbazin's avatar
 
gbazin committed
358
    uint8_t *p_buf;
gbazin's avatar
 
gbazin committed
359

gbazin's avatar
 
gbazin committed
360
    if( p_dec->fmt_out.audio.i_rate != p_sys->i_rate )
gbazin's avatar
 
gbazin committed
361
    {
gbazin's avatar
 
gbazin committed
362 363
        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
364

365 366
        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
367 368
    }

gbazin's avatar
 
gbazin committed
369 370
    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
371 372 373
    /* 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
374 375 376 377 378
    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
379

gbazin's avatar
 
gbazin committed
380 381
    p_dec->fmt_out.i_bitrate = p_sys->i_bit_rate;

gbazin's avatar
 
gbazin committed
382
    if( p_sys->b_packetizer )
gbazin's avatar
 
gbazin committed
383
    {
gbazin's avatar
 
gbazin committed
384 385 386
        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
387
    }
gbazin's avatar
 
gbazin committed
388
    else
Jon Lech Johansen's avatar
Jon Lech Johansen committed
389
    {
390
        block_t *p_aout_buffer = GetAoutBuffer( p_dec );
gbazin's avatar
 
gbazin committed
391 392
        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
393 394
    }

gbazin's avatar
 
gbazin committed
395
    return p_buf;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
396 397 398
}

/*****************************************************************************
gbazin's avatar
 
gbazin committed
399
 * GetAoutBuffer:
Jon Lech Johansen's avatar
Jon Lech Johansen committed
400
 *****************************************************************************/
401
static block_t *GetAoutBuffer( decoder_t *p_dec )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
402
{
gbazin's avatar
 
gbazin committed
403
    decoder_sys_t *p_sys = p_dec->p_sys;
404
    block_t *p_buf;
gbazin's avatar
 
gbazin committed
405

gbazin's avatar
 
gbazin committed
406 407
    /* Hack for DTS S/PDIF filter which needs to send 3 frames at a time
     * (plus a few header bytes) */
408
    p_buf = decoder_NewAudioBuffer( p_dec, p_sys->i_frame_length * 4 );
gbazin's avatar
 
gbazin committed
409
    if( p_buf == NULL ) return NULL;
410

gbazin's avatar
 
gbazin committed
411
    p_buf->i_nb_samples = p_sys->i_frame_length;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
412
    p_buf->i_buffer = p_sys->i_frame_size;
gbazin's avatar
 
gbazin committed
413

414
    p_buf->i_pts = date_Get( &p_sys->end_date );
415 416
    p_buf->i_length = date_Increment( &p_sys->end_date, p_sys->i_frame_length )
                      - p_buf->i_pts;
gbazin's avatar
 
gbazin committed
417

gbazin's avatar
 
gbazin committed
418
    return p_buf;
gbazin's avatar
 
gbazin committed
419 420 421
}

/*****************************************************************************
gbazin's avatar
 
gbazin committed
422
 * GetSoutBuffer:
gbazin's avatar
 
gbazin committed
423
 *****************************************************************************/
gbazin's avatar
 
gbazin committed
424
static block_t *GetSoutBuffer( decoder_t *p_dec )
gbazin's avatar
 
gbazin committed
425 426
{
    decoder_sys_t *p_sys = p_dec->p_sys;
gbazin's avatar
 
gbazin committed
427
    block_t *p_block;
gbazin's avatar
 
gbazin committed
428

429
    p_block = block_Alloc( p_sys->i_frame_size );
gbazin's avatar
 
gbazin committed
430
    if( p_block == NULL ) return NULL;
gbazin's avatar
 
gbazin committed
431

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

434
    p_block->i_length = date_Increment( &p_sys->end_date,
gbazin's avatar
 
gbazin committed
435 436 437
        p_sys->i_frame_length ) - p_block->i_pts;

    return p_block;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
438 439 440 441 442
}

/*****************************************************************************
 * SyncInfo: parse DTS sync info
 *****************************************************************************/
gbazin's avatar
 
gbazin committed
443 444
static const unsigned int ppi_dts_samplerate[] =
{
gbazin's avatar
 
gbazin committed
445
    0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0,
gbazin's avatar
 
gbazin committed
446 447 448 449 450 451 452 453 454 455
    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
456
    2048000, 3072000, 3840000, 1/*open*/, 2/*variable*/, 3/*lossless*/
gbazin's avatar
 
gbazin committed
457 458 459
};

static int SyncInfo( const uint8_t *p_buf,
460
                     bool *pb_dts_hd,
gbazin's avatar
 
gbazin committed
461 462 463
                     unsigned int *pi_channels,
                     unsigned int *pi_channels_conf,
                     unsigned int *pi_sample_rate,
464
                     unsigned int *pi_bit_rate,
gbazin's avatar
 
gbazin committed
465 466 467
                     unsigned int *pi_frame_length )
{
    unsigned int i_audio_mode;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
468

469 470
    unsigned int i_frame_size = GetSyncInfo( p_buf, pb_dts_hd,
            pi_sample_rate, pi_bit_rate, pi_frame_length, &i_audio_mode);
471

472 473
    if( *pb_dts_hd == true )
        return i_frame_size;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
474

gbazin's avatar
 
gbazin committed
475
    switch( i_audio_mode & 0xFFFF )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
476 477 478
    {
        case 0x0:
            /* Mono */
479
            *pi_channels = 1;
gbazin's avatar
 
gbazin committed
480
            *pi_channels_conf = AOUT_CHAN_CENTER;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
481 482 483
            break;
        case 0x1:
            /* Dual-mono = stereo + dual-mono */
484
            *pi_channels = 2;
gbazin's avatar
 
gbazin committed
485
            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
Jon Lech Johansen's avatar
Jon Lech Johansen committed
486 487 488 489 490 491
                           AOUT_CHAN_DUALMONO;
            break;
        case 0x2:
        case 0x3:
        case 0x4:
            /* Stereo */
gbazin's avatar
 
gbazin committed
492 493
            *pi_channels = 2;
            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
494 495 496
            break;
        case 0x5:
            /* 3F */
gbazin's avatar
 
gbazin committed
497 498 499
            *pi_channels = 3;
            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
                                AOUT_CHAN_CENTER;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
500 501
            break;
        case 0x6:
gbazin's avatar
 
gbazin committed
502
            /* 2F/1R */
gbazin's avatar
 
gbazin committed
503 504
            *pi_channels = 3;
            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
gbazin's avatar
 
gbazin committed
505
                                AOUT_CHAN_REARCENTER;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
506 507
            break;
        case 0x7:
gbazin's avatar
 
gbazin committed
508
            /* 3F/1R */
gbazin's avatar
 
gbazin committed
509 510
            *pi_channels = 4;
            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
gbazin's avatar
 
gbazin committed
511
                                AOUT_CHAN_CENTER | AOUT_CHAN_REARCENTER;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
512 513 514
            break;
        case 0x8:
            /* 2F2R */
gbazin's avatar
 
gbazin committed
515 516 517
            *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
518 519 520
            break;
        case 0x9:
            /* 3F2R */
gbazin's avatar
 
gbazin committed
521 522 523 524
            *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
525 526 527 528
            break;
        case 0xA:
        case 0xB:
            /* 2F2M2R */
gbazin's avatar
 
gbazin committed
529 530 531 532
            *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
533 534 535
            break;
        case 0xC:
            /* 3F2M2R */
gbazin's avatar
 
gbazin committed
536 537 538 539 540
            *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
541 542 543 544
            break;
        case 0xD:
        case 0xE:
            /* 3F2M2R/LFE */
gbazin's avatar
 
gbazin committed
545 546 547 548 549
            *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
550 551
            break;

552
        case 0xF:
Jon Lech Johansen's avatar
Jon Lech Johansen committed
553
        default:
554
            if( (i_audio_mode & 0xFFFF) >= 0x10 )
555 556
            {
                /* User defined */
gbazin's avatar
 
gbazin committed
557
                *pi_channels = 0;
558
                *pi_channels_conf = 0;
559
            }
gbazin's avatar
 
gbazin committed
560
            else return 0;
561

562
            break;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
563 564
    }

565
    if( *pi_channels && (i_audio_mode & 0x10000) )
gbazin's avatar
 
gbazin committed
566 567 568 569 570
    {
        (*pi_channels)++;
        *pi_channels_conf |= AOUT_CHAN_LFE;
    }

gbazin's avatar
 
gbazin committed
571 572
    if( *pi_sample_rate >= sizeof( ppi_dts_samplerate ) /
                           sizeof( ppi_dts_samplerate[0] ) )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
573
    {
gbazin's avatar
 
gbazin committed
574
        return 0;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
575
    }
gbazin's avatar
 
gbazin committed
576
    *pi_sample_rate = ppi_dts_samplerate[ *pi_sample_rate ];
gbazin's avatar
 
gbazin committed
577
    if( !*pi_sample_rate ) return 0;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
578

gbazin's avatar
 
gbazin committed
579 580
    if( *pi_bit_rate >= sizeof( ppi_dts_bitrate ) /
                        sizeof( ppi_dts_bitrate[0] ) )
Jon Lech Johansen's avatar
Jon Lech Johansen committed
581
    {
gbazin's avatar
 
gbazin committed
582
        return 0;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
583
    }
gbazin's avatar
 
gbazin committed
584
    *pi_bit_rate = ppi_dts_bitrate[ *pi_bit_rate ];
gbazin's avatar
 
gbazin committed
585
    if( !*pi_bit_rate ) return 0;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
586

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

gbazin's avatar
 
gbazin committed
589
    return i_frame_size;
Jon Lech Johansen's avatar
Jon Lech Johansen committed
590
}