(Code Snippet) Video reproduction using DirectShow

Discussion area about developing or extending OGRE, adding plugins for it or building applications on it. No newbie questions please, use the Help forum for that.
Post Reply
User avatar
hmoraldo
OGRE Expert User
OGRE Expert User
Posts: 517
Joined: Tue Mar 07, 2006 11:22 pm
Location: Buenos Aires, Argentina
x 1
Contact:

(Code Snippet) Video reproduction using DirectShow

Post 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
Last edited by hmoraldo on Sun Mar 11, 2007 10:14 pm, edited 4 times in total.
H. Hernan Moraldo
Personal website
User avatar
hmoraldo
OGRE Expert User
OGRE Expert User
Posts: 517
Joined: Tue Mar 07, 2006 11:22 pm
Location: Buenos Aires, Argentina
x 1
Contact:

Post 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).
H. Hernan Moraldo
Personal website
User avatar
hmoraldo
OGRE Expert User
OGRE Expert User
Posts: 517
Joined: Tue Mar 07, 2006 11:22 pm
Location: Buenos Aires, Argentina
x 1
Contact:

Post 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!
H. Hernan Moraldo
Personal website
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Post by sinbad »

Nice snippet, thanks.
User avatar
odyeiop
Halfling
Posts: 97
Joined: Fri Dec 22, 2006 4:56 am
Location: stoney creek

Post 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 =)
I'm Immortal as you are Divine.
User avatar
hmoraldo
OGRE Expert User
OGRE Expert User
Posts: 517
Joined: Tue Mar 07, 2006 11:22 pm
Location: Buenos Aires, Argentina
x 1
Contact:

Post 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.
H. Hernan Moraldo
Personal website
User avatar
odyeiop
Halfling
Posts: 97
Joined: Fri Dec 22, 2006 4:56 am
Location: stoney creek

Post 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
I'm Immortal as you are Divine.
User avatar
hmoraldo
OGRE Expert User
OGRE Expert User
Posts: 517
Joined: Tue Mar 07, 2006 11:22 pm
Location: Buenos Aires, Argentina
x 1
Contact:

Post by hmoraldo »

Ha! You have to link to Strmiids.lib too. I forgot that in the code documentation, thank you.
H. Hernan Moraldo
Personal website
User avatar
odyeiop
Halfling
Posts: 97
Joined: Fri Dec 22, 2006 4:56 am
Location: stoney creek

Post 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.
I'm Immortal as you are Divine.
User avatar
hmoraldo
OGRE Expert User
OGRE Expert User
Posts: 517
Joined: Tue Mar 07, 2006 11:22 pm
Location: Buenos Aires, Argentina
x 1
Contact:

Post by hmoraldo »

What linking errors are you getting on debug? I compiled this with no problems in debug.

Thanks a lot for your feedback.
H. Hernan Moraldo
Personal website
User avatar
odyeiop
Halfling
Posts: 97
Joined: Fri Dec 22, 2006 4:56 am
Location: stoney creek

Post 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
I'm Immortal as you are Divine.
User avatar
hmoraldo
OGRE Expert User
OGRE Expert User
Posts: 517
Joined: Tue Mar 07, 2006 11:22 pm
Location: Buenos Aires, Argentina
x 1
Contact:

Post by hmoraldo »

I uploaded these corrections to the wiki (including the detail of what libraries you need to link to).
H. Hernan Moraldo
Personal website
User avatar
hmoraldo
OGRE Expert User
OGRE Expert User
Posts: 517
Joined: Tue Mar 07, 2006 11:22 pm
Location: Buenos Aires, Argentina
x 1
Contact:

Post 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.
H. Hernan Moraldo
Personal website
User avatar
odyeiop
Halfling
Posts: 97
Joined: Fri Dec 22, 2006 4:56 am
Location: stoney creek

Post 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.
I'm Immortal as you are Divine.
User avatar
hmoraldo
OGRE Expert User
OGRE Expert User
Posts: 517
Joined: Tue Mar 07, 2006 11:22 pm
Location: Buenos Aires, Argentina
x 1
Contact:

Post by hmoraldo »

Thank you for using it!
H. Hernan Moraldo
Personal website
User avatar
odyeiop
Halfling
Posts: 97
Joined: Fri Dec 22, 2006 4:56 am
Location: stoney creek

Post 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.
I'm Immortal as you are Divine.
User avatar
hmoraldo
OGRE Expert User
OGRE Expert User
Posts: 517
Joined: Tue Mar 07, 2006 11:22 pm
Location: Buenos Aires, Argentina
x 1
Contact:

Post 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?).
Last edited by hmoraldo on Wed Jan 31, 2007 1:44 am, edited 1 time in total.
H. Hernan Moraldo
Personal website
User avatar
odyeiop
Halfling
Posts: 97
Joined: Fri Dec 22, 2006 4:56 am
Location: stoney creek

Post by odyeiop »

=D It works perfectly now! Very nice! Thank you very much
I'm Immortal as you are Divine.
User avatar
hmoraldo
OGRE Expert User
OGRE Expert User
Posts: 517
Joined: Tue Mar 07, 2006 11:22 pm
Location: Buenos Aires, Argentina
x 1
Contact:

Post by hmoraldo »

Fantastic news! Thank you for your time
H. Hernan Moraldo
Personal website
User avatar
odyeiop
Halfling
Posts: 97
Joined: Fri Dec 22, 2006 4:56 am
Location: stoney creek

Post 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.
I'm Immortal as you are Divine.
User avatar
hmoraldo
OGRE Expert User
OGRE Expert User
Posts: 517
Joined: Tue Mar 07, 2006 11:22 pm
Location: Buenos Aires, Argentina
x 1
Contact:

Post 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.
Last edited by hmoraldo on Wed Jan 31, 2007 3:57 am, edited 1 time in total.
H. Hernan Moraldo
Personal website
User avatar
hmoraldo
OGRE Expert User
OGRE Expert User
Posts: 517
Joined: Tue Mar 07, 2006 11:22 pm
Location: Buenos Aires, Argentina
x 1
Contact:

Post 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).
H. Hernan Moraldo
Personal website
User avatar
odyeiop
Halfling
Posts: 97
Joined: Fri Dec 22, 2006 4:56 am
Location: stoney creek

Post by odyeiop »

mat = Ogre::MaterialManager::getSingleton().getByName(materialName);
this seems to be what is causing the problem.
I'm Immortal as you are Divine.
User avatar
hmoraldo
OGRE Expert User
OGRE Expert User
Posts: 517
Joined: Tue Mar 07, 2006 11:22 pm
Location: Buenos Aires, Argentina
x 1
Contact:

Post 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?
H. Hernan Moraldo
Personal website
User avatar
odyeiop
Halfling
Posts: 97
Joined: Fri Dec 22, 2006 4:56 am
Location: stoney creek

Post 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.
I'm Immortal as you are Divine.
Post Reply