1 /*****************************************************************************
2 * ogg.c : ogg stream input module for vlc
3 *****************************************************************************
4 * Copyright (C) 2001 VideoLAN
5 * $Id: ogg.c,v 1.1 2002/10/24 09:30:48 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 /* info for vorbis logical streams */
66 ogg_sync_state oy; /* sync and verify incoming physical bitstream */
68 int i_streams; /* number of logical bitstreams */
69 logical_stream_t **pp_stream; /* pointer to an array of logical streams */
71 /* current audio and video es */
72 logical_stream_t *p_stream_video;
73 logical_stream_t *p_stream_audio;
81 /*****************************************************************************
83 *****************************************************************************/
84 static int Activate ( vlc_object_t * );
85 static void Deactivate( vlc_object_t * );
86 static int Demux ( input_thread_t * );
88 /* Stream managment */
89 static int Ogg_StreamStart ( input_thread_t *, demux_sys_t *, int );
90 static int Ogg_StreamSeek ( input_thread_t *, demux_sys_t *, int, mtime_t );
91 static void Ogg_StreamStop ( input_thread_t *, demux_sys_t *, int );
93 /* Bitstream manipulation */
94 static int Ogg_Check ( input_thread_t *p_input );
95 static int Ogg_ReadPage ( input_thread_t *, demux_sys_t *, ogg_page * );
96 static void Ogg_DecodePacket ( input_thread_t *p_input,
97 logical_stream_t *p_stream,
98 ogg_packet *p_oggpacket );
99 static int Ogg_FindLogicalStreams( input_thread_t *p_input,
100 demux_sys_t *p_ogg );
102 /*****************************************************************************
104 *****************************************************************************/
106 set_description( _("ogg stream demux" ) );
107 set_capability( "demux", 50 );
108 set_callbacks( Activate, Deactivate );
109 add_shortcut( "ogg" );
112 /*****************************************************************************
114 *****************************************************************************/
115 static int Ogg_StreamStart( input_thread_t *p_input,
116 demux_sys_t *p_ogg, int i_stream )
118 #define p_stream p_ogg->pp_stream[i_stream]
119 if( !p_stream->p_es )
121 msg_Warn( p_input, "stream[%d] unselectable", i_stream );
124 if( p_stream->i_activated )
126 msg_Warn( p_input, "stream[%d] already selected", i_stream );
130 if( !p_stream->p_es->p_decoder_fifo )
132 vlc_mutex_lock( &p_input->stream.stream_lock );
133 input_SelectES( p_input, p_stream->p_es );
134 vlc_mutex_unlock( &p_input->stream.stream_lock );
136 p_stream->i_activated = p_stream->p_es->p_decoder_fifo ? 1 : 0;
138 //Ogg_StreamSeek( p_input, p_ogg, i_stream, p_ogg->i_time );
140 return( p_stream->i_activated );
144 static void Ogg_StreamStop( input_thread_t *p_input,
145 demux_sys_t *p_ogg, int i_stream )
147 #define p_stream p_ogg->pp_stream[i_stream]
149 if( !p_stream->i_activated )
151 msg_Warn( p_input, "stream[%d] already unselected", i_stream );
155 if( p_stream->p_es->p_decoder_fifo )
157 vlc_mutex_lock( &p_input->stream.stream_lock );
158 input_UnselectES( p_input, p_stream->p_es );
159 vlc_mutex_unlock( &p_input->stream.stream_lock );
162 p_stream->i_activated = 0;
167 static int Ogg_StreamSeek( input_thread_t *p_input, demux_sys_t *p_ogg,
168 int i_stream, mtime_t i_date )
170 #define p_stream p_ogg->pp_stream[i_stream]
178 /****************************************************************************
179 * Ogg_Check: Check we are dealing with an ogg stream.
180 ****************************************************************************/
181 static int Ogg_Check( input_thread_t *p_input )
184 int i_size = input_Peek( p_input, &p_peek, 4 );
186 /* Check for the Ogg capture pattern */
187 if( !(i_size>3) || !(p_peek[0] == 'O') || !(p_peek[1] == 'g') ||
188 !(p_peek[2] == 'g') || !(p_peek[3] == 'S') )
191 /* FIXME: Capture pattern might not be enough so we can also check for the
192 * the first complete page */
197 /****************************************************************************
198 * Ogg_ReadPage: Read a full Ogg page from the physical bitstream.
199 ****************************************************************************
200 * Returns VLC_SUCCESS if a page has been read. An error might happen if we
201 * are at the end of stream.
202 ****************************************************************************/
203 static int Ogg_ReadPage( input_thread_t *p_input, demux_sys_t *p_ogg,
204 ogg_page *p_oggpage )
207 data_packet_t *p_data;
210 while( ogg_sync_pageout( &p_ogg->oy, p_oggpage ) != 1 )
212 i_read = input_SplitBuffer( p_input, &p_data, OGG_BLOCK_SIZE );
216 p_buffer = ogg_sync_buffer( &p_ogg->oy, i_read );
217 p_input->p_vlc->pf_memcpy( p_buffer, p_data->p_payload_start, i_read );
218 ogg_sync_wrote( &p_ogg->oy, i_read );
219 input_DeletePacket( p_input->p_method_data, p_data );
225 /****************************************************************************
226 * Ogg_DecodePacket: Decode an Ogg packet.
227 ****************************************************************************/
228 static void Ogg_DecodePacket( input_thread_t *p_input,
229 logical_stream_t *p_stream,
230 ogg_packet *p_oggpacket )
233 data_packet_t *p_data;
235 if( !( p_pes = input_NewPES( p_input->p_method_data ) ) )
239 if( !( p_data = input_NewPacket( p_input->p_method_data,
240 p_oggpacket->bytes ) ) )
242 input_DeletePES( p_input->p_method_data, p_pes );
246 p_pes->p_first = p_pes->p_last = p_data;
247 p_pes->i_nb_data = 1;
248 p_pes->i_pes_size = p_oggpacket->bytes;
249 p_pes->i_dts = p_oggpacket->granulepos;
251 /* Convert the granule into a pts */
252 p_pes->i_pts = (p_oggpacket->granulepos < 0) ? 0 :
253 p_oggpacket->granulepos * 90000 / p_stream->i_rate;
254 p_pes->i_pts = (p_oggpacket->granulepos < 0) ? 0 :
255 input_ClockGetTS( p_input, p_input->stream.p_selected_program,
258 memcpy( p_data->p_payload_start, p_oggpacket->packet, p_oggpacket->bytes );
260 input_DecodePES( p_stream->p_es->p_decoder_fifo, p_pes );
263 /****************************************************************************
264 * Ogg_FindLogicalStreams: Find the logical streams embedded in the physical
265 * stream and fill p_ogg.
266 *****************************************************************************
267 * The initial page of a logical stream is marked as a 'bos' page.
268 * Furthermore, the Ogg specification mandates that grouped bitstreams begin
269 * together and all of the initial pages must appear before any data pages.
271 * On success this function returns VLC_SUCCESS.
272 ****************************************************************************/
273 static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
275 ogg_packet oggpacket;
279 while( Ogg_ReadPage( p_input, p_ogg, &oggpage ) == VLC_SUCCESS )
281 if( ogg_page_bos( &oggpage ) )
284 /* All is wonderful in our fine fine little world.
285 * We found the beginning of our first logical stream. */
286 while( ogg_page_bos( &oggpage ) )
290 realloc( p_ogg->pp_stream, p_ogg->i_streams *
291 sizeof(logical_stream_t *) );
293 #define p_stream p_ogg->pp_stream[p_ogg->i_streams - 1]
295 p_stream = malloc( sizeof(logical_stream_t) );
296 memset( p_stream, 0, sizeof(logical_stream_t) );
298 /* Setup the logical stream */
299 p_stream->i_pages_read++;
300 p_stream->i_serial_no = ogg_page_serialno( &oggpage );
301 ogg_stream_init( &p_stream->os, p_stream->i_serial_no );
303 /* Extract the initial header from the first page and verify
304 * the codec type of tis Ogg bitstream */
305 if( ogg_stream_pagein( &p_stream->os, &oggpage ) < 0 )
307 /* error. stream version mismatch perhaps */
308 msg_Err( p_input, "Error reading first page of "
309 "Ogg bitstream data" );
313 /* FIXME: check return value */
314 ogg_stream_packetpeek( &p_stream->os, &oggpacket );
316 /* Check for Vorbis header */
317 if( oggpacket.bytes >= 7 &&
318 ! strncmp( &oggpacket.packet[1], "vorbis", 6 ) )
322 msg_Dbg( p_input, "found vorbis header" );
323 p_stream->i_cat = AUDIO_ES;
324 p_stream->i_fourcc = VLC_FOURCC( 'v','o','r','b' );
326 /* Cheat and get additionnal info ;) */
327 oggpack_readinit( &opb, oggpacket.packet, oggpacket.bytes);
328 oggpack_adv( &opb, 88 );
329 p_stream->i_channels = oggpack_read( &opb, 8 );
330 p_stream->i_rate = oggpack_read( &opb, 32 );
331 oggpack_adv( &opb, 32 );
332 p_stream->i_bitrate = oggpack_read( &opb, 32 );
336 msg_Dbg( p_input, "found unknown codec" );
337 ogg_stream_destroy( &p_stream->os );
344 if( Ogg_ReadPage( p_input, p_ogg, &oggpage ) != VLC_SUCCESS )
348 /* This is the first data page, which means we are now finished
349 * with the initial pages. We just need to store it in the relevant
351 for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
353 if( ogg_stream_pagein( &p_ogg->pp_stream[i_stream]->os,
356 p_ogg->pp_stream[i_stream]->i_pages_read++;
366 /*****************************************************************************
367 * Activate: initializes ogg demux structures
368 *****************************************************************************/
369 static int Activate( vlc_object_t * p_this )
371 int i_stream, b_forced;
373 input_thread_t *p_input = (input_thread_t *)p_this;
375 p_input->p_demux_data = NULL;
376 b_forced = ( ( *p_input->psz_demux )&&
377 ( !strncmp( p_input->psz_demux, "ogg", 10 ) ) ) ? 1 : 0;
379 /* Check if we are dealing with an ogg stream */
380 if( !b_forced && ( Ogg_Check( p_input ) != VLC_SUCCESS ) )
384 if( !( p_ogg = malloc( sizeof( demux_sys_t ) ) ) )
386 msg_Err( p_input, "out of memory" );
389 memset( p_ogg, 0, sizeof( demux_sys_t ) );
390 p_input->p_demux_data = p_ogg;
394 p_ogg->b_seekable = ( ( p_input->stream.b_seekable )
395 &&( p_input->stream.i_method == INPUT_METHOD_FILE ) );
397 /* Initialize the Ogg physical bitstream parser */
398 ogg_sync_init( &p_ogg->oy );
400 /* Find the logical streams embedded in the physical stream and
401 * initialize our p_ogg structure. */
402 if( Ogg_FindLogicalStreams( p_input, p_ogg ) != VLC_SUCCESS )
404 msg_Err( p_input, "couldn't find an ogg logical stream" );
408 /* Set the demux function */
409 p_input->pf_demux = Demux;
411 /* Initialize access plug-in structures. */
412 if( p_input->i_mtu == 0 )
415 p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
418 /* Create one program */
419 vlc_mutex_lock( &p_input->stream.stream_lock );
420 if( input_InitStream( p_input, 0 ) == -1)
422 vlc_mutex_unlock( &p_input->stream.stream_lock );
423 msg_Err( p_input, "cannot init stream" );
426 if( input_AddProgram( p_input, 0, 0) == NULL )
428 vlc_mutex_unlock( &p_input->stream.stream_lock );
429 msg_Err( p_input, "cannot add program" );
432 p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
433 vlc_mutex_unlock( &p_input->stream.stream_lock );
435 for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ )
437 #define p_stream p_ogg->pp_stream[i_stream]
438 vlc_mutex_lock( &p_input->stream.stream_lock );
439 p_stream->p_es = input_AddES( p_input,
440 p_input->stream.p_selected_program,
441 p_ogg->i_streams + 1, 0 );
442 vlc_mutex_unlock( &p_input->stream.stream_lock );
443 p_stream->p_es->i_stream_id = i_stream;
444 p_stream->p_es->i_fourcc = p_stream->i_fourcc;
445 p_stream->p_es->i_cat = p_stream->i_cat;
449 vlc_mutex_lock( &p_input->stream.stream_lock );
450 p_input->stream.i_mux_rate = 0;
451 vlc_mutex_unlock( &p_input->stream.stream_lock );
453 for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
455 #define p_stream p_ogg->pp_stream[i_stream]
456 switch( p_stream->p_es->i_cat )
460 if( (p_ogg->p_stream_video == NULL) )
462 p_ogg->p_stream_video = p_stream;
463 /* TODO add test to see if a decoder has been found */
464 Ogg_StreamStart( p_input, p_ogg, i_stream );
469 if( (p_ogg->p_stream_audio == NULL) )
471 p_ogg->p_stream_audio = p_stream;
472 Ogg_StreamStart( p_input, p_ogg, i_stream );
482 /* we select the first audio and video ES */
483 vlc_mutex_lock( &p_input->stream.stream_lock );
484 if( !p_ogg->p_stream_video )
486 msg_Warn( p_input, "no video stream found" );
488 if( !p_ogg->p_stream_audio )
490 msg_Warn( p_input, "no audio stream found!" );
492 p_input->stream.p_selected_program->b_is_ok = 1;
493 vlc_mutex_unlock( &p_input->stream.stream_lock );
498 Deactivate( (vlc_object_t *)p_input );
503 /*****************************************************************************
504 * Deactivate: frees unused data
505 *****************************************************************************/
506 static void Deactivate( vlc_object_t *p_this )
508 input_thread_t *p_input = (input_thread_t *)p_this;
509 demux_sys_t *p_ogg = (demux_sys_t *)p_input->p_demux_data ;
514 /* Cleanup the bitstream parser */
515 ogg_sync_clear( &p_ogg->oy );
517 for( i = 0; i < p_ogg->i_streams; i++ )
519 ogg_stream_clear( &p_ogg->pp_stream[i]->os );
520 free( p_ogg->pp_stream[i] );
522 if( p_ogg->pp_stream ) free( p_ogg->pp_stream );
528 /*****************************************************************************
529 * Demux: reads and demuxes data packets
530 *****************************************************************************
531 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
532 *****************************************************************************/
533 static int Demux( input_thread_t * p_input )
535 int i, i_stream, b_eos;
537 ogg_packet oggpacket;
538 demux_sys_t *p_ogg = (demux_sys_t *)p_input->p_demux_data;
540 #define p_stream p_ogg->pp_stream[i_stream]
541 /* detect new selected/unselected streams */
542 for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
546 if( p_stream->p_es->p_decoder_fifo &&
547 !p_stream->i_activated )
549 Ogg_StreamStart( p_input, p_ogg, i_stream );
552 if( !p_stream->p_es->p_decoder_fifo &&
553 p_stream->i_activated )
555 Ogg_StreamStop( p_input, p_ogg, i_stream );
560 /* search new video and audio stream selected
561 * if current have been unselected */
562 if( ( !p_ogg->p_stream_video )
563 || ( !p_ogg->p_stream_video->p_es->p_decoder_fifo ) )
565 p_ogg->p_stream_video = NULL;
566 for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
568 if( ( p_stream->i_cat == VIDEO_ES )
569 &&( p_stream->p_es->p_decoder_fifo ) )
571 p_ogg->p_stream_video = p_stream;
576 if( ( !p_ogg->p_stream_audio )
577 ||( !p_ogg->p_stream_audio->p_es->p_decoder_fifo ) )
579 p_ogg->p_stream_audio = NULL;
580 for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
582 if( ( p_stream->i_cat == AUDIO_ES )
583 &&( p_stream->p_es->p_decoder_fifo ) )
585 p_ogg->p_stream_audio = p_stream;
591 /* Update program clock reference */
592 p_ogg->i_pcr = p_ogg->i_time * 9 / 100;
594 if( (p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT)
595 || (input_ClockManageControl( p_input,
596 p_input->stream.p_selected_program,
597 (mtime_t)0 ) == PAUSE_S) )
599 msg_Warn( p_input, "synchro reinit" );
600 p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_OK;
603 /* Call the pace control. */
604 input_ClockManageRef( p_input,
605 p_input->stream.p_selected_program,
608 /* Demux ogg pages from the stream */
610 for( i = 0; i < PAGES_READ_ONCE; i++ )
612 if( Ogg_ReadPage(p_input, p_ogg, &oggpage ) != VLC_SUCCESS )
618 for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
620 /* FIXME: we already read the header */
622 if( ogg_stream_pagein( &p_stream->os, &oggpage ) != 0 )
625 while( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
627 /* FIXME: handle discontinuity */
629 if( !p_stream->p_es ||
630 !p_stream->p_es->p_decoder_fifo )
635 if( oggpacket.granulepos >= 0 )
636 p_ogg->i_time = oggpacket.granulepos * 1000000
639 p_ogg->i_time += (oggpacket.bytes * 1000000
640 / p_stream->i_bitrate);
642 Ogg_DecodePacket( p_input, p_stream, &oggpacket );
648 /* Did we reach the end of stream ? */
649 return( b_eos ? 0 : 1 );