DirectX 9 - Getting camera resolutions? (C++) - c++

noob question:
Any examples of how to get parameters from the connected camera, such as supported resolutions?
I'm using DirectX June 2010.
Code to create a device:
HWND m_hwnd;
HDC *phdc;
IDirect3D9 *m_pD3D;
IDirect3DDevice9 *m_pDevice;
IDirect3DSwapChain9 *m_pSwapChain;
HRESULT DrawDevice::CreateDevice(HWND hwnd)
{
if (m_pDevice)
{
return S_OK;
}
// Create the Direct3D object.
if (m_pD3D == NULL)
{
m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (m_pD3D == NULL)
{
return E_FAIL;
}
}
HRESULT hr = S_OK;
D3DPRESENT_PARAMETERS pp = { 0 };
D3DDISPLAYMODE mode = { 0 };
hr = m_pD3D->GetAdapterDisplayMode(
D3DADAPTER_DEFAULT,
&mode
);
if (FAILED(hr)) { return hr; }
hr = m_pD3D->CheckDeviceType(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
mode.Format,
D3DFMT_X8R8G8B8,
TRUE // windowed
);
if (FAILED(hr)) { return hr; }
pp.BackBufferFormat = D3DFMT_X8R8G8B8;
pp.SwapEffect = D3DSWAPEFFECT_COPY;
pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
pp.Windowed = TRUE;
pp.hDeviceWindow = hwnd;
hr = m_pD3D->CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hwnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE,
&pp,
&m_pDevice
);
if (FAILED(hr)) { return hr; }
m_hwnd = hwnd;
m_d3dpp = pp;
return hr;
}
My purpose is to give the user a list of options to choose...
Thanks !!

Well if you need Monitor resolutions you should use DXUT microsoft Gui library or QT or custom you should make enumeration type and declare screen resolutions. I don't know what kind of resolutions you prefer.
P.S. I am not sure if you will succeded with DX SDK 2010 June and if you are using latest Windows and Visual Studio IDE. Simply that kind of DirectX SDK doesn't supported any more by Microsoft. You should use Windows SDK at least Windows 8.1 version. Hope this helps.

Direct3D is used to render to a monitor, not to capture images from a camera. Depending on what version of the OS you are using, you should take a look at Media Foundation or legacy DirectShow.
Direct3D 9 itself is also deprecated, as is the legacy DirectX SDK. See MSDN and this post. New projects should use DirectX 11 (or very experienced Direct3D graphics developers looking for high performance on Windows 10 / Xbox One should consider DirectX 12).
For a Win32 desktop application, you should look at this sample on GitHub.
For a Universal Windows Platform (UWP) app, you should look at this sample on GitHub.

Related

HRESULT 0x8876086c D3DERR_INVALIDCALL with DirectX9 pretty much following the documentation example

So i wanna draw an overlay over another window, but im getting no real runtime error the visual Studio debugging tools tell me that the result of
HRESULT res = object->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWND, D3DCREATE_HARDWARE_VERTEXPROCESSING, &params, NULL, &device);
is 0x8876086c. So here are the snippets of my code that are important and lead to this error(D3DERR_INVALIDCALL), which leads to the device being a nullpointer, which means i can't do anything with it.
I couldn't really figure out what led to this as i pretty much followed the documentation
int Paint::init(HWND hWND) {
if (FAILED(Direct3DCreate9Ex(D3D_SDK_VERSION, &object))) {
exit(1);
}
ZeroMemory(&params, sizeof(params));
params.BackBufferWidth = width;
params.BackBufferHeight = height;
params.Windowed = true;
params.hDeviceWindow = hWND;
params.MultiSampleQuality = D3DMULTISAMPLE_NONE;
params.BackBufferFormat = D3DFMT_A8R8G8B8;
params.EnableAutoDepthStencil = TRUE;
params.AutoDepthStencilFormat = D3DFMT_D16;
HRESULT res = object->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWND, D3DCREATE_HARDWARE_VERTEXPROCESSING, &params, NULL, &device);
and in the header file:
class Paint {
private:
IDirect3D9Ex* object = NULL;
IDirect3DDevice9Ex* device = NULL;
DWORD behaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
D3DPRESENT_PARAMETERS params;
ID3DXFont* font = 0;
HWND TargetHWND;
int width, height;
int init(HWND(hWND));
}
D3DPRESENT_PARAMETERS params = {};
// Use Win32 BOOL "TRUE" instead of C++ "true"
params.Windowed = TRUE;
params.hDeviceWindow = m_window;
// params.BackBufferWidth, BackBufferHeight are ignored for Windowed = TRUE
// For Windowed = TRUE, use params.BackBufferFormat = D3DFMT_UNKNOWN, which is zero.
// For params.BackBufferCount zero is assumed to be 1, but best practice
// would be to set it
params.BackBufferCount = 1;
// You used D3DMULTISAMPLE_NONE for the MultiSampleQuality instead of MultiSampleType.
// It's all zero anyhow.
params.EnableAutoDepthStencil = TRUE;
params.AutoDepthStencilFormat = D3DFMT_D16;
// --->>> This is the actual bug: there is no valid SwapEffect that has a value of zero <<<---
params.SwapEffect = D3DSWAPEFFECT_DISCARD;
You are making the assumption that the Direct3D9 device supports D3DCREATE_HARDWARE_VERTEXPROCESSING, but you haven't validated it actually supports it. That said, D3DCREATE_SOFTWARE_VERTEXPROCESSING has known performance issues on Windows 10 so you should probably just require HW anyhow.
You should not be using legacy Direct3D9 or Direct3D9Ex for new projects. It's mostly emulated on newer versions of Windows, has lots of strange behaviors, and is almost 20 years old at this point. There's no support for the Direct3D 9 debug device on Windows 8.x or Windows 10. You should consider Direct3D 11 as a much better starting place for developers new to DirectX.

Debug DirectX code

I've been learning DirectX by following some tutorials but every time I type something myself then DirectX won't work. Here is an example of the latest error that I can't fix after hours of research:
//Header.h
static HWND hWnd;
static IDXGISwapChain* swapChain;
static ID3D11Device* dev;
static ID3D11DeviceContext* devCon;
static ID3D11RenderTargetView* renderTarget;
//DirectX.cpp
bool InitD3D11(HINSTANCE hInst)
{
HRESULT hr;
DXGI_MODE_DESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));
bufferDesc.Width = 800;
bufferDesc.Height = 600;
bufferDesc.RefreshRate.Numerator = 60;
bufferDesc.RefreshRate.Denominator = 1;
bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
swapChainDesc.BufferDesc = bufferDesc;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.OutputWindow = hWnd;
swapChainDesc.Windowed = true;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL, D3D11_SDK_VERSION, &swapChainDesc, &swapChain, &dev, NULL, &devCon);
ID3D11Texture2D* backBuffer;
hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backBuffer);
hr = dev->CreateRenderTargetView(backBuffer, NULL, &renderTarget);
backBuffer->Release();
devCon->OMSetRenderTargets(1, &renderTarget, NULL);
return true;
}
//This is not the full code - I linked directx and lib files and stuff like that.
//If I copy and paste code from tutorials, everything runs fine
Whenever I call InitD3d11, I get an error saying that the swapChain is a NULL pointer. I assume that bufferDesc and/or swapChainDesc has some invalid data but the compiler can't give me any clue what is responsible for the error. Can someone please show me how to trace and fix errors like this? Thanks.
You are not checking the HRESULT values so you are missing all error-handling. For COM programming, even with Direct3D, you must check the HRESULT of every method that can return one for failure. If the return value is safe to ignore, it returns void instead.
Checking HRESULT values in old-school C/C++ programs is done with either the FAILED or SUCCEEDED macros.
hr = D3D11CreateDeviceAndSwapChain( /* ... */ *);
if (FAILED(hr))
return false;
In most cases, a failed HRESULT is treated as a 'fast-fail' or a fatal error. In other words, the program cannot proceed if the call fails.
In other cases there can be special case handling to recover from the error perhaps by using different options. For a detailed example of that, see Anatomy of Direct3D 11 Create Device.
In older Microsoft samples based on the legacy DXUT framework, the error handling was done with macros like V or V_RETURN which did some tracing or tracing & fatal exit.
In modern C++ samples, we actually use a helper DX::ThrowIfFailed that generates a C++ exception on a failed HRESULT for the fast-fail scenario. This makes the code more streamlined and readable:
DX::ThrowIfFailed(
D3D11CreateDeviceAndSwapChain( /* ... */ *)
);
The function itself is defined as:
#include <exception>
namespace DX
{
inline void ThrowIfFailed(HRESULT hr)
{
if (FAILED(hr))
{
// Set a breakpoint on this line to catch DirectX API errors
throw std::exception();
}
}
}
Your program should be compiled with /EHsc which is already in the default Visual Studio templates. See this topic page for more details.
From your code snippet above, you are following a pretty old-school tutorial. A lot has changed even for DirectX 11 development and most of those older tutorials are going to lead to confusion. As you are new to DirectX, I recommend you take a look at the DirectX Tool Kit and the tutorials there first. You can then come back to the older tutorials with a better understanding of 'modern' Direct3D and be able to extract more relevant information from the old stuff.
After checking all HRESULTS, the next thing you should do is enable the Direct3D debug layer which provides extra debugging information in the output window.
DWORD createDeviceFlags = 0;
#ifdef _DEBUG
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
hr = D3D11CreateDeviceAndSwapChain(
nullptr, D3D_DRIVER_TYPE_HARDWARE,
nullptr, createDeviceFlags, nullptr,
0, D3D11_SDK_VERSION,
&swapChainDesc, &swapChain, &dev, nullptr, &devCon);
You'll note I'm using the C++11 nullptr which is supported on Visual C++ 2010 or later instead of the old-school NULL. That's because it is typed. You were using NULL in two places in your version where the parameter wasn't actually a pointer, it's a number.
With this, you'll get a lot of feedback on basic errors that would help diagnose why in your particular case the swapchain is failing to create. I suspect it's because you are providing some values that are only meaningful for "exclusive fullscreen mode" and not for windowed mode (bufferDesc.RefreshRate). Instead, try:
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferDesc.Width = 800;
swapChainDesc.BufferDesc.Height = 600;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.OutputWindow = hWnd;
swapChainDesc.Windowed = TRUE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
This works on VS 2013 or VS 2015 which will initialize the structure to 0 with the ={}; syntax. On older compilers, you'll need to use ZeroMemory like you did in your old-school code above.
Note that using D3D11_CREATE_DEVICE_DEBUG will fail on a system that lacks the debugging device which is intended only for developers to use. Details on where you obtain the debug device layer differs based on which version of Windows you are using. See Direct3D SDK Debug Layer Tricks which has a little summary table at the bottom.
Also, debugging in the presence of uninitialized variables is a huge pain. Uninitialized pointers in particular can be a huge time waster. It would help if you did the following:
static HWND hWnd = nullptr;
static IDXGISwapChain* swapChain = nullptr;
static ID3D11Device* dev = nullptr;
static ID3D11DeviceContext* devCon = nullptr;
static ID3D11RenderTargetView* renderTarget = nullptr;
Even better, instead of using raw pointers for your COM objects, you should be using a C++ smart-pointer like Microsoft::WRL::ComPtr. See this topic page for details. Our modern samples use it, and it works for classic Win32 desktop apps as well as for Windows Store, UWP, and Xbox One apps since it's just a C++ template.

Creating a D3D device without HWND input parameter to MSFT CreateDevice() function

Kindly Pardon me if my doubt is silly or foolish. I am totally new to DirectX programming. Just have C++ knowledge (Very basic COM knowledge).
Below code sample is from MSDN Creating D3D device which explains how to create a D3D device from scratch.
MyDoubt is :
Here the function "pD3D->CreateDeviceEx()" takes in a parameter
HWND hwnd. What if I am trying to create a D3D device from a
commadline C++ win32 app where I need to use some of the functions in D3D device's interfaces. How do I get the HWND field. In this case
how do I create D3D device. PLease explain in detail.
HRESULT InitD3D9Ex( /* IN */ HWND hWnd, /* OUT */ IDirect3DDevice9Ex ** ppD3DDevice )
{
HRESULT hr = E_FAIL;
IDirect3D9Ex * pD3D = NULL;
IDirect3DDevice9Ex * pDevice = NULL;
if(ppD3DDevice == NULL)
{
return hr;
}
// Create the D3D object, which is needed to create the D3DDevice.
if(FAILED(hr = Direct3DCreate9Ex( D3D_SDK_VERSION, &pD3D )))
{
*ppD3DDevice = NULL;
return hr;
}
// Set up the structure used to create the D3DDevice.
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
// Create the Direct3D device.
if( FAILED( hr = pD3D->CreateDeviceEx( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, NULL, &pDevice ) ) )
{
*ppD3DDevice = NULL;
return hr;
}
// Device state would normally be set here
*ppD3DDevice = pDevice;
return hr;
}
In Windows all the visual things are controlled by window handles. You cannot create the D3D "device" and attach it to "nothing". You must associate the "D3D device" with some window (your own one or a desktop).
Your console window is created by the system and you do not control its creation flags, so even if you use the GetConsoleWindow function, you cannot use this HWND in Direct3D device creation functions (this might have changed with the introduction of Aero).
You cannot avoid creating getting yet another window handle in your console application. Use the RegisterWindowClass and CreateWindow functions to create a new window or find the handle to your desktop (I doubt you would want that).

IMovieControl::Run fails on Windows XP?

Actually, it only fails the second time it's called. I'm using a windowless control to play video content, where the video being played could change while the control is still on screen. Once the graph is built the first time, we switch media by stopping playback, replacing the SOURCE filter, and running the graph again. This works fine under Vista, but when running on XP, the second call to Run() returns E_UNEXPECTED.
The initialization goes something like this:
// Get the interface for DirectShow's GraphBuilder
mGB.CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER);
// Create the Video Mixing Renderer and add it to the graph
ATL::CComPtr<IBaseFilter> pVmr;
pVmr.CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC);
mGB->AddFilter(pVmr, L"Video Mixing Renderer 9");
// Set the rendering mode and number of streams
ATL::CComPtr<IVMRFilterConfig9> pConfig;
pVmr->QueryInterface(IID_IVMRFilterConfig9, (void**)&pConfig);
pConfig->SetRenderingMode(VMR9Mode_Windowless);
pVmr->QueryInterface(IID_IVMRWindowlessControl9, (void**)&mWC);
And here's what we do when we decide to play a movie. RenderFileToVideoRenderer is borrowed from dshowutil.h in the DirectShow samples area.
// Release the source filter, if it exists, so we can replace it.
IBaseFilter *pSource = NULL;
if (SUCCEEDED(mpGB->FindFilterByName(L"SOURCE", &pSource)) && pSource)
{
mpGB->RemoveFilter(pSource);
pSource->Release();
pSource = NULL;
}
// Render the file.
hr = RenderFileToVideoRenderer(mpGB, mPlayPath.c_str(), FALSE);
// QueryInterface for DirectShow interfaces
hr = mpGB->QueryInterface(&mMC);
hr = mpGB->QueryInterface(&mME);
hr = mpGB->QueryInterface(&mMS);
// Read the default video size
hr = mpWC->GetNativeVideoSize(&lWidth, &lHeight, NULL, NULL);
if (hr != E_NOINTERFACE)
{
if (FAILED(hr))
{
return hr;
}
// Play video at native resolution, anchored at top-left corner.
RECT r;
r.left = 0;
r.top = 0;
r.right = lWidth;
r.bottom = lHeight;
hr = mpWC->SetVideoPosition(NULL, &r);
}
// Run the graph to play the media file
if (mMC)
{
hr = mMC->Run();
if (FAILED(hr))
{
// We get here the second time this code is executed.
return hr;
}
mState = Running;
}
if (mME)
{
mME->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0);
}
Anybody know what's going on here?
Try calling IMediaControl::StopWhenReady before removing the source filter.
When are you calling QueryInterface directly? you can use CComQIPtr<> to warp the QI for you. This way you won't have to call Release as it will be called automatically.
The syntax look like this: CComPtr<IMediaControl> mediaControl = pGraph;
In FindFilterByName() instead of passing live pointer pass a CComPtr, again so you won't have to call release explicitly.
Never got a resolution on this. The production solution was to just call IGraphBuilder::Release and rebuild the entire graph from scratch. There's a CPU spike and a slight redraw delay when switching videos, but it's less pronounced than we'd feared.

DirectDraw question - running the application as a regular Windows application

I am developing an application for video recording and I want to overlay the video preview with a logo and recording timer.
I tried to run the full-screen application and everything worked fine. Then I tried to run the application as a regular Windows application and it returned an error.
Could anyone take a look at the code below if there's a way to modify it to run the application as a regular Windows app?
HRESULT CViewfinderRenderer::OnStartStreaming()
{
HRESULT hr = S_OK;
DDSURFACEDESC ddsd;
m_pDD = NULL;
//full screen settings
hr = DirectDrawCreate(NULL, &m_pDD, NULL);
hr = m_pDD->SetCooperativeLevel(m_hWnd, DDSCL_FULLSCREEN);
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_FLIP | DDSCAPS_PRIMARYSURFACE;
ddsd.dwBackBufferCount = 1;
//end full screen settings
//normal settings
/*hr = DirectDrawCreate(NULL, &m_pDD, NULL);
hr = m_pDD->SetCooperativeLevel(m_hWnd, DDSCL_NORMAL);
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_BACKBUFFERCOUNT;
ddsd.dwBackBufferCount = 1;*/
//end normal settings
hr = m_pDD->CreateSurface(&ddsd, &m_pSurface, NULL);
if (hr != DD_OK) {
return hr;
}
// Get backsurface
hr = m_pSurface->EnumAttachedSurfaces(&m_pBackSurface, EnumFunction);
return S_OK;
}
Even when running windowed, you need to create a primary surface, only it is not a flippable surface.
//full screen settings
hr = DirectDrawCreate(NULL, &m_pDD, NULL);
hr = m_pDD->SetCooperativeLevel(m_hWnd, DDSCL_NORMAL);
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
Besides of creating a surface, most likely you will want to create a clipper for the window. For a complete sample see paragraph Running windowed in this GameDev article.
What error did it return?
Also try this instead:
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;