我现在需要开发一个类似Windows 11 的“相机”的应用程序,来访问我的UVC相机。请给出demo
时间: 2024-05-08 09:21:36 浏览: 154
好的,以下是一个简单的Windows应用程序示例,可以使用UVC相机进行拍照和录像:
```c++
#include <Windows.h>
#include <dshow.h>
#pragma comment(lib, "strmiids.lib")
// UVC相机操作类
class UvcCamera
{
public:
UvcCamera() : m_pGraph(nullptr), m_pCapture(nullptr), m_pControl(nullptr),
m_pStill(nullptr), m_pBuilder(nullptr), m_pSampleGrabber(nullptr), m_pCallback(nullptr),
m_hWnd(nullptr), m_bPreviewing(false)
{}
~UvcCamera()
{
if (m_bPreviewing) {
StopPreview();
}
if (m_pCallback) {
m_pCallback->Release();
m_pCallback = nullptr;
}
if (m_pSampleGrabber) {
m_pSampleGrabber->Release();
m_pSampleGrabber = nullptr;
}
if (m_pBuilder) {
m_pBuilder->Release();
m_pBuilder = nullptr;
}
if (m_pStill) {
m_pStill->Release();
m_pStill = nullptr;
}
if (m_pControl) {
m_pControl->Release();
m_pControl = nullptr;
}
if (m_pCapture) {
m_pCapture->Release();
m_pCapture = nullptr;
}
if (m_pGraph) {
m_pGraph->Release();
m_pGraph = nullptr;
}
}
// 初始化UVC相机
bool Init(HWND hWnd)
{
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, nullptr, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void**)&m_pGraph);
if (FAILED(hr)) {
return false;
}
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, nullptr, CLSCTX_INPROC_SERVER,
IID_ICaptureGraphBuilder2, (void**)&m_pBuilder);
if (FAILED(hr)) {
return false;
}
hr = m_pBuilder->SetFiltergraph(m_pGraph);
if (FAILED(hr)) {
return false;
}
hr = CoCreateInstance(CLSID_SampleGrabber, nullptr, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&m_pSampleGrabber);
if (FAILED(hr)) {
return false;
}
hr = m_pGraph->AddFilter(m_pSampleGrabber, L"Sample Grabber");
if (FAILED(hr)) {
return false;
}
hr = m_pBuilder->FindInterface(&PIN_CATEGORY_STILL, &MEDIATYPE_Video,
m_pCapture, IID_IAMStreamConfig, (void**)&m_pStill);
if (FAILED(hr)) {
return false;
}
hr = m_pBuilder->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
m_pCapture, IID_IAMVideoControl, (void**)&m_pControl);
if (FAILED(hr)) {
return false;
}
hr = m_pGraph->QueryInterface(IID_IMediaControl, (void**)&m_pMediaControl);
if (FAILED(hr)) {
return false;
}
hr = m_pGraph->QueryInterface(IID_IMediaEvent, (void**)&m_pMediaEvent);
if (FAILED(hr)) {
return false;
}
hr = m_pSampleGrabber->QueryInterface(IID_ISampleGrabber, (void**)&m_pGrabber);
if (FAILED(hr)) {
return false;
}
hr = m_pGrabber->SetCallback(this, 1);
if (FAILED(hr)) {
return false;
}
m_hWnd = hWnd;
m_bPreviewing = false;
return true;
}
// 开始预览
bool StartPreview()
{
HRESULT hr = CoCreateInstance(CLSID_VideoCapture, nullptr, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&m_pCapture);
if (FAILED(hr)) {
return false;
}
hr = m_pGraph->AddFilter(m_pCapture, L"UVC Camera");
if (FAILED(hr)) {
return false;
}
hr = m_pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
m_pCapture, m_pSampleGrabber, nullptr);
if (FAILED(hr)) {
return false;
}
hr = m_pMediaControl->Run();
if (FAILED(hr)) {
return false;
}
m_bPreviewing = true;
return true;
}
// 停止预览
bool StopPreview()
{
HRESULT hr = m_pMediaControl->Stop();
if (FAILED(hr)) {
return false;
}
hr = m_pGraph->RemoveFilter(m_pCapture);
if (FAILED(hr)) {
return false;
}
hr = m_pGraph->RemoveFilter(m_pSampleGrabber);
if (FAILED(hr)) {
return false;
}
m_pCapture->Release();
m_pCapture = nullptr;
m_bPreviewing = false;
return true;
}
// 拍照
bool CaptureImage(const wchar_t* szFileName)
{
AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
HRESULT hr = m_pStill->GetFormat(&mt);
if (FAILED(hr)) {
return false;
}
hr = m_pStill->SetFormat(&mt);
if (FAILED(hr)) {
return false;
}
hr = m_pMediaControl->Stop();
if (FAILED(hr)) {
return false;
}
hr = m_pBuilder->RenderStream(&PIN_CATEGORY_STILL, &MEDIATYPE_Video,
m_pCapture, m_pSampleGrabber, nullptr);
if (FAILED(hr)) {
return false;
}
hr = m_pMediaControl->Run();
if (FAILED(hr)) {
return false;
}
long evCode;
hr = m_pMediaEvent->WaitForCompletion(INFINITE, &evCode);
hr = m_pGrabber->GetCurrentBuffer(&mt.cbFormat, (BYTE*)mt.pbFormat);
if (FAILED(hr)) {
return false;
}
BITMAPINFOHEADER& bmih = *(BITMAPINFOHEADER*)mt.pbFormat;
BYTE* pData = nullptr;
hr = m_pGrabber->GetCurrentBuffer(&mt.cbBuffer, (BYTE**)&pData);
if (FAILED(hr)) {
return false;
}
BITMAPFILEHEADER bmfh;
ZeroMemory(&bmfh, sizeof(BITMAPFILEHEADER));
bmfh.bfType = 'MB';
bmfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + mt.cbBuffer;
bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
HANDLE hFile = CreateFile(szFileName, GENERIC_WRITE, 0, nullptr,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hFile == INVALID_HANDLE_VALUE) {
return false;
}
DWORD dwBytesWritten;
WriteFile(hFile, &bmfh, sizeof(BITMAPFILEHEADER), &dwBytesWritten, nullptr);
WriteFile(hFile, &bmih, sizeof(BITMAPINFOHEADER), &dwBytesWritten, nullptr);
WriteFile(hFile, pData, mt.cbBuffer, &dwBytesWritten, nullptr);
CloseHandle(hFile);
return true;
}
private:
IGraphBuilder* m_pGraph; // 图形构建器
ICaptureGraphBuilder2* m_pBuilder; // 捕获图形构建器
IBaseFilter* m_pCapture; // 捕获过滤器
IAMStreamConfig* m_pStill; // 静态图像流配置器
IAMVideoControl* m_pControl; // 视频控制器
IMediaControl* m_pMediaControl; // 媒体控制器
IMediaEvent* m_pMediaEvent; // 媒体事件
ISampleGrabber* m_pSampleGrabber; // 采样抓取器
ISampleGrabberCB* m_pCallback; // 采样抓取回调函数
HWND m_hWnd; // 窗口句柄
bool m_bPreviewing; // 是否正在预览
};
// 采样抓取回调函数
class SampleGrabberCallback : public ISampleGrabberCB
{
public:
SampleGrabberCallback() : m_pWnd(nullptr), m_pUvcCamera(nullptr) {}
void SetWindowHandle(HWND hWnd)
{
m_pWnd = hWnd;
}
void SetUvcCamera(UvcCamera* pUvcCamera)
{
m_pUvcCamera = pUvcCamera;
}
STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
{
if (riid == IID_ISampleGrabberCB) {
*ppv = (void*)this;
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef()
{
return 2;
}
STDMETHODIMP_(ULONG) Release()
{
return 1;
}
STDMETHODIMP SampleCB(double dSampleTime, IMediaSample* pSample)
{
return S_OK;
}
STDMETHODIMP BufferCB(double dSampleTime, BYTE* pBuffer, long lBufferSize)
{
if (m_pWnd) {
HDC hDC = GetDC(m_pWnd);
BITMAPINFOHEADER bmih;
ZeroMemory(&bmih, sizeof(BITMAPINFOHEADER));
bmih.biSize = sizeof(BITMAPINFOHEADER);
bmih.biWidth = 640;
bmih.biHeight = 480;
bmih.biPlanes = 1;
bmih.biBitCount = 24;
bmih.biCompression = BI_RGB;
SetStretchBltMode(hDC, COLORONCOLOR);
StretchDIBits(hDC, 0, 0, 640, 480, 0, 0, 640, 480, pBuffer, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, SRCCOPY);
ReleaseDC(m_pWnd, hDC);
}
return S_OK;
}
private:
HWND m_pWnd; // 窗口句柄
UvcCamera* m_pUvcCamera; // UVC相机操作类
};
// 应用程序窗口过程
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static UvcCamera uvcCamera;
static SampleGrabberCallback callback;
switch (uMsg)
{
case WM_CREATE:
if (!uvcCamera.Init(hWnd)) {
MessageBox(hWnd, L"Failed to initialize UVC camera!", L"Error", MB_ICONERROR);
return -1;
}
callback.SetWindowHandle(hWnd);
callback.SetUvcCamera(&uvcCamera);
uvcCamera.SetSampleGrabberCallback(&callback);
if (!uvcCamera.StartPreview()) {
MessageBox(hWnd, L"Failed to start preview!", L"Error", MB_ICONERROR);
return -1;
}
break;
case WM_PAINT:
break;
case WM_DESTROY:
uvcCamera.StopPreview();
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
// WinMain函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.lpszClassName = L"UvcCamera";
if (!RegisterClassEx(&wc)) {
MessageBox(nullptr, L"Failed to register window class!", L"Error", MB_ICONERROR);
return -1;
}
HWND hWnd = CreateWindowEx(0, L"UvcCamera", L"Uvc Camera", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, nullptr, nullptr, hInstance, nullptr);
if (!hWnd) {
MessageBox(nullptr, L"Failed to create window!", L"Error", MB_ICONERROR);
return -1;
}
ShowWindow(hWnd, nCmdShow);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
```
以上代码中,UvcCamera类是一个封装了UVC相机操作的类,主要实现了相机的初始化、预览、停止预览、拍照等功能。SampleGrabberCallback类是一个采样抓取回调函数,实现了当采样抓取完成时的回调函数,用来将采样数据显示到窗口中。WindowProc函数是应用程序窗口过程,主要用来处理窗口消息,包括初始化UVC相机、启动预览、停止预览、拍照等操作。WinMain函数是应用程序入口函数,主要是创建窗口并运行消息循环。
需要注意的是,在使用此示例代码之前,你需要安装DirectShow SDK并链接strmiids.lib库。示例代码中使用的是位图格式保存拍摄的照片,你可以根据需要修改保存格式。
阅读全文