ogg.c 118 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>
34
#include <vlc_access.h>
zorglub's avatar
zorglub committed
35
#include <vlc_demux.h>
36
37
#include <vlc_meta.h>
#include <vlc_input.h>
gbazin's avatar
   
gbazin committed
38
39
40

#include <ogg/ogg.h>

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

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

54
55
56
57
58
59
60
61
62
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 ()
63

gbazin's avatar
   
gbazin committed
64
65

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

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

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

84
typedef struct
gbazin's avatar
   
gbazin committed
85
86
87
88
89
90
91
92
93
94
95
96
{
    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;
97
    ogg_int16_t padding;
gbazin's avatar
   
gbazin committed
98
99
100
101

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

108
109
110
111
#define VORBIS_HEADER_IDENTIFICATION 1
#define VORBIS_HEADER_COMMENT 2
#define VORBIS_HEADER_SETUP 3

gbazin's avatar
   
gbazin committed
112
113
114
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
115
116
static int  Demux  ( demux_t * );
static int  Control( demux_t *, int, va_list );
gbazin's avatar
   
gbazin committed
117
118

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

125
static void Ogg_CreateES( demux_t *p_demux );
126
127
128
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
129

130
131
132
/* */
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 );
133
static void Ogg_ResetStream( logical_stream_t *p_stream );
134

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 );
Laurent Aimar's avatar
Laurent Aimar committed
137

138
/* Logical bitstream headers */
139
140
141
static bool Ogg_ReadTheoraHeader( logical_stream_t *, ogg_packet * );
static bool Ogg_ReadVorbisHeader( logical_stream_t *, ogg_packet * );
static bool Ogg_ReadSpeexHeader( logical_stream_t *, ogg_packet * );
142
static void Ogg_ReadOpusHeader( logical_stream_t *, ogg_packet * );
143
144
static bool Ogg_ReadKateHeader( logical_stream_t *, ogg_packet * );
static bool Ogg_ReadFlacHeader( demux_t *, logical_stream_t *, ogg_packet * );
145
static void Ogg_ReadAnnodexHeader( demux_t *, logical_stream_t *, ogg_packet * );
146
static bool Ogg_ReadDiracHeader( logical_stream_t *, ogg_packet * );
147
static bool Ogg_ReadVP8Header( demux_t *, logical_stream_t *, ogg_packet * );
148
149
150
151
152
153
154
static void Ogg_ReadSkeletonHeader( demux_t *, logical_stream_t *, ogg_packet * );

/* Skeleton */
static void Ogg_ReadSkeletonBones( demux_t *, ogg_packet * );
static void Ogg_ReadSkeletonIndex( demux_t *, ogg_packet * );
static void Ogg_FreeSkeleton( ogg_skeleton_t * );
static void Ogg_ApplySkeleton( logical_stream_t * );
155

156
157
158
159
160
161
/* Special decoding */
static void Ogg_CleanSpecificData( logical_stream_t * );
#ifdef HAVE_LIBVORBIS
static void Ogg_DecodeVorbisHeader( logical_stream_t *, ogg_packet *, int );
#endif

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
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];
}

190
191
192
193
/* Special TS value: don't send or derive any pts/pcr from it.
   Represents TS state prior first known valid timestamp */
#define VLC_TS_UNKNOWN (VLC_TS_INVALID - 1)

gbazin's avatar
   
gbazin committed
194
/*****************************************************************************
195
 * Open: initializes ogg demux structures
gbazin's avatar
   
gbazin committed
196
 *****************************************************************************/
197
static int Open( vlc_object_t * p_this )
gbazin's avatar
   
gbazin committed
198
{
199
    demux_t *p_demux = (demux_t *)p_this;
200
    demux_sys_t    *p_sys;
201
    const uint8_t  *p_peek;
gbazin's avatar
   
gbazin committed
202

203
    /* Check if we are dealing with an ogg stream */
204
    if( stream_Peek( p_demux->s, &p_peek, 4 ) < 4 ) return VLC_EGENERIC;
205
    if( !p_demux->b_force && memcmp( p_peek, "OggS", 4 ) )
206
207
208
    {
        return VLC_EGENERIC;
    }
gbazin's avatar
   
gbazin committed
209

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
210
211
    /* */
    p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) );
212
213
    if( !p_sys )
        return VLC_ENOMEM;
214

215
    p_sys->i_length = -1;
216
    p_sys->b_preparsing_done = false;
217

218
219
    stream_Control( p_demux->s, ACCESS_GET_PTS_DELAY, & p_sys->i_access_delay );

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
220
221
222
223
    /* Set exported functions */
    p_demux->pf_demux = Demux;
    p_demux->pf_control = Control;

224
225
    /* Initialize the Ogg physical bitstream parser */
    ogg_sync_init( &p_sys->oy );
gbazin's avatar
   
gbazin committed
226

Laurent Aimar's avatar
Laurent Aimar committed
227
    /* */
228
    TAB_INIT( p_sys->i_seekpoints, p_sys->pp_seekpoints );
Laurent Aimar's avatar
Laurent Aimar committed
229

230
231
232
233

    while ( !p_sys->b_preparsing_done && p_demux->pf_demux( p_demux ) > 0 )
    {}

gbazin's avatar
   
gbazin committed
234
235
236
    return VLC_SUCCESS;
}

237
238
239
240
241
/*****************************************************************************
 * Close: frees unused data
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
242
243
    demux_t *p_demux = (demux_t *)p_this;
    demux_sys_t *p_sys = p_demux->p_sys  ;
244
245
246
247

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

248
    Ogg_EndOfStream( p_demux );
249

250
251
252
    if( p_sys->p_old_stream )
        Ogg_LogicalStreamDelete( p_demux, p_sys->p_old_stream );

253
254
255
256
257
258
259
260
    free( p_sys );
}

/*****************************************************************************
 * Demux: reads and demuxes data packets
 *****************************************************************************
 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
 *****************************************************************************/
261
static int Demux( demux_t * p_demux )
262
{
263
    demux_sys_t *p_sys = p_demux->p_sys;
264
265
    ogg_packet  oggpacket;
    int         i_stream;
salsaman's avatar
salsaman committed
266
    bool b_skipping = false;
267
    bool b_canseek;
268

269
    int i_active_streams = p_sys->i_streams;
270
    for ( int i=0; i < p_sys->i_streams; i++ )
271
272
273
274
    {
        if ( p_sys->pp_stream[i]->b_finished )
            i_active_streams--;
    }
275

276
    if ( i_active_streams == 0 )
277
    {
278
        if ( p_sys->i_streams ) /* All finished */
279
        {
280
            msg_Dbg( p_demux, "end of a group of logical streams" );
281
282
283
284
285
286
287
            /* 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 );
            }
288
            Ogg_EndOfStream( p_demux );
289
            p_sys->b_chained_boundary = true;
290
291
        }

292
293
        if( Ogg_BeginningOfStream( p_demux ) != VLC_SUCCESS )
            return 0;
294

295
        msg_Dbg( p_demux, "beginning of a group of logical streams" );
296
297
298
299
300
301
302
303
304

        if ( !p_sys->b_chained_boundary )
        {
            /* Find the real duration */
            stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
            if ( b_canseek )
                Oggseek_ProbeEnd( p_demux );
        }
        else
305
306
307
        {
            p_sys->b_chained_boundary = false;
        }
308
309
    }

310
    if ( p_sys->b_preparsing_done && !p_sys->b_es_created )
311
    {
312
313
        Ogg_CreateES( p_demux );
        p_sys->b_es_created = true;
314
315
    }

316
    /*
317
318
319
320
321
322
323
324
325
326
327
328
     * 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.
329
     */
330
    if( !p_sys->b_page_waiting)
331
    {
332
333
334
        /*
         * Demux an ogg page from the stream
         */
salsaman's avatar
salsaman committed
335
        if( Ogg_ReadPage( p_demux, &p_sys->current_page ) != VLC_SUCCESS )
336
337
            return 0; /* EOF */
        /* Test for End of Stream */
338
339
340
341
        if( ogg_page_eos( &p_sys->current_page ) )
        {
            /* If we delayed restarting encoders/SET_ES_FMT for more
             * skeleton provided configuration */
342
            if ( p_sys->p_skelstream )
343
            {
344
                if ( p_sys->p_skelstream->i_serial_no == ogg_page_serialno(&p_sys->current_page) )
345
                {
346
347
348
                    msg_Dbg( p_demux, "End of Skeleton" );
                    p_sys->b_preparsing_done = true;
                    for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
349
                    {
350
                        logical_stream_t *p_stream = p_sys->pp_stream[i_stream];
351
                        Ogg_ApplySkeleton( p_stream );
352
353
354
355
                    }
                }
            }

356
357
358
359
360
361
362
363
            for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
            {
                if ( p_sys->pp_stream[i_stream]->i_serial_no == ogg_page_serialno( &p_sys->current_page ) )
                {
                    p_sys->pp_stream[i_stream]->b_finished = true;
                    break;
                }
            }
364
        }
365
    }
366

367
368
369
370
371
    b_skipping = false;
    for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
    {
        b_skipping |= p_sys->pp_stream[i_stream]->i_skip_frames;
    }
372
373
374
375
376

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

377
378
379
        /* if we've just pulled page, look for the right logical stream */
        if( !p_sys->b_page_waiting )
        {
380
            if( p_sys->i_streams == 1 &&
salsaman's avatar
salsaman committed
381
                ogg_page_serialno( &p_sys->current_page ) != p_stream->os.serialno )
382
383
            {
                msg_Err( p_demux, "Broken Ogg stream (serialno) mismatch" );
384
                Ogg_ResetStream( p_stream );
salsaman's avatar
salsaman committed
385
                ogg_stream_reset_serialno( &p_stream->os, ogg_page_serialno( &p_sys->current_page ) );
386
387
            }

388
            /* Does fail if serialno differs */
salsaman's avatar
salsaman committed
389
            if( ogg_stream_pagein( &p_stream->os, &p_sys->current_page ) != 0 )
salsaman's avatar
salsaman committed
390
            {
391
                continue;
salsaman's avatar
salsaman committed
392
            }
393
        }
394

395
        /* clear the finished flag if pages after eos (ex: after a seek) */
396
397
        if ( ! ogg_page_eos( &p_sys->current_page ) && p_sys->p_skelstream != p_stream )
            p_stream->b_finished = false;
398

399
400
        DemuxDebug(
            if ( p_stream->fmt.i_cat == VIDEO_ES )
401
                msg_Dbg(p_demux, "DEMUX READ pageno %ld g%"PRId64" (%d packets) cont %d %ld bytes",
402
403
404
405
                    ogg_page_pageno( &p_sys->current_page ),
                    ogg_page_granulepos( &p_sys->current_page ),
                    ogg_page_packets( &p_sys->current_page ),
                    ogg_page_continued(&p_sys->current_page),
406
                    p_sys->current_page.body_len )
407
408
        );

409
410
411
412
413
414
415
416
417
        if ( p_stream->i_pcr < VLC_TS_0 && ogg_page_granulepos( &p_sys->current_page ) > 0 )
        {
            // PASS 0
            if ( p_stream->fmt.i_codec == VLC_CODEC_OPUS ||
                 p_stream->fmt.i_codec == VLC_CODEC_VORBIS ||
                 p_stream->fmt.i_cat == VIDEO_ES )
            {
                assert( p_stream->p_prepcr_blocks == NULL );
                p_stream->i_prepcr_blocks = 0;
418
                p_stream->p_prepcr_blocks = malloc( sizeof(block_t *) * ogg_page_packets( &p_sys->current_page ) );
419
420
421
            }
        }

422
423
424
        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
425
            if( p_stream->i_secondary_header_packets > 0 )
426
            {
427
                if( p_stream->fmt.i_codec == VLC_CODEC_THEORA &&
428
                        oggpacket.bytes >= 7 &&
429
                        ! memcmp( oggpacket.packet, "\x80theora", 7 ) )
430
                {
431
                    Ogg_ReadTheoraHeader( p_stream, &oggpacket );
Laurent Aimar's avatar
Laurent Aimar committed
432
                    p_stream->i_secondary_header_packets = 0;
433
                }
434
                else if( p_stream->fmt.i_codec == VLC_CODEC_VORBIS &&
435
                        oggpacket.bytes >= 7 &&
436
                        ! memcmp( oggpacket.packet, "\x01vorbis", 7 ) )
437
                {
438
                    Ogg_ReadVorbisHeader( p_stream, &oggpacket );
Laurent Aimar's avatar
Laurent Aimar committed
439
                    p_stream->i_secondary_header_packets = 0;
440
                }
441
                else if( p_stream->fmt.i_codec == VLC_CODEC_CMML )
442
                {
Laurent Aimar's avatar
Laurent Aimar committed
443
                    p_stream->i_secondary_header_packets = 0;
444
                }
salsaman's avatar
salsaman committed
445
446
447

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

salsaman's avatar
salsaman committed
450
            /* If any streams have i_skip_frames, only decode (pre-roll)
451
452
453
             *  for those streams, but don't skip headers */
            if ( b_skipping && p_stream->i_skip_frames == 0
                 && p_stream->i_secondary_header_packets ) continue;
salsaman's avatar
salsaman committed
454

455
456
            if( p_stream->b_reinit )
            {
457
458
                p_stream->b_reinit = false;
                if( p_stream->fmt.i_codec == VLC_CODEC_OPUS )
459
                {
460
                    p_stream->i_skip_frames = p_stream->i_pre_skip;
461
                }
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
            }

            Ogg_DecodePacket( p_demux, p_stream, &oggpacket );

        }

        if ( p_stream->p_prepcr_blocks )
        {
            int64_t pagestamp = Oggseek_GranuleToAbsTimestamp( p_stream, ogg_page_granulepos(  &p_sys->current_page ), false );
            p_stream->i_previous_pcr = pagestamp;
#ifdef HAVE_LIBVORBIS
            int i_prev_blocksize = 0;
#endif
            // PASS 1
            for( int i=0; i<p_stream->i_prepcr_blocks; i++ )
            {
                block_t *p_block = p_stream->p_prepcr_blocks[i];
                ogg_packet dumb_packet;
                dumb_packet.bytes = p_block->i_buffer;
                dumb_packet.packet = p_block->p_buffer;
                int i_duration;
483

484
                switch( p_stream->fmt.i_codec )
485
                {
486
487
488
489
490
491
                case VLC_CODEC_OPUS:
                    i_duration = Ogg_OpusPacketDuration( p_stream, &dumb_packet );
                    p_block->i_nb_samples = i_duration;
                    break;
#ifdef HAVE_LIBVORBIS
                case VLC_CODEC_VORBIS:
492
                {
493
494
495
496
497
498
499
500
501
502
                    long i_blocksize = vorbis_packet_blocksize(
                                p_stream->special.vorbis.p_info, &dumb_packet );
                    if ( i_prev_blocksize )
                        i_duration = ( i_blocksize + i_prev_blocksize ) / 4;
                    else
                        i_duration = i_blocksize / 2;
                    i_prev_blocksize = i_blocksize;
                    p_block->i_nb_samples = i_duration;
                }
#endif
503
                }
504
            }
505

506
507
508
509
510
511
            // PASS 2
            bool b_fixed = false;
            for( int i=p_stream->i_prepcr_blocks - 1; i>=0; i-- )
            {
                block_t *p_block = p_stream->p_prepcr_blocks[i];
                switch( p_stream->fmt.i_codec )
512
                {
513
514
515
516
                case VLC_CODEC_OPUS:
                case VLC_CODEC_VORBIS:
                    pagestamp -= CLOCK_FREQ * p_block->i_nb_samples / p_stream->f_rate;
                    if ( pagestamp < 0 )
517
                    {
518
519
                        p_block->i_pts = VLC_TS_INVALID;
                        p_block->i_flags |= BLOCK_FLAG_PREROLL;
520
521
                    }
                    else
522
523
524
525
526
                        p_block->i_pts = VLC_TS_0 + p_sys->i_nzpcr_offset + pagestamp;
                    b_fixed = true;
                    break;
                default:
                    if ( p_stream->fmt.i_cat == VIDEO_ES )
527
                    {
528
529
530
                        pagestamp = pagestamp - ( CLOCK_FREQ / p_stream->f_rate );
                        p_block->i_pts = p_sys->i_nzpcr_offset + pagestamp;
                        b_fixed = true;
531
532
533
534
                    }
                }
            }

535
            if ( b_fixed )
536
            {
537
538
539
540
541
                if ( pagestamp < 0 ) pagestamp = 0;
                p_stream->i_pcr = VLC_TS_0 + pagestamp;
                p_stream->i_pcr += p_sys->i_nzpcr_offset;
                p_stream->i_previous_granulepos = ogg_page_granulepos( &p_sys->current_page );
            }
542

543
544
            FREENULL( p_stream->p_prepcr_blocks );
            p_stream->i_prepcr_blocks = 0;
545

546
            Ogg_SendOrQueueBlocks( p_demux, p_stream, NULL );
547

548
        }
549

550
551
552
553
554
555
556
        int64_t i_pagestamp = Oggseek_GranuleToAbsTimestamp( p_stream,
                            ogg_page_granulepos( &p_sys->current_page ), false );
        if ( i_pagestamp > -1 )
        {
            p_stream->i_pcr = VLC_TS_0 + i_pagestamp;
            p_stream->i_pcr += p_sys->i_nzpcr_offset;
        }
557

558
559
        if( !p_sys->b_page_waiting )
            break;
560
561
    }

562
563
564
    /* if a page was waiting, it's now processed */
    p_sys->b_page_waiting = false;

565
566
567
568
    if ( p_sys->p_skelstream && !p_sys->p_skelstream->b_finished )
        p_sys->b_preparsing_done = false;
    else
        p_sys->b_preparsing_done = true;
569

570
571
572
573
    /* We will consider the lowest PCR among tracks, because the audio core badly
     * handles PCR rewind (mute)
     */
    mtime_t i_pcr_candidate = VLC_TS_INVALID;
Laurent Aimar's avatar
Laurent Aimar committed
574
    for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
575
576
577
    {
        logical_stream_t *p_stream = p_sys->pp_stream[i_stream];

578
        if ( p_sys->b_preparsing_done && p_stream->b_initializing )
579
580
581
582
583
        {
            /* We have 1 or more streams needing more than 1 page for preparsing */
            p_sys->b_preparsing_done = false;
        }

584
585
        if( p_stream->fmt.i_cat == SPU_ES )
            continue;
586
        if( p_stream->i_pcr < VLC_TS_0 )
587
588
            continue;
        if ( p_stream->b_finished || p_stream->b_initializing )
589
            continue;
590
591
        if ( p_stream->p_preparse_block )
            continue;
592
        if( i_pcr_candidate < VLC_TS_0
593
            || p_stream->i_pcr <= i_pcr_candidate )
594
        {
595
            i_pcr_candidate = p_stream->i_pcr;
596
        }
597
598
    }

599
600
    if ( i_pcr_candidate > VLC_TS_INVALID && p_sys->i_pcr != i_pcr_candidate )
    {
601
602
603
604
605
606
607
608
609
610
611
        if ( p_sys->i_streams == 1 && p_sys->i_access_delay )
        {
            int64_t i_pcr_jitter = i_pcr_candidate - p_sys->i_pcr;
            if ( i_pcr_jitter > p_sys->i_pcr_jitter )
            {
                p_sys->i_pcr_jitter = i_pcr_jitter;
                if ( p_sys->i_access_delay < i_pcr_jitter )
                    msg_Warn( p_demux, "Consider increasing access caching variable from %"PRId64" to >%"PRId64,
                              p_sys->i_access_delay / 1000, i_pcr_jitter / 1000 );
            }
        }
612
613
614
615

        if( ! b_skipping && p_sys->b_preparsing_done )
        {
            p_sys->i_pcr = i_pcr_candidate;
616
            es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr );
617
        }
618
    }
619
620
621
622

    return 1;
}

623
static void Ogg_ResetStream( logical_stream_t *p_stream )
624
{
625
626
#ifdef HAVE_LIBVORBIS
    if ( p_stream->fmt.i_codec == VLC_CODEC_VORBIS )
627
    {
628
        p_stream->special.vorbis.i_prev_blocksize = 0;
629
    }
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
#endif
    /* we'll trash all the data until we find the next pcr */
    p_stream->b_reinit = true;
    p_stream->i_pcr = VLC_TS_UNKNOWN;
    p_stream->i_previous_granulepos = -1;
    p_stream->i_previous_pcr = VLC_TS_UNKNOWN;
    ogg_stream_reset( &p_stream->os );
    FREENULL( p_stream->p_prepcr_blocks );
    p_stream->i_prepcr_blocks = 0;
}

static void Ogg_ResetStreamsHelper( demux_sys_t *p_sys )
{
    for( int i = 0; i < p_sys->i_streams; i++ )
        Ogg_ResetStream( p_sys->pp_stream[i] );

646
    ogg_sync_reset( &p_sys->oy );
647
    p_sys->i_pcr = VLC_TS_UNKNOWN;
648
649
}

650
651
652
653
654
655
656
static logical_stream_t * Ogg_GetSelectedStream( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    logical_stream_t *p_stream = NULL;
    for( int i=0; i<p_sys->i_streams; i++ )
    {
        logical_stream_t *p_candidate = p_sys->pp_stream[i];
657
        if ( !p_candidate->p_es ) continue;
658

659
        bool b_selected = false;
660
        es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE,
661
                        p_candidate->p_es, &b_selected );
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
        if ( !b_selected ) continue;

        if ( !p_stream && p_candidate->fmt.i_cat == AUDIO_ES )
        {
            p_stream = p_candidate;
            continue; /* Try to find video anyway */
        }

        if ( p_candidate->fmt.i_cat == VIDEO_ES )
        {
            p_stream = p_candidate;
            break;
        }
    }
    return p_stream;
}

679
680
681
/*****************************************************************************
 * Control:
 *****************************************************************************/
682
static int Control( demux_t *p_demux, int i_query, va_list args )
683
{
684
    demux_sys_t *p_sys  = p_demux->p_sys;
Laurent Aimar's avatar
Laurent Aimar committed
685
    vlc_meta_t *p_meta;
686
687
688
    int64_t *pi64, i64;
    double *pf, f;
    bool *pb_bool, b;
689
690
691

    switch( i_query )
    {
Laurent Aimar's avatar
Laurent Aimar committed
692
693
694
695
696
697
        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;

698
        case DEMUX_HAS_UNSUPPORTED_META:
699
700
            pb_bool = (bool*)va_arg( args, bool* );
            *pb_bool = true;
701
702
            return VLC_SUCCESS;

703
704
705
706
707
708
        case DEMUX_GET_TIME:
            pi64 = (int64_t*)va_arg( args, int64_t * );
            *pi64 = p_sys->i_pcr;
            return VLC_SUCCESS;

        case DEMUX_SET_TIME:
709
710
711
712
713
714
715
716
717
718
            i64 = (int64_t)va_arg( args, int64_t );
            logical_stream_t *p_stream = Ogg_GetSelectedStream( p_demux );
            if ( !p_stream )
            {
                msg_Err( p_demux, "No selected seekable stream found" );
                return VLC_EGENERIC;
            }
            stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b );
            if ( Oggseek_BlindSeektoAbsoluteTime( p_demux, p_stream, i64, b ) )
            {
719
                Ogg_ResetStreamsHelper( p_sys );
720
721
722
723
724
725
                es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
                                VLC_TS_0 + i64 );
                return VLC_SUCCESS;
            }
            else
                return VLC_EGENERIC;
726

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
727
728
729
730
731
732
733
734
735
736
        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;
737
            *ppp_attach = xmalloc( sizeof(input_attachment_t*) * p_sys->i_attachments );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
738
739
740
741
742
            for( int i = 0; i < p_sys->i_attachments; i++ )
                (*ppp_attach)[i] = vlc_input_attachment_Duplicate( p_sys->attachments[i] );
            return VLC_SUCCESS;
        }

743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
        case DEMUX_GET_POSITION:
            pf = (double*)va_arg( args, double * );
            if( p_sys->i_length > 0 )
            {
                *pf =  (double) p_sys->i_pcr /
                       (double) ( p_sys->i_length * (mtime_t)1000000 );
            }
            else if( stream_Size( p_demux->s ) > 0 )
            {
                i64 = stream_Tell( p_demux->s );
                *pf = (double) i64 / stream_Size( p_demux->s );
            }
            else *pf = 0.0;
            return VLC_SUCCESS;

758
        case DEMUX_SET_POSITION:
759
760
761
            /* 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 */
762
            for ( int i=0; i< p_sys->i_streams; i++ )
763
            {
764
765
                if ( p_sys->pp_stream[i]->b_initializing )
                    return VLC_EGENERIC;
766
767
            }

768
            p_stream = Ogg_GetSelectedStream( p_demux );
769
770
771
772
773
774
775
776
777
778
779
            if ( !p_stream )
            {
                msg_Err( p_demux, "No selected seekable stream found" );
                return VLC_EGENERIC;
            }

            stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b );

            f = (double)va_arg( args, double );
            if ( p_sys->i_length <= 0 || !b /* || ! ACCESS_CAN_FASTSEEK */ )
            {
780
                Ogg_ResetStreamsHelper( p_sys );
781
782
783
784
785
                Oggseek_BlindSeektoPosition( p_demux, p_stream, f, b );
                return VLC_SUCCESS;
            }

            assert( p_sys->i_length > 0 );
Tristan Matthews's avatar
Tristan Matthews committed
786
            i64 = CLOCK_FREQ * p_sys->i_length * f;
787
            Ogg_ResetStreamsHelper( p_sys );
788
789
790
791
792
793
794
795
796
            if ( Oggseek_SeektoAbsolutetime( p_demux, p_stream, i64 ) >= 0 )
            {
                es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
                                VLC_TS_0 + i64 );
                return VLC_SUCCESS;
            }

            return VLC_EGENERIC;

797
798
799
800
801
802
803
804
        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;

805
806
807
808
809
810
811
812
813
814
        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;
815
                *ppp_title = malloc( sizeof( input_title_t* ) );
816
817
818
                input_title_t *p_title = (*ppp_title)[0] = vlc_input_title_New();
                for( int i = 0; i < p_sys->i_seekpoints; i++ )
                {
819
820
821
                    seekpoint_t *p_seekpoint_copy = vlc_seekpoint_Duplicate( p_sys->pp_seekpoints[i] );
                    if ( likely( p_seekpoint_copy ) )
                        TAB_APPEND( p_title->i_seekpoint, p_title->seekpoint, p_seekpoint_copy );
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
                }
                *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 );
838
            if( i_seekpoint > p_sys->i_seekpoints )
839
                return VLC_EGENERIC;
840

841
842
843
844
845
846
            for ( int i=0; i< p_sys->i_streams; i++ )
            {
                if ( p_sys->pp_stream[i]->b_initializing )
                    return VLC_EGENERIC;
            }

847
848
849
850
            i64 = p_sys->pp_seekpoints[i_seekpoint]->i_time_offset;

            p_stream = Ogg_GetSelectedStream( p_demux );
            if ( !p_stream )
Ludovic Fauvet's avatar
Ludovic Fauvet committed
851
            {
852
                msg_Err( p_demux, "No selected seekable stream found" );
Ludovic Fauvet's avatar
Ludovic Fauvet committed
853
854
855
                return VLC_EGENERIC;
            }

856
857
            stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b );
            if ( Oggseek_BlindSeektoAbsoluteTime( p_demux, p_stream, i64, b ) )
858
            {
859
                Ogg_ResetStreamsHelper( p_sys );
860
861
862
863
                es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
                                VLC_TS_0 + i64 );
                p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
                p_demux->info.i_seekpoint = i_seekpoint;
864
                return VLC_SUCCESS;
865
866
            }
            else
867
                return VLC_EGENERIC;
868
        }
869
870

        default:
871
            return demux_vaControlHelper( p_demux->s, 0, -1, p_sys->i_bitrate,
872
                                           1, i_query, args );
873
874
875
    }
}

gbazin's avatar
   
gbazin committed
876
877
878
879
880
881
/****************************************************************************
 * 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.
 ****************************************************************************/
882
static int Ogg_ReadPage( demux_t *p_demux, ogg_page *p_oggpage )
gbazin's avatar
   
gbazin committed
883
{
884
    demux_sys_t *p_ogg = p_demux->p_sys  ;
gbazin's avatar
   
gbazin committed
885
    int i_read = 0;
886
    char *p_buffer;
gbazin's avatar
   
gbazin committed
887
888
889

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

892
        i_read = stream_Read( p_demux->s, p_buffer, OGGSEEK_BYTES_TO_READ );
gbazin's avatar
   
gbazin committed
893
894
895
896
897
898
899
900
901
        if( i_read <= 0 )
            return VLC_EGENERIC;

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

    return VLC_SUCCESS;
}

gbazin's avatar
   
gbazin committed
902
903
904
905
/****************************************************************************
 * Ogg_UpdatePCR: update the PCR (90kHz program clock reference) for the
 *                current stream.
 ****************************************************************************/
906
static void Ogg_UpdatePCR( demux_t *p_demux, logical_stream_t *p_stream,
gbazin's avatar
   
gbazin committed
907
908
                           ogg_packet *p_oggpacket )
{
909
    demux_sys_t *p_ogg = p_demux->p_sys;
.'s avatar
. committed
910
    p_stream->i_end_trim = 0;
911

gbazin's avatar
   
gbazin committed
912
    /* Convert the granulepos into a pcr */
913
914
915
    if ( p_oggpacket->granulepos == 0 )
    {
        /* We're in headers, and we haven't parsed 1st data packet yet */
916
//        p_stream->i_pcr = VLC_TS_UNKNOWN;
917
918
    }
    else if( p_oggpacket->granulepos > 0 )
gbazin's avatar
   
gbazin committed
919
    {
920
        if( p_stream->fmt.i_codec == VLC_CODEC_THEORA ||
921
            p_stream->fmt.i_codec == VLC_CODEC_KATE ||
922
            p_stream->fmt.i_codec == VLC_CODEC_VP8 ||
923
924
            p_stream->fmt.i_codec == VLC_CODEC_DIRAC ||
            (p_stream->b_oggds && p_stream->fmt.i_cat == VIDEO_ES) )
gbazin's avatar
   
gbazin committed
925
        {
926
927
928
            p_stream->i_pcr = VLC_TS_0 + Oggseek_GranuleToAbsTimestamp( p_stream,
                                         p_oggpacket->granulepos, true );
            p_stream->i_pcr += p_ogg->i_nzpcr_offset;
929
        }
930
        else if ( p_stream->i_previous_granulepos > 0 )
931
        {
932
933
934
            ogg_int64_t sample = p_stream->i_previous_granulepos;

            if( p_stream->fmt.i_codec == VLC_CODEC_OPUS && p_oggpacket->e_o_s )
.'s avatar
. committed
935
            {
936
                int duration = Ogg_OpusPacketDuration( p_stream, p_oggpacket );
.'s avatar
. committed
937
938
                if( duration > 0 )
                {
939
940
941
                    ogg_int64_t end_sample = p_oggpacket->granulepos;
                    if( end_sample < ( sample + duration ) )
                        p_stream->i_end_trim = sample + duration - end_sample;
.'s avatar
. committed
942
943
                }
            }
944

.'s avatar
. committed
945
946
947
948
            if (sample >= p_stream->i_pre_skip)
                sample -= p_stream->i_pre_skip;
            else
                sample = 0;
949
950
951

            p_stream->i_pcr =  VLC_TS_0 + sample * CLOCK_FREQ / p_stream->f_rate;
            p_stream->i_pcr += p_ogg->i_nzpcr_offset;
952
        }
gbazin's avatar
   
gbazin committed
953
954

    }
955
    else if ( p_oggpacket->granulepos == -1 )
gbazin's avatar
   
gbazin committed
956
    {
957
        int i_duration;
gbazin's avatar
   
gbazin committed
958
959
        /* no granulepos available, try to interpolate the pcr.
         * If we can't then don't touch the old value. */
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
        if( p_stream->fmt.i_cat == VIDEO_ES && p_stream->i_pcr > VLC_TS_INVALID )
        {
            p_stream->i_pcr += (CLOCK_FREQ / p_stream->f_rate);
        }
#ifdef HAVE_LIBVORBIS
        else if ( p_stream->fmt.i_codec == VLC_CODEC_VORBIS &&
                  p_stream->special.vorbis.p_info &&
                  !p_stream->special.vorbis.b_invalid &&
                  p_stream->i_previous_granulepos > 0 )
        {
            long i_blocksize = vorbis_packet_blocksize(
                        p_stream->special.vorbis.p_info, p_oggpacket );
            if ( p_stream->special.vorbis.i_prev_blocksize )
                i_duration = ( i_blocksize + p_stream->special.vorbis.i_prev_blocksize ) / 4;
            else
                i_duration = i_blocksize / 2;
            p_stream->special.vorbis.i_prev_blocksize = i_blocksize;
            /* duration in samples per channel */
            p_oggpacket->granulepos = p_stream->i_previous_granulepos + i_duration;
            p_stream->i_pcr = p_stream->i_previous_granulepos *
                              CLOCK_FREQ / p_stream->special.vorbis.p_info->rate;
            p_stream->i_pcr += p_ogg->i_nzpcr_offset;
        }
#endif
.'s avatar
. committed
984
        else if( p_stream->fmt.i_codec == VLC_CODEC_OPUS &&
985
                 p_stream->i_previous_granulepos > 0 &&
986
                 ( i_duration =
.'s avatar
. committed
987
988
989
                     Ogg_OpusPacketDuration( p_stream, p_oggpacket ) ) > 0 )
        {
            ogg_int64_t sample;
990
991
            p_oggpacket->granulepos = p_stream->i_previous_granulepos + i_duration;
            sample = p_stream->i_previous_granulepos;
.'s avatar
. committed
992
993
994
995
            if (sample >= p_stream->i_pre_skip)
                sample -= p_stream->i_pre_skip;
            else
                sample = 0;
996
997
998

            p_stream->i_pcr = VLC_TS_0 + sample * CLOCK_FREQ / p_stream->f_rate;
            p_stream->i_pcr += p_ogg->i_nzpcr_offset;
.'s avatar
. committed
999
        }
1000
        else if( p_stream->fmt.i_bitrate && p_stream->i_pcr > VLC_TS_UNKNOWN )
.'s avatar
. committed
1001
        {
1002
1003
            p_stream->i_pcr += ( CLOCK_FREQ * p_oggpacket->bytes /
                                 p_stream->fmt.i_bitrate / 8 );
.'s avatar
. committed
1004
        }
gbazin's avatar
   
gbazin committed
1005
    }
1006

.'s avatar
. committed
1007
    p_stream->i_previous_granulepos = p_oggpacket->granulepos;
gbazin's avatar
   
gbazin committed
1008
1009
}

1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
static void Ogg_SendOrQueueBlocks( demux_t *p_demux, logical_stream_t *p_stream,
                                   block_t *p_block )
{
    demux_sys_t *p_ogg = p_demux->p_sys;
    if ( !p_stream->p_es || p_stream->p_prepcr_blocks || p_stream->i_pcr == VLC_TS_UNKNOWN )
    {
        if ( !p_block ) return;
        if ( p_stream->p_prepcr_blocks )
        {
            assert( p_stream->p_prepcr_blocks );
            p_stream->p_prepcr_blocks[p_stream->i_prepcr_blocks++] = p_block;
        }
        DemuxDebug( msg_Dbg( p_demux, "block prepcr append > pts %"PRId64" spcr %"PRId64" pcr %"PRId64,
                             p_block->i_pts, p_stream->i_pcr, p_ogg->i_pcr ); )
        block_ChainAppend( & p_stream->p_preparse_block, p_block );
    }
    else
    {
        /* Because ES creation is delayed for preparsing */
        mtime_t i_firstpts = VLC_TS_UNKNOWN;
        if ( p_stream->p_preparse_block )
        {
            block_t *temp = p_stream->p_preparse_block;
            while ( temp )
            {
                if ( temp && i_firstpts < VLC_TS_0 )
                    i_firstpts = temp->i_pts;

                block_t *tosend = temp;
                temp = temp->p_next;
                tosend->p_next = NULL;

                DemuxDebug( msg_Dbg( p_demux, "block sent from preparse > pts %"PRId64" spcr %"PRId64" pcr %"PRId64,
                         tosend->i_pts, p_stream->i_pcr, p_ogg->i_pcr ); )
                es_out_Send( p_demux->out, p_stream->p_es, tosend );

                if ( p_ogg->i_pcr < VLC_TS_0 && i_firstpts > VLC_TS_INVALID )
                {
                    p_ogg->i_pcr = i_firstpts;
                    es_out_Control( p_demux->