aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Hoops2010-05-18 14:59:20 +0000
committerMatthew Hoops2010-05-18 14:59:20 +0000
commitbddceced34f829b0640d1aecacac1e1079eb0839 (patch)
tree12bcea940ae7ad30cd3e905d523db51faa9a2ec8
parent6499ddff8e2be705f3be53ab391178ec4c3764f2 (diff)
downloadscummvm-rg350-bddceced34f829b0640d1aecacac1e1079eb0839.tar.gz
scummvm-rg350-bddceced34f829b0640d1aecacac1e1079eb0839.tar.bz2
scummvm-rg350-bddceced34f829b0640d1aecacac1e1079eb0839.zip
Have QTPlayer inherit from VideoDecoder. The video downscaling (QuickTime is insane) has also been moved to the QTPlayer class.
svn-id: r49081
-rw-r--r--engines/mohawk/video/qt_player.cpp146
-rw-r--r--engines/mohawk/video/qt_player.h79
-rw-r--r--engines/mohawk/video/video.cpp36
3 files changed, 145 insertions, 116 deletions
diff --git a/engines/mohawk/video/qt_player.cpp b/engines/mohawk/video/qt_player.cpp
index 803da4f5f1..b19343005e 100644
--- a/engines/mohawk/video/qt_player.cpp
+++ b/engines/mohawk/video/qt_player.cpp
@@ -56,36 +56,38 @@ namespace Mohawk {
// QTPlayer
////////////////////////////////////////////
-QTPlayer::QTPlayer() {
+QTPlayer::QTPlayer() : Graphics::VideoDecoder() {
_audStream = NULL;
_beginOffset = 0;
_videoCodec = NULL;
- _noCodecFound = false;
_curFrame = -1;
- _lastFrameStart = _nextFrameStart = 0;
+ _startTime = _nextFrameStartTime = 0;
_audHandle = Audio::SoundHandle();
_numStreams = 0;
+ _fd = 0;
+ _scaledSurface = 0;
+ _dirtyPalette = false;
}
QTPlayer::~QTPlayer() {
- stop();
+ close();
}
-uint16 QTPlayer::getWidth() {
+uint16 QTPlayer::getWidth() const {
if (_videoStreamIndex < 0)
return 0;
- return _streams[_videoStreamIndex]->width;
+ return _streams[_videoStreamIndex]->width / getScaleMode();
}
-uint16 QTPlayer::getHeight() {
+uint16 QTPlayer::getHeight() const {
if (_videoStreamIndex < 0)
return 0;
- return _streams[_videoStreamIndex]->height;
+ return _streams[_videoStreamIndex]->height / getScaleMode();
}
-uint32 QTPlayer::getFrameCount() {
+uint32 QTPlayer::getFrameCount() const {
if (_videoStreamIndex < 0)
return 0;
@@ -106,7 +108,7 @@ uint32 QTPlayer::getCodecTag() {
return _streams[_videoStreamIndex]->codec_tag;
}
-ScaleMode QTPlayer::getScaleMode() {
+ScaleMode QTPlayer::getScaleMode() const {
if (_videoStreamIndex < 0)
return kScaleNormal;
@@ -121,8 +123,8 @@ uint32 QTPlayer::getFrameDuration() {
for (int32 i = 0; i < _streams[_videoStreamIndex]->stts_count; i++) {
curFrameIndex += _streams[_videoStreamIndex]->stts_data[i].count;
if ((uint32)_curFrame < curFrameIndex) {
- // Ok, now we have what duration this frame has. Now, we have to convert the duration to 1/100 ms.
- return _streams[_videoStreamIndex]->stts_data[i].duration * 1000 * 100 / _streams[_videoStreamIndex]->time_scale;
+ // Ok, now we have what duration this frame has.
+ return _streams[_videoStreamIndex]->stts_data[i].duration;
}
}
@@ -131,20 +133,17 @@ uint32 QTPlayer::getFrameDuration() {
return 0;
}
-void QTPlayer::stop() {
- stopAudio();
-
- if (!_noCodecFound)
- delete _videoCodec;
+Graphics::PixelFormat QTPlayer::getPixelFormat() const {
+ if (!_videoCodec)
+ return Graphics::PixelFormat::createFormatCLUT8();
- closeFile();
+ return _videoCodec->getPixelFormat();
}
-void QTPlayer::reset() {
+void QTPlayer::rewind() {
delete _videoCodec; _videoCodec = NULL;
- _noCodecFound = false;
_curFrame = -1;
- _lastFrameStart = _nextFrameStart = 0;
+ _startTime = _nextFrameStartTime = 0;
// Restart the audio too
stopAudio();
@@ -207,57 +206,82 @@ void QTPlayer::stopAudio() {
_audStream = NULL; // the mixer automatically frees the stream
}
-Graphics::Surface *QTPlayer::getNextFrame() {
- if (_noCodecFound || _curFrame >= (int32)getFrameCount() - 1)
+Graphics::Surface *QTPlayer::decodeNextFrame() {
+ if (!_videoCodec || _curFrame >= (int32)getFrameCount() - 1)
return NULL;
- if (_nextFrameStart == 0)
- _nextFrameStart = g_system->getMillis() * 100;
+ if (_startTime == 0)
+ _startTime = g_system->getMillis();
- _lastFrameStart = _nextFrameStart;
_curFrame++;
- _nextFrameStart = getFrameDuration() + _lastFrameStart;
+ _nextFrameStartTime += getFrameDuration();
Common::SeekableReadStream *frameData = getNextFramePacket();
- if (!_videoCodec) {
- _videoCodec = createCodec(getCodecTag(), getBitsPerPixel());
- // If we don't get it still, the codec is unsupported ;)
- if (!_videoCodec) {
- _noCodecFound = true;
- return NULL;
- }
- }
-
if (frameData) {
Graphics::Surface *frame = _videoCodec->decodeImage(frameData);
delete frameData;
- return frame;
+ return scaleSurface(frame);
}
return NULL;
}
-bool QTPlayer::endOfVideo() {
- return (!_audStream || _audStream->endOfData()) && (_noCodecFound || _curFrame >= (int32)getFrameCount() - 1);
+Graphics::Surface *QTPlayer::scaleSurface(Graphics::Surface *frame) {
+ if (getScaleMode() == kScaleNormal)
+ return frame;
+
+ assert(_scaledSurface);
+
+ for (uint32 j = 0; j < _scaledSurface->h; j++)
+ for (uint32 k = 0; k < _scaledSurface->w; k++)
+ memcpy(_scaledSurface->getBasePtr(k, j), frame->getBasePtr(k * getScaleMode(), j * getScaleMode()), frame->bytesPerPixel);
+
+ return _scaledSurface;
}
-bool QTPlayer::needsUpdate() {
- if (endOfVideo())
- return false;
+bool QTPlayer::endOfVideo() const {
+ return (!_audStream || _audStream->endOfData()) && (!_videoCodec || _curFrame >= (int32)getFrameCount() - 1);
+}
- if (_curFrame == -1)
- return true;
+void QTPlayer::addPauseTime(uint32 p) {
+ Graphics::VideoDecoder::addPauseTime(p);
+ if (_videoStreamIndex >= 0)
+ _nextFrameStartTime += p * _streams[_videoStreamIndex]->time_scale / 1000;
+}
+
+bool QTPlayer::needsUpdate() const {
+ return !endOfVideo() && getTimeToNextFrame() == 0;
+}
+
+uint32 QTPlayer::getElapsedTime() const {
+ if (_audStream)
+ return g_system->getMixer()->getSoundElapsedTime(_audHandle);
+
+ return g_system->getMillis() - _startTime;
+}
+
+uint32 QTPlayer::getTimeToNextFrame() const {
+ if (endOfVideo() || _curFrame < 0)
+ return 0;
+
+ // Convert from the Sega FILM base to 1000
+ uint32 nextFrameStartTime = _nextFrameStartTime * 1000 / _streams[_videoStreamIndex]->time_scale;
+ uint32 elapsedTime = getElapsedTime();
+
+ if (nextFrameStartTime <= elapsedTime)
+ return 0;
- return (g_system->getMillis() * 100 - _lastFrameStart) >= getFrameDuration();
+ return nextFrameStartTime - elapsedTime;
}
-bool QTPlayer::loadFile(Common::SeekableReadStream *stream) {
- _fd = stream;
+bool QTPlayer::load(Common::SeekableReadStream &stream) {
+ _fd = &stream;
_foundMOOV = _foundMDAT = false;
_numStreams = 0;
_partial = 0;
_videoStreamIndex = _audioStreamIndex = -1;
+ _startTime = 0;
initParseTable();
@@ -313,6 +337,18 @@ bool QTPlayer::loadFile(Common::SeekableReadStream *stream) {
// Make sure the bits per sample transfers to the sample size
if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('raw ') || _streams[_audioStreamIndex]->codec_tag == MKID_BE('twos'))
_streams[_audioStreamIndex]->sample_size = (_streams[_audioStreamIndex]->bits_per_sample / 8) * _streams[_audioStreamIndex]->channels;
+
+ startAudio();
+ }
+
+ if (_videoStreamIndex >= 0) {
+ _videoCodec = createCodec(getCodecTag(), getBitsPerPixel());
+
+ if (getScaleMode() != kScaleNormal) {
+ // We have to initialize the scaled surface
+ _scaledSurface = new Graphics::Surface();
+ _scaledSurface->create(getWidth(), getHeight(), getPixelFormat().bytesPerPixel);
+ }
}
return true;
@@ -785,6 +821,8 @@ int QTPlayer::readSTSD(MOVatom atom) {
// if the depth is 2, 4, or 8 bpp, file is palettized
if (colorDepth == 2 || colorDepth == 4 || colorDepth == 8) {
+ _dirtyPalette = true;
+
if (colorGreyscale) {
debug(0, "Greyscale palette");
@@ -1078,14 +1116,26 @@ int QTPlayer::readWAVE(MOVatom atom) {
return 0;
}
-void QTPlayer::closeFile() {
+void QTPlayer::close() {
+ stopAudio();
+
+ delete _videoCodec; _videoCodec = 0;
+
for (uint32 i = 0; i < _numStreams; i++)
delete _streams[i];
delete _fd;
+ if (_scaledSurface) {
+ _scaledSurface->free();
+ delete _scaledSurface;
+ _scaledSurface = 0;
+ }
+
// The audio stream is deleted automatically
_audStream = NULL;
+
+ Graphics::VideoDecoder::reset();
}
Common::SeekableReadStream *QTPlayer::getNextFramePacket() {
diff --git a/engines/mohawk/video/qt_player.h b/engines/mohawk/video/qt_player.h
index ce780e22e2..5234f7cc59 100644
--- a/engines/mohawk/video/qt_player.h
+++ b/engines/mohawk/video/qt_player.h
@@ -36,7 +36,10 @@
#include "common/scummsys.h"
#include "common/queue.h"
+
+#include "graphics/video/video_decoder.h"
#include "graphics/video/codecs/codec.h"
+
#include "sound/audiostream.h"
#include "sound/mixer.h"
@@ -52,7 +55,7 @@ enum ScaleMode {
kScaleQuarter = 4
};
-class QTPlayer {
+class QTPlayer : public Graphics::VideoDecoder {
public:
QTPlayer();
virtual ~QTPlayer();
@@ -61,54 +64,37 @@ public:
* Returns the width of the video
* @return the width of the video
*/
- uint16 getWidth();
+ uint16 getWidth() const;
/**
* Returns the height of the video
* @return the height of the video
*/
- uint16 getHeight();
+ uint16 getHeight() const;
/**
* Returns the amount of frames in the video
* @return the amount of frames in the video
*/
- uint32 getFrameCount();
-
- /**
- * Returns the bits per pixel of the video
- * @return the bits per pixel of the video
- */
- byte getBitsPerPixel();
-
- /**
- * Returns the codec tag of the video
- * @return the codec tag of the video
- */
- uint32 getCodecTag();
+ uint32 getFrameCount() const;
/**
* Load a QuickTime video file from a SeekableReadStream
* @param stream the stream to load
*/
- bool loadFile(Common::SeekableReadStream* stream);
+ bool load(Common::SeekableReadStream &stream);
/**
* Close a QuickTime encoded video file
*/
- void closeFile();
-
- /**
- * Returns the downscale mode of the video
- * @return the downscale mode of the video
- */
- ScaleMode getScaleMode();
+ void close();
/**
* Returns the palette of the video
* @return the palette of the video
*/
- byte *getPalette() { return _palette; }
+ byte *getPalette() { _dirtyPalette = false; return _palette; }
+ bool hasDirtyPalette() const { return _dirtyPalette; }
/**
* Set the beginning offset of the video so we can modify the offsets in the stco
@@ -117,18 +103,22 @@ public:
*/
void setChunkBeginOffset(uint32 offset) { _beginOffset = offset; }
- int32 getCurFrame() { return _curFrame; }
- void addPauseTime(uint32 p) { _lastFrameStart += p; _nextFrameStart += p; }
- Graphics::Surface *getNextFrame();
- void updateAudioBuffer();
- void startAudio();
- void stopAudio();
+ bool isVideoLoaded() const { return _fd != 0; }
+ void addPauseTime(uint32 p);
+ Graphics::Surface *decodeNextFrame();
+ bool needsUpdate() const;
+ bool endOfVideo() const;
+ uint32 getElapsedTime() const;
+ uint32 getTimeToNextFrame() const;
+ Graphics::PixelFormat getPixelFormat() const;
+
+ void rewind(); // For a future RewindableVideoDecoder class
+
+ // TODO: These audio functions need to be removed from the public and/or added to
+ // the VideoDecoder API directly.
+ void updateAudioBuffer(); // This is going to be problematic.
void pauseAudio();
void resumeAudio();
- bool needsUpdate();
- bool endOfVideo();
- void stop();
- void reset();
protected:
// This is the file handle from which data is read from. It can be the actual file handle or a decompressed stream.
@@ -238,25 +228,32 @@ protected:
ScaleMode _scaleMode;
MOVStreamContext *_streams[20];
byte _palette[256 * 4];
+ bool _dirtyPalette;
+ uint32 _beginOffset;
void initParseTable();
Audio::AudioStream *createAudioStream(Common::SeekableReadStream *stream);
bool checkAudioCodecSupport(uint32 tag);
Common::SeekableReadStream *getNextFramePacket();
uint32 getFrameDuration();
+ uint32 getCodecTag();
+ byte getBitsPerPixel();
Audio::QueuingAudioStream *_audStream;
- int8 _videoStreamIndex;
+ void startAudio();
+ void stopAudio();
int8 _audioStreamIndex;
uint _curAudioChunk;
- uint32 _beginOffset;
+ Audio::SoundHandle _audHandle;
Graphics::Codec *createCodec(uint32 codecTag, byte bitsPerPixel);
Graphics::Codec *_videoCodec;
- bool _noCodecFound;
- int32 _curFrame;
- uint32 _lastFrameStart, _nextFrameStart; // In 1/100 ms
- Audio::SoundHandle _audHandle;
+ uint32 _nextFrameStartTime;
+ int8 _videoStreamIndex;
+
+ Graphics::Surface *_scaledSurface;
+ Graphics::Surface *scaleSurface(Graphics::Surface *frame);
+ ScaleMode getScaleMode() const;
int readDefault(MOVatom atom);
int readLeaf(MOVatom atom);
diff --git a/engines/mohawk/video/video.cpp b/engines/mohawk/video/video.cpp
index c0206a5f06..c4991ec06c 100644
--- a/engines/mohawk/video/video.cpp
+++ b/engines/mohawk/video/video.cpp
@@ -126,7 +126,7 @@ void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) {
_vm->_system->delayMillis(10);
}
- _videoStreams[videoHandle]->stop();
+ _videoStreams[videoHandle]->close();
_videoStreams.clear();
}
@@ -155,7 +155,7 @@ bool VideoManager::updateBackgroundMovies() {
// Remove any videos that are over
if (_videoStreams[i]->endOfVideo()) {
if (_videoStreams[i].loop) {
- _videoStreams[i]->reset();
+ _videoStreams[i]->rewind();
} else {
delete _videoStreams[i].video;
memset(&_videoStreams[i], 0, sizeof(VideoEntry));
@@ -166,7 +166,7 @@ bool VideoManager::updateBackgroundMovies() {
// Check if we need to draw a frame
if (_videoStreams[i]->needsUpdate()) {
- Graphics::Surface *frame = _videoStreams[i]->getNextFrame();
+ Graphics::Surface *frame = _videoStreams[i]->decodeNextFrame();
bool deleteFrame = false;
if (frame && _videoStreams[i].enabled) {
@@ -196,26 +196,10 @@ bool VideoManager::updateBackgroundMovies() {
deleteFrame = true;
}
- // Check if we're drawing at a 2x or 4x resolution (because of
- // evil QuickTime scaling it first).
- if (_videoStreams[i]->getScaleMode() == kScaleHalf || _videoStreams[i]->getScaleMode() == kScaleQuarter) {
- byte scaleFactor = (_videoStreams[i]->getScaleMode() == kScaleHalf) ? 2 : 4;
-
- Graphics::Surface scaledSurf;
- scaledSurf.create(_videoStreams[i]->getWidth() / scaleFactor, _videoStreams[i]->getHeight() / scaleFactor, frame->bytesPerPixel);
-
- for (uint32 j = 0; j < scaledSurf.h; j++)
- for (uint32 k = 0; k < scaledSurf.w; k++)
- memcpy(scaledSurf.getBasePtr(k, j), frame->getBasePtr(k * scaleFactor, j * scaleFactor), frame->bytesPerPixel);
-
- _vm->_system->copyRectToScreen((byte*)scaledSurf.pixels, scaledSurf.pitch, _videoStreams[i].x, _videoStreams[i].y, scaledSurf.w, scaledSurf.h);
- scaledSurf.free();
- } else {
- // Clip the width/height to make sure we stay on the screen (Myst does this a few times)
- uint16 width = MIN<int32>(_videoStreams[i]->getWidth(), _vm->_system->getWidth() - _videoStreams[i].x);
- uint16 height = MIN<int32>(_videoStreams[i]->getHeight(), _vm->_system->getHeight() - _videoStreams[i].y);
- _vm->_system->copyRectToScreen((byte*)frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height);
- }
+ // Clip the width/height to make sure we stay on the screen (Myst does this a few times)
+ uint16 width = MIN<int32>(_videoStreams[i]->getWidth(), _vm->_system->getWidth() - _videoStreams[i].x);
+ uint16 height = MIN<int32>(_videoStreams[i]->getHeight(), _vm->_system->getHeight() - _videoStreams[i].y);
+ _vm->_system->copyRectToScreen((byte*)frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height);
// We've drawn something to the screen, make sure we update it
updateScreen = true;
@@ -346,8 +330,7 @@ VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool
entry.loop = loop;
entry.enabled = true;
entry->setChunkBeginOffset(_vm->getResourceOffset(ID_TMOV, id));
- entry->loadFile(_vm->getRawData(ID_TMOV, id));
- entry->startAudio();
+ entry->load(*_vm->getRawData(ID_TMOV, id));
// Search for any deleted videos so we can take a formerly used slot
for (uint32 i = 0; i < _videoStreams.size(); i++)
@@ -383,8 +366,7 @@ VideoHandle VideoManager::createVideoHandle(Common::String filename, uint16 x, u
return NULL_VID_HANDLE;
}
- entry->loadFile(file);
- entry->startAudio();
+ entry->load(*file);
// Search for any deleted videos so we can take a formerly used slot
for (uint32 i = 0; i < _videoStreams.size(); i++)