[Scummvm-cvs-logs] SF.net SVN: scummvm:[53206] scummvm/trunk/engines/sword25

sev at users.sourceforge.net sev at users.sourceforge.net
Wed Oct 13 00:22:33 CEST 2010


Revision: 53206
          http://scummvm.svn.sourceforge.net/scummvm/?rev=53206&view=rev
Author:   sev
Date:     2010-10-12 22:22:33 +0000 (Tue, 12 Oct 2010)

Log Message:
-----------
SWORD25: Start for VideoDecoder-compatible Theora player.

Modified Paths:
--------------
    scummvm/trunk/engines/sword25/fmv/movieplayer.cpp
    scummvm/trunk/engines/sword25/fmv/movieplayer.h
    scummvm/trunk/engines/sword25/fmv/movieplayer_script.cpp
    scummvm/trunk/engines/sword25/module.mk

Added Paths:
-----------
    scummvm/trunk/engines/sword25/fmv/theora_decoder.cpp
    scummvm/trunk/engines/sword25/fmv/theora_decoder.h

Modified: scummvm/trunk/engines/sword25/fmv/movieplayer.cpp
===================================================================
--- scummvm/trunk/engines/sword25/fmv/movieplayer.cpp	2010-10-12 22:22:03 UTC (rev 53205)
+++ scummvm/trunk/engines/sword25/fmv/movieplayer.cpp	2010-10-12 22:22:33 UTC (rev 53206)
@@ -38,11 +38,52 @@
 
 #define BS_LOG_PREFIX "MOVIEPLAYER"
 
-BS_MoviePlayer::BS_MoviePlayer(BS_Kernel * pKernel) : BS_Service(pKernel) {
+BS_Service *BS_OggTheora_CreateObject(BS_Kernel *pKernel) { return new BS_MoviePlayer(pKernel); }
+
+BS_MoviePlayer::BS_MoviePlayer(BS_Kernel *pKernel) : BS_Service(pKernel) {
 	if (!_RegisterScriptBindings())
 		BS_LOG_ERRORLN("Script bindings could not be registered.");
 	else
 		BS_LOGLN("Script bindings registered.");
 }
 
+bool BS_MoviePlayer::LoadMovie(const Common::String &Filename, unsigned int Z) {
+	return true;
+}
+
+bool BS_MoviePlayer::UnloadMovie() {
+	return true;
+}
+
+bool BS_MoviePlayer::Play() {
+	return true;
+}
+
+bool BS_MoviePlayer::Pause() {
+	return true;
+}
+
+void BS_MoviePlayer::Update() {
+}
+
+bool BS_MoviePlayer::IsMovieLoaded() {
+	return true;
+}
+
+bool BS_MoviePlayer::IsPaused() {
+	return true;
+}
+
+float BS_MoviePlayer::GetScaleFactor() {
+	return 1.0f;
+}
+
+void BS_MoviePlayer::SetScaleFactor(float ScaleFactor) {
+}
+
+double BS_MoviePlayer::GetTime() {
+	return 1.0;
+}
+
+
 } // End of namespace Sword25

Modified: scummvm/trunk/engines/sword25/fmv/movieplayer.h
===================================================================
--- scummvm/trunk/engines/sword25/fmv/movieplayer.h	2010-10-12 22:22:03 UTC (rev 53205)
+++ scummvm/trunk/engines/sword25/fmv/movieplayer.h	2010-10-12 22:22:33 UTC (rev 53206)
@@ -55,7 +55,7 @@
 	// -----------------------------------------------------------------------------
 
 	BS_MoviePlayer(BS_Kernel *pKernel);
-	virtual ~BS_MoviePlayer() {};
+	~BS_MoviePlayer() {};
 
 	// -----------------------------------------------------------------------------
 	// Abstract interface must be implemented by each Movie Player
@@ -71,14 +71,14 @@
 	 * @param Z				Z indicates the position of the film on the main graphics layer
 	 * @return				Returns false if an error occured while loading, otherwise true.
 	*/
-	virtual bool LoadMovie(const Common::String &Filename, unsigned int Z) = 0;
+	bool LoadMovie(const Common::String &Filename, unsigned int Z);
 
 	/**
 	 * Unloads the currently loaded movie file.
 	 * @return				Returns false if an error occurred while unloading, otherwise true.
 	 * @remark				This method can only be called when IsMovieLoaded() returns true.
 	 */
-	virtual bool UnloadMovie() = 0;
+	bool UnloadMovie();
 
 	/**
 	 * Plays the loaded movie.
@@ -88,7 +88,7 @@
 	 * @return				Returns false if an error occurred while starting, otherwise true.
 	 * @remark				This method can only be called when IsMovieLoaded() returns true.
 	 */
-	virtual bool Play() = 0;
+	bool Play();
 
 	/**
 	 * Pauses movie playback.
@@ -97,23 +97,23 @@
 	 * @return				Returns false if an error occurred while pausing, otherwise true.
 	 * @remark				This method can only be called when IsMovieLoaded() returns true.
 	 */
-	virtual bool Pause() = 0;
+	bool Pause();
 
 	/**
 	 * This function must be called once per frame.
 	 */
-	virtual void Update() = 0;
+	void Update();
 
 	/**
 	 * Returns whether a film is loaded for playback.
 	 */
-	virtual bool IsMovieLoaded() = 0;
+	bool IsMovieLoaded();
 
 	/**
 	 * Returns whether the movie playback is paused.
 	 * @remark				This method can only be called when IsMovieLoaded() returns true.
 	*/
-	virtual bool IsPaused() = 0;
+	bool IsPaused();
 
 	/**
 	 * Returns the scaling factor for the loaded film.
@@ -123,20 +123,20 @@
 	 * @return				Returns the scaling factor of the film.
 	 * @remark				This method can only be called when IsMovieLoaded() returns true.
 	 */
-	virtual float GetScaleFactor() = 0;
+	float GetScaleFactor();
 
 	/**
 	 * Sets the factor by which the loaded film is to be scaled.
 	 * @param ScaleFactor	The desired scale factor.
 	 * @remark				This method can only be called when IsMovieLoaded() returns true.
 	 */
-	virtual void SetScaleFactor(float ScaleFactor) = 0;
+	void SetScaleFactor(float ScaleFactor);
 
 	/**
 	 * Returns the current playing position in seconds.
 	 * @remark				This method can only be called when IsMovieLoaded() returns true.
 	 */
-	virtual double GetTime() = 0;
+	double GetTime();
 
 private:
 	bool _RegisterScriptBindings();

Modified: scummvm/trunk/engines/sword25/fmv/movieplayer_script.cpp
===================================================================
--- scummvm/trunk/engines/sword25/fmv/movieplayer_script.cpp	2010-10-12 22:22:03 UTC (rev 53205)
+++ scummvm/trunk/engines/sword25/fmv/movieplayer_script.cpp	2010-10-12 22:22:33 UTC (rev 53206)
@@ -23,7 +23,7 @@
  *
  */
 
-/* 
+/*
  * This code is based on Broken Sword 2.5 engine
  *
  * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
@@ -45,150 +45,138 @@
 
 namespace Sword25 {
 
-	int LoadMovie(lua_State * L)
-	{
-		BS_MoviePlayer * FMVPtr = BS_Kernel::GetInstance()->GetFMV();
-		BS_ASSERT(FMVPtr);
+int LoadMovie(lua_State *L) {
+	BS_MoviePlayer *FMVPtr = BS_Kernel::GetInstance()->GetFMV();
+	BS_ASSERT(FMVPtr);
 
-		lua_pushbooleancpp(L, FMVPtr->LoadMovie(luaL_checkstring(L, 1), lua_gettop(L) == 2 ? static_cast<unsigned int>(luaL_checknumber(L, 2)) : 10));
+	lua_pushbooleancpp(L, FMVPtr->LoadMovie(luaL_checkstring(L, 1), lua_gettop(L) == 2 ? static_cast<unsigned int>(luaL_checknumber(L, 2)) : 10));
 
-		return 1;
-	}
+	return 1;
+}
 
-	// -------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 
-	int UnloadMovie(lua_State * L)
-	{
-		BS_MoviePlayer * FMVPtr = BS_Kernel::GetInstance()->GetFMV();
-		BS_ASSERT(FMVPtr);
+int UnloadMovie(lua_State *L) {
+	BS_MoviePlayer *FMVPtr = BS_Kernel::GetInstance()->GetFMV();
+	BS_ASSERT(FMVPtr);
 
-		lua_pushbooleancpp(L, FMVPtr->UnloadMovie());
+	lua_pushbooleancpp(L, FMVPtr->UnloadMovie());
 
-		return 1;
-	}
+	return 1;
+}
 
-	// -------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 
-	int Play(lua_State * L)
-	{
-		BS_MoviePlayer * FMVPtr = BS_Kernel::GetInstance()->GetFMV();
-		BS_ASSERT(FMVPtr);
+int Play(lua_State *L) {
+	BS_MoviePlayer *FMVPtr = BS_Kernel::GetInstance()->GetFMV();
+	BS_ASSERT(FMVPtr);
 
-		lua_pushbooleancpp(L, FMVPtr->Play());
+	lua_pushbooleancpp(L, FMVPtr->Play());
 
-		return 1;
-	}
+	return 1;
+}
 
-	// -------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 
-	int Pause(lua_State * L)
-	{
-		BS_MoviePlayer * FMVPtr = BS_Kernel::GetInstance()->GetFMV();
-		BS_ASSERT(FMVPtr);
+int Pause(lua_State *L) {
+	BS_MoviePlayer *FMVPtr = BS_Kernel::GetInstance()->GetFMV();
+	BS_ASSERT(FMVPtr);
 
-		lua_pushbooleancpp(L, FMVPtr->Pause());
+	lua_pushbooleancpp(L, FMVPtr->Pause());
 
-		return 1;
-	}
+	return 1;
+}
 
-	// -------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 
-	int Update(lua_State * L)
-	{
-		BS_MoviePlayer * FMVPtr = BS_Kernel::GetInstance()->GetFMV();
-		BS_ASSERT(FMVPtr);
+int Update(lua_State *L) {
+	BS_MoviePlayer *FMVPtr = BS_Kernel::GetInstance()->GetFMV();
+	BS_ASSERT(FMVPtr);
 
-		FMVPtr->Update();
+	FMVPtr->Update();
 
-		return 0;
-	}
+	return 0;
+}
 
-	// -------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 
-	int IsMovieLoaded(lua_State * L)
-	{
-		BS_MoviePlayer * FMVPtr = BS_Kernel::GetInstance()->GetFMV();
-		BS_ASSERT(FMVPtr);
+int IsMovieLoaded(lua_State *L) {
+	BS_MoviePlayer *FMVPtr = BS_Kernel::GetInstance()->GetFMV();
+	BS_ASSERT(FMVPtr);
 
-		lua_pushbooleancpp(L, FMVPtr->IsMovieLoaded());
+	lua_pushbooleancpp(L, FMVPtr->IsMovieLoaded());
 
-		return 1;
-	}
+	return 1;
+}
 
-	// -------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 
-	int IsPaused(lua_State * L)
-	{
-		BS_MoviePlayer * FMVPtr = BS_Kernel::GetInstance()->GetFMV();
-		BS_ASSERT(FMVPtr);
+int IsPaused(lua_State *L) {
+	BS_MoviePlayer *FMVPtr = BS_Kernel::GetInstance()->GetFMV();
+	BS_ASSERT(FMVPtr);
 
-		lua_pushbooleancpp(L, FMVPtr->IsPaused());
+	lua_pushbooleancpp(L, FMVPtr->IsPaused());
 
-		return 1;
-	}
+	return 1;
+}
 
-	// -------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 
-	int GetScaleFactor(lua_State * L)
-	{
-		BS_MoviePlayer * FMVPtr = BS_Kernel::GetInstance()->GetFMV();
-		BS_ASSERT(FMVPtr);
+int GetScaleFactor(lua_State *L) {
+	BS_MoviePlayer *FMVPtr = BS_Kernel::GetInstance()->GetFMV();
+	BS_ASSERT(FMVPtr);
 
-		lua_pushnumber(L, FMVPtr->GetScaleFactor());
+	lua_pushnumber(L, FMVPtr->GetScaleFactor());
 
-		return 1;
-	}
+	return 1;
+}
 
-	// -------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 
-	int SetScaleFactor(lua_State * L)
-	{
-		BS_MoviePlayer * FMVPtr = BS_Kernel::GetInstance()->GetFMV();
-		BS_ASSERT(FMVPtr);
+int SetScaleFactor(lua_State *L) {
+	BS_MoviePlayer *FMVPtr = BS_Kernel::GetInstance()->GetFMV();
+	BS_ASSERT(FMVPtr);
 
-		FMVPtr->SetScaleFactor(static_cast<float>(luaL_checknumber(L, 1)));
+	FMVPtr->SetScaleFactor(static_cast<float>(luaL_checknumber(L, 1)));
 
-		return 0;
-	}
+	return 0;
+}
 
-	// -------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 
-	int GetTime(lua_State * L)
-	{
-		BS_MoviePlayer * FMVPtr = BS_Kernel::GetInstance()->GetFMV();
-		BS_ASSERT(FMVPtr);
+int GetTime(lua_State *L) {
+	BS_MoviePlayer *FMVPtr = BS_Kernel::GetInstance()->GetFMV();
+	BS_ASSERT(FMVPtr);
 
-		lua_pushnumber(L, FMVPtr->GetTime());
+	lua_pushnumber(L, FMVPtr->GetTime());
 
-		return 1;
-	}
+	return 1;
+}
 
-	// -------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 
-	const char * LIBRARY_NAME = "Movieplayer";
+const char *LIBRARY_NAME = "Movieplayer";
 
-	const luaL_reg LIBRARY_FUNCTIONS[] =
-	{
-		{ "LoadMovie", LoadMovie },
-		{ "UnloadMovie", UnloadMovie },
-		{ "Play", Play },
-		{ "Pause", Pause },
-		{ "Update", Update },
-		{ "IsMovieLoaded", IsMovieLoaded },
-		{ "IsPaused", IsPaused },
-		{ "GetScaleFactor", GetScaleFactor },
-		{ "SetScaleFactor", SetScaleFactor },
-		{ "GetTime", GetTime },
-		{ 0, 0 }
-	};
+const luaL_reg LIBRARY_FUNCTIONS[] = {
+	{ "LoadMovie", LoadMovie },
+	{ "UnloadMovie", UnloadMovie },
+	{ "Play", Play },
+	{ "Pause", Pause },
+	{ "Update", Update },
+	{ "IsMovieLoaded", IsMovieLoaded },
+	{ "IsPaused", IsPaused },
+	{ "GetScaleFactor", GetScaleFactor },
+	{ "SetScaleFactor", SetScaleFactor },
+	{ "GetTime", GetTime },
+	{ 0, 0 }
+};
 
-bool BS_MoviePlayer::_RegisterScriptBindings()
-{
-	BS_Kernel * pKernel = BS_Kernel::GetInstance();
+bool BS_MoviePlayer::_RegisterScriptBindings() {
+	BS_Kernel *pKernel = BS_Kernel::GetInstance();
 	BS_ASSERT(pKernel);
-	BS_ScriptEngine * pScript = static_cast<BS_ScriptEngine *>(pKernel->GetService("script"));
+	BS_ScriptEngine *pScript = static_cast<BS_ScriptEngine *>(pKernel->GetService("script"));
 	BS_ASSERT(pScript);
-	lua_State * L = static_cast<lua_State *>(pScript->GetScriptObject());
+	lua_State *L = static_cast<lua_State *>(pScript->GetScriptObject());
 	BS_ASSERT(L);
 
 	if (!BS_LuaBindhelper::AddFunctionsToLib(L, LIBRARY_NAME, LIBRARY_FUNCTIONS)) return false;

Added: scummvm/trunk/engines/sword25/fmv/theora_decoder.cpp
===================================================================
--- scummvm/trunk/engines/sword25/fmv/theora_decoder.cpp	                        (rev 0)
+++ scummvm/trunk/engines/sword25/fmv/theora_decoder.cpp	2010-10-12 22:22:33 UTC (rev 53206)
@@ -0,0 +1,434 @@
+/* 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$
+ *
+ */
+
+/*
+ * Source is based on the player example from libvorbis package
+ *
+ * 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 "sword25/fmv/theora_decoder.h"
+#include "common/system.h"
+
+namespace Sword25 {
+
+TheoraDecoder::TheoraDecoder() {
+	_fileStream = 0;
+	_surface = 0;
+
+	_theoraPacket = 0;
+	_vorbisPacket = 0;
+	_stateFlag = 0;
+}
+
+TheoraDecoder::~TheoraDecoder() {
+	close();
+}
+
+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::load(Common::SeekableReadStream &stream) {
+	close();
+
+	_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
+	while (!_stateFlag) {
+		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);
+				_stateFlag = 1;
+				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);
+
+		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);
+
+	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);
+	} else {
+		// tear down the partial vorbis setup
+		vorbis_info_clear(&_vorbisInfo);
+		vorbis_comment_clear(&_vorbisComment);
+	}
+
+	// open audio
+	if (_vorbisPacket)
+		open_audio();
+
+	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);
+	}
+	if (_theoraPacket) {
+		ogg_stream_clear(&_theoraOut);
+		th_decode_free(_theoraDecode);
+		th_comment_clear(&_theoraComment);
+		th_info_clear(&_theoraInfo);
+	}
+	ogg_sync_clear(&_oggSync);
+
+	if (!_fileStream)
+		return;
+
+	delete _fileStream;
+	_fileStream = 0;
+
+	_surface->free();
+	delete _surface;
+	_surface = 0;
+
+	reset();
+}
+
+Graphics::Surface *TheoraDecoder::decodeNextFrame() {
+	int i, j;
+
+	_stateFlag = 0; // playback has not begun
+
+	// 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) / 2 / _vorbisInfo.channels;
+			for (i = 0; i < ret && i < maxsamples; i++)
+				for (j = 0; j < _vorbisInfo.channels; j++) {
+					int val = CLIP(rint(pcm[j][i] * 32767.f), -32768, 32768);
+					_audiobuf[count++] = val;
+				}
+
+			vorbis_synthesis_read(&_vorbisDSP, i);
+			_audiobufFill += i * _vorbisInfo.channels * 2;
+
+			if (_audiobufFill == audiofd_fragsize)
+				_audiobufReady = 1;
+
+			if (_vorbisDSP.granulepos >= 0)
+				_audiobufGranulePos = _vorbisDSP.granulepos - ret + i;
+			else
+				_audiobufGranulePos += i;
+			} 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 && !_videobufReady) {
+		// 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;
+			}
+			// 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);
+				_curFrame++;
+
+				// is it already too old to be useful?  This is only actually
+				// useful cosmetically after a SIGSTOP.  Note that we have to
+				// decode the frame even if we don't show it (for now) due to
+				// keyframing.  Soon enough libtheora will be able to deal
+				// with non-keyframe seeks. 
+
+				if (_videobufTime >= get_time())
+					_videobufReady = 1;
+				else {
+					// If we are too slow, reduce the pp level.
+					_ppInc = _ppLevel > 0 ? -1 : 0;
+					dropped++;
+				}
+			}
+		} else
+			break;
+	}
+
+	if (!_videobufReady && !_audiobufReady && _fileStream->eos())
+		break;
+
+	if (!_videobufReady || !_audiobufReady) {
+		// no data yet for somebody.  Grab another page
+		bufferData();
+		while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) {
+			queuePage(&_oggPage);
+		}
+	}
+
+	// If playback has begun, top audio buffer off immediately.
+	if (_stateFlag) audio_write_nonblocking();
+
+	// are we at or past time for this video frame?
+	if (_stateFlag && _videobufReady && _videobufTime <= get_time()) {
+		video_write();
+		_videobufReady = 0;
+	}
+
+	if (_stateFlag &&
+		(_audiobufReady || !_vorbisPacket) &&
+		(_videobufReady || !_theoraPacket) &&
+		!got_sigint) {
+		// we have an audio frame ready (which means the audio buffer is
+		// full), it's not time to play video, so wait until one of the
+		// audio buffer is ready or it's near time to play video
+
+		// set up select wait on the audiobuffer and a timeout for video
+		struct timeval timeout;
+		fd_set writefs;
+		fd_set empty;
+		int n = 0;
+
+		FD_ZERO(&writefs);
+		FD_ZERO(&empty);
+		if (audiofd >= 0) {
+			FD_SET(audiofd, &writefs);
+			n = audiofd + 1;
+		}
+
+		if (_theoraPacket) {
+			double tdiff;
+			long milliseconds;
+			tdiff = _videobufTime - get_time();
+
+			// If we have lots of extra time, increase the post-processing level.
+			if (tdiff > _theoraInfo.fps_denominator * 0.25 / _theoraInfo.fps_numerator) {
+				_ppInc = _ppLevel < _ppLevelMax ? 1 : 0;
+			} else if (tdiff < _theoraInfo.fps_denominator * 0.05 / _theoraInfo.fps_numerator) {
+				_ppInc = _ppLevel > 0 ? -1 : 0;
+			}
+			milliseconds = tdiff * 1000 - 5;
+			if (milliseconds > 500)
+				milliseconds = 500;
+			if (milliseconds > 0) {
+				timeout.tv_sec = milliseconds / 1000;
+				timeout.tv_usec = (milliseconds % 1000) * 1000;
+
+				n = select(n, &empty, &writefs, &empty, &timeout);
+				if (n)
+					audio_calibrate_timer(0);
+			}
+		} else {
+			select(n, &empty, &writefs, &empty, NULL);
+		}
+	}
+
+	// if our buffers either don't exist or are ready to go,
+	// we can begin playback
+	if ((!_theoraPacket || _videobufReady) &&
+		(!_vorbisPacket || _audiobufReady))
+		_stateFlag = 1;
+
+	// same if we've run out of input
+	if (_fileStream->eos())
+		_stateFlag = 1;
+}
+
+void TheoraDecoder::reset() {
+	VideoDecoder::reset();
+	if (_fileStream)
+		_fileStream->seek(0);
+
+	_videobufReady = 0;
+	_videobufGranulePos = -1;
+	_videobufTime = 0;
+
+	_audiobufFill = 0;
+	_audiobufReady = 0;
+	_audiobufGranulePos = 0;
+}
+
+} // End of namespace Sword25


Property changes on: scummvm/trunk/engines/sword25/fmv/theora_decoder.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/engines/sword25/fmv/theora_decoder.h
===================================================================
--- scummvm/trunk/engines/sword25/fmv/theora_decoder.h	                        (rev 0)
+++ scummvm/trunk/engines/sword25/fmv/theora_decoder.h	2010-10-12 22:22:33 UTC (rev 53206)
@@ -0,0 +1,120 @@
+/* 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 SWORD25_THEORADECODER_H
+#define SWORD25_THEORADECODER_H
+
+#include "graphics/video/video_decoder.h"
+
+#include <theora/theoradec.h>
+#include <vorbis/codec.h>
+
+namespace Common {
+	class SeekableReadStream;
+}
+
+namespace Sword25 {
+
+/**
+ *
+ * Decoder for Theora videos.
+ * Video decoder used in engines:
+ *  - sword25
+ */
+class TheoraDecoder : public Graphics::FixedRateVideoDecoder {
+public:
+	TheoraDecoder();
+	virtual ~TheoraDecoder();
+
+	/**
+	 * Load a video file
+	 * @param stream  the stream to load
+	 */
+	bool load(Common::SeekableReadStream &stream);
+	void close();
+
+	/**
+	 * 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
+	 */
+	Graphics::Surface *decodeNextFrame();
+
+	bool isVideoLoaded() const { return _fileStream != 0; }
+	uint16 getWidth() const { return _surface->w; }
+	uint16 getHeight() const { return _surface->h; }
+	uint32 getFrameCount() const { return _frameCount; }
+	Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 0, 0, 0); }
+
+protected:
+	Common::Rational getFrameRate() const { return _frameRate; }
+
+private:
+	void queuePage(ogg_page *page);
+	int bufferData();
+
+private:
+	Common::SeekableReadStream *_fileStream;
+	Graphics::Surface *_surface;
+	Common::Rational _frameRate;
+	uint32 _frameCount;
+
+	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 _stateFlag;
+
+	int _ppLevelMax;
+	int _ppLevel;
+	int _ppInc;
+
+	// single frame video buffering
+	int _videobufReady;
+	ogg_int64_t  _videobufGranulePos;
+	double _videobufTime;
+
+	// single audio fragment audio buffering
+	int _audiobufFill;
+	int _audiobufReady;
+	ogg_int16_t *_audiobuf;
+	ogg_int64_t  _audiobufGranulePos; // time position of last sample
+};
+
+} // End of namespace Sword25
+
+#endif


Property changes on: scummvm/trunk/engines/sword25/fmv/theora_decoder.h
___________________________________________________________________
Added: svn:executable
   + *
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Modified: scummvm/trunk/engines/sword25/module.mk
===================================================================
--- scummvm/trunk/engines/sword25/module.mk	2010-10-12 22:22:03 UTC (rev 53205)
+++ scummvm/trunk/engines/sword25/module.mk	2010-10-12 22:22:33 UTC (rev 53206)
@@ -5,14 +5,7 @@
 	sword25.o \
 	fmv/movieplayer.o \
 	fmv/movieplayer_script.o \
-	fmv/oggtheora/audiobuffer.o \
-	fmv/oggtheora/moviefile.o \
-	fmv/oggtheora/oggstate.o \
-	fmv/oggtheora/oggstreamstate.o \
-	fmv/oggtheora/oggtheora.o \
-	fmv/oggtheora/theorastate.o \
-	fmv/oggtheora/vorbisstate.o \
-	fmv/oggtheora/yuvtorgba.o \
+	fmv/theora_decoder.o \
 	gfx/animation.o \
 	gfx/animationdescription.o \
 	gfx/animationresource.o \


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list