diff --git a/include/vlc_es_out.h b/include/vlc_es_out.h index 57fc5c0..a66636a 100644 --- a/include/vlc_es_out.h +++ b/include/vlc_es_out.h @@ -58,6 +58,7 @@ enum es_out_query_e */ ES_OUT_SET_PCR, /* arg1=int64_t i_pcr(microsecond!) (using default group 0)*/ ES_OUT_SET_GROUP_PCR, /* arg1= int i_group, arg2=int64_t i_pcr(microsecond!)*/ + ES_OUT_SET_GROUP_PCR_AND_FT, /* arg1=grabtime, arg2= int i_group, arg3=int64_t i_pcr(microsecond!)*/ ES_OUT_RESET_PCR, /* no arg */ /* Try not to use this one as it is a bit hacky */ diff --git a/include/vlc_mtime.h b/include/vlc_mtime.h index 8d51250..15d626b 100644 --- a/include/vlc_mtime.h +++ b/include/vlc_mtime.h @@ -51,6 +51,8 @@ *****************************************************************************/ #define MSTRTIME_MAX_SIZE 22 +typedef mtime_t (*clock_func_t)(void *); + /***************************************************************************** * Prototypes *****************************************************************************/ @@ -59,6 +61,7 @@ VLC_EXPORT( mtime_t, mdate, ( void ) ); VLC_EXPORT( void, mwait, ( mtime_t date ) ); VLC_EXPORT( void, msleep, ( mtime_t delay ) ); VLC_EXPORT( char *, secstotimestr, ( char *psz_buffer, int32_t secs ) ); +VLC_EXPORT( void, register_clock, ( clock_func_t clock_func, void* arg ) ); # define VLC_HARD_MIN_SLEEP 10000 /* 10 milliseconds = 1 tick at 100Hz */ diff --git a/modules/access/decklink.cpp b/modules/access/decklink.cpp index 99ab7c2..1a4b984 100644 --- a/modules/access/decklink.cpp +++ b/modules/access/decklink.cpp @@ -139,6 +139,15 @@ struct demux_sys_t int i_channels; }; +mtime_t GetDecklinkClock( void *arg ) +{ + IDeckLinkInput *p_input = (IDeckLinkInput *)arg; + + BMDTimeValue hw_time, time_in_frame, ticks_per_frame; + p_input->GetHardwareReferenceClock( CLOCK_FREQ, &hw_time, &time_in_frame, &ticks_per_frame ); + return hw_time; +} + class DeckLinkCaptureDelegate : public IDeckLinkInputCallback { public: @@ -175,12 +184,22 @@ private: demux_t *p_demux_; }; +static const int decimate_factor = 1; + HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* videoFrame, IDeckLinkAudioInputPacket* audioFrame) { + static int dropframeno = 0; + if (decimate_factor > 1 && dropframeno++ % decimate_factor != 0) + return S_OK; + demux_sys_t *p_sys = p_demux_->p_sys; block_t *p_video_frame = NULL; block_t *p_audio_frame = NULL; + BMDTimeValue hw_time, time_in_frame, ticks_per_frame; + p_sys->p_input->GetHardwareReferenceClock( CLOCK_FREQ, &hw_time, &time_in_frame, &ticks_per_frame ); + mtime_t frame_grab_time = hw_time - time_in_frame; + if( videoFrame ) { if( videoFrame->GetFlags() & bmdFrameHasNoInputSource ) @@ -220,7 +239,7 @@ HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame p_sys->i_last_pts = p_video_frame->i_pts; vlc_mutex_unlock( &p_sys->pts_lock ); - es_out_Control( p_demux_->out, ES_OUT_SET_PCR, p_video_frame->i_pts ); + es_out_Control( p_demux_->out, ES_OUT_SET_GROUP_PCR_AND_FT, frame_grab_time, 0, p_video_frame->i_pts ); es_out_Send( p_demux_->out, p_sys->p_video_es, p_video_frame ); } @@ -228,7 +247,7 @@ HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame { const int i_bytes = audioFrame->GetSampleFrameCount() * sizeof(int16_t) * p_sys->i_channels; - p_audio_frame = block_New( p_demux_, i_bytes ); + p_audio_frame = block_New( p_demux_, i_bytes * decimate_factor ); if( !p_audio_frame ) { msg_Err( p_demux_, "Could not allocate memory for audio frame" ); @@ -240,6 +259,7 @@ HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame void *frame_bytes; audioFrame->GetBytes( &frame_bytes ); memcpy( p_audio_frame->p_buffer, frame_bytes, i_bytes ); + memset( p_audio_frame->p_buffer + i_bytes, 0, i_bytes * (decimate_factor - 1) ); BMDTimeValue packet_time; audioFrame->GetPacketTime( &packet_time, CLOCK_FREQ ); @@ -251,6 +271,7 @@ HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame vlc_mutex_unlock( &p_sys->pts_lock ); if( p_audio_frame->i_pts > p_sys->i_last_pts ) + es_out_Control( p_demux_->out, ES_OUT_SET_GROUP_PCR_AND_FT, frame_grab_time, 0, p_audio_frame->i_pts ); es_out_Control( p_demux_->out, ES_OUT_SET_PCR, p_audio_frame->i_pts ); es_out_Send( p_demux_->out, p_sys->p_audio_es, p_audio_frame ); } @@ -336,6 +357,9 @@ static int Open( vlc_object_t *p_this ) msg_Err( p_demux, "Card has no inputs" ); goto finish; } + + /* Use the SDI clock as the master clock. */ + register_clock( GetDecklinkClock, p_sys->p_input ); /* Set up the video and audio sources. */ IDeckLinkConfiguration *p_config; @@ -496,7 +520,7 @@ static int Open( vlc_object_t *p_this ) i_width = p_display_mode->GetWidth(); i_height = p_display_mode->GetHeight(); i_fps_num = time_scale; - i_fps_den = frame_duration; + i_fps_den = frame_duration * decimate_factor; p_sys->i_dominance_flags = i_dominance_flags; } @@ -601,6 +625,8 @@ static void Close( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t *)p_this; demux_sys_t *p_sys = p_demux->p_sys; + + register_clock( NULL, NULL ); if( p_sys->p_input ) { diff --git a/modules/codec/araw.c b/modules/codec/araw.c index c441e82..7d5df0c 100644 --- a/modules/codec/araw.c +++ b/modules/codec/araw.c @@ -364,8 +364,8 @@ static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) return NULL; } - /* Create chunks of max 1024 samples */ - i_samples = __MIN( i_samples, 1024 ); + /* Create chunks of max 960 samples */ + i_samples = __MIN( i_samples, 960 ); p_out = decoder_NewAudioBuffer( p_dec, i_samples ); if( p_out == NULL ) diff --git a/modules/mux/mpeg/ts.c b/modules/mux/mpeg/ts.c index eb0ce12..4c7486f 100644 --- a/modules/mux/mpeg/ts.c +++ b/modules/mux/mpeg/ts.c @@ -1440,7 +1440,7 @@ static int Mux( sout_mux_t *p_mux ) p_pcr_stream->i_pes_dts + p_pcr_stream->i_pes_length ) ) { /* Need more data */ - if( block_FifoCount( p_input->p_fifo ) <= 1 ) + if( block_FifoCount( p_input->p_fifo ) < 1 ) { if( ( p_input->p_fmt->i_cat == AUDIO_ES ) || ( p_input->p_fmt->i_cat == VIDEO_ES ) ) @@ -1491,6 +1491,7 @@ static int Mux( sout_mux_t *p_mux ) else p_data = FixPES( p_mux, p_input->p_fifo ); +#if 0 if( block_FifoCount( p_input->p_fifo ) > 0 && p_input->p_fmt->i_cat != SPU_ES ) { @@ -1498,8 +1499,9 @@ static int Mux( sout_mux_t *p_mux ) p_data->i_length = p_next->i_dts - p_data->i_dts; } else if( p_input->p_fmt->i_codec != - VLC_CODEC_SUBT ) + VLC_CODEC_SUBT && p_data->i_length == 0 ) p_data->i_length = 1000; +#endif if( ( p_pcr_stream->i_pes_dts > 0 && p_data->i_dts - 10000000 > p_pcr_stream->i_pes_dts + diff --git a/modules/packetizer/copy.c b/modules/packetizer/copy.c index dbaa96b..434535f 100644 --- a/modules/packetizer/copy.c +++ b/modules/packetizer/copy.c @@ -140,15 +140,9 @@ static void Close( vlc_object_t *p_this ) static block_t *Packetize ( decoder_t *p_dec, block_t **pp_block ) { block_t *p_block; - block_t *p_ret = p_dec->p_sys->p_block; if( pp_block == NULL || *pp_block == NULL ) return NULL; - if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) - { - block_Release( *pp_block ); - return NULL; - } p_block = *pp_block; *pp_block = NULL; @@ -165,15 +159,10 @@ static block_t *Packetize ( decoder_t *p_dec, block_t **pp_block ) return NULL; } - if( p_ret != NULL && p_block->i_pts > p_ret->i_pts ) - { - p_ret->i_length = p_block->i_pts - p_ret->i_pts; - } - p_dec->p_sys->p_block = p_block; - - if( p_ret && p_dec->p_sys->pf_parse ) - p_dec->p_sys->pf_parse( p_dec, p_ret ); - return p_ret; + if( p_block && p_dec->p_sys->pf_parse ) { + p_dec->p_sys->pf_parse( p_dec, p_block ); +} + return p_block; } /***************************************************************************** diff --git a/src/input/es_out.c b/src/input/es_out.c index 635b2e9..c2bb261 100644 --- a/src/input/es_out.c +++ b/src/input/es_out.c @@ -2294,10 +2294,17 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args ) case ES_OUT_SET_PCR: case ES_OUT_SET_GROUP_PCR: + case ES_OUT_SET_GROUP_PCR_AND_FT: { es_out_pgrm_t *p_pgrm = NULL; int i_group = 0; int64_t i_pcr; + mtime_t i_acquisition_time; + + if( i_query == ES_OUT_SET_GROUP_PCR_AND_FT ) + i_acquisition_time = (mtime_t)va_arg( args, mtime_t ); + else + i_acquisition_time = mdate(); /* Search program */ if( i_query == ES_OUT_SET_PCR ) @@ -2320,14 +2327,13 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args ) msg_Err( p_sys->p_input, "Invalid PCR value in ES_OUT_SET_(GROUP_)PCR !" ); return VLC_EGENERIC; } - - /* TODO do not use mdate() but proper stream acquisition date */ + bool b_late; input_clock_Update( p_pgrm->p_clock, VLC_OBJECT(p_sys->p_input), &b_late, p_sys->p_input->p->b_can_pace_control || p_sys->b_buffering, EsOutIsExtraBufferingAllowed( out ), - i_pcr, mdate() ); + i_pcr, i_acquisition_time ); if( p_pgrm == p_sys->p_pgrm ) { diff --git a/src/input/es_out_timeshift.c b/src/input/es_out_timeshift.c index 3ac19d5..349b4fd 100644 --- a/src/input/es_out_timeshift.c +++ b/src/input/es_out_timeshift.c @@ -101,6 +101,7 @@ typedef struct attribute_packed { int i_int; int64_t i_i64; + int64_t i_i64_second; } int_i64; struct { @@ -594,6 +595,7 @@ static int ControlLocked( es_out_t *p_out, int i_query, va_list args ) case ES_OUT_SET_GROUP: case ES_OUT_SET_PCR: case ES_OUT_SET_GROUP_PCR: + case ES_OUT_SET_GROUP_PCR_AND_FT: case ES_OUT_RESET_PCR: case ES_OUT_SET_NEXT_DISPLAY_TIME: case ES_OUT_SET_GROUP_META: @@ -1328,6 +1330,13 @@ static int CmdInitControl( ts_cmd_t *p_cmd, int i_query, va_list args, bool b_co p_cmd->u.control.u.int_i64.i_int = (int)va_arg( args, int ); p_cmd->u.control.u.int_i64.i_i64 = (int64_t)va_arg( args, int64_t ); break; + + case ES_OUT_SET_GROUP_PCR_AND_FT: /* arg1= int i_group, arg2=int64_t i_pcr(microsecond!)*/ + p_cmd->u.control.u.int_i64.i_i64_second = (int64_t)va_arg( args, int64_t ); + p_cmd->u.control.u.int_i64.i_int = (int)va_arg( args, int ); + p_cmd->u.control.u.int_i64.i_i64 = (int64_t)va_arg( args, int64_t ); + break; + case ES_OUT_SET_ES_SCRAMBLED_STATE: p_cmd->u.control.u.es_bool.p_es = (es_out_id_t*)va_arg( args, es_out_id_t * ); @@ -1469,6 +1478,12 @@ static int CmdExecuteControl( es_out_t *p_out, ts_cmd_t *p_cmd ) return es_out_Control( p_out, i_query, p_cmd->u.control.u.int_i64.i_int, p_cmd->u.control.u.int_i64.i_i64 ); + case ES_OUT_SET_GROUP_PCR_AND_FT: /* arg1= int i_group, arg2=int64_t i_pcr(microsecond!)*/ + return es_out_Control( p_out, i_query, p_cmd->u.control.u.int_i64.i_i64_second, + p_cmd->u.control.u.int_i64.i_int, + p_cmd->u.control.u.int_i64.i_i64 ); + + case ES_OUT_RESET_PCR: /* no arg */ return es_out_Control( p_out, i_query ); diff --git a/src/libvlccore.sym b/src/libvlccore.sym index 6b293c8..6b7d923 100644 --- a/src/libvlccore.sym +++ b/src/libvlccore.sym @@ -370,6 +370,7 @@ playlist_TreeMove playlist_TreeMoveMany playlist_Unlock pl_Get +register_clock resolve_xml_special_chars sdp_AddAttribute sdp_AddMedia diff --git a/src/misc/mtime.c b/src/misc/mtime.c index 115dbe9..ff44b41 100644 --- a/src/misc/mtime.c +++ b/src/misc/mtime.c @@ -186,6 +186,10 @@ static void mtime_init_timebase(void) } #endif +static vlc_mutex_t external_clock_lock = VLC_STATIC_MUTEX; +static clock_func_t external_clock = NULL; +static void *external_clock_arg = NULL; + /** * Return high precision date * @@ -197,6 +201,15 @@ mtime_t mdate( void ) { mtime_t res; + vlc_mutex_lock( &external_clock_lock ); + if( external_clock ) + { + res = (*external_clock)( external_clock_arg ); + vlc_mutex_unlock( &external_clock_lock ); + return res; + } + vlc_mutex_unlock( &external_clock_lock ); + #if defined (HAVE_CLOCK_NANOSLEEP) struct timespec ts; @@ -251,6 +264,14 @@ mtime_t mdate( void ) return res; } +void register_clock( clock_func_t clock_func, void *arg ) +{ + vlc_mutex_lock( &external_clock_lock ); + external_clock = clock_func; + external_clock_arg = arg; + vlc_mutex_unlock( &external_clock_lock ); +} + #undef mwait /** * Wait for a date