Page 1 of 7

(Code Snippet) Video reproduction using DirectShow

Posted: Tue Jan 23, 2007 4:43 am
by hmoraldo
Hi all,

This is a small video reproduction code snippet using Direct Show. I'll be posting it in the wiki possibly in the next week, but before that, I wanted to post it here so other fellow developers can test it in their computers and tell me about any bugs or general issues it could have.

The idea is simple: a small code snippet for playing video on Ogre materials / textures; not a full-blown video player but a class that is small enough that other coders can adapt it to their needs.

Enjoy it! And please post here your ideas, suggestions and bug reports.

Thank you!!

Edit: now the latest version of the full code and usage is available here: http://www.ogre3d.org/wiki/index.php/Di ... re_texture

Edit: removed "Preview" from the title

Posted: Tue Jan 23, 2007 5:13 pm
by hmoraldo
Well I've been testing it and it works perfectly... I'll clean the code and post it in the wiki next days, but if anyone needs it, the posted version is already working with no problems (excepting only working in Windows, of course).

Posted: Sat Jan 27, 2007 12:50 am
by hmoraldo
Finally, I posted a revised version of this code snippet here: http://www.ogre3d.org/wiki/index.php/Di ... re_texture

If anyone was using the previous version, please update, as I made some important changes (including correcting one or two small bugs related to memory management).

Best regards!

Posted: Sat Jan 27, 2007 7:44 pm
by sinbad
Nice snippet, thanks.

Posted: Tue Jan 30, 2007 6:19 am
by odyeiop
Hey, I'm using Visual Studio 2003 .NET (7.1), installed the required SDK, but the compiler can't find 'h-genutils.h'. Where is this located? I'm quite interested in trying a couple of things with this =)

Posted: Tue Jan 30, 2007 6:37 am
by hmoraldo
Hmmm... I forgot to include that one. Thank you!

Tomorrow I'll modify the code in the wiki to solve that problem... until then, as a temporary patch you can add the following two files:

h-genutils.h:

Code: Select all

#ifndef PROG_FILE_HGENUTILS
#define PROG_FILE_HGENUTILS

#include "windows.h"

namespace hGenUtils {
	// convert a char* to a wchar*
	WCHAR* convertCStringToWString(const char* string);
}

#endif // PROG_FILE_HGENUTILS
h-genutils.cpp:

Code: Select all

#include "h-genutils.h"

#include <Ogre.h>


// convert a char* to a wchar*
// warning: the return value points to a fixed buffer, whose contents change with
// every call to this function.
WCHAR* hGenUtils::convertCStringToWString(const char* string)
{
	const int MAX_STRINGZ=500;
	static WCHAR wtext[MAX_STRINGZ+2];

	if (strlen(string)>MAX_STRINGZ)
	{
		throw("hGenUtils::convertCStringToWString buffer isn't big enough");
	}

	// convert text to wchar
	if (MultiByteToWideChar(
		CP_ACP,// ansi code page
		0,// flags
		string,// orig string
		-1,// calculate len
		wtext,// where to put the string
		MAX_STRINGZ)// maximum allowed path
		==0)
	{
		throw("hGenUtils::convertCStringToWString failed with no extra error info");
	}

	return wtext;
}

Please tell me if it works for you.

Posted: Tue Jan 30, 2007 7:23 am
by odyeiop
That cleared up the errors I had (and I forgot to use the namespace, so that's in place now to), but I'm getting some compile errors. These
error LNK2001: unresolved external symbol _IID_IVideoWindow
error LNK2001: unresolved external symbol _FORMAT_VideoInfo
error LNK2001: unresolved external symbol _MEDIASUBTYPE_RGB24
error LNK2001: unresolved external symbol _MEDIATYPE_Video
error LNK2001: unresolved external symbol _IID_ISampleGrabber
error LNK2001: unresolved external symbol _CLSID_SampleGrabber
error LNK2001: unresolved external symbol _IID_IBaseFilter
error LNK2001: unresolved external symbol _IID_IMediaSeeking
error LNK2001: unresolved external symbol _IID_IMediaEvent
error LNK2001: unresolved external symbol _IID_IMediaControl
error LNK2001: unresolved external symbol _CLSID_FilterGraph
error LNK2001: unresolved external symbol _IID_IGraphBuilder
These are all used starting in UtilsOgreDshow.cpp at line 121, but I can't where they are declared. Although a most of them are recognized by intellisense :
CLSID_FilterGraph
IID_IMediaControl
IID_IMediaEvent
FORMAT_VideoInfo
MEDIASUBTYPE_RGB24
MEDIATYPE_Video

Posted: Tue Jan 30, 2007 3:22 pm
by hmoraldo
Ha! You have to link to Strmiids.lib too. I forgot that in the code documentation, thank you.

Posted: Tue Jan 30, 2007 7:41 pm
by odyeiop
Ah, well everything is fine now. I just have to actually put the video I have on a visible surface. Although if I compile in debug I still get the linking errors, I have to compile it in release for it to build properly, any idea why this might be?

Very cool though =) I'll let you know how it is when I start throwing some videos around.

Posted: Tue Jan 30, 2007 7:46 pm
by hmoraldo
What linking errors are you getting on debug? I compiled this with no problems in debug.

Thanks a lot for your feedback.

Posted: Tue Jan 30, 2007 8:02 pm
by odyeiop
The same ones that I had received before I added Strmiids.lib
UtilsOgreDshow.obj : error LNK2001: unresolved external symbol _IID_IVideoWindow
UtilsOgreDshow.obj : error LNK2001: unresolved external symbol _FORMAT_VideoInfo
UtilsOgreDshow.obj : error LNK2001: unresolved external symbol _MEDIASUBTYPE_RGB24
UtilsOgreDshow.obj : error LNK2001: unresolved external symbol _MEDIATYPE_Video
UtilsOgreDshow.obj : error LNK2001: unresolved external symbol _IID_ISampleGrabber
UtilsOgreDshow.obj : error LNK2001: unresolved external symbol _CLSID_SampleGrabber
UtilsOgreDshow.obj : error LNK2001: unresolved external symbol _IID_IBaseFilter
UtilsOgreDshow.obj : error LNK2001: unresolved external symbol _IID_IMediaSeeking
UtilsOgreDshow.obj : error LNK2001: unresolved external symbol _IID_IMediaEvent
UtilsOgreDshow.obj : error LNK2001: unresolved external symbol _IID_IMediaControl
UtilsOgreDshow.obj : error LNK2001: unresolved external symbol _CLSID_FilterGraph
UtilsOgreDshow.obj : error LNK2001: unresolved external symbol _IID_IGraphBuilder

Posted: Tue Jan 30, 2007 8:06 pm
by hmoraldo
I uploaded these corrections to the wiki (including the detail of what libraries you need to link to).

Posted: Tue Jan 30, 2007 8:07 pm
by hmoraldo
odyeiop wrote:The same ones that I had received before I added Strmiids.lib
Check you added Strmiids.lib to both project configurations, and not only to release. I suppose that's your problem here.

Posted: Tue Jan 30, 2007 8:11 pm
by odyeiop
Thank you people, I gratefully accept your nominations for noob of the year award.

That was indeed the case. I thought that the additional dependencies were constant no matter how you built the project. Live and learn =) Thanks.

Posted: Tue Jan 30, 2007 8:14 pm
by hmoraldo
Thank you for using it!

Posted: Wed Jan 31, 2007 1:33 am
by odyeiop
when I call the ->isPlaying(), it crashes. Says that hr is being used without being defined.
bool DirectShowMovieTexture::isPlayingMovie()
{
OAFilterState pfs;
HRESULT hr;<-DECLARED(line 430 UtilsOgreDshow.cpp)

if (dsdata->pEvent!=NULL){
long ev, p1, p2;

while (E_ABORT!=dsdata->pEvent->GetEvent(&ev, &p1, &p2, 0)){
// check for completion
if (ev==EC_COMPLETE)
{
pauseMovie();
return false;
}

// release event params
dsdata->pEvent->FreeEventParams(ev, p1, p2);
if (FAILED(hr)) <-HERE (line 445 UtilsOgreDshow.cpp)
{
pauseMovie();
return false;
}
it is declared at the beginning of the function, but indeed it is not defined anywhere, unless I'm missing something.

if I take that out and just call the ->playMovie() at the end of the state::enter, and ->updateMovieTexture() in the frameStarted, it still does not display anything.

Posted: Wed Jan 31, 2007 1:38 am
by hmoraldo
Well spot!! It's almost a miracle it worked here...

All you'll need is to fix this line:

Code: Select all

hr=dsdata->pEvent->FreeEventParams(ev, p1, p2);
I'll fix it in the wiki too, thank you!

Edit:
odyeiop wrote:if I take that out and just call the ->playMovie() at the end of the state::enter, and ->updateMovieTexture() in the frameStarted, it still does not display anything.
First check you can make this work without using isPlayingMovie. Do the object creation, then the load movie, then the playmovie. If your movie has sound, then you'd have to be hearing such sounds.

Once you get that working, add the updateMovieTexture, and then, add the tex->setTextureName(dshowMovieTextureSystem->getMovieTexture()->getName()); code as explained in the wiki, to make the texture be used in a material you can see. Then check the video is actually shown in the material (and if not... what do you see in the material? a black texture? junk data? the original texture for that material?).

Posted: Wed Jan 31, 2007 1:44 am
by odyeiop
=D It works perfectly now! Very nice! Thank you very much

Posted: Wed Jan 31, 2007 1:45 am
by hmoraldo
Fantastic news! Thank you for your time

Posted: Wed Jan 31, 2007 2:37 am
by odyeiop
Is there a way to get the Length of the movie, and the Position that the movie is currently running at? I was looking over dsdata, and seemed that maybe pSeeking->getDuration may work. I wasn't sure what values they were supposed to take in though.


There are 2 problems I'm encountering now though.
I set the dimensions of the plane to the dimension of the video being loaded
mMovie->getMovieDimensions().x
mMovie->getMovieDimensions().y
It sets it up fine, but the video is not proportioned correctly. It seems to be squashing it. I could probably work around this by just stretching the plane a bit, and moving the camera so that the rest is just off screen.

Also, I'm getting a memory leak now.
Alloc. Addr Size Addr Size BreakOn BreakOn
Number Reported Reported Actual Actual Unused Method Dealloc Realloc Allocated by
------ ---------- ---------- ---------- ---------- ---------- -------- ------- ------- ---------------------------------------------------
003021 0x01163120 0x0000004C 0x01163110 0x0000006C 0x00000000 new N N script_gameinformation.cpp(8 ) Script_GameInformation::getInstance
011078 0x011839C0 0x00000044 0x011839B0 0x00000064 0x00000000 new N N state_singleplayer.cpp(43) State_SinglePlayer::enter
013145 0x01183AA8 0x00000044 0x01183A98 0x00000064 0x00000000 new N N state_singleplayer.cpp(44) State_SinglePlayer::enter
003022 0x011AF270 0x00000048 0x011AF260 0x00000068 0x00000000 new N N ??(0) ??
002114 0x011AFA90 0x000000CC 0x011AFA80 0x000000EC 0x00000000 new N N ogrematerialmanager.cpp(93) Ogre::MaterialManager::createImpl
002122 0x011AFE08 0x00000004 0x011AFDF8 0x00000024 0x00000000 new N N ogresharedptr.h(59) Ogre::SharedPtr<class Ogre::Resource>::
002133 0x041FE028 0x00000114 0x041FE018 0x00000134 0x00000000 new N N ogretechnique.cpp(185) Ogre::Technique::createPass
015080 0x04217360 0x00000044 0x04217350 0x00000064 0x00000000 new N N state_singleplayer.cpp(45) State_SinglePlayer::enter
010387 0x0422D670 0x00000054 0x0422D660 0x00000074 0x00000000 new N N state_singleplayer.cpp(28 ) State_SinglePlayer::enter
016637 0x0438B920 0x00000140 0x0438B910 0x00000160 0x00000000 new N N state_singleplayer.cpp(47) State_SinglePlayer::enter
I'm guessing it's coming from when I exit the movie state and enter the singleplayer state.

I have this in my exit method
if(movieLoaded) mMovie->unloadMovie();
delete mMovie;
(movieLoaded is a bool that's set to true if the movie loads properly when the mMovie object is created)

in the OgreLog I get this warning
20:28:17: WARNING: Texture instance 'DirectShowManualTexture' was defined as manually loaded, but no manual loader was provided. This Resource will be lost if it has to be reloaded.

If there's anything you can think of that that may be causing the problem it'd be great to know. If I figure anything out I'll make sure to update this.

Posted: Wed Jan 31, 2007 3:41 am
by hmoraldo
Hmmm... are you catching the exceptions when a movie is not found, and letting it go with other movie?

Actually, I didn't program this thinking in that the user would be interested in catching that, but rather considering those to be a fatal error and exiting. If you are continuing after such error, you'll have some memory leaks that could be avoided only by cluttering the code near all throws with a lot of deinitialization code.

Also: the warning in your Ogre log is not a problem... I didn't provide need a manual loader as it's a very dynamic kind of content.

And you don't need to unload the movie if you are going to destroy the directshow object, as the object destructor handles that.

What version of the code are you using? The first version I posted here (before copying it to the wiki), had a leak as it lacked this line:

Code: Select all

delete[] pBuffer;
(actually, the line was present, only that using a delete instead of delete[])

Please check for that too.

And in any case, try to isolate the leak by finding what method of the directshow object is causing it (if any); ie: comment all dshowMovieTextureSystem-> code excepting initialization and deinitialization, and see if it still persists.

And at least: about the stretching thing, get the texture dimensions of the dshowMovieTextureSystem texture, and you'll see they are somewhat higher than the ones asked by you (so that they are two powers of two). You have to calculate what is the sector of the texture that contains useful information by comparing the texture coordinates with the movie dimensions.

Posted: Wed Jan 31, 2007 3:56 am
by hmoraldo
Well, I've just updated the code in the wiki so that the constructor respects the dimensions for the video, and only modify them to be powers of two if asked by the user to do so (by using an optional third parameter).

You can update to that version of the code and you'll get the desired aspect ratio with no problems and no further code modifications. However, power of two textures are needed for some old computers, so you might consider checking that in the future too (at least if you are interested in older computers).

Posted: Wed Jan 31, 2007 4:01 am
by odyeiop
mat = Ogre::MaterialManager::getSingleton().getByName(materialName);
this seems to be what is causing the problem.

Posted: Wed Jan 31, 2007 4:09 am
by hmoraldo
odyeiop wrote:mat = Ogre::MaterialManager::getSingleton().getByName(materialName);
this seems to be what is causing the problem.
What problem, the leak? (or is it a crash?) How do you came to that conclussion?

That's strange, as that's line is rather innocuous. Maybe you need to call mat->load() before continuing to change its texture. However, if that was the problem, you wouldn't be able to see the video in the first place.

That sounds very very strange, can you give me some more information?

Posted: Wed Jan 31, 2007 4:21 am
by odyeiop
Here's a simple breakdown of how the program runs the states

it loads all the resources in an intro state, then goes directly to a menustate

when you pick play, it takes you to the cinematic state, that plays the video
the video plays fine

you go from the cinematic state to the play state (which it does fine)
when you exit playstate it takes you back to the menustate.

You can keep looping cinematic->play->menu->cinematic etc... without any issues. When you close the program it crashes. If I take out mat = Ogre::MaterialManager::getSingleton().getByName(materialName); it does not crash.