* live.cpp : live.com support.
*****************************************************************************
* Copyright (C) 2003 VideoLAN
- * $Id: livedotcom.cpp,v 1.2 2003/11/07 00:28:58 fenrir Exp $
+ * $Id: livedotcom.cpp,v 1.14 2004/01/25 20:05:28 hartman Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
#include <codecs.h> /* BITMAPINFOHEADER, WAVEFORMATEX */
#include <iostream>
+#if defined( WIN32 )
+# include <winsock2.h>
+#endif
+
#include "BasicUsageEnvironment.hh"
#include "GroupsockHelper.hh"
#include "liveMedia.hh"
static int AccessOpen ( vlc_object_t * );
static void AccessClose( vlc_object_t * );
+#define CACHING_TEXT N_("Caching value (ms)")
+#define CACHING_LONGTEXT N_( \
+ "Allows you to modify the default caching value for rtsp streams. This " \
+ "value should be set in miliseconds units." )
+
vlc_module_begin();
set_description( _("live.com (RTSP/RTP/SDP) demuxer" ) );
set_capability( "demux", 50 );
set_callbacks( DemuxOpen, DemuxClose );
add_shortcut( "live" );
- add_category_hint( N_("live-demuxer"), NULL, VLC_TRUE );
- add_bool( "rtsp-tcp", 0, NULL,
- "Use rtp over rtsp(tcp)",
- "Use rtp over rtsp(tcp)", VLC_TRUE );
-
add_submodule();
set_description( _("RTSP/RTP describe") );
add_shortcut( "rtsp" );
+ add_shortcut( "sdp" );
set_capability( "access", 0 );
set_callbacks( AccessOpen, AccessClose );
-
+ add_bool( "rtsp-tcp", 0, NULL,
+ N_("Use rtp over rtsp (tcp)"),
+ N_("Use rtp over rtsp (tcp)"), VLC_TRUE );
+ add_integer( "rtsp-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL,
+ CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
vlc_module_end();
/* TODO:
* - Support PS/TS (need to rework the TS/PS demuxer a lot).
- * - Support X-QT/X-QUICKTIME generic codec.
- * - Handle PTS (for now I just use mdate())
+ * - Support X-QT/X-QUICKTIME generic codec for audio.
*
- * - Check memory leak, delete/free.
+ * - Check memory leak, delete/free -> still one when using rtsp-tcp but I'm
+ * not sure if it comes from me.
*
*/
{
input_thread_t *p_input;
+ vlc_bool_t b_quicktime;
+
es_format_t fmt;
es_out_id_t *p_es;
+ RTPSource *rtpSource;
FramedSource *readSource;
uint8_t buffer[65536];
char waiting;
+
+ mtime_t i_pts;
} live_track_t;
struct demux_sys_t
int i_track;
live_track_t **track; /* XXX mallocated */
+ mtime_t i_pcr;
+ mtime_t i_pcr_start;
+
+ mtime_t i_length;
+ mtime_t i_start;
char event;
};
-static ssize_t Read ( input_thread_t *, byte_t *, size_t );
-static int Demux( input_thread_t * );
+static ssize_t Read ( input_thread_t *, byte_t *, size_t );
+static ssize_t MRLRead( input_thread_t *, byte_t *, size_t );
+
+static int Demux ( input_thread_t * );
+static int Control( input_thread_t *, int, va_list );
+
/*****************************************************************************
vlc_value_t val;
char *psz_url;
- if( p_input->psz_access == NULL || strcasecmp( p_input->psz_access, "rtsp" ) )
+ if( p_input->psz_access == NULL || ( strcasecmp( p_input->psz_access, "rtsp" ) && strcasecmp( p_input->psz_access, "sdp" ) ) )
{
msg_Warn( p_input, "RTSP access discarded" );
return VLC_EGENERIC;
}
- if( ( scheduler = BasicTaskScheduler::createNew() ) == NULL )
- {
- msg_Err( p_input, "BasicTaskScheduler::createNew failed" );
- return VLC_EGENERIC;
- }
- if( ( env = BasicUsageEnvironment::createNew(*scheduler) ) == NULL )
- {
- delete scheduler;
- msg_Err( p_input, "BasicUsageEnvironment::createNew failed" );
- return VLC_EGENERIC;
- }
- if( ( rtsp = RTSPClient::createNew(*env, 1/*verbose*/, "VLC Media Player" ) ) == NULL )
+ if( !strcasecmp( p_input->psz_access, "rtsp" ) )
{
- delete env;
- delete scheduler;
- msg_Err( p_input, "RTSPClient::createNew failed" );
- return VLC_EGENERIC;
- }
+ if( ( scheduler = BasicTaskScheduler::createNew() ) == NULL )
+ {
+ msg_Err( p_input, "BasicTaskScheduler::createNew failed" );
+ return VLC_EGENERIC;
+ }
+ if( ( env = BasicUsageEnvironment::createNew(*scheduler) ) == NULL )
+ {
+ delete scheduler;
+ msg_Err( p_input, "BasicUsageEnvironment::createNew failed" );
+ return VLC_EGENERIC;
+ }
+ if( ( rtsp = RTSPClient::createNew(*env, 1/*verbose*/, "VLC Media Player" ) ) == NULL )
+ {
+ delete env;
+ delete scheduler;
+ msg_Err( p_input, "RTSPClient::createNew failed" );
+ return VLC_EGENERIC;
+ }
- psz_url = (char*)malloc( strlen( p_input->psz_name ) + 8 );
- sprintf( psz_url, "rtsp://%s", p_input->psz_name );
+ psz_url = (char*)malloc( strlen( p_input->psz_name ) + 8 );
+ sprintf( psz_url, "rtsp://%s", p_input->psz_name );
- p_sys = (access_sys_t*)malloc( sizeof( access_sys_t ) );
- p_sys->p_sdp = rtsp->describeURL( psz_url );
+ p_sys = (access_sys_t*)malloc( sizeof( access_sys_t ) );
+ p_sys->p_sdp = rtsp->describeURL( psz_url );
- if( p_sys->p_sdp == NULL )
- {
- msg_Err( p_input, "describeURL failed (%s)", env->getResultMsg() );
+ if( p_sys->p_sdp == NULL )
+ {
+ msg_Err( p_input, "describeURL failed (%s)", env->getResultMsg() );
+ free( psz_url );
+ delete env;
+ delete scheduler;
+ free( p_sys );
+ return VLC_EGENERIC;
+ }
free( psz_url );
- delete env;
- delete scheduler;
- free( p_sys );
- return VLC_EGENERIC;
- }
- free( psz_url );
- p_sys->i_sdp = strlen( p_sys->p_sdp );
- p_sys->i_pos = 0;
+ p_sys->i_sdp = strlen( p_sys->p_sdp );
+ p_sys->i_pos = 0;
- //fprintf( stderr, "sdp=%s\n", p_sys->p_sdp );
+ //fprintf( stderr, "sdp=%s\n", p_sys->p_sdp );
- delete env;
- delete scheduler;
-
- var_Create( p_input, "rtsp-tcp", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
- var_Get( p_input, "rtsp-tcp", &val );
-
- p_input->p_access_data = p_sys;
- p_input->i_mtu = 0;
-
- /* Set exported functions */
- p_input->pf_read = Read;
- p_input->pf_seek = NULL;
- p_input->pf_set_program = input_SetProgram;
- p_input->pf_set_area = NULL;
- p_input->p_private = NULL;
-
- p_input->psz_demux = "live";
-
- /* Finished to set some variable */
- vlc_mutex_lock( &p_input->stream.stream_lock );
- /* FIXME that's not true but eg over tcp, server send data too fast */
- p_input->stream.b_pace_control = val.b_bool;
- p_input->stream.p_selected_area->i_tell = 0;
- p_input->stream.b_seekable = 0;
- p_input->stream.p_selected_area->i_size = 0;
- p_input->stream.i_method = INPUT_METHOD_NETWORK;
- vlc_mutex_unlock( &p_input->stream.stream_lock );
+ delete env;
+ delete scheduler;
- /* Update default_pts to a suitable value for RTSP access */
- p_input->i_pts_delay = 4 * DEFAULT_PTS_DELAY;
- return VLC_SUCCESS;
+ var_Create( p_input, "rtsp-tcp", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
+ var_Get( p_input, "rtsp-tcp", &val );
+
+ p_input->p_access_data = p_sys;
+ p_input->i_mtu = 0;
+
+ /* Set exported functions */
+ p_input->pf_read = Read;
+ p_input->pf_seek = NULL;
+ p_input->pf_set_program = input_SetProgram;
+ p_input->pf_set_area = NULL;
+ p_input->p_private = NULL;
+
+ p_input->psz_demux = "live";
+
+ /* Finished to set some variable */
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ /* FIXME that's not true but eg over tcp, server send data too fast */
+ p_input->stream.b_pace_control = val.b_bool;
+ p_input->stream.p_selected_area->i_tell = 0;
+ p_input->stream.b_seekable = 1; /* Hack to display time */
+ p_input->stream.p_selected_area->i_size = 0;
+ p_input->stream.i_method = INPUT_METHOD_NETWORK;
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ /* Update default_pts to a suitable value for RTSP access */
+ var_Create( p_input, "rtsp-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
+ var_Get( p_input, "rtsp-caching", &val );
+ p_input->i_pts_delay = val.i_int * 1000;
+
+ return VLC_SUCCESS;
+ }
+ else
+ {
+ p_input->p_access_data = (access_sys_t*)0;
+ p_input->i_mtu = 0;
+ p_input->pf_read = MRLRead;
+ p_input->pf_seek = NULL;
+ p_input->pf_set_program = input_SetProgram;
+ p_input->pf_set_area = NULL;
+ p_input->p_private = NULL;
+ p_input->psz_demux = "live";
+ /* Finished to set some variable */
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ p_input->stream.b_pace_control = VLC_TRUE;
+ p_input->stream.p_selected_area->i_tell = 0;
+ p_input->stream.b_seekable = VLC_FALSE;
+ p_input->stream.p_selected_area->i_size = 0;
+ p_input->stream.i_method = INPUT_METHOD_NETWORK;
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ return VLC_SUCCESS;
+ }
}
/*****************************************************************************
{
input_thread_t *p_input = (input_thread_t *)p_this;
access_sys_t *p_sys = p_input->p_access_data;
-
- delete p_sys->p_sdp;
- free( p_sys );
+ if( !strcasecmp( p_input->psz_access, "rtsp" ) )
+ {
+ delete[] p_sys->p_sdp;
+ free( p_sys );
+ }
}
/*****************************************************************************
}
return i_copy;
}
+/*****************************************************************************
+ * MRLRead: read data from the mrl
+ *****************************************************************************/
+static ssize_t MRLRead ( input_thread_t *p_input, byte_t *p_buffer, size_t i_len )
+{
+ int i_done = (int)p_input->p_access_data;
+ int i_copy = __MIN( (int)i_len, (int)strlen(p_input->psz_name) - i_done );
+
+ if( i_copy > 0 )
+ {
+ memcpy( p_buffer, &p_input->psz_name[i_done], i_copy );
+ i_done += i_copy;
+ p_input->p_access_data = (access_sys_t*)i_done;
+ }
+ return i_copy;
+}
/*****************************************************************************
}
p_input->pf_demux = Demux;
- p_input->pf_demux_control = demux_vaControlDefault;
+ p_input->pf_demux_control = Control;
p_input->p_demux_data = p_sys = (demux_sys_t*)malloc( sizeof( demux_sys_t ) );
p_sys->p_sdp = NULL;
p_sys->scheduler = NULL;
p_sys->rtsp = NULL;
p_sys->i_track = 0;
p_sys->track = NULL;
+ p_sys->i_pcr = 0;
+ p_sys->i_pcr_start = 0;
+ p_sys->i_length = 0;
+ p_sys->i_start = 0;
/* Gather the complete sdp file */
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ if( input_InitStream( p_input, 0 ) == -1)
+ {
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ msg_Err( p_input, "cannot init stream" );
+ goto error;
+ }
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
i_sdp = 0;
i_sdp_max = 1000;
p_sdp = (uint8_t*)malloc( i_sdp_max );
{
int fd = sub->rtpSource()->RTPgs()->socketNum();
- msg_Warn( p_input, "RTP subsession '%s/%s'", sub->mediumName(), sub->codecName() );
+ msg_Dbg( p_input, "RTP subsession '%s/%s'", sub->mediumName(), sub->codecName() );
/* Increase the buffer size */
increaseReceiveBufferTo( *p_sys->env, fd, i_buffer );
/* Issue the SETUP */
if( p_sys->rtsp )
{
- p_sys->rtsp->setupMediaSubsession( *sub, False, val.i_int ? True : False );
+ p_sys->rtsp->setupMediaSubsession( *sub, False, val.b_bool ? True : False );
}
}
}
tk = (live_track_t*)malloc( sizeof( live_track_t ) );
tk->p_input = p_input;
tk->waiting = 0;
+ tk->i_pts = 0;
+ tk->b_quicktime = VLC_FALSE;
/* Value taken from mplayer */
if( !strcmp( sub->mediumName(), "audio" ) )
{
es_format_Init( &tk->fmt, AUDIO_ES, VLC_FOURCC( 'u', 'n', 'd', 'f' ) );
tk->fmt.audio.i_channels = sub->numChannels();
- tk->fmt.audio.i_samplerate = sub->rtpSource()->timestampFrequency();
+ tk->fmt.audio.i_rate = sub->rtpSource()->timestampFrequency();
if( !strcmp( sub->codecName(), "MPA" ) ||
!strcmp( sub->codecName(), "MPA-ROBUST" ) ||
!strcmp( sub->codecName(), "X-MP3-DRAFT-00" ) )
{
tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' );
- tk->fmt.audio.i_samplerate = 0;
+ tk->fmt.audio.i_rate = 0;
}
else if( !strcmp( sub->codecName(), "AC3" ) )
{
tk->fmt.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' );
- tk->fmt.audio.i_samplerate = 0;
+ tk->fmt.audio.i_rate = 0;
}
else if( !strcmp( sub->codecName(), "L16" ) )
{
if( ( p_extra = parseStreamMuxConfigStr( sub->fmtp_config(), i_extra ) ) )
{
- tk->fmt.i_extra_type = ES_EXTRA_TYPE_WAVEFORMATEX;
tk->fmt.i_extra = i_extra;
tk->fmt.p_extra = malloc( sizeof( i_extra ) );
memcpy( tk->fmt.p_extra, p_extra, i_extra );
- delete p_extra;
+ delete[] p_extra;
}
}
else if( !strcmp( sub->codecName(), "MPEG4-GENERIC" ) )
if( ( p_extra = parseGeneralConfigStr( sub->fmtp_config(), i_extra ) ) )
{
- tk->fmt.i_extra_type = ES_EXTRA_TYPE_WAVEFORMATEX;
tk->fmt.i_extra = i_extra;
tk->fmt.p_extra = malloc( i_extra );
memcpy( tk->fmt.p_extra, p_extra, i_extra );
- delete p_extra;
+ delete[] p_extra;
}
}
}
}
else if( !strcmp( sub->codecName(), "JPEG" ) )
{
- tk->fmt.i_codec = VLC_FOURCC( 'J', 'P', 'E', 'G' );
+ tk->fmt.i_codec = VLC_FOURCC( 'M', 'J', 'P', 'G' );
}
else if( !strcmp( sub->codecName(), "MP4V-ES" ) )
{
if( ( p_extra = parseGeneralConfigStr( sub->fmtp_config(), i_extra ) ) )
{
- tk->fmt.i_extra_type = ES_EXTRA_TYPE_BITMAPINFOHEADER;
tk->fmt.i_extra = i_extra;
tk->fmt.p_extra = malloc( i_extra );
memcpy( tk->fmt.p_extra, p_extra, i_extra );
- delete p_extra;
+ delete[] p_extra;
}
}
+ else if( !strcmp( sub->codecName(), "X-QT" ) || !strcmp( sub->codecName(), "X-QUICKTIME" ) )
+ {
+ tk->b_quicktime = VLC_TRUE;
+ }
}
if( tk->fmt.i_codec != VLC_FOURCC( 'u', 'n', 'd', 'f' ) )
{
tk->p_es = es_out_Add( p_input->p_es_out, &tk->fmt );
}
+ else
+ {
+ tk->p_es = NULL;
+ }
- if( tk->p_es )
+ if( tk->p_es || tk->b_quicktime )
{
- TAB_APPEND( p_sys->i_track, (void**)p_sys->track, (void*)tk );
+ TAB_APPEND( p_sys->i_track, p_sys->track, tk );
tk->readSource = sub->readSource();
+ tk->rtpSource = sub->rtpSource();
}
else
{
}
}
-
delete iter;
+ p_sys->i_length = (mtime_t)(p_sys->ms->playEndTime() * 1000000.0);
+ if( p_sys->i_length < 0 )
+ {
+ p_sys->i_length = 0;
+ }
+ else if( p_sys->i_length > 0 )
+ {
+ p_input->stream.p_selected_area->i_size = 1000; /* needed for now */
+ }
+
+ if( p_sys->i_track <= 0 )
+ {
+ msg_Err( p_input, "no codec supported, aborting" );
+ goto error;
+ }
+
return VLC_SUCCESS;
error:
free( p_sys->track );
}
- if( p_sys->rtsp )
+ if( p_sys->rtsp && p_sys->ms )
{
/* TEARDOWN */
- MediaSubsessionIterator iter(*p_sys->ms);
- MediaSubsession *sub;
-
- while( ( sub = iter.next() ) != NULL )
- {
- p_sys->rtsp->teardownMediaSubsession(*sub);
- }
+ p_sys->rtsp->teardownMediaSession( *p_sys->ms );
}
Medium::close( p_sys->ms );
if( p_sys->rtsp )
demux_sys_t *p_sys = p_input->p_demux_data;
TaskToken task;
+ mtime_t i_pcr = 0;
int i;
+ for( i = 0; i < p_sys->i_track; i++ )
+ {
+ live_track_t *tk = p_sys->track[i];
+
+ if( i_pcr == 0 )
+ {
+ i_pcr = tk->i_pts;
+ }
+ else if( tk->i_pts != 0 && i_pcr > tk->i_pts )
+ {
+ i_pcr = tk->i_pts ;
+ }
+ }
+ if( i_pcr != p_sys->i_pcr && i_pcr > 0 )
+ {
+ input_ClockManageRef( p_input,
+ p_input->stream.p_selected_program,
+ i_pcr * 9 / 100 );
+ p_sys->i_pcr = i_pcr;
+ if( p_sys->i_pcr_start <= 0 || p_sys->i_pcr_start > i_pcr )
+ {
+ p_sys->i_pcr_start = i_pcr;
+ }
+ }
+
/* First warm we want to read data */
p_sys->event = 0;
for( i = 0; i < p_sys->i_track; i++ )
return p_input->b_error ? 0 : 1;
}
+static int Control( input_thread_t *p_input, int i_query, va_list args )
+{
+ demux_sys_t *p_sys = p_input->p_demux_data;
+ int64_t *pi64;
+ double *pf, f;
+
+ switch( i_query )
+ {
+ case DEMUX_GET_TIME:
+ pi64 = (int64_t*)va_arg( args, int64_t * );
+ *pi64 = p_sys->i_pcr - p_sys->i_pcr_start + p_sys->i_start;
+ return VLC_SUCCESS;
+
+ case DEMUX_GET_LENGTH:
+ pi64 = (int64_t*)va_arg( args, int64_t * );
+ *pi64 = p_sys->i_length;
+ return VLC_SUCCESS;
+
+ case DEMUX_GET_POSITION:
+ pf = (double*)va_arg( args, double* );
+ if( p_sys->i_length > 0 )
+ {
+ *pf = (double)( p_sys->i_pcr - p_sys->i_pcr_start + p_sys->i_start)/
+ (double)(p_sys->i_length);
+ }
+ else
+ {
+ *pf = 0;
+ }
+ return VLC_SUCCESS;
+
+ case DEMUX_SET_POSITION:
+ {
+ float time;
+
+ f = (double)va_arg( args, double );
+ time = f * (double)p_sys->i_length / 1000000.0; /* in second */
+
+ if( p_sys->rtsp && p_sys->i_length > 0 )
+ {
+ MediaSubsessionIterator *iter = new MediaSubsessionIterator( *p_sys->ms );
+ MediaSubsession *sub;
+ int i;
+
+ while( ( sub = iter->next() ) != NULL )
+ {
+ p_sys->rtsp->playMediaSubsession( *sub, time );
+ }
+ delete iter;
+ p_sys->i_start = (mtime_t)(f * (double)p_sys->i_length);
+ p_sys->i_pcr_start = 0;
+ p_sys->i_pcr = 0;
+ for( i = 0; i < p_sys->i_track; i++ )
+ {
+ p_sys->track[i]->i_pts = 0;
+ }
+ return VLC_SUCCESS;
+ }
+ return VLC_EGENERIC;
+ }
+ default:
+ return demux_vaControlDefault( p_input, i_query, args );
+ }
+}
/*****************************************************************************
*
live_track_t *tk = (live_track_t*)p_private;
input_thread_t *p_input = tk->p_input;
demux_sys_t *p_sys = p_input->p_demux_data;
- pes_packet_t *p_pes;
- data_packet_t *p_data;
+ block_t *p_block;
+
+ mtime_t i_pts = (mtime_t)pts.tv_sec * 1000000LL + (mtime_t)pts.tv_usec;
+
+ if( tk->b_quicktime && tk->p_es == NULL )
+ {
+ QuickTimeGenericRTPSource *qtRTPSource = (QuickTimeGenericRTPSource*)tk->rtpSource;
+ QuickTimeGenericRTPSource::QTState &qtState = qtRTPSource->qtState;
+ uint8_t *sdAtom = (uint8_t*)&qtState.sdAtom[4];
+
+ if( qtState.sdAtomSize < 16 + 32 )
+ {
+ /* invalid */
+ p_sys->event = 0xff;
+ tk->waiting = 0;
+ return;
+ }
+ tk->fmt.i_codec = VLC_FOURCC( sdAtom[0], sdAtom[1], sdAtom[2], sdAtom[3] );
+ tk->fmt.video.i_width = (sdAtom[28] << 8) | sdAtom[29];
+ tk->fmt.video.i_height = (sdAtom[30] << 8) | sdAtom[31];
+
+ tk->fmt.i_extra = qtState.sdAtomSize - 16;
+ tk->fmt.p_extra = malloc( tk->fmt.i_extra );
+ memcpy( tk->fmt.p_extra, &sdAtom[12], tk->fmt.i_extra );
+
+ tk->p_es = es_out_Add( p_input->p_es_out, &tk->fmt );
+ }
#if 0
fprintf( stderr, "StreamRead size=%d pts=%lld\n",
i_size,
pts.tv_sec * 1000000LL + pts.tv_usec );
#endif
- /* Create a PES */
- if( ( p_pes = input_NewPES( p_input->p_method_data ) ) == NULL )
+ if( i_size > 65536 )
{
- return;
+ msg_Warn( p_input, "buffer overflow" );
}
/* FIXME could i_size be > buffer size ? */
- p_data = input_NewPacket( p_input->p_method_data, i_size );
+ p_block = block_New( p_input, i_size );
- memcpy( p_data->p_payload_start, tk->buffer, i_size );
- p_data->p_payload_end = p_data->p_payload_start + i_size;
+ memcpy( p_block->p_buffer, tk->buffer, i_size );
+ //p_block->i_rate = p_input->stream.control.i_rate;
- p_pes->p_first = p_pes->p_last = p_data;
- p_pes->i_nb_data = 1;
- p_pes->i_pes_size = i_size;
+ if( i_pts != tk->i_pts )
+ {
+ p_block->i_dts =
+ p_block->i_pts = input_ClockGetTS( p_input,
+ p_input->stream.p_selected_program,
+ i_pts * 9 / 100 );
+ }
+ else
+ {
+ p_block->i_dts = 0;
+ p_block->i_pts = 0;
+ }
+ //fprintf( stderr, "tk -> dpts=%lld\n", i_pts - tk->i_pts );
- /* FIXME */
- p_pes->i_pts = mdate() + p_input->i_pts_delay;
- p_pes->i_dts = mdate() + p_input->i_pts_delay;
- es_out_Send( p_input->p_es_out, tk->p_es, p_pes );
+ es_out_Send( p_input->p_es_out, tk->p_es, p_block );
/* warm that's ok */
p_sys->event = 0xff;
/* we have read data */
tk->waiting = 0;
+
+ if( i_pts > 0 )
+ {
+ tk->i_pts = i_pts;
+ }
}
/*****************************************************************************