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;
}