225 lines
5.8 KiB
C++
225 lines
5.8 KiB
C++
#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<uint8>* WebCamera::GetImage() {
|
|
return grabber->GetImage();
|
|
}
|
|
|
|
void WebCamera::OnImageGrabbed(WinMfImageGrabber* grabber, RawBuffer<uint8>* image) {
|
|
FrameNumber++;
|
|
Event_ImageCapture.Call(this, image);
|
|
}
|
|
bool WebCamera::Open() {
|
|
IMFActivate* pActivate = dynamic_cast<WinWebCameraDescription*>(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<WinWebCameraDescription*>(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<webcam_desc_ptr> WebCamera::GetConnectedDevices() {
|
|
std::vector<webcam_desc_ptr> 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;
|
|
}
|
|
} |