Аварийное завершение программы при переключении в оконный режим

Здравствуйте.Я разрабатываю программу для просмотра стерео 3D фильмов с использованием DirectShow фильтра рендера с использованием Direct 3D 9 в видео плеере.Ситуация:Иногда в фильтре происходит аварийное завершение программы при переключении в оконный режим в строке освобождения поверхности используемой для записи в бек буфер.

Кто-нибудь может помочь?

Последняя правка: пн, 29/08/2011 - 22:06
Submitted by Kozlov_Sergey on

Комментарии

Из пальца высосать диагноз, тяжело.

На вскидку.
  • Найдите все места где обьект удаляется или зануляется, исследуйте их внимательно.
  • Используйте везде ComPtr<> для COM обьектов.
  • Скорее всего баг с многопоточностью, обложите все вызовы вашего обьекта мьютексом или крит секцией, должно помочь.
  • Если хотите чтобы вам помогли более детально, нужно по больше информации.
Submitted by Relyer on

Я описал ситуацию. Может у кого было.

Используется переделаный проект рендер фильтра. Основные файлы из DirectX SDK (d3dapp.cpp) немного переделаны.При отладке 1 раз в конфигурации Release вышел на эту строку. Пробовал: без этой строки изображения нету и аварийного завершения нету.

Попробую ComPtr.

Ошибка в строкеgImageSrc->Release();

в самом конце функции.

Вот код функции:HRESULT CTransform::Transform( IMediaSample *pMediaSample, AM_MEDIA_TYPE* media_type, LPDIRECT3DDEVICE9 direct_3D_device ){ if ( pMediaSample==NULL || media_type==NULL || direct_3D_device == NULL ) { return E_POINTER;

}

AM_MEDIA_TYPE* pType = media_type;

VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *) pType->pbFormat;

BYTE *pData; // Pointer to the actual image buffer long lDataLen; // Holds length of any given sample RGBTRIPLE *prgb; // Holds a pointer to the current pixel pMediaSample->GetPointer(&pData);

lDataLen = pMediaSample->GetSize();

// Get the image properties from the BITMAPINFOHEADER int iPixelSize = pvi->bmiHeader.biBitCount / 8; int cxImage = pvi->bmiHeader.biWidth; int cyImage = pvi->bmiHeader.biHeight; int cbImage = cyImage * cxImage * iPixelSize;

int numPixels = cxImage * cyImage;

iPixelSize = pvi->bmiHeader.biBitCount / 8; cxImage = pvi->bmiHeader.biWidth; cyImage = pvi->bmiHeader.biHeight; cbImage = cyImage * cxImage * iPixelSize; numPixels = cxImage * cyImage;

prgb = (RGBTRIPLE*) pData;

int pixels_shift = 2*cxImage/100;

REFERENCE_TIME rtStart, rtEnd;

pMediaSample->GetTime(&rtStart, &rtEnd);

{ if(buffers_size!=cxImage*cyImage) {

buffers_size = cxImage*cyImage;

delete []member_cash_buffer;

delete []member_buffer;

delete []local_member_buffer_1;

delete []local_member_buffer_2;

delete []local_member_entered_buffer;

member_cash_buffer = new RGBTRIPLE[buffers_size];

member_buffer = new RGBTRIPLE[buffers_size];

local_member_buffer_1 = new RGBTRIPLE[buffers_size];

local_member_buffer_2 = new RGBTRIPLE[buffers_size];

local_member_entered_buffer = new RGBTRIPLE[buffers_size];

member_valid_cash = 0; }

}

  1. define RGB_BYTE_ORDER(r, g ,b) ((DWORD) (((BYTE) (b) | ((WORD) (g) << 8)) | (((DWORD) (BYTE) (r)) << 16)))
HRESULT local_handle_result = S_OK; { IDirect3DSurface9* gImageSrc = NULL; { local_handle_result = direct_3D_device->CreateOffscreenPlainSurface( cxImage, cyImage+1, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, // Surface is in video memory &gImageSrc, NULL); if(local_handle_result!=D3D_OK) { return local_handle_result; } if(gImageSrc==NULL) { return local_handle_result; } { DWORD *local_bit_map_buffer; local_bit_map_buffer = new DWORD[cxImage*cyImage]; for(int local_counter_width=0;local_counter_width<cxImage;local_counter_width++) { for(int local_counter_height=0;local_counter_height<cyImage;local_counter_height++) { int local_couter = local_counter_width+local_counter_height*cxImage; int local_bit_map_couter = local_counter_width+(cyImage-(local_counter_height+1))*cxImage; local_bit_map_buffer[local_bit_map_couter] = RGB_BYTE_ORDER(prgb[local_couter].rgbtRed,prgb[local_couter].rgbtGreen,prgb[local_couter].rgbtBlue); } } HBITMAP handle_bit_map = NULL; handle_bit_map = CreateBitmap( cxImage, cyImage, 1, 32, local_bit_map_buffer); delete []local_bit_map_buffer; HDC hdc; gImageSrc->GetDC(&hdc); HDC hdc_compatible = CreateCompatibleDC(hdc); SelectObject(hdc_compatible,handle_bit_map); BitBlt(hdc, 0 ,0 ,cxImage , cyImage , hdc_compatible, 0, 0, SRCCOPY); gImageSrc->ReleaseDC(hdc); DeleteDC(hdc_compatible); BOOL local_result = DeleteObject(handle_bit_map); } int gImageWidth= cxImage; // Source image width int gImageHeight= cyImage;// Source image height RECT srcRect= { 0, 0, gImageWidth, gImageHeight+1}; RECT dstRect= { 0, 0, gImageWidth, gImageHeight}; // Stereo Blitdefines
  1. define NVSTEREO_IMAGE_SIGNATURE 0x4433564e //NV3D
typedef struct _Nv_Stereo_Image_Header { unsigned int dwSignature; unsigned int dwWidth; unsigned int dwHeight; unsigned int dwBPP; unsigned int dwFlags; } NVSTEREOIMAGEHEADER, *LPNVSTEREOIMAGEHEADER; // ORedflags in the dwFlagsfielsof the _Nv_Stereo_Image_Headerstructure above
  1. define SIH_SWAP_EYES 0x00000001
  2. define SIH_SCALE_TO_FIT 0x00000002
// Lock the stereo image D3DLOCKED_RECT lr; gImageSrc->LockRect(&lr,NULL,0); // write stereo signature in the last raw of the stereo image LPNVSTEREOIMAGEHEADER pSIH= (LPNVSTEREOIMAGEHEADER)(((unsigned char *) lr.pBits) + (lr.Pitch* gImageHeight)); // Update the signature header values pSIH->dwSignature= NVSTEREO_IMAGE_SIGNATURE; pSIH->dwBPP= 32; pSIH->dwFlags= SIH_SWAP_EYES; // Src image has left on left and right on right pSIH->dwWidth= gImageWidth; pSIH->dwHeight= gImageHeight; // Unlock surface gImageSrc->UnlockRect(); D3DVIEWPORT9 local_view_port; direct_3D_device->GetViewport(&local_view_port); RECT local_view_port_rect = {0,0,local_view_port.Width,local_view_port.Height};

{

direct_3D_device->Clear (0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB (0, 0, 0), 0.0f, 0); direct_3D_device->BeginScene (); IDirect3DSurface9* pDestSurface = NULL; direct_3D_device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pDestSurface); if(pDestSurface) { direct_3D_device->StretchRect(gImageSrc, &srcRect, pDestSurface, &local_view_port_rect, D3DTEXF_LINEAR);

}

direct_3D_device->EndScene ();

direct_3D_device->Present (NULL, NULL, NULL, NULL);

if(pDestSurface) { pDestSurface->Release(); } if(gImageSrc) { gImageSrc->Release(); } } }

}

return S_OK;}

Посмотрите в строке забора данных (pMediaSample->GetPointer(&pData);

) какой у вас HRESULT приходит. А лучше сразу и проверочку добавь что если мол все S_OK то двигаемся дальше.

Submitted by Necro on
Я поставил везде проверки и возврат при ошибке и использовал CComPtr. Теперь ошибка в d3d9.dll во время вызова if(direct_3D_device->Clear (0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB (0, 0, 0), 0.0f, 0)!=D3D_OK) { return E_FAIL;

}

Вместо Вашего кода должен быть код учитывающий потерю устройства DirectX.

167. {
168.
169. direct_3D_device->Clear (0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB (0, 0, 0), 0.0f, 0);
170. direct_3D_device->BeginScene ();
171. 172. IDirect3DSurface9* pDestSurface = NULL;173. direct_3D_device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pDestSurface);
174.
175. if(pDestSurface)
176. {
177. direct_3D_device->StretchRect(gImageSrc, &srcRect, pDestSurface, &local_view_port_rect, D3DTEXF_LINEAR);
178. }
179.
180. direct_3D_device->EndScene ();
181. direct_3D_device->Present (NULL, NULL, NULL, NULL);
182.
183. if(pDestSurface)
184. {
185. pDestSurface->Release();
186. }
187.
188. if(gImageSrc)
189. {
190. gImageSrc->Release();
191. }

192. }

У меня получается примерно так:

HRESULT hr;

// Проверяем Direct3dDevice на потерянность
hr = direct_3D_device->TestCooperativeLevel();

if(hr==D3DERR_DEVICELOST)
return;

// если окно опять в фокусе пытаемся восстановить устройство рендеринга
if(hr==D3DERR_DEVICENOTRESET)
{
Cleanup();

direct_3D_device->Reset(&d3dpp);

if( direct_3D_device)
ReInit();
}

if( NULL == direct_3D_device )
return;


// Начинаем отрисовку
if( SUCCEEDED( direct_3D_device->BeginScene() ) )
{
// Очищаем задний буфер и буфер глубины
direct_3D_device->Clear (0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB (0, 0, 0), 0.0f, 0);

IDirect3DSurface9* pDestSurface = NULL;

direct_3D_device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pDestSurface);

if(pDestSurface)
{
direct_3D_device->StretchRect(gImageSrc, &srcRect, pDestSurface, &local_view_port_rect, D3DTEXF_LINEAR);
}

// Закончили рисовать
direct_3D_device->EndScene();
// Отображаем задний буфер на экран
direct_3D_device->Present( NULL, NULL, NULL, NULL );
if(pDestSurface)
{
pDestSurface->Release();
}

if(gImageSrc)
{
gImageSrc->Release();
}

}
Попробуйте использовать такой подход и где написан return - переделайте согласно прототипа своей функции.
Восстанавливать или не восстанавливать устройство (прерывать работу всего приложения) - решайте сами.
Вообще проблемма корректной работы с устройством DirectX - бич "своих" движков.

На текущий момент с DirectX 11 стало легче благодаря библиотекам классов в DirectX SDK.

Submitted by Necro on
Quote:
Necro писал(а):
// если окно опять в фокусе пытаемся восстановить устройство рендеринга
if(hr==D3DERR_DEVICENOTRESET)
{
Cleanup();

direct_3D_device->Reset(&d3dpp);

if( direct_3D_device)
ReInit();
}
Смею заметить что данный участок вкорне неверен и может привести к падению приложения. Хотя автор мог просто ошибиться. Привожу более правильный вариант:
if(hr==D3DERR_DEVICENOTRESET)
{
Cleanup();

if (direct_3D_device->Reset(&d3dpp) == D3D_OK) ReInit();
else return; }

Объясню почему. Когда мы говорим, что устройство потеряно - это не значит, что объект интерфейса IDirect3DDevice == NULL. И соответственно проверка на существование объекта { if ( direct_3D_device )... } после метода Reset ничего нам не говорит о том, что смогло ли востановится устройство или нет. direct_3D_device - это всего лишь объект (интерфейс), через который мы взаимодействоем с нашей видеокартой.

Советую более делатьлно расмотреть метод Reset в DirectX SDK.

Submitted by MaxImuS on
Quote:
Kozlov_Sergey писал(а):
Я поставил везде проверки и возврат при ошибке и использовал CComPtr. Теперь ошибка в d3d9.dll во время вызова if(direct_3D_device->Clear (0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB (0, 0, 0), 0.0f, 0)!=D3D_OK) { return E_FAIL; }
Товарищ Necro дает тебе верное направление =)
Ошибка у тебя здесь бонально в том, что устройство потеряно и соответственно метод Clear уже не валиден.

Первыйм делом при написании приложения, которое будет переходить из фуллскрина в оконный или на оборот и неважно, что оно будет там делать - нужно позабодится о отлове потери устройства и его востановлении. Как это сделать? Смотри посты выше Smile

Submitted by MaxImuS on
Через день собрал и потестировал - заработало. Ничего не менял. Думаю, что устранили ошибки в Direct 3D.То, что пишите вы, уже есть в функции переключения видео режимов.Спасибо за разъяснения.Нужно ли добавлять этот код ещё и здесь, если он есть в функции переключения видео режима?Это всё переделано из примеров DirectX SDK и добавлена специфика для видео фильмов.То, что в предыдущем сообщении с кодом, вызывается из функции Render.HRESULT CD3DApplication::Render3DEnvironment(){

HRESULT hr;

//MessageBox(NULL, "Render3DEnvironment()", "Render3DEnvironment()", 0);

//ErrorMsg("Render3DEnvironment()");

// Test the cooperative level to see if it's okay to render if( FAILED( hr = m_pd3dDevice->TestCooperativeLevel() ) ) { // If the device was lost, do not render until we get it back if( D3DERR_DEVICELOST == hr )

return S_OK;

// Check if the device needs to be resized. if( D3DERR_DEVICENOTRESET == hr ) { // If we are windowed, read the desktop mode and use the same format for // the back buffer if( m_bWindowed ) { D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter]; m_pD3D->GetAdapterDisplayMode( m_dwAdapter, &pAdapterInfo->d3ddmDesktop ); m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;

}

if( FAILED( hr = Resize3DEnvironment() ) ) return hr; } return hr;

}

// Get the app's time, in seconds. Skip rendering if no time elapsed FLOAT fAppTime = DXUtil_Timer( TIMER_GETAPPTIME ); FLOAT fElapsedAppTime = DXUtil_Timer( TIMER_GETELAPSEDTIME ); if( ( 0.0f == fElapsedAppTime ) && m_bFrameMoving )

return S_OK;

// FrameMove (animate) the scene if( m_bFrameMoving || m_bSingleStep ) { // Store the time for the app m_fTime = fAppTime;

m_fElapsedTime = fElapsedAppTime;

// Frame move the scene if( FAILED( hr = FrameMove() ) )

return hr;

m_bSingleStep = FALSE;

}

// Render the scene as normal if( FAILED( hr = Render() ) )

return hr;

// Keep track of the frame count { static FLOAT fLastTime = 0.0f; static DWORD dwFrames = 0L; FLOAT fTime = DXUtil_Timer( TIMER_GETABSOLUTETIME );

++dwFrames;

// Update the scene stats once per second if( fTime - fLastTime > 1.0f ) { m_fFPS = dwFrames / (fTime - fLastTime); fLastTime = fTime;

dwFrames = 0L;

// Get adapter's current mode so we can report // bit depth (back buffer depth may be unknown) D3DDISPLAYMODE mode;

m_pD3D->GetAdapterDisplayMode(m_dwAdapter, &mode);

_stprintf( m_strFrameStats, _T("%.02f fps (%dx%dx%d)"), m_fFPS, m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height, mode.Format==D3DFMT_X8R8G8B8?32:16 ); D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter]; D3DDeviceInfo* pDeviceInfo = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice]; D3DModeInfo* pModeInfo = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode]; if( m_bUseDepthBuffer )

{

switch( pModeInfo->DepthStencilFormat ) { case D3DFMT_D16: lstrcat( m_strFrameStats, _T(" (D16)") ); break; case D3DFMT_D15S1: lstrcat( m_strFrameStats, _T(" (D15S1)") ); break; case D3DFMT_D24X8: lstrcat( m_strFrameStats, _T(" (D24X8)") ); break; case D3DFMT_D24S8: lstrcat( m_strFrameStats, _T(" (D24S8)") ); break; case D3DFMT_D24X4S4: lstrcat( m_strFrameStats, _T(" (D24X4S4)") ); break; case D3DFMT_D32: lstrcat( m_strFrameStats, _T(" (D32)") ); break; }

}

D3DMULTISAMPLE_TYPE MultiSampleType; if( m_bWindowed ) MultiSampleType = pDeviceInfo->MultiSampleTypeWindowed; else MultiSampleType = pDeviceInfo->MultiSampleTypeFullscreen; switch( MultiSampleType ) { case D3DMULTISAMPLE_2_SAMPLES: lstrcat( m_strFrameStats, _T(" (2x Multisample)") ); break; case D3DMULTISAMPLE_3_SAMPLES: lstrcat( m_strFrameStats, _T(" (3x Multisample)") ); break; case D3DMULTISAMPLE_4_SAMPLES: lstrcat( m_strFrameStats, _T(" (4x Multisample)") ); break; case D3DMULTISAMPLE_5_SAMPLES: lstrcat( m_strFrameStats, _T(" (5x Multisample)") ); break; case D3DMULTISAMPLE_6_SAMPLES: lstrcat( m_strFrameStats, _T(" (6x Multisample)") ); break; case D3DMULTISAMPLE_7_SAMPLES: lstrcat( m_strFrameStats, _T(" (7x Multisample)") ); break; case D3DMULTISAMPLE_8_SAMPLES: lstrcat( m_strFrameStats, _T(" (8x Multisample)") ); break; case D3DMULTISAMPLE_9_SAMPLES: lstrcat( m_strFrameStats, _T(" (9x Multisample)") ); break; case D3DMULTISAMPLE_10_SAMPLES: lstrcat( m_strFrameStats, _T(" (10x Multisample)") ); break; case D3DMULTISAMPLE_11_SAMPLES: lstrcat( m_strFrameStats, _T(" (11x Multisample)") ); break; case D3DMULTISAMPLE_12_SAMPLES: lstrcat( m_strFrameStats, _T(" (12x Multisample)") ); break; case D3DMULTISAMPLE_13_SAMPLES: lstrcat( m_strFrameStats, _T(" (13x Multisample)") ); break; case D3DMULTISAMPLE_14_SAMPLES: lstrcat( m_strFrameStats, _T(" (14x Multisample)") ); break; case D3DMULTISAMPLE_15_SAMPLES: lstrcat( m_strFrameStats, _T(" (15x Multisample)") ); break; case D3DMULTISAMPLE_16_SAMPLES: lstrcat( m_strFrameStats, _T(" (16x Multisample)") ); break; } }

}

// Show the frame on the primary surface.

// m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

return S_OK;

}

Quote:
Kozlov_Sergey писал(а):
Через день собрал и потестировал - заработало. Ничего не менял. Думаю, что устранили ошибки в Direct 3D.То, что пишите вы, уже есть в функции переключения видео режимов.Спасибо за разъяснения.Нужно ли добавлять этот код ещё и здесь, если он есть в функции переключения видео режима?Это всё переделано из примеров DirectX SDK и добавлена специфика для видео фильмов.То, что в предыдущем сообщении с кодом, вызывается из функции Render.
Нет, если данное присутствует, то добовлять не надо.

P.S. Хотелось бы узнать =), как же это они устранили ошибку в Direct3D?

Submitted by MaxImuS on
Как-то. Увидели моё сообщение об ошибке, что-то сделали и всем закачали.Или может как-то добавилось в программу то, что вы писали.

А иначе почему заработало?

Quote:
Kozlov_Sergey писал(а):
Как-то. Увидели моё сообщение об ошибке, что-то сделали и всем закачали. Или может как-то добавилось в программу то, что вы писали. А иначе почему заработало?
На это много причин может быть Smile Например, у вас висела какая-то прога поп-ап и постоянно перехватывала устройство, скайп может иногда подпортить картину (не удивляйся), и еще мильОн прог. Могут быдь установлены дрОвы не с багами (их переустановка иногда спасает). И вобще я не телепат, что бы ответить на твой вопрос. Но прога элементарна и если бы в библиотеке была бы ошибка - ты представь, сколько бы игр валилось бы на компах пользователей.
Submitted by MaxImuS on

Заработало потому что что-то исправил, чудес не бывает.

Submitted by Relyer on
Кто-то исправил за меня. Ничего я не менял, только потестировал на Windows XP вместо 7, а когда заработало тестировал на 7.Такая история была, когда я делал программу для сохранения файла с веб сервера через прокси сервер. Тоже не работало. Мне сказали, что ошибка в библиотеке C++. А веб серверы все правильно работают. Пришлось использовать функции библиотеки с оглядкой. Потом всё заработало.

И ещё была история, когда мне написала Windows, что "может хватит вставлять и вынимать флеш накопитель и проще сразу всё проверить: что программа работает, и не архивировать постоянно." Я после удачной проверки архивировал. А потом переставало работать. Потом всё-таки сделал окончательно. Так прямо система и написала. Врядли такое можно запрограммировать - человек отправил.

Quote:
MaxImuS писал(а):
Quote:
Kozlov_Sergey писал(а):
Через день собрал и потестировал - заработало. Ничего не менял. Думаю, что устранили ошибки в Direct 3D. То, что пишите вы, уже есть в функции переключения видео режимов. Спасибо за разъяснения. Нужно ли добавлять этот код ещё и здесь, если он есть в функции переключения видео режима? Это всё переделано из примеров DirectX SDK и добавлена специфика для видео фильмов. То, что в предыдущем сообщении с кодом, вызывается из функции Render.

Нет, если данное присутствует, то добовлять не надо.

P.S. Хотелось бы узнать =), как же это они устранили ошибку в Direct3D?

Лично я потестировал. А кто сделал, не знаю.

В итоге я сам переделал, поставив синхронизацию переключения режима и вывода изображения.

GameDev.by