aboutsummaryrefslogtreecommitdiff
path: root/video/video_decoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'video/video_decoder.cpp')
-rw-r--r--video/video_decoder.cpp405
1 files changed, 389 insertions, 16 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;