Commit 4b8e273c authored by Gildas Bazin's avatar Gildas Bazin

* modules/demux/ogg.c: better handling of PCRs (we now base our calculations
   on all sub-streams instead of just using one of them). Some code factorisation
   too.
parent 691e4704
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* ogg.c : ogg stream input module for vlc * ogg.c : ogg stream input module for vlc
***************************************************************************** *****************************************************************************
* Copyright (C) 2001 VideoLAN * Copyright (C) 2001 VideoLAN
* $Id: ogg.c,v 1.10 2002/11/20 14:09:57 gbazin Exp $ * $Id: ogg.c,v 1.11 2002/11/21 09:39:39 gbazin Exp $
* *
* Authors: Gildas Bazin <gbazin@netcourrier.com> * Authors: Gildas Bazin <gbazin@netcourrier.com>
* *
...@@ -65,7 +65,7 @@ typedef struct logical_stream_s ...@@ -65,7 +65,7 @@ typedef struct logical_stream_s
/* program clock reference (in units of 90kHz) derived from the previous /* program clock reference (in units of 90kHz) derived from the previous
* granulepos */ * granulepos */
mtime_t i_pcr; mtime_t i_pcr;
mtime_t i_last_received_pcr; mtime_t i_interpolated_pcr;
/* info from logical streams */ /* info from logical streams */
double f_rate; double f_rate;
...@@ -91,15 +91,13 @@ struct demux_sys_t ...@@ -91,15 +91,13 @@ struct demux_sys_t
logical_stream_t *p_stream_audio; logical_stream_t *p_stream_audio;
logical_stream_t *p_stream_spu; logical_stream_t *p_stream_spu;
/* stream we use as a time reference for demux reading speed */
logical_stream_t *p_stream_timeref;
/* program clock reference (in units of 90kHz) derived from the pcr of /* program clock reference (in units of 90kHz) derived from the pcr of
* one of the sub-streams (p_stream_timeref) */ * the sub-streams */
mtime_t i_pcr; mtime_t i_pcr;
mtime_t i_length; mtime_t i_length;
int b_seekable; int b_seekable;
int b_reinit;
}; };
/* OggDS headers for the new header format (used in ogm files) */ /* OggDS headers for the new header format (used in ogm files) */
...@@ -176,9 +174,9 @@ static void Ogg_StreamStop ( input_thread_t *, demux_sys_t *, int ); ...@@ -176,9 +174,9 @@ static void Ogg_StreamStop ( input_thread_t *, demux_sys_t *, int );
/* Bitstream manipulation */ /* Bitstream manipulation */
static int Ogg_Check ( input_thread_t *p_input ); static int Ogg_Check ( input_thread_t *p_input );
static int Ogg_ReadPage ( input_thread_t *, demux_sys_t *, ogg_page * ); static int Ogg_ReadPage ( input_thread_t *, demux_sys_t *, ogg_page * );
static void Ogg_UpdatePCR ( logical_stream_t *, ogg_packet * );
static void Ogg_DecodePacket ( input_thread_t *p_input, static void Ogg_DecodePacket ( input_thread_t *p_input,
logical_stream_t *p_stream, logical_stream_t *p_stream, ogg_packet * );
ogg_packet *p_oggpacket );
static int Ogg_FindLogicalStreams( input_thread_t *p_input, static int Ogg_FindLogicalStreams( input_thread_t *p_input,
demux_sys_t *p_ogg ); demux_sys_t *p_ogg );
...@@ -303,6 +301,53 @@ static int Ogg_ReadPage( input_thread_t *p_input, demux_sys_t *p_ogg, ...@@ -303,6 +301,53 @@ static int Ogg_ReadPage( input_thread_t *p_input, demux_sys_t *p_ogg,
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/****************************************************************************
* Ogg_UpdatePCR: update the PCR (90kHz program clock reference) for the
* current stream.
****************************************************************************/
static void Ogg_UpdatePCR( logical_stream_t *p_stream,
ogg_packet *p_oggpacket )
{
/* Convert the next granulepos into a pcr */
if( p_oggpacket->granulepos >= 0 )
{
if( p_stream->i_fourcc != VLC_FOURCC( 't','h','e','o' ) )
{
p_stream->i_pcr = p_oggpacket->granulepos * 90000
/ p_stream->f_rate;
}
else
{
ogg_int64_t iframe = p_oggpacket->granulepos >>
p_stream->i_theora_keyframe_granule_shift;
ogg_int64_t pframe = p_oggpacket->granulepos -
( iframe << p_stream->i_theora_keyframe_granule_shift );
p_stream->i_pcr = ( iframe + pframe ) * 90000
/ p_stream->f_rate;
}
p_stream->i_interpolated_pcr = p_stream->i_pcr;
}
else
{
/* FIXME: ffmpeg doesn't like null pts */
if( p_stream->i_cat == VIDEO_ES )
/* 1 frame per packet */
p_stream->i_pcr += (90000 / p_stream->f_rate);
else
p_stream->i_pcr = -1;
/* no granulepos available, try to interpolate the pcr */
if( p_stream->i_bitrate )
p_stream->i_interpolated_pcr += ( p_oggpacket->bytes * 90000
/ p_stream->i_bitrate / 8 );
else
p_stream->i_interpolated_pcr = -1;
}
}
/**************************************************************************** /****************************************************************************
* Ogg_DecodePacket: Decode an Ogg packet. * Ogg_DecodePacket: Decode an Ogg packet.
****************************************************************************/ ****************************************************************************/
...@@ -312,7 +357,7 @@ static void Ogg_DecodePacket( input_thread_t *p_input, ...@@ -312,7 +357,7 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
{ {
pes_packet_t *p_pes; pes_packet_t *p_pes;
data_packet_t *p_data; data_packet_t *p_data;
demux_sys_t *p_ogg = p_input->p_demux_data; //demux_sys_t *p_ogg = p_input->p_demux_data;
int i_header_len = 0; int i_header_len = 0;
if( p_stream->b_force_backup ) if( p_stream->b_force_backup )
...@@ -350,46 +395,7 @@ static void Ogg_DecodePacket( input_thread_t *p_input, ...@@ -350,46 +395,7 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
{ {
/* This stream isn't currently selected so we don't need to decode it, /* This stream isn't currently selected so we don't need to decode it,
* but we do need to store its pcr as it might be selected later on. */ * but we do need to store its pcr as it might be selected later on. */
Ogg_UpdatePCR( p_stream, p_oggpacket );
/* Convert the next granulepos into a pcr */
if( p_oggpacket->granulepos >= 0 )
{
if( p_stream->i_fourcc != VLC_FOURCC( 't','h','e','o' ) )
{
p_stream->i_pcr = p_oggpacket->granulepos * 90000
/ p_stream->f_rate;
}
else
{
ogg_int64_t iframe = p_oggpacket->granulepos >>
p_stream->i_theora_keyframe_granule_shift;
ogg_int64_t pframe = p_oggpacket->granulepos -
( iframe << p_stream->i_theora_keyframe_granule_shift );
p_stream->i_pcr = ( iframe + pframe ) * 90000
/ p_stream->f_rate;
}
p_stream->i_last_received_pcr = p_stream->i_pcr;
}
else
{
/* no granulepos available, try to interpolate */
if( p_stream->i_bitrate )
p_stream->i_pcr += ( p_oggpacket->bytes * 90000
/ p_stream->i_bitrate / 8 );
else
p_stream->i_pcr = -1;
}
/* Update the main pcr */
if( p_stream == p_ogg->p_stream_timeref )
{
if( p_ogg->p_stream_timeref->i_pcr >= 0 )
{
p_ogg->i_pcr = p_ogg->p_stream_timeref->i_pcr;
}
}
return; return;
} }
...@@ -422,50 +428,7 @@ static void Ogg_DecodePacket( input_thread_t *p_input, ...@@ -422,50 +428,7 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
} }
/* Convert the next granulepos into a pcr */ /* Convert the next granulepos into a pcr */
if( p_oggpacket->granulepos >= 0 ) Ogg_UpdatePCR( p_stream, p_oggpacket );
{
if( p_stream->i_fourcc != VLC_FOURCC( 't','h','e','o' ) )
{
p_stream->i_pcr = p_oggpacket->granulepos * 90000
/ p_stream->f_rate;
}
else
{
ogg_int64_t iframe = p_oggpacket->granulepos >>
p_stream->i_theora_keyframe_granule_shift;
ogg_int64_t pframe = p_oggpacket->granulepos -
( iframe << p_stream->i_theora_keyframe_granule_shift );
p_stream->i_pcr = ( iframe + pframe ) * 90000 / p_stream->f_rate;
}
p_stream->i_last_received_pcr = p_stream->i_pcr;
}
else
{
/* FIXME: ffmpeg doesn't like null pts */
if( p_stream->i_cat == VIDEO_ES )
/* 1 frame per packet */
p_stream->i_pcr += (90000 / p_stream->f_rate);
else
p_stream->i_pcr = -1;
}
/* Update the main pcr */
if( p_stream == p_ogg->p_stream_timeref )
{
if( p_ogg->p_stream_timeref->i_pcr >= 0 )
{
p_ogg->i_pcr = p_ogg->p_stream_timeref->i_pcr;
}
else
{
/* no granulepos available, try to interpolate */
if( p_stream->i_bitrate )
p_ogg->i_pcr += ( p_oggpacket->bytes * 90000
/ p_stream->i_bitrate / 8 );
}
}
p_pes->i_nb_data = 1; p_pes->i_nb_data = 1;
p_pes->i_dts = p_oggpacket->granulepos; p_pes->i_dts = p_oggpacket->granulepos;
...@@ -542,10 +505,6 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg) ...@@ -542,10 +505,6 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
p_stream->i_serial_no = ogg_page_serialno( &oggpage ); p_stream->i_serial_no = ogg_page_serialno( &oggpage );
ogg_stream_init( &p_stream->os, p_stream->i_serial_no ); ogg_stream_init( &p_stream->os, p_stream->i_serial_no );
/* The first stream we find is our timeref (might be changed
* later on) */
p_ogg->p_stream_timeref = p_stream;
/* Extract the initial header from the first page and verify /* Extract the initial header from the first page and verify
* the codec type of tis Ogg bitstream */ * the codec type of tis Ogg bitstream */
if( ogg_stream_pagein( &p_stream->os, &oggpage ) < 0 ) if( ogg_stream_pagein( &p_stream->os, &oggpage ) < 0 )
...@@ -863,7 +822,6 @@ static int Activate( vlc_object_t * p_this ) ...@@ -863,7 +822,6 @@ static int Activate( vlc_object_t * p_this )
p_input->p_demux_data = p_ogg; p_input->p_demux_data = p_ogg;
p_ogg->i_pcr = 0; p_ogg->i_pcr = 0;
p_ogg->p_stream_timeref = NULL;
p_ogg->b_seekable = ( ( p_input->stream.b_seekable ) p_ogg->b_seekable = ( ( p_input->stream.b_seekable )
&&( p_input->stream.i_method == INPUT_METHOD_FILE ) ); &&( p_input->stream.i_method == INPUT_METHOD_FILE ) );
...@@ -946,7 +904,6 @@ static int Activate( vlc_object_t * p_this ) ...@@ -946,7 +904,6 @@ static int Activate( vlc_object_t * p_this )
p_ogg->pp_stream[i_audio]->p_es->i_cat != AUDIO_ES ) p_ogg->pp_stream[i_audio]->p_es->i_cat != AUDIO_ES )
{ {
p_ogg->p_stream_audio = p_stream; p_ogg->p_stream_audio = p_stream;
p_ogg->p_stream_timeref = p_stream;
Ogg_StreamStart( p_input, p_ogg, i_stream ); Ogg_StreamStart( p_input, p_ogg, i_stream );
} }
} }
...@@ -1097,7 +1054,6 @@ static int Demux( input_thread_t * p_input ) ...@@ -1097,7 +1054,6 @@ static int Demux( input_thread_t * p_input )
&&( p_stream->p_es->p_decoder_fifo ) ) &&( p_stream->p_es->p_decoder_fifo ) )
{ {
p_ogg->p_stream_audio = p_stream; p_ogg->p_stream_audio = p_stream;
p_ogg->p_stream_timeref = p_stream;
break; break;
} }
} }
...@@ -1115,16 +1071,17 @@ static int Demux( input_thread_t * p_input ) ...@@ -1115,16 +1071,17 @@ static int Demux( input_thread_t * p_input )
{ {
/* we'll trash all the data until we find the next pcr */ /* we'll trash all the data until we find the next pcr */
p_stream->b_reinit = 1; p_stream->b_reinit = 1;
p_ogg->i_pcr = 0; p_stream->i_pcr = -1;
p_stream->i_interpolated_pcr = -1;
} }
p_ogg->b_reinit = 1;
} }
/* /*
* Demux ogg pages from the stream * Demux ogg pages from the stream
*/ */
for( i = 0; (i < PAGES_READ_ONCE) || p_ogg->p_stream_timeref->b_reinit; for( i = 0; i < PAGES_READ_ONCE || p_ogg->b_reinit; i++ )
i++ )
{ {
if( Ogg_ReadPage( p_input, p_ogg, &oggpage ) != VLC_SUCCESS ) if( Ogg_ReadPage( p_input, p_ogg, &oggpage ) != VLC_SUCCESS )
{ {
...@@ -1149,19 +1106,23 @@ static int Demux( input_thread_t * p_input ) ...@@ -1149,19 +1106,23 @@ static int Demux( input_thread_t * p_input )
if( oggpacket.granulepos >= 0 ) if( oggpacket.granulepos >= 0 )
{ {
p_stream->b_reinit = 0; p_stream->b_reinit = 0;
p_stream->i_pcr = oggpacket.granulepos
* 90000 / p_stream->f_rate;
if( !p_ogg->i_pcr || /* Convert the next granulepos into a pcr */
(p_stream == p_ogg->p_stream_timeref) ) Ogg_UpdatePCR( p_stream, &oggpacket );
{
/* Call the pace control to reinitialize /* Call the pace control to reinitialize
* the system clock */ * the system clock */
p_ogg->i_pcr = p_stream->i_pcr; input_ClockManageRef( p_input,
input_ClockManageRef( p_input, p_input->stream.p_selected_program,
p_input->stream.p_selected_program, p_stream->i_pcr );
p_ogg->i_pcr );
} if( (!p_ogg->p_stream_video ||
!p_ogg->p_stream_video->b_reinit) &&
(!p_ogg->p_stream_audio ||
!p_ogg->p_stream_audio->b_reinit) )
{
p_ogg->b_reinit = 0;
}
} }
continue; continue;
} }
...@@ -1170,13 +1131,24 @@ static int Demux( input_thread_t * p_input ) ...@@ -1170,13 +1131,24 @@ static int Demux( input_thread_t * p_input )
} }
} }
#undef p_stream
} }
p_ogg->i_pcr = INT_MAX;
for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ )
{
if( p_stream->i_cat == SPU_ES )
continue;
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
/* Call the pace control */ /* Call the pace control */
if( !b_eos ) input_ClockManageRef( p_input, input_ClockManageRef( p_input, p_input->stream.p_selected_program,
p_input->stream.p_selected_program, p_ogg->i_pcr );
p_ogg->i_pcr );
/* Did we reach the end of stream ? */ /* Did we reach the end of stream ? */
return( b_eos ? 0 : 1 ); return( b_eos ? 0 : 1 );
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment