//---------------------------------------------------------------------------- //! @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(); }
//----------------------------------------------------------------------------- // InitDShowTextureRenderer : Create DirectShow filter graph and run the graph //----------------------------------------------------------------------------- HRESULT CDShowManager::InitDShowTextureRenderer() { HRESULT hr = S_OK; IBaseFilter* pFSrc; // Source Filter IPin* pFSrcPinOut; // Source Filter Output Pin CTextureRenderer *pCTR=0; // DirectShow Texture renderer // Create the filter graph //if (FAILED(g_pGB->CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC))) // return E_FAIL; hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&m_pGB); if (FAILED(hr)) { return E_FAIL; } #ifdef REGISTER_FILTERGRAPH // Register the graph in the Running Object Table (for debug purposes) AddToROT(m_pGB); #endif // Create the Texture Renderer object pCTR = new CTextureRenderer(NULL, &hr); if (FAILED(hr) || !pCTR) { delete pCTR; Msg(TEXT("Could not create texture renderer object! hr=0x%x"), hr); return E_FAIL; } // Get a pointer to the IBaseFilter on the TextureRenderer, add it to graph m_pRenderer = pCTR; pCTR->AddRef(); if (FAILED(hr = m_pGB->AddFilter(m_pRenderer, L"TEXTURERENDERER"))) { Msg(TEXT("Could not add renderer filter to graph! hr=0x%x"), hr); return hr; } // Determine the file to load based on windows directory // Use the standard win32 API to do this. TCHAR strFileName[MAX_PATH] = {0}; WCHAR wFileName[MAX_PATH]; if (! GetClipFileName(strFileName)) { DWORD dwDlgErr = CommDlgExtendedError(); // Don't show output if user cancelled the selection (no dlg error) if (dwDlgErr) { Msg(TEXT("GetClipFileName Failed! Error=0x%x\r\n"), GetLastError()); } return E_FAIL; } strFileName[MAX_PATH-1] = 0; // NULL-terminate wFileName[MAX_PATH-1] = 0; // NULL-terminate //USES_CONVERSION; (void)StringCchCopyW(wFileName, NUMELMS(wFileName), T2W(strFileName)); // Add the source filter to the graph. hr = m_pGB->AddSourceFilter (wFileName, L"SOURCE", &pFSrc); // If the media file was not found, inform the user. if (hr == VFW_E_NOT_FOUND) { Msg(TEXT("Could not add source filter to graph! (hr==VFW_E_NOT_FOUND)\r\n\r\n") TEXT("This sample reads a media file from your windows directory.\r\n") TEXT("This file is missing from this machine.")); return hr; } else if(FAILED(hr)) { Msg(TEXT("Could not add source filter to graph! hr=0x%x"), hr); return hr; } if (FAILED(hr = pFSrc->FindPin(L"Output", &pFSrcPinOut))) { Msg(TEXT("Could not find output pin! hr=0x%x"), hr); return hr; } #ifdef NO_AUDIO_RENDERER // If no audio component is desired, directly connect the two video pins // instead of allowing the Filter Graph Manager to render all pins. CComPtr<IPin> pFTRPinIn; // Texture Renderer Input Pin // Find the source's output pin and the renderer's input pin if (FAILED(hr = pFTR->FindPin(L"In", &pFTRPinIn))) { Msg(TEXT("Could not find input pin! hr=0x%x"), hr); return hr; } // Connect these two filters if (FAILED(hr = m_pGB->Connect(pFSrcPinOut, pFTRPinIn))) { Msg(TEXT("Could not connect pins! hr=0x%x"), hr); return hr; } #else // Render the source filter's output pin. The Filter Graph Manager // will connect the video stream to the loaded CTextureRenderer // and will load and connect an audio renderer (if needed). if (FAILED(hr = m_pGB->Render(pFSrcPinOut))) { Msg(TEXT("Could not render source output pin! hr=0x%x"), hr); return hr; } #endif // Get the graph's media control, event & position interfaces m_pGB->QueryInterface(&m_pMC); m_pGB->QueryInterface(&m_pMP); m_pGB->QueryInterface(&m_pME); // Start the graph running; if (FAILED(hr = m_pMC->Run())) { Msg(TEXT("Could not run the DirectShow graph! hr=0x%x"), hr); return hr; } return S_OK; }
//---------------------------------------------------------------------------- //! @brief フィルタグラフの構築 //! @param callbackwin : メッセージを送信するウィンドウ //! @param stream : 読み込み元ストリーム //! @param streamname : ストリームの名前 //! @param type : メディアタイプ(拡張子) //! @param size : メディアサイズ //---------------------------------------------------------------------------- void __stdcall tTVPDSVideoOverlay::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); } if( IsWindowsMediaFile(type) ) { CComPtr<IBaseFilter> pVRender; // for video renderer filter if( FAILED(hr = pVRender.CoCreateInstance(CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER)) ) ThrowDShowException(L"Failed to create video renderer filter object.", hr); if( FAILED(hr = GraphBuilder()->AddFilter(pVRender, L"Video Renderer")) ) ThrowDShowException(L"Failed to call IFilterGraph::AddFilter.", hr); BuildWMVGraph( pVRender, stream ); } 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, NULL)) ) 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); } else { CComPtr<IBaseFilter> pVRender; // for video renderer filter if( FAILED(hr = pVRender.CoCreateInstance(CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER)) ) ThrowDShowException(L"Failed to create video renderer filter object.", hr); if( FAILED(hr = GraphBuilder()->AddFilter(pVRender, L"Video Renderer")) ) ThrowDShowException(L"Failed to call IFilterGraph::AddFilter.", hr); BuildMPEGGraph( pVRender, m_Reader); // may throw an exception } } // 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_BasicVideo )) ) ThrowDShowException(L"Failed to query IBasicVideo", hr); if( FAILED(hr = m_GraphBuilder.QueryInterface( &m_VideoWindow )) ) ThrowDShowException(L"Failed to query IVideoWindow", hr); if( FAILED(hr = m_GraphBuilder.QueryInterface( &m_BasicAudio )) ) ThrowDShowException(L"Failed to query IBasicAudio", hr); // check whether the stream has video if(!m_VideoWindow || !m_BasicVideo ) TVPThrowExceptionMessage(L"The stream has no video components."); { long visible; if(FAILED(hr = VideoWindow()->get_Visible(&visible))) ThrowDShowException(L"The stream has no video components or has unsupported video format.", hr); } // disable AutoShow VideoWindow()->put_AutoShow(OAFALSE); // 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(); // ここでこれを呼ぶとまずそうな気がするけど、大丈夫なのかなぁ }
bool CVideoRenderer::Initialize ( const char * szFile ) { IBaseFilter * pDSound, * pXVID, * pVorbis; IBaseFilter * pSource; IFileSourceFilter * pFileSource; HRESULT hr; // Get the codecs CVideoManager *pManager = CVideoManager::GetSingletonPtr (); if ( pManager->CreateCodecSource ( &pSource ) != S_OK ) return false; if ( pManager->CreateCodecVorbis ( &pVorbis ) != S_OK ) return false; if ( pManager->CreateCodecXVID ( &pXVID ) != S_OK ) return false; // Check for a valid device if ( !m_pDevice ) return false; // Lock so we don't f**k up Lock (); CCore::GetSingleton ().GetConsole ()->Printf ( "Creating DirectShow graph instance" ); // Initialize the graph builder CoCreateInstance ( CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, reinterpret_cast < void** > ( &m_pGraph ) ); if ( m_pGraph == NULL ) return false; CCore::GetSingleton ().GetConsole ()->Printf ( "Creating DirectSound renderer instance" ); // Initialize the DirectSound filter CoCreateInstance ( CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, reinterpret_cast < void** > ( &pDSound ) ); if ( pDSound == NULL ) return false; #ifdef MTA_DEBUG CCore::GetSingleton ().GetConsole ()->Printf ( "Adding ROT for debug stuff" ); // Enable GraphView debugging AddToROT(m_pGraph); #endif CCore::GetSingleton ().GetConsole ()->Printf ( "Creating video renderer instance" ); // Create an instance of the texture renderer and add it to the graph m_pFilter = CreateTextureRenderer ( &hr, m_pDevice, this ); if ( hr != S_OK ) return false; // Add the source file filter to the grap h int iBufferSize = MultiByteToWideChar ( CP_ACP, 0, szFile, -1, NULL, 0 ); wchar_t *wszFile = new wchar_t[iBufferSize]; MultiByteToWideChar ( CP_ACP, 0, szFile, -1, wszFile, iBufferSize ); CCore::GetSingleton ().GetConsole ()->Printf ( "Registering filter (Matroska)" ); // Add the filters to the graph m_pGraph->AddFilter ( pSource, L"[MTA] MKV source" ); CCore::GetSingleton ().GetConsole ()->Printf ( "Loading video file" ); pSource->QueryInterface ( IID_IFileSourceFilter, reinterpret_cast < void** > ( &pFileSource ) ); if ( pFileSource->Load ( wszFile, NULL ) != S_OK ) return false; CCore::GetSingleton ().GetConsole ()->Printf ( "Registering filter (Output)" ); m_pGraph->AddFilter ( m_pFilter, L"[MTA] Texture renderer" ); CCore::GetSingleton ().GetConsole ()->Printf ( "Registering filter (Vorbis)" ); m_pGraph->AddFilter ( pVorbis, L"[MTA] Vorbis decoder" ); CCore::GetSingleton ().GetConsole ()->Printf ( "Registering filter (XVID)" ); m_pGraph->AddFilter ( pXVID, L"[MTA] XVID codec" ); CCore::GetSingleton ().GetConsole ()->Printf ( "Registering filter (DirectSound)" ); m_pGraph->AddFilter ( pDSound, L"[MTA] DirectSound renderer" ); CCore::GetSingleton ().GetConsole ()->Printf ( "Connecting video renderer" ); // Connect the video pins IPin *pOut, *pSourceOut; hr = ConnectFilters ( m_pGraph, pSource, pXVID, &pSourceOut ); // MKV Source -> XVID assert ( hr == S_OK ); hr = ConnectFilters ( m_pGraph, pXVID, m_pFilter, &pOut ); // XVID -> Texture Renderer assert ( hr == S_OK ); // Connect the audio pins (not necessary) hr = ConnectFilters ( m_pGraph, pSource, pVorbis, &pOut ); // MKV Source -> Vorbis Decoder hr = ConnectFilters ( m_pGraph, pVorbis, pDSound, &pOut ); // Vorbis Decoder -> DirectSound renderer m_pGraph->QueryInterface ( IID_IMediaSeeking, reinterpret_cast < void** > ( &m_pMediaSeeking ) ); assert ( m_pMediaSeeking != NULL ); m_pGraph->QueryInterface ( IID_IMediaControl, reinterpret_cast < void** > ( &m_pMediaControl ) ); if ( m_pMediaControl == NULL || m_pMediaSeeking == NULL ) return false; m_pGraph->QueryInterface ( IID_IBasicAudio, reinterpret_cast < void** > ( &m_pBasicAudio ) ); if ( m_pBasicAudio == NULL ) return false; CCore::GetSingleton ().GetConsole ()->Printf ( "Successfully loaded video renderer" ); m_pBasicAudio->get_Volume ( &lDefaultVolume ); // Clean up delete [] wszFile; // m_pGraph->Release (); // Unlock the mutex Unlock (); return true; }