aboutsummaryrefslogtreecommitdiff
path: root/video/video_decoder.cpp
diff options
context:
space:
mode:
authorMatthew Hoops2012-11-26 17:43:53 -0500
committerMatthew Hoops2012-11-26 17:44:36 -0500
commit121faeaa94bf3720143c12f025a9b95e4a875442 (patch)
treeee41db4db7205f2a20762dd06dab9fc8dec5e437 /video/video_decoder.cpp
parent77a9f0145482ed5ce95cff5d499cc9c509e86dbc (diff)
downloadscummvm-rg350-121faeaa94bf3720143c12f025a9b95e4a875442.tar.gz
scummvm-rg350-121faeaa94bf3720143c12f025a9b95e4a875442.tar.bz2
scummvm-rg350-121faeaa94bf3720143c12f025a9b95e4a875442.zip
VIDEO: Add preliminary API functions for seeking to a frame
Diffstat (limited to 'video/video_decoder.cpp')
-rw-r--r--video/video_decoder.cpp69
1 files changed, 61 insertions, 8 deletions
diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp
index 6c45cc578f..826880b450 100644
--- a/video/video_decoder.cpp
+++ b/video/video_decoder.cpp
@@ -324,6 +324,35 @@ bool VideoDecoder::seek(const Audio::Timestamp &time) {
return true;
}
+bool VideoDecoder::seekToFrame(uint frame) {
+ VideoTrack *track = 0;
+
+ for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) {
+ if (!(*it)->isSeekable())
+ return false;
+
+ if ((*it)->getTrackType() == Track::kTrackTypeVideo) {
+ // We only allow seeking by frame when one video track
+ // is present
+ if (track)
+ return false;
+
+ track = (VideoTrack *)*it;
+ }
+ }
+
+ // If we didn't find a video track, we can't seek by frame (of course)
+ if (!track)
+ return false;
+
+ Audio::Timestamp time = track->getFrameTime(frame);
+
+ if (time < 0)
+ return false;
+
+ return seek(time);
+}
+
void VideoDecoder::start() {
if (!isPlaying())
setRate(1);
@@ -434,21 +463,45 @@ bool VideoDecoder::VideoTrack::endOfTrack() const {
return getCurFrame() >= (getFrameCount() - 1);
}
+Audio::Timestamp VideoDecoder::VideoTrack::getFrameTime(uint frame) const {
+ // Default implementation: Return an invalid (negative) number
+ return Audio::Timestamp().addFrames(-1);
+}
+
uint32 VideoDecoder::FixedRateVideoTrack::getNextFrameStartTime() const {
if (endOfTrack() || getCurFrame() < 0)
return 0;
- Common::Rational time = (getCurFrame() + 1) * 1000;
- time /= getFrameRate();
- return time.toInt();
+ return getFrameTime(getCurFrame() + 1).msecs();
+}
+
+Audio::Timestamp VideoDecoder::FixedRateVideoTrack::getFrameTime(uint frame) const {
+ // Try to get as accurate as possible, considering we have a fractional frame rate
+ // (which Audio::Timestamp doesn't support).
+ Common::Rational frameRate = getFrameRate();
+
+ if (frameRate == frameRate.toInt()) // The nice case (a whole number)
+ return Audio::Timestamp(0, frame, frameRate.toInt());
+
+ // Just convert to milliseconds.
+ Common::Rational time = frame * 1000;
+ time /= frameRate;
+ return Audio::Timestamp(time.toInt(), 1000);
+}
+
+uint VideoDecoder::FixedRateVideoTrack::getFrameAtTime(const Audio::Timestamp &time) const {
+ Common::Rational frameRate = getFrameRate();
+
+ // Easy conversion
+ if (frameRate == time.framerate())
+ return time.totalNumberOfFrames();
+
+ // Default case
+ return (time.totalNumberOfFrames() * frameRate / time.framerate()).toInt();
}
Audio::Timestamp VideoDecoder::FixedRateVideoTrack::getDuration() const {
- // Since Audio::Timestamp doesn't support a fractional frame rate, we're currently
- // just converting to milliseconds.
- Common::Rational time = getFrameCount() * 1000;
- time /= getFrameRate();
- return time.toInt();
+ return getFrameTime(getFrameCount());
}
bool VideoDecoder::AudioTrack::endOfTrack() const {