HRESULT DirectShowVideoWrapper::ConnectSampleGrabber(void) { HRESULT hr = S_OK; TCHAR szErr[MAX_ERROR_TEXT_LEN]; // Register the graph in the Running Object Table (for debug purposes) AddGraphToROT(_pGraphBuilder, &dwROT); // Create the Sample Grabber which we will use // To take each frame for texture generation if(_pSampleGrabberFilter == NULL) { hr = _pSampleGrabberFilter.CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Could not create SampleGrabberFilter, error: " << szErr << std::endl; return hr; } } _pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, reinterpret_cast<void**>(&_pSampleGrabber)); // We have to set the 24-bit RGB desire here // So that the proper conversion filters // Are added automatically. AM_MEDIA_TYPE desiredType; memset(&desiredType, 0, sizeof(desiredType)); desiredType.majortype = MEDIATYPE_Video; //desiredType.subtype = MEDIASUBTYPE_RGB565; desiredType.subtype = MEDIASUBTYPE_RGB24; //desiredType.subtype = GUID_NULL; desiredType.formattype = GUID(); //desiredType.formattype = FORMAT_VideoInfo; _pSampleGrabber->SetMediaType(&desiredType); _pSampleGrabber->SetBufferSamples(TRUE); // A Null Renderer does not display the video // But it allows the Sample Grabber to run // And it will keep proper playback timing // Unless specified otherwise. if(_pVideoRenderer == NULL) { hr = _pVideoRenderer.CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Unable to create Null Renderer, error: " << szErr << std::endl; return hr; } } //Get Input pins to VideoRenderer IPin* _VideoRendererIntputPin; if (FAILED(hr = _pVideoRenderer->FindPin(L"In", &_VideoRendererIntputPin))) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Could not find VideoRenderer Intput Pin, error: " << szErr << std::endl; return hr; } IBaseFilter* pVidRenderer = NULL; hr = FindVideoRenderer(_pGraphBuilder,&pVidRenderer); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "error: " << szErr << std::endl; return hr; } if(pVidRenderer) { SLOG << "Removing default video renderer" << std::endl; //get input pin of video renderer IPin* ipin; hr = GetPin(pVidRenderer, PINDIR_INPUT, 0, &ipin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Get Vidio Renderer in pin, error: " << szErr << std::endl; return hr; } IPin* opin = NULL; //find out who the renderer is connected to and disconnect from them hr = ipin->ConnectedTo(&opin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "error: " << szErr << std::endl; return hr; } //Get the filter of the opin PIN_INFO OpinInfo; opin->QueryPinInfo(&OpinInfo); IBaseFilter* LastFilter(OpinInfo.pFilter); FILTER_INFO LastFilterInfo; LastFilter->QueryFilterInfo(&LastFilterInfo); CLSID LastFilterClassID; LastFilter->GetClassID(&LastFilterClassID); SLOG << "Last filter name: " << LastFilterInfo.achName << ", ClassID " << LastFilterClassID.Data1 << "-" << LastFilterClassID.Data2 << "-" << LastFilterClassID.Data3 << "-" << LastFilterClassID.Data4 << std::endl; LPWSTR *VendorInfo; LastFilter->QueryVendorInfo(VendorInfo); if(VendorInfo) { SLOG << "Last filter vendor: " << *VendorInfo << std::endl; } hr = ipin->Disconnect(); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "error: " << szErr << std::endl; return hr; } hr = opin->Disconnect(); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "error: " << szErr << std::endl; return hr; } //SAFE_RELEASE(ipin); //remove the default renderer from the graph hr = _pGraphBuilder->RemoveFilter(pVidRenderer); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "error: " << szErr << std::endl; return hr; } //SAFE_RELEASE(pVidRenderer); //see if the video renderer was originally connected to //a color space converter _pGraphBuilder->FindFilterByName(L"Color Space Converter", &_pCSCFilter); if(_pCSCFilter == NULL) { // Create the Color Space filter hr = _pCSCFilter.CoCreateInstance(CLSID_Colour, NULL, CLSCTX_INPROC_SERVER); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Could not create Color Space Converter Filter, error: " << szErr << std::endl; return hr; } hr = _pGraphBuilder->AddFilter(_pCSCFilter, L"Color Space Converter"); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Could not add Color Space Converter Filter, error: " << szErr << std::endl; return hr; } //get the output pin of the last filter hr = GetPin(LastFilter, PINDIR_OUTPUT, 0, &opin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Get Last filter out pin, error: " << szErr << std::endl; return hr; } //get the input pin of the Color Space Converter hr = GetPin(_pCSCFilter, PINDIR_INPUT, 0, &ipin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Get Color Space Converter In Pin, error: " << szErr << std::endl; return hr; } //connect the filter that was originally connected to the default renderer //to the Color Space Converter SLOG << "Attaching Color Space Converter Filter. " << opin << " -> " << ipin << std::endl; hr = _pGraphBuilder->Connect(opin, ipin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Could not attach Color Space Converter Filter so it won't be used, error: " << szErr << std::endl; //return hr; } else { LastFilter = _pCSCFilter; } } hr = _pGraphBuilder->AddFilter(_pSampleGrabberFilter, L"Video Sample Grabber"); //get the input pin of the Sample Grabber hr = GetPin(_pSampleGrabberFilter, PINDIR_INPUT, 0, &ipin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Get Sample Grabber In Pin, error: " << szErr << std::endl; return hr; } //get the output pin of the last filter in the graph hr = GetPin(LastFilter, PINDIR_OUTPUT, 0, &opin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Get Color Space Converter out pin, error: " << szErr << std::endl; return hr; } SLOG << "Attaching video sample grabber filter." << std::endl; hr = _pGraphBuilder->Connect(opin, ipin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "error: " << szErr << std::endl; return hr; } //SAFE_RELEASE(ipin); //SAFE_RELEASE(opin); //get output pin of sample grabber hr = GetPin(_pSampleGrabberFilter, PINDIR_OUTPUT, 0, &opin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Get Sample Grabber out pin, error: " << szErr << std::endl; return hr; } SLOG << "Attaching Video Null Renderer." << std::endl; hr = _pGraphBuilder->AddFilter(_pVideoRenderer, L"Video Null Renderer"); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Unable to add Renderer to filter graph, error: " << szErr << std::endl; return hr; } //get input pin of null renderer hr = GetPin(_pVideoRenderer, PINDIR_INPUT, 0, &ipin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Get Null Renderer in pin, error: " << szErr << std::endl; return hr; } //connect them SLOG << "Attaching null video renderer." << std::endl; hr = _pGraphBuilder->Connect(opin, ipin); if (FAILED(hr)) { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Unable to connect Renderer to sample grabber, error: " << szErr << std::endl; return hr; } //SAFE_RELEASE(ipin); //SAFE_RELEASE(opin); } // Just a little trick so that we don't have to know // The video resolution when calling this method. bool mediaConnected = false; AM_MEDIA_TYPE connectedType; if (SUCCEEDED(hr = _pSampleGrabber->GetConnectedMediaType(&connectedType))) { if (connectedType.formattype == FORMAT_VideoInfo) { VIDEOINFOHEADER* infoHeader = (VIDEOINFOHEADER*)connectedType.pbFormat; _VideoWidth = infoHeader->bmiHeader.biWidth; _VideoHeight = infoHeader->bmiHeader.biHeight; mediaConnected = true; } else if (connectedType.formattype == FORMAT_VideoInfo2) { VIDEOINFOHEADER* infoHeader = (VIDEOINFOHEADER*)connectedType.pbFormat; _VideoWidth = infoHeader->bmiHeader.biWidth; _VideoHeight = infoHeader->bmiHeader.biHeight; mediaConnected = true; } else { SWARNING << "Unable to get the media type connected to the sample grabber." << std::endl; } SLOG << "Video Dimensions: " << _VideoWidth << " x " << _VideoHeight << std::endl; CoTaskMemFree(connectedType.pbFormat); } else { AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); SWARNING << "Unable to get connected media type, error: " << szErr << std::endl; return hr; } /*if (!mediaConnected) { uninitVideo(); return false; }*/ return hr; }
//---------------------------------------------------------------------------- //! @brief フィルタグラフの構築 //! @param callbackwin : メッセージを送信するウィンドウ //! @param stream : 読み込み元ストリーム //! @param streamname : ストリームの名前 //! @param type : メディアタイプ(拡張子) //! @param size : メディアサイズ //---------------------------------------------------------------------------- void __stdcall tTVPDSMixerVideoOverlay::BuildGraph( HWND callbackwin, IStream *stream, const wchar_t * streamname, const wchar_t *type, unsigned __int64 size ) { HRESULT hr; //CoInitialize(NULL); // detect CMediaType from stream's extension ('type') try { if( FAILED(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)) ) ThrowDShowException(L"Failed to call CoInitializeEx.", hr); // create IFilterGraph instance if( FAILED(hr = m_GraphBuilder.CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC)) ) ThrowDShowException(L"Failed to create FilterGraph.", hr); // Register to ROT if(GetShouldRegisterToROT()) { AddToROT(m_dwROTReg); } { CAutoLock Lock(&m_VMRLock); OwnerWindow = callbackwin; // copy window handle for D3D m_OwnerInst = GetModuleHandle(NULL); } m_AllocatorPresenter = new CVMRCustomAllocatorPresenter9(this,m_VMRLock); m_AllocatorPresenter->AddRef(); m_AllocatorPresenter->Initialize(); if( IsWindowsMediaFile(type) ) { CComPtr<IBaseFilter> pVMR9; AddVMR9Filer( pVMR9 ); BuildWMVGraph( pVMR9, stream ); if( FAILED(hr = pVMR9.QueryInterface( &m_VMR9MixerCtrl ) ) ) ThrowDShowException(L"Failed to query IVMRMixerControl9.", hr); if( FAILED(hr = pVMR9.QueryInterface( &m_VMR9MixerBmp ) ) ) ThrowDShowException(L"Failed to query IVMRMixerBitmap9.", hr); } else { CMediaType mt; mt.majortype = MEDIATYPE_Stream; ParseVideoType( mt, type ); // may throw an exception // create proxy filter m_Proxy = new CIStreamProxy( stream, size ); hr = S_OK; m_Reader = new CIStreamReader( m_Proxy, &mt, &hr ); if( FAILED(hr) || m_Reader == NULL ) ThrowDShowException(L"Failed to create proxy filter object.", hr); m_Reader->AddRef(); // add fliter if( FAILED(hr = GraphBuilder()->AddFilter( m_Reader, L"Stream Reader")) ) ThrowDShowException(L"Failed to call IFilterGraph::AddFilter.", hr); // AddFilterしたのでRelease m_Reader->Release(); if( mt.subtype == MEDIASUBTYPE_Avi || mt.subtype == MEDIASUBTYPE_QTMovie ) { // render output pin if( FAILED(hr = GraphBuilder()->Render(m_Reader->GetPin(0))) ) ThrowDShowException(L"Failed to call IGraphBuilder::Render.", hr); CComPtr<IBaseFilter> pRender; if( FAILED(hr = FindVideoRenderer( &pRender ) ) ) ThrowDShowException(L"Failed to call FindVideoRenderer( &pRender ).", hr); CComPtr<IPin> pRenderPin; pRenderPin = GetInPin(pRender, 0); // get decoder output pin CComPtr<IPin> pDecoderPinOut; if( FAILED(hr = pRenderPin->ConnectedTo( &pDecoderPinOut )) ) ThrowDShowException(L"Failed to call pRenderPin->ConnectedTo( &pDecoderPinOut ).", hr); // dissconnect pins if( FAILED(hr = pDecoderPinOut->Disconnect()) ) ThrowDShowException(L"Failed to call pDecoderPinOut->Disconnect().", hr); if( FAILED(hr = pRenderPin->Disconnect()) ) ThrowDShowException(L"Failed to call pRenderPin->Disconnect().", hr); // remove default render if( FAILED(hr = GraphBuilder()->RemoveFilter( pRender ) ) ) ThrowDShowException(L"Failed to call GraphBuilder->RemoveFilter(pRenderPin).", hr); CComPtr<IBaseFilter> pVMR9; AddVMR9Filer( pVMR9 ); CComPtr<IPin> pRdrPinIn; pRdrPinIn = GetInPin(pVMR9, 0); if( FAILED(hr = GraphBuilder()->ConnectDirect( pDecoderPinOut, pRdrPinIn, NULL )) ) ThrowDShowException(L"Failed to call GraphBuilder()->ConnectDirect( pDecoderPinOut, pRdrPinIn, NULL ).", hr); if( FAILED(hr = pVMR9.QueryInterface( &m_VMR9MixerCtrl ) ) ) ThrowDShowException(L"Failed to query IVMRMixerControl9.", hr); if( FAILED(hr = pVMR9.QueryInterface( &m_VMR9MixerBmp ) ) ) ThrowDShowException(L"Failed to query IVMRMixerBitmap9.", hr); } else { CComPtr<IBaseFilter> pVMR9; AddVMR9Filer( pVMR9 ); BuildMPEGGraph( pVMR9, m_Reader); // may throw an exception if( FAILED(hr = pVMR9.QueryInterface( &m_VMR9MixerCtrl ) ) ) ThrowDShowException(L"Failed to query IVMRMixerControl9.", hr); if( FAILED(hr = pVMR9.QueryInterface( &m_VMR9MixerBmp ) ) ) ThrowDShowException(L"Failed to query IVMRMixerBitmap9.", hr); } } #if 1 { // 平均フレーム表示時間を取得する CComPtr<IBaseFilter> pRender; if( FAILED(hr = FindVideoRenderer( &pRender ) ) ) ThrowDShowException(L"Failed to call FindVideoRenderer( &pRender ).", hr); CComPtr<IPin> pRenderPin; pRenderPin = GetInPin(pRender, 0); AM_MEDIA_TYPE mt; if( FAILED(hr = pRenderPin->ConnectionMediaType(&mt)) ) ThrowDShowException(L"Failed to call IPin::ConnectionMediaType(pmt).", hr); if( mt.formattype == FORMAT_VideoInfo && mt.cbFormat != 0 ) { VIDEOINFOHEADER *vih = reinterpret_cast<VIDEOINFOHEADER*>(mt.pbFormat); m_AvgTimePerFrame = vih->AvgTimePerFrame; m_Width = vih->bmiHeader.biWidth; m_Height = vih->bmiHeader.biHeight; } else if( mt.formattype == FORMAT_VideoInfo2 && mt.cbFormat != 0 ) { VIDEOINFOHEADER2 *vih = reinterpret_cast<VIDEOINFOHEADER2*>(mt.pbFormat); m_AvgTimePerFrame = vih->AvgTimePerFrame; m_Width = vih->bmiHeader.biWidth; m_Height = vih->bmiHeader.biHeight; } FreeMediaType(mt); } #endif // query each interfaces if( FAILED(hr = m_GraphBuilder.QueryInterface( &m_MediaControl )) ) ThrowDShowException(L"Failed to query IMediaControl", hr); if( FAILED(hr = m_GraphBuilder.QueryInterface( &m_MediaPosition )) ) ThrowDShowException(L"Failed to query IMediaPosition", hr); if( FAILED(hr = m_GraphBuilder.QueryInterface( &m_MediaSeeking )) ) ThrowDShowException(L"Failed to query IMediaSeeking", hr); if( FAILED(hr = m_GraphBuilder.QueryInterface( &m_MediaEventEx )) ) ThrowDShowException(L"Failed to query IMediaEventEx", hr); if( FAILED(hr = m_GraphBuilder.QueryInterface( &m_BasicAudio )) ) ThrowDShowException(L"Failed to query IBasicAudio", hr); // set notify event if(callbackwin) { if(FAILED(hr = Event()->SetNotifyWindow((OAHWND)callbackwin, WM_GRAPHNOTIFY, (long)(this)))) ThrowDShowException(L"Failed to set IMediaEventEx::SetNotifyWindow.", hr); } } catch(const wchar_t *msg) { MakeAPause(true); ReleaseAll(); CoUninitialize(); TVPThrowExceptionMessage(msg); } catch(...) { MakeAPause(true); ReleaseAll(); CoUninitialize(); throw; } MakeAPause(false); CoUninitialize(); }