]> git.sesse.net Git - vlc/blob - modules/demux/ogg.c
* modules/demux/ogg.c: call ogg_sync_reset() after seeking so we don't get spurious...
[vlc] / modules / demux / ogg.c
1 /*****************************************************************************
2  * ogg.c : ogg stream input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: ogg.c,v 1.44 2003/11/18 00:57:04 gbazin Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>
29
30 #include <vlc/vlc.h>
31 #include <vlc/input.h>
32
33 #include <sys/types.h>
34
35 #include <ogg/ogg.h>
36
37 #include <codecs.h>                        /* BITMAPINFOHEADER, WAVEFORMATEX */
38
39 #define OGG_BLOCK_SIZE 4096
40
41 /*****************************************************************************
42  * Definitions of structures and functions used by this plugins
43  *****************************************************************************/
44 typedef struct logical_stream_s
45 {
46     ogg_stream_state os;                        /* logical stream of packets */
47
48     int              i_serial_no;
49     int              i_cat;                            /* AUDIO_ES, VIDEO_ES */
50     int              i_activated;
51     vlc_fourcc_t     i_fourcc;
52     vlc_fourcc_t     i_codec;
53
54     es_descriptor_t  *p_es;
55     int              b_selected;                           /* newly selected */
56
57     /* the header of some logical streams (eg vorbis) contain essential
58      * data for the decoder. We back them up here in case we need to re-feed
59      * them to the decoder. */
60     int              b_force_backup;
61     int              i_packets_backup;
62     ogg_packet       *p_packets_backup;
63
64     /* program clock reference (in units of 90kHz) derived from the previous
65      * granulepos */
66     mtime_t          i_pcr;
67     mtime_t          i_interpolated_pcr;
68     mtime_t          i_previous_pcr;
69
70     /* info from logical streams */
71     double f_rate;
72     int i_bitrate;
73     int i_channels;
74     int b_reinit;
75
76     /* codec specific stuff */
77     BITMAPINFOHEADER *p_bih;
78     WAVEFORMATEX *p_wf;
79     int i_theora_keyframe_granule_shift;
80
81 } logical_stream_t;
82
83 struct demux_sys_t
84 {
85     ogg_sync_state oy;        /* sync and verify incoming physical bitstream */
86
87     int i_streams;                           /* number of logical bitstreams */
88     logical_stream_t **pp_stream;  /* pointer to an array of logical streams */
89
90     /* current audio and video es */
91     logical_stream_t *p_stream_video;
92     logical_stream_t *p_stream_audio;
93     logical_stream_t *p_stream_spu;
94
95     /* program clock reference (in units of 90kHz) derived from the pcr of
96      * the sub-streams */
97     mtime_t i_pcr;
98     int     b_reinit;
99     int     i_prev_sync_state;
100
101     /* stream state */
102     int     i_eos;
103 };
104
105 /* OggDS headers for the new header format (used in ogm files) */
106 typedef struct stream_header_video
107 {
108     ogg_int32_t width;
109     ogg_int32_t height;
110 } stream_header_video;
111
112 typedef struct stream_header_audio
113 {
114     ogg_int16_t channels;
115     ogg_int16_t blockalign;
116     ogg_int32_t avgbytespersec;
117 } stream_header_audio;
118
119 typedef struct stream_header
120 {
121     char        streamtype[8];
122     char        subtype[4];
123
124     ogg_int32_t size;                               /* size of the structure */
125
126     ogg_int64_t time_unit;                              /* in reference time */
127     ogg_int64_t samples_per_unit;
128     ogg_int32_t default_len;                                /* in media time */
129
130     ogg_int32_t buffersize;
131     ogg_int16_t bits_per_sample;
132
133     union
134     {
135         /* Video specific */
136         stream_header_video video;
137         /* Audio specific */
138         stream_header_audio audio;
139     } sh;
140 } stream_header;
141
142 /* Some defines from OggDS */
143 #define PACKET_TYPE_HEADER   0x01
144 #define PACKET_TYPE_BITS     0x07
145 #define PACKET_LEN_BITS01    0xc0
146 #define PACKET_LEN_BITS2     0x02
147 #define PACKET_IS_SYNCPOINT  0x08
148
149 /*****************************************************************************
150  * Local prototypes
151  *****************************************************************************/
152 static int  Activate  ( vlc_object_t * );
153 static void Deactivate( vlc_object_t * );
154 static int  Demux     ( input_thread_t * );
155 static int  Control   ( input_thread_t *, int, va_list );
156
157 /* Stream managment */
158 static int  Ogg_ElemStreamStart  ( input_thread_t *, demux_sys_t *, int );
159 static void Ogg_ElemStreamStop   ( input_thread_t *, demux_sys_t *, int );
160
161 /* Bitstream manipulation */
162 static int  Ogg_Check        ( input_thread_t *p_input );
163 static int  Ogg_ReadPage     ( input_thread_t *, demux_sys_t *, ogg_page * );
164 static void Ogg_UpdatePCR    ( logical_stream_t *, ogg_packet * );
165 static void Ogg_DecodePacket ( input_thread_t *p_input,
166                                logical_stream_t *p_stream, ogg_packet * );
167
168 static int Ogg_BeginningOfStream( input_thread_t *p_input, demux_sys_t *p_ogg);
169 static int Ogg_FindLogicalStreams( input_thread_t *p_input,demux_sys_t *p_ogg);
170 static void Ogg_EndOfStream( input_thread_t *p_input, demux_sys_t *p_ogg );
171
172 /*****************************************************************************
173  * Module descriptor
174  *****************************************************************************/
175 vlc_module_begin();
176     set_description( _("ogg stream demuxer" ) );
177     set_capability( "demux", 50 );
178     set_callbacks( Activate, Deactivate );
179     add_shortcut( "ogg" );
180 vlc_module_end();
181
182 /*****************************************************************************
183  * Stream managment
184  *****************************************************************************/
185 static int Ogg_ElemStreamStart( input_thread_t *p_input,
186                                 demux_sys_t *p_ogg, int i_stream )
187 {
188 #define p_stream p_ogg->pp_stream[i_stream]
189     if( !p_stream->p_es )
190     {
191         msg_Warn( p_input, "stream[%d] unselectable", i_stream );
192         return( 0 );
193     }
194     if( p_stream->i_activated )
195     {
196         msg_Warn( p_input, "stream[%d] already selected", i_stream );
197         return( 1 );
198     }
199
200     if( !p_stream->p_es->p_decoder_fifo )
201     {
202         vlc_mutex_lock( &p_input->stream.stream_lock );
203         input_SelectES( p_input, p_stream->p_es );
204         vlc_mutex_unlock( &p_input->stream.stream_lock );
205     }
206     p_stream->i_activated = p_stream->p_es->p_decoder_fifo ? 1 : 0;
207
208     /* Feed the backup header to the decoder */
209     if( !p_stream->b_force_backup )
210     {
211         int i;
212         for( i = 0; i < p_stream->i_packets_backup; i++ )
213         {
214             /* Set correct starting date in header packets */
215             p_stream->p_packets_backup[i].granulepos =
216                 p_stream->i_interpolated_pcr * p_stream->f_rate / 90000;
217
218             Ogg_DecodePacket( p_input, p_stream,
219                               &p_stream->p_packets_backup[i] );
220         }
221     }
222
223     return( p_stream->i_activated );
224 #undef  p_stream
225 }
226
227 static void Ogg_ElemStreamStop( input_thread_t *p_input,
228                                 demux_sys_t *p_ogg, int i_stream )
229 {
230 #define p_stream    p_ogg->pp_stream[i_stream]
231
232     if( !p_stream->i_activated )
233     {
234         msg_Warn( p_input, "stream[%d] already unselected", i_stream );
235         return;
236     }
237
238     if( p_stream->p_es->p_decoder_fifo )
239     {
240         vlc_mutex_lock( &p_input->stream.stream_lock );
241         input_UnselectES( p_input, p_stream->p_es );
242         vlc_mutex_unlock( &p_input->stream.stream_lock );
243     }
244
245     p_stream->i_activated = 0;
246
247 #undef  p_stream
248 }
249
250 /****************************************************************************
251  * Ogg_Check: Check we are dealing with an ogg stream.
252  ****************************************************************************/
253 static int Ogg_Check( input_thread_t *p_input )
254 {
255     uint8_t *p_peek;
256     int i_size = input_Peek( p_input, &p_peek, 4 );
257
258     /* Check for the Ogg capture pattern */
259     if( !(i_size>3) || !(p_peek[0] == 'O') || !(p_peek[1] == 'g') ||
260         !(p_peek[2] == 'g') || !(p_peek[3] == 'S') )
261         return VLC_EGENERIC;
262
263     /* FIXME: Capture pattern might not be enough so we can also check for the
264      * the first complete page */
265
266     return VLC_SUCCESS;
267 }
268
269 /****************************************************************************
270  * Ogg_ReadPage: Read a full Ogg page from the physical bitstream.
271  ****************************************************************************
272  * Returns VLC_SUCCESS if a page has been read. An error might happen if we
273  * are at the end of stream.
274  ****************************************************************************/
275 static int Ogg_ReadPage( input_thread_t *p_input, demux_sys_t *p_ogg,
276                          ogg_page *p_oggpage )
277 {
278     int i_read = 0;
279     data_packet_t *p_data;
280     byte_t *p_buffer;
281
282     while( ogg_sync_pageout( &p_ogg->oy, p_oggpage ) != 1 )
283     {
284         i_read = input_SplitBuffer( p_input, &p_data, OGG_BLOCK_SIZE );
285         if( i_read <= 0 )
286             return VLC_EGENERIC;
287
288         p_buffer = ogg_sync_buffer( &p_ogg->oy, i_read );
289         p_input->p_vlc->pf_memcpy( p_buffer, p_data->p_payload_start, i_read );
290         ogg_sync_wrote( &p_ogg->oy, i_read );
291         input_DeletePacket( p_input->p_method_data, p_data );
292     }
293
294     return VLC_SUCCESS;
295 }
296
297 /****************************************************************************
298  * Ogg_UpdatePCR: update the PCR (90kHz program clock reference) for the
299  *                current stream.
300  ****************************************************************************/
301 static void Ogg_UpdatePCR( logical_stream_t *p_stream,
302                            ogg_packet *p_oggpacket )
303 {
304     /* Convert the granulepos into a pcr */
305     if( p_oggpacket->granulepos >= 0 )
306     {
307         if( p_stream->i_fourcc != VLC_FOURCC( 't','h','e','o' ) )
308         {
309             p_stream->i_pcr = p_oggpacket->granulepos * 90000
310                               / p_stream->f_rate;
311         }
312         else
313         {
314             ogg_int64_t iframe = p_oggpacket->granulepos >>
315               p_stream->i_theora_keyframe_granule_shift;
316             ogg_int64_t pframe = p_oggpacket->granulepos -
317               ( iframe << p_stream->i_theora_keyframe_granule_shift );
318
319             p_stream->i_pcr = ( iframe + pframe ) * 90000
320                               / p_stream->f_rate;
321         }
322
323         p_stream->i_interpolated_pcr = p_stream->i_pcr;
324     }
325     else
326     {
327         p_stream->i_pcr = -1;
328
329         /* no granulepos available, try to interpolate the pcr.
330          * If we can't then don't touch the old value. */
331         if( p_stream->i_cat == VIDEO_ES )
332             /* 1 frame per packet */
333             p_stream->i_interpolated_pcr += (90000 / p_stream->f_rate);
334         else if( p_stream->i_bitrate )
335             p_stream->i_interpolated_pcr += ( p_oggpacket->bytes * 90000
336                                               / p_stream->i_bitrate / 8 );
337     }
338 }
339
340 /****************************************************************************
341  * Ogg_DecodePacket: Decode an Ogg packet.
342  ****************************************************************************/
343 static void Ogg_DecodePacket( input_thread_t *p_input,
344                               logical_stream_t *p_stream,
345                               ogg_packet *p_oggpacket )
346 {
347     pes_packet_t  *p_pes;
348     data_packet_t *p_data;
349     vlc_bool_t b_trash = VLC_FALSE;
350     int i_header_len = 0;
351     mtime_t i_pts;
352
353     if( p_stream->b_force_backup )
354     {
355         ogg_packet *p_packet_backup;
356         p_stream->i_packets_backup++;
357         switch( p_stream->i_fourcc )
358         {
359         case VLC_FOURCC( 'v','o','r','b' ):
360         case VLC_FOURCC( 's','p','x',' ' ):
361         case VLC_FOURCC( 't','h','e','o' ):
362           if( p_stream->i_packets_backup == 3 ) p_stream->b_force_backup = 0;
363           break;
364
365         case VLC_FOURCC( 'f','l','a','c' ):
366           if( p_stream->i_packets_backup == 2 )
367           {
368 #ifdef HAVE_OGGPACKB
369               oggpack_buffer opb;
370               char title[sizeof("Stream") + 10];
371               input_info_category_t *p_cat;
372
373               sprintf( title, "Stream %d", p_stream->i_serial_no );
374               p_cat = input_InfoCategory( p_input, title );
375               input_AddInfo( p_cat, _("Type"), _("Audio") );
376               input_AddInfo( p_cat, _("Codec"), _("Flac") );
377
378               /* Parse the STREAMINFO metadata */
379               oggpackB_readinit(&opb, p_oggpacket->packet, p_oggpacket->bytes);
380               oggpackB_adv( &opb, 1 );
381               if( oggpackB_read( &opb, 7 ) == 0 )
382               {
383                   if( oggpackB_read( &opb, 24 ) >= 34 /*size STREAMINFO*/ )
384                   {
385                       oggpackB_adv( &opb, 80 );
386                       p_stream->f_rate = oggpackB_read( &opb, 20 );
387                       p_stream->i_channels = oggpackB_read( &opb, 3 ) + 1;
388
389                       input_AddInfo( p_cat, _("Sample Rate"), "%d",
390                                      (int)p_stream->f_rate );
391                       input_AddInfo( p_cat, _("Channels"), "%d",
392                                      p_stream->i_channels );
393                       msg_Dbg( p_input, "Flac header, channels: %i, rate: %i",
394                                p_stream->i_channels, (int)p_stream->f_rate );
395                   }
396                   else
397                   {
398                       msg_Dbg( p_input, "FLAC STREAMINFO metadata too short" );
399                   }
400               }
401               else
402               {
403                   /* This ain't a STREAMINFO metadata */
404                   msg_Dbg( p_input, "Invalid FLAC STREAMINFO metadata" );
405               }
406 #endif
407               p_stream->b_force_backup = 0;
408           }
409           break;
410
411         default:
412           p_stream->b_force_backup = 0;
413           break;
414         }
415
416         /* Backup the ogg packet (likely an header packet) */
417         p_stream->p_packets_backup =
418             realloc( p_stream->p_packets_backup, p_stream->i_packets_backup *
419                      sizeof(ogg_packet) );
420
421         p_packet_backup =
422             &p_stream->p_packets_backup[p_stream->i_packets_backup - 1];
423
424         p_packet_backup->bytes = p_oggpacket->bytes;
425         p_packet_backup->granulepos = p_oggpacket->granulepos;
426
427         if( p_oggpacket->granulepos >= 0 )
428         {
429             /* Because of vorbis granulepos scheme we must set the pcr for the
430              * 1st header packet so it doesn't get discarded in the
431              * packetizer */
432             Ogg_UpdatePCR( p_stream, p_oggpacket );
433         }
434
435         p_packet_backup->packet = malloc( p_oggpacket->bytes );
436         if( !p_packet_backup->packet ) return;
437         memcpy( p_packet_backup->packet, p_oggpacket->packet,
438                 p_oggpacket->bytes );
439     }
440
441     vlc_mutex_lock( &p_input->stream.control.control_lock );
442     if( p_stream->i_cat == AUDIO_ES && p_input->stream.control.b_mute )
443     {
444         b_trash = VLC_TRUE;
445     }
446     vlc_mutex_unlock( &p_input->stream.control.control_lock );
447
448     /* Convert the pcr into a pts */
449     if( p_stream->i_fourcc == VLC_FOURCC( 'v','o','r','b' ) ||
450         p_stream->i_fourcc == VLC_FOURCC( 's','p','x',' ' ) ||
451         p_stream->i_fourcc == VLC_FOURCC( 'f','l','a','c' ) )
452     {
453         if( p_stream->i_pcr >= 0 )
454         {
455             /* This is for streams where the granulepos of the header packets
456              * doesn't match these of the data packets (eg. ogg web radios). */
457             if( p_stream->i_previous_pcr == 0 &&
458                 p_stream->i_pcr  > 3 * DEFAULT_PTS_DELAY * 9/100 )
459                 p_input->stream.p_selected_program->i_synchro_state =
460                     SYNCHRO_REINIT;
461
462             p_stream->i_previous_pcr = p_stream->i_pcr;
463
464             /* Call the pace control */
465             if( p_input->stream.p_selected_program->i_synchro_state ==
466                 SYNCHRO_REINIT )
467             input_ClockManageRef( p_input,
468                                   p_input->stream.p_selected_program,
469                                   p_stream->i_pcr );
470         }
471
472         /* The granulepos is the end date of the sample */
473         i_pts = ( p_stream->i_pcr < 0 ) ? 0 :
474             input_ClockGetTS( p_input, p_input->stream.p_selected_program,
475                               p_stream->i_pcr );
476
477         /* Convert the granulepos into the next pcr */
478         Ogg_UpdatePCR( p_stream, p_oggpacket );
479     }
480     else
481     {
482         /* Convert the granulepos into the current pcr */
483         Ogg_UpdatePCR( p_stream, p_oggpacket );
484
485         if( p_stream->i_pcr >= 0 )
486         {
487             /* This is for streams where the granulepos of the header packets
488              * doesn't match these of the data packets (eg. ogg web radios). */
489             if( p_stream->i_previous_pcr == 0 &&
490                 p_stream->i_pcr  > 3 * DEFAULT_PTS_DELAY * 9/100 )
491                 p_input->stream.p_selected_program->i_synchro_state =
492                     SYNCHRO_REINIT;
493
494             p_stream->i_previous_pcr = p_stream->i_pcr;
495
496             /* Call the pace control */
497             if( p_input->stream.p_selected_program->i_synchro_state ==
498                 SYNCHRO_REINIT )
499             input_ClockManageRef( p_input,
500                                   p_input->stream.p_selected_program,
501                                   p_stream->i_pcr );
502         }
503
504         /* The granulepos is the start date of the sample */
505         i_pts = ( p_stream->i_pcr < 0 ) ? 0 :
506             input_ClockGetTS( p_input, p_input->stream.p_selected_program,
507                               p_stream->i_pcr );
508     }
509
510     if( !p_stream->p_es->p_decoder_fifo || b_trash )
511     {
512         /* This stream isn't currently selected so we don't need to decode it,
513          * but we did need to store its pcr as it might be selected later on */
514         return;
515     }
516
517     if( !( p_pes = input_NewPES( p_input->p_method_data ) ) )
518     {
519         return;
520     }
521     if( !( p_data = input_NewPacket( p_input->p_method_data,
522                                      p_oggpacket->bytes ) ) )
523     {
524         input_DeletePES( p_input->p_method_data, p_pes );
525         return;
526     }
527     p_data->p_payload_end = p_data->p_payload_start + p_oggpacket->bytes;
528
529     p_pes->i_nb_data = 1;
530     p_pes->i_dts = p_pes->i_pts = i_pts;
531     p_pes->p_first = p_pes->p_last = p_data;
532     p_pes->i_pes_size = p_oggpacket->bytes;
533
534     if( p_stream->i_cat == SPU_ES ) p_pes->i_dts = 0;
535
536     if( p_stream->i_fourcc != VLC_FOURCC( 'v','o','r','b' ) &&
537         p_stream->i_fourcc != VLC_FOURCC( 's','p','x',' ' ) &&
538         p_stream->i_fourcc != VLC_FOURCC( 'f','l','a','c' ) &&
539         p_stream->i_fourcc != VLC_FOURCC( 't','a','r','k' ) &&
540         p_stream->i_fourcc != VLC_FOURCC( 't','h','e','o' ) )
541     {
542         /* Remove the header from the packet */
543         i_header_len = (*p_oggpacket->packet & PACKET_LEN_BITS01) >> 6;
544         i_header_len |= (*p_oggpacket->packet & PACKET_LEN_BITS2) << 1;
545         i_header_len++;
546
547         p_pes->i_pes_size -= i_header_len;
548     }
549
550     if( p_stream->i_fourcc == VLC_FOURCC( 't','a','r','k' ) )
551     {
552         /* FIXME: the biggest hack I've ever done */
553         msg_Warn( p_input, "tark pts: "I64Fd", granule: "I64Fd,
554                   p_pes->i_pts, p_pes->i_dts );
555         msleep(10000);
556     }
557
558     memcpy( p_data->p_payload_start,
559             p_oggpacket->packet + i_header_len,
560             p_oggpacket->bytes - i_header_len );
561
562     p_data->p_payload_end = p_data->p_payload_start + p_pes->i_pes_size;
563     p_data->b_discard_payload = 0;
564
565     input_DecodePES( p_stream->p_es->p_decoder_fifo, p_pes );
566 }
567
568 /****************************************************************************
569  * Ogg_FindLogicalStreams: Find the logical streams embedded in the physical
570  *                         stream and fill p_ogg.
571  *****************************************************************************
572  * The initial page of a logical stream is marked as a 'bos' page.
573  * Furthermore, the Ogg specification mandates that grouped bitstreams begin
574  * together and all of the initial pages must appear before any data pages.
575  *
576  * On success this function returns VLC_SUCCESS.
577  ****************************************************************************/
578 static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
579 {
580     ogg_packet oggpacket;
581     ogg_page oggpage;
582     int i_stream;
583
584     while( Ogg_ReadPage( p_input, p_ogg, &oggpage ) == VLC_SUCCESS )
585     {
586         if( ogg_page_bos( &oggpage ) )
587         {
588
589             /* All is wonderful in our fine fine little world.
590              * We found the beginning of our first logical stream. */
591             while( ogg_page_bos( &oggpage ) )
592             {
593                 p_ogg->i_streams++;
594                 p_ogg->pp_stream =
595                     realloc( p_ogg->pp_stream, p_ogg->i_streams *
596                              sizeof(logical_stream_t *) );
597
598 #define p_stream p_ogg->pp_stream[p_ogg->i_streams - 1]
599
600                 p_stream = malloc( sizeof(logical_stream_t) );
601                 memset( p_stream, 0, sizeof(logical_stream_t) );
602
603                 /* Setup the logical stream */
604                 p_stream->i_serial_no = ogg_page_serialno( &oggpage );
605                 ogg_stream_init( &p_stream->os, p_stream->i_serial_no );
606
607                 /* Extract the initial header from the first page and verify
608                  * the codec type of tis Ogg bitstream */
609                 if( ogg_stream_pagein( &p_stream->os, &oggpage ) < 0 )
610                 {
611                     /* error. stream version mismatch perhaps */
612                     msg_Err( p_input, "Error reading first page of "
613                              "Ogg bitstream data" );
614                     return VLC_EGENERIC;
615                 }
616
617                 /* FIXME: check return value */
618                 ogg_stream_packetpeek( &p_stream->os, &oggpacket );
619
620                 /* Check for Vorbis header */
621                 if( oggpacket.bytes >= 7 &&
622                     ! strncmp( &oggpacket.packet[1], "vorbis", 6 ) )
623                 {
624                     oggpack_buffer opb;
625
626                     msg_Dbg( p_input, "found vorbis header" );
627                     p_stream->i_cat = AUDIO_ES;
628                     p_stream->i_fourcc = VLC_FOURCC( 'v','o','r','b' );
629
630                     /* Signal that we want to keep a backup of the vorbis
631                      * stream headers. They will be used when switching between
632                      * audio streams. */
633                     p_stream->b_force_backup = 1;
634
635                     /* Cheat and get additionnal info ;) */
636                     oggpack_readinit( &opb, oggpacket.packet, oggpacket.bytes);
637                     oggpack_adv( &opb, 88 );
638                     p_stream->i_channels = oggpack_read( &opb, 8 );
639                     p_stream->f_rate = oggpack_read( &opb, 32 );
640                     oggpack_adv( &opb, 32 );
641                     p_stream->i_bitrate = oggpack_read( &opb, 32 );
642                     {
643                         char title[sizeof("Stream") + 10];
644                         input_info_category_t *p_cat;
645                         sprintf( title, "Stream %d", p_ogg->i_streams );
646                         p_cat = input_InfoCategory( p_input, title );
647                         input_AddInfo( p_cat, _("Type"), _("Audio") );
648                         input_AddInfo( p_cat, _("Codec"), _("Vorbis") );
649                         input_AddInfo( p_cat, _("Sample Rate"), "%d",
650                                        (int)p_stream->f_rate );
651                         input_AddInfo( p_cat, _("Channels"), "%d",
652                                        p_stream->i_channels );
653                         input_AddInfo( p_cat, _("Bit Rate"), "%d",
654                                        p_stream->i_bitrate );
655                     }
656                 }
657                 /* Check for Speex header */
658                 else if( oggpacket.bytes >= 7 &&
659                     ! strncmp( &oggpacket.packet[0], "Speex", 5 ) )
660                 {
661                     oggpack_buffer opb;
662
663                     p_stream->i_cat = AUDIO_ES;
664                     p_stream->i_fourcc = VLC_FOURCC( 's','p','x',' ' );
665
666                     /* Signal that we want to keep a backup of the vorbis
667                      * stream headers. They will be used when switching between
668                      * audio streams. */
669                     p_stream->b_force_backup = 1;
670
671                     /* Cheat and get additionnal info ;) */
672                     oggpack_readinit( &opb, oggpacket.packet, oggpacket.bytes);
673                     oggpack_adv( &opb, 224 );
674                     oggpack_adv( &opb, 32 ); /* speex_version_id */
675                     oggpack_adv( &opb, 32 ); /* header_size */
676                     p_stream->f_rate = oggpack_read( &opb, 32 );
677                     oggpack_adv( &opb, 32 ); /* mode */
678                     oggpack_adv( &opb, 32 ); /* mode_bitstream_version */
679                     p_stream->i_channels = oggpack_read( &opb, 32 );
680                     p_stream->i_bitrate = oggpack_read( &opb, 32 );
681                     {
682                         char title[sizeof("Stream") + 10];
683                         input_info_category_t *p_cat;
684                         sprintf( title, "Stream %d", p_ogg->i_streams );
685                         p_cat = input_InfoCategory( p_input, title );
686                         input_AddInfo( p_cat, _("Type"), _("Audio") );
687                         input_AddInfo( p_cat, _("Codec"), _("Speex") );
688                         input_AddInfo( p_cat, _("Sample Rate"), "%d",
689                                        (int)p_stream->f_rate );
690                         input_AddInfo( p_cat, _("Channels"), "%d",
691                                        p_stream->i_channels );
692                         input_AddInfo( p_cat, _("Bit Rate"), "%d",
693                                        p_stream->i_bitrate );
694                         msg_Dbg( p_input, "found speex header, channels: %i, "
695                                  "rate: %i,  bitrate: %i",
696                                  p_stream->i_channels,
697                                  (int)p_stream->f_rate, p_stream->i_bitrate );
698                     }
699                 }
700                 /* Check for Flac header */
701                 else if( oggpacket.bytes >= 4 &&
702                     ! strncmp( &oggpacket.packet[0], "fLaC", 4 ) )
703                 {
704                     msg_Dbg( p_input, "found Flac header" );
705
706                     /* Grrrr!!!! Did they really have to put all the
707                      * important info in the second header packet!!!
708                      * (STREAMINFO metadata is in the following packet) */
709                     p_stream->b_force_backup = 1;
710
711                     p_stream->i_cat = AUDIO_ES;
712                     p_stream->i_fourcc = VLC_FOURCC( 'f','l','a','c' );
713                     p_stream->i_bitrate = 0;
714                 }
715                 /* Check for Theora header */
716                 else if( oggpacket.bytes >= 7 &&
717                          ! strncmp( &oggpacket.packet[1], "theora", 6 ) )
718                 {
719 #ifdef HAVE_OGGPACKB
720                     oggpack_buffer opb;
721                     int i_fps_numerator;
722                     int i_fps_denominator;
723                     int i_keyframe_frequency_force;
724 #endif
725
726                     msg_Dbg( p_input, "found theora header" );
727 #ifdef HAVE_OGGPACKB
728                     p_stream->i_cat = VIDEO_ES;
729                     p_stream->i_fourcc = VLC_FOURCC( 't','h','e','o' );
730
731                     /* Signal that we want to keep a backup of the vorbis
732                      * stream headers. They will be used when switching between
733                      * audio streams. */
734                     p_stream->b_force_backup = 1;
735
736                     /* Cheat and get additionnal info ;) */
737                     oggpackB_readinit(&opb, oggpacket.packet, oggpacket.bytes);
738                     oggpackB_adv( &opb, 56 );
739                     oggpackB_read( &opb, 8 ); /* major version num */
740                     oggpackB_read( &opb, 8 ); /* minor version num */
741                     oggpackB_read( &opb, 8 ); /* subminor version num */
742                     oggpackB_read( &opb, 16 ) /*<< 4*/; /* width */
743                     oggpackB_read( &opb, 16 ) /*<< 4*/; /* height */
744                     oggpackB_read( &opb, 24 ); /* frame width */
745                     oggpackB_read( &opb, 24 ); /* frame height */
746                     oggpackB_read( &opb, 8 ); /* x offset */
747                     oggpackB_read( &opb, 8 ); /* y offset */
748
749                     i_fps_numerator = oggpackB_read( &opb, 32 );
750                     i_fps_denominator = oggpackB_read( &opb, 32 );
751                     oggpackB_read( &opb, 24 ); /* aspect_numerator */
752                     oggpackB_read( &opb, 24 ); /* aspect_denominator */
753                     i_keyframe_frequency_force = 1 << oggpackB_read( &opb, 5 );
754                     oggpackB_read( &opb, 8 ); /* colorspace */
755                     p_stream->i_bitrate = oggpackB_read( &opb, 24 );
756                     oggpackB_read( &opb, 6 ); /* quality */
757
758                     /* granule_shift = i_log( frequency_force -1 ) */
759                     p_stream->i_theora_keyframe_granule_shift = 0;
760                     i_keyframe_frequency_force--;
761                     while( i_keyframe_frequency_force )
762                     {
763                         p_stream->i_theora_keyframe_granule_shift++;
764                         i_keyframe_frequency_force >>= 1;
765                     }
766
767                     p_stream->f_rate = ((float)i_fps_numerator) /
768                                                 i_fps_denominator;
769                     msg_Dbg( p_input,
770                              "found theora header, bitrate: %i, rate: %f",
771                              p_stream->i_bitrate, p_stream->f_rate );
772                     {
773                         char title[sizeof("Stream") + 10];
774                         input_info_category_t *p_cat;
775                         sprintf( title, "Stream %d", p_ogg->i_streams );
776                         p_cat = input_InfoCategory( p_input, title );
777                         input_AddInfo( p_cat, _("Type"), _("Video") );
778                         input_AddInfo( p_cat, _("Codec"), _("Theora") );
779                         input_AddInfo( p_cat, _("Frame Rate"), "%.2f",
780                                        p_stream->f_rate );
781                         input_AddInfo( p_cat, _("Bit Rate"), "%d",
782                                        p_stream->i_bitrate );
783                     }
784 #else /* HAVE_OGGPACKB */
785                     msg_Dbg( p_input, "the ogg demuxer has been compiled "
786                              "without support for the oggpackB extension."
787                              "The theora stream won't be decoded." );
788                     free( p_stream );
789                     p_ogg->i_streams--;
790 #endif /* HAVE_OGGPACKB */
791                 }
792                 /* Check for Tarkin header */
793                 else if( oggpacket.bytes >= 7 &&
794                          ! strncmp( &oggpacket.packet[1], "tarkin", 6 ) )
795                 {
796                     oggpack_buffer opb;
797
798                     msg_Dbg( p_input, "found tarkin header" );
799                     p_stream->i_cat = VIDEO_ES;
800                     p_stream->i_fourcc = VLC_FOURCC( 't','a','r','k' );
801
802                     /* Cheat and get additionnal info ;) */
803                     oggpack_readinit( &opb, oggpacket.packet, oggpacket.bytes);
804                     oggpack_adv( &opb, 88 );
805                     oggpack_adv( &opb, 104 );
806                     p_stream->i_bitrate = oggpack_read( &opb, 32 );
807                     p_stream->f_rate = 2; /* FIXME */
808                     msg_Dbg( p_input,
809                              "found tarkin header, bitrate: %i, rate: %f",
810                              p_stream->i_bitrate, p_stream->f_rate );
811                                         {
812                         char title[sizeof("Stream") + 10];
813                         input_info_category_t *p_cat;
814                         sprintf( title, "Stream %d", p_ogg->i_streams );
815                         p_cat = input_InfoCategory( p_input, title );
816                         input_AddInfo( p_cat, _("Type"), _("Video") );
817                         input_AddInfo( p_cat, _("Codec"), _("tarkin") );
818                         input_AddInfo( p_cat, _("Sample Rate"), "%d",
819                                        (int)p_stream->f_rate );
820                         input_AddInfo( p_cat, _("Bit Rate"), "%d",
821                                        p_stream->i_bitrate );
822                     }
823
824                 }
825                 else if( oggpacket.bytes >= 142 &&
826                          !strncmp( &oggpacket.packet[1],
827                                    "Direct Show Samples embedded in Ogg", 35 ))
828                 {
829                     /* Old header type */
830
831                     /* Check for video header (old format) */
832                     if( GetDWLE((oggpacket.packet+96)) == 0x05589f80 &&
833                         oggpacket.bytes >= 184 )
834                     {
835                         p_stream->i_cat = VIDEO_ES;
836
837                         p_stream->p_bih = (BITMAPINFOHEADER *)
838                             malloc( sizeof(BITMAPINFOHEADER) );
839                         if( !p_stream->p_bih )
840                         {
841                             /* Mem allocation error, just ignore the stream */
842                             free( p_stream );
843                             p_ogg->i_streams--;
844                             break;
845                         }
846                         p_stream->p_bih->biSize = sizeof(BITMAPINFOHEADER);
847                         p_stream->p_bih->biCompression= p_stream->i_fourcc =
848                             VLC_FOURCC( oggpacket.packet[68],
849                                         oggpacket.packet[69],
850                                         oggpacket.packet[70],
851                                         oggpacket.packet[71] );
852                         msg_Dbg( p_input, "found video header of type: %.4s",
853                                  (char *)&p_stream->i_fourcc );
854
855                         p_stream->f_rate = 10000000.0 /
856                             GetQWLE((oggpacket.packet+164));
857                         p_stream->p_bih->biBitCount =
858                             GetWLE((oggpacket.packet+182));
859                         if( !p_stream->p_bih->biBitCount )
860                             p_stream->p_bih->biBitCount=24; // hack, FIXME
861                         p_stream->p_bih->biWidth =
862                             GetDWLE((oggpacket.packet+176));
863                         p_stream->p_bih->biHeight =
864                             GetDWLE((oggpacket.packet+180));
865                         p_stream->p_bih->biPlanes= 1 ;
866                         p_stream->p_bih->biSizeImage =
867                             (p_stream->p_bih->biBitCount >> 3) *
868                             p_stream->p_bih->biWidth *
869                             p_stream->p_bih->biHeight;
870
871                         msg_Dbg( p_input,
872                              "fps: %f, width:%i; height:%i, bitcount:%i",
873                             p_stream->f_rate, p_stream->p_bih->biWidth,
874                             p_stream->p_bih->biHeight,
875                             p_stream->p_bih->biBitCount);
876                         {
877                             char title[sizeof("Stream") + 10];
878                             input_info_category_t *p_cat;
879                             sprintf( title, "Stream %d", p_ogg->i_streams );
880                             p_cat = input_InfoCategory( p_input, title );
881                             input_AddInfo( p_cat, _("Type"), _("Video") );
882                             input_AddInfo( p_cat, _("Codec"), "%.4s",
883                                            (char *)&p_stream->i_fourcc );
884                             input_AddInfo( p_cat, _("Frame Rate"), "%.2f",
885                                            p_stream->f_rate );
886                             input_AddInfo( p_cat, _("Bit Count"), "%d",
887                                            p_stream->p_bih->biBitCount );
888                             input_AddInfo( p_cat, _("Width"), "%d",
889                                            p_stream->p_bih->biWidth );
890                             input_AddInfo( p_cat, _("Height"), "%d",
891                                            p_stream->p_bih->biHeight );
892                         }
893                         p_stream->i_bitrate = 0;
894                     }
895                     /* Check for audio header (old format) */
896                     else if( GetDWLE((oggpacket.packet+96)) == 0x05589F81 )
897                     {
898                         unsigned int i_extra_size;
899
900                         p_stream->i_cat = AUDIO_ES;
901
902                         i_extra_size = GetWLE((oggpacket.packet+140));
903
904                         p_stream->p_wf = (WAVEFORMATEX *)
905                             malloc( sizeof(WAVEFORMATEX) + i_extra_size );
906                         if( !p_stream->p_wf )
907                         {
908                             /* Mem allocation error, just ignore the stream */
909                             free( p_stream );
910                             p_ogg->i_streams--;
911                             break;
912                         }
913
914                         p_stream->p_wf->wFormatTag =
915                             GetWLE((oggpacket.packet+124));
916                         p_stream->p_wf->nChannels =
917                             GetWLE((oggpacket.packet+126));
918                         p_stream->f_rate = p_stream->p_wf->nSamplesPerSec =
919                             GetDWLE((oggpacket.packet+128));
920                         p_stream->i_bitrate = p_stream->p_wf->nAvgBytesPerSec =
921                             GetDWLE((oggpacket.packet+132));
922                         p_stream->i_bitrate *= 8;
923                         p_stream->p_wf->nBlockAlign =
924                             GetWLE((oggpacket.packet+136));
925                         p_stream->p_wf->wBitsPerSample =
926                             GetWLE((oggpacket.packet+138));
927                         p_stream->p_wf->cbSize = i_extra_size;
928
929                         if( i_extra_size > 0 )
930                             memcpy( p_stream->p_wf+sizeof(WAVEFORMATEX),
931                                     oggpacket.packet+142, i_extra_size );
932
933                         switch( p_stream->p_wf->wFormatTag )
934                         {
935                         case WAVE_FORMAT_PCM:
936                             p_stream->i_fourcc =
937                                 VLC_FOURCC( 'a', 'r', 'a', 'w' );
938                             break;
939                         case WAVE_FORMAT_MPEG:
940                         case WAVE_FORMAT_MPEGLAYER3:
941                             p_stream->i_fourcc =
942                                 VLC_FOURCC( 'm', 'p', 'g', 'a' );
943                             break;
944                         case WAVE_FORMAT_A52:
945                             p_stream->i_fourcc =
946                                 VLC_FOURCC( 'a', '5', '2', ' ' );
947                             break;
948                         case WAVE_FORMAT_WMA1:
949                             p_stream->i_fourcc =
950                                 VLC_FOURCC( 'w', 'm', 'a', '1' );
951                             break;
952                         case WAVE_FORMAT_WMA2:
953                             p_stream->i_fourcc =
954                                 VLC_FOURCC( 'w', 'm', 'a', '2' );
955                             break;
956                         default:
957                             p_stream->i_fourcc = VLC_FOURCC( 'm', 's',
958                                 ( p_stream->p_wf->wFormatTag >> 8 ) & 0xff,
959                                 p_stream->p_wf->wFormatTag & 0xff );
960                         }
961
962                         msg_Dbg( p_input, "found audio header of type: %.4s",
963                                  (char *)&p_stream->i_fourcc );
964                         msg_Dbg( p_input, "audio:0x%4.4x channels:%d %dHz "
965                                  "%dbits/sample %dkb/s",
966                                  p_stream->p_wf->wFormatTag,
967                                  p_stream->p_wf->nChannels,
968                                  p_stream->p_wf->nSamplesPerSec,
969                                  p_stream->p_wf->wBitsPerSample,
970                                  p_stream->p_wf->nAvgBytesPerSec * 8 / 1024 );
971                         {
972                             char title[sizeof("Stream") + 10];
973                             input_info_category_t *p_cat;
974                             sprintf( title, "Stream %d", p_ogg->i_streams );
975                             p_cat = input_InfoCategory( p_input, title );
976                             input_AddInfo( p_cat, _("Type"), _("Audio") );
977                             input_AddInfo( p_cat, _("Codec"), "%.4s",
978                                            (char *)&p_stream->i_fourcc );
979                             input_AddInfo( p_cat, _("Sample Rate"), "%d",
980                                            p_stream->p_wf->nSamplesPerSec );
981                             input_AddInfo( p_cat, _("Bit Rate"), "%d",
982                                            p_stream->p_wf->nAvgBytesPerSec * 8
983                                               / 1024 );
984                             input_AddInfo( p_cat, _("Channels"), "%d",
985                                            p_stream->p_wf->nChannels );
986                             input_AddInfo( p_cat, _("Bits per Sample"), "%d",
987                                            p_stream->p_wf->wBitsPerSample );
988                         }
989
990                     }
991                     else
992                     {
993                         msg_Dbg( p_input, "stream %d has an old header "
994                             "but is of an unknown type", p_ogg->i_streams-1 );
995                         free( p_stream );
996                         p_ogg->i_streams--;
997                     }
998                 }
999                 else if( (*oggpacket.packet & PACKET_TYPE_BITS )
1000                          == PACKET_TYPE_HEADER &&
1001                          oggpacket.bytes >= (int)sizeof(stream_header)+1 )
1002                 {
1003                     stream_header *st = (stream_header *)(oggpacket.packet+1);
1004
1005                     /* Check for video header (new format) */
1006                     if( !strncmp( st->streamtype, "video", 5 ) )
1007                     {
1008                         p_stream->i_cat = VIDEO_ES;
1009
1010                         /* We need to get rid of the header packet */
1011                         ogg_stream_packetout( &p_stream->os, &oggpacket );
1012
1013                         p_stream->p_bih = (BITMAPINFOHEADER *)
1014                             malloc( sizeof(BITMAPINFOHEADER) );
1015                         if( !p_stream->p_bih )
1016                         {
1017                             /* Mem allocation error, just ignore the stream */
1018                             free( p_stream );
1019                             p_ogg->i_streams--;
1020                             break;
1021                         }
1022                         p_stream->p_bih->biSize = sizeof(BITMAPINFOHEADER);
1023                         p_stream->p_bih->biCompression=
1024                             p_stream->i_fourcc = VLC_FOURCC( st->subtype[0],
1025                                                              st->subtype[1],
1026                                                              st->subtype[2],
1027                                                              st->subtype[3] );
1028                         msg_Dbg( p_input, "found video header of type: %.4s",
1029                                  (char *)&p_stream->i_fourcc );
1030
1031                         p_stream->f_rate = 10000000.0 /
1032                             GetQWLE(&st->time_unit);
1033                         p_stream->p_bih->biBitCount =
1034                             GetWLE(&st->bits_per_sample);
1035                         p_stream->p_bih->biWidth =
1036                             GetDWLE(&st->sh.video.width);
1037                         p_stream->p_bih->biHeight =
1038                             GetDWLE(&st->sh.video.height);
1039                         p_stream->p_bih->biPlanes= 1 ;
1040                         p_stream->p_bih->biSizeImage =
1041                             (p_stream->p_bih->biBitCount >> 3) *
1042                             p_stream->p_bih->biWidth *
1043                             p_stream->p_bih->biHeight;
1044
1045                         msg_Dbg( p_input,
1046                              "fps: %f, width:%i; height:%i, bitcount:%i",
1047                             p_stream->f_rate, p_stream->p_bih->biWidth,
1048                             p_stream->p_bih->biHeight,
1049                             p_stream->p_bih->biBitCount);
1050
1051                         {
1052                             char title[sizeof("Stream") + 10];
1053                             input_info_category_t *p_cat;
1054                             sprintf( title, "Stream %d", p_ogg->i_streams );
1055                             p_cat = input_InfoCategory( p_input, title );
1056                             input_AddInfo( p_cat, _("Type"), _("Video") );
1057                             input_AddInfo( p_cat, _("Codec"), "%.4s",
1058                                            (char *)&p_stream->i_fourcc );
1059                             input_AddInfo( p_cat, _("Frame Rate"), "%.2f",
1060                                            p_stream->f_rate );
1061                             input_AddInfo( p_cat, _("Bit Count"), "%d",
1062                                            p_stream->p_bih->biBitCount );
1063                             input_AddInfo( p_cat, _("Width"), "%d",
1064                                            p_stream->p_bih->biWidth );
1065                             input_AddInfo( p_cat, _("Height"), "%d",
1066                                            p_stream->p_bih->biHeight );
1067                         }
1068                         p_stream->i_bitrate = 0;
1069                     }
1070                     /* Check for audio header (new format) */
1071                     else if( !strncmp( st->streamtype, "audio", 5 ) )
1072                     {
1073                         char p_buffer[5];
1074
1075                         p_stream->i_cat = AUDIO_ES;
1076
1077                         /* We need to get rid of the header packet */
1078                         ogg_stream_packetout( &p_stream->os, &oggpacket );
1079
1080                         p_stream->p_wf = (WAVEFORMATEX *)
1081                             malloc( sizeof(WAVEFORMATEX) );
1082                         if( !p_stream->p_wf )
1083                         {
1084                             /* Mem allocation error, just ignore the stream */
1085                             free( p_stream );
1086                             p_ogg->i_streams--;
1087                             break;
1088                         }
1089
1090                         memcpy( p_buffer, st->subtype, 4 );
1091                         p_buffer[4] = '\0';
1092                         p_stream->p_wf->wFormatTag = strtol(p_buffer,NULL,16);
1093                         p_stream->p_wf->nChannels =
1094                             GetWLE(&st->sh.audio.channels);
1095                         p_stream->f_rate = p_stream->p_wf->nSamplesPerSec =
1096                             GetQWLE(&st->samples_per_unit);
1097                         p_stream->i_bitrate = p_stream->p_wf->nAvgBytesPerSec =
1098                             GetDWLE(&st->sh.audio.avgbytespersec);
1099                         p_stream->i_bitrate *= 8;
1100                         p_stream->p_wf->nBlockAlign =
1101                             GetWLE(&st->sh.audio.blockalign);
1102                         p_stream->p_wf->wBitsPerSample =
1103                             GetWLE(&st->bits_per_sample);
1104                         p_stream->p_wf->cbSize = 0;
1105
1106                         switch( p_stream->p_wf->wFormatTag )
1107                         {
1108                         case WAVE_FORMAT_PCM:
1109                             p_stream->i_fourcc =
1110                                 VLC_FOURCC( 'a', 'r', 'a', 'w' );
1111                             break;
1112                         case WAVE_FORMAT_MPEG:
1113                         case WAVE_FORMAT_MPEGLAYER3:
1114                             p_stream->i_fourcc =
1115                                 VLC_FOURCC( 'm', 'p', 'g', 'a' );
1116                             break;
1117                         case WAVE_FORMAT_A52:
1118                             p_stream->i_fourcc =
1119                                 VLC_FOURCC( 'a', '5', '2', ' ' );
1120                             break;
1121                         case WAVE_FORMAT_WMA1:
1122                             p_stream->i_fourcc =
1123                                 VLC_FOURCC( 'w', 'm', 'a', '1' );
1124                             break;
1125                         case WAVE_FORMAT_WMA2:
1126                             p_stream->i_fourcc =
1127                                 VLC_FOURCC( 'w', 'm', 'a', '2' );
1128                             break;
1129                         default:
1130                             p_stream->i_fourcc = VLC_FOURCC( 'm', 's',
1131                                 ( p_stream->p_wf->wFormatTag >> 8 ) & 0xff,
1132                                 p_stream->p_wf->wFormatTag & 0xff );
1133                         }
1134
1135                         msg_Dbg( p_input, "found audio header of type: %.4s",
1136                                  (char *)&p_stream->i_fourcc );
1137                         msg_Dbg( p_input, "audio:0x%4.4x channels:%d %dHz "
1138                                  "%dbits/sample %dkb/s",
1139                                  p_stream->p_wf->wFormatTag,
1140                                  p_stream->p_wf->nChannels,
1141                                  p_stream->p_wf->nSamplesPerSec,
1142                                  p_stream->p_wf->wBitsPerSample,
1143                                  p_stream->p_wf->nAvgBytesPerSec * 8 / 1024 );
1144                         {
1145                             char title[sizeof("Stream") + 10];
1146                             input_info_category_t *p_cat;
1147                             sprintf( title, "Stream %d", p_ogg->i_streams );
1148                             p_cat = input_InfoCategory( p_input, title );
1149                             input_AddInfo( p_cat, _("Type"), _("Audio") );
1150                             input_AddInfo( p_cat, _("Codec"), "%.4s",
1151                                            (char *)&p_stream->i_fourcc );
1152                             input_AddInfo( p_cat, _("Sample Rate"), "%d",
1153                                            p_stream->p_wf->nSamplesPerSec );
1154                             input_AddInfo( p_cat, _("Bit Rate"), "%d",
1155                                            p_stream->p_wf->nAvgBytesPerSec * 8
1156                                               / 1024 );
1157                             input_AddInfo( p_cat, _("Channels"), "%d",
1158                                            p_stream->p_wf->nChannels );
1159                             input_AddInfo( p_cat, _("Bits per Sample"), "%d",
1160                                            p_stream->p_wf->wBitsPerSample );
1161                         }
1162                     }
1163                     /* Check for text (subtitles) header */
1164                     else if( !strncmp(st->streamtype, "text", 4) )
1165                     {
1166                         /* We need to get rid of the header packet */
1167                         ogg_stream_packetout( &p_stream->os, &oggpacket );
1168
1169                         msg_Dbg( p_input, "found text subtitles header" );
1170                         p_stream->i_cat = SPU_ES;
1171                         p_stream->i_fourcc =
1172                             VLC_FOURCC( 's', 'u', 'b', 't' );
1173                         p_stream->f_rate = 1000; /* granulepos is in milisec */
1174                     }
1175                     else
1176                     {
1177                         msg_Dbg( p_input, "stream %d has a header marker "
1178                             "but is of an unknown type", p_ogg->i_streams-1 );
1179                         free( p_stream );
1180                         p_ogg->i_streams--;
1181                     }
1182                 }
1183                 else
1184                 {
1185                     msg_Dbg( p_input, "stream %d is of unknown type",
1186                              p_ogg->i_streams-1 );
1187                     free( p_stream );
1188                     p_ogg->i_streams--;
1189                 }
1190
1191 #undef p_stream
1192
1193                 if( Ogg_ReadPage( p_input, p_ogg, &oggpage ) != VLC_SUCCESS )
1194                     return VLC_EGENERIC;
1195             }
1196
1197             /* This is the first data page, which means we are now finished
1198              * with the initial pages. We just need to store it in the relevant
1199              * bitstream. */
1200             for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
1201             {
1202                 if( ogg_stream_pagein( &p_ogg->pp_stream[i_stream]->os,
1203                                        &oggpage ) == 0 )
1204                 {
1205                     break;
1206                 }
1207             }
1208             return VLC_SUCCESS;
1209         }
1210     }
1211     return VLC_EGENERIC;
1212 }
1213
1214 /*****************************************************************************
1215  * Activate: initializes ogg demux structures
1216  *****************************************************************************/
1217 static int Activate( vlc_object_t * p_this )
1218 {
1219     input_thread_t *p_input = (input_thread_t *)p_this;
1220     demux_sys_t    *p_ogg;
1221     int            b_forced;
1222
1223     p_input->p_demux_data = NULL;
1224     b_forced = ( ( *p_input->psz_demux )&&
1225                  ( !strncmp( p_input->psz_demux, "ogg", 10 ) ) ) ? 1 : 0;
1226
1227     /* Check if we are dealing with an ogg stream */
1228     if( !b_forced && ( Ogg_Check( p_input ) != VLC_SUCCESS ) )
1229         return -1;
1230
1231     /* Allocate p_ogg */
1232     if( !( p_ogg = malloc( sizeof( demux_sys_t ) ) ) )
1233     {
1234         msg_Err( p_input, "out of memory" );
1235         goto error;
1236     }
1237     memset( p_ogg, 0, sizeof( demux_sys_t ) );
1238     p_input->p_demux_data = p_ogg;
1239     p_ogg->pp_stream = NULL;
1240     p_ogg->p_stream_video = NULL;
1241     p_ogg->p_stream_audio = NULL;
1242     p_ogg->p_stream_spu = NULL;
1243
1244     /* Initialize the Ogg physical bitstream parser */
1245     ogg_sync_init( &p_ogg->oy );
1246
1247     /*Set exported functions */
1248     p_input->pf_demux = Demux;
1249     p_input->pf_demux_control = Control;
1250
1251     /* Initialize access plug-in structures. */
1252     if( p_input->i_mtu == 0 )
1253     {
1254         /* Improve speed. */
1255         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
1256     }
1257
1258     /* Create one program */
1259     vlc_mutex_lock( &p_input->stream.stream_lock );
1260     if( input_InitStream( p_input, 0 ) == -1)
1261     {
1262         vlc_mutex_unlock( &p_input->stream.stream_lock );
1263         msg_Err( p_input, "cannot init stream" );
1264         goto error;
1265     }
1266     if( input_AddProgram( p_input, 0, 0) == NULL )
1267     {
1268         vlc_mutex_unlock( &p_input->stream.stream_lock );
1269         msg_Err( p_input, "cannot add program" );
1270         goto error;
1271     }
1272     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
1273     vlc_mutex_unlock( &p_input->stream.stream_lock );
1274
1275     /* Begnning of stream, tell the demux to look for elementary streams. */
1276     p_ogg->i_eos = 0;
1277
1278     p_ogg->i_prev_sync_state = SYNCHRO_REINIT;
1279
1280     return 0;
1281
1282  error:
1283     Deactivate( (vlc_object_t *)p_input );
1284     return -1;
1285
1286 }
1287
1288 /****************************************************************************
1289  * Ogg_BeginningOfStream: Look for Beginning of Stream ogg pages and add
1290  *                        Elementary streams.
1291  ****************************************************************************/
1292 static int Ogg_BeginningOfStream( input_thread_t *p_input, demux_sys_t *p_ogg)
1293 {
1294     int i_stream;
1295
1296     /* Find the logical streams embedded in the physical stream and
1297      * initialize our p_ogg structure. */
1298     if( Ogg_FindLogicalStreams( p_input, p_ogg ) != VLC_SUCCESS )
1299     {
1300         msg_Warn( p_input, "couldn't find any ogg logical stream" );
1301         return VLC_EGENERIC;
1302     }
1303
1304     vlc_mutex_lock( &p_input->stream.stream_lock );
1305     p_input->stream.i_mux_rate = 0;
1306     vlc_mutex_unlock( &p_input->stream.stream_lock );
1307
1308     for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ )
1309     {
1310 #define p_stream p_ogg->pp_stream[i_stream]
1311         vlc_mutex_lock( &p_input->stream.stream_lock );
1312         p_stream->p_es = input_AddES( p_input,
1313                                       p_input->stream.p_selected_program,
1314                                       i_stream,
1315                                       p_stream->i_cat, NULL, 0 );
1316         p_input->stream.i_mux_rate += (p_stream->i_bitrate / ( 8 * 50 ));
1317         vlc_mutex_unlock( &p_input->stream.stream_lock );
1318         p_stream->p_es->i_stream_id = i_stream;
1319         p_stream->p_es->i_fourcc = p_stream->i_fourcc;
1320         p_stream->p_es->p_waveformatex      = (void*)p_stream->p_wf;
1321         p_stream->p_es->p_bitmapinfoheader  = (void*)p_stream->p_bih;
1322
1323         p_stream->i_pcr  = p_stream->i_previous_pcr = -1;
1324         p_stream->b_reinit = 0;
1325 #undef p_stream
1326     }
1327
1328     for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
1329     {
1330 #define p_stream  p_ogg->pp_stream[i_stream]
1331         switch( p_stream->p_es->i_cat )
1332         {
1333             case( VIDEO_ES ):
1334                 if( (p_ogg->p_stream_video == NULL) )
1335                 {
1336                     p_ogg->p_stream_video = p_stream;
1337                     /* TODO add test to see if a decoder has been found */
1338                     Ogg_ElemStreamStart( p_input, p_ogg, i_stream );
1339                 }
1340                 break;
1341
1342             case( AUDIO_ES ):
1343                 if( (p_ogg->p_stream_audio == NULL) )
1344                 {
1345                     int i_audio = config_GetInt( p_input, "audio-channel" );
1346                     if( i_audio == i_stream || i_audio <= 0 ||
1347                         i_audio >= p_ogg->i_streams ||
1348                         p_ogg->pp_stream[i_audio]->p_es->i_cat != AUDIO_ES )
1349                     {
1350                         p_ogg->p_stream_audio = p_stream;
1351                         Ogg_ElemStreamStart( p_input, p_ogg, i_stream );
1352                     }
1353                 }
1354                 break;
1355
1356             case( SPU_ES ):
1357                 if( (p_ogg->p_stream_spu == NULL) )
1358                 {
1359                     /* for spu, default is none */
1360                     int i_spu = config_GetInt( p_input, "spu-channel" );
1361                     if( i_spu < 0 || i_spu >= p_ogg->i_streams ||
1362                         p_ogg->pp_stream[i_spu]->p_es->i_cat != SPU_ES )
1363                     {
1364                         break;
1365                     }
1366                     else if( i_spu == i_stream )
1367                     {
1368                         p_ogg->p_stream_spu = p_stream;
1369                         Ogg_ElemStreamStart( p_input, p_ogg, i_stream );
1370                     }
1371                 }
1372                 break;
1373
1374             default:
1375                 break;
1376         }
1377 #undef p_stream
1378     }
1379
1380     /* we select the first audio and video ES */
1381     vlc_mutex_lock( &p_input->stream.stream_lock );
1382     if( !p_ogg->p_stream_video )
1383     {
1384         msg_Warn( p_input, "no video stream found" );
1385     }
1386     if( !p_ogg->p_stream_audio )
1387     {
1388         msg_Warn( p_input, "no audio stream found!" );
1389     }
1390     p_input->stream.p_selected_program->b_is_ok = 1;
1391     vlc_mutex_unlock( &p_input->stream.stream_lock );
1392
1393     return VLC_SUCCESS;
1394 }
1395
1396 /****************************************************************************
1397  * Ogg_EndOfStream: clean up the ES when an End of Stream is detected.
1398  ****************************************************************************/
1399 static void Ogg_EndOfStream( input_thread_t *p_input, demux_sys_t *p_ogg )
1400 {
1401     int i_stream, j;
1402
1403 #define p_stream p_ogg->pp_stream[i_stream]
1404         vlc_mutex_lock( &p_input->stream.stream_lock );
1405         if( p_input->stream.i_pgrm_number )
1406         while( p_input->stream.p_selected_program->i_es_number )
1407         {
1408             input_DelES( p_input,
1409                          p_input->stream.p_selected_program->pp_es[0] );
1410         }
1411         vlc_mutex_unlock( &p_input->stream.stream_lock );
1412 #undef p_stream
1413
1414     for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ )
1415     {
1416 #define p_stream p_ogg->pp_stream[i_stream]
1417         vlc_mutex_lock( &p_input->stream.stream_lock );
1418         p_input->stream.i_mux_rate -= (p_stream->i_bitrate / ( 8 * 50 ));
1419         vlc_mutex_unlock( &p_input->stream.stream_lock );
1420 #undef p_stream
1421
1422         ogg_stream_clear( &p_ogg->pp_stream[i_stream]->os );
1423         for( j = 0; j < p_ogg->pp_stream[i_stream]->i_packets_backup; j++ )
1424         {
1425             free( p_ogg->pp_stream[i_stream]->p_packets_backup[j].packet );
1426         }
1427         if( p_ogg->pp_stream[i_stream]->p_packets_backup)
1428             free( p_ogg->pp_stream[i_stream]->p_packets_backup );
1429
1430 #if 0 /* hmmm, it's already freed in input_DelES() */
1431             if( p_ogg->pp_stream[i]->p_bih )
1432                 free( p_ogg->pp_stream[i]->p_bih );
1433             if( p_ogg->pp_stream[i]->p_wf )
1434                 free( p_ogg->pp_stream[i]->p_wf );
1435 #endif
1436
1437         free( p_ogg->pp_stream[i_stream] );
1438     }
1439
1440     /* Reinit p_ogg */
1441     if( p_ogg->pp_stream ) free( p_ogg->pp_stream );
1442     p_ogg->pp_stream = NULL;
1443     p_ogg->i_streams = 0;
1444     p_ogg->p_stream_video = NULL;
1445     p_ogg->p_stream_audio = NULL;
1446     p_ogg->p_stream_spu = NULL;
1447 }
1448
1449 /*****************************************************************************
1450  * Deactivate: frees unused data
1451  *****************************************************************************/
1452 static void Deactivate( vlc_object_t *p_this )
1453 {
1454     input_thread_t *p_input = (input_thread_t *)p_this;
1455     demux_sys_t *p_ogg = (demux_sys_t *)p_input->p_demux_data  ;
1456
1457     if( p_ogg )
1458     {
1459         /* Cleanup the bitstream parser */
1460         ogg_sync_clear( &p_ogg->oy );
1461
1462         Ogg_EndOfStream( p_input, p_ogg );
1463
1464         free( p_ogg );
1465     }
1466 }
1467
1468 /*****************************************************************************
1469  * Demux: reads and demuxes data packets
1470  *****************************************************************************
1471  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
1472  *****************************************************************************/
1473 static int Demux( input_thread_t * p_input )
1474 {
1475     demux_sys_t *p_ogg = (demux_sys_t *)p_input->p_demux_data;
1476     ogg_page    oggpage;
1477     ogg_packet  oggpacket;
1478     int         i_stream;
1479
1480     if( p_ogg->i_eos == p_ogg->i_streams )
1481     {
1482         if( p_ogg->i_eos )
1483         {
1484             msg_Dbg( p_input, "end of a group of logical streams" );
1485             Ogg_EndOfStream( p_input, p_ogg );
1486         }
1487
1488         if( Ogg_BeginningOfStream( p_input, p_ogg ) != VLC_SUCCESS ) return 0;
1489         p_ogg->i_eos = 0;
1490
1491         msg_Dbg( p_input, "beginning of a group of logical streams" );
1492
1493         p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_REINIT;
1494         input_ClockManageRef( p_input, p_input->stream.p_selected_program, 0 );
1495     }
1496
1497 #define p_stream p_ogg->pp_stream[i_stream]
1498
1499     /* detect new selected/unselected streams */
1500     for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
1501     {
1502         if( p_stream->p_es )
1503         {
1504             if( p_stream->p_es->p_decoder_fifo &&
1505                 !p_stream->i_activated )
1506             {
1507                 Ogg_ElemStreamStart( p_input, p_ogg, i_stream );
1508             }
1509             else
1510             if( !p_stream->p_es->p_decoder_fifo &&
1511                 p_stream->i_activated )
1512             {
1513                 Ogg_ElemStreamStop( p_input, p_ogg, i_stream );
1514             }
1515         }
1516     }
1517
1518     /* search for new video and audio stream to select
1519      * if current have been unselected */
1520     if( ( !p_ogg->p_stream_video )
1521             || ( !p_ogg->p_stream_video->p_es->p_decoder_fifo ) )
1522     {
1523         p_ogg->p_stream_video = NULL;
1524         for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
1525         {
1526             if( ( p_stream->i_cat == VIDEO_ES )
1527                   &&( p_stream->p_es->p_decoder_fifo ) )
1528             {
1529                 p_ogg->p_stream_video = p_stream;
1530                 break;
1531             }
1532         }
1533     }
1534     if( ( !p_ogg->p_stream_audio )
1535             ||( !p_ogg->p_stream_audio->p_es->p_decoder_fifo ) )
1536     {
1537         p_ogg->p_stream_audio = NULL;
1538         for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
1539         {
1540             if( ( p_stream->i_cat == AUDIO_ES )
1541                   &&( p_stream->p_es->p_decoder_fifo ) )
1542             {
1543                 p_ogg->p_stream_audio = p_stream;
1544                 break;
1545             }
1546         }
1547     }
1548
1549     if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
1550     {
1551         msg_Warn( p_input, "synchro reinit" );
1552
1553         for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
1554         {
1555             /* we'll trash all the data until we find the next pcr */
1556             p_stream->b_reinit = 1;
1557             p_stream->i_pcr = -1;
1558             p_stream->i_interpolated_pcr = -1;
1559         }
1560         if( p_ogg->i_prev_sync_state != SYNCHRO_REINIT )
1561             ogg_sync_reset( &p_ogg->oy );
1562     }
1563
1564     p_ogg->i_prev_sync_state =
1565         p_input->stream.p_selected_program->i_synchro_state;
1566
1567     /*
1568      * Demux an ogg page from the stream
1569      */
1570     if( Ogg_ReadPage( p_input, p_ogg, &oggpage ) != VLC_SUCCESS )
1571     {
1572         return 0; /* EOF */
1573     }
1574
1575     /* Test for End of Stream */
1576     if( ogg_page_eos( &oggpage ) ) p_ogg->i_eos++;
1577
1578
1579     for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
1580     {
1581         if( ogg_stream_pagein( &p_stream->os, &oggpage ) != 0 )
1582             continue;
1583
1584         while( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
1585         {
1586             if( !p_stream->p_es )
1587             {
1588                 break;
1589             }
1590
1591             if( p_stream->b_reinit )
1592             {
1593                 /* If synchro is re-initialized we need to drop all the packets
1594                  * until we find a new dated one. */
1595                 Ogg_UpdatePCR( p_stream, &oggpacket );
1596
1597                 if( p_stream->i_pcr >= 0 )
1598                 {
1599                     p_stream->b_reinit = 0;
1600                 }
1601                 else
1602                 {
1603                     p_stream->i_interpolated_pcr = -1;
1604                     continue;
1605                 }
1606
1607                 /* An Ogg/vorbis packet contains an end date granulepos */
1608                 if( p_stream->i_fourcc == VLC_FOURCC( 'v','o','r','b' ) ||
1609                     p_stream->i_fourcc == VLC_FOURCC( 's','p','x',' ' ) ||
1610                     p_stream->i_fourcc == VLC_FOURCC( 'f','l','a','c' ) )
1611                 {
1612                     if( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
1613                     {
1614                         Ogg_DecodePacket( p_input, p_stream, &oggpacket );
1615                     }
1616                     else
1617                     {
1618                         input_ClockManageRef( p_input,
1619                             p_input->stream.p_selected_program, p_ogg->i_pcr );
1620                     }
1621                     continue;
1622                 }
1623             }
1624
1625             Ogg_DecodePacket( p_input, p_stream, &oggpacket );
1626         }
1627         break;
1628     }
1629
1630     i_stream = 0; p_ogg->i_pcr = -1;
1631     for( ; i_stream < p_ogg->i_streams; i_stream++ )
1632     {
1633         if( p_stream->i_cat == SPU_ES )
1634             continue;
1635         if( p_stream->i_interpolated_pcr < 0 )
1636             continue;
1637
1638         if( p_ogg->i_pcr < 0 || p_stream->i_interpolated_pcr < p_ogg->i_pcr )
1639             p_ogg->i_pcr = p_stream->i_interpolated_pcr;
1640     }
1641
1642     if( p_input->stream.p_selected_program->i_synchro_state != SYNCHRO_REINIT )
1643     {
1644         input_ClockManageRef( p_input, p_input->stream.p_selected_program,
1645                               p_ogg->i_pcr );
1646     }
1647
1648 #undef p_stream
1649
1650     return 1;
1651 }
1652
1653 /*****************************************************************************
1654  * Control:
1655  *****************************************************************************/
1656 static int Control( input_thread_t *p_input, int i_query, va_list args )
1657 {
1658     demux_sys_t *p_ogg  = (demux_sys_t *)p_input->p_demux_data;
1659     int64_t *pi64;
1660
1661     switch( i_query )
1662     {
1663         case DEMUX_GET_TIME:
1664             pi64 = (int64_t*)va_arg( args, int64_t * );
1665             *pi64 = p_ogg->i_pcr * 100 / 9;
1666             return VLC_SUCCESS;
1667
1668         default:
1669             return demux_vaControlDefault( p_input, i_query, args );
1670     }
1671 }