* ogg.c : ogg stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: ogg.c,v 1.13 2002/11/26 17:38:33 gbazin Exp $
+ * $Id: ogg.c,v 1.33 2003/09/07 22:48:29 fenrir Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
/* info from logical streams */
double f_rate;
int i_bitrate;
+ int i_channels;
int b_reinit;
/* codec specific stuff */
/* program clock reference (in units of 90kHz) derived from the pcr of
* the sub-streams */
mtime_t i_pcr;
+ mtime_t i_old_pcr;
- mtime_t i_length;
int b_seekable;
int b_reinit;
};
#define PACKET_LEN_BITS2 0x02
#define PACKET_IS_SYNCPOINT 0x08
-/* Some functions to manipulate memory */
-static uint16_t GetWLE( uint8_t *p_buff )
-{
- return( (p_buff[0]) + ( p_buff[1] <<8 ) );
-}
-
-static uint32_t GetDWLE( uint8_t *p_buff )
-{
- return( p_buff[0] + ( p_buff[1] <<8 ) +
- ( p_buff[2] <<16 ) + ( p_buff[3] <<24 ) );
-}
-
-static uint64_t GetQWLE( uint8_t *p_buff )
-{
- return( GetDWLE( p_buff ) + ( ((uint64_t)GetDWLE( p_buff + 4 )) << 32 ) );
-}
/*****************************************************************************
* Local prototypes
*****************************************************************************/
* Module descriptor
*****************************************************************************/
vlc_module_begin();
- set_description( _("ogg stream demux" ) );
+ set_description( _("ogg stream demuxer" ) );
set_capability( "demux", 50 );
set_callbacks( Activate, Deactivate );
add_shortcut( "ogg" );
switch( p_stream->i_fourcc )
{
case VLC_FOURCC( 'v','o','r','b' ):
+ case VLC_FOURCC( 't','h','e','o' ):
if( p_stream->i_packets_backup == 3 ) p_stream->b_force_backup = 0;
break;
input_DeletePES( p_input->p_method_data, p_pes );
return;
}
+ p_data->p_payload_end = p_data->p_payload_start + p_oggpacket->bytes;
/* Convert the pcr into a pts */
- if( p_stream->i_cat != SPU_ES )
+ if( p_stream->i_fourcc == VLC_FOURCC( 'v','o','r','b' ) ||
+ p_stream->i_fourcc == VLC_FOURCC( 't','h','e','o' ) )
{
p_pes->i_pts = ( p_stream->i_pcr < 0 ) ? 0 :
input_ClockGetTS( p_input, p_input->stream.p_selected_program,
if( p_stream->i_fourcc == VLC_FOURCC( 't','a','r','k' ) )
{
/* FIXME: the biggest hack I've ever done */
- msg_Warn( p_input, "tark pts: %lli, granule: %i",
+ msg_Warn( p_input, "tark pts: "I64Fd", granule: "I64Fd,
p_pes->i_pts, p_pes->i_dts );
msleep(10000);
}
/* Cheat and get additionnal info ;) */
oggpack_readinit( &opb, oggpacket.packet, oggpacket.bytes);
- oggpack_adv( &opb, 96 );
+ oggpack_adv( &opb, 88 );
+ p_stream->i_channels = oggpack_read( &opb, 8 );
p_stream->f_rate = oggpack_read( &opb, 32 );
oggpack_adv( &opb, 32 );
p_stream->i_bitrate = oggpack_read( &opb, 32 );
+ {
+ char title[sizeof("Stream") + 10];
+ input_info_category_t *p_cat;
+ sprintf( title, "Stream %d", p_ogg->i_streams );
+ p_cat = input_InfoCategory( p_input, title );
+ input_AddInfo( p_cat, _("Type"), _("Audio") );
+ input_AddInfo( p_cat, _("Codec"), _("Vorbis") );
+ input_AddInfo( p_cat, _("Sample Rate"), "%f",
+ p_stream->f_rate );
+ input_AddInfo( p_cat, _("Channels"), "%d",
+ p_stream->i_channels );
+ input_AddInfo( p_cat, _("Bit Rate"), "%d",
+ p_stream->i_bitrate );
+ }
}
/* Check for Theora header */
else if( oggpacket.bytes >= 7 &&
p_stream->i_cat = VIDEO_ES;
p_stream->i_fourcc = VLC_FOURCC( 't','h','e','o' );
+ /* Signal that we want to keep a backup of the vorbis
+ * stream headers. They will be used when switching between
+ * audio streams. */
+ p_stream->b_force_backup = 1;
+
/* Cheat and get additionnal info ;) */
oggpackB_readinit(&opb, oggpacket.packet, oggpacket.bytes);
oggpackB_adv( &opb, 56 );
oggpackB_read( &opb, 8 ); /* subminor version num */
oggpackB_read( &opb, 16 ) /*<< 4*/; /* width */
oggpackB_read( &opb, 16 ) /*<< 4*/; /* height */
+ oggpackB_read( &opb, 24 ); /* frame width */
+ oggpackB_read( &opb, 24 ); /* frame height */
+ oggpackB_read( &opb, 8 ); /* x offset */
+ oggpackB_read( &opb, 8 ); /* y offset */
+
i_fps_numerator = oggpackB_read( &opb, 32 );
i_fps_denominator = oggpackB_read( &opb, 32 );
oggpackB_read( &opb, 24 ); /* aspect_numerator */
oggpackB_read( &opb, 24 ); /* aspect_denominator */
i_keyframe_frequency_force = 1 << oggpackB_read( &opb, 5 );
+ oggpackB_read( &opb, 8 ); /* colorspace */
p_stream->i_bitrate = oggpackB_read( &opb, 24 );
- oggpackB_read(&opb,6); /* quality */
+ oggpackB_read( &opb, 6 ); /* quality */
/* granule_shift = i_log( frequency_force -1 ) */
p_stream->i_theora_keyframe_granule_shift = 0;
i_keyframe_frequency_force >>= 1;
}
- p_stream->f_rate = (float)i_fps_numerator /
+ p_stream->f_rate = ((float)i_fps_numerator) /
i_fps_denominator;
msg_Dbg( p_input,
"found theora header, bitrate: %i, rate: %f",
p_stream->i_bitrate, p_stream->f_rate );
+ {
+ char title[sizeof("Stream") + 10];
+ input_info_category_t *p_cat;
+ sprintf( title, "Stream %d", p_ogg->i_streams );
+ p_cat = input_InfoCategory( p_input, title );
+ input_AddInfo( p_cat, _("Type"), _("Video") );
+ input_AddInfo( p_cat, _("Codec"), _("Theora") );
+ input_AddInfo( p_cat, _("Frame Rate"), "%f",
+ p_stream->f_rate );
+ input_AddInfo( p_cat, _("Bit Rate"), "%d",
+ p_stream->i_bitrate );
+ }
#else /* HAVE_OGGPACKB */
msg_Dbg( p_input, "the ogg demuxer has been compiled "
"without support for the oggpackB extension."
msg_Dbg( p_input,
"found tarkin header, bitrate: %i, rate: %f",
p_stream->i_bitrate, p_stream->f_rate );
+ {
+ char title[sizeof("Stream") + 10];
+ input_info_category_t *p_cat;
+ sprintf( title, "Stream %d", p_ogg->i_streams );
+ p_cat = input_InfoCategory( p_input, title );
+ input_AddInfo( p_cat, _("Type"), _("Video") );
+ input_AddInfo( p_cat, _("Codec"), _("tarkin") );
+ input_AddInfo( p_cat, _("Sample Rate"), "%f",
+ p_stream->f_rate );
+ input_AddInfo( p_cat, _("Bit Rate"), "%d",
+ p_stream->i_bitrate );
+ }
+
+ }
+ else if( oggpacket.bytes >= 142 &&
+ !strncmp( &oggpacket.packet[1],
+ "Direct Show Samples embedded in Ogg", 35 ))
+ {
+ /* Old header type */
+
+ /* Check for video header (old format) */
+ if( GetDWLE((oggpacket.packet+96)) == 0x05589f80 &&
+ oggpacket.bytes >= 184 )
+ {
+ p_stream->i_cat = VIDEO_ES;
+
+ p_stream->p_bih = (BITMAPINFOHEADER *)
+ malloc( sizeof(BITMAPINFOHEADER) );
+ if( !p_stream->p_bih )
+ {
+ /* Mem allocation error, just ignore the stream */
+ free( p_stream );
+ p_ogg->i_streams--;
+ continue;
+ }
+ p_stream->p_bih->biSize = sizeof(BITMAPINFOHEADER);
+ p_stream->p_bih->biCompression= p_stream->i_fourcc =
+ VLC_FOURCC( oggpacket.packet[68],
+ oggpacket.packet[69],
+ oggpacket.packet[70],
+ oggpacket.packet[71] );
+ msg_Dbg( p_input, "found video header of type: %.4s",
+ (char *)&p_stream->i_fourcc );
+
+ p_stream->f_rate = 10000000.0 /
+ GetQWLE((oggpacket.packet+164));
+ p_stream->p_bih->biBitCount =
+ GetWLE((oggpacket.packet+182));
+ if( !p_stream->p_bih->biBitCount )
+ p_stream->p_bih->biBitCount=24; // hack, FIXME
+ p_stream->p_bih->biWidth =
+ GetDWLE((oggpacket.packet+176));
+ p_stream->p_bih->biHeight =
+ GetDWLE((oggpacket.packet+180));
+ p_stream->p_bih->biPlanes= 1 ;
+ p_stream->p_bih->biSizeImage =
+ (p_stream->p_bih->biBitCount >> 3) *
+ p_stream->p_bih->biWidth *
+ p_stream->p_bih->biHeight;
+
+ msg_Dbg( p_input,
+ "fps: %f, width:%i; height:%i, bitcount:%i",
+ p_stream->f_rate, p_stream->p_bih->biWidth,
+ p_stream->p_bih->biHeight,
+ p_stream->p_bih->biBitCount);
+ {
+ char title[sizeof("Stream") + 10];
+ input_info_category_t *p_cat;
+ sprintf( title, "Stream %d", p_ogg->i_streams );
+ p_cat = input_InfoCategory( p_input, title );
+ input_AddInfo( p_cat, _("Type"), _("Video") );
+ input_AddInfo( p_cat, _("Codec"), "%.4s",
+ (char *)&p_stream->i_fourcc );
+ input_AddInfo( p_cat, _("Frame Rate"), "%f",
+ p_stream->f_rate );
+ input_AddInfo( p_cat, _("Bit Count"), "%d",
+ p_stream->p_bih->biBitCount );
+ input_AddInfo( p_cat, _("Width"), "%d",
+ p_stream->p_bih->biWidth );
+ input_AddInfo( p_cat, _("Height"), "%d",
+ p_stream->p_bih->biHeight );
+ }
+ p_stream->i_bitrate = 0;
+ }
+ /* Check for audio header (old format) */
+ else if( GetDWLE((oggpacket.packet+96)) == 0x05589F81 )
+ {
+ unsigned int i_extra_size;
+
+ p_stream->i_cat = AUDIO_ES;
+
+ i_extra_size = GetWLE((oggpacket.packet+140));
+
+ p_stream->p_wf = (WAVEFORMATEX *)
+ malloc( sizeof(WAVEFORMATEX) + i_extra_size );
+ if( !p_stream->p_wf )
+ {
+ /* Mem allocation error, just ignore the stream */
+ free( p_stream );
+ p_ogg->i_streams--;
+ continue;
+ }
+
+ p_stream->p_wf->wFormatTag =
+ GetWLE((oggpacket.packet+124));
+ p_stream->p_wf->nChannels =
+ GetWLE((oggpacket.packet+126));
+ p_stream->f_rate = p_stream->p_wf->nSamplesPerSec =
+ GetDWLE((oggpacket.packet+128));
+ p_stream->i_bitrate = p_stream->p_wf->nAvgBytesPerSec =
+ GetDWLE((oggpacket.packet+132));
+ p_stream->i_bitrate *= 8;
+ p_stream->p_wf->nBlockAlign =
+ GetWLE((oggpacket.packet+136));
+ p_stream->p_wf->wBitsPerSample =
+ GetWLE((oggpacket.packet+138));
+ p_stream->p_wf->cbSize = i_extra_size;
+
+ if( i_extra_size > 0 )
+ memcpy( p_stream->p_wf+sizeof(WAVEFORMATEX),
+ oggpacket.packet+142, i_extra_size );
+
+ switch( p_stream->p_wf->wFormatTag )
+ {
+ case WAVE_FORMAT_PCM:
+ p_stream->i_fourcc =
+ VLC_FOURCC( 'a', 'r', 'a', 'w' );
+ break;
+ case WAVE_FORMAT_MPEG:
+ case WAVE_FORMAT_MPEGLAYER3:
+ p_stream->i_fourcc =
+ VLC_FOURCC( 'm', 'p', 'g', 'a' );
+ break;
+ case WAVE_FORMAT_A52:
+ p_stream->i_fourcc =
+ VLC_FOURCC( 'a', '5', '2', ' ' );
+ break;
+ case WAVE_FORMAT_WMA1:
+ p_stream->i_fourcc =
+ VLC_FOURCC( 'w', 'm', 'a', '1' );
+ break;
+ case WAVE_FORMAT_WMA2:
+ p_stream->i_fourcc =
+ VLC_FOURCC( 'w', 'm', 'a', '2' );
+ break;
+ default:
+ p_stream->i_fourcc = VLC_FOURCC( 'm', 's',
+ ( p_stream->p_wf->wFormatTag >> 8 ) & 0xff,
+ p_stream->p_wf->wFormatTag & 0xff );
+ }
+
+ msg_Dbg( p_input, "found audio header of type: %.4s",
+ (char *)&p_stream->i_fourcc );
+ msg_Dbg( p_input, "audio:0x%4.4x channels:%d %dHz "
+ "%dbits/sample %dkb/s",
+ p_stream->p_wf->wFormatTag,
+ p_stream->p_wf->nChannels,
+ p_stream->p_wf->nSamplesPerSec,
+ p_stream->p_wf->wBitsPerSample,
+ p_stream->p_wf->nAvgBytesPerSec * 8 / 1024 );
+ {
+ char title[sizeof("Stream") + 10];
+ input_info_category_t *p_cat;
+ sprintf( title, "Stream %d", p_ogg->i_streams );
+ p_cat = input_InfoCategory( p_input, title );
+ input_AddInfo( p_cat, _("Type"), _("Audio") );
+ input_AddInfo( p_cat, _("Codec"), "%.4s",
+ (char *)&p_stream->i_fourcc );
+ input_AddInfo( p_cat, _("Sample Rate"), "%d",
+ p_stream->p_wf->nSamplesPerSec );
+ input_AddInfo( p_cat, _("Bit Rate"), "%d",
+ p_stream->p_wf->nAvgBytesPerSec * 8
+ / 1024 );
+ input_AddInfo( p_cat, _("Channels"), "%d",
+ p_stream->p_wf->nChannels );
+ input_AddInfo( p_cat, _("Bits per Sample"), "%d",
+ p_stream->p_wf->wBitsPerSample );
+ }
+
+ }
+ else
+ {
+ msg_Dbg( p_input, "stream %d has an old header "
+ "but is of an unknown type", p_ogg->i_streams-1 );
+ free( p_stream );
+ p_ogg->i_streams--;
+ }
}
else if( (*oggpacket.packet & PACKET_TYPE_BITS )
== PACKET_TYPE_HEADER &&
(char *)&p_stream->i_fourcc );
p_stream->f_rate = 10000000.0 /
- GetQWLE((uint8_t *)&st->time_unit);
+ GetQWLE(&st->time_unit);
p_stream->p_bih->biBitCount =
- GetWLE((uint8_t *)&st->bits_per_sample);
+ GetWLE(&st->bits_per_sample);
p_stream->p_bih->biWidth =
- GetDWLE((uint8_t *)&st->sh.video.width);
+ GetDWLE(&st->sh.video.width);
p_stream->p_bih->biHeight =
- GetDWLE((uint8_t *)&st->sh.video.height);
+ GetDWLE(&st->sh.video.height);
p_stream->p_bih->biPlanes= 1 ;
p_stream->p_bih->biSizeImage =
(p_stream->p_bih->biBitCount >> 3) *
p_stream->p_bih->biHeight,
p_stream->p_bih->biBitCount);
+ {
+ char title[sizeof("Stream") + 10];
+ input_info_category_t *p_cat;
+ sprintf( title, "Stream %d", p_ogg->i_streams );
+ p_cat = input_InfoCategory( p_input, title );
+ input_AddInfo( p_cat, _("Type"), _("Video") );
+ input_AddInfo( p_cat, _("Codec"), "%.4s",
+ (char *)&p_stream->i_fourcc );
+ input_AddInfo( p_cat, _("Frame Rate"), "%f",
+ p_stream->f_rate );
+ input_AddInfo( p_cat, _("Bit Count"), "%d",
+ p_stream->p_bih->biBitCount );
+ input_AddInfo( p_cat, _("Width"), "%d",
+ p_stream->p_bih->biWidth );
+ input_AddInfo( p_cat, _("Height"), "%d",
+ p_stream->p_bih->biHeight );
+ }
p_stream->i_bitrate = 0;
}
/* Check for audio header (new format) */
p_buffer[4] = '\0';
p_stream->p_wf->wFormatTag = strtol(p_buffer,NULL,16);
p_stream->p_wf->nChannels =
- GetWLE((uint8_t *)&st->sh.audio.channels);
+ GetWLE(&st->sh.audio.channels);
p_stream->f_rate = p_stream->p_wf->nSamplesPerSec =
- GetQWLE((uint8_t *)&st->samples_per_unit);
+ GetQWLE(&st->samples_per_unit);
p_stream->i_bitrate = p_stream->p_wf->nAvgBytesPerSec =
- GetDWLE((uint8_t *)&st->sh.audio.avgbytespersec);
+ GetDWLE(&st->sh.audio.avgbytespersec);
p_stream->i_bitrate *= 8;
p_stream->p_wf->nBlockAlign =
- GetWLE((uint8_t *)&st->sh.audio.blockalign);
+ GetWLE(&st->sh.audio.blockalign);
p_stream->p_wf->wBitsPerSample =
- GetWLE((uint8_t *)&st->bits_per_sample);
+ GetWLE(&st->bits_per_sample);
p_stream->p_wf->cbSize = 0;
switch( p_stream->p_wf->wFormatTag )
p_stream->p_wf->nSamplesPerSec,
p_stream->p_wf->wBitsPerSample,
p_stream->p_wf->nAvgBytesPerSec * 8 / 1024 );
+ {
+ char title[sizeof("Stream") + 10];
+ input_info_category_t *p_cat;
+ sprintf( title, "Stream %d", p_ogg->i_streams );
+ p_cat = input_InfoCategory( p_input, title );
+ input_AddInfo( p_cat, _("Type"), _("Audio") );
+ input_AddInfo( p_cat, _("Codec"), "%.4s",
+ (char *)&p_stream->i_fourcc );
+ input_AddInfo( p_cat, _("Sample Rate"), "%d",
+ p_stream->p_wf->nSamplesPerSec );
+ input_AddInfo( p_cat, _("Bit Rate"), "%d",
+ p_stream->p_wf->nAvgBytesPerSec * 8
+ / 1024 );
+ input_AddInfo( p_cat, _("Channels"), "%d",
+ p_stream->p_wf->nChannels );
+ input_AddInfo( p_cat, _("Bits per Sample"), "%d",
+ p_stream->p_wf->wBitsPerSample );
+ }
}
/* Check for text (subtitles) header */
else if( !strncmp(st->streamtype, "text", 4) )
/* Set the demux function */
p_input->pf_demux = Demux;
+ p_input->pf_demux_control = demux_vaControlDefault;
/* Initialize access plug-in structures. */
if( p_input->i_mtu == 0 )
vlc_mutex_lock( &p_input->stream.stream_lock );
p_stream->p_es = input_AddES( p_input,
p_input->stream.p_selected_program,
- p_ogg->i_streams + 1, 0 );
+ i_stream,
+ p_stream->i_cat, NULL, 0 );
p_input->stream.i_mux_rate += (p_stream->i_bitrate / ( 8 * 50 ));
vlc_mutex_unlock( &p_input->stream.stream_lock );
- p_stream->p_es->i_stream_id = p_stream->p_es->i_id = i_stream;
+ p_stream->p_es->i_stream_id = i_stream;
p_stream->p_es->i_fourcc = p_stream->i_fourcc;
- p_stream->p_es->i_cat = p_stream->i_cat;
- p_stream->p_es->p_demux_data = p_stream->p_bih ?
- (void *)p_stream->p_bih : (void *)p_stream->p_wf;
+ p_stream->p_es->p_waveformatex = (void*)p_stream->p_wf;
+ p_stream->p_es->p_bitmapinfoheader = (void*)p_stream->p_bih;
#undef p_stream
}
}
i_stream = 0;
+ p_ogg->i_old_pcr = p_ogg->i_pcr;
p_ogg->i_pcr = p_stream->i_interpolated_pcr;
for( ; i_stream < p_ogg->i_streams; i_stream++ )
{
if( p_stream->i_cat == SPU_ES )
continue;
- if( p_stream->i_interpolated_pcr < p_ogg->i_pcr )
+ if( p_stream->i_interpolated_pcr > 0
+ && p_stream->i_interpolated_pcr < p_ogg->i_pcr )
p_ogg->i_pcr = p_stream->i_interpolated_pcr;
}
#undef p_stream
+ /* This is for streams where the granulepos of the header packets
+ * don't match these of the data packets (eg. ogg web radios). */
+ if( p_ogg->i_old_pcr == 0 && p_ogg->i_pcr > 3 * DEFAULT_PTS_DELAY * 9/100 )
+ p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_REINIT;
/* Call the pace control */
input_ClockManageRef( p_input, p_input->stream.p_selected_program,