Updated ffmpeg implementation (setProperty & getProperty methods)
authorAlexander Reshetnikov <no@email>
Sat, 18 Feb 2012 12:56:00 +0000 (12:56 +0000)
committerAlexander Reshetnikov <no@email>
Sat, 18 Feb 2012 12:56:00 +0000 (12:56 +0000)
modules/highgui/src/cap_ffmpeg_impl.hpp

index 8801b5e..8ef2880 100644 (file)
@@ -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;
             }