aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/quicktime.h1
-rw-r--r--engines/mohawk/video.cpp13
-rw-r--r--engines/mohawk/video.h4
-rw-r--r--engines/sci/engine/kvideo.cpp4
-rw-r--r--video/qt_decoder.cpp650
-rw-r--r--video/qt_decoder.h183
6 files changed, 286 insertions, 569 deletions
diff --git a/common/quicktime.h b/common/quicktime.h
index 974502d075..08ca35ad51 100644
--- a/common/quicktime.h
+++ b/common/quicktime.h
@@ -35,6 +35,7 @@
#include "common/scummsys.h"
#include "common/stream.h"
#include "common/rational.h"
+#include "common/types.h"
namespace Common {
class MacResManager;
diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp
index 18d609c513..3b4e61646d 100644
--- a/engines/mohawk/video.cpp
+++ b/engines/mohawk/video.cpp
@@ -207,7 +207,7 @@ bool VideoManager::updateMovies() {
// Remove any videos that are over
if (_videoStreams[i].endOfVideo()) {
if (_videoStreams[i].loop) {
- _videoStreams[i]->seekToTime(_videoStreams[i].start);
+ _videoStreams[i]->seek(_videoStreams[i].start);
} else {
// Check the video time one last time before deleting it
_vm->doVideoTimer(i, true);
@@ -394,6 +394,8 @@ VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool
entry.loop = loop;
entry.enabled = true;
+ entry->start();
+
// Search for any deleted videos so we can take a formerly used slot
for (uint32 i = 0; i < _videoStreams.size(); i++)
if (!_videoStreams[i].video) {
@@ -430,6 +432,7 @@ VideoHandle VideoManager::createVideoHandle(const Common::String &filename, uint
entry->loadStream(file);
entry->setVolume(volume);
+ entry->start();
// Search for any deleted videos so we can take a formerly used slot
for (uint32 i = 0; i < _videoStreams.size(); i++)
@@ -492,7 +495,7 @@ uint32 VideoManager::getTime(VideoHandle handle) {
uint32 VideoManager::getDuration(VideoHandle handle) {
assert(handle != NULL_VID_HANDLE);
- return _videoStreams[handle]->getDuration();
+ return _videoStreams[handle]->getDuration().msecs();
}
bool VideoManager::endOfVideo(VideoHandle handle) {
@@ -512,13 +515,13 @@ void VideoManager::setVideoBounds(VideoHandle handle, Audio::Timestamp start, Au
assert(handle != NULL_VID_HANDLE);
_videoStreams[handle].start = start;
_videoStreams[handle].end = end;
- _videoStreams[handle]->seekToTime(start);
+ _videoStreams[handle]->seek(start);
}
void VideoManager::drawVideoFrame(VideoHandle handle, Audio::Timestamp time) {
assert(handle != NULL_VID_HANDLE);
_videoStreams[handle].end = Audio::Timestamp(0xffffffff, 1);
- _videoStreams[handle]->seekToTime(time);
+ _videoStreams[handle]->seek(time);
updateMovies();
delete _videoStreams[handle].video;
_videoStreams[handle].clear();
@@ -526,7 +529,7 @@ void VideoManager::drawVideoFrame(VideoHandle handle, Audio::Timestamp time) {
void VideoManager::seekToTime(VideoHandle handle, Audio::Timestamp time) {
assert(handle != NULL_VID_HANDLE);
- _videoStreams[handle]->seekToTime(time);
+ _videoStreams[handle]->seek(time);
}
void VideoManager::setVideoLooping(VideoHandle handle, bool loop) {
diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h
index 98bcadfb53..937cd0f2dd 100644
--- a/engines/mohawk/video.h
+++ b/engines/mohawk/video.h
@@ -45,7 +45,7 @@ struct MLSTRecord {
struct VideoEntry {
// Playback variables
- Video::SeekableVideoDecoder *video;
+ Video::AdvancedVideoDecoder *video;
uint16 x;
uint16 y;
bool loop;
@@ -57,7 +57,7 @@ struct VideoEntry {
int id; // Internal Mohawk files
// Helper functions
- Video::SeekableVideoDecoder *operator->() const { assert(video); return video; } // TODO: Remove this eventually
+ Video::AdvancedVideoDecoder *operator->() const { assert(video); return video; } // TODO: Remove this eventually
void clear();
bool endOfVideo();
};
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index 456f860493..da63aa3a8d 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -170,8 +170,6 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
delete videoDecoder;
videoDecoder = 0;
}
-
- ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); // TODO: Remove after new API is complete
}
} else {
// Windows AVI
@@ -212,7 +210,6 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
videoDecoder = 0;
} else {
s->_videoState.fileName = filename;
- ((Video::AdvancedVideoDecoder *)videoDecoder)->start();
}
break;
}
@@ -222,6 +219,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
}
if (videoDecoder) {
+ ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); // TODO: Remove after new API is complete
playVideo(videoDecoder, s->_videoState);
// HACK: Switch back to 8bpp if we played a true color video.
diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp
index aba545abc0..70dcdff9c6 100644
--- a/video/qt_decoder.cpp
+++ b/video/qt_decoder.cpp
@@ -33,14 +33,12 @@
#include "audio/audiostream.h"
#include "common/debug.h"
-#include "common/endian.h"
#include "common/memstream.h"
#include "common/system.h"
#include "common/textconsole.h"
#include "common/util.h"
// Video codecs
-#include "video/codecs/codec.h"
#include "video/codecs/cinepak.h"
#include "video/codecs/mjpeg.h"
#include "video/codecs/qtrle.h"
@@ -56,97 +54,43 @@ namespace Video {
////////////////////////////////////////////
QuickTimeDecoder::QuickTimeDecoder() {
- _setStartTime = false;
_scaledSurface = 0;
- _dirtyPalette = false;
- _palette = 0;
_width = _height = 0;
- _needUpdate = false;
}
QuickTimeDecoder::~QuickTimeDecoder() {
close();
}
-int32 QuickTimeDecoder::getCurFrame() const {
- // TODO: This is rather simplistic and doesn't take edits that
- // repeat sections of the media into account. Doing that
- // over-complicates things and shouldn't be necessary, but
- // it would be nice to have in the future.
-
- int32 frame = -1;
-
- for (uint32 i = 0; i < _handlers.size(); i++)
- if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo)
- frame += ((VideoTrackHandler *)_handlers[i])->getCurFrame() + 1;
-
- return frame;
-}
-
-uint32 QuickTimeDecoder::getFrameCount() const {
- uint32 count = 0;
-
- for (uint32 i = 0; i < _handlers.size(); i++)
- if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo)
- count += ((VideoTrackHandler *)_handlers[i])->getFrameCount();
-
- return count;
-}
-
-void QuickTimeDecoder::startAudio() {
- updateAudioBuffer();
-
- for (uint32 i = 0; i < _audioTracks.size(); i++) {
- g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audioHandles[i], _audioTracks[i], -1, getVolume(), getBalance(), DisposeAfterUse::NO);
+bool QuickTimeDecoder::loadFile(const Common::String &filename) {
+ if (!Common::QuickTimeParser::parseFile(filename))
+ return false;
- // Pause the audio again if we're still paused
- if (isPaused())
- g_system->getMixer()->pauseHandle(_audioHandles[i], true);
- }
+ init();
+ return true;
}
-void QuickTimeDecoder::stopAudio() {
- for (uint32 i = 0; i < _audioHandles.size(); i++)
- g_system->getMixer()->stopHandle(_audioHandles[i]);
-}
+bool QuickTimeDecoder::loadStream(Common::SeekableReadStream *stream) {
+ if (!Common::QuickTimeParser::parseStream(stream))
+ return false;
-void QuickTimeDecoder::pauseVideoIntern(bool pause) {
- for (uint32 i = 0; i < _audioHandles.size(); i++)
- g_system->getMixer()->pauseHandle(_audioHandles[i], pause);
+ init();
+ return true;
}
-QuickTimeDecoder::VideoTrackHandler *QuickTimeDecoder::findNextVideoTrack() const {
- VideoTrackHandler *bestTrack = 0;
- uint32 bestTime = 0xffffffff;
-
- for (uint32 i = 0; i < _handlers.size(); i++) {
- if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo && !_handlers[i]->endOfTrack()) {
- VideoTrackHandler *track = (VideoTrackHandler *)_handlers[i];
- uint32 time = track->getNextFrameStartTime();
+void QuickTimeDecoder::close() {
+ AdvancedVideoDecoder::close();
+ Common::QuickTimeParser::close();
- if (time < bestTime) {
- bestTime = time;
- bestTrack = track;
- }
- }
+ if (_scaledSurface) {
+ _scaledSurface->free();
+ delete _scaledSurface;
+ _scaledSurface = 0;
}
-
- return bestTrack;
}
const Graphics::Surface *QuickTimeDecoder::decodeNextFrame() {
- if (!_nextVideoTrack)
- return 0;
-
- const Graphics::Surface *frame = _nextVideoTrack->decodeNextFrame();
-
- if (!_setStartTime) {
- _startTime = g_system->getMillis();
- _setStartTime = true;
- }
-
- _nextVideoTrack = findNextVideoTrack();
- _needUpdate = false;
+ const Graphics::Surface *frame = AdvancedVideoDecoder::decodeNextFrame();
// Update audio buffers too
// (needs to be done after we find the next track)
@@ -166,138 +110,7 @@ const Graphics::Surface *QuickTimeDecoder::decodeNextFrame() {
return frame;
}
-void QuickTimeDecoder::scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst, Common::Rational scaleFactorX, Common::Rational scaleFactorY) {
- assert(src && dst);
-
- for (int32 j = 0; j < dst->h; j++)
- for (int32 k = 0; k < dst->w; k++)
- memcpy(dst->getBasePtr(k, j), src->getBasePtr((k * scaleFactorX).toInt() , (j * scaleFactorY).toInt()), src->format.bytesPerPixel);
-}
-
-bool QuickTimeDecoder::endOfVideo() const {
- if (!isVideoLoaded())
- return true;
-
- for (uint32 i = 0; i < _handlers.size(); i++)
- if (!_handlers[i]->endOfTrack())
- return false;
-
- return true;
-}
-
-uint32 QuickTimeDecoder::getTime() const {
- // Try to base sync off an active audio track
- for (uint32 i = 0; i < _audioHandles.size(); i++) {
- if (g_system->getMixer()->isSoundHandleActive(_audioHandles[i])) {
- uint32 time = g_system->getMixer()->getSoundElapsedTime(_audioHandles[i]) + _audioStartOffset.msecs();
- if (Audio::Timestamp(time, 1000) < _audioTracks[i]->getLength())
- return time;
- }
- }
-
- // Just use time elapsed since the beginning
- return SeekableVideoDecoder::getTime();
-}
-
-uint32 QuickTimeDecoder::getTimeToNextFrame() const {
- if (_needUpdate)
- return 0;
-
- if (_nextVideoTrack) {
- uint32 nextFrameStartTime = _nextVideoTrack->getNextFrameStartTime();
-
- if (nextFrameStartTime == 0)
- return 0;
-
- // TODO: Add support for rate modification
-
- uint32 elapsedTime = getTime();
-
- if (elapsedTime < nextFrameStartTime)
- return nextFrameStartTime - elapsedTime;
- }
-
- return 0;
-}
-
-bool QuickTimeDecoder::loadFile(const Common::String &filename) {
- if (!Common::QuickTimeParser::parseFile(filename))
- return false;
-
- init();
- return true;
-}
-
-bool QuickTimeDecoder::loadStream(Common::SeekableReadStream *stream) {
- if (!Common::QuickTimeParser::parseStream(stream))
- return false;
-
- init();
- return true;
-}
-
-void QuickTimeDecoder::updateVolume() {
- for (uint32 i = 0; i < _audioHandles.size(); i++)
- if (g_system->getMixer()->isSoundHandleActive(_audioHandles[i]))
- g_system->getMixer()->setChannelVolume(_audioHandles[i], getVolume());
-}
-
-void QuickTimeDecoder::updateBalance() {
- for (uint32 i = 0; i < _audioHandles.size(); i++)
- if (g_system->getMixer()->isSoundHandleActive(_audioHandles[i]))
- g_system->getMixer()->setChannelBalance(_audioHandles[i], getBalance());
-}
-
-void QuickTimeDecoder::init() {
- Audio::QuickTimeAudioDecoder::init();
-
- _startTime = 0;
- _setStartTime = false;
-
- // Initialize all the audio tracks
- if (!_audioTracks.empty()) {
- _audioHandles.resize(_audioTracks.size());
-
- for (uint32 i = 0; i < _audioTracks.size(); i++)
- _handlers.push_back(new AudioTrackHandler(this, _audioTracks[i]));
- }
-
- // Initialize all the video tracks
- for (uint32 i = 0; i < _tracks.size(); i++) {
- if (_tracks[i]->codecType == CODEC_TYPE_VIDEO) {
- for (uint32 j = 0; j < _tracks[i]->sampleDescs.size(); j++)
- ((VideoSampleDesc *)_tracks[i]->sampleDescs[j])->initCodec();
-
- _handlers.push_back(new VideoTrackHandler(this, _tracks[i]));
- }
- }
-
- // Prepare the first video track
- _nextVideoTrack = findNextVideoTrack();
-
- if (_nextVideoTrack) {
- if (_scaleFactorX != 1 || _scaleFactorY != 1) {
- // We have to take the scale into consideration when setting width/height
- _width = (_nextVideoTrack->getWidth() / _scaleFactorX).toInt();
- _height = (_nextVideoTrack->getHeight() / _scaleFactorY).toInt();
- } else {
- _width = _nextVideoTrack->getWidth().toInt();
- _height = _nextVideoTrack->getHeight().toInt();
- }
-
- _needUpdate = true;
- } else {
- _needUpdate = false;
- }
-
- // Now start any audio
- if (!_audioTracks.empty()) {
- startAudio();
- _audioStartOffset = Audio::Timestamp(0);
- }
-}
-
-Common::QuickTimeParser::SampleDesc *QuickTimeDecoder::readSampleDesc(Track *track, uint32 format) {
+Common::QuickTimeParser::SampleDesc *QuickTimeDecoder::readSampleDesc(Common::QuickTimeParser::Track *track, uint32 format) {
if (track->codecType == CODEC_TYPE_VIDEO) {
debug(0, "Video Codec FourCC: \'%s\'", tag2str(format));
@@ -395,61 +208,52 @@ Common::QuickTimeParser::SampleDesc *QuickTimeDecoder::readSampleDesc(Track *tra
return Audio::QuickTimeAudioDecoder::readSampleDesc(track, format);
}
-void QuickTimeDecoder::close() {
- stopAudio();
- freeAllTrackHandlers();
-
- if (_scaledSurface) {
- _scaledSurface->free();
- delete _scaledSurface;
- _scaledSurface = 0;
- }
-
- _width = _height = 0;
-
- Common::QuickTimeParser::close();
- SeekableVideoDecoder::reset();
-}
-
-void QuickTimeDecoder::freeAllTrackHandlers() {
- for (uint32 i = 0; i < _handlers.size(); i++)
- delete _handlers[i];
-
- _handlers.clear();
-}
+void QuickTimeDecoder::init() {
+ Audio::QuickTimeAudioDecoder::init();
-void QuickTimeDecoder::seekToTime(const Audio::Timestamp &time) {
- stopAudio();
- _audioStartOffset = time;
+ // Initialize all the audio tracks
+ for (uint32 i = 0; i < _audioTracks.size(); i++)
+ addTrack(new AudioTrackHandler(this, _audioTracks[i]));
- // Sets all tracks to this time
- for (uint32 i = 0; i < _handlers.size(); i++)
- _handlers[i]->seekToTime(time);
+ // Initialize all the video tracks
+ Common::Array<Common::QuickTimeParser::Track *> &tracks = Common::QuickTimeParser::_tracks;
+ for (uint32 i = 0; i < tracks.size(); i++) {
+ if (tracks[i]->codecType == CODEC_TYPE_VIDEO) {
+ for (uint32 j = 0; j < tracks[i]->sampleDescs.size(); j++)
+ ((VideoSampleDesc *)tracks[i]->sampleDescs[j])->initCodec();
- startAudio();
+ addTrack(new VideoTrackHandler(this, tracks[i]));
+ }
+ }
- // Reset our start time
- _startTime = g_system->getMillis() - time.msecs();
- _setStartTime = true;
- resetPauseStartTime();
+ // Prepare the first video track
+ VideoTrackHandler *nextVideoTrack = (VideoTrackHandler *)findNextVideoTrack();
- // Reset the next video track too
- _nextVideoTrack = findNextVideoTrack();
- _needUpdate = _nextVideoTrack != 0;
+ if (nextVideoTrack) {
+ if (_scaleFactorX != 1 || _scaleFactorY != 1) {
+ // We have to take the scale into consideration when setting width/height
+ _width = (nextVideoTrack->getScaledWidth() / _scaleFactorX).toInt();
+ _height = (nextVideoTrack->getScaledHeight() / _scaleFactorY).toInt();
+ } else {
+ _width = nextVideoTrack->getWidth();
+ _height = nextVideoTrack->getHeight();
+ }
+ }
}
void QuickTimeDecoder::updateAudioBuffer() {
// Updates the audio buffers for all audio tracks
- for (uint32 i = 0; i < _handlers.size(); i++)
- if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeAudio)
- ((AudioTrackHandler *)_handlers[i])->updateBuffer();
+ for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++)
+ if ((*it)->getTrackType() == AdvancedVideoDecoder::Track::kTrackTypeAudio)
+ ((AudioTrackHandler *)*it)->updateBuffer();
}
-Graphics::PixelFormat QuickTimeDecoder::getPixelFormat() const {
- if (_nextVideoTrack)
- return _nextVideoTrack->getPixelFormat();
+void QuickTimeDecoder::scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst, const Common::Rational &scaleFactorX, const Common::Rational &scaleFactorY) {
+ assert(src && dst);
- return Graphics::PixelFormat();
+ for (int32 j = 0; j < dst->h; j++)
+ for (int32 k = 0; k < dst->w; k++)
+ memcpy(dst->getBasePtr(k, j), src->getBasePtr((k * scaleFactorX).toInt() , (j * scaleFactorY).toInt()), src->format.bytesPerPixel);
}
QuickTimeDecoder::VideoSampleDesc::VideoSampleDesc(Common::QuickTimeParser::Track *parentTrack, uint32 codecTag) : Common::QuickTimeParser::SampleDesc(parentTrack, codecTag) {
@@ -504,25 +308,8 @@ void QuickTimeDecoder::VideoSampleDesc::initCodec() {
}
}
-bool QuickTimeDecoder::endOfVideoTracks() const {
- for (uint32 i = 0; i < _handlers.size(); i++)
- if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo && !_handlers[i]->endOfTrack())
- return false;
-
- return true;
-}
-
-QuickTimeDecoder::TrackHandler::TrackHandler(QuickTimeDecoder *decoder, Track *parent) : _decoder(decoder), _parent(parent), _fd(_decoder->_fd) {
- _curEdit = 0;
-}
-
-bool QuickTimeDecoder::TrackHandler::endOfTrack() {
- // A track is over when we've finished going through all edits
- return _curEdit == _parent->editCount;
-}
-
QuickTimeDecoder::AudioTrackHandler::AudioTrackHandler(QuickTimeDecoder *decoder, QuickTimeAudioTrack *audioTrack)
- : TrackHandler(decoder, audioTrack->getParent()), _audioTrack(audioTrack) {
+ : _decoder(decoder), _audioTrack(audioTrack) {
}
void QuickTimeDecoder::AudioTrackHandler::updateBuffer() {
@@ -532,21 +319,20 @@ void QuickTimeDecoder::AudioTrackHandler::updateBuffer() {
_audioTrack->queueAudio(Audio::Timestamp(_decoder->getTimeToNextFrame() + 500, 1000));
}
-bool QuickTimeDecoder::AudioTrackHandler::endOfTrack() {
- return _audioTrack->endOfData();
-}
-
-void QuickTimeDecoder::AudioTrackHandler::seekToTime(Audio::Timestamp time) {
- _audioTrack->seek(time);
+Audio::SeekableAudioStream *QuickTimeDecoder::AudioTrackHandler::getSeekableAudioStream() const {
+ return _audioTrack;
}
-QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder, Common::QuickTimeParser::Track *parent) : TrackHandler(decoder, parent) {
+QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder, Common::QuickTimeParser::Track *parent) : _decoder(decoder), _parent(parent) {
+ _curEdit = 0;
enterNewEditList(false);
_holdNextFrameStartTime = false;
_curFrame = -1;
_durationOverride = -1;
_scaledSurface = 0;
+ _curPalette = 0;
+ _dirtyPalette = false;
}
QuickTimeDecoder::VideoTrackHandler::~VideoTrackHandler() {
@@ -556,6 +342,88 @@ QuickTimeDecoder::VideoTrackHandler::~VideoTrackHandler() {
}
}
+bool QuickTimeDecoder::VideoTrackHandler::endOfTrack() const {
+ // A track is over when we've finished going through all edits
+ return _curEdit == _parent->editCount;
+}
+
+bool QuickTimeDecoder::VideoTrackHandler::seek(const Audio::Timestamp &requestedTime) {
+ // First, figure out what edit we're in
+ Audio::Timestamp time = requestedTime.convertToFramerate(_parent->timeScale);
+
+ // Continue until we get to where we need to be
+ for (_curEdit = 0; !endOfTrack(); _curEdit++)
+ if ((uint32)time.totalNumberOfFrames() >= getCurEditTimeOffset() && (uint32)time.totalNumberOfFrames() < getCurEditTimeOffset() + getCurEditTrackDuration())
+ break;
+
+ // This track is done
+ if (endOfTrack())
+ return true;
+
+ enterNewEditList(false);
+
+ // One extra check for the end of a track
+ if (endOfTrack())
+ return true;
+
+ // Now we're in the edit and need to figure out what frame we need
+ while (getRateAdjustedFrameTime() < (uint32)time.totalNumberOfFrames()) {
+ _curFrame++;
+ if (_durationOverride >= 0) {
+ _nextFrameStartTime += _durationOverride;
+ _durationOverride = -1;
+ } else {
+ _nextFrameStartTime += getFrameDuration();
+ }
+ }
+
+ // All that's left is to figure out what our starting time is going to be
+ // Compare the starting point for the frame to where we need to be
+ _holdNextFrameStartTime = getRateAdjustedFrameTime() != (uint32)time.totalNumberOfFrames();
+
+ // If we went past the time, go back a frame
+ if (_holdNextFrameStartTime)
+ _curFrame--;
+
+ // Handle the keyframe here
+ int32 destinationFrame = _curFrame + 1;
+
+ assert(destinationFrame < (int32)_parent->frameCount);
+ _curFrame = findKeyFrame(destinationFrame) - 1;
+ while (_curFrame < destinationFrame - 1)
+ bufferNextFrame();
+
+ return true;
+}
+
+Audio::Timestamp QuickTimeDecoder::VideoTrackHandler::getDuration() const {
+ return Audio::Timestamp(0, _parent->duration, _decoder->_timeScale);
+}
+
+uint16 QuickTimeDecoder::VideoTrackHandler::getWidth() const {
+ return getScaledWidth().toInt();
+}
+
+uint16 QuickTimeDecoder::VideoTrackHandler::getHeight() const {
+ return getScaledHeight().toInt();
+}
+
+Graphics::PixelFormat QuickTimeDecoder::VideoTrackHandler::getPixelFormat() const {
+ return ((VideoSampleDesc *)_parent->sampleDescs[0])->_videoCodec->getPixelFormat();
+}
+
+int QuickTimeDecoder::VideoTrackHandler::getFrameCount() const {
+ return _parent->frameCount;
+}
+
+uint32 QuickTimeDecoder::VideoTrackHandler::getNextFrameStartTime() const {
+ if (endOfTrack())
+ return 0;
+
+ // Convert to milliseconds so the tracks can be compared
+ return getRateAdjustedFrameTime() * 1000 / _parent->timeScale;
+}
+
const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame() {
if (endOfTrack())
return 0;
@@ -586,7 +454,7 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame()
if (frame && (_parent->scaleFactorX != 1 || _parent->scaleFactorY != 1)) {
if (!_scaledSurface) {
_scaledSurface = new Graphics::Surface();
- _scaledSurface->create(getWidth().toInt(), getHeight().toInt(), getPixelFormat());
+ _scaledSurface->create(getScaledWidth().toInt(), getScaledHeight().toInt(), getPixelFormat());
}
_decoder->scaleSurface(frame, _scaledSurface, _parent->scaleFactorX, _parent->scaleFactorY);
@@ -596,6 +464,85 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame()
return frame;
}
+Common::Rational QuickTimeDecoder::VideoTrackHandler::getScaledWidth() const {
+ return Common::Rational(_parent->width) / _parent->scaleFactorX;
+}
+
+Common::Rational QuickTimeDecoder::VideoTrackHandler::getScaledHeight() const {
+ return Common::Rational(_parent->height) / _parent->scaleFactorY;
+}
+
+Common::SeekableReadStream *QuickTimeDecoder::VideoTrackHandler::getNextFramePacket(uint32 &descId) {
+ // First, we have to track down which chunk holds the sample and which sample in the chunk contains the frame we are looking for.
+ int32 totalSampleCount = 0;
+ int32 sampleInChunk = 0;
+ int32 actualChunk = -1;
+ uint32 sampleToChunkIndex = 0;
+
+ for (uint32 i = 0; i < _parent->chunkCount; i++) {
+ if (sampleToChunkIndex < _parent->sampleToChunkCount && i >= _parent->sampleToChunk[sampleToChunkIndex].first)
+ sampleToChunkIndex++;
+
+ totalSampleCount += _parent->sampleToChunk[sampleToChunkIndex - 1].count;
+
+ if (totalSampleCount > _curFrame) {
+ actualChunk = i;
+ descId = _parent->sampleToChunk[sampleToChunkIndex - 1].id;
+ sampleInChunk = _parent->sampleToChunk[sampleToChunkIndex - 1].count - totalSampleCount + _curFrame;
+ break;
+ }
+ }
+
+ if (actualChunk < 0) {
+ warning("Could not find data for frame %d", _curFrame);
+ return 0;
+ }
+
+ // Next seek to that frame
+ Common::SeekableReadStream *stream = _decoder->_fd;
+ stream->seek(_parent->chunkOffsets[actualChunk]);
+
+ // Then, if the chunk holds more than one frame, seek to where the frame we want is located
+ for (int32 i = _curFrame - sampleInChunk; i < _curFrame; i++) {
+ if (_parent->sampleSize != 0)
+ stream->skip(_parent->sampleSize);
+ else
+ stream->skip(_parent->sampleSizes[i]);
+ }
+
+ // Finally, read in the raw data for the frame
+ //debug("Frame Data[%d]: Offset = %d, Size = %d", _curFrame, stream->pos(), _parent->sampleSizes[_curFrame]);
+
+ if (_parent->sampleSize != 0)
+ return stream->readStream(_parent->sampleSize);
+
+ return stream->readStream(_parent->sampleSizes[_curFrame]);
+}
+
+uint32 QuickTimeDecoder::VideoTrackHandler::getFrameDuration() {
+ uint32 curFrameIndex = 0;
+ for (int32 i = 0; i < _parent->timeToSampleCount; i++) {
+ curFrameIndex += _parent->timeToSample[i].count;
+ if ((uint32)_curFrame < curFrameIndex) {
+ // Ok, now we have what duration this frame has.
+ return _parent->timeToSample[i].duration;
+ }
+ }
+
+ // This should never occur
+ error("Cannot find duration for frame %d", _curFrame);
+ return 0;
+}
+
+uint32 QuickTimeDecoder::VideoTrackHandler::findKeyFrame(uint32 frame) const {
+ for (int i = _parent->keyframeCount - 1; i >= 0; i--)
+ if (_parent->keyframes[i] <= frame)
+ return _parent->keyframes[i];
+
+ // If none found, we'll assume the requested frame is a key frame
+ return frame;
+}
+
void QuickTimeDecoder::VideoTrackHandler::enterNewEditList(bool bufferFrames) {
// Bypass all empty edit lists first
while (!endOfTrack() && _parent->editList[_curEdit].mediaTime == -1)
@@ -667,166 +614,25 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::bufferNextFrame()
if (entry->_videoCodec->containsPalette()) {
// The codec itself contains a palette
if (entry->_videoCodec->hasDirtyPalette()) {
- _decoder->_palette = entry->_videoCodec->getPalette();
- _decoder->_dirtyPalette = true;
+ _curPalette = entry->_videoCodec->getPalette();
+ _dirtyPalette = true;
}
} else {
// Check if the video description has been updated
byte *palette = entry->_palette;
- if (palette !=_decoder-> _palette) {
- _decoder->_palette = palette;
- _decoder->_dirtyPalette = true;
- }
- }
-
- return frame;
-}
-
-uint32 QuickTimeDecoder::VideoTrackHandler::getNextFrameStartTime() {
- if (endOfTrack())
- return 0;
-
- // Convert to milliseconds so the tracks can be compared
- return getRateAdjustedFrameTime() * 1000 / _parent->timeScale;
-}
-
-uint32 QuickTimeDecoder::VideoTrackHandler::getFrameCount() {
- return _parent->frameCount;
-}
-
-uint32 QuickTimeDecoder::VideoTrackHandler::getFrameDuration() {
- uint32 curFrameIndex = 0;
- for (int32 i = 0; i < _parent->timeToSampleCount; i++) {
- curFrameIndex += _parent->timeToSample[i].count;
- if ((uint32)_curFrame < curFrameIndex) {
- // Ok, now we have what duration this frame has.
- return _parent->timeToSample[i].duration;
- }
- }
-
- // This should never occur
- error("Cannot find duration for frame %d", _curFrame);
- return 0;
-}
-
-Common::SeekableReadStream *QuickTimeDecoder::VideoTrackHandler::getNextFramePacket(uint32 &descId) {
- // First, we have to track down which chunk holds the sample and which sample in the chunk contains the frame we are looking for.
- int32 totalSampleCount = 0;
- int32 sampleInChunk = 0;
- int32 actualChunk = -1;
- uint32 sampleToChunkIndex = 0;
-
- for (uint32 i = 0; i < _parent->chunkCount; i++) {
- if (sampleToChunkIndex < _parent->sampleToChunkCount && i >= _parent->sampleToChunk[sampleToChunkIndex].first)
- sampleToChunkIndex++;
-
- totalSampleCount += _parent->sampleToChunk[sampleToChunkIndex - 1].count;
-
- if (totalSampleCount > _curFrame) {
- actualChunk = i;
- descId = _parent->sampleToChunk[sampleToChunkIndex - 1].id;
- sampleInChunk = _parent->sampleToChunk[sampleToChunkIndex - 1].count - totalSampleCount + _curFrame;
- break;
+ if (palette != _curPalette) {
+ _curPalette = palette;
+ _dirtyPalette = true;
}
}
- if (actualChunk < 0) {
- warning("Could not find data for frame %d", _curFrame);
- return 0;
- }
-
- // Next seek to that frame
- _fd->seek(_parent->chunkOffsets[actualChunk]);
-
- // Then, if the chunk holds more than one frame, seek to where the frame we want is located
- for (int32 i = _curFrame - sampleInChunk; i < _curFrame; i++) {
- if (_parent->sampleSize != 0)
- _fd->skip(_parent->sampleSize);
- else
- _fd->skip(_parent->sampleSizes[i]);
- }
-
- // Finally, read in the raw data for the frame
- //debug("Frame Data[%d]: Offset = %d, Size = %d", _curFrame, _fd->pos(), _parent->sampleSizes[_curFrame]);
-
- if (_parent->sampleSize != 0)
- return _fd->readStream(_parent->sampleSize);
-
- return _fd->readStream(_parent->sampleSizes[_curFrame]);
-}
-
-uint32 QuickTimeDecoder::VideoTrackHandler::findKeyFrame(uint32 frame) const {
- for (int i = _parent->keyframeCount - 1; i >= 0; i--)
- if (_parent->keyframes[i] <= frame)
- return _parent->keyframes[i];
-
- // If none found, we'll assume the requested frame is a key frame
return frame;
}
-void QuickTimeDecoder::VideoTrackHandler::seekToTime(Audio::Timestamp time) {
- // First, figure out what edit we're in
- time = time.convertToFramerate(_parent->timeScale);
-
- // Continue until we get to where we need to be
- for (_curEdit = 0; !endOfTrack(); _curEdit++)
- if ((uint32)time.totalNumberOfFrames() >= getCurEditTimeOffset() && (uint32)time.totalNumberOfFrames() < getCurEditTimeOffset() + getCurEditTrackDuration())
- break;
-
- // This track is done
- if (endOfTrack())
- return;
-
- enterNewEditList(false);
-
- // One extra check for the end of a track
- if (endOfTrack())
- return;
-
- // Now we're in the edit and need to figure out what frame we need
- while (getRateAdjustedFrameTime() < (uint32)time.totalNumberOfFrames()) {
- _curFrame++;
- if (_durationOverride >= 0) {
- _nextFrameStartTime += _durationOverride;
- _durationOverride = -1;
- } else {
- _nextFrameStartTime += getFrameDuration();
- }
- }
-
- // All that's left is to figure out what our starting time is going to be
- // Compare the starting point for the frame to where we need to be
- _holdNextFrameStartTime = getRateAdjustedFrameTime() != (uint32)time.totalNumberOfFrames();
-
- // If we went past the time, go back a frame
- if (_holdNextFrameStartTime)
- _curFrame--;
-
- // Handle the keyframe here
- int32 destinationFrame = _curFrame + 1;
-
- assert(destinationFrame < (int32)_parent->frameCount);
- _curFrame = findKeyFrame(destinationFrame) - 1;
- while (_curFrame < destinationFrame - 1)
- bufferNextFrame();
-}
-
-Common::Rational QuickTimeDecoder::VideoTrackHandler::getWidth() const {
- return Common::Rational(_parent->width) / _parent->scaleFactorX;
-}
-
-Common::Rational QuickTimeDecoder::VideoTrackHandler::getHeight() const {
- return Common::Rational(_parent->height) / _parent->scaleFactorY;
-}
-
-Graphics::PixelFormat QuickTimeDecoder::VideoTrackHandler::getPixelFormat() const {
- return ((VideoSampleDesc *)_parent->sampleDescs[0])->_videoCodec->getPixelFormat();
-}
-
uint32 QuickTimeDecoder::VideoTrackHandler::getRateAdjustedFrameTime() const {
// Figure out what time the next frame is at taking the edit list rate into account
- uint32 convertedTime = (Common::Rational(_nextFrameStartTime - getCurEditTimeOffset()) / _parent->editList[_curEdit].mediaRate).toInt();
+ uint32 convertedTime = (Common::Rational(_nextFrameStartTime - getCurEditTimeOffset()) / _parent->editList[_curEdit].mediaRate).toInt();
return convertedTime + getCurEditTimeOffset();
}
diff --git a/video/qt_decoder.h b/video/qt_decoder.h
index ce32562d64..7a251b8580 100644
--- a/video/qt_decoder.h
+++ b/video/qt_decoder.h
@@ -31,16 +31,17 @@
#ifndef VIDEO_QT_DECODER_H
#define VIDEO_QT_DECODER_H
-#include "audio/mixer.h"
#include "audio/decoders/quicktime_intern.h"
#include "common/scummsys.h"
-#include "common/rational.h"
-#include "graphics/pixelformat.h"
#include "video/video_decoder.h"
namespace Common {
- class Rational;
+class Rational;
+}
+
+namespace Graphics {
+struct PixelFormat;
}
namespace Video {
@@ -54,68 +55,33 @@ class Codec;
* - mohawk
* - sci
*/
-class QuickTimeDecoder : public SeekableVideoDecoder, public Audio::QuickTimeAudioDecoder {
+class QuickTimeDecoder : public AdvancedVideoDecoder, public Audio::QuickTimeAudioDecoder {
public:
QuickTimeDecoder();
virtual ~QuickTimeDecoder();
- /**
- * Returns the width of the video
- * @return the width of the video
- */
- uint16 getWidth() const { return _width; }
-
- /**
- * Returns the height of the video
- * @return the height of the video
- */
- uint16 getHeight() const { return _height; }
-
- /**
- * Returns the amount of frames in the video
- * @return the amount of frames in the video
- */
- uint32 getFrameCount() const;
-
- /**
- * Load a video file
- * @param filename the filename to load
- */
bool loadFile(const Common::String &filename);
-
- /**
- * Load a QuickTime video file from a SeekableReadStream
- * @param stream the stream to load
- */
bool loadStream(Common::SeekableReadStream *stream);
-
- /**
- * Close a QuickTime encoded video file
- */
void close();
+ uint16 getWidth() const { return _width; }
+ uint16 getHeight() const { return _height; }
+ const Graphics::Surface *decodeNextFrame();
+ Audio::Timestamp getDuration() const { return Audio::Timestamp(0, _duration, _timeScale); }
- /**
- * Returns the palette of the video
- * @return the palette of the video
- */
- const byte *getPalette() { _dirtyPalette = false; return _palette; }
- bool hasDirtyPalette() const { return _dirtyPalette; }
+protected:
+ Common::QuickTimeParser::SampleDesc *readSampleDesc(Common::QuickTimeParser::Track *track, uint32 format);
- int32 getCurFrame() const;
+private:
+ void init();
- bool isVideoLoaded() const { return isOpen(); }
- const Graphics::Surface *decodeNextFrame();
- bool endOfVideo() const;
- uint32 getTime() const;
- uint32 getTimeToNextFrame() const;
- Graphics::PixelFormat getPixelFormat() const;
+ void updateAudioBuffer();
- // SeekableVideoDecoder API
- void seekToFrame(uint32 frame);
- void seekToTime(const Audio::Timestamp &time);
- uint32 getDuration() const { return _duration * 1000 / _timeScale; }
+ uint16 _width, _height;
+
+ Graphics::Surface *_scaledSurface;
+ void scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst,
+ const Common::Rational &scaleFactorX, const Common::Rational &scaleFactorY);
-protected:
class VideoSampleDesc : public Common::QuickTimeParser::SampleDesc {
public:
VideoSampleDesc(Common::QuickTimeParser::Track *parentTrack, uint32 codecTag);
@@ -131,110 +97,59 @@ protected:
Codec *_videoCodec;
};
- Common::QuickTimeParser::SampleDesc *readSampleDesc(Track *track, uint32 format);
-
- // VideoDecoder API
- void updateVolume();
- void updateBalance();
-
-private:
- void init();
-
- void startAudio();
- void stopAudio();
- void updateAudioBuffer();
- void readNextAudioChunk();
- Common::Array<Audio::SoundHandle> _audioHandles;
- Audio::Timestamp _audioStartOffset;
-
- Codec *createCodec(uint32 codecTag, byte bitsPerPixel);
- uint32 findKeyFrame(uint32 frame) const;
-
- bool _dirtyPalette;
- const byte *_palette;
- bool _setStartTime;
- bool _needUpdate;
-
- uint16 _width, _height;
-
- Graphics::Surface *_scaledSurface;
- void scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst,
- Common::Rational scaleFactorX, Common::Rational scaleFactorY);
-
- void pauseVideoIntern(bool pause);
- bool endOfVideoTracks() const;
-
- // The TrackHandler is a class that wraps around a QuickTime Track
- // and handles playback in this decoder class.
- class TrackHandler {
- public:
- TrackHandler(QuickTimeDecoder *decoder, Track *parent);
- virtual ~TrackHandler() {}
-
- enum TrackType {
- kTrackTypeAudio,
- kTrackTypeVideo
- };
-
- virtual TrackType getTrackType() const = 0;
-
- virtual void seekToTime(Audio::Timestamp time) = 0;
-
- virtual bool endOfTrack();
-
- protected:
- uint32 _curEdit;
- QuickTimeDecoder *_decoder;
- Common::SeekableReadStream *_fd;
- Track *_parent;
- };
-
// The AudioTrackHandler is currently just a wrapper around some
// QuickTimeDecoder functions.
- class AudioTrackHandler : public TrackHandler {
+ class AudioTrackHandler : public SeekableAudioTrack {
public:
AudioTrackHandler(QuickTimeDecoder *decoder, QuickTimeAudioTrack *audioTrack);
- TrackType getTrackType() const { return kTrackTypeAudio; }
void updateBuffer();
- void seekToTime(Audio::Timestamp time);
- bool endOfTrack();
+
+ protected:
+ Audio::SeekableAudioStream *getSeekableAudioStream() const;
private:
+ QuickTimeDecoder *_decoder;
QuickTimeAudioTrack *_audioTrack;
};
// The VideoTrackHandler is the bridge between the time of playback
// and the media for the given track. It calculates when to start
// tracks and at what rate to play the media using the edit list.
- class VideoTrackHandler : public TrackHandler {
+ class VideoTrackHandler : public VideoTrack {
public:
- VideoTrackHandler(QuickTimeDecoder *decoder, Track *parent);
+ VideoTrackHandler(QuickTimeDecoder *decoder, Common::QuickTimeParser::Track *parent);
~VideoTrackHandler();
- TrackType getTrackType() const { return kTrackTypeVideo; }
-
- const Graphics::Surface *decodeNextFrame();
-
- uint32 getNextFrameStartTime();
-
- uint32 getFrameCount();
-
- int32 getCurFrame() { return _curFrame; }
+ bool endOfTrack() const;
+ bool isSeekable() const { return true; }
+ bool seek(const Audio::Timestamp &time);
+ Audio::Timestamp getDuration() const;
+ uint16 getWidth() const;
+ uint16 getHeight() const;
Graphics::PixelFormat getPixelFormat() const;
+ int getCurFrame() const { return _curFrame; }
+ int getFrameCount() const;
+ uint32 getNextFrameStartTime() const;
+ const Graphics::Surface *decodeNextFrame();
+ const byte *getPalette() const { _dirtyPalette = false; return _curPalette; }
+ bool hasDirtyPalette() const { return _curPalette; }
- void seekToTime(Audio::Timestamp time);
-
- Common::Rational getWidth() const;
- Common::Rational getHeight() const;
+ Common::Rational getScaledWidth() const;
+ Common::Rational getScaledHeight() const;
private:
+ QuickTimeDecoder *_decoder;
+ Common::QuickTimeParser::Track *_parent;
+ uint32 _curEdit;
int32 _curFrame;
uint32 _nextFrameStartTime;
Graphics::Surface *_scaledSurface;
bool _holdNextFrameStartTime;
int32 _durationOverride;
+ const byte *_curPalette;
+ mutable bool _dirtyPalette;
Common::SeekableReadStream *getNextFramePacket(uint32 &descId);
uint32 getFrameDuration();
@@ -245,12 +160,6 @@ private:
uint32 getCurEditTimeOffset() const;
uint32 getCurEditTrackDuration() const;
};
-
- Common::Array<TrackHandler *> _handlers;
- VideoTrackHandler *_nextVideoTrack;
- VideoTrackHandler *findNextVideoTrack() const;
-
- void freeAllTrackHandlers();
};
} // End of namespace Video