[Scummvm-cvs-logs] scummvm master -> d1f907485ecb8feccdd7522e9949d1a705a69874
clone2727
clone2727 at gmail.com
Wed May 18 16:08:16 CEST 2011
This automated email contains information about 6 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
f559741bfc SWORD25: Fix a/v sync with using the TheoraDecoder standalone
0addffbfd3 GRAPHICS: Add a YUV to RGB table lookup for use with Theora
f8323cc672 SWORD25: Make Theora handle the case when the packet eos is not set
affb6a38a1 GRAPHICS: Add some docs and sanity checks to the YUV to RGB code
14e1cc728f SWORD25: Properly use endOfVideo()
d1f907485e SWORD25: Implement TheoraDecoder::pauseVideoIntern()
Commit: f559741bfc0024b772724201b7e764441fee13c2
https://github.com/scummvm/scummvm/commit/f559741bfc0024b772724201b7e764441fee13c2
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2011-05-18T07:05:13-07:00
Commit Message:
SWORD25: Fix a/v sync with using the TheoraDecoder standalone
Hopefully should fix a/v sync from in-game. If not, the engine needs to be changed slightly
Changed paths:
engines/sword25/fmv/theora_decoder.cpp
engines/sword25/fmv/theora_decoder.h
diff --git a/engines/sword25/fmv/theora_decoder.cpp b/engines/sword25/fmv/theora_decoder.cpp
index f7e5e7a..4f5a006 100644
--- a/engines/sword25/fmv/theora_decoder.cpp
+++ b/engines/sword25/fmv/theora_decoder.cpp
@@ -59,6 +59,7 @@ TheoraDecoder::TheoraDecoder(Audio::Mixer::SoundType soundType) {
_vorbisPacket = 0;
_theoraDecode = 0;
_theoraSetup = 0;
+ _nextFrameStartTime = 0.0;
_soundType = soundType;
_audStream = 0;
@@ -99,6 +100,8 @@ int TheoraDecoder::bufferData() {
bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) {
close();
+ _endOfAudio = false;
+ _endOfVideo = false;
_fileStream = stream;
// start up Ogg stream synchronization layer
@@ -272,17 +275,26 @@ bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) {
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);
} else {
// tear down the partial vorbis setup
vorbis_info_clear(&_vorbisInfo);
vorbis_comment_clear(&_vorbisComment);
- }
-
- // open audio
- if (_vorbisPacket) {
- _audStream = Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels);
- if (_audStream)
- g_system->getMixer()->playStream(_soundType, _audHandle, _audStream);
+ _endOfAudio = true;
}
_surface = new Graphics::Surface();
@@ -332,49 +344,8 @@ void TheoraDecoder::close() {
}
const Graphics::Surface *TheoraDecoder::decodeNextFrame() {
- int i, j;
-
- // we want a video and audio frame ready to go at all times. If
- // we have to buffer incoming, buffer the compressed data (ie, let
- // ogg do the buffering)
- while (_vorbisPacket && !_audiobufReady) {
- int ret;
- float **pcm;
-
- // if there's pending, decoded audio, grab it
- if ((ret = vorbis_synthesis_pcmout(&_vorbisDSP, &pcm)) > 0) {
- int count = _audiobufFill / 2;
- int maxsamples = ((AUDIOFD_FRAGSIZE - _audiobufFill) / _vorbisInfo.channels) >> 1;
- for (i = 0; i < ret && i < maxsamples; i++)
- for (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)
- _audiobufReady = true;
-
-#if ENABLE_THEORA_SEEKING
- if (_vorbisDSP.granulepos >= 0)
- _audiobufGranulePos = _vorbisDSP.granulepos - ret + i;
- else
- _audiobufGranulePos += i;
-#endif
- } 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 need more data; break out to suck in another page
- break;
- }
- }
-
- while (_theoraPacket && !_theoraOut.e_o_s) {
+ // First, let's get our frame
+ while (_theoraPacket) {
// theora is one in, one out...
if (ogg_stream_packetout(&_theoraOut, &_oggPacket) > 0) {
@@ -384,22 +355,7 @@ const Graphics::Surface *TheoraDecoder::decodeNextFrame() {
_ppInc = 0;
}
-#if ENABLE_THEORA_SEEKING
- // HACK: This should be set after a seek or a gap, but we might not have
- // a granulepos for the first packet (we only have them for the last
- // packet on a page), so we just set it as often as we get it.
- // To do this right, we should back-track from the last packet on the
- // page and compute the correct granulepos for the first packet after
- // a seek or a gap.
- if (_oggPacket.granulepos >= 0) {
- th_decode_ctl(_theoraDecode, TH_DECCTL_SET_GRANPOS, &_oggPacket.granulepos, sizeof(_oggPacket.granulepos));
- }
-
- if (th_decode_packetin(_theoraDecode, &_oggPacket, &_videobufGranulePos) == 0) {
- _videobufTime = th_granule_time(_theoraDecode, _videobufGranulePos);
-#else
if (th_decode_packetin(_theoraDecode, &_oggPacket, NULL) == 0) {
-#endif
_curFrame++;
// Convert YUV data to RGB data
@@ -410,33 +366,103 @@ const Graphics::Surface *TheoraDecoder::decodeNextFrame() {
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) {
+ _endOfVideo = true;
+ break;
+ }
+
// Queue more data
bufferData();
while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0)
queuePage(&_oggPage);
}
+
+ // Update audio if we can
+ queueAudio();
}
- // If playback has begun, top audio buffer off immediately.
- if (_audiobufReady) {
- _audStream->queueBuffer((byte *)_audiobuf, AUDIOFD_FRAGSIZE, DisposeAfterUse::NO, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_STEREO);
+ // 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);
- // 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));
- _audiobufFill = 0;
- _audiobufReady = false;
+ bool queuedAudio = queueAudio();
+ if (_vorbisOut.e_o_s && !queuedAudio) {
+ _endOfAudio = true;
+ break;
+ }
}
return _surface;
}
+bool TheoraDecoder::queueAudio() {
+ if (!_audStream)
+ 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) {
+ _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.
+ // We need to create a new one.
+ _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t));
+ _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() {
- FixedRateVideoDecoder::reset();
+ VideoDecoder::reset();
// FIXME: This does a rewind() instead of a reset()!
@@ -459,14 +485,27 @@ void TheoraDecoder::reset() {
}
bool TheoraDecoder::endOfVideo() const {
- return !isVideoLoaded() || _theoraOut.e_o_s;
+ return !isVideoLoaded() || (_endOfVideo && (!_audStream || (_audStream->endOfData() && _endOfAudio)));
+}
+
+uint32 TheoraDecoder::getTimeToNextFrame() const {
+ if (endOfVideo() || _curFrame < 0)
+ return 0;
+
+ uint32 elapsedTime = getElapsedTime();
+ uint32 nextFrameStartTime = (uint32)(_nextFrameStartTime * 1000);
+
+ if (nextFrameStartTime <= elapsedTime)
+ return 0;
+
+ return nextFrameStartTime - elapsedTime;
}
uint32 TheoraDecoder::getElapsedTime() const {
if (_audStream)
return g_system->getMixer()->getSoundElapsedTime(*_audHandle);
- return FixedRateVideoDecoder::getElapsedTime();
+ return VideoDecoder::getElapsedTime();
}
static void convertYUVtoBGRA(int y, int u, int v, byte *dst, Graphics::PixelFormat format) {
diff --git a/engines/sword25/fmv/theora_decoder.h b/engines/sword25/fmv/theora_decoder.h
index a1ce3ae..4a646f1 100644
--- a/engines/sword25/fmv/theora_decoder.h
+++ b/engines/sword25/fmv/theora_decoder.h
@@ -41,8 +41,6 @@ namespace Common {
class SeekableReadStream;
}
-//#define ENABLE_THEORA_SEEKING // enables the extra calculations used for video seeking
-
namespace Sword25 {
/**
@@ -51,7 +49,7 @@ namespace Sword25 {
* Video decoder used in engines:
* - sword25
*/
-class TheoraDecoder : public Video::FixedRateVideoDecoder {
+class TheoraDecoder : public Video::VideoDecoder {
public:
TheoraDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kMusicSoundType);
virtual ~TheoraDecoder();
@@ -83,16 +81,14 @@ public:
}
Graphics::PixelFormat getPixelFormat() const { return _surface->format; }
-
uint32 getElapsedTime() const;
+ uint32 getTimeToNextFrame() const;
bool endOfVideo() const;
-protected:
- Common::Rational getFrameRate() const { return _frameRate; }
-
private:
void queuePage(ogg_page *page);
+ bool queueAudio();
int bufferData();
void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer);
@@ -100,7 +96,9 @@ private:
Common::SeekableReadStream *_fileStream;
Graphics::Surface *_surface;
Common::Rational _frameRate;
- uint32 _frameCount;
+ double _nextFrameStartTime;
+ bool _endOfVideo;
+ bool _endOfAudio;
Audio::Mixer::SoundType _soundType;
Audio::SoundHandle *_audHandle;
@@ -131,12 +129,6 @@ private:
int _audiobufFill;
bool _audiobufReady;
ogg_int16_t *_audiobuf;
-
-#if ENABLE_THEORA_SEEKING
- double _videobufTime;
- ogg_int64_t _videobufGranulePos;
- ogg_int64_t _audiobufGranulePos; // time position of last sample
-#endif
};
} // End of namespace Sword25
Commit: 0addffbfd3952f766e7f839c210465c9c34b94bd
https://github.com/scummvm/scummvm/commit/0addffbfd3952f766e7f839c210465c9c34b94bd
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2011-05-18T07:05:13-07:00
Commit Message:
GRAPHICS: Add a YUV to RGB table lookup for use with Theora
Based on the video/mpeg_player.* one, which is based on lots of other things (too many to name, go see the file)
Changed paths:
A graphics/yuv_to_rgb.cpp
A graphics/yuv_to_rgb.h
engines/sword25/fmv/theora_decoder.cpp
graphics/module.mk
diff --git a/engines/sword25/fmv/theora_decoder.cpp b/engines/sword25/fmv/theora_decoder.cpp
index 4f5a006..9aa7ead 100644
--- a/engines/sword25/fmv/theora_decoder.cpp
+++ b/engines/sword25/fmv/theora_decoder.cpp
@@ -39,7 +39,8 @@
#ifdef USE_THEORADEC
#include "common/system.h"
#include "common/textconsole.h"
-#include "graphics/conversion.h"
+#include "common/util.h"
+#include "graphics/yuv_to_rgb.h"
#include "audio/decoders/raw.h"
#include "sword25/kernel/common.h"
@@ -508,16 +509,6 @@ uint32 TheoraDecoder::getElapsedTime() const {
return VideoDecoder::getElapsedTime();
}
-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);
-
- if (format.bytesPerPixel == 2)
- *((uint16 *)dst) = format.RGBToColor(r, g, b);
- else
- *((uint32 *)dst) = format.RGBToColor(r, g, b);
-}
-
enum TheoraYUVBuffers {
kBufferY = 0,
kBufferU = 1,
@@ -537,40 +528,7 @@ void TheoraDecoder::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer) {
assert(YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height >> 1);
assert(YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height >> 1);
- const byte *ySrc = YUVBuffer[kBufferY].data;
- const byte *uSrc = YUVBuffer[kBufferU].data;
- const byte *vSrc = YUVBuffer[kBufferV].data;
- byte *dst = (byte *)_surface->pixels;
- int u = 0, v = 0;
-
- 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;
- // The UV step is usually 0, since in most cases stride == width.
- // The asserts at the top ensure that the U and V steps are equal
- // (and they must always be equal)
- const int uvStep = YUVBuffer[kBufferU].stride - YUVBuffer[kBufferU].width;
- const int stride = YUVBuffer[kBufferY].stride;
-
- for (int h = 0; h < halfHeight; ++h) {
- for (int w = 0; w < halfWidth; ++w) {
- u = *uSrc++;
- v = *vSrc++;
-
- for (int i = 0; i <= 1; i++) {
- convertYUVtoBGRA(*ySrc, u, v, dst, getPixelFormat());
- convertYUVtoBGRA(*(ySrc + stride), u, v, dst + blockSize, getPixelFormat());
- ySrc++;
- dst += 4; // BGRA
- }
- }
-
- dst += blockSize;
- ySrc += yStep;
- uSrc += uvStep;
- vSrc += uvStep;
- }
+ Graphics::convertYUV420ToRGB(_surface, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride);
}
} // End of namespace Sword25
diff --git a/graphics/module.mk b/graphics/module.mk
index 59621dc..a9051c8 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -25,7 +25,8 @@ MODULE_OBJS := \
thumbnail.o \
VectorRenderer.o \
VectorRendererSpec.o \
- wincursor.o
+ wincursor.o \
+ yuv_to_rgb.o
ifdef USE_SCALERS
MODULE_OBJS += \
diff --git a/graphics/yuv_to_rgb.cpp b/graphics/yuv_to_rgb.cpp
new file mode 100644
index 0000000..b1107a7
--- /dev/null
+++ b/graphics/yuv_to_rgb.cpp
@@ -0,0 +1,240 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// The YUV to RGB conversion code is derived from SDL's YUV overlay code, which
+// in turn appears to be derived from mpeg_play. The following copyright
+// notices have been included in accordance with the original license. Please
+// note that the term "software" in this context only applies to the
+// buildLookup() and plotYUV*() functions below.
+
+// Copyright (c) 1995 The Regents of the University of California.
+// All rights reserved.
+//
+// Permission to use, copy, modify, and distribute this software and its
+// documentation for any purpose, without fee, and without written agreement is
+// hereby granted, provided that the above copyright notice and the following
+// two paragraphs appear in all copies of this software.
+//
+// IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+// OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+// CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+// ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+// PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+// Copyright (c) 1995 Erik Corry
+// All rights reserved.
+//
+// Permission to use, copy, modify, and distribute this software and its
+// documentation for any purpose, without fee, and without written agreement is
+// hereby granted, provided that the above copyright notice and the following
+// two paragraphs appear in all copies of this software.
+//
+// IN NO EVENT SHALL ERIK CORRY BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+// SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
+// THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF ERIK CORRY HAS BEEN ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ERIK CORRY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND ERIK CORRY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
+// UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+// Portions of this software Copyright (c) 1995 Brown University.
+// All rights reserved.
+//
+// Permission to use, copy, modify, and distribute this software and its
+// documentation for any purpose, without fee, and without written agreement
+// is hereby granted, provided that the above copyright notice and the
+// following two paragraphs appear in all copies of this software.
+//
+// IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR
+// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+// OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN
+// UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+#include "common/scummsys.h"
+#include "common/singleton.h"
+
+#include "graphics/surface.h"
+
+namespace Graphics {
+
+class YUVToRGBLookup {
+public:
+ YUVToRGBLookup(Graphics::PixelFormat format);
+ ~YUVToRGBLookup();
+
+ int16 *_colorTab;
+ uint32 *_rgbToPix;
+};
+
+YUVToRGBLookup::YUVToRGBLookup(Graphics::PixelFormat format) {
+ _colorTab = new int16[4 * 256]; // 2048 bytes
+
+ int16 *Cr_r_tab = &_colorTab[0 * 256];
+ int16 *Cr_g_tab = &_colorTab[1 * 256];
+ int16 *Cb_g_tab = &_colorTab[2 * 256];
+ int16 *Cb_b_tab = &_colorTab[3 * 256];
+
+ _rgbToPix = new uint32[3 * 768]; // 9216 bytes
+
+ uint32 *r_2_pix_alloc = &_rgbToPix[0 * 768];
+ uint32 *g_2_pix_alloc = &_rgbToPix[1 * 768];
+ uint32 *b_2_pix_alloc = &_rgbToPix[2 * 768];
+
+ int16 CR, CB;
+ int i;
+
+ // Generate the tables for the display surface
+
+ for (i = 0; i < 256; i++) {
+ // Gamma correction (luminescence table) and chroma correction
+ // would be done here. See the Berkeley mpeg_play sources.
+
+ CR = CB = (i - 128);
+ Cr_r_tab[i] = (int16) ( (0.419 / 0.299) * CR) + 0 * 768 + 256;
+ Cr_g_tab[i] = (int16) (-(0.299 / 0.419) * CR) + 1 * 768 + 256;
+ Cb_g_tab[i] = (int16) (-(0.114 / 0.331) * CB);
+ Cb_b_tab[i] = (int16) ( (0.587 / 0.331) * CB) + 2 * 768 + 256;
+ }
+
+ // Set up entries 0-255 in rgb-to-pixel value tables.
+ for (i = 0; i < 256; i++) {
+ r_2_pix_alloc[i + 256] = format.RGBToColor(i, 0, 0);
+ g_2_pix_alloc[i + 256] = format.RGBToColor(0, i, 0);
+ b_2_pix_alloc[i + 256] = format.RGBToColor(0, 0, i);
+ }
+
+ // Spread out the values we have to the rest of the array so that we do
+ // not need to check for overflow.
+ for (i = 0; i < 256; i++) {
+ r_2_pix_alloc[i] = r_2_pix_alloc[256];
+ r_2_pix_alloc[i + 512] = r_2_pix_alloc[511];
+ g_2_pix_alloc[i] = g_2_pix_alloc[256];
+ g_2_pix_alloc[i + 512] = g_2_pix_alloc[511];
+ b_2_pix_alloc[i] = b_2_pix_alloc[256];
+ b_2_pix_alloc[i + 512] = b_2_pix_alloc[511];
+ }
+}
+
+YUVToRGBLookup::~YUVToRGBLookup() {
+ delete[] _rgbToPix;
+ delete[] _colorTab;
+}
+
+class YUVToRGBManager : public Common::Singleton<YUVToRGBManager> {
+public:
+ const YUVToRGBLookup *getLookup(Graphics::PixelFormat format);
+
+private:
+ friend class Common::Singleton<SingletonBaseType>;
+ YUVToRGBManager();
+ ~YUVToRGBManager();
+
+ Graphics::PixelFormat _lastFormat;
+ YUVToRGBLookup *_lookup;
+};
+
+YUVToRGBManager::YUVToRGBManager() {
+ _lookup = 0;
+}
+
+YUVToRGBManager::~YUVToRGBManager() {
+ delete _lookup;
+}
+
+const YUVToRGBLookup *YUVToRGBManager::getLookup(Graphics::PixelFormat format) {
+ if (_lastFormat == format)
+ return _lookup;
+
+ delete _lookup;
+ _lookup = new YUVToRGBLookup(format);
+ _lastFormat = format;
+ return _lookup;
+}
+
+} // End of namespace Graphics
+
+DECLARE_SINGLETON(Graphics::YUVToRGBManager);
+
+#define YUVToRGBMan (Graphics::YUVToRGBManager::instance())
+
+namespace Graphics {
+
+#define PUT_PIXEL(s, d) \
+ L = &lookup->_rgbToPix[(s)]; \
+ if (dst->format.bytesPerPixel == 2) \
+ *((uint16 *)(d)) = (L[cr_r] | L[crb_g] | L[cb_b]); \
+ else \
+ *((uint32 *)(d)) = (L[cr_r] | L[crb_g] | L[cb_b])
+
+void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
+ const YUVToRGBLookup *lookup = YUVToRGBMan.getLookup(dst->format);
+
+ byte *dstPtr = (byte *)dst->pixels;
+
+ int halfHeight = yHeight >> 1;
+ int halfWidth = yWidth >> 1;
+
+ for (int h = 0; h < halfHeight; h++) {
+ for (int w = 0; w < halfWidth; w++) {
+ register uint32 *L;
+
+ int16 cr_r = lookup->_colorTab[*vSrc + 0 * 256];
+ int16 crb_g = lookup->_colorTab[*vSrc + 1 * 256] + lookup->_colorTab[*uSrc + 2 * 256];
+ int16 cb_b = lookup->_colorTab[*uSrc + 3 * 256];
+ ++uSrc;
+ ++vSrc;
+
+ PUT_PIXEL(*ySrc, dstPtr);
+ PUT_PIXEL(*(ySrc + yPitch), dstPtr + dst->pitch);
+ ySrc++;
+ dstPtr += dst->format.bytesPerPixel;
+ PUT_PIXEL(*ySrc, dstPtr);
+ PUT_PIXEL(*(ySrc + yPitch), dstPtr + dst->pitch);
+ ySrc++;
+ dstPtr += dst->format.bytesPerPixel;
+ }
+
+ dstPtr += dst->pitch;
+ ySrc += (yPitch << 1) - yWidth;
+ uSrc += uvPitch - halfWidth;
+ vSrc += uvPitch - halfWidth;
+ }
+}
+
+} // End of namespace Graphics
diff --git a/graphics/yuv_to_rgb.h b/graphics/yuv_to_rgb.h
new file mode 100644
index 0000000..30f64ee
--- /dev/null
+++ b/graphics/yuv_to_rgb.h
@@ -0,0 +1,40 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef GRAPHICS_YUV_TO_RGB_H
+#define GRAPHICS_YUV_TO_RGB_H
+
+#include "common/scummsys.h"
+#include "graphics/surface.h"
+
+namespace Graphics {
+
+struct Surface;
+
+void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch);
+
+} // End of namespace Graphics
+
+#endif
Commit: f8323cc67230b64de5af93624f57aba4020fecdf
https://github.com/scummvm/scummvm/commit/f8323cc67230b64de5af93624f57aba4020fecdf
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2011-05-18T07:05:13-07:00
Commit Message:
SWORD25: Make Theora handle the case when the packet eos is not set
Changed paths:
engines/sword25/fmv/theora_decoder.cpp
diff --git a/engines/sword25/fmv/theora_decoder.cpp b/engines/sword25/fmv/theora_decoder.cpp
index 9aa7ead..7957cb0 100644
--- a/engines/sword25/fmv/theora_decoder.cpp
+++ b/engines/sword25/fmv/theora_decoder.cpp
@@ -383,7 +383,7 @@ const Graphics::Surface *TheoraDecoder::decodeNextFrame() {
}
} else {
// If we can't get any more frames, we're done.
- if (_theoraOut.e_o_s) {
+ if (_theoraOut.e_o_s || _fileStream->eos()) {
_endOfVideo = true;
break;
}
@@ -406,7 +406,7 @@ const Graphics::Surface *TheoraDecoder::decodeNextFrame() {
queuePage(&_oggPage);
bool queuedAudio = queueAudio();
- if (_vorbisOut.e_o_s && !queuedAudio) {
+ if ((_vorbisOut.e_o_s || _fileStream->eos()) && !queuedAudio) {
_endOfAudio = true;
break;
}
Commit: affb6a38a198d410922492026e5277794a310279
https://github.com/scummvm/scummvm/commit/affb6a38a198d410922492026e5277794a310279
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2011-05-18T07:05:13-07:00
Commit Message:
GRAPHICS: Add some docs and sanity checks to the YUV to RGB code
Changed paths:
graphics/yuv_to_rgb.cpp
graphics/yuv_to_rgb.h
diff --git a/graphics/yuv_to_rgb.cpp b/graphics/yuv_to_rgb.cpp
index b1107a7..831736c 100644
--- a/graphics/yuv_to_rgb.cpp
+++ b/graphics/yuv_to_rgb.cpp
@@ -203,6 +203,13 @@ namespace Graphics {
*((uint32 *)(d)) = (L[cr_r] | L[crb_g] | L[cb_b])
void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
+ // Sanity checks
+ assert(dst && dst->pixels);
+ assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4);
+ assert(ySrc && uSrc && vSrc);
+ assert((yWidth & 1) == 0);
+ assert((yHeight & 1) == 0);
+
const YUVToRGBLookup *lookup = YUVToRGBMan.getLookup(dst->format);
byte *dstPtr = (byte *)dst->pixels;
diff --git a/graphics/yuv_to_rgb.h b/graphics/yuv_to_rgb.h
index 30f64ee..9b561f2 100644
--- a/graphics/yuv_to_rgb.h
+++ b/graphics/yuv_to_rgb.h
@@ -23,6 +23,12 @@
*
*/
+/**
+ * @file
+ * YUV to RGB conversion used in engines:
+ * - sword25
+ */
+
#ifndef GRAPHICS_YUV_TO_RGB_H
#define GRAPHICS_YUV_TO_RGB_H
@@ -33,6 +39,18 @@ namespace Graphics {
struct Surface;
+/**
+ * Convert a YUV420 image to an RGB surface
+ *
+ * @param dst the destination surface
+ * @param ySrc the source of the y component
+ * @param uSrc the source of the u component
+ * @param vSrc the source of the v component
+ * @param yWidth the width of the y surface (must be divisible by 2)
+ * @param yHeight the height of the y surface (must be divisible by 2)
+ * @param yPitch the pitch of the y surface
+ * @param uvPitch the pitch of the u and v surfaces
+ */
void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch);
} // End of namespace Graphics
Commit: 14e1cc728f0e7233dfecce6c58ebfa319512152b
https://github.com/scummvm/scummvm/commit/14e1cc728f0e7233dfecce6c58ebfa319512152b
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2011-05-18T07:05:14-07:00
Commit Message:
SWORD25: Properly use endOfVideo()
Changed paths:
engines/sword25/fmv/movieplayer.cpp
diff --git a/engines/sword25/fmv/movieplayer.cpp b/engines/sword25/fmv/movieplayer.cpp
index c60f5d4..d267506 100644
--- a/engines/sword25/fmv/movieplayer.cpp
+++ b/engines/sword25/fmv/movieplayer.cpp
@@ -119,21 +119,23 @@ bool MoviePlayer::pause() {
void MoviePlayer::update() {
if (_decoder.isVideoLoaded()) {
- const Graphics::Surface *s = _decoder.decodeNextFrame();
- if (s) {
- // Transfer the next frame
- assert(s->format.bytesPerPixel == 4);
+ if (_decoder.endOfVideo()) {
+ // Movie complete, so unload the movie
+ unloadMovie();
+ } else {
+ const Graphics::Surface *s = _decoder.decodeNextFrame();
+ if (s) {
+ // Transfer the next frame
+ assert(s->format.bytesPerPixel == 4);
#ifdef THEORA_INDIRECT_RENDERING
- byte *frameData = (byte *)s->getBasePtr(0, 0);
- _outputBitmap->setContent(frameData, s->pitch * s->h, 0, s->pitch);
+ byte *frameData = (byte *)s->getBasePtr(0, 0);
+ _outputBitmap->setContent(frameData, s->pitch * s->h, 0, s->pitch);
#else
- g_system->copyRectToScreen((byte *)s->getBasePtr(0, 0), s->pitch, _outX, _outY, MIN(s->w, _backSurface->w), MIN(s->h, _backSurface->h));
- g_system->updateScreen();
+ g_system->copyRectToScreen((byte *)s->getBasePtr(0, 0), s->pitch, _outX, _outY, MIN(s->w, _backSurface->w), MIN(s->h, _backSurface->h));
+ g_system->updateScreen();
#endif
- } else {
- // Movie complete, so unload the movie
- unloadMovie();
+ }
}
}
}
Commit: d1f907485ecb8feccdd7522e9949d1a705a69874
https://github.com/scummvm/scummvm/commit/d1f907485ecb8feccdd7522e9949d1a705a69874
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2011-05-18T07:05:14-07:00
Commit Message:
SWORD25: Implement TheoraDecoder::pauseVideoIntern()
Changed paths:
engines/sword25/fmv/theora_decoder.cpp
engines/sword25/fmv/theora_decoder.h
diff --git a/engines/sword25/fmv/theora_decoder.cpp b/engines/sword25/fmv/theora_decoder.cpp
index 7957cb0..07cb563 100644
--- a/engines/sword25/fmv/theora_decoder.cpp
+++ b/engines/sword25/fmv/theora_decoder.cpp
@@ -509,6 +509,11 @@ uint32 TheoraDecoder::getElapsedTime() const {
return VideoDecoder::getElapsedTime();
}
+void TheoraDecoder::pauseVideoIntern(bool pause) {
+ if (_audStream)
+ g_system->getMixer()->pauseHandle(*_audHandle, pause);
+}
+
enum TheoraYUVBuffers {
kBufferY = 0,
kBufferU = 1,
diff --git a/engines/sword25/fmv/theora_decoder.h b/engines/sword25/fmv/theora_decoder.h
index 4a646f1..10a0564 100644
--- a/engines/sword25/fmv/theora_decoder.h
+++ b/engines/sword25/fmv/theora_decoder.h
@@ -86,13 +86,15 @@ public:
bool endOfVideo() const;
+protected:
+ void pauseVideoIntern(bool pause);
+
private:
void queuePage(ogg_page *page);
bool queueAudio();
int bufferData();
void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer);
-private:
Common::SeekableReadStream *_fileStream;
Graphics::Surface *_surface;
Common::Rational _frameRate;
More information about the Scummvm-git-logs
mailing list