Game Development Community

dev|Pro Game Development Curriculum

1.4 Theora Support In TSE

by Jon Wilsdon · 04/02/2006 (10:28 am) · 26 comments

I assume you have gotten TGE 1.4 and are using Visual Studio. This format should be familiar to you if you got TGE 1.4 theora support to work in 1.3 since this shares quite a few steps with that resource.

Copy over the theora stuff from 1.4.

copy 1.4/engine/core/theoraPlayer.cc to TSE/engine/core/theoraPlayer.cpp (extension change made for consistency)
copy 1.4/engine/core/theoraPlayer.h to TSE/engine/core/theoraPlayer.h

create a new folder in TSE/engine/gui/ that is called shiny/

copy 1.4/engine/gui/shiny/guiTheoraCtrl.cc to TSE/engine/gui/shiny/guiTheoraCtrl.cpp (extension change made for consistency)
copy 1.4/engine/gui/shiny/guiTheoraCtrl.h to TSE/engine/gui/shiny/guiTheoraCtrl.h

copy 1.4/engine/audio/oggMixedStreamSource.h to TSE/engine/audio/oggMixedStreamSource.cpp (extension change made for consistency)
copy 1.4/engine/audio/oggMixedStreamSource.h to TSE/engine/audio/oggMixedStreamSource.h

copy 1.4/engine/core/dataChunker.h to TSE/engine/core/dataChunker.h (this replaces an existing file)

copy the whole 1.4/lib/xiph directory to TSE/lib/xiph (you probably want to remove the CVS directories after copying)

to clean things up that won't be used, delete the TSE/lib/xiph/linux/ and TSE/lib/xiph/macosx/ directories.

Set up Visual Studio

load up the solution file in visual studio

in the solution:
add core/theoraPlayer.cpp
add core/theoraPlayer.h
add a new folder in gui/ called shiny/
add gui/shiny/guiTheoraCtrl.cpp
add gui/shiny/guiTheoraCtrl.h
add audio/oggMixedStreamSource.cpp
add audio/oggMixedStreamSource.h

In your Solution Explorer in Visual Studio right click on Torque Shader Engine and click Properties. Select Linker, then Input on the left and in the Additional Dependencies on the right, change ../lib/vorbis/win32/ogg_static.lib to ../lib/xiph/win32/ogg_static.lib and ../lib/vorbis/win32/vorbis_static_mt.lib to ../lib/xiph/win32/vorbis_static_mt.lib and then add ../lib/xiph/win32/theora_static.lib

Then click on C/C++ on the left and in the Additional Include Directories change ../lib/vorbis/include to ../lib/xiph/include

Make Code Changes

change the includes to be gfx calls

in engine/core/theoraPlayer.h change
#ifndef _GTEXMANAGER_H_
#include "dgl/gTexManager.h"
#endif

#ifndef _GBITMAP_H_
#include "dgl/gBitmap.h"
#endif

... to ...

#ifndef _GTEXMANAGER_H_
#include "gfx/gfxTextureHandle.h"
#endif

#ifndef _GBITMAP_H_
#include "gfx/gBitmap.h"
#endif

in engine/core/theoraPlayer.h after all the #ifndef's add
#ifndef _PLATFORMMUTEX_H_
#include "platform/platformMutex.h"
#endif

update to the new texture object

in engine/core/theoraPlayer.h change
operator TextureObject*()
   {
      return (TextureObject*)*mTextureHandle;
   }

... to ...

   operator GFXTextureObject*()
   {
      return *mTextureHandle;
   }

no need to include OpenGL functions

in engine/core/theoraPlayer.h change
U32  getGLName();

... to ...

// U32  getGLName();

in engine/core/theoraPlayer.h change
TextureHandle*	mTextureHandle;

... to ...

   GFXTexHandle*	mTextureHandle;

update rendering calls with a new texture profile

in engine/core/theoraPlayer.cpp {createVideoBuffers()} change
const GBitmap *bmp = new GBitmap(
                        getMax((U32)mTheoraInfo.frame_width, (U32)mTheoraInfo.width),
                        getMax((U32)mTheoraInfo.frame_height, (U32)mTheoraInfo.height),
                        false, GBitmap::RGB);

   mTextureHandle = new TextureHandle(NULL, bmp, true);

... to ...

   GBitmap *bmp = new GBitmap(
                        getMax(mTheoraInfo.frame_width, mTheoraInfo.width),
                        getMax(mTheoraInfo.frame_height, mTheoraInfo.height),
                        false, GFXFormatR8G8B8);

   mTextureHandle = new GFXTexHandle(bmp, &GFXTheoraProfile, true);

use getAddress to be consistent

in engine/core/theoraPlayer.cpp {drawFrame()} change
U8 *dst1 = dst0 + bmp->getWidth() * bmp->bytesPerPixel;

... to ...

   U8 *dst1 = bmp->getAddress(0, 1);

we need to make the theora player write out as bgr instead of rgb

in engine/core/theoraPlayer.cpp {drawFrame()} change
// pixel 0x0
         *dst0++ = sClamp[sAdjY[*pY0] + sAdjCrr[*pV]];
         *dst0++ = sClamp[sAdjY[*pY0] - G];
         *dst0++ = sClamp[sAdjY[*pY0++] + sAdjCbb[*pU]];

         // pixel 1x0
         *dst0++ = sClamp[sAdjY[*pY0] + sAdjCrr[*pV]];
         *dst0++ = sClamp[sAdjY[*pY0] - G];
         *dst0++ = sClamp[sAdjY[*pY0++] + sAdjCbb[*pU]];

         // pixel 0x1
         *dst1++ = sClamp[sAdjY[*pY1] + sAdjCrr[*pV]];
         *dst1++ = sClamp[sAdjY[*pY1] - G];
         *dst1++ = sClamp[sAdjY[*pY1++] + sAdjCbb[*pU]];

         // pixel 1x1
         *dst1++ = sClamp[sAdjY[*pY1] + sAdjCrr[*pV++]];
         *dst1++ = sClamp[sAdjY[*pY1] - G];
         *dst1++ = sClamp[sAdjY[*pY1++] + sAdjCbb[*pU++]];

... to ...

         // pixel 0x0
         *dst0++ = sClamp[sAdjY[*pY0++] + sAdjCbb[*pU]];
         *dst0++ = sClamp[sAdjY[*pY0] - G];
         *dst0++ = sClamp[sAdjY[*pY0] + sAdjCrr[*pV]];

         // pixel 1x0
		 *dst0++ = sClamp[sAdjY[*pY0++] + sAdjCbb[*pU]];
         *dst0++ = sClamp[sAdjY[*pY0] - G];
		 *dst0++ = sClamp[sAdjY[*pY0] + sAdjCrr[*pV]];

         // pixel 0x1
         *dst1++ = sClamp[sAdjY[*pY1++] + sAdjCbb[*pU]];
         *dst1++ = sClamp[sAdjY[*pY1] - G];
         *dst1++ = sClamp[sAdjY[*pY1] + sAdjCrr[*pV]];

         // pixel 1x1
         *dst1++ = sClamp[sAdjY[*pY1++] + sAdjCbb[*pU++]];
         *dst1++ = sClamp[sAdjY[*pY1] - G];
         *dst1++ = sClamp[sAdjY[*pY1] + sAdjCrr[*pV++]];

in engine/core/theoraPlayer.cpp {play()} change
mPlayThread = new Thread((ThreadRunFunction)playThread, (S32) this, 1);

... to ...

      mPlayThread = new Thread((ThreadRunFunction)playThread, this, true);

we don't need the OpenGL stuff anymore

in engine/core/theoraPlayer.cpp change
U32 TheoraTexture::getGLName()
{
   if(mTextureHandle)
   {
      mTextureHandle->refresh();
      return mTextureHandle->getGLName();
   }
   return 0;
}

... to ...

/*U32 TheoraTexture::getGLName()
{
   if(mTextureHandle)
   {
      mTextureHandle->refresh();
      return mTextureHandle->getGLName();
   }
   return 0;
}*/

straight dgl to gfx conversions

in engine/gui/shiny/guiTheoraCtrl.cpp change
#include "dgl/dgl.h"

... to ...

#include "gfx/gBitmap.h"

in engine/gui/shiny/guiTheoraCtrl.cpp change
dglClearBitmapModulation();
		dglDrawBitmapStretch(mTheoraTexture, rect);

... to ...

		GFX->clearBitmapModulation();
		GFX->drawBitmapStretch(mTheoraTexture, rect);

in engine/gui/shiny/guiTheoraCtrl.cpp change
dglDrawRectFill(rect, mBackgroundColor); // black rect

... to ...

 		GFX->drawRectFill(rect, mBackgroundColor); // black rect

in engine/audio/audio.cpp change
mHandle[index] |= AUDIOHANDLE_STREAMING_BIT;

... to ...

      mHandle[index] |= AUDIOHANDLE_STREAMING_BIT | AUDIOHANDLE_LOADING_BIT;

in engine/audio/audio.cpp change
return NULL;
//   AudioStreamSource *streamSource = AudioStreamSourceFactory::getNewInstance(filename);
//   return(streamSource);

... to ...

   AudioStreamSource *streamSource = AudioStreamSourceFactory::getNewInstance(filename);
   return(streamSource);

at the end of engine/audio/audio.cpp add
AudioStreamSource* alxFindAudioStreamSource(AUDIOHANDLE handle)
{
	StreamingList::iterator itr2 = mStreamingList.findImage(handle);
	if(itr2)
		return *itr2;
	return NULL;
}

add the new texture profile

in engine/gfx/gfxTextureProfile.cpp after the other ImplementTextureProfile's add
GFX_ImplementTextureProfile(GFXTheoraProfile, 
                            GFXTextureProfile::DiffuseMap,
                            GFXTextureProfile::KeepBitmap | GFXTextureProfile::Dynamic | GFXTextureProfile::NoMipmap,
                            GFXTextureProfile::None);

in engine/gfx/gfxTextureProfile.h after the other DeclareTextureProfile's add
// Texture for Theora videos
GFX_DeclareTextureProfile( GFXTheoraProfile );

in engine/gfx/gfxTextureManager.h change
virtual bool _loadTexture(GFXTextureObject *texture, GBitmap *bmp)=0;

... to ...

      virtual bool _loadTexture(GFXTextureObject *texture, GBitmap *bmp, bool convert=true)=0;

in engine/gfx/D3D/gfxD3DTextureManager.h change
bool _loadTexture(GFXTextureObject *texture, GBitmap *bmp);

... to ...

      bool _loadTexture(GFXTextureObject *texture, GBitmap *bmp, bool convert = true);

in engine/gfx/D3D/gfxD3DTextureManager.cpp change
bool GFXD3DTextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *pDL)

... to ...

bool GFXD3DTextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *pDL, bool convert)

in engine/gfx/D3D/gfxD3DTextureManager.cpp {_loadTexture()} change
pDL->convertToBGRx(); // This does checking for format inside it, fear not

... to ...

   if( convert ) 
       pDL->convertToBGRx(); // This does checking for format inside it, fear not

in engine/gfx/D3D/gfxD3DTextureManager.cpp {_refreshTexture()} before the texture->mProfile->doStoreBitmap if, add
if(texture->mProfile->doStoreBitmap() && texture->mProfile->isDynamic() ) {
	   
	   realTex->release();
	   innerCreateTexture(realTex, texture->getHeight(), texture->getWidth(), texture->getDepth(), texture->mFormat, texture->mProfile, texture->mMipLevels);

	   if(texture->mBitmap)
		   _loadTexture(texture, texture->mBitmap, false);

	   usedStrategies++;
   }
   else {

and in engine/gfx/D3D/gfxD3DTextureManager.cpp {refreshTexture()} after the last } of the second if add
}

in engine/platform/platformAudio.h after the AudioSampleEnvironment class add:
class AudioStreamSource;

in engine/platform/platformAudio.h after the last alxCreateSource add
AudioStreamSource* alxFindAudioStreamSource(AUDIOHANDLE handle);

in engine/audio/audioStreamSourceFactory.cpp after including vorbisStreamSource.h add
#include "audio/oggMixedStreamSource.h"

in engine/audio/audioStreamSourceFactory.cpp after the #ifndef NO_OGGVORBIS add
if(!dStricmp(filename, "oggMixedStream"))
        return new OggMixedStreamSource(filename);

remove the mutex code in engine/core/theoraPlayer.cpp... it was too much of a pain to try to add and works fine without it... below are all the unique lines that need to be deleted... you can just do a find for these lines.
mMutex = Mutex::createMutex();

   Mutex::destroyMutex(mMutex);

   MutexHandle handle;
   handle.lock(mMutex);

remove the mutex from engine/core/theoraPlayer.h
void *mMutex;

For some of the reasoning behind these changes, take a look at this thread: www.garagegames.com/mg/forums/result.thread.php?qt=35943

Testing

To test it you can create a video folder in your example/demo/data/ directory then copy over the 1.4/example/demo/data/video/soundTest.ogg file to the video directory you just created.

As a simple test, in your example/demo/client/ui/ folder create a new file called videoGui.gui:
//--- OBJECT WRITE BEGIN ---
new GuiTheoraCtrl(theo) {
   profile = "GuiDefaultProfile";
   horizSizing = "center";
   vertSizing = "center";
   position = "40 25";
   extent = "512 512";
   minExtent = "8 2";
   visible = "1";
   done = "0";
   stopOnSleep = "1";
   backgroundColor = "0 0 0 255";
};
//--- OBJECT WRITE END ---

Start the demo and get to the main menu. Bring down the console and type:
exec("demo/client/ui/videoGui.gui");
canvas.pushDialog("theo");
theo.setFile("demo/data/video/soundtest.ogg");

and the video should play... the gui will probably stretch to fill the screen, but this resource just kept getting larger and larger and by the time I got to the gui part, I didn't really want to fix it.

You will also want to make sure that you have one of the latest versions of the OpenAL32.dll... mine is somewhere around 100K.

March 07, 2006 Update

The resource used to say to do this:


trying to use getAddress the way I think it was intended

in engine/core/theoraPlayer.cpp {drawFrame()} change

dst1 += bmp->getWidth() * bmp->bytesPerPixel;

... to ...

      dst1 = bmp->getAddress(0,y+1);

but the getAddress call is actually incorrect, so until I know why that call is off just slighty, using the original line will work.

Jon
Page«First 1 2 Next»
#21
09/03/2007 (12:08 pm)
yeah that is not very usefull have you tried using a debug version and launching the debug from within visual studio? that usually give more detail.
#22
09/06/2007 (1:55 am)
Thanks, works fine so far with TGEA 1.0.3 in fullscreen mode with 320x240 test videos. I didn't have to replace dataChunker.h though :) More tests will follow the next days...
#23
01/14/2008 (1:44 pm)
Hello I hope someone is still listening to this post. I have TGEA 1.0.3 and can't seem to get the video to play. All I get is the sound. no Crashes or warnings just no video. Hope someone can help.
#24
09/18/2008 (5:38 am)
Many thanks, it worked the first time out of the box
#25
12/18/2008 (6:20 pm)
bump for 1.7.1 or 1.8?
#26
07/13/2009 (11:21 am)
bump for 1.7.1 or 1.8?
Page«First 1 2 Next»