Jump to content
  • Advertisement

Archived

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

crypting

Obtaining pitch of a DS video sample

This topic is 5155 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi.. I''m writting a DirectShow source filter.. it seems to work fine on my personal computer which has a GeForce2 MX400, but it crashes on my notebook which has a ATI 9000. The problem appears when copying a Direct3D surface contents to the video sample buffer, I copy it byte per byte. I know how to obtain the pitch of the surface but not the pitch of the video sample. A sample of the SDK forces to use RGB32bit with the code under this lines, but it only seems to work on my computer, not on my notebook: m_lVidPitch = (m_lVidWidth * 4 + 4) & ~(4); So... which is the correct way to ask for a video sample pitch? Thanks

Share this post


Link to post
Share on other sites
Advertisement
Guest Anonymous Poster
If it is 32bit RGB it should be like this:
m_lVidPitch = m_lVidWidth * 4; 

Share this post


Link to post
Share on other sites
From SDK Documentation, Width vs. Pitch:
quote:

Pitch is the distance, in bytes, between two memory addresses that represent the beginning of one bitmap line and the beginning of the next bitmap line. Because pitch is measured in bytes rather than pixels, a 640x480x8 surface has a very different pitch value than a surface with the same dimensions but a different pixel format. Additionally, the pitch value sometimes reflects bytes that Direct3D has reserved as a cache, so it is not safe to assume that pitch is just the width multiplied by the number of bytes per pixel.
[..]
Do not assume a pitch based solely on the display mode. If your application works on some display adapters but looks garbled on others, this may be the cause of the problem.



So.. it''s not as simple as Width*Format_bytes. With a D3D surface it''s easy to know, since IDirect3DSurface9:LockRect first parameter returns a pointer to a D3DLOCKED_RECT structure, describing the locked region and its pitch. But I don''t know how to obtain it from a video sample in a source filter.

Share this post


Link to post
Share on other sites
quote:
Original post by crypting
So.. it''s not as simple as Width*Format_bytes. With a D3D surface it''s easy to know, since IDirect3DSurface9:LockRect first parameter returns a pointer to a D3DLOCKED_RECT structure, describing the locked region and its pitch. But I don''t know how to obtain it from a video sample in a source filter.



That''s correct for DirectX surfaces. He''s talking about video frame samples, for which pitch = width * bytes per pixel.

Share this post


Link to post
Share on other sites
Aham.. I see... well, I''m totally lost then..

Where can be the problem with my notebook? Any ATI9000 limitation working with dynamic textures? I haven''t noticed anything before.

In fact, when copying the surface using Direct3DSurface9::GetDC, to get a device context, create a compatible bitmap, BitBlt the surface and use GetDIBits to copy the bitmap into the provide video sample buffer it doesn''t crash.

Any hints? The application runs, the offscreen surface is correctly converted to a video stream.. but when the surface changes (because of interacting with the mouse to move the cube I''m rendering on the surface).. it crashes.

Same application using the "GetDC" approach instead of LockRect and memcpy works without crashing, but very slow in performance

Thanks for any hints

Share this post


Link to post
Share on other sites
Hmm, kinda lost too...

Last idea, is the width of the video odd? Maybe the pitch needs to be aligned to 32 bits?

Debugging hint: on receiving a new frame don''t copy the bitmap data, but instead fill the surface with a solid color. If it still crashed, odds are the reading is done wrong.
Try to only read half the video frame and see if you really get half the video frame.

Share this post


Link to post
Share on other sites
If I just fill the video sample buffer with a solid color, for example with green doing something like this:

DWORD * pDW = (DWORD *)pData;
for(int index=0;index<256*256;index++) pDW[index] = 0xFF00FF00;

where the video sample is a 256x256 RGB32 one, it doesn't crash.

If I copy the contents of the D3D surface to the video sample buffer just the first time and don't update it when the user interacts with the D3D scene, it doesn't crash neither.

I use LockRect, memcpy, UnlockRect to copy from surface to sample video as usual.

So, maybe there's a conflict between locking the surface to copy its contents to the video sample buffer and the render loop trying to update the offscreen rendered surface with the new scene (for example, a new position/orientation of the cube in the scene).

But, why is it working on my personal computer and not on my notebook? Because my notebook's graphic card is just to slow to do both things?

EDITED: Thanks for your help

[edited by - crypting on April 13, 2004 7:22:26 PM]

Share this post


Link to post
Share on other sites
Here is the code of my render function and the FillBuffer method where I copy the surface contents to the video sample buffer.

Notice I use GetRenderTargetData method to copy the dynamic texture surface created using D3DPOOL_DEFAULT to one created in system memory (D3DPOOL_SYSTEMMEM). I do so, because when accessing "manually" to a surface not created using IDirect3DDevice9::CreateOffscreenPlainSurface method the application crashes.
(It has to be for the same reason as with Direct3DSurface9::GetDC method, which doesn't support D3DPOOL_DEFAULT memory also for surfaces which are not created using the IDirect3DDevice9::CreateOffscreenPlainSurface method.)


void D3Drender( void )
{
D3DXMATRIX matWorld;
D3DXMATRIX matTranslation;
D3DXMATRIX matRotation;

//-------------------------------------------------------------------------

// Use the "render to" surface for off-screen rendering

//-------------------------------------------------------------------------


m_pRenderToSurface->BeginScene( m_pTextureSurface, NULL );

g_pD3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_COLORVALUE(0.0f,1.0f,0.0f,0.0f), 1.0f, 0);

//

// We'll need to change the projection matrix on the device, to match the

// off-screen surface's dimensions, or the cube will look wrong.

//

g_pD3DDevice->SetTransform( D3DTS_PROJECTION, &g_matProjection_offscreenSurface );

//

// Let the user spin the cube about with the right mouse button, so our

// dynamic texture will show motion.

//

D3DXMatrixTranslation( &matTranslation, g_fTransX_L, g_fTransY_L, 8.0f );

D3DXMatrixRotationYawPitchRoll( &matRotation,
D3DXToRadian(g_fSpinX_R),
D3DXToRadian(g_fSpinY_R),
0.0f );

matWorld = matRotation * matTranslation;

g_pD3DDevice->SetTransform( D3DTS_WORLD, &matWorld );

//

// Now the render the cube to the off-screen surface

//

g_pD3DDevice->SetTexture( 0, g_pTestTexture );
g_pD3DDevice->SetStreamSource( 0, g_pVertexBuffer, 0, sizeof(Vertex) );
g_pD3DDevice->SetFVF( Vertex::FVF_Flags );

g_pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
g_pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 4, 2 );
g_pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 8, 2 );
g_pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 12, 2 );
g_pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 16, 2 );
g_pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 20, 2 );

m_pRenderToSurface->EndScene( 0 );

g_pD3DDevice->GetRenderTargetData(m_pTextureSurface, g_pSurface);
}


//---------------------------------------------------------

//---------------------------------------------------------

// This is where we insert the surface bits into the video stream.

// FillBuffer is called once for every sample in the stream.

HRESULT CPushPinD3D::FillBuffer(IMediaSample *pSample)
{
BYTE *pData;
long cbData;

CheckPointer(pSample, E_POINTER);

CAutoLock cAutoLockShared(&m_cSharedState);

// Access the sample's data buffer

pSample->GetPointer(&pData);
cbData = pSample->GetSize();

// Check that we're still using video

ASSERT(m_mt.formattype == FORMAT_VideoInfo);

VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)m_mt.pbFormat;

// Copy the surface bits over into our filter's output buffer.


LPDIRECT3DSURFACE9 pD3DSurface = NULL; //D3D Source Surface

PushSourceD3D()->get_D3DSurface(&pD3DSurface);

D3DSURFACE_DESC surfaceDesc;
pD3DSurface->GetDesc(&surfaceDesc);
D3DLOCKED_RECT d3dlr;
BYTE *pSurfaceBuffer;


pD3DSurface->LockRect(&d3dlr, 0, D3DLOCK_DONOTWAIT);
pSurfaceBuffer = (BYTE *) d3dlr.pBits + d3dlr.Pitch*(surfaceDesc.Height - 1);

int m_lVidPitch = surfaceDesc.Width * 4; //video sample pitch


for (int i=0;i<(int)surfaceDesc.Height;i++)
{
memcpy(pData+(surfaceDesc.Height - i - 1) * surfaceDesc.Width * 4, (BYTE*) d3dlr.pBits + i * d3dlr.Pitch, surfaceDesc.Width * 4);
}

pD3DSurface->UnlockRect();


// Set the timestamps that will govern playback frame rate.

// If this file is getting written out as an AVI,

// then you'll also need to configure the AVI Mux filter to

// set the Average Time Per Frame for the AVI Header.

// The current time is the sample's start.

REFERENCE_TIME rtStart = m_iFrameNumber * m_rtFrameLength;
REFERENCE_TIME rtStop = rtStart + m_rtFrameLength;

pSample->SetTime(&rtStart, &rtStop);
m_iFrameNumber++;

// Set TRUE on every sample for uncompressed frames

pSample->SetSyncPoint(TRUE);

return S_OK;
}




That's it..

Thanks

[edited by - crypting on April 14, 2004 11:48:44 AM]

Share this post


Link to post
Share on other sites
Hmmm, are you sure the 3d surface you''re copying from is also using 32bits? (iow only D3DFMT_X8R8G8B8 or D3DFMT_A8R8G8B8 are possible). If you''re using the sample framework you might actually end up with a 16 bit surface.

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!