ogg.c 50.2 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
    int              i_serial_no;
Gildas Bazin's avatar
 
Gildas Bazin committed
62

Gildas Bazin's avatar
 
Gildas Bazin committed
63 64 65 66 67
    /* 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;
68 69
    uint8_t          *p_headers;
    int              i_headers;
Gildas Bazin's avatar
 
Gildas Bazin committed
70

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
/* Logical bitstream headers */
166 167 168 169 170
static void Ogg_ReadTheoraHeader( logical_stream_t *, ogg_packet * );
static void Ogg_ReadVorbisHeader( logical_stream_t *, ogg_packet * );
static void Ogg_ReadSpeexHeader( logical_stream_t *, ogg_packet * );
static void Ogg_ReadFlacHeader( demux_t *, logical_stream_t *, ogg_packet * );
static void Ogg_ReadAnnodexHeader( vlc_object_t *, logical_stream_t *, ogg_packet * );
171

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

181 182

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

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

    memset( p_sys, 0, sizeof( demux_sys_t ) );
200
    p_sys->i_bitrate = 0;
201 202 203 204 205 206 207
    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
208 209 210 211

    return VLC_SUCCESS;
}

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

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

223
    Ogg_EndOfStream( p_demux );
224 225 226 227 228 229 230 231 232

    free( p_sys );
}

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


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

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

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

    /*
     * Demux an ogg page from the stream
     */
259
    if( Ogg_ReadPage( p_demux, &oggpage ) != VLC_SUCCESS )
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
    {
        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 )
            {
280
                if( p_stream->fmt.i_codec == VLC_FOURCC('t','h','e','o') &&
281 282 283 284 285 286
                        oggpacket.bytes >= 7 &&
                        ! strncmp( &oggpacket.packet[1], "theora", 6 ) )
                {
                    Ogg_ReadTheoraHeader( p_stream, &oggpacket );
                    p_stream->secondary_header_packets = 0;
                }
287
                else if( p_stream->fmt.i_codec == VLC_FOURCC('v','o','r','b') &&
288 289 290 291 292 293
                        oggpacket.bytes >= 7 &&
                        ! strncmp( &oggpacket.packet[1], "vorbis", 6 ) )
                {
                    Ogg_ReadVorbisHeader( p_stream, &oggpacket );
                    p_stream->secondary_header_packets = 0;
                }
294
                else if ( p_stream->fmt.i_codec == VLC_FOURCC('c','m','m','l') )
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
                {
                    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 )
                    {
325
                        Ogg_DecodePacket( p_demux, p_stream, &oggpacket );
326 327 328
                    }
                    else
                    {
329 330
                        es_out_Control( p_demux->out, ES_OUT_SET_PCR,
                                        p_stream->i_pcr );
331 332 333 334 335
                    }
                    continue;
                }
            }

336
            Ogg_DecodePacket( p_demux, p_stream, &oggpacket );
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
        }
        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 )
    {
357
        es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr );
358 359 360 361 362 363 364 365 366
    }


    return 1;
}

/*****************************************************************************
 * Control:
 *****************************************************************************/
367
static int Control( demux_t *p_demux, int i_query, va_list args )
368
{
369
    demux_sys_t *p_sys  = p_demux->p_sys;
370 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
    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:
397 398
            return demux2_vaControlHelper( p_demux->s, 0, -1, p_sys->i_bitrate,
                                           1, i_query, args );
399 400 401
    }
}

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

    while( ogg_sync_pageout( &p_ogg->oy, p_oggpage ) != 1 )
    {
416 417 418
        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
419 420 421 422 423 424 425 426 427
        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
428 429 430 431 432 433 434
/****************************************************************************
 * 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
435
    /* Convert the granulepos into a pcr */
Gildas Bazin's avatar
 
Gildas Bazin committed
436 437
    if( p_oggpacket->granulepos >= 0 )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
438
        if( p_stream->fmt.i_codec != VLC_FOURCC( 't','h','e','o' ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
439
        {
440
            p_stream->i_pcr = p_oggpacket->granulepos * I64C(1000000)
Gildas Bazin's avatar
 
Gildas Bazin committed
441 442 443 444 445 446 447 448 449
                              / 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 );

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
460 461
        /* 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
462
        if( p_stream->fmt.i_cat == VIDEO_ES )
Gildas Bazin's avatar
 
Gildas Bazin committed
463
            /* 1 frame per packet */
464
            p_stream->i_interpolated_pcr += (I64C(1000000) / p_stream->f_rate);
Gildas Bazin's avatar
 
Gildas Bazin committed
465
        else if( p_stream->fmt.i_bitrate )
466 467 468
            p_stream->i_interpolated_pcr +=
                ( p_oggpacket->bytes * I64C(1000000) /
                  p_stream->fmt.i_bitrate / 8 );
Gildas Bazin's avatar
 
Gildas Bazin committed
469 470 471
    }
}

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

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

491 492 493 494 495 496 497 498 499 500 501 502 503
    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; 
    }

504 505 506 507
    /* Check the ES is selected */
    es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE,
                    p_stream->p_es, &b_selected );

Gildas Bazin's avatar
 
Gildas Bazin committed
508 509
    if( p_stream->b_force_backup )
    {
510 511 512
        uint8_t *p_extra;
	vlc_bool_t b_store_size = VLC_TRUE;

Gildas Bazin's avatar
 
Gildas Bazin committed
513
        p_stream->i_packets_backup++;
Gildas Bazin's avatar
 
Gildas Bazin committed
514
        switch( p_stream->fmt.i_codec )
Gildas Bazin's avatar
 
Gildas Bazin committed
515 516
        {
        case VLC_FOURCC( 'v','o','r','b' ):
Gildas Bazin's avatar
 
Gildas Bazin committed
517
        case VLC_FOURCC( 's','p','x',' ' ):
Gildas Bazin's avatar
 
Gildas Bazin committed
518 519 520 521
        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
522
        case VLC_FOURCC( 'f','l','a','c' ):
523
          if( p_stream->i_packets_backup == 2 )
Gildas Bazin's avatar
 
Gildas Bazin committed
524
          {
525
	      Ogg_ReadFlacHeader( p_demux, p_stream, p_oggpacket );
Gildas Bazin's avatar
 
Gildas Bazin committed
526 527
              p_stream->b_force_backup = 0;
          }
528
          b_store_size = VLC_FALSE;
Gildas Bazin's avatar
 
Gildas Bazin committed
529 530
          break;

Gildas Bazin's avatar
 
Gildas Bazin committed
531 532 533 534 535 536
        default:
          p_stream->b_force_backup = 0;
          break;
        }

        /* Backup the ogg packet (likely an header packet) */
537 538 539 540 541
        p_stream->p_headers =
            realloc( p_stream->p_headers, p_stream->i_headers +
                     p_oggpacket->bytes + (b_store_size ? 2 : 0) );
        p_extra = p_stream->p_headers + p_stream->i_headers;
        if( b_store_size )
Gildas Bazin's avatar
 
Gildas Bazin committed
542
        {
543 544
            *(p_extra++) = p_oggpacket->bytes >> 8;
            *(p_extra++) = p_oggpacket->bytes & 0xFF;
Gildas Bazin's avatar
 
Gildas Bazin committed
545
        }
546 547
        memcpy( p_extra, p_oggpacket->packet, p_oggpacket->bytes );
        p_stream->i_headers += p_oggpacket->bytes + (b_store_size ? 2 : 0);
Gildas Bazin's avatar
 
Gildas Bazin committed
548

Gildas Bazin's avatar
 
Gildas Bazin committed
549 550
        if( !p_stream->b_force_backup )
        {
551 552 553 554 555 556 557 558
            /* Last header received, commit changes */
            p_stream->fmt.i_extra = p_stream->i_headers;
            p_stream->fmt.p_extra =
                realloc( p_stream->fmt.p_extra, p_stream->i_headers );
	    memcpy( p_stream->fmt.p_extra, p_stream->p_headers,
		    p_stream->i_headers );
            es_out_Control( p_demux->out, ES_OUT_SET_FMT,
                            p_stream->p_es, &p_stream->fmt );
Gildas Bazin's avatar
 
Gildas Bazin committed
559
        }
560 561

        b_selected = VLC_FALSE; /* Discard the header packet */
Gildas Bazin's avatar
 
Gildas Bazin committed
562 563
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
564
    /* Convert the pcr into a pts */
Gildas Bazin's avatar
 
Gildas Bazin committed
565 566 567
    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
568
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
569 570 571 572 573
        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 &&
574 575
                p_stream->i_pcr  > 3 * DEFAULT_PTS_DELAY )
            {
576
                es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
Gildas Bazin's avatar
 
Gildas Bazin committed
577

578
                /* Call the pace control */
579 580
                es_out_Control( p_demux->out, ES_OUT_SET_PCR,
                                p_stream->i_pcr );
581
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
582

583
            p_stream->i_previous_pcr = p_stream->i_pcr;
Gildas Bazin's avatar
 
Gildas Bazin committed
584

Gildas Bazin's avatar
 
Gildas Bazin committed
585
            /* The granulepos is the end date of the sample */
586
            i_pts =  p_stream->i_pcr;
Gildas Bazin's avatar
 
Gildas Bazin committed
587
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
588
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
589

Gildas Bazin's avatar
 
Gildas Bazin committed
590 591
    /* Convert the granulepos into the next pcr */
    Ogg_UpdatePCR( p_stream, p_oggpacket );
Gildas Bazin's avatar
 
Gildas Bazin committed
592

Gildas Bazin's avatar
 
Gildas Bazin committed
593 594 595 596 597
    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 &&
598 599
            p_stream->i_pcr  > 3 * DEFAULT_PTS_DELAY )
        {
600
            es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
601 602

            /* Call the pace control */
603
            es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_stream->i_pcr );
604
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
605
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
606

Gildas Bazin's avatar
 
Gildas Bazin committed
607 608 609
    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
610 611 612
        p_stream->i_pcr >= 0 )
    {
        p_stream->i_previous_pcr = p_stream->i_pcr;
Gildas Bazin's avatar
 
Gildas Bazin committed
613 614

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

Gildas Bazin's avatar
 
Gildas Bazin committed
618
    if( !b_selected )
Gildas Bazin's avatar
 
Gildas Bazin committed
619 620 621 622 623 624
    {
        /* This stream isn't currently selected so we don't need to decode it,
         * but we did need to store its pcr as it might be selected later on */
        return;
    }

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

Gildas Bazin's avatar
 
Gildas Bazin committed
627 628 629 630
    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 )
    {
631 632
        p_block->i_dts = p_block->i_pts = i_pts;
        p_block->i_length = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
633 634 635 636 637 638 639 640
    }
    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
641

Gildas Bazin's avatar
 
Gildas Bazin committed
642 643 644 645
    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' ) &&
646 647
        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
648
    {
649
        /* We remove the header from the packet */
Gildas Bazin's avatar
 
Gildas Bazin committed
650 651
        i_header_len = (*p_oggpacket->packet & PACKET_LEN_BITS01) >> 6;
        i_header_len |= (*p_oggpacket->packet & PACKET_LEN_BITS2) << 1;
652 653 654 655
        
        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
656
            int i, lenbytes = 0;
657
        
Gildas Bazin's avatar
 
Gildas Bazin committed
658
            if( i_header_len > 0 && p_oggpacket->bytes >= i_header_len + 1 )
659 660 661 662
            {
                for( i = 0, lenbytes = 0; i < i_header_len; i++ )
                {
                    lenbytes = lenbytes << 8;
Gildas Bazin's avatar
 
Gildas Bazin committed
663
                    lenbytes += *(p_oggpacket->packet + i_header_len - i);
664 665
                }
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
666 667 668 669 670
            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' ) )
671
            {
672
                p_block->i_length = (mtime_t)lenbytes * 1000;
673 674
            }
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
675

676
        i_header_len++;
Gildas Bazin's avatar
 
Gildas Bazin committed
677
        p_block->i_buffer -= i_header_len;
Gildas Bazin's avatar
 
Gildas Bazin committed
678 679
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
680
    if( p_stream->fmt.i_codec == VLC_FOURCC( 't','a','r','k' ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
681 682
    {
        /* FIXME: the biggest hack I've ever done */
683
        msg_Warn( p_demux, "tarkin pts: "I64Fd", granule: "I64Fd,
Gildas Bazin's avatar
 
Gildas Bazin committed
684
                  p_block->i_pts, p_block->i_dts );
Gildas Bazin's avatar
 
Gildas Bazin committed
685
        msleep(10000);
Gildas Bazin's avatar
 
Gildas Bazin committed
686 687
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
688
    memcpy( p_block->p_buffer, p_oggpacket->packet + i_header_len,
Gildas Bazin's avatar
 
Gildas Bazin committed
689 690
            p_oggpacket->bytes - i_header_len );

691
    es_out_Send( p_demux->out, p_stream->p_es, p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
692 693 694 695 696 697 698 699 700 701 702 703
}

/****************************************************************************
 * 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.
 ****************************************************************************/
704
static int Ogg_FindLogicalStreams( demux_t *p_demux )
Gildas Bazin's avatar
 
Gildas Bazin committed
705
{
706
    demux_sys_t *p_ogg = p_demux->p_sys  ;
Gildas Bazin's avatar
 
Gildas Bazin committed
707 708 709 710
    ogg_packet oggpacket;
    ogg_page oggpage;
    int i_stream;

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

713
    while( Ogg_ReadPage( p_demux, &oggpage ) == VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
    {
        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) );
729
                p_stream->p_headers = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
730

Gildas Bazin's avatar
 
Gildas Bazin committed
731 732
                es_format_Init( &p_stream->fmt, 0, 0 );

Gildas Bazin's avatar
 
Gildas Bazin committed
733 734 735 736 737 738 739 740 741
                /* 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 */
742
                    msg_Err( p_demux, "error reading first page of "
Gildas Bazin's avatar
 
Gildas Bazin committed
743 744 745 746 747 748 749 750
                             "Ogg bitstream data" );
                    return VLC_EGENERIC;
                }

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

                /* Check for Vorbis header */
751
                if( oggpacket.bytes >= 7 &&
Gildas Bazin's avatar
 
Gildas Bazin committed
752 753
                    ! strncmp( &oggpacket.packet[1], "vorbis", 6 ) )
                {
754
                    Ogg_ReadVorbisHeader( p_stream, &oggpacket );
755
                    msg_Dbg( p_demux, "found vorbis header" );
Gildas Bazin's avatar
 
Gildas Bazin committed
756
                }
Gildas Bazin's avatar
 
Gildas Bazin committed
757
                /* Check for Speex header */
Gildas Bazin's avatar
 
Gildas Bazin committed
758
                else if( oggpacket.bytes >= 7 &&
Gildas Bazin's avatar
 
Gildas Bazin committed
759 760
                    ! strncmp( &oggpacket.packet[0], "Speex", 5 ) )
                {
761
                    Ogg_ReadSpeexHeader( p_stream, &oggpacket );
762
                    msg_Dbg( p_demux, "found speex header, channels: %i, "
Gildas Bazin's avatar
 
Gildas Bazin committed
763 764 765
                             "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
766
                }
Gildas Bazin's avatar
 
Gildas Bazin committed
767 768 769 770
                /* Check for Flac header */
                else if( oggpacket.bytes >= 4 &&
                    ! strncmp( &oggpacket.packet[0], "fLaC", 4 ) )
                {
771
                    msg_Dbg( p_demux, "found FLAC header" );
Gildas Bazin's avatar
 
Gildas Bazin committed
772 773 774 775 776 777

                    /* 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
778 779
                    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
780
                }
Gildas Bazin's avatar
 
Gildas Bazin committed
781 782 783 784
                /* Check for Theora header */
                else if( oggpacket.bytes >= 7 &&
                         ! strncmp( &oggpacket.packet[1], "theora", 6 ) )
                {
785
                    Ogg_ReadTheoraHeader( p_stream, &oggpacket );
Gildas Bazin's avatar
 
Gildas Bazin committed
786

787
                    msg_Dbg( p_demux,
Gildas Bazin's avatar
 
Gildas Bazin committed
788
                             "found theora header, bitrate: %i, rate: %f",
Gildas Bazin's avatar
 
Gildas Bazin committed
789
                             p_stream->fmt.i_bitrate, p_stream->f_rate );
Gildas Bazin's avatar
 
Gildas Bazin committed
790 791 792 793 794 795 796
                }
                /* Check for Tarkin header */
                else if( oggpacket.bytes >= 7 &&
                         ! strncmp( &oggpacket.packet[1], "tarkin", 6 ) )
                {
                    oggpack_buffer opb;

797
                    msg_Dbg( p_demux, "found tarkin header" );
Gildas Bazin's avatar
 
Gildas Bazin committed
798 799
                    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
800 801 802 803 804

                    /* 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
805
                    p_stream->fmt.i_bitrate = oggpack_read( &opb, 32 );
Gildas Bazin's avatar
 
Gildas Bazin committed
806
                    p_stream->f_rate = 2; /* FIXME */
807
                    msg_Dbg( p_demux,
Gildas Bazin's avatar
 
Gildas Bazin committed
808
                             "found tarkin header, bitrate: %i, rate: %f",
Gildas Bazin's avatar
 
Gildas Bazin committed
809
                             p_stream->fmt.i_bitrate, p_stream->f_rate );
Gildas Bazin's avatar
 
Gildas Bazin committed
810
                }
811 812 813 814
                /* Check for Annodex header */
                else if( oggpacket.bytes >= 7 &&
                         ! strncmp( &oggpacket.packet[0], "Annodex", 7 ) )
                {
815
                    Ogg_ReadAnnodexHeader( VLC_OBJECT(p_demux), p_stream,
816 817 818 819 820 821 822 823 824
                                           &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 ) )
                {
825
                    Ogg_ReadAnnodexHeader( VLC_OBJECT(p_demux), p_stream,
826 827
                                           &oggpacket );
                }
Gildas Bazin's avatar
 
Gildas Bazin committed
828 829 830 831 832 833 834 835 836 837
                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
838 839
                        p_stream->fmt.i_cat = VIDEO_ES;
                        p_stream->fmt.i_codec =
Gildas Bazin's avatar
 
Gildas Bazin committed
840 841 842 843
                            VLC_FOURCC( oggpacket.packet[68],
                                        oggpacket.packet[69],
                                        oggpacket.packet[70],
                                        oggpacket.packet[71] );
844
                        msg_Dbg( p_demux, "found video header of type: %.4s",
Gildas Bazin's avatar
 
Gildas Bazin committed
845
                                 (char *)&p_stream->fmt.i_codec );
Gildas Bazin's avatar
 
Gildas Bazin committed
846 847 848

                        p_stream->f_rate = 10000000.0 /
                            GetQWLE((oggpacket.packet+164));
Gildas Bazin's avatar
 
Gildas Bazin committed
849
                        p_stream->fmt.video.i_bits_per_pixel =
Gildas Bazin's avatar
 
Gildas Bazin committed
850
                            GetWLE((oggpacket.packet+182));
Gildas Bazin's avatar
 
Gildas Bazin committed
851 852 853 854
                        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
855
                            GetDWLE((oggpacket.packet+176));
Gildas Bazin's avatar
 
Gildas Bazin committed
856
                        p_stream->fmt.video.i_height =
Gildas Bazin's avatar
 
Gildas Bazin committed
857 858
                            GetDWLE((oggpacket.packet+180));

859
                        msg_Dbg( p_demux,
Gildas Bazin's avatar
 
Gildas Bazin committed
860 861 862 863 864 865
                                 "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
866 867 868 869 870
                    }
                    /* 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
871
                        unsigned int i_format_tag;
Gildas Bazin's avatar
 
Gildas Bazin committed
872

Gildas Bazin's avatar
 
Gildas Bazin committed
873
                        p_stream->fmt.i_cat = AUDIO_ES;
Gildas Bazin's avatar
 
Gildas Bazin committed
874 875

                        i_extra_size = GetWLE((oggpacket.packet+140));
Gildas Bazin's avatar
 
Gildas Bazin committed
876
                        if( i_extra_size )
Gildas Bazin's avatar
 
Gildas Bazin committed
877
                        {
Gildas Bazin's avatar
 
Gildas Bazin committed
878 879 880 881
                            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
882 883
                        }

Gildas Bazin's avatar
 
Gildas Bazin committed
884 885
                        i_format_tag = GetWLE((oggpacket.packet+124));
                        p_stream->fmt.audio.i_channels =
Gildas Bazin's avatar
 
Gildas Bazin committed
886
                            GetWLE((oggpacket.packet+126));
Gildas Bazin's avatar
 
Gildas Bazin committed
887
                        p_stream->f_rate = p_stream->fmt.audio.i_rate =
Gildas Bazin's avatar
 
Gildas Bazin committed
888
                            GetDWLE((oggpacket.packet+128));
Gildas Bazin's avatar
 
Gildas Bazin committed
889 890 891
                        p_stream->fmt.i_bitrate =
                            GetDWLE((oggpacket.packet+132)) * 8;
                        p_stream->fmt.audio.i_blockalign =
Gildas Bazin's avatar
 
Gildas Bazin committed
892
                            GetWLE((oggpacket.packet+136));
Gildas Bazin's avatar
 
Gildas Bazin committed
893
                        p_stream->fmt.audio.i_bitspersample =
Gildas Bazin's avatar
 
Gildas Bazin committed
894 895
                            GetWLE((oggpacket.packet+138));

896 897 898 899 900
                        wf_tag_to_fourcc( i_format_tag,
                                          &p_stream->fmt.i_codec, 0 );

                        if( p_stream->fmt.i_codec ==
                            VLC_FOURCC('u','n','d','f') )
Gildas Bazin's avatar
 
Gildas Bazin committed
901
                        {
Gildas Bazin's avatar
 
Gildas Bazin committed
902 903 904
                            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
905 906
                        }

907
                        msg_Dbg( p_demux, "found audio header of type: %.4s",
Gildas Bazin's avatar
 
Gildas Bazin committed
908
                                 (char *)&p_stream->fmt.i_codec );
909
                        msg_Dbg( p_demux, "audio:0x%4.4x channels:%d %dHz "
Gildas Bazin's avatar
 
Gildas Bazin committed
910
                                 "%dbits/sample %dkb/s",
Gildas Bazin's avatar
 
Gildas Bazin committed
911 912 913 914 915
                                 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 );
916

Gildas Bazin's avatar
 
Gildas Bazin committed
917 918 919
                    }
                    else
                    {
920
                        msg_Dbg( p_demux, "stream %d has an old header "
Gildas Bazin's avatar
 
Gildas Bazin committed
921 922 923 924 925
                            "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
926
                else if( (*oggpacket.packet & PACKET_TYPE_BITS )
Sam Hocevar's avatar
Sam Hocevar committed
927
                         == PACKET_TYPE_HEADER &&
Gildas Bazin's avatar
 
Gildas Bazin committed
928 929 930 931 932 933 934
                         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
935
                        p_stream->fmt.i_cat = VIDEO_ES;
Gildas Bazin's avatar
 
Gildas Bazin committed
936 937 938 939

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

Gildas Bazin's avatar
 
Gildas Bazin committed
940 941 942
                        p_stream->fmt.i_codec =
                            VLC_FOURCC( st->subtype[0], st->subtype[1],
                                        st->subtype[2], st->subtype[3] );
943
                        msg_Dbg( p_demux, "found video header of type: %.4s",
Gildas Bazin's avatar
 
Gildas Bazin committed
944
                                 (char *)&p_stream->fmt.i_codec );
Gildas Bazin's avatar
 
Gildas Bazin committed
945

Gildas Bazin's avatar
 
Gildas Bazin committed
946
                        p_stream->f_rate = 10000000.0 /
947
                            GetQWLE(&st->time_unit);
Gildas Bazin's avatar
 
Gildas Bazin committed
948
                        p_stream->fmt.video.i_bits_per_pixel =
949
                            GetWLE(&st->bits_per_sample);
Gildas Bazin's avatar
 
Gildas Bazin committed
950
                        p_stream->fmt.video.i_width =
951
                            GetDWLE(&st->sh.video.width);
Gildas Bazin's avatar
 
Gildas Bazin committed
952
                        p_stream->fmt.video.i_height =
953
                            GetDWLE(&st->sh.video.height);
Gildas Bazin's avatar
 
Gildas Bazin committed
954

955
                        msg_Dbg( p_demux,
Gildas Bazin's avatar
 
Gildas Bazin committed
956 957 958 959 960
                                 "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
961 962 963 964 965
                    }
                    /* Check for audio header (new format) */
                    else if( !strncmp( st->streamtype, "audio", 5 ) )
                    {
                        char p_buffer[5];
Gildas Bazin's avatar
 
Gildas Bazin committed
966
                        int i_format_tag;
Gildas Bazin's avatar
 
Gildas Bazin committed
967

Gildas Bazin's avatar
 
Gildas Bazin committed
968
                        p_stream->fmt.i_cat = AUDIO_ES;
Gildas Bazin's avatar
 
Gildas Bazin committed
969 970 971 972

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

973 974 975 976 977 978 979 980 981 982
                        p_stream->fmt.i_extra = GetQWLE(&st->size) -
                            sizeof(stream_header);
                        if( p_stream->fmt.i_extra )
                        {
                            p_stream->fmt.p_extra =
                                malloc( p_stream->fmt.i_extra );
                            memcpy( p_stream->fmt.p_extra, st + 1,
                                    p_stream->fmt.i_extra );
                        }

Gildas Bazin's avatar
 
Gildas Bazin committed
983 984
                        memcpy( p_buffer, st->subtype, 4 );
                        p_buffer[4] = '\0';
Gildas Bazin's avatar
 
Gildas Bazin committed
985 986
                        i_format_tag = strtol(p_buffer,NULL,16);
                        p_stream->fmt.audio.i_channels =
987
                            GetWLE(&st->sh.audio.channels);
Gildas Bazin's avatar
 
Gildas Bazin committed
988
                        p_stream->f_rate = p_stream->fmt.audio.i_rate =
989
                            GetQWLE(&st->samples_per_unit);
Gildas Bazin's avatar
 
Gildas Bazin committed
990 991 992
                        p_stream->fmt.i_bitrate =
                            GetDWLE(&st->sh.audio.avgbytespersec) * 8;
                        p_stream->fmt.audio.i_blockalign =
993
                            GetWLE(&st->sh.audio.blockalign);
Gildas Bazin's avatar
 
Gildas Bazin committed
994
                        p_stream->fmt.audio.i_bitspersample =
995
                            GetWLE(&st->bits_per_sample);
Gildas Bazin's avatar
 
Gildas Bazin committed
996

997 998 999 1000 1001
                        wf_tag_to_fourcc( i_format_tag,
                                          &p_stream->fmt.i_codec, 0 );

                        if( p_stream->fmt.i_codec ==
                            VLC_FOURCC('u','n','d','f') )
Gildas Bazin's avatar
 
Gildas Bazin committed
1002
                        {
Gildas Bazin's avatar
 
Gildas Bazin committed
1003 1004 1005
                            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
1006 1007
                        }

1008
                        msg_Dbg( p_demux, "found audio header of type: %.4s",
Gildas Bazin's avatar
 
Gildas Bazin committed
1009
                                 (char *)&p_stream->fmt.i_codec );
1010
                        msg_Dbg( p_demux, "audio:0x%4.4x channels:%d %dHz "
Gildas Bazin's avatar
 
Gildas Bazin committed
1011
                                 "%dbits/sample %dkb/s",
Gildas Bazin's avatar
 
Gildas Bazin committed
1012 1013 1014 1015 1016
                                 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
1017
                    }
Gildas Bazin's avatar
 
Gildas Bazin committed
1018 1019 1020
                    /* Check for text (subtitles) header */
                    else if( !strncmp(st->streamtype, "text", 4) )
                    {
Gildas Bazin's avatar
 
Gildas Bazin committed
1021 1022 1023
                        /* We need to get rid of the header packet */
                        ogg_stream_packetout( &p_stream->os, &oggpacket );

1024
                        msg_Dbg( p_demux, "found text subtitles header" );
Gildas Bazin's avatar
 
Gildas Bazin committed
1025 1026
                        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
1027
                        p_stream->f_rate = 1000; /* granulepos is in milisec */
Gildas Bazin's avatar
 
Gildas Bazin committed
1028
                    }
Gildas Bazin's avatar
 
Gildas Bazin committed
1029 1030
                    else
                    {
1031
                        msg_Dbg( p_demux, "stream %d has a header marker "
Gildas Bazin's avatar
 
Gildas Bazin committed
1032 1033 1034 1035 1036
                            "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
1037 1038
                else
                {
1039
                    msg_Dbg( p_demux, "stream %d is of unknown type",
Gildas Bazin's avatar
 
Gildas Bazin committed
1040
                             p_ogg->i_streams-1 );
Gildas Bazin's avatar
 
Gildas Bazin committed
1041 1042
                    free( p_stream );
                    p_ogg->i_streams--;
Gildas Bazin's avatar
 
Gildas Bazin committed
1043 1044
                }

1045
                if( Ogg_ReadPage( p_demux, &oggpage ) != VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
                    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
1060

Gildas Bazin's avatar
 
Gildas Bazin committed
1061 1062 1063
            return VLC_SUCCESS;
        }
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
1064 1065
#undef p_stream

Gildas Bazin's avatar
 
Gildas Bazin committed
1066 1067 1068
    return VLC_EGENERIC;
}

Gildas Bazin's avatar
 
Gildas Bazin committed
1069
/****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
1070 1071
 * Ogg_BeginningOfStream: Look for Beginning of Stream ogg pages and add
 *                        Elementary streams.
Gildas Bazin's avatar
 
Gildas Bazin committed
1072
 ****************************************************************************/
1073
static int Ogg_BeginningOfStream( demux_t *p_demux )
Gildas Bazin's avatar
 
Gildas Bazin committed
1074
{
1075
    demux_sys_t *p_ogg = p_demux->p_sys  ;
Gildas Bazin's avatar
 
Gildas Bazin committed
1076 1077 1078 1079
    int i_stream;

    /* Find the logical streams embedded in the physical stream and
     * initialize our p_ogg structure. */
1080
    if( Ogg_FindLogicalStreams( p_demux ) != VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
1081
    {
1082
        msg_Warn( p_demux, "couldn't find any ogg logical stream" );
Gildas Bazin's avatar
 
Gildas Bazin committed
1083 1084 1085
        return VLC_EGENERIC;
    }

1086
    p_ogg->i_bitrate = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
1087 1088 1089 1090

    for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ )
    {
#define p_stream p_ogg->pp_stream[i_stream]
1091
        p_stream->p_es = es_out_Add( p_demux->out, &p_stream->fmt );
Gildas Bazin's avatar
 
Gildas Bazin committed
1092

1093 1094 1095
        if( p_stream->fmt.i_codec == VLC_FOURCC('c','m','m','l') )
        {
            /* Set the CMML stream active */
1096
            es_out_Control( p_demux->out, ES_OUT_SET_ES, p_stream->p_es );
1097 1098
        }

1099
        p_ogg->i_bitrate += p_stream->fmt.i_bitrate;
Gildas Bazin's avatar
 
Gildas Bazin committed
1100

Gildas Bazin's avatar
 
Gildas Bazin committed
1101 1102
        p_stream->i_pcr = p_stream->i_previous_pcr =
            p_stream->i_interpolated_pcr = -1;
Gildas Bazin's avatar
 
Gildas Bazin committed
1103
        p_stream->b_reinit = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
1104 1105 1106
#undef p_stream
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
1107 1108
    return VLC_SUCCESS;
}
Gildas Bazin's avatar
 
Gildas Bazin committed
1109

Gildas Bazin's avatar
 
Gildas Bazin committed
1110 1111 1112
/****************************************************************************
 * Ogg_EndOfStream: clean up the ES when an End of Stream is detected.
 ****************************************************************************/
1113
static void Ogg_EndOfStream( demux_t *p_demux )
Gildas Bazin's avatar
 
Gildas Bazin committed
1114
{
1115
    demux_sys_t *p_ogg = p_demux->p_sys  ;
1116
    int i_stream;
Gildas Bazin's avatar
 
Gildas Bazin committed
1117

Gildas Bazin's avatar
 
Gildas Bazin committed
1118 1119 1120
#define p_stream p_ogg->pp_stream[i_stream]
    for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
1121
        if( p_stream->p_es )
1122
            es_out_Del( p_demux->out, p_stream->p_es );
Gildas Bazin's avatar
 
Gildas Bazin committed
1123

1124
        p_ogg->i_bitrate -= p_stream->fmt.i_bitrate;
Gildas Bazin's avatar
 
Gildas Bazin committed
1125 1126

        ogg_stream_clear( &p_ogg->pp_stream[i_stream]->os );
1127 1128
        if( p_ogg->pp_stream[i_stream]->p_headers)
            free( p_ogg->pp_stream[i_stream]->p_headers );
Gildas Bazin's avatar
 
Gildas Bazin committed
1129

Gildas Bazin's avatar