[Top][All Lists]
[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
- [libcvd-members] libcvd/cvd_src videofilebuffer.cc,
Colin Starr <=