aboutsummaryrefslogtreecommitdiff
path: root/engines/sword25/fmv
diff options
context:
space:
mode:
authorMatthew Hoops2011-05-14 22:48:44 -0400
committerMatthew Hoops2011-05-15 02:20:49 -0400
commite6452518ddb13294c2b3264e9dc754c8ad6ff3ef (patch)
treead35443a058115ce8ae96bca09e511a100d6f174 /engines/sword25/fmv
parent0bcfbd3cbdc4910e40635846844b1d356b1ae82e (diff)
downloadscummvm-rg350-e6452518ddb13294c2b3264e9dc754c8ad6ff3ef.tar.gz
scummvm-rg350-e6452518ddb13294c2b3264e9dc754c8ad6ff3ef.tar.bz2
scummvm-rg350-e6452518ddb13294c2b3264e9dc754c8ad6ff3ef.zip
SWORD25: Begin fixing the TheoraDecoder implementation
getFrameRate() and endOfVideo() have been fixed so it can be used as a standalone decoder. a/v sync still needs to be fixed
Diffstat (limited to 'engines/sword25/fmv')
-rw-r--r--engines/sword25/fmv/movieplayer.cpp2
-rw-r--r--engines/sword25/fmv/theora_decoder.cpp117
-rw-r--r--engines/sword25/fmv/theora_decoder.h34
3 files changed, 56 insertions, 97 deletions
diff --git a/engines/sword25/fmv/movieplayer.cpp b/engines/sword25/fmv/movieplayer.cpp
index 2a55f6dd91..c60f5d4cbf 100644
--- a/engines/sword25/fmv/movieplayer.cpp
+++ b/engines/sword25/fmv/movieplayer.cpp
@@ -46,7 +46,7 @@ namespace Sword25 {
#define FLT_EPSILON 1.192092896e-07F /* smallest such that 1.0+FLT_EPSILON != 1.0 */
#ifdef USE_THEORADEC
-MoviePlayer::MoviePlayer(Kernel *pKernel) : Service(pKernel), _decoder(g_system->getMixer()) {
+MoviePlayer::MoviePlayer(Kernel *pKernel) : Service(pKernel), _decoder() {
if (!registerScriptBindings())
error("Script bindings could not be registered.");
else
diff --git a/engines/sword25/fmv/theora_decoder.cpp b/engines/sword25/fmv/theora_decoder.cpp
index 15e81af79c..f7e5e7ae25 100644
--- a/engines/sword25/fmv/theora_decoder.cpp
+++ b/engines/sword25/fmv/theora_decoder.cpp
@@ -51,7 +51,7 @@ static double rint(double v) {
return floor(v + 0.5);
}
-TheoraDecoder::TheoraDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : _mixer(mixer) {
+TheoraDecoder::TheoraDecoder(Audio::Mixer::SoundType soundType) {
_fileStream = 0;
_surface = 0;
@@ -59,7 +59,6 @@ TheoraDecoder::TheoraDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundT
_vorbisPacket = 0;
_theoraDecode = 0;
_theoraSetup = 0;
- _stateFlag = false;
_soundType = soundType;
_audStream = 0;
@@ -67,7 +66,7 @@ TheoraDecoder::TheoraDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundT
ogg_sync_init(&_oggSync);
- _curFrame = 0;
+ _curFrame = -1;
_audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t));
reset();
@@ -115,7 +114,8 @@ bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) {
// Ogg file open; parse the headers
// Only interested in Vorbis/Theora streams
- while (!_stateFlag) {
+ bool foundHeader = false;
+ while (!foundHeader) {
int ret = bufferData();
if (ret == 0)
@@ -128,7 +128,7 @@ bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) {
if (!ogg_page_bos(&_oggPage)) {
// don't leak the page; get it into the appropriate stream
queuePage(&_oggPage);
- _stateFlag = true;
+ foundHeader = true;
break;
}
@@ -280,15 +280,17 @@ bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) {
// open audio
if (_vorbisPacket) {
- _audStream = createAudioStream();
- if (_audStream && _mixer)
- _mixer->playStream(_soundType, _audHandle, _audStream);
+ _audStream = Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels);
+ if (_audStream)
+ g_system->getMixer()->playStream(_soundType, _audHandle, _audStream);
}
_surface = new Graphics::Surface();
-
_surface->create(_theoraInfo.frame_width, _theoraInfo.frame_height, g_system->getScreenFormat());
+ // Set the frame rate
+ _frameRate = Common::Rational(_theoraInfo.fps_numerator, _theoraInfo.fps_denominator);
+
return true;
}
@@ -300,8 +302,8 @@ void TheoraDecoder::close() {
vorbis_comment_clear(&_vorbisComment);
vorbis_info_clear(&_vorbisInfo);
- if (_mixer)
- _mixer->stopHandle(*_audHandle);
+ g_system->getMixer()->stopHandle(*_audHandle);
+
_audStream = 0;
_vorbisPacket = false;
}
@@ -372,7 +374,7 @@ const Graphics::Surface *TheoraDecoder::decodeNextFrame() {
}
}
- while (_theoraPacket && !_videobufReady) {
+ while (_theoraPacket && !_theoraOut.e_o_s) {
// theora is one in, one out...
if (ogg_stream_packetout(&_theoraOut, &_oggPacket) > 0) {
@@ -399,26 +401,28 @@ const Graphics::Surface *TheoraDecoder::decodeNextFrame() {
if (th_decode_packetin(_theoraDecode, &_oggPacket, NULL) == 0) {
#endif
_curFrame++;
- _videobufReady = true;
- }
- } else
- break;
- }
- if (!_videobufReady && !_audiobufReady && _fileStream->eos()) {
- return NULL;
- }
+ // Convert YUV data to RGB data
+ th_ycbcr_buffer yuv;
+ th_decode_ycbcr_out(_theoraDecode, yuv);
+ translateYUVtoRGBA(yuv);
- if (!_videobufReady || !_audiobufReady) {
- // no data yet for somebody. Grab another page
- bufferData();
- while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) {
- queuePage(&_oggPage);
+ if (_curFrame == 0)
+ _startTime = g_system->getMillis();
+
+ // break out
+ break;
+ }
+ } else {
+ // Queue more data
+ bufferData();
+ while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0)
+ queuePage(&_oggPage);
}
}
// If playback has begun, top audio buffer off immediately.
- if (_stateFlag && _audiobufReady) {
+ if (_audiobufReady) {
_audStream->queueBuffer((byte *)_audiobuf, AUDIOFD_FRAGSIZE, DisposeAfterUse::NO, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_STEREO);
// The audio mixer is now responsible for the old audio buffer.
@@ -428,39 +432,17 @@ const Graphics::Surface *TheoraDecoder::decodeNextFrame() {
_audiobufReady = false;
}
- // are we at or past time for this video frame?
- if (_stateFlag && _videobufReady) {
- th_ycbcr_buffer yuv;
-
- th_decode_ycbcr_out(_theoraDecode, yuv);
-
- // Convert YUV data to RGB data
- translateYUVtoRGBA(yuv, (byte *)_surface->getBasePtr(0, 0));
-
- _videobufReady = false;
- }
-
- // if our buffers either don't exist or are ready to go,
- // we can begin playback
- if ((!_theoraPacket || _videobufReady) &&
- (!_vorbisPacket || _audiobufReady))
- _stateFlag = true;
-
- // same if we've run out of input
- if (_fileStream->eos())
- _stateFlag = true;
-
return _surface;
}
void TheoraDecoder::reset() {
FixedRateVideoDecoder::reset();
+ // FIXME: This does a rewind() instead of a reset()!
+
if (_fileStream)
_fileStream->seek(0);
- _videobufReady = false;
-
#if ENABLE_THEORA_SEEKING
_videobufGranulePos = -1;
_audiobufGranulePos = 0;
@@ -470,36 +452,31 @@ void TheoraDecoder::reset() {
_audiobufFill = 0;
_audiobufReady = false;
- _curFrame = 0;
+ _curFrame = -1;
_theoraPacket = 0;
_vorbisPacket = 0;
- _stateFlag = false;
}
bool TheoraDecoder::endOfVideo() const {
- return !isVideoLoaded();
+ return !isVideoLoaded() || _theoraOut.e_o_s;
}
-
uint32 TheoraDecoder::getElapsedTime() const {
- if (_audStream && _mixer)
- return _mixer->getSoundElapsedTime(*_audHandle);
+ if (_audStream)
+ return g_system->getMixer()->getSoundElapsedTime(*_audHandle);
return FixedRateVideoDecoder::getElapsedTime();
}
-Audio::QueuingAudioStream *TheoraDecoder::createAudioStream() {
- return Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels);
-}
-
-static void convertYUVtoBGRA(int y, int u, int v, byte *dst) {
+static void convertYUVtoBGRA(int y, int u, int v, byte *dst, Graphics::PixelFormat format) {
byte r, g, b;
Graphics::YUV2RGB(y, u, v, r, g, b);
- *(dst + 0) = b;
- *(dst + 1) = g;
- *(dst + 2) = r;
- *(dst + 3) = 0xFF;
+
+ if (format.bytesPerPixel == 2)
+ *((uint16 *)dst) = format.RGBToColor(r, g, b);
+ else
+ *((uint32 *)dst) = format.RGBToColor(r, g, b);
}
enum TheoraYUVBuffers {
@@ -508,7 +485,7 @@ enum TheoraYUVBuffers {
kBufferV = 2
};
-void TheoraDecoder::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer, byte *pixelData) {
+void TheoraDecoder::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer) {
// Width and height of all buffers have to be divisible by 2.
assert((YUVBuffer[kBufferY].width & 1) == 0);
assert((YUVBuffer[kBufferY].height & 1) == 0);
@@ -524,10 +501,10 @@ void TheoraDecoder::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer, byte *pixelDa
const byte *ySrc = YUVBuffer[kBufferY].data;
const byte *uSrc = YUVBuffer[kBufferU].data;
const byte *vSrc = YUVBuffer[kBufferV].data;
- byte *dst = pixelData;
+ byte *dst = (byte *)_surface->pixels;
int u = 0, v = 0;
- const int blockSize = YUVBuffer[kBufferY].width << 2;
+ const int blockSize = YUVBuffer[kBufferY].width * getPixelFormat().bytesPerPixel;
const int halfHeight = YUVBuffer[kBufferY].height >> 1;
const int halfWidth = YUVBuffer[kBufferY].width >> 1;
const int yStep = (YUVBuffer[kBufferY].stride << 1) - YUVBuffer[kBufferY].width;
@@ -543,8 +520,8 @@ void TheoraDecoder::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer, byte *pixelDa
v = *vSrc++;
for (int i = 0; i <= 1; i++) {
- convertYUVtoBGRA(*ySrc, u, v, dst);
- convertYUVtoBGRA(*(ySrc + stride), u, v, dst + blockSize);
+ convertYUVtoBGRA(*ySrc, u, v, dst, getPixelFormat());
+ convertYUVtoBGRA(*(ySrc + stride), u, v, dst + blockSize, getPixelFormat());
ySrc++;
dst += 4; // BGRA
}
diff --git a/engines/sword25/fmv/theora_decoder.h b/engines/sword25/fmv/theora_decoder.h
index d8da024ab9..a1ce3ae473 100644
--- a/engines/sword25/fmv/theora_decoder.h
+++ b/engines/sword25/fmv/theora_decoder.h
@@ -53,7 +53,7 @@ namespace Sword25 {
*/
class TheoraDecoder : public Video::FixedRateVideoDecoder {
public:
- TheoraDecoder(Audio::Mixer *mixer = 0, Audio::Mixer::SoundType soundType = Audio::Mixer::kMusicSoundType);
+ TheoraDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kMusicSoundType);
virtual ~TheoraDecoder();
/**
@@ -71,43 +71,30 @@ public:
*/
const Graphics::Surface *decodeNextFrame();
- bool isVideoLoaded() const {
- return _fileStream != 0;
- }
- bool isPaused() const {
- return (FixedRateVideoDecoder::isPaused() || !isVideoLoaded());
- }
+ bool isVideoLoaded() const { return _fileStream != 0; }
+ uint16 getWidth() const { return _surface->w; }
+ uint16 getHeight() const { return _surface->h; }
- uint16 getWidth() const {
- return _surface->w;
- }
- uint16 getHeight() const {
- return _surface->h;
- }
uint32 getFrameCount() const {
// It is not possible to get frame count easily
// I.e. seeking is required
assert(0);
return 0;
}
- Graphics::PixelFormat getPixelFormat() const {
- return Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24);
- }
+
+ Graphics::PixelFormat getPixelFormat() const { return _surface->format; }
uint32 getElapsedTime() const;
bool endOfVideo() const;
protected:
- Common::Rational getFrameRate() const {
- return _frameRate;
- }
+ Common::Rational getFrameRate() const { return _frameRate; }
private:
void queuePage(ogg_page *page);
int bufferData();
- Audio::QueuingAudioStream *createAudioStream();
- void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer, byte *pixelData);
+ void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer);
private:
Common::SeekableReadStream *_fileStream;
@@ -115,7 +102,6 @@ private:
Common::Rational _frameRate;
uint32 _frameCount;
- Audio::Mixer *_mixer;
Audio::Mixer::SoundType _soundType;
Audio::SoundHandle *_audHandle;
Audio::QueuingAudioStream *_audStream;
@@ -136,15 +122,11 @@ private:
int _theoraPacket;
int _vorbisPacket;
- bool _stateFlag;
int _ppLevelMax;
int _ppLevel;
int _ppInc;
- // single frame video buffering
- bool _videobufReady;
-
// single audio fragment audio buffering
int _audiobufFill;
bool _audiobufReady;