diff --git a/modules/highgui/src/cap_ffmpeg_impl.hpp b/modules/highgui/src/cap_ffmpeg_impl.hpp index 8801b5e7b67d7e67354aed076f3287e5f09ad434..8ef2880a278579b52047d5e8cae4f56c86e06928 100644 --- a/modules/highgui/src/cap_ffmpeg_impl.hpp +++ b/modules/highgui/src/cap_ffmpeg_impl.hpp @@ -384,6 +384,7 @@ struct CvCapture_FFMPEG void close(); double getProperty(int); + bool seekKeyAndRunOverFrames(int framenumber); bool setProperty(int, double); bool grabFrame(); bool retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn); @@ -510,6 +511,9 @@ bool CvCapture_FFMPEG::reopen() #ifndef AVSEEK_FLAG_ANY #define AVSEEK_FLAG_ANY 1 #endif +#ifndef SHORTER_DISTANCE_FOR_SEEK_TO_MAKE_IT_FASTER + #define SHORTER_DISTANCE_FOR_SEEK_TO_MAKE_IT_FASTER 25 +#endif bool CvCapture_FFMPEG::open( const char* _filename ) { @@ -724,7 +728,7 @@ double CvCapture_FFMPEG::getProperty( int property_id ) { case CV_FFMPEG_CAP_PROP_POS_MSEC: if(video_st->parser && video_st->parser->dts != AV_NOPTS_VALUE_) - return (((double)video_st->parser->dts-1) *1000.0f) * av_q2d (video_st->time_base); + return (((double)video_st->parser->dts-1) *1000.0) * av_q2d (video_st->time_base); if(video_st->cur_dts != AV_NOPTS_VALUE_) return ((video_st->cur_dts-video_st->first_dts) * 1000.0 * av_q2d (video_st->time_base)); break; @@ -742,7 +746,7 @@ double CvCapture_FFMPEG::getProperty( int property_id ) break; case CV_FFMPEG_CAP_PROP_FRAME_COUNT: if(video_st->duration != AV_NOPTS_VALUE_) - return (double)video_st->duration * frameScale; + return (double)ceil(ic->duration * av_q2d(video_st->r_frame_rate) / AV_TIME_BASE); break; case CV_FFMPEG_CAP_PROP_FRAME_WIDTH: return (double)frame.width; @@ -787,10 +791,36 @@ bool CvCapture_FFMPEG::slowSeek( int framenumber ) return true; } +bool CvCapture_FFMPEG::seekKeyAndRunOverFrames(int framenumber) +{ + int ret; + if (framenumber > video_st->cur_dts-1) { + if (framenumber-(video_st->cur_dts-1) > SHORTER_DISTANCE_FOR_SEEK_TO_MAKE_IT_FASTER) { + ret = av_seek_frame(ic, video_stream, framenumber, 1); + assert(ret >= 0); + if( ret < 0 ) + return false; + } + grabFrame(); + while ((video_st->cur_dts-1) < framenumber) + if ( !grabFrame() ) return false; + } + else if ( framenumber < (video_st->cur_dts-1) ) { + ret=av_seek_frame(ic, video_stream, framenumber, 1); + assert( ret >= 0 ); + if( ret < 0 ) + return false; + grabFrame(); + while ((video_st->cur_dts-1) < framenumber ) + if ( !grabFrame() ) return false; + } + return true; +} bool CvCapture_FFMPEG::setProperty( int property_id, double value ) { if( !video_st ) return false; + int framenumber = 0; switch( property_id ) { @@ -805,21 +835,18 @@ bool CvCapture_FFMPEG::setProperty( int property_id, double value ) switch( property_id ) { case CV_FFMPEG_CAP_PROP_POS_FRAMES: - timestamp += (int64_t)(value * timeScale); - if(ic->start_time != AV_NOPTS_VALUE_) - timestamp += ic->start_time; + framenumber=(int)value; + seekKeyAndRunOverFrames(framenumber); break; case CV_FFMPEG_CAP_PROP_POS_MSEC: - timestamp +=(int64_t)(value*(float(time_base.den)/float(time_base.num))/1000); - if(ic->start_time != AV_NOPTS_VALUE_) - timestamp += ic->start_time; + framenumber=(int)(value/(1000.0f * av_q2d (video_st->time_base))); + seekKeyAndRunOverFrames(framenumber); break; case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO: - timestamp += (int64_t)(value*ic->duration); - if(ic->start_time != AV_NOPTS_VALUE_ && ic->duration != AV_NOPTS_VALUE_) - timestamp += ic->start_time; + framenumber = (int)(value*ic->duration); + seekKeyAndRunOverFrames(framenumber); break; }