diff options
-rw-r--r-- | video/video_decoder.cpp | 69 | ||||
-rw-r--r-- | video/video_decoder.h | 23 |
2 files changed, 84 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 { diff --git a/video/video_decoder.h b/video/video_decoder.h index ca88696b57..e7626261a2 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -178,6 +178,14 @@ public: virtual bool seek(const Audio::Timestamp &time); /** + * Seek to a given frame. + * + * This only works when one video track is present, and that track + * supports getFrameTime(). This calls seek() internally. + */ + bool seekToFrame(uint frame); + + /** * Pause or resume the video. This should stop/resume any audio playback * and other stuff. The initial pause time is kept so that any timing * variables can be updated appropriately. @@ -535,6 +543,14 @@ protected: * Does the palette currently in use by this track need to be updated? */ virtual bool hasDirtyPalette() const { return false; } + + /** + * Get the time the given frame should be shown. + * + * By default, this returns a negative (invalid) value. This function + * should only be used by VideoDecoder::seekToFrame(). + */ + virtual Audio::Timestamp getFrameTime(uint frame) const; }; /** @@ -549,12 +565,19 @@ protected: uint32 getNextFrameStartTime() const; virtual Audio::Timestamp getDuration() const; + Audio::Timestamp getFrameTime(uint frame) const; protected: /** * Get the rate at which this track is played. */ virtual Common::Rational getFrameRate() const = 0; + + /** + * Get the frame that should be displaying at the given time. This is + * helpful for someone implementing seek(). + */ + uint getFrameAtTime(const Audio::Timestamp &time) const; }; /** |