libcvd-members
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libcvd-members] libcvd/cvd_src videofilebuffer.cc


From: Colin Starr
Subject: [libcvd-members] libcvd/cvd_src videofilebuffer.cc
Date: Mon, 26 Mar 2007 17:20:23 +0000

CVSROOT:        /cvsroot/libcvd
Module name:    libcvd
Changes by:     Colin Starr <ccs36>     07/03/26 17:20:23

Modified files:
        cvd_src        : videofilebuffer.cc 

Log message:
        Previous seek_to would only work when seeking to keyframes. This 
version correctly seeks to all frames.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/libcvd/cvd_src/videofilebuffer.cc?cvsroot=libcvd&r1=1.12&r2=1.13

Patches:
Index: videofilebuffer.cc
===================================================================
RCS file: /cvsroot/libcvd/libcvd/cvd_src/videofilebuffer.cc,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -b -r1.12 -r1.13
--- videofilebuffer.cc  24 May 2006 13:09:18 -0000      1.12
+++ videofilebuffer.cc  26 Mar 2007 17:20:23 -0000      1.13
@@ -365,10 +365,28 @@
 //
 void RawVideoFileBuffer::seek_to(double t)
 {      
+       // The call to av_seek_frame only searches to the nearest keyframe. To 
continue from there, we
+       // must decode and read one frame at a time until we get to the desired 
point.
+
+       // Hack: I do not know how to obtain the current frame number or 
timestamp after the call to 
+       // av_seek_frame without performing another read_frame. This will 
obviously read one extra frame.
+       // So we must subtract one frame from the position we are actually 
searching for.
+       // t is defined as frame_number * frame_rate.
+
+       double frame_rate = 
av_q2d(pFormatContext->streams[video_stream]->r_frame_rate);
+       int frame_num = static_cast<int>(t * frame_rate + 0.5);
+       t = (frame_num - 1) / frame_rate;
+
+       int64_t targetPts = static_cast<int64_t>(t * AV_TIME_BASE + 0.5);
+       // Handling the case where t == 0.
+       int64_t seekToPts = targetPts < 0 ? 0 : targetPts;
+
        #if LIBAVFORMAT_BUILD >= 4623
-       if(av_seek_frame(pFormatContext, -1, 
static_cast<int64_t>(t*AV_TIME_BASE+0.5), AVSEEK_FLAG_ANY) < 0)
+       // The flag AVSEEK_FLAG_ANY will seek to the specified frame, but we 
cannot decode from there because
+       // we do not have the info from the previous frames and keyframe, hence 
the BACKWARD flag.
+       if (av_seek_frame(pFormatContext, -1, seekToPts, AVSEEK_FLAG_BACKWARD) 
< 0)
        #else
-       if(av_seek_frame(pFormatContext, -1, 
static_cast<int64_t>(t*AV_TIME_BASE+0.5)) < 0)
+       if (av_seek_frame(pFormatContext, -1, seekToPts < 0)
        #endif
        {
                cerr << "av_seek_frame not supported by this codec: performing 
(slow) manual seek" << endl;
@@ -414,19 +432,43 @@
                start_time = 0;
                frame_ready = true;
                
+               puts("done");
+
                // REOPENED FILE OK
-               // Now read frames until we get to the time we want
+       }
                
-               int frames = static_cast<int>((t * frames_per_second() + 0.5));
-               for(int i = 0; i < frames; i++)
-               {
+       // Special case
+       if (targetPts < 0) {
                        read_next_frame();
+         return;
                }
-       }
        
-       if(!read_next_frame())
-                       throw BadSeek(t);
+       // Now read frames until we get to the time we want
+
+       AVPacket packet;
+       int gotFrame;
+       int64_t pts;          
+             
+       // Decode frame by frame until we reach the desired point.
+       do {
+               av_read_frame(pFormatContext, &packet);
+               
+               // Decode only video packets
+               if (packet.stream_index != video_stream)
+                 continue;
+               
+               // Timestamp of the decoded frame.
+               pts = static_cast<int64_t>(packet.pts / packet.duration * 
AV_TIME_BASE / frame_rate + 0.5);
+
+               avcodec_decode_video(pCodecContext, pFrame, &gotFrame, 
packet.data, packet.size);
+               av_free_packet(&packet);
+       } while (pts < targetPts);
+
+       // This read_frame is necessary to ensure that the first frame read by 
the calling program
+       // is actually the seeked-to frame.
+       read_next_frame();
 }
 
+
 }
 } // namespace CVD




reply via email to

[Prev in Thread] Current Thread [Next in Thread]