aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorEinar Johan Trøan Sømåen2012-08-31 13:49:38 +0200
committerEinar Johan Trøan Sømåen2012-08-31 13:49:38 +0200
commit16b27090b1c7dc11cdc199b1a98c0f2973db5f45 (patch)
tree795fe24dc2097801bbb773a907fd465bc23e9499 /engines
parent3fe7f2cbe2b70eaa824b7159d94d40c2280006a3 (diff)
downloadscummvm-rg350-16b27090b1c7dc11cdc199b1a98c0f2973db5f45.tar.gz
scummvm-rg350-16b27090b1c7dc11cdc199b1a98c0f2973db5f45.tar.bz2
scummvm-rg350-16b27090b1c7dc11cdc199b1a98c0f2973db5f45.zip
WINTERMUTE: Update to use new TGA-decoder and new Video-system
Diffstat (limited to 'engines')
-rw-r--r--engines/wintermute/base/gfx/base_image.cpp4
-rw-r--r--engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp2
-rw-r--r--engines/wintermute/graphics/tga.cpp164
-rw-r--r--engines/wintermute/graphics/tga.h59
-rw-r--r--engines/wintermute/module.mk2
-rw-r--r--engines/wintermute/video/decoders/theora_decoder.cpp570
-rw-r--r--engines/wintermute/video/decoders/theora_decoder.h147
-rw-r--r--engines/wintermute/video/video_theora_player.cpp21
-rw-r--r--engines/wintermute/video/video_theora_player.h2
9 files changed, 17 insertions, 954 deletions
diff --git a/engines/wintermute/base/gfx/base_image.cpp b/engines/wintermute/base/gfx/base_image.cpp
index ec52e26c00..1184d2bbf7 100644
--- a/engines/wintermute/base/gfx/base_image.cpp
+++ b/engines/wintermute/base/gfx/base_image.cpp
@@ -32,8 +32,8 @@
#include "graphics/decoders/png.h"
#include "graphics/decoders/jpeg.h"
#include "graphics/decoders/bmp.h"
+#include "graphics/decoders/tga.h"
#include "graphics/surface.h"
-#include "engines/wintermute/graphics/tga.h"
#include "common/textconsole.h"
#include "common/stream.h"
#include "common/system.h"
@@ -69,7 +69,7 @@ bool BaseImage::loadFile(const Common::String &filename) {
} else if (_filename.hasSuffix(".bmp")) {
_decoder = new Graphics::BitmapDecoder();
} else if (_filename.hasSuffix(".tga")) {
- _decoder = new Wintermute::TGA();
+ _decoder = new Graphics::TGADecoder();
} else if (_filename.hasSuffix(".jpg")) {
_decoder = new Graphics::JPEGDecoder();
} else {
diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
index 5b0f7c94c3..f0ec41a265 100644
--- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
+++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
@@ -36,8 +36,8 @@
#include "graphics/decoders/png.h"
#include "graphics/decoders/bmp.h"
#include "graphics/decoders/jpeg.h"
+#include "graphics/decoders/tga.h"
#include "engines/wintermute/graphics/transparent_surface.h"
-#include "engines/wintermute/graphics/tga.h"
#include "graphics/pixelformat.h"
#include "graphics/surface.h"
#include "common/stream.h"
diff --git a/engines/wintermute/graphics/tga.cpp b/engines/wintermute/graphics/tga.cpp
deleted file mode 100644
index 8c3868c023..0000000000
--- a/engines/wintermute/graphics/tga.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* Based on code from eos https://github.com/DrMcCoy/xoreos/
- * relicensed under GPLv2+ with permission from DrMcCoy and clone2727
- */
-
-#include "common/util.h"
-#include "common/stream.h"
-#include "common/textconsole.h"
-#include "common/error.h"
-
-#include "engines/wintermute/graphics/tga.h"
-
-namespace Wintermute {
-
-TGA::TGA() {
-
-}
-
-TGA::~TGA() {
- destroy();
-}
-
-void TGA::destroy() {
- _surface.free();
-}
-
-bool TGA::loadStream(Common::SeekableReadStream &tga) {
- byte imageType, pixelDepth;
- bool success;
- success = readHeader(tga, imageType, pixelDepth);
- success = readData(tga, imageType, pixelDepth);
-
- if (tga.err() || !success) {
- warning("Failed reading TGA-file");
- return false;
- }
- return success;
-}
-
-bool TGA::readHeader(Common::SeekableReadStream &tga, byte &imageType, byte &pixelDepth) {
- if (!tga.seek(0)) {
- warning("Failed reading TGA-file");
- return false;
- }
-
- // TGAs have an optional "id" string in the header
- uint32 idLength = tga.readByte();
-
- // Number of colors in the color map / palette
- if (tga.readByte() != 0) {
- warning("Unsupported feature: Color map");
- return false;
- }
-
- // Image type. 2 == unmapped RGB, 3 == Grayscale
- imageType = tga.readByte();
- if ((imageType != 2) && (imageType != 3)) {
- warning("Unsupported image type: %d", imageType);
- return false;
- }
-
- // Color map specifications + X + Y
- tga.skip(5 + 2 + 2);
-
- // Image dimensions
- _surface.w = tga.readUint16LE();
- _surface.h = tga.readUint16LE();
-
- // Bits per pixel
- pixelDepth = tga.readByte();
- _surface.format.bytesPerPixel = pixelDepth / 8;
-
- if (imageType == 2) {
- if (pixelDepth == 24) {
- _hasAlpha = false;
- _format = Graphics::PixelFormat(pixelDepth / 8, 8, 8, 8, 0, 16, 8, 0, 0);
- } else if (pixelDepth == 16 || pixelDepth == 32) {
- _hasAlpha = true;
- _format = Graphics::PixelFormat(pixelDepth / 8, 8, 8, 8, 8, 24, 16, 8, 0);
- } else {
- warning("Unsupported pixel depth: %d, %d", imageType, pixelDepth);
- return false;
- }
- } else if (imageType == 3) {
- if (pixelDepth != 8) {
- warning("Unsupported pixel depth: %d, %d", imageType, pixelDepth);
- return false;
- }
-
- _hasAlpha = false;
- _format = Graphics::PixelFormat(1, 0, 0, 0, 0, 0, 0, 0, 0);
- }
-
- // Image descriptor
- tga.skip(1);
-
- // Skip the id string
- tga.skip(idLength);
- return true;
-}
-
-bool TGA::readData(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth) {
- if (imageType == 2) {
- _surface.create(_surface.w, _surface.h, _format);
-
- if (pixelDepth == 16) {
- // Convert from 16bpp to 32bpp
- // 16bpp TGA is ARGB1555
- uint16 count = _surface.w * _surface.h;
- byte *dst = (byte *)_surface.pixels;
-
- while (count--) {
- uint16 pixel = tga.readUint16LE();
-
- *dst++ = (pixel & 0x1F) << 3;
- *dst++ = (pixel & 0x3E0) >> 2;
- *dst++ = (pixel & 0x7C00) >> 7;
- *dst++ = (pixel & 0x8000) ? 0xFF : 0x00;
- }
-
- } else {
- // Read it in raw
- tga.read(_surface.pixels, _surface.pitch * _surface.w);
- }
- } else if (imageType == 3) {
- _surface.create(_surface.w, _surface.h, _surface.format);
-
- byte *data = (byte *)_surface.pixels;
- uint32 count = _surface.w * _surface.h;
-
- while (count-- > 0) {
- byte g = tga.readByte();
-
- memset(data, g, 3);
- data[3] = 0xFF;
-
- data += 4;
- }
-
- }
- return true;
-}
-
-} // End of namespace Graphics
diff --git a/engines/wintermute/graphics/tga.h b/engines/wintermute/graphics/tga.h
deleted file mode 100644
index 5e118f2338..0000000000
--- a/engines/wintermute/graphics/tga.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* Based on code from eos https://github.com/DrMcCoy/xoreos/
- * relicensed under GPLv2+ with permission from DrMcCoy and clone2727
- */
-
-#ifndef WINTERMUTE_GRAPHICS_IMAGES_TGA_H
-#define WINTERMUTE_GRAPHICS_IMAGES_TGA_H
-
-#include "graphics/surface.h"
-#include "graphics/decoders/image_decoder.h"
-
-namespace Common {
-class SeekableReadStream;
-}
-
-namespace Wintermute {
-
-/** TarGa image. */
-class TGA : public Graphics::ImageDecoder {
-public:
- TGA();
- virtual ~TGA();
- virtual void destroy();
- virtual const Graphics::Surface *getSurface() const {
- return &_surface;
- };
- virtual bool loadStream(Common::SeekableReadStream &stream);
-private:
- Graphics::PixelFormat _format;
- bool _hasAlpha;
- Graphics::Surface _surface;
- // Loading helpers
- bool readHeader(Common::SeekableReadStream &tga, byte &imageType, byte &pixelDepth);
- bool readData(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth);
-};
-
-} // End of namespace Graphics
-
-#endif // GRAPHICS_IMAGES_TGA_H
diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk
index ee36e4d7a6..7b5b1b1a3a 100644
--- a/engines/wintermute/module.mk
+++ b/engines/wintermute/module.mk
@@ -87,7 +87,6 @@ MODULE_OBJS := \
base/saveload.o \
detection.o \
graphics/transparent_surface.o \
- graphics/tga.o \
math/math_util.o \
math/matrix4.o \
math/vector2.o \
@@ -109,7 +108,6 @@ MODULE_OBJS := \
utils/utils.o \
video/video_player.o \
video/video_theora_player.o \
- video/decoders/theora_decoder.o \
wintermute.o \
persistent.o
diff --git a/engines/wintermute/video/decoders/theora_decoder.cpp b/engines/wintermute/video/decoders/theora_decoder.cpp
deleted file mode 100644
index 6267e300f9..0000000000
--- a/engines/wintermute/video/decoders/theora_decoder.cpp
+++ /dev/null
@@ -1,570 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-/*
- * Source is based on the player example from libvorbis package,
- * available at: http://svn.xiph.org/trunk/theora/examples/player_example.c
- *
- * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE.
- * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS
- * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE
- * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.
- *
- * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009
- * by the Xiph.Org Foundation and contributors http://www.xiph.org/
- *
- */
-
-#include "engines/wintermute/video/decoders/theora_decoder.h"
-
-#ifdef USE_THEORADEC
-#include "common/system.h"
-#include "common/textconsole.h"
-#include "common/util.h"
-#include "graphics/yuv_to_rgb.h"
-#include "audio/decoders/raw.h"
-#include "common/stream.h"
-#include "common/debug.h"
-
-namespace Wintermute {
-
-#define AUDIOFD_FRAGSIZE 10240
-
-static double rint(double v) {
- return floor(v + 0.5);
-}
-
-TheoraDecoder::TheoraDecoder(Audio::Mixer::SoundType soundType) {
- _fileStream = 0;
-
- _theoraPacket = 0;
- _vorbisPacket = 0;
- _theoraDecode = 0;
- _theoraSetup = 0;
- _nextFrameStartTime = 0.0;
-
- _soundType = soundType;
- _audStream = 0;
- _audHandle = new Audio::SoundHandle();
-
- ogg_sync_init(&_oggSync);
-
- _curFrame = -1;
- _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t));
-
- reset();
-}
-
-TheoraDecoder::~TheoraDecoder() {
- close();
- delete _fileStream;
- delete _audHandle;
- free(_audiobuf);
-}
-
-void TheoraDecoder::queuePage(ogg_page *page) {
- if (_theoraPacket)
- ogg_stream_pagein(&_theoraOut, page);
-
- if (_vorbisPacket)
- ogg_stream_pagein(&_vorbisOut, page);
-}
-
-int TheoraDecoder::bufferData() {
- char *buffer = ogg_sync_buffer(&_oggSync, 4096);
- int bytes = _fileStream->read(buffer, 4096);
-
- ogg_sync_wrote(&_oggSync, bytes);
-
- return bytes;
-}
-
-bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) {
- close();
-
- _endOfAudio = false;
- _endOfVideo = false;
- _fileStream = stream;
-
- // start up Ogg stream synchronization layer
- ogg_sync_init(&_oggSync);
-
- // init supporting Vorbis structures needed in header parsing
- vorbis_info_init(&_vorbisInfo);
- vorbis_comment_init(&_vorbisComment);
-
- // init supporting Theora structures needed in header parsing
- th_comment_init(&_theoraComment);
- th_info_init(&_theoraInfo);
-
- // Ogg file open; parse the headers
- // Only interested in Vorbis/Theora streams
- bool foundHeader = false;
- while (!foundHeader) {
- int ret = bufferData();
-
- if (ret == 0)
- break;
-
- while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) {
- ogg_stream_state test;
-
- // is this a mandated initial header? If not, stop parsing
- if (!ogg_page_bos(&_oggPage)) {
- // don't leak the page; get it into the appropriate stream
- queuePage(&_oggPage);
- foundHeader = true;
- break;
- }
-
- ogg_stream_init(&test, ogg_page_serialno(&_oggPage));
- ogg_stream_pagein(&test, &_oggPage);
- ogg_stream_packetout(&test, &_oggPacket);
-
- // identify the codec: try theora
- if (!_theoraPacket && th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket) >= 0) {
- // it is theora
- memcpy(&_theoraOut, &test, sizeof(test));
- _theoraPacket = 1;
- } else if (!_vorbisPacket && vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket) >= 0) {
- // it is vorbis
- memcpy(&_vorbisOut, &test, sizeof(test));
- _vorbisPacket = 1;
- } else {
- // whatever it is, we don't care about it
- ogg_stream_clear(&test);
- }
- }
- // fall through to non-bos page parsing
- }
-
- // we're expecting more header packets.
- while ((_theoraPacket && _theoraPacket < 3) || (_vorbisPacket && _vorbisPacket < 3)) {
- int ret;
-
- // look for further theora headers
- while (_theoraPacket && (_theoraPacket < 3) && (ret = ogg_stream_packetout(&_theoraOut, &_oggPacket))) {
- if (ret < 0)
- error("Error parsing Theora stream headers; corrupt stream?");
-
- if (!th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket))
- error("Error parsing Theora stream headers; corrupt stream?");
-
- _theoraPacket++;
- }
-
- // look for more vorbis header packets
- while (_vorbisPacket && (_vorbisPacket < 3) && (ret = ogg_stream_packetout(&_vorbisOut, &_oggPacket))) {
- if (ret < 0)
- error("Error parsing Vorbis stream headers; corrupt stream?");
-
- if (vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket))
- error("Error parsing Vorbis stream headers; corrupt stream?");
-
- _vorbisPacket++;
-
- if (_vorbisPacket == 3)
- break;
- }
-
- // The header pages/packets will arrive before anything else we
- // care about, or the stream is not obeying spec
-
- if (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) {
- queuePage(&_oggPage); // demux into the appropriate stream
- } else {
- ret = bufferData(); // someone needs more data
-
- if (ret == 0)
- error("End of file while searching for codec headers.");
- }
- }
-
- // and now we have it all. initialize decoders
- if (_theoraPacket) {
- _theoraDecode = th_decode_alloc(&_theoraInfo, _theoraSetup);
- debugN(1, "Ogg logical stream %lx is Theora %dx%d %.02f fps",
- _theoraOut.serialno, _theoraInfo.pic_width, _theoraInfo.pic_height,
- (double)_theoraInfo.fps_numerator / _theoraInfo.fps_denominator);
-
- switch (_theoraInfo.pixel_fmt) {
- case TH_PF_420:
- debug(1, " 4:2:0 video");
- break;
- case TH_PF_422:
- debug(1, " 4:2:2 video");
- break;
- case TH_PF_444:
- debug(1, " 4:4:4 video");
- break;
- case TH_PF_RSVD:
- default:
- debug(1, " video\n (UNKNOWN Chroma sampling!)");
- break;
- }
-
- if (_theoraInfo.pic_width != _theoraInfo.frame_width || _theoraInfo.pic_height != _theoraInfo.frame_height)
- debug(1, " Frame content is %dx%d with offset (%d,%d).",
- _theoraInfo.frame_width, _theoraInfo.frame_height, _theoraInfo.pic_x, _theoraInfo.pic_y);
-
- switch (_theoraInfo.colorspace){
- case TH_CS_UNSPECIFIED:
- /* nothing to report */
- break;
- case TH_CS_ITU_REC_470M:
- debug(1, " encoder specified ITU Rec 470M (NTSC) color.");
- break;
- case TH_CS_ITU_REC_470BG:
- debug(1, " encoder specified ITU Rec 470BG (PAL) color.");
- break;
- default:
- debug(1, "warning: encoder specified unknown colorspace (%d).", _theoraInfo.colorspace);
- break;
- }
-
- debug(1, "Encoded by %s", _theoraComment.vendor);
- if (_theoraComment.comments) {
- debug(1, "theora comment header:");
- for (int i = 0; i < _theoraComment.comments; i++) {
- if (_theoraComment.user_comments[i]) {
- int len = _theoraComment.comment_lengths[i];
- char *value = (char *)malloc(len + 1);
- if (value) {
- memcpy(value, _theoraComment.user_comments[i], len);
- value[len] = '\0';
- debug(1, "\t%s", value);
- free(value);
- }
- }
- }
- }
-
- th_decode_ctl(_theoraDecode, TH_DECCTL_GET_PPLEVEL_MAX, &_ppLevelMax, sizeof(_ppLevelMax));
- _ppLevel = _ppLevelMax;
- th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel));
- _ppInc = 0;
- } else {
- // tear down the partial theora setup
- th_info_clear(&_theoraInfo);
- th_comment_clear(&_theoraComment);
- }
-
- th_setup_free(_theoraSetup);
- _theoraSetup = 0;
-
- if (_vorbisPacket) {
- vorbis_synthesis_init(&_vorbisDSP, &_vorbisInfo);
- vorbis_block_init(&_vorbisDSP, &_vorbisBlock);
- debug(3, "Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.",
- _vorbisOut.serialno, _vorbisInfo.channels, _vorbisInfo.rate);
-
- _audStream = Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels);
-
- // Get enough audio data to start us off
- while (_audStream->numQueuedStreams() == 0) {
- // Queue more data
- bufferData();
- while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0)
- queuePage(&_oggPage);
-
- queueAudio();
- }
-
- if (_audStream)
- g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, _audHandle, _audStream, -1, getVolume(), getBalance());
- } else {
- // tear down the partial vorbis setup
- vorbis_info_clear(&_vorbisInfo);
- vorbis_comment_clear(&_vorbisComment);
- _endOfAudio = true;
- }
-
- _surface.create(_theoraInfo.frame_width, _theoraInfo.frame_height, g_system->getScreenFormat());
-
- // Set up a display surface
- _displaySurface.pixels = _surface.getBasePtr(_theoraInfo.pic_x, _theoraInfo.pic_y);
- _displaySurface.w = _theoraInfo.pic_width;
- _displaySurface.h = _theoraInfo.pic_height;
- _displaySurface.format = _surface.format;
- _displaySurface.pitch = _surface.pitch;
-
- // Set the frame rate
- _frameRate = Common::Rational(_theoraInfo.fps_numerator, _theoraInfo.fps_denominator);
-
- return true;
-}
-
-void TheoraDecoder::close() {
- if (_vorbisPacket) {
- ogg_stream_clear(&_vorbisOut);
- vorbis_block_clear(&_vorbisBlock);
- vorbis_dsp_clear(&_vorbisDSP);
- vorbis_comment_clear(&_vorbisComment);
- vorbis_info_clear(&_vorbisInfo);
-
- g_system->getMixer()->stopHandle(*_audHandle);
-
- _audStream = 0;
- _vorbisPacket = false;
- }
- if (_theoraPacket) {
- ogg_stream_clear(&_theoraOut);
- th_decode_free(_theoraDecode);
- th_comment_clear(&_theoraComment);
- th_info_clear(&_theoraInfo);
- _theoraDecode = 0;
- _theoraPacket = false;
- }
-
- if (!_fileStream)
- return;
-
- ogg_sync_clear(&_oggSync);
-
- delete _fileStream;
- _fileStream = 0;
-
- _surface.free();
- _displaySurface.pixels = 0;
- _displaySurface.free();
-
- reset();
-}
-
-const Graphics::Surface *TheoraDecoder::decodeNextFrame() {
- // First, let's get our frame
- while (_theoraPacket) {
- // theora is one in, one out...
- if (ogg_stream_packetout(&_theoraOut, &_oggPacket) > 0) {
-
- if (_ppInc) {
- _ppLevel += _ppInc;
- th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel));
- _ppInc = 0;
- }
-
- if (th_decode_packetin(_theoraDecode, &_oggPacket, NULL) == 0) {
- _curFrame++;
-
- // Convert YUV data to RGB data
- th_ycbcr_buffer yuv;
- th_decode_ycbcr_out(_theoraDecode, yuv);
- translateYUVtoRGBA(yuv);
-
- if (_curFrame == 0)
- _startTime = g_system->getMillis();
-
- double time = th_granule_time(_theoraDecode, _oggPacket.granulepos);
-
- // We need to calculate when the next frame should be shown
- // This is all in floating point because that's what the Ogg code gives us
- // Ogg is a lossy container format, so it doesn't always list the time to the
- // next frame. In such cases, we need to calculate it ourselves.
- if (time == -1.0)
- _nextFrameStartTime += _frameRate.getInverse().toDouble();
- else
- _nextFrameStartTime = time;
-
- // break out
- break;
- }
- } else {
- // If we can't get any more frames, we're done.
- if (_theoraOut.e_o_s || _fileStream->eos()) {
- _endOfVideo = true;
- break;
- }
-
- // Queue more data
- bufferData();
- while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0)
- queuePage(&_oggPage);
- }
-
- // Update audio if we can
- queueAudio();
- }
-
- // Force at least some audio to be buffered
- // TODO: 5 is very arbitrary. We probably should do something like QuickTime does.
- while (!_endOfAudio && _audStream->numQueuedStreams() < 5) {
- bufferData();
- while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0)
- queuePage(&_oggPage);
-
- bool queuedAudio = queueAudio();
- if ((_vorbisOut.e_o_s || _fileStream->eos()) && !queuedAudio) {
- _endOfAudio = true;
- break;
- }
- }
-
- return &_displaySurface;
-}
-
-bool TheoraDecoder::queueAudio() {
- if (!_audStream)
- return false;
-
- // An audio buffer should have been allocated (either in the constructor or after queuing the current buffer)
- if (!_audiobuf) {
- warning("[TheoraDecoder::queueAudio] Invalid audio buffer");
- return false;
- }
-
- bool queuedAudio = false;
-
- for (;;) {
- float **pcm;
-
- // if there's pending, decoded audio, grab it
- int ret = vorbis_synthesis_pcmout(&_vorbisDSP, &pcm);
- if (ret > 0) {
- int count = _audiobufFill / 2;
- int maxsamples = ((AUDIOFD_FRAGSIZE - _audiobufFill) / _vorbisInfo.channels) >> 1;
- int i;
- for (i = 0; i < ret && i < maxsamples; i++)
- for (int j = 0; j < _vorbisInfo.channels; j++) {
- int val = CLIP((int)rint(pcm[j][i] * 32767.f), -32768, 32767);
- _audiobuf[count++] = val;
- }
-
- vorbis_synthesis_read(&_vorbisDSP, i);
- _audiobufFill += (i * _vorbisInfo.channels) << 1;
-
- if (_audiobufFill == AUDIOFD_FRAGSIZE) {
- byte flags = Audio::FLAG_16BITS | Audio::FLAG_STEREO;
-#ifdef SCUMM_LITTLE_ENDIAN
- flags |= Audio::FLAG_LITTLE_ENDIAN;
-#endif
- _audStream->queueBuffer((byte *)_audiobuf, AUDIOFD_FRAGSIZE, DisposeAfterUse::YES, flags);
-
- // The audio mixer is now responsible for the old audio buffer.
- // We need to create a new one.
- _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t));
- if (!_audiobuf) {
- warning("[TheoraDecoder::queueAudio] Cannot allocate memory for audio buffer");
- return false;
- }
-
- _audiobufFill = 0;
- queuedAudio = true;
- }
- } else {
- // no pending audio; is there a pending packet to decode?
- if (ogg_stream_packetout(&_vorbisOut, &_oggPacket) > 0) {
- if (vorbis_synthesis(&_vorbisBlock, &_oggPacket) == 0) // test for success!
- vorbis_synthesis_blockin(&_vorbisDSP, &_vorbisBlock);
- } else // we've buffered all we have, break out for now
- return queuedAudio;
- }
- }
-
- // Unreachable
- return false;
-}
-
-void TheoraDecoder::reset() {
- VideoDecoder::reset();
-
- // FIXME: This does a rewind() instead of a reset()!
-
- if (_fileStream)
- _fileStream->seek(0);
-
- _audiobufFill = 0;
- _audiobufReady = false;
-
- _curFrame = -1;
-
- _theoraPacket = 0;
- _vorbisPacket = 0;
-}
-
-bool TheoraDecoder::endOfVideo() const {
- return !isVideoLoaded() || (_endOfVideo && (!_audStream || (_audStream->endOfData() && _endOfAudio)));
-}
-
-uint32 TheoraDecoder::getTimeToNextFrame() const {
- if (endOfVideo() || _curFrame < 0)
- return 0;
-
- uint32 elapsedTime = getTime();
- uint32 nextFrameStartTime = (uint32)(_nextFrameStartTime * 1000);
-
- if (nextFrameStartTime <= elapsedTime)
- return 0;
-
- return nextFrameStartTime - elapsedTime;
-}
-
-uint32 TheoraDecoder::getTime() const {
- if (_audStream)
- return g_system->getMixer()->getSoundElapsedTime(*_audHandle);
-
- return VideoDecoder::getTime();
-}
-
-void TheoraDecoder::pauseVideoIntern(bool pause) {
- if (_audStream)
- g_system->getMixer()->pauseHandle(*_audHandle, pause);
-}
-
-enum TheoraYUVBuffers {
- kBufferY = 0,
- kBufferU = 1,
- kBufferV = 2
-};
-
-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);
- assert((YUVBuffer[kBufferU].width & 1) == 0);
- assert((YUVBuffer[kBufferV].width & 1) == 0);
-
- // UV images have to have a quarter of the Y image resolution
- assert(YUVBuffer[kBufferU].width == YUVBuffer[kBufferY].width >> 1);
- assert(YUVBuffer[kBufferV].width == YUVBuffer[kBufferY].width >> 1);
- assert(YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height >> 1);
- assert(YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height >> 1);
-
- Graphics::convertYUV420ToRGB(&_surface, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride);
-}
-
-void TheoraDecoder::updateVolume() {
- if (g_system->getMixer()->isSoundHandleActive(*_audHandle))
- g_system->getMixer()->setChannelVolume(*_audHandle, getVolume());
-}
-
-void TheoraDecoder::updateBalance() {
- if (g_system->getMixer()->isSoundHandleActive(*_audHandle))
- g_system->getMixer()->setChannelBalance(*_audHandle, getBalance());
-}
-
-void TheoraDecoder::rewind() {
- reset();
-}
-
-} // End of namespace Sword25
-
-#endif
diff --git a/engines/wintermute/video/decoders/theora_decoder.h b/engines/wintermute/video/decoders/theora_decoder.h
deleted file mode 100644
index fd94f52142..0000000000
--- a/engines/wintermute/video/decoders/theora_decoder.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef WINTERMUTE_THEORADECODER_H
-#define WINTERMUTE_THEORADECODER_H
-
-#include "common/scummsys.h" // for USE_THEORADEC
-
-#ifdef USE_THEORADEC
-
-#include "common/rational.h"
-#include "video/video_decoder.h"
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
-#include "graphics/pixelformat.h"
-#include "graphics/surface.h"
-
-#include <theora/theoradec.h>
-#include <vorbis/codec.h>
-
-namespace Common {
-class SeekableReadStream;
-}
-
-namespace Wintermute {
-
-/**
- *
- * Decoder for Theora videos.
- * Video decoder used in engines:
- * - sword25
- * - wintermute
- */
-class TheoraDecoder : public Video::RewindableVideoDecoder {
-public:
- TheoraDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kMusicSoundType);
- virtual ~TheoraDecoder();
-
- /**
- * Load a video file
- * @param stream the stream to load
- */
- bool loadStream(Common::SeekableReadStream *stream);
- void close();
- void reset();
-
- /**
- * Decode the next frame and return the frame's surface
- * @note the return surface should *not* be freed
- * @note this may return 0, in which case the last frame should be kept on screen
- */
- const Graphics::Surface *decodeNextFrame();
-
- bool isVideoLoaded() const { return _fileStream != 0; }
- uint16 getWidth() const { return _displaySurface.w; }
- uint16 getHeight() const { return _displaySurface.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 _displaySurface.format; }
- uint32 getTime() const;
- uint32 getTimeToNextFrame() const;
-
- bool endOfVideo() const;
-
- void rewind();
-
-protected:
- // VideoDecoder API
- void updateVolume();
- void updateBalance();
- void pauseVideoIntern(bool pause);
-
-private:
- void queuePage(ogg_page *page);
- bool queueAudio();
- int bufferData();
- void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer);
-
- Common::SeekableReadStream *_fileStream;
- Graphics::Surface _surface;
- Graphics::Surface _displaySurface;
- Common::Rational _frameRate;
- double _nextFrameStartTime;
- bool _endOfVideo;
- bool _endOfAudio;
-
- Audio::Mixer::SoundType _soundType;
- Audio::SoundHandle *_audHandle;
- Audio::QueuingAudioStream *_audStream;
-
- ogg_sync_state _oggSync;
- ogg_page _oggPage;
- ogg_packet _oggPacket;
- ogg_stream_state _vorbisOut;
- ogg_stream_state _theoraOut;
- th_info _theoraInfo;
- th_comment _theoraComment;
- th_dec_ctx *_theoraDecode;
- th_setup_info *_theoraSetup;
- vorbis_info _vorbisInfo;
- vorbis_dsp_state _vorbisDSP;
- vorbis_block _vorbisBlock;
- vorbis_comment _vorbisComment;
-
- int _theoraPacket;
- int _vorbisPacket;
-
- int _ppLevelMax;
- int _ppLevel;
- int _ppInc;
-
- // single audio fragment audio buffering
- int _audiobufFill;
- bool _audiobufReady;
- ogg_int16_t *_audiobuf;
-};
-
-} // End of namespace Sword25
-
-#endif
-
-#endif
diff --git a/engines/wintermute/video/video_theora_player.cpp b/engines/wintermute/video/video_theora_player.cpp
index d92a74610d..2804c3d3a9 100644
--- a/engines/wintermute/video/video_theora_player.cpp
+++ b/engines/wintermute/video/video_theora_player.cpp
@@ -35,7 +35,7 @@
#include "engines/wintermute/base/sound/base_sound_manager.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/platform_osystem.h"
-#include "engines/wintermute/video/decoders/theora_decoder.h"
+#include "video/theora_decoder.h"
#include "engines/wintermute/wintermute.h"
#include "common/system.h"
@@ -126,7 +126,7 @@ bool VideoTheoraPlayer::initialize(const Common::String &filename, const Common:
}
#if defined (USE_THEORADEC)
- _theoraDecoder = new TheoraDecoder();
+ _theoraDecoder = new Video::TheoraDecoder();
#else
return STATUS_FAILED;
#endif
@@ -225,6 +225,8 @@ bool VideoTheoraPlayer::play(TVideoPlayback type, int x, int y, bool freezeGame,
_posY = (int)((_gameRef->_renderer->_height - height) / 2);
break;
}
+ _theoraDecoder->start();
+
return STATUS_OK;
#if 0 // Stubbed for now as theora isn't seekable
if (StartTime) SeekToTime(StartTime);
@@ -274,11 +276,14 @@ bool VideoTheoraPlayer::update() {
}
}
if (_state == THEORA_STATE_PLAYING) {
- if (_theoraDecoder->getTimeToNextFrame() == 0) {
- _surface.free();
- _surface.copyFrom(*_theoraDecoder->decodeNextFrame());
- if (_texture) {
- writeVideo();
+ if (!_theoraDecoder->endOfVideo() && _theoraDecoder->getTimeToNextFrame() == 0) {
+ const Graphics::Surface *decodedFrame = _theoraDecoder->decodeNextFrame();
+ if (decodedFrame) {
+ _surface.free();
+ _surface.copyFrom(*decodedFrame);
+ if (_texture) {
+ writeVideo();
+ }
}
}
return STATUS_OK;
@@ -333,7 +338,7 @@ bool VideoTheoraPlayer::writeVideo() {
return STATUS_OK;
}
-void VideoTheoraPlayer::writeAlpha() { // TODO: Endian-fix.
+void VideoTheoraPlayer::writeAlpha() {
if (_alphaImage && _surface.w == _alphaImage->getSurface()->w && _surface.h == _alphaImage->getSurface()->h) {
assert(_alphaImage->getSurface()->format.bytesPerPixel == 4);
assert(_surface.format.bytesPerPixel == 4);
diff --git a/engines/wintermute/video/video_theora_player.h b/engines/wintermute/video/video_theora_player.h
index 41b45d2289..fd1b7b94b3 100644
--- a/engines/wintermute/video/video_theora_player.h
+++ b/engines/wintermute/video/video_theora_player.h
@@ -46,7 +46,7 @@ private:
THEORA_STATE_PAUSED = 2,
THEORA_STATE_FINISHED = 3
};
- Video::RewindableVideoDecoder *_theoraDecoder;
+ Video::VideoDecoder *_theoraDecoder;
Graphics::Surface _surface;
public:
DECLARE_PERSISTENT(VideoTheoraPlayer, BaseClass)