Commit 8cbc8f8d authored by Gildas Bazin's avatar Gildas Bazin

* modules/demux/ogg.c: reworked a bit. Ogg web radios should work again, vorbis audio tracks switching should work better as well.
* modules/mux/ogg.c: attempt at supporting theora.
parent 6001ebac
...@@ -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.33 2003/09/07 22:48:29 fenrir Exp $ * $Id: ogg.c,v 1.34 2003/09/25 23:09:41 gbazin Exp $
* *
* Authors: Gildas Bazin <gbazin@netcourrier.com> * Authors: Gildas Bazin <gbazin@netcourrier.com>
* *
...@@ -66,6 +66,7 @@ typedef struct logical_stream_s ...@@ -66,6 +66,7 @@ typedef struct logical_stream_s
* granulepos */ * granulepos */
mtime_t i_pcr; mtime_t i_pcr;
mtime_t i_interpolated_pcr; mtime_t i_interpolated_pcr;
mtime_t i_previous_pcr;
/* info from logical streams */ /* info from logical streams */
double f_rate; double f_rate;
...@@ -95,7 +96,6 @@ struct demux_sys_t ...@@ -95,7 +96,6 @@ struct demux_sys_t
/* program clock reference (in units of 90kHz) derived from the pcr of /* program clock reference (in units of 90kHz) derived from the pcr of
* the sub-streams */ * the sub-streams */
mtime_t i_pcr; mtime_t i_pcr;
mtime_t i_old_pcr;
int b_seekable; int b_seekable;
int b_reinit; int b_reinit;
...@@ -207,6 +207,11 @@ static int Ogg_StreamStart( input_thread_t *p_input, ...@@ -207,6 +207,11 @@ static int Ogg_StreamStart( input_thread_t *p_input,
int i; int i;
for( i = 0; i < p_stream->i_packets_backup; i++ ) for( i = 0; i < p_stream->i_packets_backup; i++ )
{ {
/* Set correct starting date in the last header packet */
if( i == p_stream->i_packets_backup -1 )
p_stream->p_packets_backup[i].granulepos =
p_stream->i_interpolated_pcr * p_stream->f_rate / 90000;
Ogg_DecodePacket( p_input, p_stream, Ogg_DecodePacket( p_input, p_stream,
&p_stream->p_packets_backup[i] ); &p_stream->p_packets_backup[i] );
} }
...@@ -293,8 +298,7 @@ static int Ogg_ReadPage( input_thread_t *p_input, demux_sys_t *p_ogg, ...@@ -293,8 +298,7 @@ static int Ogg_ReadPage( input_thread_t *p_input, demux_sys_t *p_ogg,
static void Ogg_UpdatePCR( logical_stream_t *p_stream, static void Ogg_UpdatePCR( logical_stream_t *p_stream,
ogg_packet *p_oggpacket ) ogg_packet *p_oggpacket )
{ {
/* Convert the granulepos into a pcr */
/* Convert the next granulepos into a pcr */
if( p_oggpacket->granulepos >= 0 ) if( p_oggpacket->granulepos >= 0 )
{ {
if( p_stream->i_fourcc != VLC_FOURCC( 't','h','e','o' ) ) if( p_stream->i_fourcc != VLC_FOURCC( 't','h','e','o' ) )
...@@ -317,16 +321,14 @@ static void Ogg_UpdatePCR( logical_stream_t *p_stream, ...@@ -317,16 +321,14 @@ static void Ogg_UpdatePCR( logical_stream_t *p_stream,
} }
else 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; p_stream->i_pcr = -1;
/* no granulepos available, try to interpolate the pcr. /* no granulepos available, try to interpolate the pcr.
* If we can't then don't touch the old value. */ * If we can't then don't touch the old value. */
if( p_stream->i_bitrate ) if( p_stream->i_cat == VIDEO_ES )
/* 1 frame per packet */
p_stream->i_interpolated_pcr += (90000 / p_stream->f_rate);
else if( p_stream->i_bitrate )
p_stream->i_interpolated_pcr += ( p_oggpacket->bytes * 90000 p_stream->i_interpolated_pcr += ( p_oggpacket->bytes * 90000
/ p_stream->i_bitrate / 8 ); / p_stream->i_bitrate / 8 );
} }
...@@ -346,9 +348,21 @@ static void Ogg_DecodePacket( input_thread_t *p_input, ...@@ -346,9 +348,21 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
if( p_stream->b_force_backup ) if( p_stream->b_force_backup )
{ {
/* Backup the ogg packet (likely an header packet) */
ogg_packet *p_packet_backup; ogg_packet *p_packet_backup;
p_stream->i_packets_backup++; p_stream->i_packets_backup++;
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;
default:
p_stream->b_force_backup = 0;
break;
}
/* Backup the ogg packet (likely an header packet) */
p_stream->p_packets_backup = p_stream->p_packets_backup =
realloc( p_stream->p_packets_backup, p_stream->i_packets_backup * realloc( p_stream->p_packets_backup, p_stream->i_packets_backup *
sizeof(ogg_packet) ); sizeof(ogg_packet) );
...@@ -357,23 +371,12 @@ static void Ogg_DecodePacket( input_thread_t *p_input, ...@@ -357,23 +371,12 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
&p_stream->p_packets_backup[p_stream->i_packets_backup - 1]; &p_stream->p_packets_backup[p_stream->i_packets_backup - 1];
p_packet_backup->bytes = p_oggpacket->bytes; p_packet_backup->bytes = p_oggpacket->bytes;
if( p_stream->b_force_backup ) p_oggpacket->granulepos = -1;
p_packet_backup->granulepos = p_oggpacket->granulepos; p_packet_backup->granulepos = p_oggpacket->granulepos;
p_packet_backup->packet = malloc( p_oggpacket->bytes ); p_packet_backup->packet = malloc( p_oggpacket->bytes );
if( !p_packet_backup->packet ) return; if( !p_packet_backup->packet ) return;
memcpy( p_packet_backup->packet, p_oggpacket->packet, memcpy( p_packet_backup->packet, p_oggpacket->packet,
p_oggpacket->bytes ); p_oggpacket->bytes );
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;
default:
p_stream->b_force_backup = 0;
break;
}
} }
vlc_mutex_lock( &p_input->stream.control.control_lock ); vlc_mutex_lock( &p_input->stream.control.control_lock );
...@@ -387,6 +390,26 @@ static void Ogg_DecodePacket( input_thread_t *p_input, ...@@ -387,6 +390,26 @@ 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. */
if( p_stream->i_pcr >= 0 )
{
/* This is for streams where the granulepos of the header packets
* doesn't match these of the data packets (eg. ogg web radios). */
if( p_stream->i_previous_pcr == 0 &&
p_stream->i_pcr > 3 * DEFAULT_PTS_DELAY * 9/100 )
p_input->stream.p_selected_program->i_synchro_state =
SYNCHRO_REINIT;
p_stream->i_previous_pcr = p_stream->i_pcr;
/* Call the pace control */
if( p_input->stream.p_selected_program->i_synchro_state ==
SYNCHRO_REINIT )
input_ClockManageRef( p_input,
p_input->stream.p_selected_program,
p_stream->i_pcr );
}
Ogg_UpdatePCR( p_stream, p_oggpacket ); Ogg_UpdatePCR( p_stream, p_oggpacket );
return; return;
...@@ -405,27 +428,67 @@ static void Ogg_DecodePacket( input_thread_t *p_input, ...@@ -405,27 +428,67 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
p_data->p_payload_end = p_data->p_payload_start + p_oggpacket->bytes; p_data->p_payload_end = p_data->p_payload_start + p_oggpacket->bytes;
/* Convert the pcr into a pts */ /* Convert the pcr into a pts */
if( p_stream->i_fourcc == VLC_FOURCC( 'v','o','r','b' ) || if( p_stream->i_fourcc == VLC_FOURCC( 'v','o','r','b' ) )
p_stream->i_fourcc == VLC_FOURCC( 't','h','e','o' ) ) {
if( p_stream->i_pcr >= 0 )
{ {
/* This is for streams where the granulepos of the header packets
* doesn't match these of the data packets (eg. ogg web radios). */
if( p_stream->i_previous_pcr == 0 &&
p_stream->i_pcr > 3 * DEFAULT_PTS_DELAY * 9/100 )
p_input->stream.p_selected_program->i_synchro_state =
SYNCHRO_REINIT;
p_stream->i_previous_pcr = p_stream->i_pcr;
/* Call the pace control */
if( p_input->stream.p_selected_program->i_synchro_state ==
SYNCHRO_REINIT )
input_ClockManageRef( p_input,
p_input->stream.p_selected_program,
p_stream->i_pcr );
}
/* The granulepos is the end date of the sample */
p_pes->i_pts = ( p_stream->i_pcr < 0 ) ? 0 : p_pes->i_pts = ( p_stream->i_pcr < 0 ) ? 0 :
input_ClockGetTS( p_input, p_input->stream.p_selected_program, input_ClockGetTS( p_input, p_input->stream.p_selected_program,
p_stream->i_pcr ); p_stream->i_pcr );
/* Convert the granulepos into the next pcr */
Ogg_UpdatePCR( p_stream, p_oggpacket );
} }
else else
{ {
/* Of course subtitles had to be different! */ /* Convert the granulepos into the current pcr */
p_pes->i_pts = ( p_oggpacket->granulepos < 0 ) ? 0 : Ogg_UpdatePCR( p_stream, p_oggpacket );
input_ClockGetTS( p_input, p_input->stream.p_selected_program,
p_oggpacket->granulepos * 90000 / if( p_stream->i_pcr >= 0 )
p_stream->f_rate ); {
/* This is for streams where the granulepos of the header packets
* doesn't match these of the data packets (eg. ogg web radios). */
if( p_stream->i_previous_pcr == 0 &&
p_stream->i_pcr > 3 * DEFAULT_PTS_DELAY * 9/100 )
p_input->stream.p_selected_program->i_synchro_state =
SYNCHRO_REINIT;
p_stream->i_previous_pcr = p_stream->i_pcr;
/* Call the pace control */
if( p_input->stream.p_selected_program->i_synchro_state ==
SYNCHRO_REINIT )
input_ClockManageRef( p_input,
p_input->stream.p_selected_program,
p_stream->i_pcr );
} }
/* Convert the next granulepos into a pcr */ /* The granulepos is the start date of the sample */
Ogg_UpdatePCR( p_stream, p_oggpacket ); p_pes->i_pts = ( p_stream->i_pcr < 0 ) ? 0 :
input_ClockGetTS( p_input, p_input->stream.p_selected_program,
p_stream->i_pcr );
}
p_pes->i_nb_data = 1; p_pes->i_nb_data = 1;
p_pes->i_dts = p_oggpacket->granulepos; p_pes->i_dts = p_pes->i_pts;
p_pes->p_first = p_pes->p_last = p_data; p_pes->p_first = p_pes->p_last = p_data;
p_pes->i_pes_size = p_oggpacket->bytes; p_pes->i_pes_size = p_oggpacket->bytes;
...@@ -439,7 +502,6 @@ static void Ogg_DecodePacket( input_thread_t *p_input, ...@@ -439,7 +502,6 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
i_header_len++; i_header_len++;
p_pes->i_pes_size -= i_header_len; p_pes->i_pes_size -= i_header_len;
p_pes->i_dts = 0;
} }
if( p_stream->i_fourcc == VLC_FOURCC( 't','a','r','k' ) ) if( p_stream->i_fourcc == VLC_FOURCC( 't','a','r','k' ) )
...@@ -1075,7 +1137,6 @@ static int Activate( vlc_object_t * p_this ) ...@@ -1075,7 +1137,6 @@ static int Activate( vlc_object_t * p_this )
memset( p_ogg, 0, sizeof( demux_sys_t ) ); memset( p_ogg, 0, sizeof( demux_sys_t ) );
p_input->p_demux_data = p_ogg; p_input->p_demux_data = p_ogg;
p_ogg->i_pcr = 0;
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 ) );
...@@ -1090,9 +1151,8 @@ static int Activate( vlc_object_t * p_this ) ...@@ -1090,9 +1151,8 @@ static int Activate( vlc_object_t * p_this )
goto error; goto error;
} }
/* Set the demux function */ /* Set exported function */
p_input->pf_demux = Demux; p_input->pf_demux = Demux;
p_input->pf_demux_control = demux_vaControlDefault;
/* Initialize access plug-in structures. */ /* Initialize access plug-in structures. */
if( p_input->i_mtu == 0 ) if( p_input->i_mtu == 0 )
...@@ -1133,6 +1193,8 @@ static int Activate( vlc_object_t * p_this ) ...@@ -1133,6 +1193,8 @@ static int Activate( vlc_object_t * p_this )
p_stream->p_es->i_fourcc = p_stream->i_fourcc; p_stream->p_es->i_fourcc = p_stream->i_fourcc;
p_stream->p_es->p_waveformatex = (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; p_stream->p_es->p_bitmapinfoheader = (void*)p_stream->p_bih;
p_stream->i_pcr = p_stream->i_previous_pcr = -1;
#undef p_stream #undef p_stream
} }
...@@ -1201,11 +1263,6 @@ static int Activate( vlc_object_t * p_this ) ...@@ -1201,11 +1263,6 @@ static int Activate( vlc_object_t * p_this )
p_input->stream.p_selected_program->b_is_ok = 1; p_input->stream.p_selected_program->b_is_ok = 1;
vlc_mutex_unlock( &p_input->stream.stream_lock ); vlc_mutex_unlock( &p_input->stream.stream_lock );
/* Call the pace control */
input_ClockManageRef( p_input,
p_input->stream.p_selected_program,
p_ogg->i_pcr );
return 0; return 0;
error: error:
...@@ -1258,7 +1315,7 @@ static void Deactivate( vlc_object_t *p_this ) ...@@ -1258,7 +1315,7 @@ static void Deactivate( vlc_object_t *p_this )
*****************************************************************************/ *****************************************************************************/
static int Demux( input_thread_t * p_input ) static int Demux( input_thread_t * p_input )
{ {
int i, i_stream, b_eos = 0; int i, i_stream, b_pcr = 0, b_eos = 0;
ogg_page oggpage; ogg_page oggpage;
ogg_packet oggpacket; ogg_packet oggpacket;
demux_sys_t *p_ogg = (demux_sys_t *)p_input->p_demux_data; demux_sys_t *p_ogg = (demux_sys_t *)p_input->p_demux_data;
...@@ -1318,10 +1375,6 @@ static int Demux( input_thread_t * p_input ) ...@@ -1318,10 +1375,6 @@ static int Demux( input_thread_t * p_input )
{ {
msg_Warn( p_input, "synchro reinit" ); msg_Warn( p_input, "synchro reinit" );
/* An ogg packet does only contain the starting date of the next
* packet, not its own starting date.
* As a quick work around, we just skip an oggpage */
for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ ) for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
{ {
/* we'll trash all the data until we find the next pcr */ /* we'll trash all the data until we find the next pcr */
...@@ -1358,30 +1411,21 @@ static int Demux( input_thread_t * p_input ) ...@@ -1358,30 +1411,21 @@ static int Demux( input_thread_t * p_input )
if( p_stream->b_reinit ) if( p_stream->b_reinit )
{ {
if( oggpacket.granulepos >= 0 ) /* Convert the granulepos into a pcr */
{
p_stream->b_reinit = 0;
/* Convert the next granulepos into a pcr */
Ogg_UpdatePCR( p_stream, &oggpacket ); Ogg_UpdatePCR( p_stream, &oggpacket );
/* Call the pace control to reinitialize if( p_stream->i_pcr >= 0 )
* the system clock */
input_ClockManageRef( p_input,
p_input->stream.p_selected_program,
p_stream->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; p_stream->b_reinit = 0;
}
} }
else continue;
/* An Ogg/vorbis packet contains an end date granulepos */
if( p_stream->i_fourcc == VLC_FOURCC( 'v','o','r','b' ) )
continue; continue;
} }
p_ogg->b_reinit = 0;
Ogg_DecodePacket( p_input, p_stream, &oggpacket ); Ogg_DecodePacket( p_input, p_stream, &oggpacket );
} }
...@@ -1389,7 +1433,6 @@ static int Demux( input_thread_t * p_input ) ...@@ -1389,7 +1433,6 @@ static int Demux( input_thread_t * p_input )
} }
i_stream = 0; i_stream = 0;
p_ogg->i_old_pcr = p_ogg->i_pcr;
p_ogg->i_pcr = p_stream->i_interpolated_pcr; p_ogg->i_pcr = p_stream->i_interpolated_pcr;
for( ; i_stream < p_ogg->i_streams; i_stream++ ) for( ; i_stream < p_ogg->i_streams; i_stream++ )
{ {
...@@ -1399,17 +1442,17 @@ static int Demux( input_thread_t * p_input ) ...@@ -1399,17 +1442,17 @@ static int Demux( input_thread_t * p_input )
if( p_stream->i_interpolated_pcr > 0 if( p_stream->i_interpolated_pcr > 0
&& p_stream->i_interpolated_pcr < p_ogg->i_pcr ) && p_stream->i_interpolated_pcr < p_ogg->i_pcr )
p_ogg->i_pcr = p_stream->i_interpolated_pcr; p_ogg->i_pcr = p_stream->i_interpolated_pcr;
}
#undef p_stream
/* This is for streams where the granulepos of the header packets if( p_stream->i_pcr >= 0 ) b_pcr = VLC_TRUE;
* 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 */ if( b_pcr )
{
input_ClockManageRef( p_input, p_input->stream.p_selected_program, input_ClockManageRef( p_input, p_input->stream.p_selected_program,
p_ogg->i_pcr ); p_ogg->i_pcr );
}
#undef p_stream
/* Did we reach the end of stream ? */ /* Did we reach the end of stream ? */
return( b_eos ? 0 : 1 ); return( b_eos ? 0 : 1 );
......
/***************************************************************************** /*****************************************************************************
* ogg.c * ogg.c: ogg muxer module for vlc
***************************************************************************** *****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN * Copyright (C) 2001, 2002 VideoLAN
* $Id: ogg.c,v 1.8 2003/07/01 17:14:58 sam Exp $ * $Id: ogg.c,v 1.9 2003/09/25 23:09:41 gbazin Exp $
* *
* Authors: Laurent Aimar <fenrir@via.ecp.fr> * Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Gildas Bazin <gbazin@netcourrier.com> * Gildas Bazin <gbazin@netcourrier.com>
...@@ -262,11 +262,16 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) ...@@ -262,11 +262,16 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
p_input->p_fmt->i_height ); p_input->p_fmt->i_height );
break; break;
case VLC_FOURCC( 't', 'h', 'e', 'o' ):
msg_Dbg( p_mux, "theora stream" );
break;
default: default:
FREE( p_input->p_sys ); FREE( p_input->p_sys );
return( VLC_EGENERIC ); return( VLC_EGENERIC );
} }
break; break;
case AUDIO_ES: case AUDIO_ES:
switch( p_input->p_fmt->i_fourcc ) switch( p_input->p_fmt->i_fourcc )
{ {
...@@ -300,6 +305,7 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) ...@@ -300,6 +305,7 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
case VLC_FOURCC( 'v', 'o', 'r', 'b' ): case VLC_FOURCC( 'v', 'o', 'r', 'b' ):
msg_Dbg( p_mux, "vorbis stream" ); msg_Dbg( p_mux, "vorbis stream" );
break; break;
default: default:
FREE( p_input->p_sys ); FREE( p_input->p_sys );
return( VLC_EGENERIC ); return( VLC_EGENERIC );
...@@ -466,7 +472,8 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts ) ...@@ -466,7 +472,8 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
p_stream = (ogg_stream_t*)p_mux->pp_inputs[i]->p_sys; p_stream = (ogg_stream_t*)p_mux->pp_inputs[i]->p_sys;
if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ) if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ||
p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
{ {
/* Special case, headers are already there in the /* Special case, headers are already there in the
* incoming stream */ * incoming stream */
...@@ -504,7 +511,8 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts ) ...@@ -504,7 +511,8 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
p_stream = (ogg_stream_t*)p_mux->pp_inputs[i]->p_sys; p_stream = (ogg_stream_t*)p_mux->pp_inputs[i]->p_sys;
if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ) if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ||
p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
{ {
/* Special case, headers are already there in the incoming stream. /* Special case, headers are already there in the incoming stream.
* We need to gather them an mark them as headers. */ * We need to gather them an mark them as headers. */
...@@ -644,6 +652,11 @@ static int Mux( sout_mux_t *p_mux ) ...@@ -644,6 +652,11 @@ static int Mux( sout_mux_t *p_mux )
} }
else if( p_stream->i_cat == VIDEO_ES ) else if( p_stream->i_cat == VIDEO_ES )
{ {
if( p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
{
op.granulepos = op.packetno; /* FIXME */
}
else
op.granulepos = ( i_dts - p_sys->i_start_dts ) / 1000; op.granulepos = ( i_dts - p_sys->i_start_dts ) / 1000;
} }
......
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