VIDEO: Add support for playing videos at a modified speed

Currently this only works for positive (forward) playback, but will eventually work for negative (backward).
This commit is contained in:
Matthew Hoops 2012-11-24 01:03:36 -05:00
parent 4d75aa5319
commit db908fcdc4
2 changed files with 81 additions and 25 deletions

View File

@ -37,7 +37,7 @@ VideoDecoder::VideoDecoder() {
_startTime = 0;
_dirtyPalette = false;
_palette = 0;
_isPlaying = false;
_playbackRate = 0;
_audioVolume = Audio::Mixer::kMaxChannelVolume;
_audioBalance = 0;
_pauseLevel = 0;
@ -212,7 +212,7 @@ uint32 VideoDecoder::getTime() const {
return _lastTimeChange.msecs();
if (isPaused())
return _pauseStartTime - _startTime;
return (_playbackRate * (_pauseStartTime - _startTime)).toInt();
if (useAudioSync()) {
for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) {
@ -225,7 +225,7 @@ uint32 VideoDecoder::getTime() const {
}
}
return g_system->getMillis() - _startTime;
return (_playbackRate * (g_system->getMillis() - _startTime)).toInt();
}
uint32 VideoDecoder::getTimeToNextFrame() const {
@ -325,17 +325,8 @@ bool VideoDecoder::seek(const Audio::Timestamp &time) {
}
void VideoDecoder::start() {
if (isPlaying() || !isVideoLoaded())
return;
_isPlaying = true;
_startTime = g_system->getMillis();
// Adjust start time if we've seeked to something besides zero time
if (_lastTimeChange.totalNumberOfFrames() != 0)
_startTime -= _lastTimeChange.msecs();
startAudio();
if (!isPlaying())
setRate(1);
}
void VideoDecoder::stop() {
@ -346,12 +337,12 @@ void VideoDecoder::stop() {
stopAudio();
// Keep the time marked down in case we start up again
// We do this before _isPlaying is set so we don't get
// We do this before _playbackRate is set so we don't get
// _lastTimeChange returned, but before _pauseLevel is
// reset.
_lastTimeChange = getTime();
_isPlaying = false;
_playbackRate = 0;
_startTime = 0;
_palette = 0;
_dirtyPalette = false;
@ -365,6 +356,46 @@ void VideoDecoder::stop() {
(*it)->pause(false);
}
void VideoDecoder::setRate(const Common::Rational &rate) {
if (!isVideoLoaded() || _playbackRate == rate)
return;
if (rate == 0) {
stop();
return;
} else if (rate != 1 && hasAudio()) {
warning("Cannot set custom rate in videos with audio");
return;
}
Common::Rational targetRate = rate;
if (rate < 0) {
// TODO: Implement support for this
warning("Cannot set custom rate to backwards");
targetRate = 1;
if (_playbackRate == targetRate)
return;
}
if (_playbackRate != 0)
_lastTimeChange = getTime();
_playbackRate = targetRate;
_startTime = g_system->getMillis();
// Adjust start time if we've seeked to something besides zero time
if (_lastTimeChange.totalNumberOfFrames() != 0)
_startTime -= (_lastTimeChange.msecs() / _playbackRate).toInt();
startAudio();
}
bool VideoDecoder::isPlaying() const {
return _playbackRate != 0;
}
Audio::Timestamp VideoDecoder::getDuration() const {
Audio::Timestamp maxDuration(0, 1000);
@ -676,4 +707,12 @@ bool VideoDecoder::hasFramesLeft() const {
return false;
}
bool VideoDecoder::hasAudio() const {
for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
if ((*it)->getTrackType() == Track::kTrackTypeAudio)
return true;
return false;
}
} // End of namespace Video

View File

@ -26,6 +26,7 @@
#include "audio/mixer.h"
#include "audio/timestamp.h" // TODO: Move this to common/ ?
#include "common/array.h"
#include "common/rational.h"
#include "common/str.h"
#include "graphics/pixelformat.h"
@ -36,7 +37,6 @@ class SeekableAudioStream;
}
namespace Common {
class Rational;
class SeekableReadStream;
}
@ -100,7 +100,7 @@ public:
/////////////////////////////////////////
/**
* Begin playback of the video.
* Begin playback of the video at normal speed.
*
* @note This has no effect if the video is already playing.
*/
@ -113,6 +113,26 @@ public:
*/
void stop();
/**
* Set the rate of playback.
*
* For instance, a rate of 0 would stop the video, while a rate of 1
* would play the video normally. Passing 2 to this function would
* play the video at twice the normal speed.
*
* @note This function does not work for non-0/1 rates on videos that
* have audio tracks.
*
* @todo This currently does not implement backwards playback, but will
* be implemented soon.
*/
void setRate(const Common::Rational &rate);
/**
* Returns the rate at which the video is being played.
*/
Common::Rational getRate() const { return _playbackRate; }
/**
* Returns if the video is currently playing or not.
*
@ -121,7 +141,7 @@ public:
* return true after calling start() and will continue to return true
* until stop() (or close()) is called.
*/
bool isPlaying() const { return _isPlaying; }
bool isPlaying() const;
/**
* Returns if a video is rewindable or not. The default implementation
@ -367,11 +387,6 @@ public:
*/
bool addStreamFileTrack(const Common::String &baseName);
// Future API
//void setRate(const Common::Rational &rate);
//Common::Rational getRate() const;
protected:
/**
* An abstract representation of a track in a movie. Since tracks here are designed
@ -764,9 +779,10 @@ private:
TrackList _tracks;
// Current playback status
bool _isPlaying, _needsUpdate;
bool _needsUpdate;
Audio::Timestamp _lastTimeChange, _endTime;
bool _endTimeSet;
Common::Rational _playbackRate;
// Palette settings from individual tracks
mutable bool _dirtyPalette;
@ -780,6 +796,7 @@ private:
void startAudio();
void startAudioLimit(const Audio::Timestamp &limit);
bool hasFramesLeft() const;
bool hasAudio() const;
int32 _startTime;
uint32 _pauseLevel;