#include "WebCamera.h" #include "../Utils.h" #include "../log/NLog.h" #include "../Com.h" namespace LifeCore { class WinWebCameraDescription : public WebCameraDescription { public: friend class WebCamera; WinWebCameraDescription(IMFActivate* act, int id) : activate(act), deviceId(id) { if(activate != nullptr) activate->AddRef(); } ~WinWebCameraDescription() { SafeRelease(&activate); } std::wstring GetName() override{ if(activate == nullptr) return std::wstring(L""); WCHAR *szFriendlyName = NULL; UINT32 cchName; auto hr = activate->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &szFriendlyName, &cchName); if(hr != S_OK) return std::wstring(L""); std::wstring result(szFriendlyName); CoTaskMemFree(szFriendlyName); return result; } int deviceId; protected: IMFActivate* activate; }; struct ChooseDeviceParam { ChooseDeviceParam() : ppDevices(NULL), count(0) {} ~ChooseDeviceParam() { for(DWORD i = 0; i < count; i++) { SafeRelease(&ppDevices[i]); } CoTaskMemFree(ppDevices); } IMFActivate **ppDevices; UINT32 count; UINT32 selection; }; class WinWebCamCallback : IMFCaptureEngineOnEventCallback { public: WinWebCamCallback(WebCamera* cam) : m_cRef(1), camera(cam), sleeping(false) { } // IUnknown STDMETHODIMP QueryInterface(REFIID riid, void** ppv) { static const QITAB qit[] = { QITABENT(WinWebCamCallback, IMFCaptureEngineOnEventCallback), { 0 } }; return QISearch(this, qit, riid, ppv); } STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&m_cRef); } STDMETHODIMP_(ULONG) Release() { LONG cRef = InterlockedDecrement(&m_cRef); if(cRef == 0) { delete this; } return cRef; } // IMFCaptureEngineOnEventCallback STDMETHODIMP OnEvent(_In_ IMFMediaEvent* pEvent) { if(sleeping && camera != nullptr) { // We're about to fall asleep, that means we've just asked the CE to stop the preview // and record. We need to handle it here since our message pump may be gone. GUID guidType; HRESULT hrStatus; HRESULT hr = pEvent->GetStatus(&hrStatus); if(FAILED(hr)) { hrStatus = hr; } hr = pEvent->GetExtendedType(&guidType); if(SUCCEEDED(hr)) { if(guidType == MF_CAPTURE_ENGINE_PREVIEW_STOPPED) { LogInfo() << "Preview stopped"; //m_pManager->OnPreviewStopped(hrStatus); // SetEvent(m_pManager->m_hEvent); } else if(guidType == MF_CAPTURE_ENGINE_RECORD_STOPPED) { LogInfo() << "Engine stopped"; //m_pManager->OnRecordStopped(hrStatus); //SetEvent(m_pManager->m_hEvent); } else { // This is an event we don't know about, we don't really care and there's // no clean way to report the error so just set the event and fall through. //SetEvent(m_pManager->m_hEvent); } } return S_OK; } else { LogInfo() << "Capture event"; pEvent->AddRef(); // The application will release the pointer when it handles the message. camera->OnCaptureEvent(pEvent); //PostMessage(m_hwnd, WM_APP_CAPTURE_EVENT, (WPARAM)pEvent, 0L); } return S_OK; } protected: bool sleeping; long m_cRef; WebCamera* camera; }; WebCamera::WebCamera(webcam_desc_ptr desc) : description(desc), FrameNumber(0), pSource(nullptr), grabber(nullptr) { callback = new WinWebCamCallback(this); } void WebCamera::OnCaptureEvent(IMFMediaEvent* pEvent) { HRESULT hrStatus; GUID eventType; pEvent->GetStatus(&hrStatus); pEvent->GetExtendedType(&eventType); } RawBuffer* WebCamera::GetImage() { return grabber->GetImage(); } void WebCamera::OnImageGrabbed(WinMfImageGrabber* grabber, RawBuffer* image) { FrameNumber++; Event_ImageCapture.Call(this, image); } bool WebCamera::Open() { IMFActivate* pActivate = dynamic_cast(description.get())->activate; HRESULT hr = pActivate->ActivateObject(__uuidof(IMFMediaSource), (void**)&pSource); if(FAILED(hr)) { LogInfo() << "Failed to activate camera!"; return false; } grabber = new WinMfImageGrabber(this); if(FAILED(grabber->initImageGrabber(pSource, MFVideoFormat_RGB24)) || FAILED(grabber->startGrabbing())) { LogInfo() << "Failed to init camera grabber"; pActivate->ShutdownObject(); FINAL_RELEASE(grabber); FINAL_RELEASE(pSource); return false; } return true; } void WebCamera::Close() { IMFActivate* pActivate = dynamic_cast(description.get())->activate; if(grabber != nullptr) grabber->stopGrabbing(); FINAL_RELEASE(grabber); FINAL_RELEASE(pSource); pActivate->ShutdownObject(); pActivate->AddRef(); auto val = pActivate->Release(); LogInfo() << "Initial 2 pActivate refCount = " << val; FrameNumber = 0; } int2 WebCamera::GetSize() { return int2(); } int32 WebCamera::GetBpp() { return -1; } bool WebCamera::Read(int2 size, uint8* buffer) { return false; } void WebCamera::Update() { grabber->processGrabbing(); } std::vector WebCamera::GetConnectedDevices() { std::vector result; IMFAttributes *pAttributes = NULL; ChooseDeviceParam param; HRESULT hr = MFCreateAttributes(&pAttributes, 1); if(FAILED(hr)) { printf("Failed\n"); goto Exit; } // Ask for source type = video capture devices hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID); if(FAILED(hr)) { printf("Failed\n"); goto Exit; } // Enumerate devices. hr = MFEnumDeviceSources(pAttributes, ¶m.ppDevices, ¶m.count); if(FAILED(hr)) { printf("Failed\n"); goto Exit; } for(UINT32 i = 0; i < param.count; ++i) { result.push_back(webcam_desc_ptr(new WinWebCameraDescription(param.ppDevices[i], i))); } Exit: if(NULL != pAttributes) { pAttributes->Release(); pAttributes = NULL; } return result; } }