bool directx_videofile_server::open_and_find_parameters(const char *filename) { //------------------------------------------------------------------- // Create COM and DirectX objects needed to access a video stream. // Initialize COM. This must have a matching uninitialize in // the destructor. #ifdef DEBUG fprintf(stderr, "directx_videofile_server::open_and_find_parameters(): Before CoInitialize\n"); #endif CoInitialize(NULL); // Create the filter graph manager #ifdef DEBUG fprintf(stderr, "directx_videofile_server::open_and_find_parameters(): Before manager CoCreateInstance\n"); #endif CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&_pGraph); if (_pGraph == NULL) { fprintf(stderr, "directx_videofile_server::open_and_find_parameters(): Can't create graph manager\n"); return false; } _pGraph->QueryInterface(IID_IMediaControl, (void **)&_pMediaControl); _pGraph->QueryInterface(IID_IMediaEvent, (void **)&_pEvent); // Create the Capture Graph Builder. #ifdef DEBUG fprintf(stderr, "directx_videofile_server::open_and_find_parameters(): Before builder CoCreateInstance\n"); #endif if (CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void **)&_pBuilder) != S_OK) { _pBuilder = NULL; fprintf(stderr, "directx_videofile_server::open_and_find_parameters(): Can't create graph builder\n"); return false; } // Associate the graph with the builder. _pBuilder->SetFiltergraph(_pGraph); //------------------------------------------------------------------- // Construct the sample grabber callback handler that will be used // to receive image data from the sample grabber. if ( (_pCallback = new directx_samplegrabber_callback()) == NULL) { fprintf(stderr,"directx_videofile_server::open_and_find_parameters(): Can't create sample grabber callback handler (out of memory?)\n"); return false; } //------------------------------------------------------------------- // Construct the sample grabber that will be used to snatch images from // the video stream as they go by. // Create the Sample Grabber. #ifdef DEBUG fprintf(stderr, "directx_videofile_server::open_and_find_parameters(): Before grabber CoCreateInstance\n"); #endif CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, reinterpret_cast<void**>(&_pSampleGrabberFilter)); _pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, reinterpret_cast<void**>(&_pGrabber)); // Set the media type to video and 8-bit RGB. AM_MEDIA_TYPE mt; ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE)); mt.majortype = MEDIATYPE_Video; // Ask for video media producers mt.subtype = MEDIASUBTYPE_RGB24; // Ask for 8 bit RGB _pGrabber->SetMediaType(&mt); // Set the callback, where '0' means 'use the SampleCB callback' _pGrabber->SetCallback(_pCallback, 0); //------------------------------------------------------------------- // Create a NULL renderer that will be used to discard the video frames // on the output pin of the sample grabber IBaseFilter *pNull = NULL; #ifdef DEBUG fprintf(stderr, "directx_videofile_server::open_and_find_parameters(): Before NULL render CoCreateInstance\n"); #endif CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, reinterpret_cast<void**>(&pNull)); //------------------------------------------------------------------- // Build the filter graph. First add the filters and then connect them. #ifdef DEBUG fprintf(stderr, "directx_videofile_server::open_and_find_parameters(): Building filter graph..."); #endif // pSrc is a the file-reading filter. IBaseFilter *pSrc; wchar_t longfilename[2048]; mbstowcs(longfilename, filename, 2047); longfilename[2047] = L'\0'; if (FAILED(_pGraph->AddSourceFilter(longfilename, L"Source", &pSrc))) { fprintf(stderr,"directx_videofile_server::open_and_find_parameters(): Can't create reader for %s\n", filename); return false; } #ifdef DEBUG fprintf(stderr, "(source)..."); #endif // Add the sample grabber filter if (FAILED(_pGraph->AddFilter(_pSampleGrabberFilter, L"SampleGrabber"))) { fprintf(stderr,"directx_videofile_server::open_and_find_parameters(): Can't create grabber filter\n"); return false; } #ifdef DEBUG fprintf(stderr, "(grabber)..."); #endif // Add the null renderer filter if (FAILED(_pGraph->AddFilter(pNull, L"NullRenderer"))) { fprintf(stderr,"directx_videofile_server::open_and_find_parameters(): Can't create Null Renderer\n"); return false; } #ifdef DEBUG fprintf(stderr, "(renderer)..."); #endif // Connect the output of the video reader to the sample grabber input fprintf(stderr, "XXX DirectShow reading of video files fails on Windows 7\n"); return false; // XXX The call below hangs on Windows 7 on Russ Taylor's laptop. ConnectTwoFilters(_pGraph, pSrc, _pSampleGrabberFilter); #ifdef DEBUG fprintf(stderr, "(connected reader)..."); #endif // Connect the output of the sample grabber to the NULL renderer input #ifdef DEBUG fprintf(stderr, "(connected grabber)..."); #endif ConnectTwoFilters(_pGraph, _pSampleGrabberFilter, pNull); #ifdef DEBUG fprintf(stderr, "\n"); #endif //------------------------------------------------------------------- // We don't need a reference clock for playout because we're going // to limit playback rate by controlling how fast we pass frames through // the callback handler. We can't set a playout rate anyway, because // the NULL renderer won't do this for us. Recall that the frames come // out of the file reader as fast as it can process them, and only // block up if the downstream buffers all fill up. pNull->SetSyncSource(NULL); // Turn off the reference clock. //------------------------------------------------------------------- // Find the control that lets you seek in the media (rewind uses this // to restart at the beginning of the file). #ifdef DEBUG fprintf(stderr, "directx_videofile_server::open_and_find_parameters(): Locating seek controls\n"); #endif if (FAILED(_pGraph->QueryInterface(IID_IMediaSeeking, (void **)&_pMediaSeeking))) { fprintf(stderr,"directx_videofile_server::open_and_find_parameters(): Can't create media seeker\n"); pSrc->Release(); pNull->Release(); return false; } //------------------------------------------------------------------- // Find _num_rows and _num_columns, which is the maximum size. #ifdef DEBUG fprintf(stderr, "directx_videofile_server::open_and_find_parameters(): Determining image size\n"); #endif _pGrabber->GetConnectedMediaType(&mt); VIDEOINFOHEADER *pVih; if (mt.formattype == FORMAT_VideoInfo) { pVih = reinterpret_cast<VIDEOINFOHEADER*>(mt.pbFormat); } else if (mt.formattype == FORMAT_VideoInfo2) { pVih = reinterpret_cast<VIDEOINFOHEADER*>(mt.pbFormat); } else { fprintf(stderr,"directx_videofile_server::open_and_find_parameters(): Can't get video header type\n"); fprintf(stderr," (Expected %x or %x, got %x)\n", FORMAT_VideoInfo, FORMAT_VideoInfo2, mt.formattype); fprintf(stderr," (GetConnectedMediaType is not valid for DirectX headers later than version 7)\n"); fprintf(stderr," (We need to re-implement reading video in some other interface)\n"); return false; } // Number of rows and columns. This is different if we are using a target // rectangle (rcTarget) than if we are not. if (IsRectEmpty(&pVih->rcTarget)) { _num_columns = pVih->bmiHeader.biWidth; _num_rows = pVih->bmiHeader.biHeight; } else { _num_columns = pVih->rcTarget.right; _num_rows = pVih->bmiHeader.biHeight; printf("XXX directx_videofile_server::open_and_find_parameters(): Warning: may not work correctly with target rectangle\n"); } printf("Got %dx%d video\n", _num_columns, _num_rows); // Make sure that the image is not compressed and that we have 8 bits // per pixel. #ifdef DEBUG fprintf(stderr, "directx_videofile_server::open_and_find_parameters(): Checking compression\n"); #endif if (pVih->bmiHeader.biCompression != BI_RGB) { fprintf(stderr,"directx_videofile_server::open_and_find_parameters(): Compression not RGB\n"); switch (pVih->bmiHeader.biCompression) { case BI_RLE8: fprintf(stderr," (It is BI_RLE8)\n"); break; case BI_RLE4: fprintf(stderr," (It is BI_RLE4)\n"); case BI_BITFIELDS: fprintf(stderr," (It is BI_BITFIELDS)\n"); break; default: fprintf(stderr," (Unknown compression type)\n"); } return false; } int BytesPerPixel = pVih->bmiHeader.biBitCount / 8; if (BytesPerPixel != 3) { fprintf(stderr,"directx_videofile_server::open_and_find_parameters(): Not 3 bytes per (%d)\n", pVih->bmiHeader.biBitCount); return false; } // A negative height indicates that the images are stored non-inverted in Y // Not sure what to do with images that have negative height -- need to // read the book some more to find out. if (_num_rows < 0) { fprintf(stderr,"directx_videofile_server::open_and_find_parameters(): Num Rows is negative (internal error)\n"); return false; } // Find the stride to take when moving from one row of video to the // next. This is rounded up to the nearest DWORD. _stride = (_num_columns * BytesPerPixel + 3) & ~3; //------------------------------------------------------------------- // Release resources that won't be used later and return #ifdef DEBUG fprintf(stderr, "directx_videofile_server::open_and_find_parameters(): Releasing resources\n"); #endif pSrc->Release(); pNull->Release(); return true; }
bool directx_camera_server::open_moniker_and_finish_setup( comutils::Ptr<IMoniker> pMoniker, FilterOperation const &sourceConfig, unsigned width, unsigned height) { if (!pMoniker) { fprintf(stderr, "directx_camera_server::open_moniker_and_finish_setup(): " "Null device moniker passed: no device found?\n"); return false; } auto prop = PropertyBagHelper{*pMoniker}; printf("directx_camera_server: Using capture device '%s' at path '%s'\n", getDeviceHumanDesc(prop).c_str(), getDevicePath(prop).c_str()); // Bind the chosen moniker to a filter object. auto pSrc = comutils::Ptr<IBaseFilter>{}; pMoniker->BindToObject(nullptr, nullptr, IID_IBaseFilter, AttachPtr(pSrc)); //------------------------------------------------------------------- // Construct the sample grabber that will be used to snatch images from // the video stream as they go by. Set its media type and callback. // Create and configure the Sample Grabber. _pSampleGrabberWrapper.reset(new SampleGrabberWrapper); // Get the exchange object for receiving data from the sample grabber. sampleExchange_ = _pSampleGrabberWrapper->getExchange(); //------------------------------------------------------------------- // Ask for the video resolution that has been passed in. // This code is based on // intuiting that we need to use the SetFormat call on the IAMStreamConfig // interface; this interface is described in the help pages. // If the width and height are specified as 0, then they are not set // in the header, letting them use whatever is the default. /// @todo factor this out into its own header. if ((width != 0) && (height != 0)) { auto pStreamConfig = comutils::Ptr<IAMStreamConfig>{}; _pBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pSrc.get(), IID_IAMStreamConfig, AttachPtr(pStreamConfig)); checkForConstructionError(pStreamConfig, "StreamConfig interface"); AM_MEDIA_TYPE mt = {0}; mt.majortype = MEDIATYPE_Video; // Ask for video media producers mt.subtype = MEDIASUBTYPE_RGB24; // Ask for 8 bit RGB VIDEOINFOHEADER vih = {0}; mt.pbFormat = reinterpret_cast<BYTE *>(&vih); auto pVideoHeader = &vih; pVideoHeader->bmiHeader.biBitCount = 24; pVideoHeader->bmiHeader.biWidth = width; pVideoHeader->bmiHeader.biHeight = height; pVideoHeader->bmiHeader.biPlanes = 1; pVideoHeader->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pVideoHeader->bmiHeader.biSizeImage = dibsize(pVideoHeader->bmiHeader); // Set the format type and size. mt.formattype = FORMAT_VideoInfo; mt.cbFormat = sizeof(VIDEOINFOHEADER); // Set the sample size. mt.bFixedSizeSamples = TRUE; mt.lSampleSize = dibsize(pVideoHeader->bmiHeader); // Make the call to actually set the video type to what we want. if (pStreamConfig->SetFormat(&mt) != S_OK) { fprintf(stderr, "directx_camera_server::open_and_find_parameters():" " Can't set resolution to %dx%d using uncompressed " "24-bit video\n", pVideoHeader->bmiHeader.biWidth, pVideoHeader->bmiHeader.biHeight); return false; } } //------------------------------------------------------------------- // Create a null renderer that will be used to discard the video frames // on the output pin of the sample grabber #ifdef DEBUG printf("directx_camera_server::open_and_find_parameters(): Before " "createNullRenderFilter\n"); #endif auto pNullRender = createNullRenderFilter(); auto sampleGrabberFilter = _pSampleGrabberWrapper->getFilter(); //------------------------------------------------------------------- // Build the filter graph. First add the filters and then connect them. // pSrc is the capture filter for the video device we found above. auto hr = _pGraph->AddFilter(pSrc.get(), L"Video Capture"); BOOST_ASSERT_MSG(SUCCEEDED(hr), "Adding Video Capture filter to graph"); // Add the sample grabber filter hr = _pGraph->AddFilter(sampleGrabberFilter.get(), L"SampleGrabber"); BOOST_ASSERT_MSG(SUCCEEDED(hr), "Adding SampleGrabber filter to graph"); // Add the null renderer filter hr = _pGraph->AddFilter(pNullRender.get(), L"NullRenderer"); BOOST_ASSERT_MSG(SUCCEEDED(hr), "Adding NullRenderer filter to graph"); // Connect the output of the video reader to the sample grabber input ConnectTwoFilters(*_pGraph, *pSrc, *sampleGrabberFilter); // Connect the output of the sample grabber to the null renderer input ConnectTwoFilters(*_pGraph, *sampleGrabberFilter, *pNullRender); // If we were given a config action for the source, do it now. if (sourceConfig) { sourceConfig(*pSrc); } //------------------------------------------------------------------- // XXX See if this is a video tuner card by querying for that interface. // Set it to read the video channel if it is one. auto pTuner = comutils::Ptr<IAMTVTuner>{}; hr = _pBuilder->FindInterface(nullptr, nullptr, pSrc.get(), IID_IAMTVTuner, AttachPtr(pTuner)); if (pTuner) { #ifdef DEBUG printf("directx_camera_server::open_and_find_parameters(): Found a TV " "Tuner!\n"); #endif // XXX Put code here. // Set the first input pin to use the cable as input hr = pTuner->put_InputType(0, TunerInputCable); if (FAILED(hr)) { fprintf(stderr, "directx_camera_server::open_and_find_parameters():" " Can't set input to cable\n"); } // Set the channel on the video to be baseband (is this channel zero?) hr = pTuner->put_Channel(0, -1, -1); if (FAILED(hr)) { fprintf(stderr, "directx_camera_server::open_and_find_parameters():" " Can't set channel\n"); } } //------------------------------------------------------------------- // Find _num_rows and _num_columns in the video stream. AM_MEDIA_TYPE mt = {0}; _pSampleGrabberWrapper->getConnectedMediaType(mt); VIDEOINFOHEADER *pVih; if (mt.formattype == FORMAT_VideoInfo || mt.formattype == FORMAT_VideoInfo2) { pVih = reinterpret_cast<VIDEOINFOHEADER *>(mt.pbFormat); } else { fprintf(stderr, "directx_camera_server::open_and_find_parameters(): " "Can't get video header type\n"); fprintf(stderr, " (Expected %x or %x, got %x)\n", FORMAT_VideoInfo, FORMAT_VideoInfo2, mt.formattype); fprintf(stderr, " (GetConnectedMediaType is not valid for DirectX " "headers later than version 7)\n"); fprintf(stderr, " (We need to re-implement reading video in some " "other interface)\n"); return false; } // Number of rows and columns. This is different if we are using a target // rectangle (rcTarget) than if we are not. if (IsRectEmpty(&pVih->rcTarget)) { _num_columns = pVih->bmiHeader.biWidth; _num_rows = pVih->bmiHeader.biHeight; } else { _num_columns = pVih->rcTarget.right; _num_rows = pVih->bmiHeader.biHeight; printf("XXX directx_camera_server::open_and_find_parameters(): " "Warning: may not work correctly with target rectangle\n"); } #ifdef DEBUG printf("Got %dx%d video\n", _num_columns, _num_rows); #endif // Make sure that the image is not compressed and that we have 8 bits // per pixel. if (pVih->bmiHeader.biCompression != BI_RGB) { fprintf(stderr, "directx_camera_server::open_and_find_parameters(): " "Compression not RGB\n"); switch (pVih->bmiHeader.biCompression) { case BI_RLE8: fprintf(stderr, " (It is BI_RLE8)\n"); break; case BI_RLE4: fprintf(stderr, " (It is BI_RLE4)\n"); case BI_BITFIELDS: fprintf(stderr, " (It is BI_BITFIELDS)\n"); break; default: fprintf(stderr, " (Unknown compression type)\n"); } return false; } int BytesPerPixel = pVih->bmiHeader.biBitCount / 8; if (BytesPerPixel != 3) { fprintf(stderr, "directx_camera_server::open_and_find_parameters(): " "Not 3 bytes per pixel (%d)\n", pVih->bmiHeader.biBitCount); return false; } // A negative height indicates that the images are stored non-inverted in Y // Not sure what to do with images that have negative height -- need to // read the book some more to find out. if (_num_rows < 0) { fprintf(stderr, "directx_camera_server::open_and_find_parameters(): " "Num Rows is negative (internal error)\n"); return false; } // Find the stride to take when moving from one row of video to the // next. This is rounded up to the nearest DWORD. _stride = (_num_columns * BytesPerPixel + 3) & ~3; return true; }
bool directx_camera_server::open_and_find_parameters(const int which, unsigned width, unsigned height) { HRESULT hr; //------------------------------------------------------------------- // Create COM and DirectX objects needed to access a video stream. // Initialize COM. This must have a matching uninitialize somewhere before // the object is destroyed. #ifdef DEBUG printf("directx_camera_server::open_and_find_parameters(): Before CoInitialize\n"); #endif CoInitialize(NULL); // Create the filter graph manager #ifdef DEBUG printf("directx_camera_server::open_and_find_parameters(): Before CoCreateInstance FilterGraph\n"); #endif CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&_pGraph); if (_pGraph == NULL) { fprintf(stderr, "directx_camera_server::open_and_find_parameters(): Can't create graph manager\n"); return false; } _pGraph->QueryInterface(IID_IMediaControl, (void **)&_pMediaControl); _pGraph->QueryInterface(IID_IMediaEvent, (void **)&_pEvent); // Create the Capture Graph Builder. #ifdef DEBUG printf("directx_camera_server::open_and_find_parameters(): Before CoCreateInstance CaptureGraphBuilder2\n"); #endif CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void **)&_pBuilder); if (_pBuilder == NULL) { fprintf(stderr, "directx_camera_server::open_and_find_parameters(): Can't create graph builder\n"); return false; } // Associate the graph with the builder. #ifdef DEBUG printf("directx_camera_server::open_and_find_parameters(): Before SetFilterGraph\n"); #endif _pBuilder->SetFiltergraph(_pGraph); //------------------------------------------------------------------- // Go find a video device to use: in this case, we are using the Nth // one we find, where the number N is the "which" parameter. // Create the system device enumerator. #ifdef DEBUG printf("directx_camera_server::open_and_find_parameters(): Before CoCreateInstance SystemDeviceEnum\n"); #endif ICreateDevEnum *pDevEnum = NULL; CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void **)&pDevEnum); if (pDevEnum == NULL) { fprintf(stderr, "directx_camera_server::open_and_find_parameters(): Can't create device enumerator\n"); return false; } // Create an enumerator for video capture devices. #ifdef DEBUG printf("directx_camera_server::open_and_find_parameters(): Before CreateClassEnumerator\n"); #endif IEnumMoniker *pClassEnum = NULL; pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0); if (pClassEnum == NULL) { fprintf(stderr, "directx_camera_server::open_and_find_parameters(): Can't create video enumerator (no cameras?)\n"); pDevEnum->Release(); return false; } #ifdef DEBUG printf("directx_camera_server::open_and_find_parameters(): Before Loop over enumerators\n"); #endif ULONG cFetched; IMoniker *pMoniker = NULL; IBaseFilter *pSrc = NULL; // Skip (which - 1) cameras int i; for (i = 0; i < which-1 ; i++) { if (pClassEnum->Next(1, &pMoniker, &cFetched) != S_OK) { fprintf(stderr,"directx_camera_server::open_and_find_parameters(): Can't open camera (not enough cameras)\n"); pMoniker->Release(); return false; } } // Take the next camera and bind it if (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK) { // Bind the first moniker to a filter object. pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pSrc); pMoniker->Release(); } else { fprintf(stderr,"directx_camera_server::open_and_find_parameters(): Can't open camera (not enough cameras)\n"); pMoniker->Release(); return false; } pClassEnum->Release(); pDevEnum->Release(); //------------------------------------------------------------------- // Construct the sample grabber callback handler that will be used // to receive image data from the sample grabber. if ( (_pCallback = new directx_samplegrabber_callback()) == NULL) { fprintf(stderr,"directx_camera_server::open_and_find_parameters(): Can't create sample grabber callback handler (out of memory?)\n"); return false; } //------------------------------------------------------------------- // Construct the sample grabber that will be used to snatch images from // the video stream as they go by. Set its media type and callback. // Create the Sample Grabber. #ifdef DEBUG printf("directx_camera_server::open_and_find_parameters(): Before CoCreateInstance SampleGrabber\n"); #endif CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, reinterpret_cast<void**>(&_pSampleGrabberFilter)); if (_pSampleGrabberFilter == NULL) { fprintf(stderr,"directx_camera_server::open_and_find_parameters(): Can't get SampleGrabber filter (not DirectX 8.1+?)\n"); return false; } #ifdef DEBUG printf("directx_camera_server::open_and_find_parameters(): Before QueryInterface\n"); #endif _pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, reinterpret_cast<void**>(&_pGrabber)); // Set the media type to video #ifdef DEBUG printf("directx_camera_server::open_and_find_parameters(): Before SetMediaType\n"); #endif AM_MEDIA_TYPE mt; // Ask for video media producers that produce 8-bit RGB ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE)); mt.majortype = MEDIATYPE_Video; // Ask for video media producers mt.subtype = MEDIASUBTYPE_RGB24; // Ask for 8 bit RGB _pGrabber->SetMediaType(&mt); //------------------------------------------------------------------- // Ask for the video resolution that has been passed in. // This code is based on // intuiting that we need to use the SetFormat call on the IAMStreamConfig // interface; this interface is described in the help pages. // If the width and height are specified as 0, then they are not set // in the header, letting them use whatever is the default. if ( (width != 0) && (height != 0) ) { _pBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pSrc, IID_IAMStreamConfig, (void **)&_pStreamConfig); if (_pStreamConfig == NULL) { fprintf(stderr,"directx_camera_server::open_and_find_parameters(): Can't get StreamConfig interface\n"); return false; } ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE)); mt.majortype = MEDIATYPE_Video; // Ask for video media producers mt.subtype = MEDIASUBTYPE_RGB24; // Ask for 8 bit RGB mt.pbFormat = (BYTE*)CoTaskMemAlloc(sizeof(VIDEOINFOHEADER)); VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)mt.pbFormat; ZeroMemory(pVideoHeader, sizeof(VIDEOINFOHEADER)); pVideoHeader->bmiHeader.biBitCount = 24; pVideoHeader->bmiHeader.biWidth = width; pVideoHeader->bmiHeader.biHeight = height; pVideoHeader->bmiHeader.biPlanes = 1; pVideoHeader->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pVideoHeader->bmiHeader.biSizeImage = DIBSIZE(pVideoHeader->bmiHeader); // Set the format type and size. mt.formattype = FORMAT_VideoInfo; mt.cbFormat = sizeof(VIDEOINFOHEADER); // Set the sample size. mt.bFixedSizeSamples = TRUE; mt.lSampleSize = DIBSIZE(pVideoHeader->bmiHeader); // Make the call to actually set the video type to what we want. if (_pStreamConfig->SetFormat(&mt) != S_OK) { fprintf(stderr,"directx_camera_server::open_and_find_parameters(): Can't set resolution to %dx%d\n", pVideoHeader->bmiHeader.biWidth, pVideoHeader->bmiHeader.biHeight); return false; } // Clean up the pbFormat header memory we allocated above. CoTaskMemFree(mt.pbFormat); } //------------------------------------------------------------------- // Create a NULL renderer that will be used to discard the video frames // on the output pin of the sample grabber #ifdef DEBUG printf("directx_camera_server::open_and_find_parameters(): Before CoCreateInstance NullRenderer\n"); #endif IBaseFilter *pNull = NULL; CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, reinterpret_cast<void**>(&pNull)); //------------------------------------------------------------------- // Build the filter graph. First add the filters and then connect them. // pSrc is the capture filter for the video device we found above. _pGraph->AddFilter(pSrc, L"Video Capture"); // Add the sample grabber filter _pGraph->AddFilter(_pSampleGrabberFilter, L"SampleGrabber"); // Add the null renderer filter _pGraph->AddFilter(pNull, L"NullRenderer"); // Connect the output of the video reader to the sample grabber input ConnectTwoFilters(_pGraph, pSrc, _pSampleGrabberFilter); // Connect the output of the sample grabber to the NULL renderer input ConnectTwoFilters(_pGraph, _pSampleGrabberFilter, pNull); //------------------------------------------------------------------- // XXX See if this is a video tuner card by querying for that interface. // Set it to read the video channel if it is one. IAMTVTuner *pTuner = NULL; hr = _pBuilder->FindInterface(NULL, NULL, pSrc, IID_IAMTVTuner, (void**)&pTuner); if (pTuner != NULL) { #ifdef DEBUG printf("directx_camera_server::open_and_find_parameters(): Found a TV Tuner!\n"); #endif //XXX Put code here. // Set the first input pin to use the cable as input hr = pTuner->put_InputType(0, TunerInputCable); if (FAILED(hr)) { fprintf(stderr,"directx_camera_server::open_and_find_parameters(): Can't set input to cable\n"); } // Set the channel on the video to be baseband (is this channel zero?) hr = pTuner->put_Channel(0, -1, -1); if (FAILED(hr)) { fprintf(stderr,"directx_camera_server::open_and_find_parameters(): Can't set channel\n"); } pTuner->Release(); } //------------------------------------------------------------------- // Find _num_rows and _num_columns in the video stream. _pGrabber->GetConnectedMediaType(&mt); VIDEOINFOHEADER *pVih; if (mt.formattype == FORMAT_VideoInfo) { pVih = reinterpret_cast<VIDEOINFOHEADER*>(mt.pbFormat); } else { fprintf(stderr,"directx_camera_server::open_and_find_parameters(): Can't get video header type\n"); return false; } // Number of rows and columns. This is different if we are using a target // rectangle (rcTarget) than if we are not. if (IsRectEmpty(&pVih->rcTarget)) { _num_columns = pVih->bmiHeader.biWidth; _num_rows = pVih->bmiHeader.biHeight; } else { _num_columns = pVih->rcTarget.right; _num_rows = pVih->bmiHeader.biHeight; printf("XXX directx_camera_server::open_and_find_parameters(): Warning: may not work correctly with target rectangle\n"); } _minX = 0; _maxX = _num_columns - 1; _minY = 0; _maxY = _num_rows - 1; #ifdef DEBUG printf("Got %dx%d video\n", _num_columns, _num_rows); #endif // Make sure that the image is not compressed and that we have 8 bits // per pixel. if (pVih->bmiHeader.biCompression != BI_RGB) { fprintf(stderr,"directx_camera_server::open_and_find_parameters(): Compression not RGB\n"); switch (pVih->bmiHeader.biCompression) { case BI_RLE8: fprintf(stderr," (It is BI_RLE8)\n"); break; case BI_RLE4: fprintf(stderr," (It is BI_RLE4)\n"); case BI_BITFIELDS: fprintf(stderr," (It is BI_BITFIELDS)\n"); break; default: fprintf(stderr," (Unknown compression type)\n"); } return false; } int BytesPerPixel = pVih->bmiHeader.biBitCount / 8; if (BytesPerPixel != 3) { fprintf(stderr,"directx_camera_server::open_and_find_parameters(): Not 3 bytes per pixel (%d)\n", pVih->bmiHeader.biBitCount); return false; } // A negative height indicates that the images are stored non-inverted in Y // Not sure what to do with images that have negative height -- need to // read the book some more to find out. if (_num_rows < 0) { fprintf(stderr,"directx_camera_server::open_and_find_parameters(): Num Rows is negative (internal error)\n"); return false; } // Find the stride to take when moving from one row of video to the // next. This is rounded up to the nearest DWORD. _stride = (_num_columns * BytesPerPixel + 3) & ~3; // Set the callback, where '0' means 'use the SampleCB callback' _pGrabber->SetCallback(_pCallback, 0); //------------------------------------------------------------------- // Release resources that won't be used later and return pSrc->Release(); pNull->Release(); return true; }