Skip to main content
GameDev.net gamedev.net
🔒 Locked

Live video with DirectX

Started by billz1010 Feb 4, 2010 at 9:01 PM 7 replies 2.3k views
Original Post
billz1010
billz1010
Hello, I have a question about using DirectX to show a live video stream. I have some C# code that grabs 1024x768 14-bit video from a frame grabber (hardware can run at 50 Hz), and am generating an 8-bit grayscale bitmap that I'm updating in a windows form. I'm using unsafe code to update the bitmap, and can get around 15 fps update rate using GDI. Problem is, this is still too slow (and I think I'm dropping frames). My question is: how should I go about implementing DirectX to get around all the GDI overhead. I've looked at SlimDX, but am having trouble finding routines that update pixel by pixel point values every frame vs texturing etc. I'd prefer to stay in managed code (since my GUI is already in c#), but can do c++ if necessary. Can you point me in the right direction? Thanks in advance. Billy
Nik02
Nik02
The general approach to sending uncompressed live video to a D3D device:

At program startup:
-create a texture with the "dynamic" allocation flag

At each frame:
-lock the texture to gain access to its memory
-use the locked pointer to move your data in
-unlock the texture to make it available to the GPU
-render something with it. "Something" is usually a quad geometry to fill a complete render target, but it doesn't need to be.

To avoid stalling (GPU waiting for CPU or vice versa), you can use double buffering - that is, use two textures, and while one of them is locked by the CPU, the other can be simultaneously used by the GPU.

Using a raw pointer to data is possible in C#, by using the "unsafe" keyword. That said, the amount and content of D3D-specific code is very similar whether you use C# or C++.
Niko Suni
billz1010
billz1010
Thanks Nik02. This is exactly what I needed. Now off to some coding... haha. I guess in this situation my bottleneck becomes moving the data into the texture, correct?
Nik02
Nik02
Quote:
Original post by billz1010
Thanks Nik02. This is exactly what I needed. Now off to some coding... haha. I guess in this situation my bottleneck becomes moving the data into the texture, correct?


No problem.

1024x768x32bppx50fps is 150 MBps, which is well within the bandwidth limitations of the graphics bus.

However, if you don't implement double (or even triple) buffering, you effectively limit the system's ability to use GPU and CPU in parallel. This may have a massive performance impact, even though bandwidth demands are not high.
Niko Suni
Narf the Mouse
Narf the Mouse
SlimDX can do everything, or nearly everything, DirectX can - Version-dependent, of course. And the procedure for modifying a bitmap is as Nik02 said, save that in C# you would use "System.Runtime.InteropServices.Marshal.Copy()" to copy the data from the IntPtr to a byte array and then back again.
billz1010
billz1010
So I've been playing around with this, and I get the error "'SlimDX.Direct3D9.Texture.InternalPointer' is inaccessible due to its protection level". How do I access the texture pointer?

var texture = new Texture(device, form.ClientSize.Width, form.ClientSize.Height, 0, Usage.Dynamic, Format.A8R8G8B8, Pool.Default);MessagePump.Run(form, () =>{     device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);     device.BeginScene();     texture.LockRectangle(0,LockFlags.None);     System.Runtime.InteropServices.Marshal.Copy(data, 0, (IntPtr)texture.InternalPointer, 100);     texture.UnlockRectangle(0);// Render      device.EndScene();}


Is this the proper way to load in the data?
jpetrie
jpetrie
You want the ComPointer member. InternalPointer is, as the name implies, internal to SlimDX.
billz1010
billz1010
Thanks. Now it throws an exception on that same line saying "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

I think I have my data lengths correct... where am I going wrong now? Thanks for your help.

EDIT: the code above should have data.length as the last argument, not 100.
billz1010
billz1010
SOLVED:

Thanks for those that helped me, and for anyone else who is interested I got this working by using a dynamic texture and the returned pointer from the LockRectangle function:

//Declare texture  var texture = new Texture(device, form.ClientSize.Width, form.ClientSize.Height, 0, Usage.Dynamic, Format.A8R8G8B8, Pool.Default);//Generate data..//Now in render loop://Get pointer to the LockRectangle associated with the texture  uint* pData = (uint*)texture.LockRectangle(0,                        LockFlags.None).Data.DataPointer.ToPointer();//Copy my data (databyte) to the pointer location  System.Runtime.InteropServices.Marshal.Copy(databyte, 0, (IntPtr)pData, databyte.Length);//Unlock the rectangle  texture.UnlockRectangle(0);//Draw  device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);  device.BeginScene();  sprite.Begin(SpriteFlags.None);  sprite.Draw(texture, Color.White);  sprite.End();  device.EndScene();  device.Present();


Amazingly simple when you consider it all. I am able to generate a random 1024x768 array and render at over 200 fps on my DirectX9 card. Thanks for the help.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.