Obtaining pitch of a DS video sample

Started by
12 comments, last by crypting 20 years ago
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
Advertisement
If it is 32bit RGB it should be like this:
m_lVidPitch = m_lVidWidth * 4; 
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.
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.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

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
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.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

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]
Hmmm, well then show the actual read code. If it''s not the writing to the video sample buffer that''s crashing, it''s gotta be the reading.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

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]
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.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

This topic is closed to new replies.

Advertisement