1 /*****************************************************************************
2 * ogg.c : ogg stream input module for vlc
3 *****************************************************************************
4 * Copyright (C) 2001 VideoLAN
5 * $Id: ogg.c,v 1.3 2002/11/02 18:13:22 gbazin Exp $
7 * Authors: Gildas Bazin <gbazin@netcourrier.com>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
31 #include <vlc/input.h>
33 #include <sys/types.h>
37 #define OGG_BLOCK_SIZE 4096
38 #define PAGES_READ_ONCE 1
40 /*****************************************************************************
41 * Definitions of structures and functions used by this plugins
42 *****************************************************************************/
43 typedef struct logical_stream_s
45 ogg_stream_state os; /* logical stream of packets */
49 int i_cat; /* AUDIO_ES, VIDEO_ES */
51 vlc_fourcc_t i_fourcc;
54 es_descriptor_t *p_es;
55 int b_selected; /* newly selected */
57 /* program clock reference (in units of 90kHz) derived from the previous
61 /* info from logical streams */
70 ogg_sync_state oy; /* sync and verify incoming physical bitstream */
72 int i_streams; /* number of logical bitstreams */
73 logical_stream_t **pp_stream; /* pointer to an array of logical streams */
75 /* current audio and video es */
76 logical_stream_t *p_stream_video;
77 logical_stream_t *p_stream_audio;
79 /* stream we use as a time reference for demux reading speed */
80 logical_stream_t *p_stream_timeref;
82 /* program clock reference (in units of 90kHz) derived from the pcr of
83 * one of the sub-streams (p_stream_timeref) */
90 /*****************************************************************************
92 *****************************************************************************/
93 static int Activate ( vlc_object_t * );
94 static void Deactivate( vlc_object_t * );
95 static int Demux ( input_thread_t * );
97 /* Stream managment */
98 static int Ogg_StreamStart ( input_thread_t *, demux_sys_t *, int );
99 static int Ogg_StreamSeek ( input_thread_t *, demux_sys_t *, int, mtime_t );
100 static void Ogg_StreamStop ( input_thread_t *, demux_sys_t *, int );
102 /* Bitstream manipulation */
103 static int Ogg_Check ( input_thread_t *p_input );
104 static int Ogg_ReadPage ( input_thread_t *, demux_sys_t *, ogg_page * );
105 static void Ogg_DecodePacket ( input_thread_t *p_input,
106 logical_stream_t *p_stream,
107 ogg_packet *p_oggpacket );
108 static int Ogg_FindLogicalStreams( input_thread_t *p_input,
109 demux_sys_t *p_ogg );
111 /*****************************************************************************
113 *****************************************************************************/
115 set_description( _("ogg stream demux" ) );
116 set_capability( "demux", 50 );
117 set_callbacks( Activate, Deactivate );
118 add_shortcut( "ogg" );
121 /*****************************************************************************
123 *****************************************************************************/
124 static int Ogg_StreamStart( input_thread_t *p_input,
125 demux_sys_t *p_ogg, int i_stream )
127 #define p_stream p_ogg->pp_stream[i_stream]
128 if( !p_stream->p_es )
130 msg_Warn( p_input, "stream[%d] unselectable", i_stream );
133 if( p_stream->i_activated )
135 msg_Warn( p_input, "stream[%d] already selected", i_stream );
139 if( !p_stream->p_es->p_decoder_fifo )
141 vlc_mutex_lock( &p_input->stream.stream_lock );
142 input_SelectES( p_input, p_stream->p_es );
143 vlc_mutex_unlock( &p_input->stream.stream_lock );
145 p_stream->i_activated = p_stream->p_es->p_decoder_fifo ? 1 : 0;
147 //Ogg_StreamSeek( p_input, p_ogg, i_stream, p_ogg->i_time );
149 return( p_stream->i_activated );
153 static void Ogg_StreamStop( input_thread_t *p_input,
154 demux_sys_t *p_ogg, int i_stream )
156 #define p_stream p_ogg->pp_stream[i_stream]
158 if( !p_stream->i_activated )
160 msg_Warn( p_input, "stream[%d] already unselected", i_stream );
164 if( p_stream->p_es->p_decoder_fifo )
166 vlc_mutex_lock( &p_input->stream.stream_lock );
167 input_UnselectES( p_input, p_stream->p_es );
168 vlc_mutex_unlock( &p_input->stream.stream_lock );
171 p_stream->i_activated = 0;
176 static int Ogg_StreamSeek( input_thread_t *p_input, demux_sys_t *p_ogg,
177 int i_stream, mtime_t i_date )
179 #define p_stream p_ogg->pp_stream[i_stream]
187 /****************************************************************************
188 * Ogg_Check: Check we are dealing with an ogg stream.
189 ****************************************************************************/
190 static int Ogg_Check( input_thread_t *p_input )
193 int i_size = input_Peek( p_input, &p_peek, 4 );
195 /* Check for the Ogg capture pattern */
196 if( !(i_size>3) || !(p_peek[0] == 'O') || !(p_peek[1] == 'g') ||
197 !(p_peek[2] == 'g') || !(p_peek[3] == 'S') )
200 /* FIXME: Capture pattern might not be enough so we can also check for the
201 * the first complete page */
206 /****************************************************************************
207 * Ogg_ReadPage: Read a full Ogg page from the physical bitstream.
208 ****************************************************************************
209 * Returns VLC_SUCCESS if a page has been read. An error might happen if we
210 * are at the end of stream.
211 ****************************************************************************/
212 static int Ogg_ReadPage( input_thread_t *p_input, demux_sys_t *p_ogg,
213 ogg_page *p_oggpage )
216 data_packet_t *p_data;
219 while( ogg_sync_pageout( &p_ogg->oy, p_oggpage ) != 1 )
221 i_read = input_SplitBuffer( p_input, &p_data, OGG_BLOCK_SIZE );
225 p_buffer = ogg_sync_buffer( &p_ogg->oy, i_read );
226 p_input->p_vlc->pf_memcpy( p_buffer, p_data->p_payload_start, i_read );
227 ogg_sync_wrote( &p_ogg->oy, i_read );
228 input_DeletePacket( p_input->p_method_data, p_data );
234 /****************************************************************************
235 * Ogg_DecodePacket: Decode an Ogg packet.
236 ****************************************************************************/
237 static void Ogg_DecodePacket( input_thread_t *p_input,
238 logical_stream_t *p_stream,
239 ogg_packet *p_oggpacket )
242 data_packet_t *p_data;
243 demux_sys_t *p_ogg = p_input->p_demux_data;
245 if( !( p_pes = input_NewPES( p_input->p_method_data ) ) )
249 if( !( p_data = input_NewPacket( p_input->p_method_data,
250 p_oggpacket->bytes ) ) )
252 input_DeletePES( p_input->p_method_data, p_pes );
256 p_pes->p_first = p_pes->p_last = p_data;
257 p_pes->i_nb_data = 1;
258 p_pes->i_pes_size = p_oggpacket->bytes;
259 p_pes->i_dts = p_oggpacket->granulepos;
261 /* Convert the pcr into a pts */
262 p_pes->i_pts = ( p_stream->i_pcr < 0 ) ? 0 :
263 input_ClockGetTS( p_input, p_input->stream.p_selected_program,
266 /* Convert the next granule into a pcr */
267 p_stream->i_pcr = ( p_oggpacket->granulepos < 0 ) ? -1 :
268 p_oggpacket->granulepos * 90000 / p_stream->i_rate;
270 /* Update the main pcr */
271 if( p_stream == p_ogg->p_stream_timeref )
273 if( p_ogg->p_stream_timeref->i_pcr >= 0 )
275 p_ogg->i_pcr = p_ogg->p_stream_timeref->i_pcr;
279 p_ogg->i_pcr += ( p_oggpacket->bytes * 90000
280 / p_stream->i_bitrate / 8 );
284 memcpy( p_data->p_payload_start, p_oggpacket->packet, p_oggpacket->bytes );
286 input_DecodePES( p_stream->p_es->p_decoder_fifo, p_pes );
289 /****************************************************************************
290 * Ogg_FindLogicalStreams: Find the logical streams embedded in the physical
291 * stream and fill p_ogg.
292 *****************************************************************************
293 * The initial page of a logical stream is marked as a 'bos' page.
294 * Furthermore, the Ogg specification mandates that grouped bitstreams begin
295 * together and all of the initial pages must appear before any data pages.
297 * On success this function returns VLC_SUCCESS.
298 ****************************************************************************/
299 static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
301 ogg_packet oggpacket;
305 while( Ogg_ReadPage( p_input, p_ogg, &oggpage ) == VLC_SUCCESS )
307 if( ogg_page_bos( &oggpage ) )
310 /* All is wonderful in our fine fine little world.
311 * We found the beginning of our first logical stream. */
312 while( ogg_page_bos( &oggpage ) )
316 realloc( p_ogg->pp_stream, p_ogg->i_streams *
317 sizeof(logical_stream_t *) );
319 #define p_stream p_ogg->pp_stream[p_ogg->i_streams - 1]
321 p_stream = malloc( sizeof(logical_stream_t) );
322 memset( p_stream, 0, sizeof(logical_stream_t) );
324 /* Setup the logical stream */
325 p_stream->i_pages_read++;
326 p_stream->i_serial_no = ogg_page_serialno( &oggpage );
327 ogg_stream_init( &p_stream->os, p_stream->i_serial_no );
329 /* The first stream we find is our timeref (might be changed
331 p_ogg->p_stream_timeref = p_stream;
333 /* Extract the initial header from the first page and verify
334 * the codec type of tis Ogg bitstream */
335 if( ogg_stream_pagein( &p_stream->os, &oggpage ) < 0 )
337 /* error. stream version mismatch perhaps */
338 msg_Err( p_input, "Error reading first page of "
339 "Ogg bitstream data" );
343 /* FIXME: check return value */
344 ogg_stream_packetpeek( &p_stream->os, &oggpacket );
346 /* Check for Vorbis header */
347 if( oggpacket.bytes >= 7 &&
348 ! strncmp( &oggpacket.packet[1], "vorbis", 6 ) )
352 msg_Dbg( p_input, "found vorbis header" );
353 p_stream->i_cat = AUDIO_ES;
354 p_stream->i_fourcc = VLC_FOURCC( 'v','o','r','b' );
356 /* Cheat and get additionnal info ;) */
357 oggpack_readinit( &opb, oggpacket.packet, oggpacket.bytes);
358 oggpack_adv( &opb, 96 );
359 p_stream->i_rate = oggpack_read( &opb, 32 );
360 oggpack_adv( &opb, 32 );
361 p_stream->i_bitrate = oggpack_read( &opb, 32 );
365 msg_Dbg( p_input, "found unknown codec" );
366 ogg_stream_destroy( &p_stream->os );
373 if( Ogg_ReadPage( p_input, p_ogg, &oggpage ) != VLC_SUCCESS )
377 /* This is the first data page, which means we are now finished
378 * with the initial pages. We just need to store it in the relevant
380 for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
382 if( ogg_stream_pagein( &p_ogg->pp_stream[i_stream]->os,
385 p_ogg->pp_stream[i_stream]->i_pages_read++;
395 /*****************************************************************************
396 * Activate: initializes ogg demux structures
397 *****************************************************************************/
398 static int Activate( vlc_object_t * p_this )
400 int i_stream, b_forced;
402 input_thread_t *p_input = (input_thread_t *)p_this;
404 p_input->p_demux_data = NULL;
405 b_forced = ( ( *p_input->psz_demux )&&
406 ( !strncmp( p_input->psz_demux, "ogg", 10 ) ) ) ? 1 : 0;
408 /* Check if we are dealing with an ogg stream */
409 if( !b_forced && ( Ogg_Check( p_input ) != VLC_SUCCESS ) )
413 if( !( p_ogg = malloc( sizeof( demux_sys_t ) ) ) )
415 msg_Err( p_input, "out of memory" );
418 memset( p_ogg, 0, sizeof( demux_sys_t ) );
419 p_input->p_demux_data = p_ogg;
422 p_ogg->p_stream_timeref = NULL;
423 p_ogg->b_seekable = ( ( p_input->stream.b_seekable )
424 &&( p_input->stream.i_method == INPUT_METHOD_FILE ) );
426 /* Initialize the Ogg physical bitstream parser */
427 ogg_sync_init( &p_ogg->oy );
429 /* Find the logical streams embedded in the physical stream and
430 * initialize our p_ogg structure. */
431 if( Ogg_FindLogicalStreams( p_input, p_ogg ) != VLC_SUCCESS )
433 msg_Err( p_input, "couldn't find an ogg logical stream" );
437 /* Set the demux function */
438 p_input->pf_demux = Demux;
440 /* Initialize access plug-in structures. */
441 if( p_input->i_mtu == 0 )
444 p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
447 /* Create one program */
448 vlc_mutex_lock( &p_input->stream.stream_lock );
449 if( input_InitStream( p_input, 0 ) == -1)
451 vlc_mutex_unlock( &p_input->stream.stream_lock );
452 msg_Err( p_input, "cannot init stream" );
455 if( input_AddProgram( p_input, 0, 0) == NULL )
457 vlc_mutex_unlock( &p_input->stream.stream_lock );
458 msg_Err( p_input, "cannot add program" );
461 p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
462 p_input->stream.i_mux_rate = 0;
463 vlc_mutex_unlock( &p_input->stream.stream_lock );
465 for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ )
467 #define p_stream p_ogg->pp_stream[i_stream]
468 vlc_mutex_lock( &p_input->stream.stream_lock );
469 p_stream->p_es = input_AddES( p_input,
470 p_input->stream.p_selected_program,
471 p_ogg->i_streams + 1, 0 );
472 p_input->stream.i_mux_rate += (p_stream->i_bitrate / ( 8 * 50 ));
473 vlc_mutex_unlock( &p_input->stream.stream_lock );
474 p_stream->p_es->i_stream_id = i_stream;
475 p_stream->p_es->i_fourcc = p_stream->i_fourcc;
476 p_stream->p_es->i_cat = p_stream->i_cat;
480 for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
482 #define p_stream p_ogg->pp_stream[i_stream]
483 switch( p_stream->p_es->i_cat )
487 if( (p_ogg->p_stream_video == NULL) )
489 p_ogg->p_stream_video = p_stream;
490 /* TODO add test to see if a decoder has been found */
491 Ogg_StreamStart( p_input, p_ogg, i_stream );
496 if( (p_ogg->p_stream_audio == NULL) )
498 p_ogg->p_stream_audio = p_stream;
499 p_ogg->p_stream_timeref = p_stream;
500 Ogg_StreamStart( p_input, p_ogg, i_stream );
510 /* we select the first audio and video ES */
511 vlc_mutex_lock( &p_input->stream.stream_lock );
512 if( !p_ogg->p_stream_video )
514 msg_Warn( p_input, "no video stream found" );
516 if( !p_ogg->p_stream_audio )
518 msg_Warn( p_input, "no audio stream found!" );
520 p_input->stream.p_selected_program->b_is_ok = 1;
521 vlc_mutex_unlock( &p_input->stream.stream_lock );
523 /* Call the pace control */
524 input_ClockManageRef( p_input,
525 p_input->stream.p_selected_program,
531 Deactivate( (vlc_object_t *)p_input );
536 /*****************************************************************************
537 * Deactivate: frees unused data
538 *****************************************************************************/
539 static void Deactivate( vlc_object_t *p_this )
541 input_thread_t *p_input = (input_thread_t *)p_this;
542 demux_sys_t *p_ogg = (demux_sys_t *)p_input->p_demux_data ;
547 /* Cleanup the bitstream parser */
548 ogg_sync_clear( &p_ogg->oy );
550 for( i = 0; i < p_ogg->i_streams; i++ )
552 ogg_stream_clear( &p_ogg->pp_stream[i]->os );
553 free( p_ogg->pp_stream[i] );
555 if( p_ogg->pp_stream ) free( p_ogg->pp_stream );
561 /*****************************************************************************
562 * Demux: reads and demuxes data packets
563 *****************************************************************************
564 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
565 *****************************************************************************/
566 static int Demux( input_thread_t * p_input )
568 int i, i_stream, b_eos = 0;
570 ogg_packet oggpacket;
571 demux_sys_t *p_ogg = (demux_sys_t *)p_input->p_demux_data;
573 #define p_stream p_ogg->pp_stream[i_stream]
574 /* detect new selected/unselected streams */
575 for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
579 if( p_stream->p_es->p_decoder_fifo &&
580 !p_stream->i_activated )
582 Ogg_StreamStart( p_input, p_ogg, i_stream );
585 if( !p_stream->p_es->p_decoder_fifo &&
586 p_stream->i_activated )
588 Ogg_StreamStop( p_input, p_ogg, i_stream );
593 /* search for new video and audio stream to select
594 * if current have been unselected */
595 if( ( !p_ogg->p_stream_video )
596 || ( !p_ogg->p_stream_video->p_es->p_decoder_fifo ) )
598 p_ogg->p_stream_video = NULL;
599 for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
601 if( ( p_stream->i_cat == VIDEO_ES )
602 &&( p_stream->p_es->p_decoder_fifo ) )
604 p_ogg->p_stream_video = p_stream;
609 if( ( !p_ogg->p_stream_audio )
610 ||( !p_ogg->p_stream_audio->p_es->p_decoder_fifo ) )
612 p_ogg->p_stream_audio = NULL;
613 for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
615 if( ( p_stream->i_cat == AUDIO_ES )
616 &&( p_stream->p_es->p_decoder_fifo ) )
618 p_ogg->p_stream_audio = p_stream;
619 p_ogg->p_stream_timeref = p_stream;
625 if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
627 msg_Warn( p_input, "synchro reinit" );
629 /* An ogg packet does only contain the starting date of the next
630 * packet, not its own starting date.
631 * As a quick work around, we just skip an oggpage */
633 for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
635 /* we'll trash all the data until we find the next pcr */
636 p_stream->b_reinit = 1;
642 /* Demux ogg pages from the stream */
643 for( i = 0; (i < PAGES_READ_ONCE) || p_ogg->p_stream_timeref->b_reinit;
646 if( Ogg_ReadPage( p_input, p_ogg, &oggpage ) != VLC_SUCCESS )
652 for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
654 /* FIXME: we already read the header */
656 if( ogg_stream_pagein( &p_stream->os, &oggpage ) != 0 )
659 while( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
661 if( !p_stream->p_es ||
662 !p_stream->p_es->p_decoder_fifo )
667 if( p_stream->b_reinit )
669 if( oggpacket.granulepos >= 0 )
671 p_stream->b_reinit = 0;
672 p_stream->i_pcr = oggpacket.granulepos
673 * 90000 / p_stream->i_rate;
676 (p_stream == p_ogg->p_stream_timeref) )
678 /* Call the pace control to reinitialize
679 * the system clock */
680 p_ogg->i_pcr = p_stream->i_pcr;
681 input_ClockManageRef( p_input,
682 p_input->stream.p_selected_program,
689 Ogg_DecodePacket( p_input, p_stream, &oggpacket );
696 /* Call the pace control */
697 if( !b_eos ) input_ClockManageRef( p_input,
698 p_input->stream.p_selected_program,
701 /* Did we reach the end of stream ? */
702 return( b_eos ? 0 : 1 );