Sign in to follow this  
The Riddler

Streaming AVI to a texutre in Direct3D 9

Recommended Posts

The Riddler    122
Hi, I have written an application that opens an AVI file and streams the bitmap info to a texture as per the other threads on this fourm... However wen i look at this texture the AVI image only fills roughly a quarter of the texture... After playing with this for days it would appear I'm not receiving all the pixel data. Would this be because I need the ICDecompress function? (I have tried creating an explicitly "uncompressed frames AVI" with Paint Shop Professional Animation Shop 7 and still the same result... help anyone? Here is the code to extract and copy Bitmap info: lpbi = (LPBITMAPINFO)AVIStreamGetFrame(pgf, 0); D3DXCreateTexture(D3DRenderDevice,lpbi->bmiHeader.biWidth,lpbi->bmiHeader.biHeight,NULL,NULL,D3DFMT_R8G8B8,D3DPOOL_MANAGED,&VideoSurface); VideoSurface->GetSurfaceLevel(0, &Surface); lpbi = (LPBITMAPINFO)AVIStreamGetFrame(pgf, PlayThisFrame); ImageData = (LPBYTE)lpbi + lpbi->bmiHeader.biSize; // Get a DC for the surface r = Surface->GetDC(&SurfaceDC); // Get a DC for the bitmap BitmapDC = CreateCompatibleDC(SurfaceDC); // Have to create the DIB section HandleBitmap = CreateDIBSection(BitmapDC, lpbi, DIB_RGB_COLORS, (LPVOID*)&BitmapColorInfo, NULL, 0); // Copy the bitmap data into our DIB section memcpy(BitmapColorInfo, ImageData, lpbi->bmiHeader.biSizeImage); // Have to select the bitmap into the DC OldObject = SelectObject(BitmapDC, HandleBitmap); if (BitBlt(SurfaceDC, 0, 0, lpbi->bmiHeader.biWidth, lpbi->bmiHeader.biHeight, BitmapDC, 0, 0, SRCCOPY)){ // Draws Here } // Cleanup SelectObject(BitmapDC, OldObject); DeleteObject(HandleBitmap); DeleteDC(BitmapDC); r = Surface->ReleaseDC(SurfaceDC);

Share this post


Link to post
Share on other sites
The Riddler    122
After playing with this further I have found that drawing to the screen with a sprite function displays the image correctly provided u are in the same screen resolution as the AVI file.

However if I use SetTexture() and draw a quad the bitmap image retrieved is only spanning about 1/4 of the texture.

I am using the D3DFMT_X8R8G8B8 format for all surfaces and can UpdateTexture another texture from this texture fine and has the same display characteristics (Not filling a quad run through T&L). However, a call to StretchRect does not fail but returns a blank screen...

Can anyone explain this odd phenomenon?

Share this post


Link to post
Share on other sites
Racky1275    122
Have you checked that the texture size you request is actually what you get?

Not all hardware will allow textures that are not a multiple of 2...

Have you checked that your quad texture coordinates range from -1.0 to +1.0 on both axis?

Share this post


Link to post
Share on other sites
The Riddler    122
Thanks for answering:

The videos being run through this are 640x480 and 800x600 in 24bit not 8.
And yes the quads texture co-ordinates are fine as I can display other textures loaded with CreateTextureFromFile() from dds fine.

The routine has now changed and will play them in the center of the screen with sprite routines correctly ( Of course if you in the wrong screen mode u just get a box the video size in the center of the screen) however calls to StretchRect directly to the back buffer give the same result as drawing the quad over the whole screen.... (I had to UpdateTexture a new Texture from this texture and use GetSurfaceLevel to get StretchRect to return a image)

>:!

If you would be so kind as to post a email or MSN no(icq?) I will send u a copy of the offending application/routine?

I suspect there is a format conversion error happing here somewhere and the sprite draw routine is the only one fixing it?

Thanks again

[Edited by - The Riddler on November 22, 2007 9:11:53 PM]

Share this post


Link to post
Share on other sites
Racky1275    122
I'd rather help you fix the problem via the forums if possible, that way others can learn from it too... [smile]

1) When you say the image is 1/4 size, does the visible part look correct? Are all the colours mixed up?

Check that when you use AVIStreamGetFrameOpen() you ask the system to return frames with .biBitCount = 32, and .biCompression = BI_RGB.

2) Personally I don't bother with the whole GetDC() etc, I just take the raw 32bit data from AVIStreamGetFrame() and Lock/MemCopy(line by line due to the Pitch)/Unlock it into a texture. Then you just need to alter the texture coordinates and quad position to get the desired image.

Be warned that the DIB frame data is only valid until the next time you call AVIStreamGetFrame(), so copy it quickly. THIS IS VERY ANNOYING. [evil]

Share this post


Link to post
Share on other sites
The Riddler    122
Hey,

1) Yes the colours are correct

...

U will see at the top commented lines forcing .biBitCount = 32 and .biCompression = BI_RGB but application then crashes.

>:! Perplexed here

[Edited by - The Riddler on December 12, 2007 1:10:05 AM]

Share this post


Link to post
Share on other sites
Racky1275    122

First of all, setting biBitCount shouldn't cause a crash... this should fix it:


ZeroMemory(&pInfo, sizeof(pInfo));
pInfo.biSize = sizeof(pInfo);
pInfo.biWidth = AviFileInfo.dwWidth;
pInfo.biHeight = AviFileInfo.dwHeight;
pInfo.biPlanes = 1;
pInfo.biBitCount = 32;
pInfo.biCompression = BI_RGB;

pgf = AVIStreamGetFrameOpen(pVideo[0], &pInfo);



If your sprite routine works, then your DIB handling should be OK.

I've still not got my head around the problem you are actually seeing on-screen... If the image looks ok but parts are missing, then it could simply be a frame tearing issue - are you locked to vsync? Have you tried other avi samples of different sizes? Can you post a screen-shot taken with Fraps?

PS. Have you looked at the debug output of the DX libs? You might have something failing quietly.

Share this post


Link to post
Share on other sites
The Riddler    122
Hey thanks for your help,

The code u posted still crashes the application. Not a tearing issue. I will get up some screen shots asap.

Different resolution videos give right size result with the sprite Blit function
(which means if your in the same screen res as video res it looks correct and fullscreen image) but still gives wrong result with stretchrect call instead (image then covers roughly 1/4 to 1/2 the screen)

Other calls to stretchrect work fine on textures loaded with the CreateTextureFromFile function.

[Edited by - The Riddler on December 6, 2007 10:20:05 PM]

Share this post


Link to post
Share on other sites
The Riddler    122
Fixed it,

Asked for a 24 bit surface instead (R8G8B8) and stretchrect calls had no problems ;) One last question tho?

Everyone states that you should copy the texture fast as its only valid till the next AVIGetFrame call, others suggest a swap texture is useful for this.

Why do I still have to update another texture from the Original texture to be able to draw it?

Would this be because the application is executing the next AVIGetFrame before video hardware has finished the draw?

Thanks again

Share this post


Link to post
Share on other sites
Racky1275    122
Excellent news!

Ok, about copying the buffers...

Firstly, the buffer you get back from AVIGetFrame is obviously in main memory, and therefore needs copying to the video cards memory. If you just copy it to the same texture that you are rendering from, then the driver will make your lock wait until it has finished rendering. This is time you could have spent decoding the next AVI frame.

If you use two video textures, then you can be rendering from one, whilst copying data into the other. But your frame decoder is locked to the display framerate.

If you use multiple buffers you can be rendering from one, whilst the others are free to receive frames. So you can decode the AVI frames as fast as you can, until the buffer is full.

This helps when you are decoding complex codecs such as x264. It is not uncommon for the following to happen:

Frame 1 - Decode in 10ms
Frame 2 - Decode in 15ms
Frame 3 - Decode in 10ms
Frame 4 - Decode in 75ms
Frame 5 - Decode in 15ms

At 60Hz you have 16ms between screen updates, so for video at 30Hz you have 32ms. As you can see, most frames are well within this limit, but frame 4 is complex. If your decoder is locked to the framerate then it will stutter at frame 4, using a multi-frame buffer solves this.

Hope this helps. [smile]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this