Archived

This topic is now archived and is closed to further replies.

Alan Kemp

Playing an avi onto a direct3d surface

Recommended Posts

Hi, I want to be able to play an avi file onto a region of my direct3d8 window. I presume the "proper" way of doing this involves DirectShow, but I am finding DirectShow *very* slow. The avi I am trying to play is width=900, height=1200. The fil plays for 10 seconds at 30 frames per second, and is currently encoded with the cinpack compressor (although I can easily change to pretty much any other codec if it will make things simpler/faster). As far as I can tell the only DirectShow example program that also uses Diret3d8 is the one that plays the skiing avi onto a texture, and then maps that onto a cylinder. The others all seem to not use direct3d8 (some only create a window, and one uses direct draw in full screen mode). However, I modified the avi-texture sample to play my avi, and to map it onto an single polygon. However, even for just displaying the top 512x512 area of this avi with this technique I was only getting 10-12 fps with my 1.7Ghz P4 + 128MB Geforce4. With directx7 I used to be able to play avi''s really fast using the windows streaming services, but these require an IDirectDrawSurface (note, no number on the end) to render to, and I dont seem to be able to QueryInterface() that kind on surface from anything in Direct3d8. Sorry for the long post, my questions are these: - Has anyone got a non-sdk example of using DirectShow to render an avi to a direct3d8 window? - Is there a way to get an IDirectDrawSurface from Direct3d8 anywhere so I can continue using my old code? - Any better ideas for playing a movie quickly in direct3d8? I dont need to play it onto a texture, I just want to play it to a specified rectangle on the screen. Thanks for any advice, Alan

Share this post


Link to post
Share on other sites
quote:
Original post by Michalson
Have you tried playing an AVI that is not so insanely big?


Its worse than you can possibly imagine...

The huge avi is just the backdrop for a trade-show display. On top of that there is 3d graphics, scrolling text etc etc.

ZealousElixir: Yep, I have already seen those. The DirectShow one is just plain win32 (no direct3d), and the other uses DirectDraw (no number) and DirectDrawSurface (again no number), so unless someone knows a way of extracting either of those from direct3d8...

No one has any hints or tips then?

Alan

Share this post


Link to post
Share on other sites
Basically you have to copy the data to a texture. I use a 32 bit power of 2 texture, since most cards need textures to be power of 2, the 32 bit is so its is easier to copy the 24 bit dib to the texture. Also make sure your avi has keyframes at smallish intervals, otherwise it may chug.

You can either rescale the dib at run time (stretch blit to another dib), or rescale your avi before hand to be a power of 2. Then just draw a quad using this texture before your 3d stuff etc.

I'm doing this and it seems to work quite well. For an 512x256 avi on a gforce ti4600, Athalon 1800mhz, I get 60fps+.

have a look here for the code I used for decoding an avi

http://www.gamedev.net/reference/programming/features/avifile/page5.asp


I just do:-


  
// DeltaTime is in seconds, ie 1/60.0f ...

lElapsedTime = DeltaTime*1000.0f;
lFrameTime += lElapsedTime * lVideoDirection;

LPBITMAPINFOHEADER pBmp;
GetVideoFrameAtTime(0, lFrameTime, &pBmp);

//then in you dx stuff somewhere.. Note this is not the most efficent way of doing it,


// the texture

LPDIRECT3DTEXTURE8 Surface=YourTexture;
if( pBmp )
{
D3DLOCKED_RECT rect;
u16 y,x;
DXCOLOUR *Dst;
LPBITMAPINFO pBmpInfo=(LPBITMAPINFO)pBmp;
u8 *pBmpBits = ((LPBYTE)pBmpInfo) + pBmpInfo->bmiHeader.biSize;


// lock and copy

if( SUCCEEDED(Surface->LockRect( 0, &rect, 0, 0 )) )
{
// copy

for( y=0;y<pBmp->biHeight;y++)
{
Dst = (DXCOLOUR*)((u8*)rect.pBits + (rect.Pitch*y));


for( x=0;x<pBmp->biWidth;x++,pBmpBits+=3)
{
Dst[x].r = pBmpBits[2];
Dst[x].g = pBmpBits[1];
Dst[x].b = pBmpBits[0];
Dst[x].a = 255;
}
}
Surface->UnlockRect(0);
}
}

//then draw the rect




[edit, added to surface code]

Mark Duffill[The Jackal]
Eurocom Entertainment Software


[edited by - mark duffill on July 17, 2002 7:00:33 PM]

Share this post


Link to post
Share on other sites
(assuming you only need 2D video) play the AVI using a plain ol'' fullscreen directshow window with video overlay.

create your direct3d window OVER the DS window. Set your clear color to match the overlay color. In some cases, the overlay color may be different when the app runs. You may need to account for that.

Render your 3D stuff as usual. The overlay will handle the mixing automagically. BUT, you won''t have any real transparency between the video and 3D objects. You can create cheap transparency with dithered textures. We can discuss that if need be...

Share this post


Link to post
Share on other sites
i assume it plays fine when using media player.

the reason is simple. you must call Sleep(x) where x is some amount of wait time in milliseconds in your main thread (ie render thread). if you dont use create threads, then place it in yoru main game loop somewhere. if you dont you eat all the cpu and the dshow threads can process the video since they dont get enough cpu. dshow creates its own threads and you dont have much control over this. unfortunatly giving up render time means slower framerates and possible even wasted cpu where your idling (ie the dshow thread finished decoding what it needed to and your render thread is still waiting. you could drop your main threads priority (may not be good enough) or create another thread meant for rendering in which you drop the priority.

i have gotten full framerate 720x480 divx encoded avis playing on a texture using dshow. i use a 1024x512 (may have been 1024x1024) texture and i DONT scale the video. instead i use texture coordinates to fit the video properly on the polygons.

i suggest dropping the res of your video. 900x1200 definatly will be difficult to fit on screen and would use tons of resource to read and decode. just transferring that much data over the agp bus is quite difficult and slow. try a lower res (ie drop the actual file, not at runtime).

if you want you could use the the dshow7 interface and lock the surface for the transfer.

there is a problem however, possibly hardware accelration (like overlays and only updating small section of vram instead of the entire frame, hardware yuv decoding) can be the reason you get high framerates. when this accelration is taken away with your render filter, things get slow. 900x1200 is large, drop it to 450x600 and scale using the polygon. it will still be plenty clear. heck, are you ever running at 1600x1200? if not your wasting agp bandwidth sending data to the card that you will just crop anyway (ie down scale).

Share this post


Link to post
Share on other sites