diff options
author | Einar Johan Trøan Sømåen | 2012-08-31 13:49:38 +0200 |
---|---|---|
committer | Einar Johan Trøan Sømåen | 2012-08-31 13:49:38 +0200 |
commit | 16b27090b1c7dc11cdc199b1a98c0f2973db5f45 (patch) | |
tree | 795fe24dc2097801bbb773a907fd465bc23e9499 /engines | |
parent | 3fe7f2cbe2b70eaa824b7159d94d40c2280006a3 (diff) | |
download | scummvm-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.cpp | 4 | ||||
-rw-r--r-- | engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp | 2 | ||||
-rw-r--r-- | engines/wintermute/graphics/tga.cpp | 164 | ||||
-rw-r--r-- | engines/wintermute/graphics/tga.h | 59 | ||||
-rw-r--r-- | engines/wintermute/module.mk | 2 | ||||
-rw-r--r-- | engines/wintermute/video/decoders/theora_decoder.cpp | 570 | ||||
-rw-r--r-- | engines/wintermute/video/decoders/theora_decoder.h | 147 | ||||
-rw-r--r-- | engines/wintermute/video/video_theora_player.cpp | 21 | ||||
-rw-r--r-- | engines/wintermute/video/video_theora_player.h | 2 |
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) |