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