ogg.c 53.7 KB
Newer Older
Gildas Bazin's avatar
 
Gildas Bazin committed
1
/*****************************************************************************
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
2
 * ogg.c : ogg stream demux module for vlc
Gildas Bazin's avatar
 
Gildas Bazin committed
3
 *****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
4
 * Copyright (C) 2001-2003 VideoLAN
5
 * $Id$
Gildas Bazin's avatar
 
Gildas Bazin 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
 *
Gildas Bazin's avatar
 
Gildas Bazin committed
10 11 12 13
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
Sam Hocevar's avatar
Sam Hocevar committed
14
 *
Gildas Bazin's avatar
 
Gildas Bazin committed
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <vlc/vlc.h>
#include <vlc/input.h>

#include <ogg/ogg.h>

Gildas Bazin's avatar
 
Gildas Bazin committed
33 34
#include "codecs.h"
#include "vlc_bits.h"
Gildas Bazin's avatar
 
Gildas Bazin committed
35

36 37 38 39 40 41 42 43
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );

vlc_module_begin();
    set_description( _("Ogg stream demuxer" ) );
44
    set_capability( "demux2", 50 );
45 46 47 48
    set_callbacks( Open, Close );
    add_shortcut( "ogg" );
vlc_module_end();

Gildas Bazin's avatar
 
Gildas Bazin committed
49 50

/*****************************************************************************
Sam Hocevar's avatar
Sam Hocevar committed
51
 * Definitions of structures and functions used by this plugins
Gildas Bazin's avatar
 
Gildas Bazin committed
52 53 54 55 56
 *****************************************************************************/
typedef struct logical_stream_s
{
    ogg_stream_state os;                        /* logical stream of packets */

Gildas Bazin's avatar
 
Gildas Bazin committed
57 58 59
    es_format_t      fmt;
    es_out_id_t      *p_es;
    double           f_rate;
Gildas Bazin's avatar
 
Gildas Bazin committed
60

Gildas Bazin's avatar
 
Gildas Bazin committed
61 62
    int              i_serial_no;
    int              b_activated;
Gildas Bazin's avatar
 
Gildas Bazin committed
63

Gildas Bazin's avatar
 
Gildas Bazin committed
64 65 66 67 68 69 70
    /* the header of some logical streams (eg vorbis) contain essential
     * data for the decoder. We back them up here in case we need to re-feed
     * them to the decoder. */
    int              b_force_backup;
    int              i_packets_backup;
    ogg_packet       *p_packets_backup;

Gildas Bazin's avatar
 
Gildas Bazin committed
71 72
    /* program clock reference (in units of 90kHz) derived from the previous
     * granulepos */
Gildas Bazin's avatar
 
Gildas Bazin committed
73
    mtime_t          i_pcr;
Gildas Bazin's avatar
 
Gildas Bazin committed
74
    mtime_t          i_interpolated_pcr;
Gildas Bazin's avatar
 
Gildas Bazin committed
75
    mtime_t          i_previous_pcr;
Gildas Bazin's avatar
 
Gildas Bazin committed
76

Gildas Bazin's avatar
 
Gildas Bazin committed
77
    /* Misc */
Gildas Bazin's avatar
 
Gildas Bazin committed
78
    int b_reinit;
Gildas Bazin's avatar
 
Gildas Bazin committed
79
    int i_theora_keyframe_granule_shift;
Gildas Bazin's avatar
 
Gildas Bazin committed
80

81 82 83
    /* for Annodex logical bitstreams */
    int secondary_header_packets;

Gildas Bazin's avatar
 
Gildas Bazin committed
84 85 86 87 88 89 90 91 92
} logical_stream_t;

struct demux_sys_t
{
    ogg_sync_state oy;        /* sync and verify incoming physical bitstream */

    int i_streams;                           /* number of logical bitstreams */
    logical_stream_t **pp_stream;  /* pointer to an array of logical streams */

Gildas Bazin's avatar
 
Gildas Bazin committed
93
    /* program clock reference (in units of 90kHz) derived from the pcr of
Gildas Bazin's avatar
 
Gildas Bazin committed
94
     * the sub-streams */
Gildas Bazin's avatar
 
Gildas Bazin committed
95
    mtime_t i_pcr;
Gildas Bazin's avatar
 
Gildas Bazin committed
96 97

    /* stream state */
Gildas Bazin's avatar
 
Gildas Bazin committed
98
    int     i_eos;
99 100 101

    /* bitrate */
    int     i_bitrate;
Gildas Bazin's avatar
 
Gildas Bazin committed
102 103
};

Gildas Bazin's avatar
 
Gildas Bazin committed
104 105 106 107 108 109
/* OggDS headers for the new header format (used in ogm files) */
typedef struct stream_header_video
{
    ogg_int32_t width;
    ogg_int32_t height;
} stream_header_video;
Sam Hocevar's avatar
Sam Hocevar committed
110

Gildas Bazin's avatar
 
Gildas Bazin committed
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
typedef struct stream_header_audio
{
    ogg_int16_t channels;
    ogg_int16_t blockalign;
    ogg_int32_t avgbytespersec;
} stream_header_audio;

typedef struct stream_header
{
    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;

    union
    {
        /* Video specific */
        stream_header_video video;
        /* Audio specific */
        stream_header_audio audio;
    } sh;
} stream_header;

141 142
#define OGG_BLOCK_SIZE 4096

Gildas Bazin's avatar
 
Gildas Bazin committed
143 144 145 146 147 148 149
/* 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

Gildas Bazin's avatar
 
Gildas Bazin committed
150 151 152
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
153 154
static int  Demux  ( demux_t * );
static int  Control( demux_t *, int, va_list );
Gildas Bazin's avatar
 
Gildas Bazin committed
155 156

/* Bitstream manipulation */
157
static int  Ogg_ReadPage     ( demux_t *, ogg_page * );
Gildas Bazin's avatar
 
Gildas Bazin committed
158
static void Ogg_UpdatePCR    ( logical_stream_t *, ogg_packet * );
159
static void Ogg_DecodePacket ( demux_t *, logical_stream_t *, ogg_packet * );
Gildas Bazin's avatar
 
Gildas Bazin committed
160

161 162 163
static int Ogg_BeginningOfStream( demux_t *p_demux );
static int Ogg_FindLogicalStreams( demux_t *p_demux );
static void Ogg_EndOfStream( demux_t *p_demux );
Gildas Bazin's avatar
 
Gildas Bazin committed
164

165 166 167 168 169 170 171 172
/* Logical bitstream headers */
static void Ogg_ReadTheoraHeader( logical_stream_t *p_stream,
                                  ogg_packet *p_oggpacket );
static void Ogg_ReadVorbisHeader( logical_stream_t *p_stream,
                                  ogg_packet *p_oggpacket );
static void Ogg_ReadAnnodexHeader( vlc_object_t *, logical_stream_t *p_stream,
                                   ogg_packet *p_oggpacket );

Gildas Bazin's avatar
 
Gildas Bazin committed
173
/*****************************************************************************
174
 * Open: initializes ogg demux structures
Gildas Bazin's avatar
 
Gildas Bazin committed
175
 *****************************************************************************/
176
static int Open( vlc_object_t * p_this )
Gildas Bazin's avatar
 
Gildas Bazin committed
177
{
178
    demux_t *p_demux = (demux_t *)p_this;
179 180
    demux_sys_t    *p_sys;
    uint8_t        *p_peek;
Gildas Bazin's avatar
 
Gildas Bazin committed
181

182 183

    /* Check if we are dealing with an ogg stream */
184
    if( stream_Peek( p_demux->s, &p_peek, 4 ) < 4 )
185
    {
186
        msg_Err( p_demux, "cannot peek" );
Gildas Bazin's avatar
 
Gildas Bazin committed
187
        return VLC_EGENERIC;
188
    }
189
    if( strcmp( p_demux->psz_demux, "ogg" ) && strncmp( p_peek, "OggS", 4 ) )
190
    {
191
        msg_Warn( p_demux, "ogg module discarded (invalid header)" );
192 193
        return VLC_EGENERIC;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
194

195
    /* Set exported functions */
196 197 198
    p_demux->pf_demux = Demux;
    p_demux->pf_control = Control;
    p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
199 200

    memset( p_sys, 0, sizeof( demux_sys_t ) );
201
    p_sys->i_bitrate = 0;
202 203 204 205 206 207 208
    p_sys->pp_stream = NULL;

    /* Begnning of stream, tell the demux to look for elementary streams. */
    p_sys->i_eos = 0;

    /* Initialize the Ogg physical bitstream parser */
    ogg_sync_init( &p_sys->oy );
Gildas Bazin's avatar
 
Gildas Bazin committed
209 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 229 230 231 232 233

    free( p_sys );
}

/*****************************************************************************
 * Demux: reads and demuxes data packets
 *****************************************************************************
 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
 *****************************************************************************/
234
static int Demux( demux_t * p_demux )
235
{
236
    demux_sys_t *p_sys = p_demux->p_sys;
237 238 239 240 241 242 243 244 245
    ogg_page    oggpage;
    ogg_packet  oggpacket;
    int         i_stream;


    if( p_sys->i_eos == p_sys->i_streams )
    {
        if( p_sys->i_eos )
        {
246 247
            msg_Dbg( p_demux, "end of a group of logical streams" );
            Ogg_EndOfStream( p_demux );
248 249 250
        }

        p_sys->i_eos = 0;
251
        if( Ogg_BeginningOfStream( p_demux ) != VLC_SUCCESS ) return 0;
252

253 254
        msg_Dbg( p_demux, "beginning of a group of logical streams" );
        es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
255 256 257 258 259
    }

    /*
     * Demux an ogg page from the stream
     */
260
    if( Ogg_ReadPage( p_demux, &oggpage ) != VLC_SUCCESS )
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
    {
        return 0; /* EOF */
    }

    /* Test for End of Stream */
    if( ogg_page_eos( &oggpage ) ) p_sys->i_eos++;


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

        if( ogg_stream_pagein( &p_stream->os, &oggpage ) != 0 )
            continue;

        while( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
        {
            /* Read info from any secondary header packets, if there are any */
            if( p_stream->secondary_header_packets > 0 )
            {
                if( p_stream->fmt.i_codec == VLC_FOURCC( 't','h','e','o' ) &&
                        oggpacket.bytes >= 7 &&
                        ! strncmp( &oggpacket.packet[1], "theora", 6 ) )
                {
                    Ogg_ReadTheoraHeader( p_stream, &oggpacket );
                    p_stream->secondary_header_packets = 0;
                }
                else if( p_stream->fmt.i_codec == VLC_FOURCC( 'v','o','r','b' ) &&
                        oggpacket.bytes >= 7 &&
                        ! strncmp( &oggpacket.packet[1], "vorbis", 6 ) )
                {
                    Ogg_ReadVorbisHeader( p_stream, &oggpacket );
                    p_stream->secondary_header_packets = 0;
                }
                else if ( p_stream->fmt.i_codec == VLC_FOURCC( 'c','m','m','l' ) )
                {
                    p_stream->secondary_header_packets = 0;
                }

                p_stream->secondary_header_packets--;
            }

            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 )
                {
                    p_stream->b_reinit = 0;
                }
                else
                {
                    p_stream->i_interpolated_pcr = -1;
                    continue;
                }

                /* An Ogg/vorbis packet contains an end date granulepos */
                if( p_stream->fmt.i_codec == VLC_FOURCC( 'v','o','r','b' ) ||
                    p_stream->fmt.i_codec == VLC_FOURCC( 's','p','x',' ' ) ||
                    p_stream->fmt.i_codec == VLC_FOURCC( 'f','l','a','c' ) )
                {
                    if( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
                    {
326
                        Ogg_DecodePacket( p_demux, p_stream, &oggpacket );
327 328 329
                    }
                    else
                    {
330 331
                        es_out_Control( p_demux->out, ES_OUT_SET_PCR,
                                        p_stream->i_pcr );
332 333 334 335 336
                    }
                    continue;
                }
            }

337
            Ogg_DecodePacket( p_demux, p_stream, &oggpacket );
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
        }
        break;
    }

    i_stream = 0; p_sys->i_pcr = -1;
    for( ; i_stream < p_sys->i_streams; i_stream++ )
    {
        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;
    }

    if( p_sys->i_pcr >= 0 )
    {
358
        es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr );
359 360 361 362 363 364 365 366 367
    }


    return 1;
}

/*****************************************************************************
 * Control:
 *****************************************************************************/
368
static int Control( demux_t *p_demux, int i_query, va_list args )
369
{
370
    demux_sys_t *p_sys  = p_demux->p_sys;
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
    int64_t *pi64;
    int i;

    switch( i_query )
    {
        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;

        case DEMUX_SET_POSITION:
            for( 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 = 1;
                p_stream->i_pcr = -1;
                p_stream->i_interpolated_pcr = -1;
                ogg_stream_reset( &p_stream->os );
            }
            ogg_sync_reset( &p_sys->oy );

        default:
398 399
            return demux2_vaControlHelper( p_demux->s, 0, -1, p_sys->i_bitrate,
                                           1, i_query, args );
400 401 402
    }
}

Gildas Bazin's avatar
 
Gildas Bazin committed
403 404 405 406 407 408
/****************************************************************************
 * 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.
 ****************************************************************************/
409
static int Ogg_ReadPage( demux_t *p_demux, ogg_page *p_oggpage )
Gildas Bazin's avatar
 
Gildas Bazin committed
410
{
411
    demux_sys_t *p_ogg = p_demux->p_sys  ;
Gildas Bazin's avatar
 
Gildas Bazin committed
412 413 414 415 416
    int i_read = 0;
    byte_t *p_buffer;

    while( ogg_sync_pageout( &p_ogg->oy, p_oggpage ) != 1 )
    {
417 418 419
        p_buffer = ogg_sync_buffer( &p_ogg->oy, OGG_BLOCK_SIZE );

        i_read = stream_Read( p_demux->s, p_buffer, OGG_BLOCK_SIZE );
Gildas Bazin's avatar
 
Gildas Bazin committed
420 421 422 423 424 425 426 427 428
        if( i_read <= 0 )
            return VLC_EGENERIC;

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

    return VLC_SUCCESS;
}

Gildas Bazin's avatar
 
Gildas Bazin committed
429 430 431 432 433 434 435
/****************************************************************************
 * 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 )
{
Gildas Bazin's avatar
 
Gildas Bazin committed
436
    /* Convert the granulepos into a pcr */
Gildas Bazin's avatar
 
Gildas Bazin committed
437 438
    if( p_oggpacket->granulepos >= 0 )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
439
        if( p_stream->fmt.i_codec != VLC_FOURCC( 't','h','e','o' ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
440
        {
441
            p_stream->i_pcr = p_oggpacket->granulepos * I64C(1000000)
Gildas Bazin's avatar
 
Gildas Bazin committed
442 443 444 445 446 447 448 449 450
                              / p_stream->f_rate;
        }
        else
        {
            ogg_int64_t iframe = p_oggpacket->granulepos >>
              p_stream->i_theora_keyframe_granule_shift;
            ogg_int64_t pframe = p_oggpacket->granulepos -
              ( iframe << p_stream->i_theora_keyframe_granule_shift );

451
            p_stream->i_pcr = ( iframe + pframe ) * I64C(1000000)
Gildas Bazin's avatar
 
Gildas Bazin committed
452 453 454 455 456 457 458
                              / p_stream->f_rate;
        }

        p_stream->i_interpolated_pcr = p_stream->i_pcr;
    }
    else
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
459
        p_stream->i_pcr = -1;
Gildas Bazin's avatar
 
Gildas Bazin committed
460

Gildas Bazin's avatar
 
Gildas Bazin committed
461 462
        /* no granulepos available, try to interpolate the pcr.
         * If we can't then don't touch the old value. */
Gildas Bazin's avatar
 
Gildas Bazin committed
463
        if( p_stream->fmt.i_cat == VIDEO_ES )
Gildas Bazin's avatar
 
Gildas Bazin committed
464
            /* 1 frame per packet */
465
            p_stream->i_interpolated_pcr += (I64C(1000000) / p_stream->f_rate);
Gildas Bazin's avatar
 
Gildas Bazin committed
466
        else if( p_stream->fmt.i_bitrate )
467 468 469
            p_stream->i_interpolated_pcr +=
                ( p_oggpacket->bytes * I64C(1000000) /
                  p_stream->fmt.i_bitrate / 8 );
Gildas Bazin's avatar
 
Gildas Bazin committed
470 471 472
    }
}

Gildas Bazin's avatar
 
Gildas Bazin committed
473 474 475
/****************************************************************************
 * Ogg_DecodePacket: Decode an Ogg packet.
 ****************************************************************************/
476
static void Ogg_DecodePacket( demux_t *p_demux,
Gildas Bazin's avatar
 
Gildas Bazin committed
477 478 479
                              logical_stream_t *p_stream,
                              ogg_packet *p_oggpacket )
{
Gildas Bazin's avatar
 
Gildas Bazin committed
480 481
    block_t *p_block;
    vlc_bool_t b_selected;
Gildas Bazin's avatar
 
Gildas Bazin committed
482
    int i_header_len = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
483
    mtime_t i_pts = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
484

Gildas Bazin's avatar
 
Gildas Bazin committed
485 486 487
    /* Sanity check */
    if( !p_oggpacket->bytes )
    {
488
        msg_Dbg( p_demux, "discarding 0 sized packet" );
Gildas Bazin's avatar
 
Gildas Bazin committed
489 490 491
        return;
    }

492 493 494 495 496 497 498 499 500 501 502 503 504
    if( p_oggpacket->bytes >= 7 &&
        ! strncmp ( &p_oggpacket->packet[0], "Annodex", 7 ) )
    {
        /* it's an Annodex packet -- skip it (do nothing) */
        return; 
    }
    else if( p_oggpacket->bytes >= 7 &&
        ! strncmp ( &p_oggpacket->packet[0], "AnxData", 7 ) )
    {
        /* it's an AnxData packet -- skip it (do nothing) */
        return; 
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
505 506 507 508
    if( p_stream->b_force_backup )
    {
        ogg_packet *p_packet_backup;
        p_stream->i_packets_backup++;
Gildas Bazin's avatar
 
Gildas Bazin committed
509
        switch( p_stream->fmt.i_codec )
Gildas Bazin's avatar
 
Gildas Bazin committed
510 511
        {
        case VLC_FOURCC( 'v','o','r','b' ):
Gildas Bazin's avatar
 
Gildas Bazin committed
512
        case VLC_FOURCC( 's','p','x',' ' ):
Gildas Bazin's avatar
 
Gildas Bazin committed
513 514 515 516
        case VLC_FOURCC( 't','h','e','o' ):
          if( p_stream->i_packets_backup == 3 ) p_stream->b_force_backup = 0;
          break;

Gildas Bazin's avatar
 
Gildas Bazin committed
517
        case VLC_FOURCC( 'f','l','a','c' ):
Gildas Bazin's avatar
 
Gildas Bazin committed
518 519
          if( p_stream->i_packets_backup == 1 ) return;
          else if( p_stream->i_packets_backup == 2 )
Gildas Bazin's avatar
 
Gildas Bazin committed
520 521
          {
              /* Parse the STREAMINFO metadata */
Gildas Bazin's avatar
 
Gildas Bazin committed
522 523 524 525
              bs_t s;
              bs_init( &s, p_oggpacket->packet, p_oggpacket->bytes );
              bs_read( &s, 1 );
              if( bs_read( &s, 7 ) == 0 )
Gildas Bazin's avatar
 
Gildas Bazin committed
526
              {
Gildas Bazin's avatar
 
Gildas Bazin committed
527
                  if( bs_read( &s, 24 ) >= 34 /*size STREAMINFO*/ )
Gildas Bazin's avatar
 
Gildas Bazin committed
528
                  {
Gildas Bazin's avatar
 
Gildas Bazin committed
529 530 531 532 533 534
                      bs_skip( &s, 80 );
                      p_stream->f_rate = p_stream->fmt.audio.i_rate =
                          bs_read( &s, 20 );
                      p_stream->fmt.audio.i_channels =
                          bs_read( &s, 3 ) + 1;

535
                      msg_Dbg( p_demux, "FLAC header, channels: %i, rate: %i",
Gildas Bazin's avatar
 
Gildas Bazin committed
536 537
                               p_stream->fmt.audio.i_channels,
                               (int)p_stream->f_rate );
Gildas Bazin's avatar
 
Gildas Bazin committed
538 539 540
                  }
                  else
                  {
541
                      msg_Dbg( p_demux, "FLAC STREAMINFO metadata too short" );
Gildas Bazin's avatar
 
Gildas Bazin committed
542
                  }
Gildas Bazin's avatar
 
Gildas Bazin committed
543 544 545 546 547 548 549 550 551 552 553

                  /* Store STREAMINFO for the decoder and packetizer */
                  p_stream->fmt.i_extra = p_oggpacket->bytes + 4;
                  p_stream->fmt.p_extra = malloc( p_stream->fmt.i_extra );
                  memcpy( p_stream->fmt.p_extra, "fLaC", 4);
                  memcpy( ((uint8_t *)p_stream->fmt.p_extra) + 4,
                          p_oggpacket->packet, p_oggpacket->bytes );

                  /* Fake this as the last metadata block */
                  ((uint8_t*)p_stream->fmt.p_extra)[4] |= 0x80;

554
                  p_stream->p_es = es_out_Add( p_demux->out,
Gildas Bazin's avatar
 
Gildas Bazin committed
555
                                               &p_stream->fmt );
Gildas Bazin's avatar
 
Gildas Bazin committed
556 557 558 559
              }
              else
              {
                  /* This ain't a STREAMINFO metadata */
560
                  msg_Dbg( p_demux, "Invalid FLAC STREAMINFO metadata" );
Gildas Bazin's avatar
 
Gildas Bazin committed
561 562
              }
              p_stream->b_force_backup = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
563
              p_stream->i_packets_backup = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
564 565 566 567 568

              if( p_oggpacket->granulepos >= 0 )
                  Ogg_UpdatePCR( p_stream, p_oggpacket );

              p_stream->i_previous_pcr = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
569
              return;
Gildas Bazin's avatar
 
Gildas Bazin committed
570 571 572
          }
          break;

Gildas Bazin's avatar
 
Gildas Bazin committed
573 574 575 576 577 578
        default:
          p_stream->b_force_backup = 0;
          break;
        }

        /* Backup the ogg packet (likely an header packet) */
Gildas Bazin's avatar
 
Gildas Bazin committed
579 580 581 582 583 584 585 586 587
        p_stream->p_packets_backup =
            realloc( p_stream->p_packets_backup, p_stream->i_packets_backup *
                     sizeof(ogg_packet) );

        p_packet_backup =
            &p_stream->p_packets_backup[p_stream->i_packets_backup - 1];

        p_packet_backup->bytes = p_oggpacket->bytes;
        p_packet_backup->granulepos = p_oggpacket->granulepos;
Gildas Bazin's avatar
 
Gildas Bazin committed
588 589 590 591 592 593 594 595 596

        if( p_oggpacket->granulepos >= 0 )
        {
            /* Because of vorbis granulepos scheme we must set the pcr for the
             * 1st header packet so it doesn't get discarded in the
             * packetizer */
            Ogg_UpdatePCR( p_stream, p_oggpacket );
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
597 598 599 600 601 602
        p_packet_backup->packet = malloc( p_oggpacket->bytes );
        if( !p_packet_backup->packet ) return;
        memcpy( p_packet_backup->packet, p_oggpacket->packet,
                p_oggpacket->bytes );
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
603
    /* Check the ES is selected */
604
    es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE,
Gildas Bazin's avatar
 
Gildas Bazin committed
605 606 607
                    p_stream->p_es, &b_selected );

    if( b_selected && !p_stream->b_activated )
Gildas Bazin's avatar
 
Gildas Bazin committed
608
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
609 610 611 612 613 614 615 616 617 618
        p_stream->b_activated = VLC_TRUE;

        /* Newly activated stream, feed the backup headers to the decoder */
        if( !p_stream->b_force_backup )
        {
            int i;
            for( i = 0; i < p_stream->i_packets_backup; i++ )
            {
                /* Set correct starting date in header packets */
                p_stream->p_packets_backup[i].granulepos =
619 620
                    p_stream->i_interpolated_pcr * p_stream->f_rate /
                    I64C(1000000);
Gildas Bazin's avatar
 
Gildas Bazin committed
621

622
                Ogg_DecodePacket( p_demux, p_stream,
Gildas Bazin's avatar
 
Gildas Bazin committed
623 624 625
                                  &p_stream->p_packets_backup[i] );
            }
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
626 627
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
628
    /* Convert the pcr into a pts */
Gildas Bazin's avatar
 
Gildas Bazin committed
629 630 631
    if( p_stream->fmt.i_codec == VLC_FOURCC( 'v','o','r','b' ) ||
        p_stream->fmt.i_codec == VLC_FOURCC( 's','p','x',' ' ) ||
        p_stream->fmt.i_codec == VLC_FOURCC( 'f','l','a','c' ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
632
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
633 634 635 636 637
        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 &&
638 639
                p_stream->i_pcr  > 3 * DEFAULT_PTS_DELAY )
            {
640
                es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
Gildas Bazin's avatar
 
Gildas Bazin committed
641

642
                /* Call the pace control */
643 644
                es_out_Control( p_demux->out, ES_OUT_SET_PCR,
                                p_stream->i_pcr );
645
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
646

647
            p_stream->i_previous_pcr = p_stream->i_pcr;
Gildas Bazin's avatar
 
Gildas Bazin committed
648

Gildas Bazin's avatar
 
Gildas Bazin committed
649
            /* The granulepos is the end date of the sample */
650
            i_pts =  p_stream->i_pcr;
Gildas Bazin's avatar
 
Gildas Bazin committed
651
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
652
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
653

Gildas Bazin's avatar
 
Gildas Bazin committed
654 655
    /* Convert the granulepos into the next pcr */
    Ogg_UpdatePCR( p_stream, p_oggpacket );
Gildas Bazin's avatar
 
Gildas Bazin committed
656

Gildas Bazin's avatar
 
Gildas Bazin committed
657 658 659 660 661
    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 &&
662 663
            p_stream->i_pcr  > 3 * DEFAULT_PTS_DELAY )
        {
664
            es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
665 666

            /* Call the pace control */
667
            es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_stream->i_pcr );
668
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
669
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
670

Gildas Bazin's avatar
 
Gildas Bazin committed
671 672 673
    if( p_stream->fmt.i_codec != VLC_FOURCC( 'v','o','r','b' ) &&
        p_stream->fmt.i_codec != VLC_FOURCC( 's','p','x',' ' ) &&
        p_stream->fmt.i_codec != VLC_FOURCC( 'f','l','a','c' ) &&
Gildas Bazin's avatar
 
Gildas Bazin committed
674 675 676
        p_stream->i_pcr >= 0 )
    {
        p_stream->i_previous_pcr = p_stream->i_pcr;
Gildas Bazin's avatar
 
Gildas Bazin committed
677 678

        /* The granulepos is the start date of the sample */
679
        i_pts = p_stream->i_pcr;
Gildas Bazin's avatar
 
Gildas Bazin committed
680
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
681

Gildas Bazin's avatar
 
Gildas Bazin committed
682
    if( !b_selected )
Gildas Bazin's avatar
 
Gildas Bazin committed
683 684 685
    {
        /* 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 */
Gildas Bazin's avatar
 
Gildas Bazin committed
686
        p_stream->b_activated = VLC_FALSE;
Gildas Bazin's avatar
 
Gildas Bazin committed
687 688 689
        return;
    }

690
    if( !( p_block = block_New( p_demux, p_oggpacket->bytes ) ) ) return;
Gildas Bazin's avatar
 
Gildas Bazin committed
691

Gildas Bazin's avatar
 
Gildas Bazin committed
692 693 694 695
    if( p_stream->fmt.i_cat == AUDIO_ES )
        p_block->i_dts = p_block->i_pts = i_pts;
    else if( p_stream->fmt.i_cat == SPU_ES )
    {
696 697
        p_block->i_dts = p_block->i_pts = i_pts;
        p_block->i_length = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
698 699 700 701 702 703 704 705
    }
    else if( p_stream->fmt.i_codec == VLC_FOURCC( 't','h','e','o' ) )
        p_block->i_dts = p_block->i_pts = i_pts;
    else
    {
        p_block->i_dts = i_pts;
        p_block->i_pts = 0;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
706

Gildas Bazin's avatar
 
Gildas Bazin committed
707 708 709 710
    if( p_stream->fmt.i_codec != VLC_FOURCC( 'v','o','r','b' ) &&
        p_stream->fmt.i_codec != VLC_FOURCC( 's','p','x',' ' ) &&
        p_stream->fmt.i_codec != VLC_FOURCC( 'f','l','a','c' ) &&
        p_stream->fmt.i_codec != VLC_FOURCC( 't','a','r','k' ) &&
711 712
        p_stream->fmt.i_codec != VLC_FOURCC( 't','h','e','o' ) &&
        p_stream->fmt.i_codec != VLC_FOURCC( 'c','m','m','l' ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
713
    {
714
        /* We remove the header from the packet */
Gildas Bazin's avatar
 
Gildas Bazin committed
715 716
        i_header_len = (*p_oggpacket->packet & PACKET_LEN_BITS01) >> 6;
        i_header_len |= (*p_oggpacket->packet & PACKET_LEN_BITS2) << 1;
717 718 719 720
        
        if( p_stream->fmt.i_codec == VLC_FOURCC( 's','u','b','t' ))
        {
            /* But with subtitles we need to retrieve the duration first */
Gildas Bazin's avatar
 
Gildas Bazin committed
721
            int i, lenbytes = 0;
722
        
Gildas Bazin's avatar
 
Gildas Bazin committed
723
            if( i_header_len > 0 && p_oggpacket->bytes >= i_header_len + 1 )
724 725 726 727
            {
                for( i = 0, lenbytes = 0; i < i_header_len; i++ )
                {
                    lenbytes = lenbytes << 8;
Gildas Bazin's avatar
 
Gildas Bazin committed
728
                    lenbytes += *(p_oggpacket->packet + i_header_len - i);
729 730
                }
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
731 732 733 734 735
            if( p_oggpacket->bytes - 1 - i_header_len > 2 ||
                ( p_oggpacket->packet[i_header_len + 1] != ' ' &&
                  p_oggpacket->packet[i_header_len + 1] != 0 && 
                  p_oggpacket->packet[i_header_len + 1] != '\n' &&
                  p_oggpacket->packet[i_header_len + 1] != '\r' ) )
736
            {
737
                p_block->i_length = (mtime_t)lenbytes * 1000;
738 739
            }
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
740

741
        i_header_len++;
Gildas Bazin's avatar
 
Gildas Bazin committed
742
        p_block->i_buffer -= i_header_len;
Gildas Bazin's avatar
 
Gildas Bazin committed
743 744
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
745
    if( p_stream->fmt.i_codec == VLC_FOURCC( 't','a','r','k' ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
746 747
    {
        /* FIXME: the biggest hack I've ever done */
748
        msg_Warn( p_demux, "tarkin pts: "I64Fd", granule: "I64Fd,
Gildas Bazin's avatar
 
Gildas Bazin committed
749
                  p_block->i_pts, p_block->i_dts );
Gildas Bazin's avatar
 
Gildas Bazin committed
750
        msleep(10000);
Gildas Bazin's avatar
 
Gildas Bazin committed
751 752
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
753
    memcpy( p_block->p_buffer, p_oggpacket->packet + i_header_len,
Gildas Bazin's avatar
 
Gildas Bazin committed
754 755
            p_oggpacket->bytes - i_header_len );

756
    es_out_Send( p_demux->out, p_stream->p_es, p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
757 758 759 760 761 762 763 764 765 766 767 768
}

/****************************************************************************
 * Ogg_FindLogicalStreams: Find the logical streams embedded in the physical
 *                         stream and fill p_ogg.
 *****************************************************************************
 * The initial page of a logical stream is marked as a 'bos' page.
 * Furthermore, the Ogg specification mandates that grouped bitstreams begin
 * together and all of the initial pages must appear before any data pages.
 *
 * On success this function returns VLC_SUCCESS.
 ****************************************************************************/
769
static int Ogg_FindLogicalStreams( demux_t *p_demux )
Gildas Bazin's avatar
 
Gildas Bazin committed
770
{
771
    demux_sys_t *p_ogg = p_demux->p_sys  ;
Gildas Bazin's avatar
 
Gildas Bazin committed
772 773 774 775
    ogg_packet oggpacket;
    ogg_page oggpage;
    int i_stream;

Gildas Bazin's avatar
 
Gildas Bazin committed
776 777
#define p_stream p_ogg->pp_stream[p_ogg->i_streams - 1]

778
    while( Ogg_ReadPage( p_demux, &oggpage ) == VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794
    {
        if( ogg_page_bos( &oggpage ) )
        {

            /* All is wonderful in our fine fine little world.
             * We found the beginning of our first logical stream. */
            while( ogg_page_bos( &oggpage ) )
            {
                p_ogg->i_streams++;
                p_ogg->pp_stream =
                    realloc( p_ogg->pp_stream, p_ogg->i_streams *
                             sizeof(logical_stream_t *) );

                p_stream = malloc( sizeof(logical_stream_t) );
                memset( p_stream, 0, sizeof(logical_stream_t) );

Gildas Bazin's avatar
 
Gildas Bazin committed
795 796 797
                es_format_Init( &p_stream->fmt, 0, 0 );
                p_stream->b_activated = VLC_TRUE;

Gildas Bazin's avatar
 
Gildas Bazin committed
798 799 800 801 802 803 804 805 806
                /* Setup the logical stream */
                p_stream->i_serial_no = ogg_page_serialno( &oggpage );
                ogg_stream_init( &p_stream->os, p_stream->i_serial_no );

                /* Extract the initial header from the first page and verify
                 * the codec type of tis Ogg bitstream */
                if( ogg_stream_pagein( &p_stream->os, &oggpage ) < 0 )
                {
                    /* error. stream version mismatch perhaps */
807
                    msg_Err( p_demux, "error reading first page of "
Gildas Bazin's avatar
 
Gildas Bazin committed
808 809 810 811 812 813 814 815
                             "Ogg bitstream data" );
                    return VLC_EGENERIC;
                }

                /* FIXME: check return value */
                ogg_stream_packetpeek( &p_stream->os, &oggpacket );

                /* Check for Vorbis header */
816
                if( oggpacket.bytes >= 7 &&
Gildas Bazin's avatar
 
Gildas Bazin committed
817 818
                    ! strncmp( &oggpacket.packet[1], "vorbis", 6 ) )
                {
819
                    Ogg_ReadVorbisHeader( p_stream, &oggpacket );
820
                    msg_Dbg( p_demux, "found vorbis header" );
Gildas Bazin's avatar
 
Gildas Bazin committed
821
                }
Gildas Bazin's avatar
 
Gildas Bazin committed
822
                /* Check for Speex header */
Gildas Bazin's avatar
 
Gildas Bazin committed
823
                else if( oggpacket.bytes >= 7 &&
Gildas Bazin's avatar
 
Gildas Bazin committed
824 825 826 827
                    ! strncmp( &oggpacket.packet[0], "Speex", 5 ) )
                {
                    oggpack_buffer opb;

Gildas Bazin's avatar
 
Gildas Bazin committed
828 829
                    p_stream->fmt.i_cat = AUDIO_ES;
                    p_stream->fmt.i_codec = VLC_FOURCC( 's','p','x',' ' );
Gildas Bazin's avatar
 
Gildas Bazin committed
830 831 832 833 834 835 836 837 838 839 840

                    /* Signal that we want to keep a backup of the vorbis
                     * stream headers. They will be used when switching between
                     * audio streams. */
                    p_stream->b_force_backup = 1;

                    /* Cheat and get additionnal info ;) */
                    oggpack_readinit( &opb, oggpacket.packet, oggpacket.bytes);
                    oggpack_adv( &opb, 224 );
                    oggpack_adv( &opb, 32 ); /* speex_version_id */
                    oggpack_adv( &opb, 32 ); /* header_size */
Gildas Bazin's avatar
 
Gildas Bazin committed
841 842
                    p_stream->f_rate = p_stream->fmt.audio.i_rate =
                        oggpack_read( &opb, 32 );
Gildas Bazin's avatar
 
Gildas Bazin committed
843 844
                    oggpack_adv( &opb, 32 ); /* mode */
                    oggpack_adv( &opb, 32 ); /* mode_bitstream_version */
Gildas Bazin's avatar
 
Gildas Bazin committed
845 846 847
                    p_stream->fmt.audio.i_channels = oggpack_read( &opb, 32 );
                    p_stream->fmt.i_bitrate = oggpack_read( &opb, 32 );

848
                    msg_Dbg( p_demux, "found speex header, channels: %i, "
Gildas Bazin's avatar
 
Gildas Bazin committed
849 850 851
                             "rate: %i,  bitrate: %i",
                             p_stream->fmt.audio.i_channels,
                             (int)p_stream->f_rate, p_stream->fmt.i_bitrate );
Gildas Bazin's avatar
 
Gildas Bazin committed
852
                }
Gildas Bazin's avatar
 
Gildas Bazin committed
853 854 855 856
                /* Check for Flac header */
                else if( oggpacket.bytes >= 4 &&
                    ! strncmp( &oggpacket.packet[0], "fLaC", 4 ) )
                {
857
                    msg_Dbg( p_demux, "found FLAC header" );
Gildas Bazin's avatar
 
Gildas Bazin committed
858 859 860 861 862 863

                    /* Grrrr!!!! Did they really have to put all the
                     * important info in the second header packet!!!
                     * (STREAMINFO metadata is in the following packet) */
                    p_stream->b_force_backup = 1;

Gildas Bazin's avatar
 
Gildas Bazin committed
864 865
                    p_stream->fmt.i_cat = AUDIO_ES;
                    p_stream->fmt.i_codec = VLC_FOURCC( 'f','l','a','c' );
Gildas Bazin's avatar
 
Gildas Bazin committed
866
                }
Gildas Bazin's avatar
 
Gildas Bazin committed
867 868 869 870
                /* Check for Theora header */
                else if( oggpacket.bytes >= 7 &&
                         ! strncmp( &oggpacket.packet[1], "theora", 6 ) )
                {
871
                    Ogg_ReadTheoraHeader( p_stream, &oggpacket );
Gildas Bazin's avatar
 
Gildas Bazin committed
872

873
                    msg_Dbg( p_demux,
Gildas Bazin's avatar
 
Gildas Bazin committed
874
                             "found theora header, bitrate: %i, rate: %f",
Gildas Bazin's avatar
 
Gildas Bazin committed
875
                             p_stream->fmt.i_bitrate, p_stream->f_rate );
Gildas Bazin's avatar
 
Gildas Bazin committed
876 877 878 879 880 881 882
                }
                /* Check for Tarkin header */
                else if( oggpacket.bytes >= 7 &&
                         ! strncmp( &oggpacket.packet[1], "tarkin", 6 ) )
                {
                    oggpack_buffer opb;

883
                    msg_Dbg( p_demux, "found tarkin header" );
Gildas Bazin's avatar
 
Gildas Bazin committed
884 885
                    p_stream->fmt.i_cat = VIDEO_ES;
                    p_stream->fmt.i_codec = VLC_FOURCC( 't','a','r','k' );
Gildas Bazin's avatar
 
Gildas Bazin committed
886 887 888 889 890

                    /* Cheat and get additionnal info ;) */
                    oggpack_readinit( &opb, oggpacket.packet, oggpacket.bytes);
                    oggpack_adv( &opb, 88 );
                    oggpack_adv( &opb, 104 );
Gildas Bazin's avatar
 
Gildas Bazin committed
891
                    p_stream->fmt.i_bitrate = oggpack_read( &opb, 32 );
Gildas Bazin's avatar
 
Gildas Bazin committed
892
                    p_stream->f_rate = 2; /* FIXME */
893
                    msg_Dbg( p_demux,
Gildas Bazin's avatar
 
Gildas Bazin committed
894
                             "found tarkin header, bitrate: %i, rate: %f",
Gildas Bazin's avatar
 
Gildas Bazin committed
895
                             p_stream->fmt.i_bitrate, p_stream->f_rate );
Gildas Bazin's avatar
 
Gildas Bazin committed
896
                }
897 898 899 900
                /* Check for Annodex header */
                else if( oggpacket.bytes >= 7 &&
                         ! strncmp( &oggpacket.packet[0], "Annodex", 7 ) )
                {
901
                    Ogg_ReadAnnodexHeader( VLC_OBJECT(p_demux), p_stream,
902 903 904 905 906 907 908 909 910
                                           &oggpacket );
                    /* kill annodex track */
                    free( p_stream );
                    p_ogg->i_streams--;
                }
                /* Check for Annodex header */
                else if( oggpacket.bytes >= 7 &&
                         ! strncmp( &oggpacket.packet[0], "AnxData", 7 ) )
                {
911
                    Ogg_ReadAnnodexHeader( VLC_OBJECT(p_demux), p_stream,
912 913
                                           &oggpacket );
                }
Gildas Bazin's avatar
 
Gildas Bazin committed
914 915 916 917 918 919 920 921 922 923
                else if( oggpacket.bytes >= 142 &&
                         !strncmp( &oggpacket.packet[1],
                                   "Direct Show Samples embedded in Ogg", 35 ))
                {
                    /* Old header type */

                    /* Check for video header (old format) */
                    if( GetDWLE((oggpacket.packet+96)) == 0x05589f80 &&
                        oggpacket.bytes >= 184 )
                    {
Gildas Bazin's avatar
 
Gildas Bazin committed
924 925
                        p_stream->fmt.i_cat = VIDEO_ES;
                        p_stream->fmt.i_codec =
Gildas Bazin's avatar
 
Gildas Bazin committed
926 927 928 929
                            VLC_FOURCC( oggpacket.packet[68],
                                        oggpacket.packet[69],
                                        oggpacket.packet[70],
                                        oggpacket.packet[71] );
930
                        msg_Dbg( p_demux, "found video header of type: %.4s",
Gildas Bazin's avatar
 
Gildas Bazin committed
931
                                 (char *)&p_stream->fmt.i_codec );
Gildas Bazin's avatar
 
Gildas Bazin committed
932 933 934

                        p_stream->f_rate = 10000000.0 /
                            GetQWLE((oggpacket.packet+164));
Gildas Bazin's avatar
 
Gildas Bazin committed
935
                        p_stream->fmt.video.i_bits_per_pixel =
Gildas Bazin's avatar
 
Gildas Bazin committed
936
                            GetWLE((oggpacket.packet+182));
Gildas Bazin's avatar
 
Gildas Bazin committed
937 938 939 940
                        if( !p_stream->fmt.video.i_bits_per_pixel )
                            /* hack, FIXME */
                            p_stream->fmt.video.i_bits_per_pixel = 24;
                        p_stream->fmt.video.i_width =
Gildas Bazin's avatar
 
Gildas Bazin committed
941
                            GetDWLE((oggpacket.packet+176));
Gildas Bazin's avatar
 
Gildas Bazin committed
942
                        p_stream->fmt.video.i_height =
Gildas Bazin's avatar
 
Gildas Bazin committed
943 944
                            GetDWLE((oggpacket.packet+180));

945
                        msg_Dbg( p_demux,
Gildas Bazin's avatar
 
Gildas Bazin committed
946 947 948 949 950 951
                                 "fps: %f, width:%i; height:%i, bitcount:%i",
                                 p_stream->f_rate,
                                 p_stream->fmt.video.i_width,
                                 p_stream->fmt.video.i_height,
                                 p_stream->fmt.video.i_bits_per_pixel);

Gildas Bazin's avatar
 
Gildas Bazin committed
952 953 954 955 956
                    }
                    /* Check for audio header (old format) */
                    else if( GetDWLE((oggpacket.packet+96)) == 0x05589F81 )
                    {
                        unsigned int i_extra_size;
Gildas Bazin's avatar
 
Gildas Bazin committed
957
                        unsigned int i_format_tag;
Gildas Bazin's avatar
 
Gildas Bazin committed
958

Gildas Bazin's avatar
 
Gildas Bazin committed
959
                        p_stream->fmt.i_cat = AUDIO_ES;
Gildas Bazin's avatar
 
Gildas Bazin committed
960 961

                        i_extra_size = GetWLE((oggpacket.packet+140));
Gildas Bazin's avatar
 
Gildas Bazin committed
962
                        if( i_extra_size )
Gildas Bazin's avatar
 
Gildas Bazin committed
963
                        {
Gildas Bazin's avatar
 
Gildas Bazin committed
964 965 966 967
                            p_stream->fmt.i_extra = i_extra_size;
                            p_stream->fmt.p_extra = malloc( i_extra_size );
                            memcpy( p_stream->fmt.p_extra,
                                    oggpacket.packet + 142, i_extra_size );
Gildas Bazin's avatar
 
Gildas Bazin committed
968 969
                        }

Gildas Bazin's avatar
 
Gildas Bazin committed
970 971
                        i_format_tag = GetWLE((oggpacket.packet+124));
                        p_stream->fmt.audio.i_channels =
Gildas Bazin's avatar
 
Gildas Bazin committed
972
                            GetWLE((oggpacket.packet+126));
Gildas Bazin's avatar
 
Gildas Bazin committed
973
                        p_stream->f_rate = p_stream->fmt.audio.i_rate =
Gildas Bazin's avatar
 
Gildas Bazin committed
974
                            GetDWLE((oggpacket.packet+128));
Gildas Bazin's avatar
 
Gildas Bazin committed
975 976 977
                        p_stream->fmt.i_bitrate =
                            GetDWLE((oggpacket.packet+132)) * 8;
                        p_stream->fmt.audio.i_blockalign =
Gildas Bazin's avatar
 
Gildas Bazin committed
978
                            GetWLE((oggpacket.packet+136));
Gildas Bazin's avatar
 
Gildas Bazin committed
979
                        p_stream->fmt.audio.i_bitspersample =
Gildas Bazin's avatar
 
Gildas Bazin committed
980 981
                            GetWLE((oggpacket.packet+138));

Gildas Bazin's avatar
 
Gildas Bazin committed
982
                        switch( i_format_tag )
Gildas Bazin's avatar
 
Gildas Bazin committed
983 984
                        {
                        case WAVE_FORMAT_PCM:
Gildas Bazin's avatar
 
Gildas Bazin committed
985
                            p_stream->fmt.i_codec =
Gildas Bazin's avatar
 
Gildas Bazin committed
986 987 988 989
                                VLC_FOURCC( 'a', 'r', 'a', 'w' );
                            break;
                        case WAVE_FORMAT_MPEG:
                        case WAVE_FORMAT_MPEGLAYER3:
Gildas Bazin's avatar
 
Gildas Bazin committed
990
                            p_stream->fmt.i_codec =
Gildas Bazin's avatar
 
Gildas Bazin committed
991 992 993
                                VLC_FOURCC( 'm', 'p', 'g', 'a' );
                            break;
                        case WAVE_FORMAT_A52:
Gildas Bazin's avatar
 
Gildas Bazin committed
994
                            p_stream->fmt.i_codec =
Gildas Bazin's avatar
 
Gildas Bazin committed
995 996 997
                                VLC_FOURCC( 'a', '5', '2', ' ' );
                            break;
                        case WAVE_FORMAT_WMA1:
Gildas Bazin's avatar
 
Gildas Bazin committed
998
                            p_stream->fmt.i_codec =
Gildas Bazin's avatar
 
Gildas Bazin committed
999 1000 1001
                                VLC_FOURCC( 'w', 'm', 'a', '1' );
                            break;
                        case WAVE_FORMAT_WMA2:
Gildas Bazin's avatar
 
Gildas Bazin committed
1002
                            p_stream->fmt.i_codec =
Gildas Bazin's avatar
 
Gildas Bazin committed
1003 1004 1005
                                VLC_FOURCC( 'w', 'm', 'a', '2' );
                            break;
                        default:
Gildas Bazin's avatar
 
Gildas Bazin committed
1006 1007 1008
                            p_stream->fmt.i_codec = VLC_FOURCC( 'm', 's',
                                ( i_format_tag >> 8 ) & 0xff,
                                i_format_tag & 0xff );
Gildas Bazin's avatar
 
Gildas Bazin committed
1009 1010
                        }

1011
                        msg_Dbg( p_demux, "found audio header of type: %.4s",
Gildas Bazin's avatar
 
Gildas Bazin committed
1012
                                 (char *)&p_stream->fmt.i_codec );
1013
                        msg_Dbg( p_demux, "audio:0x%4.4x channels:%d %dHz "
Gildas Bazin's avatar
 
Gildas Bazin committed
1014
                                 "%dbits/sample %dkb/s",
Gildas Bazin's avatar
 
Gildas Bazin committed
1015 1016 1017 1018 1019
                                 i_format_tag,
                                 p_stream->fmt.audio.i_channels,
                                 p_stream->fmt.audio.i_rate,
                                 p_stream->fmt.audio.i_bitspersample,
                                 p_stream->fmt.i_bitrate / 1024 );
1020

Gildas Bazin's avatar
 
Gildas Bazin committed
1021 1022 1023
                    }
                    else
                    {
1024
                        msg_Dbg( p_demux, "stream %d has an old header "
Gildas Bazin's avatar
 
Gildas Bazin committed
1025 1026 1027 1028 1029
                            "but is of an unknown type", p_ogg->i_streams-1 );
                        free( p_stream );
                        p_ogg->i_streams--;
                    }
                }
Gildas Bazin's avatar
 
Gildas Bazin committed
1030
                else if( (*oggpacket.packet & PACKET_TYPE_BITS )
Sam Hocevar's avatar
Sam Hocevar committed
1031
                         == PACKET_TYPE_HEADER &&
Gildas Bazin's avatar
 
Gildas Bazin committed
1032 1033 1034 1035 1036 1037 1038
                         oggpacket.bytes >= (int)sizeof(stream_header)+1 )
                {
                    stream_header *st = (stream_header *)(oggpacket.packet+1);

                    /* Check for video header (new format) */
                    if( !strncmp( st->streamtype, "video", 5 ) )
                    {
Gildas Bazin's avatar
 
Gildas Bazin committed
1039
                        p_stream->fmt.i_cat = VIDEO_ES;
Gildas Bazin's avatar
 
Gildas Bazin committed
1040 1041 1042 1043

                        /* We need to get rid of the header packet */
                        ogg_stream_packetout( &p_stream->os, &oggpacket );

Gildas Bazin's avatar
 
Gildas Bazin committed
1044 1045 1046
                        p_stream->fmt.i_codec =
                            VLC_FOURCC( st->subtype[0], st->subtype[1],
                                        st->subtype[2], st->subtype[3] );
1047
                        msg_Dbg( p_demux, "found video header of type: %.4s",
Gildas Bazin's avatar
 
Gildas Bazin committed
1048
                                 (char *)&p_stream->fmt.i_codec );
Gildas Bazin's avatar
 
Gildas Bazin committed
1049

Gildas Bazin's avatar
 
Gildas Bazin committed
1050
                        p_stream->f_rate = 10000000.0 /
1051
                            GetQWLE(&st->time_unit);
Gildas Bazin's avatar
 
Gildas Bazin committed
1052
                        p_stream->fmt.video.i_bits_per_pixel =
1053
                            GetWLE(&st->bits_per_sample);
Gildas Bazin's avatar
 
Gildas Bazin committed
1054
                        p_stream->fmt.video.i_width =
1055
                            GetDWLE(&st->sh.video.width);
Gildas Bazin's avatar
 
Gildas Bazin committed
1056
                        p_stream->fmt.video.i_height =
1057
                            GetDWLE(&st->sh.video.height);
Gildas Bazin's avatar
 
Gildas Bazin committed
1058

1059
                        msg_Dbg( p_demux,
Gildas Bazin's avatar
 
Gildas Bazin committed
1060 1061 1062 1063 1064
                                 "fps: %f, width:%i; height:%i, bitcount:%i",
                                 p_stream->f_rate,
                                 p_stream->fmt.video.i_width,
                                 p_stream->fmt.video.i_height,
                                 p_stream->fmt.video.i_bits_per_pixel );
Gildas Bazin's avatar
 
Gildas Bazin committed
1065 1066 1067 1068 1069
                    }
                    /* Check for audio header (new format) */
                    else if( !strncmp( st->streamtype, "audio", 5 ) )
                    {
                        char p_buffer[5];
Gildas Bazin's avatar
 
Gildas Bazin committed
1070
                        int i_format_tag;
Gildas Bazin's avatar
 
Gildas Bazin committed
1071

Gildas Bazin's avatar
 
Gildas Bazin committed
1072
                        p_stream->fmt.i_cat = AUDIO_ES;
Gildas Bazin's avatar
 
Gildas Bazin committed
1073 1074 1075 1076

                        /* We need to get rid of the header packet */
                        ogg_stream_packetout( &p_stream->os, &oggpacket );

Gildas Bazin's avatar
 
Gildas Bazin committed
1077 1078
                        memcpy( p_buffer, st->subtype, 4 );
                        p_buffer[4] = '\0';
Gildas Bazin's avatar
 
Gildas Bazin committed
1079 1080
                        i_format_tag = strtol(p_buffer,NULL,16);
                        p_stream->fmt.audio.i_channels =
1081
                            GetWLE(&st->sh.audio.channels);
Gildas Bazin's avatar
 
Gildas Bazin committed
1082
                        p_stream->f_rate = p_stream->fmt.audio.i_rate =
1083
                            GetQWLE(&st->samples_per_unit);
Gildas Bazin's avatar
 
Gildas Bazin committed
1084 1085 1086
                        p_stream->fmt.i_bitrate =
                            GetDWLE(&st->sh.audio.avgbytespersec) * 8;
                        p_stream->fmt.audio.i_blockalign =
1087
                            GetWLE(&st->sh.audio.blockalign);
Gildas Bazin's avatar
 
Gildas Bazin committed
1088
                        p_stream->fmt.audio.i_bitspersample =
1089
                            GetWLE(&st->bits_per_sample);
Gildas Bazin's avatar
 
Gildas Bazin committed
1090

Gildas Bazin's avatar
 
Gildas Bazin committed
1091
                        switch( i_format_tag )
Gildas Bazin's avatar
 
Gildas Bazin committed
1092 1093
                        {
                        case WAVE_FORMAT_PCM:
Gildas Bazin's avatar
 
Gildas Bazin committed
1094
                            p_stream->fmt.i_codec =
Gildas Bazin's avatar
 
Gildas Bazin committed
1095 1096 1097 1098
                                VLC_FOURCC( 'a', 'r', 'a', 'w' );
                            break;
                        case WAVE_FORMAT_MPEG:
                        case WAVE_FORMAT_MPEGLAYER3:
Gildas Bazin's avatar
 
Gildas Bazin committed
1099
                            p_stream->fmt.i_codec =
Gildas Bazin's avatar
 
Gildas Bazin committed
1100 1101 1102
                                VLC_FOURCC( 'm', 'p', 'g', 'a' );
                            break;
                        case WAVE_FORMAT_A52:
Gildas Bazin's avatar
 
Gildas Bazin committed
1103
                            p_stream->fmt.i_codec =
Gildas Bazin's avatar
 
Gildas Bazin committed
1104 1105 1106
                                VLC_FOURCC( 'a', '5', '2', ' ' );
                            break;
                        case WAVE_FORMAT_WMA1:
Gildas Bazin's avatar
 
Gildas Bazin committed
1107
                            p_stream->fmt.i_codec =
Gildas Bazin's avatar
 
Gildas Bazin committed
1108 1109 1110
                                VLC_FOURCC( 'w', 'm', 'a', '1' );
                            break;
                        case WAVE_FORMAT_WMA2:
Gildas Bazin's avatar
 
Gildas Bazin committed
1111
                            p_stream->fmt.i_codec =
Gildas Bazin's avatar
 
Gildas Bazin committed
1112 1113 1114
                                VLC_FOURCC( 'w', 'm', 'a', '2' );
                            break;
                        default:
Gildas Bazin's avatar
 
Gildas Bazin committed
1115 1116 1117
                            p_stream->fmt.i_codec = VLC_FOURCC( 'm', 's',
                                ( i_format_tag >> 8 ) & 0xff,
                                i_format_tag & 0xff );
Gildas Bazin's avatar
 
Gildas Bazin committed
1118 1119
                        }

1120
                        msg_Dbg( p_demux, "found audio header of type: %.4s",
Gildas Bazin's avatar
 
Gildas Bazin committed
1121
                                 (char *)&p_stream->fmt.i_codec );
1122
                        msg_Dbg( p_demux, "audio:0x%4.4x channels:%d %dHz "
Gildas Bazin's avatar
 
Gildas Bazin committed
1123
                                 "%dbits/sample %dkb/s",
Gildas Bazin's avatar
 
Gildas Bazin committed
1124 1125 1126 1127 1128
                                 i_format_tag,
                                 p_stream->fmt.audio.i_channels,
                                 p_stream->fmt.audio.i_rate,
                                 p_stream->fmt.audio.i_bitspersample,
                                 p_stream->fmt.i_bitrate / 1024 );
Gildas Bazin's avatar
 
Gildas Bazin committed
1129
                    }
Gildas Bazin's avatar
 
Gildas Bazin committed
1130 1131 1132
                    /* Check for text (subtitles) header */
                    else if( !strncmp(st->streamtype, "text", 4) )
                    {
Gildas Bazin's avatar
 
Gildas Bazin committed
1133 1134 1135
                        /* We need to get rid of the header packet */
                        ogg_stream_packetout( &p_stream->os, &oggpacket );

1136
                        msg_Dbg( p_demux, "found text subtitles header" );
Gildas Bazin's avatar
 
Gildas Bazin committed
1137 1138
                        p_stream->fmt.i_cat = SPU_ES;
                        p_stream->fmt.i_codec = VLC_FOURCC('s','u','b','t');
Gildas Bazin's avatar
 
Gildas Bazin committed
1139
                        p_stream->f_rate = 1000; /* granulepos is in milisec */
Gildas Bazin's avatar
 
Gildas Bazin committed
1140
                    }
Gildas Bazin's avatar
 
Gildas Bazin committed
1141 1142
                    else
                    {
1143
                        msg_Dbg( p_demux, "stream %d has a header marker "
Gildas Bazin's avatar
 
Gildas Bazin committed
1144 1145 1146 1147 1148
                            "but is of an unknown type", p_ogg->i_streams-1 );
                        free( p_stream );
                        p_ogg->i_streams--;
                    }
                }
Gildas Bazin's avatar
 
Gildas Bazin committed
1149 1150
                else
                {
1151
                    msg_Dbg( p_demux, "stream %d is of unknown type",
Gildas Bazin's avatar
 
Gildas Bazin committed
1152
                             p_ogg->i_streams-1 );
Gildas Bazin's avatar
 
Gildas Bazin committed
1153 1154
                    free( p_stream );
                    p_ogg->i_streams--;
Gildas Bazin's avatar
 
Gildas Bazin committed
1155 1156
                }

1157
                if( Ogg_ReadPage( p_demux, &oggpage ) != VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
                    return VLC_EGENERIC;
            }

            /* This is the first data page, which means we are now finished
             * with the initial pages. We just need to store it in the relevant
             * bitstream. */
            for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
            {
                if( ogg_stream_pagein( &p_ogg->pp_stream[i_stream]->os,
                                       &oggpage ) == 0 )
                {
                    break;
                }
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
1172

Gildas Bazin's avatar
 
Gildas Bazin committed
1173 1174 1175
            return VLC_SUCCESS;
        }
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
1176 1177
#undef p_stream

Gildas Bazin's avatar
 
Gildas Bazin committed
1178 1179 1180
    return VLC_EGENERIC;
}

Gildas Bazin's avatar
 
Gildas Bazin committed
1181
/****************************************************************************
Gildas Bazin's avatar