ogg.c 90.8 KB
Newer Older
gbazin's avatar
   
gbazin committed
1
/*****************************************************************************
hartman's avatar
hartman committed
2
 * ogg.c : ogg stream demux module for vlc
gbazin's avatar
   
gbazin committed
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2001-2007 VLC authors and VideoLAN
5
 * $Id$
gbazin's avatar
   
gbazin committed
6
 *
7
8
 * Authors: Gildas Bazin <gbazin@netcourrier.com>
 *          Andre Pang <Andre.Pang@csiro.au> (Annodex support)
Sam Hocevar's avatar
Sam Hocevar committed
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
gbazin's avatar
   
gbazin committed
13
 * (at your option) any later version.
Sam Hocevar's avatar
Sam Hocevar committed
14
 *
gbazin's avatar
   
gbazin committed
15
16
 * 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.
gbazin's avatar
   
gbazin committed
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.
gbazin's avatar
   
gbazin committed
23
24
25
26
27
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
28
29
30
31
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

32
#include <vlc_common.h>
33
#include <vlc_plugin.h>
zorglub's avatar
zorglub committed
34
#include <vlc_demux.h>
35
36
#include <vlc_meta.h>
#include <vlc_input.h>
gbazin's avatar
   
gbazin committed
37
38
39

#include <ogg/ogg.h>

zorglub's avatar
zorglub committed
40
41
#include <vlc_codecs.h>
#include <vlc_bits.h>
42
#include "xiph.h"
43
#include "xiph_metadata.h"
salsaman's avatar
salsaman committed
44
#include "ogg.h"
salsaman's avatar
salsaman committed
45
#include "oggseek.h"
gbazin's avatar
   
gbazin committed
46

47
48
49
50
51
52
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );

53
54
55
56
57
58
59
60
61
vlc_module_begin ()
    set_shortname ( "OGG" )
    set_description( N_("OGG demuxer" ) )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_DEMUX )
    set_capability( "demux", 50 )
    set_callbacks( Open, Close )
    add_shortcut( "ogg" )
vlc_module_end ()
62

gbazin's avatar
   
gbazin committed
63
64

/*****************************************************************************
Sam Hocevar's avatar
Sam Hocevar committed
65
 * Definitions of structures and functions used by this plugins
gbazin's avatar
   
gbazin committed
66
67
 *****************************************************************************/

gbazin's avatar
   
gbazin committed
68
/* OggDS headers for the new header format (used in ogm files) */
69
typedef struct
gbazin's avatar
   
gbazin committed
70
71
72
{
    ogg_int32_t width;
    ogg_int32_t height;
73
} stream_header_video_t;
Sam Hocevar's avatar
Sam Hocevar committed
74

75
typedef struct
gbazin's avatar
   
gbazin committed
76
77
{
    ogg_int16_t channels;
78
    ogg_int16_t padding;
gbazin's avatar
   
gbazin committed
79
80
    ogg_int16_t blockalign;
    ogg_int32_t avgbytespersec;
81
} stream_header_audio_t;
gbazin's avatar
   
gbazin committed
82

83
typedef struct
gbazin's avatar
   
gbazin committed
84
85
86
87
88
89
90
91
92
93
94
95
{
    char        streamtype[8];
    char        subtype[4];

    ogg_int32_t size;                               /* size of the structure */

    ogg_int64_t time_unit;                              /* in reference time */
    ogg_int64_t samples_per_unit;
    ogg_int32_t default_len;                                /* in media time */

    ogg_int32_t buffersize;
    ogg_int16_t bits_per_sample;
96
    ogg_int16_t padding;
gbazin's avatar
   
gbazin committed
97
98
99
100

    union
    {
        /* Video specific */
101
        stream_header_video_t video;
gbazin's avatar
   
gbazin committed
102
        /* Audio specific */
103
        stream_header_audio_t audio;
gbazin's avatar
   
gbazin committed
104
    } sh;
105
} stream_header_t;
gbazin's avatar
   
gbazin committed
106

107

gbazin's avatar
   
gbazin committed
108
109
110
111
112
113
114
/* Some defines from OggDS */
#define PACKET_TYPE_HEADER   0x01
#define PACKET_TYPE_BITS     0x07
#define PACKET_LEN_BITS01    0xc0
#define PACKET_LEN_BITS2     0x02
#define PACKET_IS_SYNCPOINT  0x08

gbazin's avatar
   
gbazin committed
115
116
117
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
118
119
static int  Demux  ( demux_t * );
static int  Control( demux_t *, int, va_list );
gbazin's avatar
   
gbazin committed
120
121

/* Bitstream manipulation */
122
static int  Ogg_ReadPage     ( demux_t *, ogg_page * );
gbazin's avatar
   
gbazin committed
123
static void Ogg_UpdatePCR    ( logical_stream_t *, ogg_packet * );
124
static void Ogg_DecodePacket ( demux_t *, logical_stream_t *, ogg_packet * );
.'s avatar
. committed
125
static int  Ogg_OpusPacketDuration( logical_stream_t *, ogg_packet * );
gbazin's avatar
   
gbazin committed
126

127
128
129
static int Ogg_BeginningOfStream( demux_t *p_demux );
static int Ogg_FindLogicalStreams( demux_t *p_demux );
static void Ogg_EndOfStream( demux_t *p_demux );
gbazin's avatar
   
gbazin committed
130

131
132
133
134
/* */
static void Ogg_LogicalStreamDelete( demux_t *p_demux, logical_stream_t *p_stream );
static bool Ogg_LogicalStreamResetEsFormat( demux_t *p_demux, logical_stream_t *p_stream );

Laurent Aimar's avatar
Laurent Aimar committed
135
/* */
136
static void Ogg_ExtractMeta( demux_t *p_demux, es_format_t *p_fmt, const uint8_t *p_headers, int i_headers );
.'s avatar
. committed
137
static int64_t Ogg_GetLastPacket( demux_t *p_demux, logical_stream_t *p_stream, double f_rate );
Laurent Aimar's avatar
Laurent Aimar committed
138

139
/* Logical bitstream headers */
140
static void Ogg_ReadTheoraHeader( demux_t *, logical_stream_t *, ogg_packet * );
141
static void Ogg_ReadVorbisHeader( demux_t *, logical_stream_t *, ogg_packet * );
142
static void Ogg_ReadSpeexHeader( logical_stream_t *, ogg_packet * );
143
static void Ogg_ReadOpusHeader( demux_t *, logical_stream_t *, ogg_packet * );
144
static void Ogg_ReadKateHeader( logical_stream_t *, ogg_packet * );
145
static void Ogg_ReadFlacHeader( demux_t *, logical_stream_t *, ogg_packet * );
146
static void Ogg_ReadAnnodexHeader( demux_t *, logical_stream_t *, ogg_packet * );
147
static bool Ogg_ReadDiracHeader( logical_stream_t *, ogg_packet * );
148

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
static void fill_channels_info(audio_format_t *audio)
{
    static const int pi_channels_map[9] =
    {
        0,
        AOUT_CHAN_CENTER,
        AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
        AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
        AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
            | AOUT_CHAN_REARRIGHT,
        AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
            | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT,
        AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
            | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE,
        AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
            | AOUT_CHAN_REARCENTER | AOUT_CHAN_MIDDLELEFT
            | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_LFE,
        AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT
            | AOUT_CHAN_REARRIGHT | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT
            | AOUT_CHAN_LFE,
    };

    unsigned chans = audio->i_channels;
    if (chans < sizeof(pi_channels_map) / sizeof(pi_channels_map[0]))
        audio->i_physical_channels =
        audio->i_original_channels = pi_channels_map[chans];
}

gbazin's avatar
   
gbazin committed
177
/*****************************************************************************
178
 * Open: initializes ogg demux structures
gbazin's avatar
   
gbazin committed
179
 *****************************************************************************/
180
static int Open( vlc_object_t * p_this )
gbazin's avatar
   
gbazin committed
181
{
182
    demux_t *p_demux = (demux_t *)p_this;
183
    demux_sys_t    *p_sys;
184
    const uint8_t  *p_peek;
gbazin's avatar
   
gbazin committed
185

186
    /* Check if we are dealing with an ogg stream */
187
    if( stream_Peek( p_demux->s, &p_peek, 4 ) < 4 ) return VLC_EGENERIC;
188
    if( !p_demux->b_force && memcmp( p_peek, "OggS", 4 ) )
189
190
191
    {
        return VLC_EGENERIC;
    }
gbazin's avatar
   
gbazin committed
192

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
193
194
    /* */
    p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) );
195
196
    if( !p_sys )
        return VLC_ENOMEM;
197

198
199
    p_sys->i_length = -1;

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
200
201
202
203
    /* Set exported functions */
    p_demux->pf_demux = Demux;
    p_demux->pf_control = Control;

204
205
    /* Initialize the Ogg physical bitstream parser */
    ogg_sync_init( &p_sys->oy );
gbazin's avatar
   
gbazin committed
206

Laurent Aimar's avatar
Laurent Aimar committed
207
    /* */
208
    TAB_INIT( p_sys->i_seekpoints, p_sys->pp_seekpoints );
Laurent Aimar's avatar
Laurent Aimar committed
209

gbazin's avatar
   
gbazin committed
210
211
212
    return VLC_SUCCESS;
}

213
214
215
216
217
/*****************************************************************************
 * Close: frees unused data
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
218
219
    demux_t *p_demux = (demux_t *)p_this;
    demux_sys_t *p_sys = p_demux->p_sys  ;
220
221
222
223

    /* Cleanup the bitstream parser */
    ogg_sync_clear( &p_sys->oy );

224
    Ogg_EndOfStream( p_demux );
225

226
227
228
    if( p_sys->p_old_stream )
        Ogg_LogicalStreamDelete( p_demux, p_sys->p_old_stream );

229
230
    TAB_CLEAN( p_sys->i_seekpoints, p_sys->pp_seekpoints );

231
232
233
234
235
236
237
238
    free( p_sys );
}

/*****************************************************************************
 * Demux: reads and demuxes data packets
 *****************************************************************************
 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
 *****************************************************************************/
239
static int Demux( demux_t * p_demux )
240
{
241
    demux_sys_t *p_sys = p_demux->p_sys;
242
243
    ogg_packet  oggpacket;
    int         i_stream;
salsaman's avatar
salsaman committed
244
    bool b_skipping = false;
245
246
247
248
249
250


    if( p_sys->i_eos == p_sys->i_streams )
    {
        if( p_sys->i_eos )
        {
251
            msg_Dbg( p_demux, "end of a group of logical streams" );
252
253
254
255
256
257
258
            /* We keep the ES to try reusing it in Ogg_BeginningOfStream
             * only 1 ES is supported (common case for ogg web radio) */
            if( p_sys->i_streams == 1 )
            {
                p_sys->p_old_stream = p_sys->pp_stream[0];
                TAB_CLEAN( p_sys->i_streams, p_sys->pp_stream );
            }
259
            Ogg_EndOfStream( p_demux );
260
261
262
        }

        p_sys->i_eos = 0;
263
264
        if( Ogg_BeginningOfStream( p_demux ) != VLC_SUCCESS )
            return 0;
265

266
        msg_Dbg( p_demux, "beginning of a group of logical streams" );
267
        es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 );
268
269
270
    }

    /*
271
272
273
274
275
276
277
278
279
280
281
282
     * The first data page of a physical stream is stored in the relevant logical stream
     * in Ogg_FindLogicalStreams. Therefore, we must not read a page and only update the
     * stream it belongs to if we haven't processed this first page yet. If we do, we
     * will only process that first page whenever we find the second page for this stream.
     * While this is fine for Vorbis and Theora, which are continuous codecs, which means
     * the second page will arrive real quick, this is not fine for Kate, whose second
     * data page will typically arrive much later.
     * This means it is now possible to seek right at the start of a stream where the last
     * logical stream is Kate, without having to wait for the second data page to unblock
     * the first one, which is the one that triggers the 'no more headers to backup' code.
     * And, as we all know, seeking without having backed up all headers is bad, since the
     * codec will fail to initialize if it's missing its headers.
283
     */
284
    if( !p_sys->b_page_waiting)
285
    {
286
287
288
        /*
         * Demux an ogg page from the stream
         */
salsaman's avatar
salsaman committed
289
        if( Ogg_ReadPage( p_demux, &p_sys->current_page ) != VLC_SUCCESS )
290
            return 0; /* EOF */
291

292
        /* Test for End of Stream */
salsaman's avatar
salsaman committed
293
        if( ogg_page_eos( &p_sys->current_page ) )
Laurent Aimar's avatar
Laurent Aimar committed
294
            p_sys->i_eos++;
295
    }
296
297
298
299
300
301


    for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
    {
        logical_stream_t *p_stream = p_sys->pp_stream[i_stream];

302
303
304
        /* if we've just pulled page, look for the right logical stream */
        if( !p_sys->b_page_waiting )
        {
305
            if( p_sys->i_streams == 1 &&
salsaman's avatar
salsaman committed
306
                ogg_page_serialno( &p_sys->current_page ) != p_stream->os.serialno )
307
308
            {
                msg_Err( p_demux, "Broken Ogg stream (serialno) mismatch" );
salsaman's avatar
salsaman committed
309
                ogg_stream_reset_serialno( &p_stream->os, ogg_page_serialno( &p_sys->current_page ) );
310
311

                p_stream->b_reinit = true;
312
313
                p_stream->i_pcr = VLC_TS_0;
                p_stream->i_interpolated_pcr = VLC_TS_0;
.'s avatar
. committed
314
                p_stream->i_previous_granulepos = -1;
315
                es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0);
316
317
            }

salsaman's avatar
salsaman committed
318
            if( ogg_stream_pagein( &p_stream->os, &p_sys->current_page ) != 0 )
salsaman's avatar
salsaman committed
319
            {
320
                continue;
salsaman's avatar
salsaman committed
321
322
            }

323
        }
324
325
326
327

        while( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
        {
            /* Read info from any secondary header packets, if there are any */
Laurent Aimar's avatar
Laurent Aimar committed
328
            if( p_stream->i_secondary_header_packets > 0 )
329
            {
330
                if( p_stream->fmt.i_codec == VLC_CODEC_THEORA &&
331
                        oggpacket.bytes >= 7 &&
332
                        ! memcmp( oggpacket.packet, "\x80theora", 7 ) )
333
                {
334
                    Ogg_ReadTheoraHeader( p_demux, p_stream, &oggpacket );
Laurent Aimar's avatar
Laurent Aimar committed
335
                    p_stream->i_secondary_header_packets = 0;
336
                }
337
                else if( p_stream->fmt.i_codec == VLC_CODEC_VORBIS &&
338
                        oggpacket.bytes >= 7 &&
339
                        ! memcmp( oggpacket.packet, "\x01vorbis", 7 ) )
340
                {
341
                    Ogg_ReadVorbisHeader( p_demux, p_stream, &oggpacket );
Laurent Aimar's avatar
Laurent Aimar committed
342
                    p_stream->i_secondary_header_packets = 0;
343
                }
344
                else if( p_stream->fmt.i_codec == VLC_CODEC_CMML )
345
                {
Laurent Aimar's avatar
Laurent Aimar committed
346
                    p_stream->i_secondary_header_packets = 0;
347
                }
salsaman's avatar
salsaman committed
348
349
350
351

                /* update start of data pointer */
                p_stream->i_data_start = stream_Tell( p_demux->s );

352
353
            }

salsaman's avatar
salsaman committed
354
355
356
357
358
            /* If any streams have i_skip_frames, only decode (pre-roll)
             *  for those streams */
            if ( b_skipping && p_stream->i_skip_frames == 0 ) continue;


359
360
361
362
363
364
365
366
            if( p_stream->b_reinit )
            {
                /* If synchro is re-initialized we need to drop all the packets
                 * until we find a new dated one. */
                Ogg_UpdatePCR( p_stream, &oggpacket );

                if( p_stream->i_pcr >= 0 )
                {
Laurent Aimar's avatar
Laurent Aimar committed
367
                    p_stream->b_reinit = false;
.'s avatar
. committed
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
                    /* For Opus, trash the first 80 ms of decoded output as
                       well, to avoid blowing out speakers if we get unlucky.
                       Opus predicts content from prior frames, which can go
                       badly if we seek right where the stream goes from very
                       quiet to very loud. It will converge after a bit. */
                    if( p_stream->fmt.i_codec == VLC_CODEC_OPUS )
                    {
                        ogg_int64_t start_time;
                        int duration;
                        p_stream->i_skip_frames = 80*48;
                        /* Make sure we never play audio from within the
                           pre-skip at the beginning of the stream. */
                        duration =
                            Ogg_OpusPacketDuration( p_stream, &oggpacket );
                        start_time = p_stream->i_previous_granulepos;
                        if( duration > 0 )
                        {
                            start_time = start_time > duration ?
                                start_time - duration : 0;
                        }
                        if( p_stream->i_pre_skip > start_time )
                        {
                            p_stream->i_skip_frames +=
                                p_stream->i_pre_skip - start_time;
                        }
                    }
394
395
396
397
                }
                else
                {
                    p_stream->i_interpolated_pcr = -1;
.'s avatar
. committed
398
                    p_stream->i_previous_granulepos = -1;
399
400
401
402
                    continue;
                }

                /* An Ogg/vorbis packet contains an end date granulepos */
403
404
                if( p_stream->fmt.i_codec == VLC_CODEC_VORBIS ||
                    p_stream->fmt.i_codec == VLC_CODEC_SPEEX ||
Gregory Maxwell's avatar
Gregory Maxwell committed
405
                    p_stream->fmt.i_codec == VLC_CODEC_OPUS ||
406
                    p_stream->fmt.i_codec == VLC_CODEC_FLAC )
407
408
409
                {
                    if( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
                    {
410
                        Ogg_DecodePacket( p_demux, p_stream, &oggpacket );
411
412
413
                    }
                    else
                    {
414
                        es_out_Control( p_demux->out, ES_OUT_SET_PCR,
415
                                        VLC_TS_0 + p_stream->i_pcr );
416
417
418
419
420
                    }
                    continue;
                }
            }

421
            Ogg_DecodePacket( p_demux, p_stream, &oggpacket );
422
        }
423
424
425

        if( !p_sys->b_page_waiting )
            break;
426
427
    }

428
429
430
    /* if a page was waiting, it's now processed */
    p_sys->b_page_waiting = false;

Laurent Aimar's avatar
Laurent Aimar committed
431
432
    p_sys->i_pcr = -1;
    for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
433
434
435
436
437
438
439
440
441
442
443
444
    {
        logical_stream_t *p_stream = p_sys->pp_stream[i_stream];

        if( p_stream->fmt.i_cat == SPU_ES )
            continue;
        if( p_stream->i_interpolated_pcr < 0 )
            continue;

        if( p_sys->i_pcr < 0 || p_stream->i_interpolated_pcr < p_sys->i_pcr )
            p_sys->i_pcr = p_stream->i_interpolated_pcr;
    }

salsaman's avatar
salsaman committed
445
    if( p_sys->i_pcr >= 0 && ! b_skipping )
446
        es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_pcr );
447
448
449
450

    return 1;
}

451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
static void Ogg_ResetStreamHelper( demux_sys_t *p_sys )
{
    for( int i = 0; i < p_sys->i_streams; i++ )
    {
        logical_stream_t *p_stream = p_sys->pp_stream[i];

        /* we'll trash all the data until we find the next pcr */
        p_stream->b_reinit = true;
        p_stream->i_pcr = -1;
        p_stream->i_interpolated_pcr = -1;
        p_stream->i_previous_granulepos = -1;
        ogg_stream_reset( &p_stream->os );
    }
    ogg_sync_reset( &p_sys->oy );
}

467
468
469
/*****************************************************************************
 * Control:
 *****************************************************************************/
470
static int Control( demux_t *p_demux, int i_query, va_list args )
471
{
472
    demux_sys_t *p_sys  = p_demux->p_sys;
Laurent Aimar's avatar
Laurent Aimar committed
473
    vlc_meta_t *p_meta;
474
    int64_t *pi64;
475
    bool *pb_bool;
476
477
478

    switch( i_query )
    {
Laurent Aimar's avatar
Laurent Aimar committed
479
480
481
482
483
484
        case DEMUX_GET_META:
            p_meta = (vlc_meta_t *)va_arg( args, vlc_meta_t* );
            if( p_sys->p_meta )
                vlc_meta_Merge( p_meta, p_sys->p_meta );
            return VLC_SUCCESS;

485
        case DEMUX_HAS_UNSUPPORTED_META:
486
487
            pb_bool = (bool*)va_arg( args, bool* );
            *pb_bool = true;
488
489
            return VLC_SUCCESS;

490
491
492
493
494
495
496
497
        case DEMUX_GET_TIME:
            pi64 = (int64_t*)va_arg( args, int64_t * );
            *pi64 = p_sys->i_pcr;
            return VLC_SUCCESS;

        case DEMUX_SET_TIME:
            return VLC_EGENERIC;

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
498
499
500
501
502
503
504
505
506
507
        case DEMUX_GET_ATTACHMENTS:
        {
            input_attachment_t ***ppp_attach =
                (input_attachment_t***)va_arg( args, input_attachment_t*** );
            int *pi_int = (int*)va_arg( args, int * );

            if( p_sys->i_attachments <= 0 )
                return VLC_EGENERIC;

            *pi_int = p_sys->i_attachments;
508
            *ppp_attach = xmalloc( sizeof(input_attachment_t*) * p_sys->i_attachments );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
509
510
511
512
513
            for( int i = 0; i < p_sys->i_attachments; i++ )
                (*ppp_attach)[i] = vlc_input_attachment_Duplicate( p_sys->attachments[i] );
            return VLC_SUCCESS;
        }

514
        case DEMUX_SET_POSITION:
515
516
517
518
519
520
521
522
            /* forbid seeking if we haven't initialized all logical bitstreams yet;
               if we allowed, some headers would not get backed up and decoder init
               would fail, making that logical stream unusable */
            if( p_sys->i_bos > 0 )
            {
                return VLC_EGENERIC;
            }

523
            Ogg_ResetStreamHelper( p_sys );
524
525
526
527
528
529
530
531
532
533
            return demux_vaControlHelper( p_demux->s, 0, -1, p_sys->i_bitrate,
                                          1, i_query, args );
        case DEMUX_GET_LENGTH:
            if ( p_sys->i_length < 0 )
                return demux_vaControlHelper( p_demux->s, 0, -1, p_sys->i_bitrate,
                                              1, i_query, args );
            pi64 = (int64_t*)va_arg( args, int64_t * );
            *pi64 = p_sys->i_length * 1000000;
            return VLC_SUCCESS;

534
535
536
537
538
539
540
541
542
543
        case DEMUX_GET_TITLE_INFO:
        {
            input_title_t ***ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
            int *pi_int    = (int*)va_arg( args, int* );
            int *pi_title_offset = (int*)va_arg( args, int* );
            int *pi_seekpoint_offset = (int*)va_arg( args, int* );

            if( p_sys->i_seekpoints > 0 )
            {
                *pi_int = 1;
544
                *ppp_title = malloc( sizeof( input_title_t* ) );
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
                input_title_t *p_title = (*ppp_title)[0] = vlc_input_title_New();
                for( int i = 0; i < p_sys->i_seekpoints; i++ )
                {
                    TAB_APPEND( p_title->i_seekpoint, p_title->seekpoint, p_sys->pp_seekpoints[i] );
                }
                *pi_title_offset = 0;
                *pi_seekpoint_offset = 0;
            }
            return VLC_SUCCESS;
        }
        case DEMUX_SET_TITLE:
        {
            const int i_title = (int)va_arg( args, int );
            if( i_title > 1 )
                return VLC_EGENERIC;
            return VLC_SUCCESS;
        }
        case DEMUX_SET_SEEKPOINT:
        {
            const int i_seekpoint = (int)va_arg( args, int );
            if( i_seekpoint > p_sys->i_seekpoints )
                return VLC_EGENERIC;
Ludovic Fauvet's avatar
Ludovic Fauvet committed
567
568
569
570
571
            if( p_sys->i_bos > 0 )
            {
                return VLC_EGENERIC;
            }

572
            Ogg_ResetStreamHelper( p_sys );
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593

            if ( p_sys->i_bitrate == 0 )
            {
                /* we won't be able to find block by time
                 * we'll need to bisect search from here
                 * or use skeleton index if any (FIXME)
                */
                if ( p_sys->pp_stream[0]->fmt.i_codec == VLC_CODEC_OPUS )
                {
                    /* Granule = Freq * T + pre-skip */
                    oggseek_find_frame ( p_demux, p_sys->pp_stream[0],
                        ( p_sys->pp_seekpoints[i_seekpoint]->i_time_offset * 0.048 + p_sys->pp_stream[0]->i_pre_skip ) );
                }
                else return VLC_EGENERIC;
            }
            else
            {
                int64_t i_block = p_sys->pp_seekpoints[i_seekpoint]->i_time_offset * p_sys->i_bitrate / INT64_C(8000000);
                if( stream_Seek( p_demux->s, i_block ) )
                    return VLC_EGENERIC;
            }
594
595
            p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
            p_demux->info.i_seekpoint = i_seekpoint;
Ludovic Fauvet's avatar
Ludovic Fauvet committed
596
            return VLC_SUCCESS;
597
        }
598
599

        default:
600
            return demux_vaControlHelper( p_demux->s, 0, -1, p_sys->i_bitrate,
601
                                           1, i_query, args );
602
603
604
    }
}

gbazin's avatar
   
gbazin committed
605
606
607
608
609
610
/****************************************************************************
 * Ogg_ReadPage: Read a full Ogg page from the physical bitstream.
 ****************************************************************************
 * Returns VLC_SUCCESS if a page has been read. An error might happen if we
 * are at the end of stream.
 ****************************************************************************/
611
static int Ogg_ReadPage( demux_t *p_demux, ogg_page *p_oggpage )
gbazin's avatar
   
gbazin committed
612
{
613
    demux_sys_t *p_ogg = p_demux->p_sys  ;
gbazin's avatar
   
gbazin committed
614
    int i_read = 0;
615
    char *p_buffer;
gbazin's avatar
   
gbazin committed
616
617
618

    while( ogg_sync_pageout( &p_ogg->oy, p_oggpage ) != 1 )
    {
619
        p_buffer = ogg_sync_buffer( &p_ogg->oy, OGGSEEK_BYTES_TO_READ );
620

621
        i_read = stream_Read( p_demux->s, p_buffer, OGGSEEK_BYTES_TO_READ );
gbazin's avatar
   
gbazin committed
622
623
624
625
626
627
628
629
630
        if( i_read <= 0 )
            return VLC_EGENERIC;

        ogg_sync_wrote( &p_ogg->oy, i_read );
    }

    return VLC_SUCCESS;
}

gbazin's avatar
   
gbazin committed
631
632
633
634
635
636
637
/****************************************************************************
 * Ogg_UpdatePCR: update the PCR (90kHz program clock reference) for the
 *                current stream.
 ****************************************************************************/
static void Ogg_UpdatePCR( logical_stream_t *p_stream,
                           ogg_packet *p_oggpacket )
{
.'s avatar
. committed
638
    p_stream->i_end_trim = 0;
gbazin's avatar
   
gbazin committed
639
    /* Convert the granulepos into a pcr */
gbazin's avatar
   
gbazin committed
640
641
    if( p_oggpacket->granulepos >= 0 )
    {
642
643
        if( p_stream->fmt.i_codec == VLC_CODEC_THEORA ||
            p_stream->fmt.i_codec == VLC_CODEC_KATE )
gbazin's avatar
   
gbazin committed
644
645
        {
            ogg_int64_t iframe = p_oggpacket->granulepos >>
646
              p_stream->i_granule_shift;
gbazin's avatar
   
gbazin committed
647
            ogg_int64_t pframe = p_oggpacket->granulepos -
648
              ( iframe << p_stream->i_granule_shift );
gbazin's avatar
   
gbazin committed
649

salsaman's avatar
salsaman committed
650
            p_stream->i_pcr = ( iframe + pframe - p_stream->i_keyframe_offset )
651
              * INT64_C(1000000) / p_stream->f_rate;
gbazin's avatar
   
gbazin committed
652
        }
653
        else if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC )
654
655
656
657
658
        {
            ogg_int64_t i_dts = p_oggpacket->granulepos >> 31;
            /* NB, OggDirac granulepos values are in units of 2*picturerate */
            p_stream->i_pcr = (i_dts/2) * INT64_C(1000000) / p_stream->f_rate;
        }
659
660
        else
        {
.'s avatar
. committed
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
            ogg_int64_t sample;
            sample = p_oggpacket->granulepos;
            if( p_oggpacket->e_o_s &&
                p_stream->fmt.i_codec == VLC_CODEC_OPUS &&
                p_stream->i_previous_granulepos >= 0 )
            {
                int duration;
                duration = Ogg_OpusPacketDuration( p_stream, p_oggpacket );
                if( duration > 0 )
                {
                    ogg_int64_t end_sample;
                    end_sample = p_stream->i_previous_granulepos + duration;
                    if( end_sample > sample )
                        p_stream->i_end_trim = (int)(end_sample - sample);
                }
            }
            if (sample >= p_stream->i_pre_skip)
                sample -= p_stream->i_pre_skip;
            else
                sample = 0;
            p_stream->i_pcr = sample * INT64_C(1000000) / p_stream->f_rate;
682
        }
gbazin's avatar
   
gbazin committed
683

.'s avatar
. committed
684
        p_stream->i_pcr += VLC_TS_0;
gbazin's avatar
   
gbazin committed
685
686
687
688
        p_stream->i_interpolated_pcr = p_stream->i_pcr;
    }
    else
    {
.'s avatar
. committed
689
        int duration;
gbazin's avatar
   
gbazin committed
690
        p_stream->i_pcr = -1;
gbazin's avatar
   
gbazin committed
691

gbazin's avatar
   
gbazin committed
692
693
        /* no granulepos available, try to interpolate the pcr.
         * If we can't then don't touch the old value. */
gbazin's avatar
   
gbazin committed
694
        if( p_stream->fmt.i_cat == VIDEO_ES )
gbazin's avatar
   
gbazin committed
695
            /* 1 frame per packet */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
696
            p_stream->i_interpolated_pcr += (INT64_C(1000000) / p_stream->f_rate);
.'s avatar
. committed
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
        else if( p_stream->fmt.i_codec == VLC_CODEC_OPUS &&
                 p_stream->i_previous_granulepos >= 0 &&
                 ( duration =
                     Ogg_OpusPacketDuration( p_stream, p_oggpacket ) ) > 0 )
        {
            ogg_int64_t sample;
            p_oggpacket->granulepos =
                p_stream->i_previous_granulepos + duration;
            sample = p_oggpacket->granulepos;
            if (sample >= p_stream->i_pre_skip)
                sample -= p_stream->i_pre_skip;
            else
                sample = 0;
            p_stream->i_interpolated_pcr =
                VLC_TS_0 + sample * INT64_C(1000000) / p_stream->f_rate;
        }
gbazin's avatar
   
gbazin committed
713
        else if( p_stream->fmt.i_bitrate )
.'s avatar
. committed
714
        {
715
            p_stream->i_interpolated_pcr +=
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
716
                ( p_oggpacket->bytes * INT64_C(1000000) /
717
                  p_stream->fmt.i_bitrate / 8 );
.'s avatar
. committed
718
        }
gbazin's avatar
   
gbazin committed
719
    }
.'s avatar
. committed
720
    p_stream->i_previous_granulepos = p_oggpacket->granulepos;
gbazin's avatar
   
gbazin committed
721
722
}

gbazin's avatar
   
gbazin committed
723
724
725
/****************************************************************************
 * Ogg_DecodePacket: Decode an Ogg packet.
 ****************************************************************************/
726
static void Ogg_DecodePacket( demux_t *p_demux,
gbazin's avatar
   
gbazin committed
727
728
729
                              logical_stream_t *p_stream,
                              ogg_packet *p_oggpacket )
{
gbazin's avatar
   
gbazin committed
730
    block_t *p_block;
731
    bool b_selected;
gbazin's avatar
   
gbazin committed
732
    int i_header_len = 0;
733
    mtime_t i_pts = -1, i_interpolated_pts;
734
    demux_sys_t *p_ogg = p_demux->p_sys;
gbazin's avatar
   
gbazin committed
735

736
    if( p_oggpacket->bytes >= 7 &&
737
        ! memcmp ( p_oggpacket->packet, "Annodex", 7 ) )
738
739
    {
        /* it's an Annodex packet -- skip it (do nothing) */
740
        return;
741
742
    }
    else if( p_oggpacket->bytes >= 7 &&
743
        ! memcmp ( p_oggpacket->packet, "AnxData", 7 ) )
744
745
    {
        /* it's an AnxData packet -- skip it (do nothing) */
746
        return;
747
748
    }

.'s avatar
. committed
749
    if( p_stream->fmt.i_codec == VLC_CODEC_SUBT && p_oggpacket->bytes > 0 &&
750
751
        p_oggpacket->packet[0] & PACKET_TYPE_BITS ) return;

752
753
754
755
    /* Check the ES is selected */
    es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE,
                    p_stream->p_es, &b_selected );

gbazin's avatar
   
gbazin committed
756
757
    if( p_stream->b_force_backup )
    {
758
        bool b_xiph;
gbazin's avatar
   
gbazin committed
759
        p_stream->i_packets_backup++;
gbazin's avatar
   
gbazin committed
760
        switch( p_stream->fmt.i_codec )
gbazin's avatar
   
gbazin committed
761
        {
762
763
764
        case VLC_CODEC_VORBIS:
        case VLC_CODEC_SPEEX:
        case VLC_CODEC_THEORA:
765
766
            if( p_stream->i_packets_backup == 3 )
                p_stream->b_force_backup = false;
767
            b_xiph = true;
768
            break;
gbazin's avatar
   
gbazin committed
769

Gregory Maxwell's avatar
Gregory Maxwell committed
770
        case VLC_CODEC_OPUS:
771
772
            if( p_stream->i_packets_backup == 2 )
                p_stream->b_force_backup = false;
Gregory Maxwell's avatar
Gregory Maxwell committed
773
774
775
            b_xiph = true;
            break;

776
        case VLC_CODEC_FLAC:
777
778
779
            if( !p_stream->fmt.audio.i_rate && p_stream->i_packets_backup == 2 )
            {
                Ogg_ReadFlacHeader( p_demux, p_stream, p_oggpacket );
780
                p_stream->b_force_backup = false;
781
782
783
            }
            else if( p_stream->fmt.audio.i_rate )
            {
784
                p_stream->b_force_backup = false;
785
786
787
788
789
790
                if( p_oggpacket->bytes >= 9 )
                {
                    p_oggpacket->packet += 9;
                    p_oggpacket->bytes -= 9;
                }
            }
791
            b_xiph = false;
792
            break;
gbazin's avatar
   
gbazin committed
793

794
        case VLC_CODEC_KATE:
795
796
            if( p_stream->i_packets_backup == p_stream->i_kate_num_headers )
                p_stream->b_force_backup = false;
797
            b_xiph = true;
798
799
            break;

gbazin's avatar
   
gbazin committed
800
        default:
801
            p_stream->b_force_backup = false;
802
            b_xiph = false;
803
            break;
gbazin's avatar
   
gbazin committed
804
805
806
        }

        /* Backup the ogg packet (likely an header packet) */
807
        if( !b_xiph )
808
        {
809
810
811
812
            void *p_org = p_stream->p_headers;
            p_stream->i_headers += p_oggpacket->bytes;
            p_stream->p_headers = realloc( p_stream->p_headers, p_stream->i_headers );
            if( p_stream->p_headers )
813
            {
salsaman's avatar
salsaman committed
814
                memcpy( (unsigned char *)p_stream->p_headers + p_stream->i_headers - p_oggpacket->bytes,
815
                        p_oggpacket->packet, p_oggpacket->bytes );
816
            }
817
            else
818
            {
819
#warning Memory leak
820
821
822
                p_stream->i_headers = 0;
                p_stream->p_headers = NULL;
                free( p_org );
823
            }
824
825
826
827
828
829
830
831
832
        }
        else if( xiph_AppendHeaders( &p_stream->i_headers, &p_stream->p_headers,
                                     p_oggpacket->bytes, p_oggpacket->packet ) )
        {
            p_stream->i_headers = 0;
            p_stream->p_headers = NULL;
        }
        if( p_stream->i_headers > 0 )
        {
833
834
835
836
837
838
            if( !p_stream->b_force_backup )
            {
                /* Last header received, commit changes */
                free( p_stream->fmt.p_extra );

                p_stream->fmt.i_extra = p_stream->i_headers;
Laurent Aimar's avatar
Laurent Aimar committed
839
                p_stream->fmt.p_extra = malloc( p_stream->i_headers );
840
841
842
843
844
                if( p_stream->fmt.p_extra )
                    memcpy( p_stream->fmt.p_extra, p_stream->p_headers,
                            p_stream->i_headers );
                else
                    p_stream->fmt.i_extra = 0;
gbazin's avatar
   
gbazin committed
845

846
                if( Ogg_LogicalStreamResetEsFormat( p_demux, p_stream ) )
Laurent Aimar's avatar
Laurent Aimar committed
847
                    es_out_Control( p_demux->out, ES_OUT_SET_ES_FMT,
848
                                    p_stream->p_es, &p_stream->fmt );
849

Laurent Aimar's avatar
Laurent Aimar committed
850
                if( p_stream->i_headers > 0 )
851
                    Ogg_ExtractMeta( p_demux, & p_stream->fmt,
Laurent Aimar's avatar
Laurent Aimar committed
852
853
                                     p_stream->p_headers, p_stream->i_headers );

854
855
                /* we're not at BOS anymore for this logical stream */
                p_ogg->i_bos--;
856
857
            }
        }
858

859
        b_selected = false; /* Discard the header packet */
gbazin's avatar
   
gbazin committed
860
861
    }

gbazin's avatar
   
gbazin committed
862
    /* Convert the pcr into a pts */
863
864
    if( p_stream->fmt.i_codec == VLC_CODEC_VORBIS ||
        p_stream->fmt.i_codec == VLC_CODEC_SPEEX ||
Gregory Maxwell's avatar
Gregory Maxwell committed
865
        p_stream->fmt.i_codec == VLC_CODEC_OPUS ||
866
        p_stream->fmt.i_codec == VLC_CODEC_FLAC )
gbazin's avatar
   
gbazin committed
867
    {
gbazin's avatar
   
gbazin committed
868
869
870
871
872
        if( p_stream->i_pcr >= 0 )
        {
            /* This is for streams where the granulepos of the header packets
             * doesn't match these of the data packets (eg. ogg web radios). */
            if( p_stream->i_previous_pcr == 0 &&
873
874
                p_stream->i_pcr  > 3 * DEFAULT_PTS_DELAY )
            {
gbazin's avatar
   
gbazin committed
875

876
                /* Call the pace control */
877
                es_out_Control( p_demux->out, ES_OUT_SET_PCR,
878
                                VLC_TS_0 + p_stream->i_pcr );
879
            }
gbazin's avatar
   
gbazin committed
880

881
            p_stream->i_previous_pcr = p_stream->i_pcr;
gbazin's avatar
   
gbazin committed
882

gbazin's avatar
   
gbazin committed
883
            /* The granulepos is the end date of the sample */
Gregory Maxwell's avatar
Gregory Maxwell committed
884
            i_pts = p_stream->i_pcr;
gbazin's avatar
   
gbazin committed
885
        }
gbazin's avatar
   
gbazin committed
886
    }
gbazin's avatar
   
gbazin committed
887

gbazin's avatar
   
gbazin committed
888
    /* Convert the granulepos into the next pcr */
889
    i_interpolated_pts = p_stream->i_interpolated_pcr;
gbazin's avatar
   
gbazin committed
890
    Ogg_UpdatePCR( p_stream, p_oggpacket );
gbazin's avatar
   
gbazin committed
891

892
893
    /* SPU streams are typically discontinuous, do not mind large gaps */
    if( p_stream->fmt.i_cat != SPU_ES )
gbazin's avatar
   
gbazin committed
894
    {
895
        if( p_stream->i_pcr >= 0 )
896
        {
897
898
899
900
901
            /* This is for streams where the granulepos of the header packets
             * doesn't match these of the data packets (eg. ogg web radios). */
            if( p_stream->i_previous_pcr == 0 &&
                p_stream->i_pcr  > 3 * DEFAULT_PTS_DELAY )
            {
902

903
                /* Call the pace control */
904
                es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_stream->i_pcr );
905
            }
906
        }
gbazin's avatar
   
gbazin committed
907
    }
gbazin's avatar
   
gbazin committed
908

909
910
    if( p_stream->fmt.i_codec != VLC_CODEC_VORBIS &&
        p_stream->fmt.i_codec != VLC_CODEC_SPEEX &&
Gregory Maxwell's avatar
Gregory Maxwell committed
911
        p_stream->fmt.i_codec != VLC_CODEC_OPUS &&
912
        p_stream->fmt.i_codec != VLC_CODEC_FLAC &&
gbazin's avatar
   
gbazin committed
913
914
915
        p_stream->i_pcr >= 0 )
    {
        p_stream->i_previous_pcr = p_stream->i_pcr;
gbazin's avatar
   
gbazin committed
916
917

        /* The granulepos is the start date of the sample */
918
        i_pts = p_stream->i_pcr;
gbazin's avatar
   
gbazin committed
919
    }
gbazin's avatar
   
gbazin committed
920

gbazin's avatar
   
gbazin committed
921
    if( !b_selected )
gbazin's avatar
   
gbazin committed
922
923
924
925
926
927
    {
        /* This stream isn't currently selected so we don't need to decode it,
         * but we did need to store its pcr as it might be selected later on */
        return;
    }

928
    if( !( p_block = block_Alloc( p_oggpacket->bytes ) ) ) return;
gbazin's avatar
   
gbazin committed
929

salsaman's avatar
salsaman committed
930

.'s avatar
. committed
931
    /* may need to preroll after a seek */
salsaman's avatar
salsaman committed
932
933
    if ( p_stream->i_skip_frames > 0 )
    {
.'s avatar
. committed
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
        if( p_stream->fmt.i_codec == VLC_CODEC_OPUS )
        {
            int duration;
            duration = Ogg_OpusPacketDuration( p_stream, p_oggpacket );
            if( p_stream->i_skip_frames > duration )
            {
                p_block->i_flags |= BLOCK_FLAG_PREROLL;
                p_block->i_nb_samples = 0;
                p_stream->i_skip_frames -= duration;
            }
            else
            {
                p_block->i_nb_samples = duration - p_stream->i_skip_frames;
                if( p_stream->i_previous_granulepos >=
                    p_block->i_nb_samples + p_stream->i_pre_skip )
                {
                    i_pts = VLC_TS_0 + (p_stream->i_previous_granulepos
                        - p_block->i_nb_samples - p_stream->i_pre_skip) *
                        INT64_C(1000000) / p_stream->f_rate;
                }
                p_stream->i_skip_frames = 0;
            }
        }
        else
        {
            p_block->i_flags |= BLOCK_FLAG_PREROLL;
            p_stream->i_skip_frames--;
        }
salsaman's avatar
salsaman committed
962
    }
.'s avatar
. committed
963
964
    else if( p_stream->fmt.i_codec == VLC_CODEC_OPUS )
        p_block->i_nb_samples = Ogg_OpusPacketDuration( p_stream, p_oggpacket );
salsaman's avatar
salsaman committed
965
966


967
    /* Normalize PTS */
.'s avatar
. committed
968
969
970
    if( i_pts == VLC_TS_INVALID ) i_pts = VLC_TS_0;
    else if( i_pts == -1 && i_interpolated_pts == VLC_TS_INVALID )
        i_pts = VLC_TS_0;
971
972
    else if( i_pts == -1 && (p_stream->fmt.i_cat == VIDEO_ES || p_stream->fmt.i_codec == VLC_CODEC_OPUS) )
        i_pts = i_interpolated_pts; /* FIXME : why is this incorrect for vorbis? */
973
    else if( i_pts == -1 ) i_pts = VLC_TS_INVALID;
974

gbazin's avatar
   
gbazin committed
975
    if( p_stream->fmt.i_cat == AUDIO_ES )
.'s avatar
. committed
976
    {
gbazin's avatar
   
gbazin committed
977
        p_block->i_dts = p_block->i_pts = i_pts;
.'s avatar
. committed
978
979
980
        /* Blatant abuse of the i_length field. */
        p_block->i_length = p_stream->i_end_trim;
    }
gbazin's avatar
   
gbazin committed
981
982
    else if( p_stream->fmt.i_cat == SPU_ES )
    {
983
984
        p_block->i_dts = p_block->i_pts = i_pts;
        p_block->i_length = 0;
gbazin's avatar
   
gbazin committed
985
    }
986
    else if( p_stream->fmt.i_codec == VLC_CODEC_THEORA )
ogg.k.ogg.k's avatar
ogg.k.ogg.k committed
987
    {
gbazin's avatar
   
gbazin committed
988
        p_block->i_dts = p_block->i_pts = i_pts;
ogg.k.ogg.k's avatar
ogg.k.ogg.k committed
989
990
991
992
993
        if( (p_oggpacket->granulepos & ((1<<p_stream->i_granule_shift)-1)) == 0 )
        {
            p_block->i_flags |= BLOCK_FLAG_TYPE_I;
        }
    }
994
    else if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC )
995
    {
996
997
998
999
1000
1001
        ogg_int64_t dts = p_oggpacket->granulepos >> 31;
        ogg_int64_t delay = (p_oggpacket->granulepos >> 9) & 0x1fff;

        uint64_t u_pnum = dts + delay;

        p_block->i_dts = p_stream->i_pcr;
1002
        p_block->i_pts = VLC_TS_INVALID;
1003
        /* NB, OggDirac granulepos values are in units of 2*picturerate */
salsaman's avatar
salsaman committed
1004
1005

        /* granulepos for dirac is possibly broken, this value should be ignored */
1006
1007
        if( -1 != p_oggpacket->granulepos )
            p_block->i_pts = u_pnum * INT64_C(1000000) / p_stream->f_rate / 2;
1008
    }
gbazin's avatar
   
gbazin committed
1009
1010
1011
    else
    {
        p_block->i_dts = i_pts;
1012
        p_block->i_pts = VLC_TS_INVALID;
gbazin's avatar
   
gbazin committed
1013
    }
gbazin's avatar
   
gbazin committed
1014

1015
1016
    if( p_stream->fmt.i_codec != VLC_CODEC_VORBIS &&
        p_stream->fmt.i_codec != VLC_CODEC_SPEEX &&