示例#1
0
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;
}
示例#2
0
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;
}
示例#3
0
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;
}