aboutsummaryrefslogtreecommitdiff
path: root/video
diff options
context:
space:
mode:
authorMatthew Hoops2012-07-20 20:51:42 -0400
committerMatthew Hoops2012-07-20 20:51:42 -0400
commit818c16bdd09f4aa92c4a46de5256f28331c35cbb (patch)
treeb449e93a7a219d2dfcaa9f531110636881c1ead8 /video
parentf0304ee0bb09f2b57d755e5e3100fe157512af56 (diff)
downloadscummvm-rg350-818c16bdd09f4aa92c4a46de5256f28331c35cbb.tar.gz
scummvm-rg350-818c16bdd09f4aa92c4a46de5256f28331c35cbb.tar.bz2
scummvm-rg350-818c16bdd09f4aa92c4a46de5256f28331c35cbb.zip
VIDEO: Add first draft of the new VideoDecoder API
It is currently named "AdvancedVideoDecoder" until all current VideoDecoders are converted to the new API.
Diffstat (limited to 'video')
-rw-r--r--video/video_decoder.cpp405
-rw-r--r--video/video_decoder.h358
2 files changed, 744 insertions, 19 deletions
diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp
index 44d7917652..ef2aeae94f 100644
--- a/video/video_decoder.cpp
+++ b/video/video_decoder.cpp
@@ -22,6 +22,7 @@
#include "video/video_decoder.h"
+#include "audio/audiostream.h"
#include "audio/mixer.h" // for kMaxChannelVolume
#include "common/rational.h"
@@ -51,26 +52,10 @@ uint32 VideoDecoder::getTime() const {
return g_system->getMillis() - _startTime;
}
-void VideoDecoder::setSystemPalette() {
- g_system->getPaletteManager()->setPalette(getPalette(), 0, 256);
-}
-
bool VideoDecoder::needsUpdate() const {
return !endOfVideo() && getTimeToNextFrame() == 0;
}
-void VideoDecoder::reset() {
- _curFrame = -1;
- _startTime = 0;
- _pauseLevel = 0;
- _audioVolume = Audio::Mixer::kMaxChannelVolume;
- _audioBalance = 0;
-}
-
-bool VideoDecoder::endOfVideo() const {
- return !isVideoLoaded() || (getCurFrame() >= (int32)getFrameCount() - 1);
-}
-
void VideoDecoder::pauseVideo(bool pause) {
if (pause) {
_pauseLevel++;
@@ -108,6 +93,394 @@ void VideoDecoder::setBalance(int8 balance) {
updateBalance();
}
+AdvancedVideoDecoder::AdvancedVideoDecoder() {
+ _needsRewind = false;
+ _dirtyPalette = false;
+ _palette = 0;
+ _isPlaying = false;
+}
+
+void AdvancedVideoDecoder::close() {
+ if (_isPlaying)
+ stop();
+
+ for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
+ delete *it;
+
+ _tracks.clear();
+ _needsRewind = false;
+ _dirtyPalette = false;
+ _palette = 0;
+ _startTime = 0;
+ reset();
+}
+
+bool AdvancedVideoDecoder::isVideoLoaded() const {
+ return !_tracks.empty();
+}
+
+const Graphics::Surface *AdvancedVideoDecoder::decodeNextFrame() {
+ readNextPacket();
+ VideoTrack *track = findNextVideoTrack();
+
+ if (!track)
+ return 0;
+
+ const Graphics::Surface *frame = track->decodeNextFrame();
+
+ if (track->hasDirtyPalette()) {
+ _palette = track->getPalette();
+ _dirtyPalette = true;
+ }
+
+ return frame;
+}
+
+const byte *AdvancedVideoDecoder::getPalette() {
+ _dirtyPalette = false;
+ return _palette;
+}
+
+int AdvancedVideoDecoder::getCurFrame() const {
+ int32 frame = -1;
+
+ for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
+ if ((*it)->getTrackType() == Track::kTrackTypeVideo)
+ frame += ((VideoTrack *)*it)->getCurFrame() + 1;
+
+ return frame;
+}
+
+uint32 AdvancedVideoDecoder::getFrameCount() const {
+ int count = 0;
+
+ for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
+ if ((*it)->getTrackType() == Track::kTrackTypeVideo)
+ count += ((VideoTrack *)*it)->getFrameCount();
+
+ return count;
+}
+
+uint32 AdvancedVideoDecoder::getTime() const {
+ if (isPaused())
+ return _pauseStartTime - _startTime;
+
+ for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) {
+ if ((*it)->getTrackType() == Track::kTrackTypeAudio) {
+ uint32 time = ((const AudioTrack *)*it)->getRunningTime();
+
+ if (time != 0)
+ return time + _audioStartOffset.msecs();
+ }
+ }
+
+ return g_system->getMillis() - _startTime;
+}
+
+uint32 AdvancedVideoDecoder::getTimeToNextFrame() const {
+ if (endOfVideo())
+ return 0;
+
+ const VideoTrack *track = findNextVideoTrack();
+
+ if (!track)
+ return 0;
+
+ uint32 elapsedTime = getTime();
+ uint32 nextFrameStartTime = track->getNextFrameStartTime();
+
+ if (nextFrameStartTime <= elapsedTime)
+ return 0;
+
+ return nextFrameStartTime - elapsedTime;
+}
+
+bool AdvancedVideoDecoder::endOfVideo() const {
+ // TODO: Bring _isPlaying into account?
+
+ if (!isVideoLoaded())
+ return true;
+
+ for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
+ if (!(*it)->endOfTrack())
+ return false;
+
+ return true;
+}
+
+bool AdvancedVideoDecoder::isRewindable() const {
+ if (_tracks.empty())
+ return false;
+
+ for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
+ if (!(*it)->isRewindable())
+ return false;
+
+ return true;
+}
+
+bool AdvancedVideoDecoder::rewind() {
+ if (!isRewindable())
+ return false;
+
+ _needsRewind = false;
+
+ // TODO: Pause status
+
+ for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
+ if (!(*it)->rewind())
+ return false;
+
+ _audioStartOffset = 0;
+ return true;
+}
+
+bool AdvancedVideoDecoder::isSeekable() const {
+ if (_tracks.empty())
+ return false;
+
+ for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
+ if (!(*it)->isSeekable())
+ return false;
+
+ return true;
+}
+
+bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) {
+ if (!isSeekable())
+ return false;
+
+ _needsRewind = false;
+
+ // TODO: Pause status
+
+ for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
+ if (!(*it)->seek(time))
+ return false;
+
+ _audioStartOffset = time;
+ return true;
+}
+
+void AdvancedVideoDecoder::start() {
+ if (_isPlaying || !isVideoLoaded())
+ return;
+
+ _isPlaying = true;
+ _startTime = g_system->getMillis();
+ _audioStartOffset = 0;
+
+ // If someone previously called stop(), we'll rewind it.
+ if (_needsRewind)
+ rewind();
+
+ for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
+ (*it)->start();
+}
+
+void AdvancedVideoDecoder::stop() {
+ if (!_isPlaying)
+ return;
+
+ _isPlaying = false;
+ _startTime = 0;
+ _audioStartOffset = 0;
+ _palette = 0;
+ _dirtyPalette = false;
+
+ for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
+ (*it)->stop();
+
+ // Also reset the pause state.
+ _pauseLevel = 0;
+
+ // If this is a rewindable video, don't close it too. We'll just rewind() the video
+ // the next time someone calls start(). Otherwise, since it can't be rewound, we
+ // just close it.
+ if (isRewindable())
+ _needsRewind = true;
+ else
+ close();
+}
+
+Audio::Timestamp AdvancedVideoDecoder::getDuration() const {
+ return Audio::Timestamp(0, 1000);
+}
+
+void AdvancedVideoDecoder::pauseVideoIntern(bool pause) {
+ for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
+ (*it)->pause(pause);
+}
+
+void AdvancedVideoDecoder::updateVolume() {
+ // For API compatibility only
+ for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
+ if ((*it)->getTrackType() == Track::kTrackTypeAudio)
+ ((AudioTrack *)*it)->setVolume(_audioVolume);
+}
+
+void AdvancedVideoDecoder::updateBalance() {
+ // For API compatibility only
+ for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
+ if ((*it)->getTrackType() == Track::kTrackTypeAudio)
+ ((AudioTrack *)*it)->setBalance(_audioBalance);
+}
+
+AdvancedVideoDecoder::Track::Track() {
+ _paused = false;
+}
+
+bool AdvancedVideoDecoder::Track::isRewindable() const {
+ return isSeekable();
+}
+
+bool AdvancedVideoDecoder::Track::rewind() {
+ return seek(Audio::Timestamp(0, 1000));
+}
+
+uint32 AdvancedVideoDecoder::FixedRateVideoTrack::getNextFrameStartTime() const {
+ if (endOfTrack() || getCurFrame() < 0)
+ return 0;
+
+ Common::Rational time = (getCurFrame() + 1) * 1000;
+ time /= getFrameRate();
+ return time.toInt();
+}
+
+bool AdvancedVideoDecoder::FixedLengthVideoTrack::endOfTrack() const {
+ return getCurFrame() >= (getFrameCount() - 1);
+}
+
+bool AdvancedVideoDecoder::AudioTrack::endOfTrack() const {
+ Audio::AudioStream *stream = getAudioStream();
+ return !stream || (!g_system->getMixer()->isSoundHandleActive(_handle) && stream->endOfData());
+}
+
+void AdvancedVideoDecoder::AudioTrack::setVolume(byte volume) {
+ _volume = volume;
+
+ if (g_system->getMixer()->isSoundHandleActive(_handle))
+ g_system->getMixer()->setChannelVolume(_handle, _volume);
+}
+
+void AdvancedVideoDecoder::AudioTrack::setBalance(int8 balance) {
+ _balance = balance;
+
+ if (g_system->getMixer()->isSoundHandleActive(_handle))
+ g_system->getMixer()->setChannelBalance(_handle, _balance);
+}
+
+void AdvancedVideoDecoder::AudioTrack::start() {
+ stop();
+
+ Audio::AudioStream *stream = getAudioStream();
+ assert(stream);
+
+ g_system->getMixer()->playStream(getSoundType(), &_handle, stream, -1, getVolume(), getBalance(), DisposeAfterUse::NO);
+
+ // Pause the audio again if we're still paused
+ if (isPaused())
+ g_system->getMixer()->pauseHandle(_handle, true);
+}
+
+void AdvancedVideoDecoder::AudioTrack::stop() {
+ g_system->getMixer()->stopHandle(_handle);
+}
+
+uint32 AdvancedVideoDecoder::AudioTrack::getRunningTime() const {
+ if (g_system->getMixer()->isSoundHandleActive(_handle))
+ return g_system->getMixer()->getSoundElapsedTime(_handle);
+
+ return 0;
+}
+
+void AdvancedVideoDecoder::AudioTrack::pauseIntern(bool shouldPause) {
+ if (g_system->getMixer()->isSoundHandleActive(_handle))
+ g_system->getMixer()->pauseHandle(_handle, shouldPause);
+}
+
+Audio::AudioStream *AdvancedVideoDecoder::RewindableAudioTrack::getAudioStream() const {
+ return getRewindableAudioStream();
+}
+
+bool AdvancedVideoDecoder::RewindableAudioTrack::rewind() {
+ Audio::RewindableAudioStream *stream = getRewindableAudioStream();
+ assert(stream);
+ return stream->rewind();
+}
+
+Audio::AudioStream *AdvancedVideoDecoder::SeekableAudioTrack::getAudioStream() const {
+ return getSeekableAudioStream();
+}
+
+bool AdvancedVideoDecoder::SeekableAudioTrack::seek(const Audio::Timestamp &time) {
+ Audio::SeekableAudioStream *stream = getSeekableAudioStream();
+ assert(stream);
+ return stream->seek(time);
+}
+
+void AdvancedVideoDecoder::addTrack(Track *track) {
+ _tracks.push_back(track);
+}
+
+AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack() {
+ VideoTrack *bestTrack = 0;
+ uint32 bestTime = 0xFFFFFFFF;
+
+ for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) {
+ if ((*it)->getTrackType() == Track::kTrackTypeVideo) {
+ VideoTrack *track = (VideoTrack *)*it;
+ uint32 time = track->getNextFrameStartTime();
+
+ if (time < bestTime) {
+ bestTime = time;
+ bestTrack = track;
+ }
+ }
+ }
+
+ return bestTrack;
+}
+
+const AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack() const {
+ const VideoTrack *bestTrack = 0;
+ uint32 bestTime = 0xFFFFFFFF;
+
+ for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) {
+ if ((*it)->getTrackType() == Track::kTrackTypeVideo) {
+ const VideoTrack *track = (const VideoTrack *)*it;
+ uint32 time = track->getNextFrameStartTime();
+
+ if (time < bestTime) {
+ bestTime = time;
+ bestTrack = track;
+ }
+ }
+ }
+
+ return bestTrack;
+}
+
+//////////////////////////////////////////////
+///////////////// DEPRECATED /////////////////
+//////////////////////////////////////////////
+
+void VideoDecoder::reset() {
+ _curFrame = -1;
+ _startTime = 0;
+ _pauseLevel = 0;
+ _audioVolume = Audio::Mixer::kMaxChannelVolume;
+ _audioBalance = 0;
+}
+
+bool VideoDecoder::endOfVideo() const {
+ return !isVideoLoaded() || (getCurFrame() >= (int32)getFrameCount() - 1);
+}
+
+void VideoDecoder::setSystemPalette() {
+ g_system->getPaletteManager()->setPalette(getPalette(), 0, 256);
+}
+
uint32 FixedRateVideoDecoder::getTimeToNextFrame() const {
if (endOfVideo() || _curFrame < 0)
return 0;
diff --git a/video/video_decoder.h b/video/video_decoder.h
index 3bb75ade09..1c359591b3 100644
--- a/video/video_decoder.h
+++ b/video/video_decoder.h
@@ -23,10 +23,16 @@
#ifndef VIDEO_DECODER_H
#define VIDEO_DECODER_H
-#include "common/str.h"
-
+#include "audio/mixer.h"
#include "audio/timestamp.h" // TODO: Move this to common/ ?
+#include "common/list.h"
+#include "common/str.h"
+namespace Audio {
+class AudioStream;
+class RewindableAudioStream;
+class SeekableAudioStream;
+}
namespace Common {
class Rational;
@@ -42,6 +48,7 @@ namespace Video {
/**
* Generic interface for video decoder classes.
+ * @note This class is now deprecated in favor of AdvancedVideoDecoder.
*/
class VideoDecoder {
public:
@@ -109,6 +116,7 @@ public:
/**
* Set the system palette to the palette returned by getPalette.
* @see getPalette
+ * @note This function is now deprecated. There is no replacement.
*/
void setSystemPalette();
@@ -222,39 +230,46 @@ public:
protected:
/**
* Resets _curFrame and _startTime. Should be called from every close() function.
+ * @note This function is now deprecated. There is no replacement.
*/
void reset();
/**
* Actual implementation of pause by subclasses. See pause()
* for details.
+ * @note This function is now deprecated. There is no replacement.
*/
virtual void pauseVideoIntern(bool pause) {}
/**
* Add the time the video has been paused to maintain sync
+ * @note This function is now deprecated. There is no replacement.
*/
virtual void addPauseTime(uint32 ms) { _startTime += ms; }
/**
* Reset the pause start time (which should be called when seeking)
+ * @note This function is now deprecated. There is no replacement.
*/
void resetPauseStartTime();
/**
* Update currently playing audio tracks with the new volume setting
+ * @note This function is now deprecated. There is no replacement.
*/
virtual void updateVolume() {}
/**
* Update currently playing audio tracks with the new balance setting
+ * @note This function is now deprecated. There is no replacement.
*/
virtual void updateBalance() {}
int32 _curFrame;
int32 _startTime;
-private:
+// FIXME: These are protected until the new API takes over this one
+//private:
uint32 _pauseLevel;
uint32 _pauseStartTime;
byte _audioVolume;
@@ -262,7 +277,342 @@ private:
};
/**
+ * Improved interface for video decoder classes.
+ */
+class AdvancedVideoDecoder : public VideoDecoder {
+public:
+ AdvancedVideoDecoder();
+ virtual ~AdvancedVideoDecoder() {}
+
+ // Old API Non-changing
+ // loadFile()
+ // loadStream()
+ // getWidth()
+ // getHeight()
+ // needsUpdate()
+
+ // Old API Changing
+ virtual void close();
+ bool isVideoLoaded() const;
+ virtual const Graphics::Surface *decodeNextFrame();
+ const byte *getPalette();
+ bool hasDirtyPalette() const { return _dirtyPalette; }
+ int getCurFrame() const;
+ uint32 getFrameCount() const;
+ uint32 getTime() const;
+ uint32 getTimeToNextFrame() const;
+ bool endOfVideo() const;
+
+ // New API
+ /**
+ * Returns if a video is rewindable or not.
+ */
+ bool isRewindable() const;
+
+ /**
+ * Rewind a video to its beginning.
+ *
+ * If the video is playing, it will continue to play.
+ *
+ * @return true on success, false otherwise
+ */
+ bool rewind();
+
+ /**
+ * Returns if a video is seekable or not.
+ */
+ bool isSeekable() const;
+
+ /**
+ * Seek to a given time in the video.
+ *
+ * If the video is playing, it will continue to play.
+ *
+ * @param time The time to seek to
+ * @return true on success, false otherwise
+ */
+ bool seek(const Audio::Timestamp &time);
+
+ /**
+ * Begin playback of the video.
+ *
+ * @note This has no effect is the video is already playing.
+ */
+ void start();
+
+ /**
+ * Stop playback of the video.
+ *
+ * @note This will close() the video if it is not rewindable.
+ */
+ void stop();
+
+ /**
+ * Returns if the video is currently playing or not.
+ * @todo Differentiate this function from endOfVideo()
+ */
+ bool isPlaying() const { return _isPlaying; }
+
+ /**
+ * Get the duration of the video.
+ *
+ * If the duration is unknown, this will return 0.
+ */
+ virtual Audio::Timestamp getDuration() const;
+
+ // Future API
+ //void setRate(const Common::Rational &rate);
+ //Common::Rational getRate() const;
+ //void setStartTime(const Audio::Timestamp &startTime);
+ //Audio::Timestamp getStartTime() const;
+ //void setStopTime(const Audio::Timestamp &stopTime);
+ //Audio::Timestamp getStopTime() const;
+ //void setSegment(const Audio::Timestamp &startTime, const Audio::Timestamp &stopTime);
+
+protected:
+ // Old API
+ void pauseVideoIntern(bool pause);
+ void updateVolume();
+ void updateBalance();
+
+ // New API
+
+ /**
+ * An abstract representation of a track in a movie.
+ */
+ class Track {
+ public:
+ Track();
+ virtual ~Track() {}
+
+ /**
+ * The types of tracks this class can be.
+ */
+ enum TrackType {
+ kTrackTypeNone,
+ kTrackTypeVideo,
+ kTrackTypeAudio
+ };
+
+ /**
+ * Get the type of track.
+ */
+ virtual TrackType getTrackType() const = 0;
+
+ /**
+ * Return if the track has finished.
+ */
+ virtual bool endOfTrack() const = 0;
+
+ /**
+ * Return if the track is rewindable.
+ */
+ virtual bool isRewindable() const;
+
+ /**
+ * Rewind the video to the beginning.
+ * @return true on success, false otherwise.
+ */
+ virtual bool rewind();
+
+ /**
+ * Return if the track is seekable.
+ */
+ virtual bool isSeekable() const { return false; }
+
+ /**
+ * Seek to the given time.
+ * @param time The time to seek to.
+ * @return true on success, false otherwise.
+ */
+ virtual bool seek(const Audio::Timestamp &time) { return false; }
+
+ /**
+ * Start playback of the track.
+ */
+ virtual void start() {}
+
+ /**
+ * Stop playback of the track.
+ */
+ virtual void stop() {}
+
+ /**
+ * Set the pause status of the track.
+ */
+ void pause(bool shouldPause) {}
+
+ /**
+ * Return if the track is paused.
+ */
+ bool isPaused() const { return _paused; }
+
+ protected:
+ /**
+ * Function called by pause() for subclasses to implement.
+ */
+ void pauseIntern(bool pause);
+
+ private:
+ bool _paused;
+ };
+
+ /**
+ * An abstract representation of a video track.
+ */
+ class VideoTrack : public Track {
+ public:
+ VideoTrack() {}
+ virtual ~VideoTrack() {}
+
+ TrackType getTrackType() const { return kTrackTypeVideo; }
+
+ // TODO: Document
+ virtual int getCurFrame() const = 0;
+ virtual int getFrameCount() const { return 0; }
+ virtual uint32 getNextFrameStartTime() const = 0;
+ virtual const Graphics::Surface *decodeNextFrame() = 0;
+ virtual const byte *getPalette() const { return 0; }
+ virtual bool hasDirtyPalette() const { return false; }
+ };
+
+ /**
+ * A VideoTrack that is played at a constant rate.
+ */
+ class FixedRateVideoTrack : public virtual VideoTrack {
+ public:
+ FixedRateVideoTrack() {}
+ virtual ~FixedRateVideoTrack() {}
+
+ uint32 getNextFrameStartTime() const;
+
+ protected:
+ /**
+ * Get the rate at which this track is played.
+ */
+ virtual Common::Rational getFrameRate() const = 0;
+ };
+
+ /**
+ * A VideoTrack with a known frame count that can be reliably
+ * used to figure out if the track has finished.
+ */
+ class FixedLengthVideoTrack : public virtual VideoTrack {
+ public:
+ FixedLengthVideoTrack() {}
+ virtual ~FixedLengthVideoTrack() {}
+
+ bool endOfTrack() const;
+ };
+
+ /**
+ * An abstract representation of an audio track.
+ */
+ class AudioTrack : public Track {
+ public:
+ AudioTrack() {}
+ virtual ~AudioTrack() {}
+
+ TrackType getTrackType() const { return kTrackTypeAudio; }
+
+ virtual bool endOfTrack() const;
+ void start();
+ void stop();
+
+ // TODO: Document
+ byte getVolume() const { return _volume; }
+ void setVolume(byte volume);
+ int8 getBalance() const { return _balance; }
+ void setBalance(int8 balance);
+ uint32 getRunningTime() const;
+
+ virtual Audio::Mixer::SoundType getSoundType() const { return Audio::Mixer::kPlainSoundType; }
+
+ protected:
+ void pauseIntern(bool pause);
+
+ // TODO: Document
+ virtual Audio::AudioStream *getAudioStream() const = 0;
+
+ private:
+ Audio::SoundHandle _handle;
+ byte _volume;
+ int8 _balance;
+ };
+
+ /**
+ * An AudioTrack that implements isRewindable() and rewind() using
+ * the RewindableAudioStream API.
+ */
+ class RewindableAudioTrack : public AudioTrack {
+ public:
+ RewindableAudioTrack() {}
+ virtual ~RewindableAudioTrack() {}
+
+ bool isRewindable() const { return true; }
+ bool rewind();
+
+ protected:
+ Audio::AudioStream *getAudioStream() const;
+
+ // TODO: Document
+ virtual Audio::RewindableAudioStream *getRewindableAudioStream() const = 0;
+ };
+
+ /**
+ * An AudioTrack that implements isSeekable() and seek() using
+ * the SeekableAudioStream API.
+ */
+ class SeekableAudioTrack : public AudioTrack {
+ public:
+ SeekableAudioTrack() {}
+ virtual ~SeekableAudioTrack() {}
+
+ bool isSeekable() const { return true; }
+ bool seek(const Audio::Timestamp &time);
+
+ protected:
+ Audio::AudioStream *getAudioStream() const;
+
+ // TODO: Document
+ virtual Audio::SeekableAudioStream *getSeekableAudioStream() const = 0;
+ };
+
+ /**
+ * Decode enough data for the next frame and enough audio to last that long.
+ *
+ * This function is used by the default decodeNextFrame() function. A subclass
+ * of a Track may decide to just have its decodeNextFrame() function read
+ * and decode the frame.
+ */
+ virtual void readNextPacket() {}
+
+ /**
+ * Define a track to be used by this class.
+ *
+ * The pointer is then owned by this base class.
+ */
+ void addTrack(Track *track);
+
+private:
+ // Tracks owned by this AdvancedVideoDecoder
+ typedef Common::List<Track *> TrackList;
+ TrackList _tracks;
+ VideoTrack *findNextVideoTrack();
+ const VideoTrack *findNextVideoTrack() const;
+
+ // Current playback status
+ bool _isPlaying, _needsRewind;
+ Audio::Timestamp _audioStartOffset;
+
+ // Palette settings from individual tracks
+ mutable bool _dirtyPalette;
+ const byte *_palette;
+};
+
+/**
* A VideoDecoder wrapper that implements getTimeToNextFrame() based on getFrameRate().
+ * @note This class is now deprecated. Use AdvancedVideoDecoder instead.
*/
class FixedRateVideoDecoder : public virtual VideoDecoder {
public:
@@ -282,6 +632,7 @@ private:
/**
* A VideoDecoder that can be rewound back to the beginning.
+ * @note This class is now deprecated. Use AdvancedVideoDecoder instead.
*/
class RewindableVideoDecoder : public virtual VideoDecoder {
public:
@@ -293,6 +644,7 @@ public:
/**
* A VideoDecoder that can seek to a frame or point in time.
+ * @note This class is now deprecated. Use AdvancedVideoDecoder instead.
*/
class SeekableVideoDecoder : public virtual RewindableVideoDecoder {
public: