]> git.sesse.net Git - vlc/blob - modules/demux/ogg.c
* modules/demux/ogg.c: we now correctly handle multiple vorbis logical streams
[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.5 2002/11/03 13:22:44 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 #define OGG_BLOCK_SIZE 4096
38 #define PAGES_READ_ONCE 1
39
40 /*****************************************************************************
41  * Definitions of structures and functions used by this plugins 
42  *****************************************************************************/
43 typedef struct logical_stream_s
44 {
45     ogg_stream_state os;                        /* logical stream of packets */
46
47     int              i_serial_no;
48     int              i_cat;                            /* AUDIO_ES, VIDEO_ES */
49     int              i_activated;
50     vlc_fourcc_t     i_fourcc;
51     vlc_fourcc_t     i_codec;
52
53     es_descriptor_t  *p_es;   
54     int              b_selected;                           /* newly selected */
55
56     /* the header of some logical streams (eg vorbis) contain essential
57      * data for the decoder. We back them up here in case we need to re-feed
58      * them to the decoder. */
59     int              b_force_backup;
60     int              i_packets_backup;
61     ogg_packet       *p_packets_backup;
62
63     /* program clock reference (in units of 90kHz) derived from the previous
64      * granulepos */
65     mtime_t i_pcr;
66
67     /* info from logical streams */
68     int i_rate;
69     int i_bitrate;
70     int b_reinit;
71
72 } logical_stream_t;
73
74 struct demux_sys_t
75 {
76     ogg_sync_state oy;        /* sync and verify incoming physical bitstream */
77
78     int i_streams;                           /* number of logical bitstreams */
79     logical_stream_t **pp_stream;  /* pointer to an array of logical streams */
80
81     /* current audio and video es */
82     logical_stream_t *p_stream_video;
83     logical_stream_t *p_stream_audio;
84
85     /* stream we use as a time reference for demux reading speed */
86     logical_stream_t *p_stream_timeref;
87
88     /* program clock reference (in units of 90kHz) derived from the pcr of
89      * one of the sub-streams (p_stream_timeref) */
90     mtime_t i_pcr;
91
92     mtime_t i_length;
93     int     b_seekable;
94 };
95
96 /*****************************************************************************
97  * Local prototypes
98  *****************************************************************************/
99 static int  Activate  ( vlc_object_t * );
100 static void Deactivate( vlc_object_t * );
101 static int  Demux     ( input_thread_t * );
102
103 /* Stream managment */
104 static int  Ogg_StreamStart  ( input_thread_t *, demux_sys_t *, int );
105 static int  Ogg_StreamSeek   ( input_thread_t *, demux_sys_t *, int, mtime_t );
106 static void Ogg_StreamStop   ( input_thread_t *, demux_sys_t *, int );
107
108 /* Bitstream manipulation */
109 static int  Ogg_Check        ( input_thread_t *p_input );
110 static int  Ogg_ReadPage     ( input_thread_t *, demux_sys_t *, ogg_page * );
111 static void Ogg_DecodePacket ( input_thread_t *p_input,
112                                logical_stream_t *p_stream,
113                                ogg_packet *p_oggpacket );
114 static int  Ogg_FindLogicalStreams( input_thread_t *p_input,
115                                     demux_sys_t *p_ogg );
116
117 /*****************************************************************************
118  * Module descriptor
119  *****************************************************************************/
120 vlc_module_begin();
121     set_description( _("ogg stream demux" ) );
122     set_capability( "demux", 50 );
123     set_callbacks( Activate, Deactivate );
124     add_shortcut( "ogg" );
125 vlc_module_end();
126
127 /*****************************************************************************
128  * Stream managment
129  *****************************************************************************/
130 static int Ogg_StreamStart( input_thread_t *p_input,
131                             demux_sys_t *p_ogg, int i_stream )
132 {
133 #define p_stream p_ogg->pp_stream[i_stream]
134     if( !p_stream->p_es )
135     {
136         msg_Warn( p_input, "stream[%d] unselectable", i_stream );
137         return( 0 );
138     }
139     if( p_stream->i_activated )
140     {
141         msg_Warn( p_input, "stream[%d] already selected", i_stream );
142         return( 1 );
143     }
144
145     if( !p_stream->p_es->p_decoder_fifo )
146     {
147         vlc_mutex_lock( &p_input->stream.stream_lock );
148         input_SelectES( p_input, p_stream->p_es );
149         vlc_mutex_unlock( &p_input->stream.stream_lock );
150     }
151     p_stream->i_activated = p_stream->p_es->p_decoder_fifo ? 1 : 0;
152
153     /* Feed the backup header to the decoder */
154     if( !p_stream->b_force_backup )
155     {
156         int i;
157         for( i = 0; i < p_stream->i_packets_backup; i++ )
158         {
159             Ogg_DecodePacket( p_input, p_stream,
160                               &p_stream->p_packets_backup[i] );
161         }
162     }
163
164     //Ogg_StreamSeek( p_input, p_ogg, i_stream, p_ogg->i_time );
165
166     return( p_stream->i_activated );
167 #undef  p_stream
168 }
169
170 static void Ogg_StreamStop( input_thread_t *p_input,
171                             demux_sys_t *p_ogg, int i_stream )
172 {
173 #define p_stream    p_ogg->pp_stream[i_stream]
174
175     if( !p_stream->i_activated )
176     {
177         msg_Warn( p_input, "stream[%d] already unselected", i_stream );
178         return;
179     }
180
181     if( p_stream->p_es->p_decoder_fifo )
182     {
183         vlc_mutex_lock( &p_input->stream.stream_lock );
184         input_UnselectES( p_input, p_stream->p_es );
185         vlc_mutex_unlock( &p_input->stream.stream_lock );
186     }
187
188     p_stream->i_activated = 0;
189
190 #undef  p_stream
191 }
192
193 static int Ogg_StreamSeek( input_thread_t *p_input, demux_sys_t  *p_ogg,
194                            int i_stream, mtime_t i_date )
195 {
196 #define p_stream    p_ogg->pp_stream[i_stream]
197
198     /* FIXME: todo */
199
200     return 1;
201 #undef p_stream
202 }
203
204 /****************************************************************************
205  * Ogg_Check: Check we are dealing with an ogg stream.
206  ****************************************************************************/
207 static int Ogg_Check( input_thread_t *p_input )
208 {
209     u8 *p_peek;
210     int i_size = input_Peek( p_input, &p_peek, 4 );
211
212     /* Check for the Ogg capture pattern */
213     if( !(i_size>3) || !(p_peek[0] == 'O') || !(p_peek[1] == 'g') ||
214         !(p_peek[2] == 'g') || !(p_peek[3] == 'S') )
215         return VLC_EGENERIC;
216
217     /* FIXME: Capture pattern might not be enough so we can also check for the
218      * the first complete page */
219
220     return VLC_SUCCESS;
221 }
222
223 /****************************************************************************
224  * Ogg_ReadPage: Read a full Ogg page from the physical bitstream.
225  ****************************************************************************
226  * Returns VLC_SUCCESS if a page has been read. An error might happen if we
227  * are at the end of stream.
228  ****************************************************************************/
229 static int Ogg_ReadPage( input_thread_t *p_input, demux_sys_t *p_ogg,
230                          ogg_page *p_oggpage )
231 {
232     int i_read = 0;
233     data_packet_t *p_data;
234     byte_t *p_buffer;
235
236     while( ogg_sync_pageout( &p_ogg->oy, p_oggpage ) != 1 )
237     {
238         i_read = input_SplitBuffer( p_input, &p_data, OGG_BLOCK_SIZE );
239         if( i_read <= 0 )
240             return VLC_EGENERIC;
241
242         p_buffer = ogg_sync_buffer( &p_ogg->oy, i_read );
243         p_input->p_vlc->pf_memcpy( p_buffer, p_data->p_payload_start, i_read );
244         ogg_sync_wrote( &p_ogg->oy, i_read );
245         input_DeletePacket( p_input->p_method_data, p_data );
246     }
247
248     return VLC_SUCCESS;
249 }
250
251 /****************************************************************************
252  * Ogg_DecodePacket: Decode an Ogg packet.
253  ****************************************************************************/
254 static void Ogg_DecodePacket( input_thread_t *p_input,
255                               logical_stream_t *p_stream,
256                               ogg_packet *p_oggpacket )
257 {
258     pes_packet_t  *p_pes;
259     data_packet_t *p_data;
260     demux_sys_t *p_ogg = p_input->p_demux_data;
261
262     if( p_stream->b_force_backup )
263     {
264         /* Backup the ogg packet (likely an header) */
265         ogg_packet *p_packet_backup;
266         p_stream->i_packets_backup++;
267         p_stream->p_packets_backup =
268             realloc( p_stream->p_packets_backup, p_stream->i_packets_backup *
269                      sizeof(ogg_packet) );
270
271         p_packet_backup =
272             &p_stream->p_packets_backup[p_stream->i_packets_backup - 1];
273
274         p_packet_backup->bytes = p_oggpacket->bytes;
275         p_packet_backup->granulepos = p_oggpacket->granulepos;
276         p_packet_backup->packet = malloc( p_oggpacket->bytes );
277         if( !p_packet_backup->packet ) return;
278         memcpy( p_packet_backup->packet, p_oggpacket->packet,
279                 p_oggpacket->bytes );
280
281         switch( p_stream->i_fourcc )
282         {
283         case VLC_FOURCC( 'v','o','r','b' ):
284           if( p_stream->i_packets_backup == 3 ) p_stream->b_force_backup = 0;
285           break;
286
287         default:
288           p_stream->b_force_backup = 0;
289           break;
290         }
291     }
292
293     if( !p_stream->p_es->p_decoder_fifo )
294     {
295         /* This stream isn't currently selected so we don't need to decode it,
296          * but we do need to store its pcr as it might be selected later on. */
297
298         /* Convert the next granule into a pcr */
299         p_stream->i_pcr = ( p_oggpacket->granulepos < 0 ) ?
300             p_stream->i_pcr + ( p_oggpacket->bytes * 90000
301                 / p_stream->i_bitrate / 8 ):
302             p_oggpacket->granulepos * 90000 / p_stream->i_rate;
303
304         return;
305     }
306
307     if( !( p_pes = input_NewPES( p_input->p_method_data ) ) )
308     {
309         return;
310     }
311     if( !( p_data = input_NewPacket( p_input->p_method_data,
312                                      p_oggpacket->bytes ) ) )
313     {
314         input_DeletePES( p_input->p_method_data, p_pes );
315         return;
316     }
317
318     p_pes->p_first = p_pes->p_last = p_data;
319     p_pes->i_nb_data = 1;
320     p_pes->i_pes_size = p_oggpacket->bytes;
321     p_pes->i_dts = p_oggpacket->granulepos;
322
323     /* Convert the pcr into a pts */
324     p_pes->i_pts = ( p_stream->i_pcr < 0 ) ? 0 :
325         input_ClockGetTS( p_input, p_input->stream.p_selected_program,
326                           p_stream->i_pcr );
327
328     /* Convert the next granule into a pcr */
329     p_stream->i_pcr = ( p_oggpacket->granulepos < 0 ) ? -1 :
330                         p_oggpacket->granulepos * 90000 / p_stream->i_rate;
331
332     /* Update the main pcr */
333     if( p_stream == p_ogg->p_stream_timeref )
334     {
335         if( p_ogg->p_stream_timeref->i_pcr >= 0 )
336         {
337             p_ogg->i_pcr = p_ogg->p_stream_timeref->i_pcr;
338         }
339         else
340         {
341             p_ogg->i_pcr += ( p_oggpacket->bytes * 90000
342                               / p_stream->i_bitrate / 8 );
343         }
344     }
345
346     memcpy( p_data->p_payload_start, p_oggpacket->packet, p_oggpacket->bytes );
347
348     input_DecodePES( p_stream->p_es->p_decoder_fifo, p_pes );
349 }
350
351 /****************************************************************************
352  * Ogg_FindLogicalStreams: Find the logical streams embedded in the physical
353  *                         stream and fill p_ogg.
354  *****************************************************************************
355  * The initial page of a logical stream is marked as a 'bos' page.
356  * Furthermore, the Ogg specification mandates that grouped bitstreams begin
357  * together and all of the initial pages must appear before any data pages.
358  *
359  * On success this function returns VLC_SUCCESS.
360  ****************************************************************************/
361 static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
362 {
363     ogg_packet oggpacket;
364     ogg_page oggpage;
365     int i_stream;
366
367     while( Ogg_ReadPage( p_input, p_ogg, &oggpage ) == VLC_SUCCESS )
368     {
369         if( ogg_page_bos( &oggpage ) )
370         {
371
372             /* All is wonderful in our fine fine little world.
373              * We found the beginning of our first logical stream. */
374             while( ogg_page_bos( &oggpage ) )
375             {
376                 p_ogg->i_streams++;
377                 p_ogg->pp_stream =
378                     realloc( p_ogg->pp_stream, p_ogg->i_streams *
379                              sizeof(logical_stream_t *) );
380
381 #define p_stream p_ogg->pp_stream[p_ogg->i_streams - 1]
382
383                 p_stream = malloc( sizeof(logical_stream_t) );
384                 memset( p_stream, 0, sizeof(logical_stream_t) );
385
386                 /* Setup the logical stream */
387                 p_stream->i_serial_no = ogg_page_serialno( &oggpage );
388                 ogg_stream_init( &p_stream->os, p_stream->i_serial_no );
389
390                 /* The first stream we find is our timeref (might be changed
391                  * later on) */
392                 p_ogg->p_stream_timeref = p_stream;
393
394                 /* Extract the initial header from the first page and verify
395                  * the codec type of tis Ogg bitstream */
396                 if( ogg_stream_pagein( &p_stream->os, &oggpage ) < 0 )
397                 {
398                     /* error. stream version mismatch perhaps */
399                     msg_Err( p_input, "Error reading first page of "
400                              "Ogg bitstream data" );
401                     return VLC_EGENERIC;
402                 }
403
404                 /* FIXME: check return value */
405                 ogg_stream_packetpeek( &p_stream->os, &oggpacket );
406
407                 /* Check for Vorbis header */
408                 if( oggpacket.bytes >= 7 &&
409                     ! strncmp( &oggpacket.packet[1], "vorbis", 6 ) )
410                 {
411                     oggpack_buffer opb;
412
413                     msg_Dbg( p_input, "found vorbis header" );
414                     p_stream->i_cat = AUDIO_ES;
415                     p_stream->i_fourcc = VLC_FOURCC( 'v','o','r','b' );
416
417                     /* Signal that we want to keep a backup of the vorbis
418                      * stream headers. They will be used when switching between
419                      * audio streams. */
420                     p_stream->b_force_backup = 1;
421
422                     /* Cheat and get additionnal info ;) */
423                     oggpack_readinit( &opb, oggpacket.packet, oggpacket.bytes);
424                     oggpack_adv( &opb, 96 );
425                     p_stream->i_rate = oggpack_read( &opb, 32 );
426                     oggpack_adv( &opb, 32 );
427                     p_stream->i_bitrate = oggpack_read( &opb, 32 );
428                 }
429                 else
430                 {
431                     msg_Dbg( p_input, "found unknown codec" );
432                     free( p_stream );
433                     p_ogg->i_streams--;
434                 }
435
436 #undef p_stream
437
438                 if( Ogg_ReadPage( p_input, p_ogg, &oggpage ) != VLC_SUCCESS )
439                     return VLC_EGENERIC;
440             }
441
442             /* This is the first data page, which means we are now finished
443              * with the initial pages. We just need to store it in the relevant
444              * bitstream. */
445             for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
446             {
447                 if( ogg_stream_pagein( &p_ogg->pp_stream[i_stream]->os,
448                                        &oggpage ) == 0 )
449                 {
450                     break;
451                 }
452             }
453             return VLC_SUCCESS;
454         }
455     }
456     return VLC_EGENERIC;
457 }
458
459 /*****************************************************************************
460  * Activate: initializes ogg demux structures
461  *****************************************************************************/
462 static int Activate( vlc_object_t * p_this )
463 {
464     int i_stream, b_forced;
465     demux_sys_t    *p_ogg;
466     input_thread_t *p_input = (input_thread_t *)p_this;
467
468     p_input->p_demux_data = NULL;
469     b_forced = ( ( *p_input->psz_demux )&&
470                  ( !strncmp( p_input->psz_demux, "ogg", 10 ) ) ) ? 1 : 0;
471
472     /* Check if we are dealing with an ogg stream */
473     if( !b_forced && ( Ogg_Check( p_input ) != VLC_SUCCESS ) )
474         return -1;
475
476     /* Allocate p_ogg */
477     if( !( p_ogg = malloc( sizeof( demux_sys_t ) ) ) )
478     {
479         msg_Err( p_input, "out of memory" );
480         goto error;
481     }
482     memset( p_ogg, 0, sizeof( demux_sys_t ) );
483     p_input->p_demux_data = p_ogg;
484
485     p_ogg->i_pcr  = 0;
486     p_ogg->p_stream_timeref = NULL;
487     p_ogg->b_seekable = ( ( p_input->stream.b_seekable )
488                         &&( p_input->stream.i_method == INPUT_METHOD_FILE ) );
489
490     /* Initialize the Ogg physical bitstream parser */
491     ogg_sync_init( &p_ogg->oy );
492
493     /* Find the logical streams embedded in the physical stream and
494      * initialize our p_ogg structure. */
495     if( Ogg_FindLogicalStreams( p_input, p_ogg ) != VLC_SUCCESS )
496     {
497         msg_Err( p_input, "couldn't find an ogg logical stream" );
498         goto error;
499     }
500
501     /* Set the demux function */
502     p_input->pf_demux = Demux;
503
504     /* Initialize access plug-in structures. */
505     if( p_input->i_mtu == 0 )
506     {
507         /* Improve speed. */
508         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
509     }
510
511     /* Create one program */
512     vlc_mutex_lock( &p_input->stream.stream_lock );
513     if( input_InitStream( p_input, 0 ) == -1)
514     {
515         vlc_mutex_unlock( &p_input->stream.stream_lock );
516         msg_Err( p_input, "cannot init stream" );
517         goto error;
518     }
519     if( input_AddProgram( p_input, 0, 0) == NULL )
520     {
521         vlc_mutex_unlock( &p_input->stream.stream_lock );
522         msg_Err( p_input, "cannot add program" );
523         goto error;
524     }
525     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
526     p_input->stream.i_mux_rate = 0;
527     vlc_mutex_unlock( &p_input->stream.stream_lock );
528
529     for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ )
530     {
531 #define p_stream p_ogg->pp_stream[i_stream]
532         vlc_mutex_lock( &p_input->stream.stream_lock );
533         p_stream->p_es = input_AddES( p_input,
534                                       p_input->stream.p_selected_program,
535                                       p_ogg->i_streams + 1, 0 );
536         p_input->stream.i_mux_rate += (p_stream->i_bitrate / ( 8 * 50 ));
537         vlc_mutex_unlock( &p_input->stream.stream_lock );
538         p_stream->p_es->i_stream_id = i_stream;
539         p_stream->p_es->i_fourcc = p_stream->i_fourcc;
540         p_stream->p_es->i_cat = p_stream->i_cat;
541 #undef p_stream
542     }
543
544     for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
545     {
546 #define p_stream  p_ogg->pp_stream[i_stream]
547         switch( p_stream->p_es->i_cat )
548         {
549             case( VIDEO_ES ):
550
551                 if( (p_ogg->p_stream_video == NULL) )
552                 {
553                     p_ogg->p_stream_video = p_stream;
554                     /* TODO add test to see if a decoder has been found */
555                     Ogg_StreamStart( p_input, p_ogg, i_stream );
556                 }
557                 break;
558
559             case( AUDIO_ES ):
560                 if( (p_ogg->p_stream_audio == NULL) )
561                 {
562                     p_ogg->p_stream_audio = p_stream;
563                     p_ogg->p_stream_timeref = p_stream;
564                     Ogg_StreamStart( p_input, p_ogg, i_stream );
565                 }
566                 break;
567
568             default:
569                 break;
570         }
571 #undef p_stream
572     }
573
574     /* we select the first audio and video ES */
575     vlc_mutex_lock( &p_input->stream.stream_lock );
576     if( !p_ogg->p_stream_video )
577     {
578         msg_Warn( p_input, "no video stream found" );
579     }
580     if( !p_ogg->p_stream_audio )
581     {
582         msg_Warn( p_input, "no audio stream found!" );
583     }
584     p_input->stream.p_selected_program->b_is_ok = 1;
585     vlc_mutex_unlock( &p_input->stream.stream_lock );
586
587     /* Call the pace control */
588     input_ClockManageRef( p_input,
589                           p_input->stream.p_selected_program,
590                           p_ogg->i_pcr );
591
592     return 0;
593
594  error:
595     Deactivate( (vlc_object_t *)p_input );
596     return -1;
597
598 }
599
600 /*****************************************************************************
601  * Deactivate: frees unused data
602  *****************************************************************************/
603 static void Deactivate( vlc_object_t *p_this )
604 {
605     input_thread_t *p_input = (input_thread_t *)p_this;
606     demux_sys_t *p_ogg = (demux_sys_t *)p_input->p_demux_data  ; 
607     int i, j;
608
609     if( p_ogg )
610     {
611         /* Cleanup the bitstream parser */
612         ogg_sync_clear( &p_ogg->oy );
613
614         for( i = 0; i < p_ogg->i_streams; i++ )
615         {
616             ogg_stream_clear( &p_ogg->pp_stream[i]->os );
617             for( j = 0; j < p_ogg->pp_stream[i]->i_packets_backup; j++ )
618             {
619                 free( p_ogg->pp_stream[i]->p_packets_backup[j].packet );
620             }
621             free( p_ogg->pp_stream[i]->p_packets_backup );
622             free( p_ogg->pp_stream[i] );
623         }
624         if( p_ogg->pp_stream ) free( p_ogg->pp_stream );
625
626         free( p_ogg );
627     }
628 }
629
630 /*****************************************************************************
631  * Demux: reads and demuxes data packets
632  *****************************************************************************
633  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
634  *****************************************************************************/
635 static int Demux( input_thread_t * p_input )
636 {
637     int i, i_stream, b_eos = 0;
638     ogg_page    oggpage;
639     ogg_packet  oggpacket;
640     demux_sys_t *p_ogg  = (demux_sys_t *)p_input->p_demux_data;
641
642 #define p_stream p_ogg->pp_stream[i_stream]
643     /* detect new selected/unselected streams */
644     for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
645     {
646         if( p_stream->p_es )
647         {
648             if( p_stream->p_es->p_decoder_fifo &&
649                 !p_stream->i_activated )
650             {
651                 Ogg_StreamStart( p_input, p_ogg, i_stream );
652             }
653             else
654             if( !p_stream->p_es->p_decoder_fifo &&
655                 p_stream->i_activated )
656             {
657                 Ogg_StreamStop( p_input, p_ogg, i_stream );
658             }
659         }
660     }
661
662     /* search for new video and audio stream to select
663      * if current have been unselected */
664     if( ( !p_ogg->p_stream_video )
665             || ( !p_ogg->p_stream_video->p_es->p_decoder_fifo ) )
666     {
667         p_ogg->p_stream_video = NULL;
668         for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
669         {
670             if( ( p_stream->i_cat == VIDEO_ES )
671                   &&( p_stream->p_es->p_decoder_fifo ) )
672             {
673                 p_ogg->p_stream_video = p_stream;
674                 break;
675             }
676         }
677     }
678     if( ( !p_ogg->p_stream_audio )
679             ||( !p_ogg->p_stream_audio->p_es->p_decoder_fifo ) )
680     {
681         p_ogg->p_stream_audio = NULL;
682         for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
683         {
684             if( ( p_stream->i_cat == AUDIO_ES )
685                   &&( p_stream->p_es->p_decoder_fifo ) )
686             {
687                 p_ogg->p_stream_audio = p_stream;
688                 p_ogg->p_stream_timeref = p_stream;
689                 break;
690             }
691         }
692     }
693
694     if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
695     {
696         msg_Warn( p_input, "synchro reinit" );
697
698         /* An ogg packet does only contain the starting date of the next
699          * packet, not its own starting date.
700          * As a quick work around, we just skip an oggpage */
701
702         for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
703         {
704             /* we'll trash all the data until we find the next pcr */
705             p_stream->b_reinit = 1;
706             p_ogg->i_pcr = 0;
707         }
708     }
709
710
711     /* Demux ogg pages from the stream */
712     for( i = 0; (i < PAGES_READ_ONCE) || p_ogg->p_stream_timeref->b_reinit;
713          i++ )
714     {
715         if( Ogg_ReadPage( p_input, p_ogg, &oggpage ) != VLC_SUCCESS )
716         {
717             b_eos = 1;
718             break;
719         }
720
721         for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
722         {
723             if( ogg_stream_pagein( &p_stream->os, &oggpage ) != 0 )
724                 continue;
725
726             while( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
727             {
728                 if( !p_stream->p_es )
729                 {
730                     break;
731                 }
732
733                 if( p_stream->b_reinit )
734                 {
735                     if( oggpacket.granulepos >= 0 )
736                     {
737                         p_stream->b_reinit = 0;
738                         p_stream->i_pcr = oggpacket.granulepos
739                             * 90000 / p_stream->i_rate;
740
741                         if( !p_ogg->i_pcr ||
742                             (p_stream == p_ogg->p_stream_timeref) )
743                         {
744                             /* Call the pace control to reinitialize
745                              * the system clock */
746                             p_ogg->i_pcr = p_stream->i_pcr;
747                             input_ClockManageRef( p_input,
748                                p_input->stream.p_selected_program,
749                                p_ogg->i_pcr );
750                         }
751                     }
752                     continue;
753                 }
754
755                 Ogg_DecodePacket( p_input, p_stream, &oggpacket );
756
757             }
758         }
759 #undef p_stream
760     }
761
762     /* Call the pace control */
763     if( !b_eos ) input_ClockManageRef( p_input,
764                                        p_input->stream.p_selected_program,
765                                        p_ogg->i_pcr );
766
767     /* Did we reach the end of stream ? */
768     return( b_eos ? 0 : 1 );
769 }