Sign in to follow this  
Headkaze

Offscreen surface for video frame capture

Recommended Posts

Headkaze    607
When I am copying a video frame into an offscreen surface most of the time it works. But when I try to copy strange video sizes such as 220 x 256 or 200 x 256 the video is distorted (offset). To show you want I mean here are some frameshots The first one shows a 220 x 256 video before adding a 16 bit (4 pixel) offset to each stride. Surface Before And after adding the 16 bit offset to each stride corrects the image. Surface After Both the source frame and destination offscreen surface are A8R8G8B8 so there is no problem there AFAIK. But it seems for some strange reason, an offscreen surface doesn't like some of the widths the video's are. Here is the code I'm using to create the offscreen surface and then copy the frame to it.
m_videoSurface = device.CreateOffscreenPlainSurface(m_videoWidth, m_videoHeight, Format.A8R8G8B8, Pool.Default);
pBuffer = Marshal.AllocCoTaskMem(BufferLen);

hr = m_sampGrabber.GetCurrentBuffer(ref BufferLen, pBuffer);
DsError.ThrowExceptionForHR(hr);

GraphicsStream gs = m_videoSurface.LockRectangle(LockFlags.Discard);

CopyMemory(gs.InternalData, pBuffer, (uint)BufferLen);

m_videoSurface.UnlockRectangle();

device.StretchRectangle(
m_videoSurface,
new Rectangle(0, 0, m_videoWidth, m_videoHeight),
surface,
new Rectangle(Point.Empty, m_frameSize),
TextureFilter.None
);

Now that works fine for video sizes 320 x 240, 256 x 192 etc. But here are some examples of what I need to do to correct some video sizes. For a 220 x 256 Video
int offset1 = 0;
int offset2 = 0;

for (int i = 0; i < m_videoHeight; i++)
{
	CopyMemory((IntPtr)(gs.InternalData.ToInt32() + offset2), (IntPtr)(pBuffer.ToInt32() + offset1), (uint)(m_stride));
	offset1 += m_stride;
	offset2 += m_stride + 16;
}

Notice the 16 bit (4 pixel) offset I have to add for each stride of the offscreen surface? Similar thing for a 200 x 256 video
for (int i = 0; i < m_videoHeight; i++)
{
	CopyMemory((IntPtr)(gs.InternalData.ToInt32() + offset2), (IntPtr)(pBuffer.ToInt32() + offset1), (uint)(m_stride));
	offset1 += m_stride;
	offset2 += m_stride + 32;
}

This time I need a 32 bit (8 pixel) offset for the image to not appear warped. So onto my questions - I assume the offscreen surface can't be strange sizes such as 220 or 200 pixels in width? So there is some sort of padding going on? - How do I calculate how much extra the surface needs for padding? - Can I avoid doing a CopyMemory for every stride of every video frame or is jumping the padding like this the only way? Obviously it's a performance hit having to do that. - And finally, is there a better way to do this perhaps? [Edited by - Headkaze on April 22, 2008 6:58:05 AM]

Share this post


Link to post
Share on other sites
Adam_42    3629
You need to work out the correct stride and do one CopyMemory() per scanline. Normally the stride is returned from IDirect3DSurface9::LockRect() but I'm not sure how you get at it in managed code.

Alternatively take a look at GetRenderTargetData() instead which will do it all for you.

Share this post


Link to post
Share on other sites
Headkaze    607
Thanks heaps Adam, your a life saver!

Here is the solution for anyone else

// Allocate the buffer and read it
pBuffer = Marshal.AllocCoTaskMem(BufferLen);

hr = m_sampGrabber.GetCurrentBuffer(ref BufferLen, pBuffer);
DsError.ThrowExceptionForHR(hr);

int pitch = 0;

GraphicsStream gs = m_videoSurface.LockRectangle(LockFlags.Discard, out pitch);

if (pitch == m_stride)
CopyMemory(gs.InternalData, pBuffer, (uint)BufferLen);
else
for (int i = 0; i < m_videoHeight; i++)
CopyMemory((IntPtr)(gs.InternalData.ToInt32() + i * pitch), (IntPtr)(pBuffer.ToInt32() + i * m_stride), (uint)m_stride);

m_videoSurface.UnlockRectangle();

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