int videoInput::start()

in modules/videoio/src/cap_dshow.cpp [2478:2797]


int videoInput::start(int deviceID, videoDevice *VD){

    HRESULT hr             = NOERROR;
    VD->myID             = deviceID;
    VD->setupStarted    = true;
    CAPTURE_MODE           = PIN_CATEGORY_CAPTURE; //Don't worry - it ends up being preview (which is faster)
    callbackSetCount     = 1;  //make sure callback method is not changed after setup called

    DebugPrintOut("SETUP: Setting up device %i\n",deviceID);

    // CREATE THE GRAPH BUILDER //
    // Create the filter graph manager and query for interfaces.
    hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void **)&VD->pCaptureGraph);
    if (FAILED(hr))    // FAILED is a macro that tests the return value
    {
        DebugPrintOut("ERROR - Could not create the Filter Graph Manager\n");
        return hr;
    }

    //FITLER GRAPH MANAGER//
    // Create the Filter Graph Manager.
    hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void**)&VD->pGraph);
    if (FAILED(hr))
    {
        DebugPrintOut("ERROR - Could not add the graph builder!\n");
        stopDevice(deviceID);
        return hr;
    }

    //SET THE FILTERGRAPH//
    hr = VD->pCaptureGraph->SetFiltergraph(VD->pGraph);
    if (FAILED(hr))
    {
        DebugPrintOut("ERROR - Could not set filtergraph\n");
        stopDevice(deviceID);
        return hr;
    }

    //MEDIA CONTROL (START/STOPS STREAM)//
    // Using QueryInterface on the graph builder,
    // Get the Media Control object.
    hr = VD->pGraph->QueryInterface(IID_IMediaControl, (void **)&VD->pControl);
    if (FAILED(hr))
    {
        DebugPrintOut("ERROR - Could not create the Media Control object\n");
        stopDevice(deviceID);
        return hr;
    }


    //FIND VIDEO DEVICE AND ADD TO GRAPH//
    //gets the device specified by the second argument.
    hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName);

    if (SUCCEEDED(hr)){
        DebugPrintOut("SETUP: %s\n", VD->nDeviceName);
        hr = VD->pGraph->AddFilter(VD->pVideoInputFilter, VD->wDeviceName);
    }else{
        DebugPrintOut("ERROR - Could not find specified video device\n");
        stopDevice(deviceID);
        return hr;
    }

    //LOOK FOR PREVIEW PIN IF THERE IS NONE THEN WE USE CAPTURE PIN AND THEN SMART TEE TO PREVIEW
    IAMStreamConfig *streamConfTest = NULL;
    hr = VD->pCaptureGraph->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, VD->pVideoInputFilter, IID_IAMStreamConfig, (void **)&streamConfTest);
    if(FAILED(hr)){
        DebugPrintOut("SETUP: Couldn't find preview pin using SmartTee\n");
    }else{
         CAPTURE_MODE = PIN_CATEGORY_PREVIEW;
         streamConfTest->Release();
         streamConfTest = NULL;
    }

    //CROSSBAR (SELECT PHYSICAL INPUT TYPE)//
    //my own function that checks to see if the device can support a crossbar and if so it routes it.
    //webcams tend not to have a crossbar so this function will also detect a webcams and not apply the crossbar
    if(VD->useCrossbar)
    {
        DebugPrintOut("SETUP: Checking crossbar\n");
        routeCrossbar(&VD->pCaptureGraph, &VD->pVideoInputFilter, VD->connection, CAPTURE_MODE);
    }


    //we do this because webcams don't have a preview mode
    hr = VD->pCaptureGraph->FindInterface(&CAPTURE_MODE, &MEDIATYPE_Video, VD->pVideoInputFilter, IID_IAMStreamConfig, (void **)&VD->streamConf);
    if(FAILED(hr)){
        DebugPrintOut("ERROR: Couldn't config the stream!\n");
        stopDevice(deviceID);
        return hr;
    }

    //NOW LETS DEAL WITH GETTING THE RIGHT SIZE
    hr = VD->streamConf->GetFormat(&VD->pAmMediaType);
    if(FAILED(hr)){
        DebugPrintOut("ERROR: Couldn't getFormat for pAmMediaType!\n");
        stopDevice(deviceID);
        return hr;
    }

    VIDEOINFOHEADER *pVih =  reinterpret_cast<VIDEOINFOHEADER*>(VD->pAmMediaType->pbFormat);
    int currentWidth    =  HEADER(pVih)->biWidth;
    int currentHeight    =  HEADER(pVih)->biHeight;

    bool customSize = VD->tryDiffSize;

    bool foundSize  = false;

    if(customSize){
        DebugPrintOut("SETUP: Default Format is set to %ix%i\n", currentWidth, currentHeight);

        char guidStr[8];
            // try specified format and size
            getMediaSubtypeAsString(VD->tryVideoType, guidStr);
            DebugPrintOut("SETUP: trying specified format %s @ %ix%i\n", guidStr, VD->tryWidth, VD->tryHeight);

            if( setSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, VD->tryVideoType) ){
                VD->setSize(VD->tryWidth, VD->tryHeight);
                VD->videoType = VD->tryVideoType;
                foundSize = true;
            } else {
                // try specified size with all formats
                for(int i = 0; i < VI_NUM_TYPES; i++){

                    getMediaSubtypeAsString(mediaSubtypes[i], guidStr);

                    DebugPrintOut("SETUP: trying format %s @ %ix%i\n", guidStr, VD->tryWidth, VD->tryHeight);
                    if( setSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, mediaSubtypes[i]) ){
                        VD->setSize(VD->tryWidth, VD->tryHeight);
                        VD->videoType = mediaSubtypes[i];
                        foundSize = true;
                        break;
                    }
                }
            }


        //if we didn't find the requested size - lets try and find the closest matching size
        if( foundSize == false ){
            DebugPrintOut("SETUP: couldn't find requested size - searching for closest matching size\n");

            int closestWidth        = -1;
            int closestHeight        = -1;
            GUID newMediaSubtype;

            findClosestSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, closestWidth, closestHeight, newMediaSubtype);

            if( closestWidth != -1 && closestHeight != -1){
                getMediaSubtypeAsString(newMediaSubtype, guidStr);

                DebugPrintOut("SETUP: closest supported size is %s @ %i %i\n", guidStr, closestWidth, closestHeight);
                if( setSizeAndSubtype(VD, closestWidth, closestHeight, newMediaSubtype) ){
                    VD->setSize(closestWidth, closestHeight);
                    foundSize = true;
                }
            }
        }
    }

    //if we didn't specify a custom size or if we did but couldn't find it lets setup with the default settings
    if(customSize == false || foundSize == false){
        if( VD->requestedFrameTime != -1 ){
            pVih->AvgTimePerFrame  = VD->requestedFrameTime;
            hr = VD->streamConf->SetFormat(VD->pAmMediaType);
        }
        VD->setSize(currentWidth, currentHeight);
    }

    //SAMPLE GRABBER (ALLOWS US TO GRAB THE BUFFER)//
    // Create the Sample Grabber.
    hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,IID_IBaseFilter, (void**)&VD->pGrabberF);
    if (FAILED(hr)){
        DebugPrintOut("Could not Create Sample Grabber - CoCreateInstance()\n");
        stopDevice(deviceID);
        return hr;
    }

    hr = VD->pGraph->AddFilter(VD->pGrabberF, L"Sample Grabber");
    if (FAILED(hr)){
        DebugPrintOut("Could not add Sample Grabber - AddFilter()\n");
        stopDevice(deviceID);
        return hr;
    }

    hr = VD->pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&VD->pGrabber);
    if (FAILED(hr)){
        DebugPrintOut("ERROR: Could not query SampleGrabber\n");
        stopDevice(deviceID);
        return hr;
    }


    //Set Params - One Shot should be false unless you want to capture just one buffer
    hr = VD->pGrabber->SetOneShot(FALSE);
    if(bCallback){
        hr = VD->pGrabber->SetBufferSamples(FALSE);
    }else{
        hr = VD->pGrabber->SetBufferSamples(TRUE);
    }

    if(bCallback){
        //Tell the grabber to use our callback function - 0 is for SampleCB and 1 for BufferCB
        //We use SampleCB
        hr = VD->pGrabber->SetCallback(VD->sgCallback, 0);
        if (FAILED(hr)){
            DebugPrintOut("ERROR: problem setting callback\n");
            stopDevice(deviceID);
            return hr;
        }else{
            DebugPrintOut("SETUP: Capture callback set\n");
        }
    }

    //MEDIA CONVERSION
    //Get video properties from the stream's mediatype and apply to the grabber (otherwise we don't get an RGB image)
    //zero the media type - lets try this :) - maybe this works?
    AM_MEDIA_TYPE mt;
    ZeroMemory(&mt,sizeof(AM_MEDIA_TYPE));

    mt.majortype     = MEDIATYPE_Video;
    mt.subtype         = MEDIASUBTYPE_RGB24;
    mt.formattype     = FORMAT_VideoInfo;

    //VD->pAmMediaType->subtype = VD->videoType;
    hr = VD->pGrabber->SetMediaType(&mt);

    //lets try freeing our stream conf here too
    //this will fail if the device is already running
    if(VD->streamConf){
        VD->streamConf->Release();
        VD->streamConf = NULL;
    }else{
        DebugPrintOut("ERROR: connecting device - prehaps it is already being used?\n");
        stopDevice(deviceID);
        return S_FALSE;
    }


    //NULL RENDERER//
    //used to give the video stream somewhere to go to.
    hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)(&VD->pDestFilter));
    if (FAILED(hr)){
        DebugPrintOut("ERROR: Could not create filter - NullRenderer\n");
        stopDevice(deviceID);
        return hr;
    }

    hr = VD->pGraph->AddFilter(VD->pDestFilter, L"NullRenderer");
    if (FAILED(hr)){
        DebugPrintOut("ERROR: Could not add filter - NullRenderer\n");
        stopDevice(deviceID);
        return hr;
    }

    //RENDER STREAM//
    //This is where the stream gets put together.
    hr = VD->pCaptureGraph->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, VD->pVideoInputFilter, VD->pGrabberF, VD->pDestFilter);

    if (FAILED(hr)){
        DebugPrintOut("ERROR: Could not connect pins - RenderStream()\n");
        stopDevice(deviceID);
        return hr;
    }


    //EXP - lets try setting the sync source to null - and make it run as fast as possible
    {
        IMediaFilter *pMediaFilter = 0;
        hr = VD->pGraph->QueryInterface(IID_IMediaFilter, (void**)&pMediaFilter);
        if (FAILED(hr)){
            DebugPrintOut("ERROR: Could not get IID_IMediaFilter interface\n");
        }else{
            pMediaFilter->SetSyncSource(NULL);
            pMediaFilter->Release();
        }
    }


    //LETS RUN THE STREAM!
    hr = VD->pControl->Run();

    if (FAILED(hr)){
         DebugPrintOut("ERROR: Could not start graph\n");
         stopDevice(deviceID);
         return hr;
    }


    //MAKE SURE THE DEVICE IS SENDING VIDEO BEFORE WE FINISH
    if(!bCallback){

        long bufferSize = VD->videoSize;

        while( hr != S_OK){
            hr = VD->pGrabber->GetCurrentBuffer(&bufferSize, (long *)VD->pBuffer);
            Sleep(10);
        }

    }

    DebugPrintOut("SETUP: Device is setup and ready to capture.\n\n");
    VD->readyToCapture = true;

    //Release filters - seen someone else do this
    //looks like it solved the freezes

    //if we release this then we don't have access to the settings
    //we release our video input filter but then reconnect with it
    //each time we need to use it
    VD->pVideoInputFilter->Release();
    VD->pVideoInputFilter = NULL;

    VD->pGrabberF->Release();
    VD->pGrabberF = NULL;

    VD->pDestFilter->Release();
    VD->pDestFilter = NULL;

    return S_OK;
}