From ec97683ddfee36d958b38c74c39cde9b653412dc Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Sun, 19 Jun 2011 22:06:32 +0000 Subject: [PATCH] fixed positioning in ffmpeg wrapper (thanks to mike_at_nrec for the patch). Added frame positioning feature to laplace demo to test the feature --- modules/highgui/src/cap_ffmpeg.cpp | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/modules/highgui/src/cap_ffmpeg.cpp b/modules/highgui/src/cap_ffmpeg.cpp index f58eeb6..69614d9 100644 --- a/modules/highgui/src/cap_ffmpeg.cpp +++ b/modules/highgui/src/cap_ffmpeg.cpp @@ -505,7 +505,9 @@ bool CvCapture_FFMPEG::open( const char* _filename ) // seek seems to work, so we don't need the filename, // but we still need to seek back to filestart filename=NULL; - av_seek_frame(ic, video_stream, 0, 0); + int64_t ts = video_st->first_dts; + int flags = AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD; + av_seek_frame(ic, video_stream, ts, flags); } exit_func: @@ -621,7 +623,7 @@ double CvCapture_FFMPEG::getProperty( int property_id ) // if( !capture || !video_st || !picture->data[0] ) return 0; if( !video_st ) return 0; - + double frameScale = av_q2d (video_st->time_base) * av_q2d (video_st->r_frame_rate); int64_t timestamp; timestamp = picture_pts; @@ -631,24 +633,23 @@ double CvCapture_FFMPEG::getProperty( int property_id ) 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); if(video_st->cur_dts != AV_NOPTS_VALUE_) - return (((double)video_st->cur_dts-1) *1000.0f * av_q2d (video_st->time_base)); - // return (((double)video_st->cur_dts-1) *1000) / av_q2d (video_st->r_frame_rate); + return ((video_st->cur_dts-video_st->first_dts) * 1000.0 * av_q2d (video_st->time_base)); break; case CV_CAP_PROP_POS_FRAMES: if(video_st->parser && video_st->parser->dts != AV_NOPTS_VALUE_) return (double)video_st->parser->dts-1; if(video_st->cur_dts != AV_NOPTS_VALUE_) - return (double)video_st->cur_dts-1; + return((video_st->cur_dts-video_st->first_dts) * frameScale); break; case CV_CAP_PROP_POS_AVI_RATIO: if(video_st->parser && video_st->parser->dts != AV_NOPTS_VALUE_) return (double)(video_st->parser->dts-1)/(double)video_st->duration; if(video_st->cur_dts != AV_NOPTS_VALUE_ && video_st->duration != AV_NOPTS_VALUE_) - return (double)(video_st->cur_dts-1)/(double)video_st->duration; + return(((video_st->cur_dts-video_st->first_dts)+(1.0/frameScale)) / (double)video_st->duration); break; case CV_CAP_PROP_FRAME_COUNT: if(video_st->duration != AV_NOPTS_VALUE_) - return (double)video_st->duration; + return (double)video_st->duration * frameScale; break; case CV_CAP_PROP_FRAME_WIDTH: return (double)frame.width; @@ -705,25 +706,26 @@ bool CvCapture_FFMPEG::setProperty( int property_id, double value ) case CV_CAP_PROP_POS_FRAMES: case CV_CAP_PROP_POS_AVI_RATIO: { - int64_t timestamp = 0; - AVRational time_base; + int64_t timestamp = ic->streams[video_stream]->first_dts; + AVRational time_base = ic->streams[video_stream]->time_base; + AVRational frame_base = ic->streams[video_stream]->r_frame_rate; + double timeScale = (time_base.den / (double)time_base.num) / (frame_base.num / frame_base.den); switch( property_id ) { case CV_CAP_PROP_POS_FRAMES: - timestamp=(int64_t)value; + timestamp += (int64_t)(value * timeScale); if(ic->start_time != AV_NOPTS_VALUE_) timestamp += ic->start_time; break; case CV_CAP_PROP_POS_MSEC: - time_base=ic->streams[video_stream]->time_base; - timestamp=(int64_t)(value*(float(time_base.den)/float(time_base.num))/1000); + timestamp +=(int64_t)(value*(float(time_base.den)/float(time_base.num))/1000); if(ic->start_time != AV_NOPTS_VALUE_) timestamp += ic->start_time; break; case CV_CAP_PROP_POS_AVI_RATIO: - timestamp=(int64_t)(value*ic->duration); + timestamp += (int64_t)(value*ic->duration); if(ic->start_time != AV_NOPTS_VALUE_ && ic->duration != AV_NOPTS_VALUE_) timestamp += ic->start_time; break; @@ -741,7 +743,10 @@ bool CvCapture_FFMPEG::setProperty( int property_id, double value ) } else { - int ret = av_seek_frame(ic, video_stream, timestamp, 0); + int flags = AVSEEK_FLAG_FRAME; + if (timestamp < ic->streams[video_stream]->cur_dts) + flags |= AVSEEK_FLAG_BACKWARD; + int ret = av_seek_frame(ic, video_stream, timestamp, flags); if (ret < 0) { fprintf(stderr, "HIGHGUI ERROR: AVI: could not seek to position %0.3f\n", -- 2.7.4