summaryrefslogtreecommitdiff
path: root/src/imaging/DSCamera.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/imaging/DSCamera.cpp')
-rw-r--r--src/imaging/DSCamera.cpp733
1 files changed, 733 insertions, 0 deletions
diff --git a/src/imaging/DSCamera.cpp b/src/imaging/DSCamera.cpp
new file mode 100644
index 0000000..e9e3b3b
--- /dev/null
+++ b/src/imaging/DSCamera.cpp
@@ -0,0 +1,733 @@
+//
+// libavg - Media Playback Engine.
+// Copyright (C) 2003-2014 Ulrich von Zadow
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Current versions can be found at www.libavg.de
+//
+
+#include <InitGuid.h>
+
+#include "DSHelper.h"
+#include "DSCamera.h"
+#include "DSSampleGrabber.h"
+
+#include "../base/Logger.h"
+#include "../base/Exception.h"
+#include "../base/ScopeTimer.h"
+#include "../graphics/FilterFlip.h"
+#include "../graphics/Filtergrayscale.h"
+
+#include <oleauto.h>
+
+#include <math.h>
+
+#include <sstream>
+
+namespace avg {
+
+using namespace std;
+
+DSCamera::DSCamera(std::string sDevice, IntPoint size, PixelFormat camPF,
+ PixelFormat destPF, float frameRate)
+ : Camera(camPF, destPF, size, frameRate),
+ m_sDevice(sDevice),
+ m_pGraph(0),
+ m_pCapture(0),
+ m_pCameraPropControl(0)
+{
+ open();
+}
+
+DSCamera::~DSCamera()
+{
+ close();
+}
+
+void DSCamera::open()
+{
+ initGraphBuilder();
+ findCaptureDevice(&m_pSrcFilter);
+ if (m_pSrcFilter) {
+ HRESULT hr;
+ hr = m_pGraph->AddFilter(m_pSrcFilter, L"Video Capture");
+ checkForDShowError(hr, "DSCamera::open()::Add capture filter");
+
+ // Create and configure the sample grabber that delivers the frames to the app.
+ m_pGrabFilter = new CSampleGrabber(NULL, &hr);
+ m_pGrabFilter->AddRef();
+ checkForDShowError(hr, "DSCamera::open()::Create SampleGrabber");
+ hr = m_pGrabFilter->QueryInterface(IID_IlibavgGrabber,
+ (void **)&m_pSampleGrabber);
+ checkForDShowError(hr, "DSCamera::open()::Create SampleGrabber 2");
+
+ hr = m_pSrcFilter->QueryInterface(IID_IAMVideoProcAmp,
+ (void **)&m_pCameraPropControl);
+ checkForDShowError(hr, "DSCamera::open()::get IAMVideoProcAmp");
+ hr = m_pSrcFilter->QueryInterface(IID_IAMCameraControl,
+ (void **)&m_pAMCameraControl);
+ checkForDShowError(hr, "DSCamera::open()::get IAMCameraControl");
+
+ hr = m_pGraph->AddFilter(m_pGrabFilter, L"Sample Grabber");
+ checkForDShowError(hr, "DSCamera::open()::Add Grabber");
+ setCaptureFormat();
+
+ checkForDShowError(hr, "DSCamera::open()::SetMediaType");
+
+ m_pSampleGrabber->SetCallback(this);
+
+ IBaseFilter * pNull;
+ hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER,
+ IID_IBaseFilter, (LPVOID*) &pNull);
+ checkForDShowError(hr, "DSCamera::open()::Create null filter");
+ m_pGraph->AddFilter(pNull, L"NullRender");
+ pNull->Release();
+
+ connectFilters(m_pGraph, m_pSrcFilter, m_pGrabFilter);
+ connectFilters(m_pGraph, m_pGrabFilter, pNull);
+
+ // Add our graph to the running object table, which will allow
+ // the GraphEdit application to "spy" on our graph.
+ hr = AddGraphToRot(m_pGraph, &m_GraphRegisterID);
+ checkForDShowError(hr, "DSCamera::open()::AddGraphToRot");
+
+ } else {
+ throw (Exception(AVG_ERR_CAMERA_NONFATAL, "DS Camera unavailable"));
+ }
+}
+
+void DSCamera::startCapture()
+{
+ HRESULT hr = m_pMediaControl->Run();
+ checkForDShowError(hr, "DSCamera::open()::Run");
+}
+
+void DSCamera::close()
+{
+ if (m_pAMCameraControl) {
+ m_pAMCameraControl->Release();
+ }
+ m_pMediaControl->Stop();
+ RemoveGraphFromRot(m_GraphRegisterID);
+ m_pGraph->Release();
+ m_pCapture->Release();
+ m_pMediaControl->Release();
+ if (m_pCameraPropControl) {
+ m_pCameraPropControl->Release();
+ }
+ m_pSrcFilter->Release();
+ m_pGrabFilter->Release();
+ m_pSampleGrabber->Release();
+}
+
+BitmapPtr DSCamera::getImage(bool bWait)
+{
+ BitmapPtr pBmp;
+ try {
+ pBmp = m_BitmapQ.pop(bWait);
+ } catch (Exception&) {
+ return BitmapPtr();
+ }
+
+ return pBmp;
+}
+
+void DSCamera::setCaptureFormat()
+{
+ IAMStreamConfig *pSC;
+ HRESULT hr = m_pCapture->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
+ m_pSrcFilter, IID_IAMStreamConfig, (void **)&pSC);
+ checkForDShowError(hr, "DSCamera::setCaptureFormat::FindInterface");
+
+ int numCaps = 0;
+ int capsSize = 0;
+ hr = pSC->GetNumberOfCapabilities(&numCaps, &capsSize);
+ checkForDShowError(hr, "DSCamera::dumpMediaTypes::GetNumberOfCapabilities");
+
+ AVG_ASSERT(capsSize == sizeof(VIDEO_STREAM_CONFIG_CAPS));
+ bool bFormatFound = false;
+ bool bCloseFormatFound = false;
+ AM_MEDIA_TYPE* pmtConfig;
+ AM_MEDIA_TYPE* pmtCloseConfig;
+ vector<string> sImageFormats;
+ VIDEOINFOHEADER* pvih;
+ BITMAPINFOHEADER bih;
+ PixelFormat capsPF;
+ for (int i = 0; i < numCaps; i++) {
+ VIDEO_STREAM_CONFIG_CAPS scc;
+ hr = pSC->GetStreamCaps(i, &pmtConfig, (BYTE*)&scc);
+ checkForDShowError(hr, "DSCamera::dumpMediaTypes::GetStreamCaps");
+ pvih = (VIDEOINFOHEADER*)(pmtConfig->pbFormat);
+ bih = pvih->bmiHeader;
+ float frameRate = float(10000000L/pvih->AvgTimePerFrame);
+ capsPF = mediaSubtypeToPixelFormat(pmtConfig->subtype);
+
+ if (capsPF != NO_PIXELFORMAT && bih.biWidth != 0) {
+ sImageFormats.push_back(camImageFormatToString(pmtConfig));
+ }
+
+ bool bFormatUsed = false;
+ int height = bih.biHeight;
+ if (height < 0) {
+ height = -height;
+ }
+ if (bih.biWidth == getImgSize().x && height == getImgSize().y &&
+ (getCamPF() == capsPF || (getCamPF() == BAYER8_GBRG && capsPF == I8)))
+ {
+ if (fabs(getFrameRate()-frameRate) < 0.001) {
+ bFormatFound = true;
+ break;
+ } else if (!bCloseFormatFound) {
+ // The current format fits everything but the framerate.
+ // Not all framerates are reported, so we're going to try this one as
+ // well.
+ bCloseFormatFound = true;
+ bFormatUsed = true;
+ pmtCloseConfig = pmtConfig;
+ }
+ }
+ if (!bFormatUsed) {
+ CoTaskMemFree((PVOID)pmtConfig->pbFormat);
+ CoTaskMemFree(pmtConfig);
+ }
+ }
+ if (bFormatFound) {
+ AVG_TRACE(Logger::category::CONFIG, Logger::severity::INFO,
+ "Camera image format: " << camImageFormatToString(pmtConfig));
+ int height = ((VIDEOINFOHEADER*)(pmtConfig->pbFormat))->bmiHeader.biHeight;
+ m_bUpsideDown = (height > 0);
+ hr = pSC->SetFormat(pmtConfig);
+ checkForDShowError(hr, "DSCamera::dumpMediaTypes::SetFormat");
+ CoTaskMemFree((PVOID)pmtConfig->pbFormat);
+ CoTaskMemFree(pmtConfig);
+ } else {
+ if (bCloseFormatFound) {
+ // Set the framerate manually.
+ pvih = (VIDEOINFOHEADER*)(pmtCloseConfig->pbFormat);
+ pvih->AvgTimePerFrame = REFERENCE_TIME(10000000/getFrameRate());
+ int height = pvih->bmiHeader.biHeight;
+ m_bUpsideDown = (height > 0);
+ hr = pSC->SetFormat(pmtCloseConfig);
+ checkForDShowError(hr, "DSCamera::dumpMediaTypes::SetFormat");
+ AVG_TRACE(Logger::category::CONFIG, Logger::severity::INFO,
+ "Camera image format: " << camImageFormatToString(pmtCloseConfig));
+ CoTaskMemFree((PVOID)pmtCloseConfig->pbFormat);
+ CoTaskMemFree(pmtCloseConfig);
+
+ // TODO: Check if framerate is actually attained.
+ } else {
+ AVG_LOG_WARNING("Possibly incomplete list of camera image formats: ");
+ for (unsigned i = 0; i < sImageFormats.size(); i++) {
+ AVG_LOG_WARNING(" " << sImageFormats[i]);
+ }
+ throw Exception(AVG_ERR_CAMERA_NONFATAL,
+ "Could not find requested camera image format.");
+ }
+ }
+ pSC->Release();
+}
+
+
+const string& DSCamera::getDevice() const
+{
+ return m_sDevice;
+}
+
+const std::string& DSCamera::getDriverName() const
+{
+ static string sDriverName = "directshow";
+ return sDriverName;
+}
+
+int DSCamera::getFeature(CameraFeature feature) const
+{
+ long prop = getDSFeatureID(feature);
+ long val;
+ long flags;
+ HRESULT hr;
+ if (isDSFeatureCamControl(feature)) {
+ hr = m_pAMCameraControl->Get(prop, &val, &flags);
+ } else {
+ hr = m_pCameraPropControl->Get(prop, &val, &flags);
+ }
+ if (!SUCCEEDED(hr)) {
+ AVG_LOG_WARNING("DSCamera::getFeature " + cameraFeatureToString(feature)+
+ " failed.");
+ return 0;
+ }
+ return val;
+}
+
+void DSCamera::setFeature(CameraFeature feature, int value, bool bIgnoreOldValue)
+{
+ long prop = getDSFeatureID(feature);
+ if (!m_pCameraPropControl) {
+ return;
+ }
+ long flags;
+ if (value == -1) {
+ flags = VideoProcAmp_Flags_Auto;
+ } else {
+ flags = VideoProcAmp_Flags_Manual;
+ }
+ HRESULT hr;
+ if (isDSFeatureCamControl(feature)) {
+ hr = m_pAMCameraControl->Set(prop, value, flags);
+ } else {
+ hr = m_pCameraPropControl->Set(prop, value, flags);
+ }
+ switch (hr) {
+ case E_INVALIDARG:
+ // TODO: Throw exception
+ AVG_LOG_ERROR("DSCamera::setFeature(" << cameraFeatureToString(feature) <<
+ ", " << value << ") failed.");
+ break;
+ case E_PROP_ID_UNSUPPORTED:
+ case E_PROP_SET_UNSUPPORTED:
+ AVG_LOG_ERROR("DSCamera::setFeature(" << cameraFeatureToString(feature)
+ << ") failed: Feature not supported by camera.");
+ break;
+ default:
+ checkForDShowError(hr, "DSCamera::setFeature()::Set value");
+ }
+}
+
+void DSCamera::setFeatureOneShot(CameraFeature feature)
+{
+ AVG_LOG_WARNING(
+ "OneShot feature setting not implemented for DirectShow camera driver.");
+}
+
+int DSCamera::getWhitebalanceU() const
+{
+ AVG_LOG_WARNING(
+ "Whitebalance not implemented for DirectShow camera driver.");
+ return 0;
+}
+
+int DSCamera::getWhitebalanceV() const
+{
+ AVG_LOG_WARNING(
+ "Whitebalance not implemented for DirectShow camera driver.");
+ return 0;
+}
+
+void DSCamera::setWhitebalance(int u, int v, bool bIgnoreOldValue)
+{
+ AVG_LOG_WARNING(
+ "Whitebalance not implemented for DirectShow camera driver.");
+}
+
+void DSCamera::onSample(IMediaSample * pSample)
+{
+ unsigned char * pData;
+
+ // Get the current image.
+ pSample->GetPointer(&pData);
+
+ int stride = getImgSize().x*getBytesPerPixel(getCamPF());
+ Bitmap camBmp(getImgSize(), getCamPF(), pData, stride, false, "CameraImage");
+ // Copy over to bitmap queue, doing pixel format conversion if necessary.
+ BitmapPtr pDestBmp = BitmapPtr(new Bitmap(getImgSize(), getDestPF(),
+ "ConvertedCameraImage"));
+ pDestBmp->copyPixels(camBmp);
+
+ if (m_bUpsideDown) {
+ FilterFlip().applyInPlace(pDestBmp);
+ }
+
+ m_BitmapQ.push(pDestBmp);
+}
+
+int DSCamera::countCameras()
+{
+ int count = 0;
+ HRESULT hr = S_OK;
+ hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+ checkForDShowError(hr, "DSCamera::countCameras()::CoInitializeEx");
+
+ ICreateDevEnum *pDevEnum =NULL;
+ hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
+ IID_ICreateDevEnum, (void **) &pDevEnum);
+ checkForDShowError(hr, "DSCamera::countCameras()::CreateDevEnum");
+
+ IEnumMoniker *pClassEnum = NULL;
+ hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
+ checkForDShowError(hr, "DSCamera::countCameras()::CreateClassEnumerator");
+
+ if (pClassEnum == NULL) {
+ pDevEnum->Release();
+ return count;
+ }
+ IMoniker* pMoniker = NULL;
+ while (pClassEnum->Next(1, &pMoniker, NULL) == S_OK) {
+ count += 1;
+ }
+ pMoniker->Release();
+ pClassEnum->Release();
+ pDevEnum->Release();
+ return count;
+}
+
+CameraInfo* DSCamera::getCameraInfos(int deviceNumber)
+{
+#ifdef AVG_ENABLE_DSHOW
+ HRESULT hr = S_OK;
+ // Create apartment for Thread
+ hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+ checkForDShowError(hr, "DSCamera::getCameraInfos()::CoInitializeEx");
+ // Create the system device enumerator
+ ICreateDevEnum *pDevEnum =NULL;
+ hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
+ IID_ICreateDevEnum, (void **) &pDevEnum);
+ checkForDShowError(hr, "DSCamera::getCameraInfos()::CreateDevEnum");
+ // Create an enumerator for the video capture devices
+ IEnumMoniker *pClassEnum = NULL;
+ hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
+ checkForDShowError(hr, "DSCamera::getCameraInfos()::CreateClassEnumerator");
+ if (pClassEnum == NULL) {
+ pClassEnum->Release();
+ pDevEnum->Release();
+ return NULL;
+ }
+ IMoniker* pMoniker = NULL;
+ pClassEnum->Skip(deviceNumber);
+ hr = pClassEnum->Next(1, &pMoniker, NULL);
+ if (hr != S_OK) {
+ pClassEnum->Release();
+ pDevEnum->Release();
+ pMoniker->Release();
+ return NULL;
+ }
+ IPropertyBag* pPropBag;
+ hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag));
+ checkForDShowError(hr, "DSCamera::getCameraInfos()::BindToStorage");
+
+ std::string deviceID = getStringProp(pPropBag, L"DevicePath");
+ if (deviceID.empty()) {
+ deviceID = getStringProp(pPropBag, L"Description");
+ if (deviceID.empty()) {
+ deviceID = getStringProp(pPropBag, L"FriendlyName");
+ }
+ }
+ CameraInfo* pCamInfo = new CameraInfo("DirectShow", deviceID);
+
+ getCameraImageFormats(pMoniker, pCamInfo);
+ getCameraControls(pMoniker, pCamInfo);
+
+ pPropBag->Release();
+ pMoniker->Release();
+ pClassEnum->Release();
+ pDevEnum->Release();
+ return pCamInfo;
+#endif
+ return NULL;
+}
+
+void DSCamera::getCameraImageFormats(IMoniker* pMoniker, CameraInfo* pCamInfo)
+{
+ HRESULT hr = S_OK;
+ IAMStreamConfig* pSC;
+ ICaptureGraphBuilder2* pCapture;
+ IBaseFilter* pSrcFilter;
+ // locates the object identified by pMoniker and
+ // returns a pointer to its filter interface
+ hr = pMoniker->BindToObject(0,0,IID_IBaseFilter, (void**) &pSrcFilter);
+ checkForDShowError(hr, "DSCamera::getImageFormats()::BindToObject");
+ if (pSrcFilter == NULL) {
+ return;
+ }
+ // Creates an uninitialized instance and returns a pointer to
+ // the IID_ICaptureGraphBuilder2 interface
+ hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,
+ IID_ICaptureGraphBuilder2, (void **) &pCapture);
+ checkForDShowError(hr, "DSCamera::getImageFormats()::CaptureGraphBuilder2");
+ // searches the graph for a IID_IAMStreamConfig interface, returns a pointer
+ hr = pCapture->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
+ pSrcFilter, IID_IAMStreamConfig, (void **)&pSC);
+ checkForDShowError(hr, "DSCamera::getImageFormats()::FindInterface");
+ int numCaps = 0;
+ int capsSize = 0;
+ hr = pSC->GetNumberOfCapabilities(&numCaps, &capsSize);
+ checkForDShowError(hr, "DSCamera::getImageFormats()::GetNumberOfCapabilities");
+ AM_MEDIA_TYPE* pmtConfig;
+ vector<string> sImageFormats;
+ VIDEOINFOHEADER* pvih;
+ BITMAPINFOHEADER bih;
+ PixelFormat capsPF;
+ for (int i = 0; i < numCaps; i++) {
+ VIDEO_STREAM_CONFIG_CAPS scc;
+ hr = pSC->GetStreamCaps(i, &pmtConfig, (BYTE*)&scc);
+ checkForDShowError(hr, "DSCamera::getImageFormats()::GetStreamCaps");
+ pvih = (VIDEOINFOHEADER*)(pmtConfig->pbFormat);
+ bih = pvih->bmiHeader;
+ capsPF = mediaSubtypeToPixelFormat(pmtConfig->subtype);
+
+ if (capsPF != NO_PIXELFORMAT && bih.biWidth != 0) {
+ IntPoint size;
+ if (bih.biHeight >= 0) {
+ size = IntPoint(bih.biWidth, bih.biHeight);
+ } else {
+ size = IntPoint(bih.biWidth, -bih.biHeight);
+ }
+
+ std::vector<float> framerates;
+ float minFramerate = (float)(10000000 / scc.MinFrameInterval);
+ float maxFramerate = (float)(10000000 / scc.MaxFrameInterval);
+ float averageFramerate = (float)(10000000 / pvih->AvgTimePerFrame);
+ if (maxFramerate != 0.) {
+ framerates.push_back(maxFramerate);
+ }
+ if (averageFramerate != maxFramerate && averageFramerate != minFramerate) {
+ framerates.push_back(averageFramerate);
+ }
+ if (minFramerate != 0. && minFramerate != maxFramerate) {
+ framerates.push_back(minFramerate);
+ }
+ CameraImageFormat imageFormat = CameraImageFormat(size, capsPF, framerates);
+ pCamInfo->addImageFormat(imageFormat);
+ }
+ }
+ pCapture->Release();
+ pSrcFilter->Release();
+}
+
+void DSCamera::getCameraControls(IMoniker* pMoniker, CameraInfo* pCamInfo)
+{
+ HRESULT hr = S_OK;
+ IBaseFilter * pSrcFilter;
+ // locates the object identified by pMoniker and
+ // returns a pointer to its filter interface
+ hr = pMoniker->BindToObject(0,0,IID_IBaseFilter, (void**) &pSrcFilter);
+ checkForDShowError(hr, "DSCamera::dumpImageFormats()::BindToObject");
+ if (pSrcFilter == NULL) {
+ return;
+ }
+ IAMCameraControl* pAMCameraControl;
+ pSrcFilter->QueryInterface(IID_IAMCameraControl,
+ (void **)&pAMCameraControl);
+ if (pAMCameraControl != NULL) {
+ // DirectShow has 7 supported CameraControlProperties
+ for (int indexControl = 0; indexControl <= 6; indexControl++) {
+ long value = -999;
+ long flags = -999;
+ pAMCameraControl->Get((CameraControlProperty)indexControl, &value, &flags);
+ long min = -999;
+ long max = -999;
+ long delta = -999;
+ long defaultValue = -999;
+ flags = -999;
+ pAMCameraControl->GetRange((CameraControlProperty)indexControl, &min, &max,
+ &delta, &defaultValue, &flags);
+
+ CameraFeature feature = getCameraFeatureID_CCP((CameraControlProperty)indexControl);
+ if (min != -999 && max != -999 && defaultValue != -999
+ && feature != CAM_FEATURE_UNSUPPORTED) {
+ std::string featureName = cameraFeatureToString(feature);
+ CameraControl control = CameraControl(featureName,min,max,defaultValue);
+ pCamInfo->addControl(control);
+ }
+ }
+ }
+ IAMVideoProcAmp* pCameraPropControl;
+ pSrcFilter->QueryInterface(IID_IAMVideoProcAmp,
+ (void **)&pCameraPropControl);
+ if (pCameraPropControl != NULL) {
+ // DirectShow has 10 supported VideoProcAmpProperties
+ for (int indexPropControl = 0; indexPropControl <= 9; indexPropControl++) {
+ long value = -999;
+ long flags = -999;
+ pCameraPropControl->Get((VideoProcAmpProperty)indexPropControl, &value,
+ &flags);
+ long min = -999;
+ long max = -999;
+ long delta = -999;
+ long defaultValue = -999;
+ flags = -999;
+ pCameraPropControl->GetRange((VideoProcAmpProperty)indexPropControl, &min,
+ &max, &delta, &defaultValue, &flags);
+
+ CameraFeature feature = getCameraFeatureID_VPAP((VideoProcAmpProperty)indexPropControl);
+ if (min != -999 && max != -999 && defaultValue != -999
+ && feature != CAM_FEATURE_UNSUPPORTED) {
+ std::string featureName = cameraFeatureToString(feature);
+ CameraControl control = CameraControl(featureName,min,max,defaultValue);
+ pCamInfo->addControl(control);
+ }
+ }
+ }
+}
+
+
+void DSCamera::initGraphBuilder()
+{
+ HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+ checkForDShowError(hr, "DSCamera::initGraphBuilder()::CoInitializeEx");
+
+ // Create the filter graph
+ hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder,
+ (void **) &m_pGraph);
+ checkForDShowError(hr, "DSCamera::initGraphBuilder()::GraphBuilder");
+ // Create the capture graph builder
+ hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,
+ IID_ICaptureGraphBuilder2, (void **) &m_pCapture);
+ checkForDShowError(hr, "DSCamera::initGraphBuilder()::CaptureGraphBuilder2");
+
+ hr = m_pCapture->SetFiltergraph(m_pGraph);
+ checkForDShowError(hr, "DSCamera::initGraphBuilder()::SetFilterGraph");
+
+ m_pGraph->QueryInterface(IID_IMediaControl,(void**)&m_pMediaControl);
+}
+
+void DSCamera::findCaptureDevice(IBaseFilter ** ppSrcFilter)
+{
+ HRESULT hr = S_OK;
+ IBaseFilter * pSrc = NULL;
+ IMoniker* pMoniker = NULL;
+ ICreateDevEnum *pDevEnum = NULL;
+ IEnumMoniker *pClassEnum = NULL;
+
+ // Create the system device enumerator
+ hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
+ IID_ICreateDevEnum, (void **) &pDevEnum);
+ checkForDShowError(hr, "DSCamera::findCaptureDevice()::CreateDevEnum");
+
+ // Create an enumerator for the video capture devices
+ hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum,
+ 0);
+ checkForDShowError(hr, "DSCamera::findCaptureDevice()::CreateClassEnumerator");
+
+ // If there are no enumerators for the requested type, then
+ // CreateClassEnumerator will succeed, but pClassEnum will be NULL.
+ if (pClassEnum == NULL) {
+ *ppSrcFilter = 0;
+ throw(Exception(AVG_ERR_CAMERA_NONFATAL, "No DirectShow Capture Device found"));
+ }
+
+ bool bFound = false;
+ while (!bFound && pClassEnum->Next(1, &pMoniker, NULL) == S_OK) {
+ IPropertyBag *pPropBag;
+ hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag));
+ checkForDShowError(hr, "DSCamera::findCaptureDevice()::BindToStorage");
+
+ string sDescription = getStringProp(pPropBag, L"Description");
+ string sFriendlyName = getStringProp(pPropBag, L"FriendlyName");
+ string sDevicePath = getStringProp(pPropBag, L"DevicePath");
+
+ if (m_sDevice == sDescription || m_sDevice == sFriendlyName ||
+ sDevicePath.find(m_sDevice) != -1 || m_sDevice == "")
+ {
+ bFound = true;
+ } else {
+ pMoniker->Release();
+ }
+ pPropBag->Release();
+ }
+ if (!bFound) {
+ pClassEnum->Reset();
+ if (pClassEnum->Next(1, &pMoniker, NULL) == S_OK) {
+ AVG_LOG_WARNING(string("Camera ") + m_sDevice
+ + " not found. Using first camera.");
+ bFound = true;
+ IPropertyBag *pPropBag;
+ hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag));
+ m_sDevice = getStringProp(pPropBag, L"FriendlyName");
+ checkForDShowError(hr, "DSCamera::findCaptureDevice()::BindToStorage");
+ pPropBag->Release();
+ } else {
+ throw(Exception(AVG_ERR_CAMERA_NONFATAL,
+ "No DirectShow Capture Device found"));
+ }
+ }
+
+ // Bind Moniker to a filter object
+ hr = pMoniker->BindToObject(0,0,IID_IBaseFilter, (void**)&pSrc);
+ checkForDShowError(hr, "DSCamera::findCaptureDevice()::BindToObject");
+
+ // Copy the found filter pointer to the output parameter.
+ *ppSrcFilter = pSrc;
+ (*ppSrcFilter)->AddRef();
+
+ pSrc->Release();
+ pMoniker->Release();
+ pDevEnum->Release();
+ pClassEnum->Release();
+}
+
+
+void DSCamera::connectFilters(IGraphBuilder *pGraph, IBaseFilter *pSrc,
+ IBaseFilter *pDest)
+{
+ IPin *pOut = 0;
+ getUnconnectedPin(pSrc, PINDIR_OUTPUT, &pOut);
+
+ IPin *pIn = 0;
+ getUnconnectedPin(pDest, PINDIR_INPUT, &pIn);
+
+ HRESULT hr = pGraph->ConnectDirect(pOut, pIn, 0);
+ checkForDShowError(hr, "DSCamera::ConnectFilters::Connect");
+ pOut->Release();
+ pIn->Release();
+}
+
+void DSCamera::getUnconnectedPin(IBaseFilter *pFilter, PIN_DIRECTION pinDir, IPin **ppPin)
+{
+ *ppPin = 0;
+ IEnumPins *pEnum = 0;
+ IPin *pPin = 0;
+ HRESULT hr = pFilter->EnumPins(&pEnum);
+ checkForDShowError(hr, "DSCamera::ConnectFilters::Connect");
+ while (pEnum->Next(1, &pPin, NULL) == S_OK)
+ {
+ PIN_DIRECTION thisPinDir;
+ pPin->QueryDirection(&thisPinDir);
+ if (thisPinDir == pinDir) {
+ IPin* pTmp = 0;
+ hr = pPin->ConnectedTo(&pTmp);
+ if (SUCCEEDED(hr)) { // Already connected, not the pin we want.
+ pTmp->Release();
+ } else { // Unconnected, this is the pin we want.
+ pEnum->Release();
+ *ppPin = pPin;
+ return;
+ }
+ }
+ pPin->Release();
+ }
+ pEnum->Release();
+ // Did not find a matching pin.
+ AVG_ASSERT(false);
+}
+
+#pragma warning(disable : 4995)
+void DSCamera::checkForDShowError(HRESULT hr, const string& sLocation)
+{
+ if (SUCCEEDED(hr)) {
+ return;
+ }
+ if (HRESULT_FACILITY(hr) == FACILITY_WINDOWS) {
+ hr = HRESULT_CODE(hr);
+ }
+ char szErr[MAX_ERROR_TEXT_LEN];
+ DWORD res = AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
+ if (res == 0) {
+ wsprintf(szErr, "Unknown Error: 0x%2x", hr);
+ }
+ cerr << sLocation << ": " << szErr << endl;
+}
+
+
+}