HRESULT CMediaPlayerDlg::PrepareMedia(LPTSTR lpszMovie) { USES_CONVERSION; HRESULT hr = S_OK; // Is this a Windows Media file (ASF, WMA, WMV)? If so, use the new // ASF Reader filter, which is faster and much better at seeking than // the default ASF Reader filter used by default with RenderFile. if (IsWindowsMediaFile(lpszMovie)) { hr = RenderWMFile(T2W(lpszMovie)); if (FAILED(hr)) { MPRetailOutput(TEXT("*** Failed(%08lx) to Render WM File(%s)!\r\n"), hr, lpszMovie); return hr; } } else { // Allow DirectShow to create the FilterGraph for this media file hr = pGB_MP->RenderFile(T2W(lpszMovie), NULL); if (FAILED(hr)) { MPRetailOutput(TEXT("*** Failed(%08lx) in RenderFile(%s)!\r\n"), hr, lpszMovie); return hr; } } // Set the message drain of the video window to point to our main // application window. If this is an audio-only or MIDI file, // then put_MessageDrain will fail. hr = pVW_MP->put_MessageDrain((OAHWND) m_hWnd); if (FAILED(hr)) { g_bAudioOnly_MP = TRUE; } // Have the graph signal event via window callbacks hr = pME_MP->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0); // Configure the video window if (!g_bAudioOnly_MP) { // We'll manually set the video to be visible hr = pVW_MP->put_Visible(OAFALSE); hr = pVW_MP->put_WindowStyle(WS_CHILD); hr = pVW_MP->put_Owner((OAHWND) m_MPScreen.GetSafeHwnd()); // Place video window within the bounding rectangle CenterVideo(); // Make the video window visible within the screen window. // If this is an audio-only file, then there won't be a video interface. hr = pVW_MP->put_Visible(OATRUE); hr = pVW_MP->SetWindowForeground(-1); } return hr; }
//---------------------------------------------------------------------------- //! @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(); // ここでこれを呼ぶとまずそうな気がするけど、大丈夫なのかなぁ }
//---------------------------------------------------------------------------- //! @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(); }
HRESULT PlayMovieInWindow(LPTSTR szFile, BOOL bReOpenAfterLicenseAcquired) { USES_CONVERSION; WCHAR wFile[MAX_PATH]; HRESULT hr; // Check input string if (!szFile) return E_POINTER; // Clear open dialog remnants before calling RenderFile() UpdateWindow(ghApp); // Convert filename to wide character string wcsncpy(wFile, T2W(szFile), NUMELMS(wFile)-1); wFile[MAX_PATH-1] = 0; // First pass of rendering the media file. If a DRM license must // be acquired before the file can be loaded, then the reopen flag // will be set. if( !bReOpenAfterLicenseAcquired ) { // Get the interface for DirectShow's GraphBuilder JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGB)); JIF(pGB->QueryInterface(IID_IMediaEventEx, (void **)&pME)); if(SUCCEEDED(hr)) { // Have the graph signal event via window callbacks // // Start this before we insert the reader filter, since we may need // to monitor DRM license acquistion messages on reader creation // JIF(pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0)); // Use special handling for Windows Media files if (IsWindowsMediaFile(szFile)) { // Load the improved ASF reader filter by CLSID hr = CreateFilter(CLSID_WMAsfReader, &g_pReader); if(FAILED(hr)) { Msg(TEXT("Failed to create WMAsfWriter filter! hr=0x%x\0"), hr); return hr; } // Add the ASF reader filter to the graph. For ASF/WMV/WMA content, // this filter is NOT the default and must be added explicitly. hr = pGB->AddFilter(g_pReader, L"ASF Reader"); if(FAILED(hr)) { Msg(TEXT("Failed to add ASF reader filter to graph! hr=0x%x\0"), hr); return hr; } // Create the key provider that will be used to unlock the WM SDK JIF(AddKeyProvider(pGB)); // Create the DRM license event g_hLicenseEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); if( !g_hLicenseEvent ) { return E_OUTOFMEMORY; } // Set its source filename JIF(g_pReader->QueryInterface(IID_IFileSourceFilter, (void **) &g_pFileSource)); // Attempt to load this file hr = g_pFileSource->Load(wFile, NULL); // Handle Digital Rights Management (DRM) errors if(NS_E_LICENSE_REQUIRED == hr) { Msg(TEXT("This media file is protected by DRM and needs a license.\r\n\r\n") TEXT("Attempting to acquire a license...\0")); g_bWaitingForLicense = TRUE; return hr; } else if(NS_E_PROTECTED_CONTENT == hr) { Msg(TEXT("This media file is protected by DRM and needs a license.\r\n\r\n") TEXT("In order to play DRM-encoded content, you must acquire a DRM stub library\r\n") TEXT("from Microsoft and link it with this application. The default version of\r\n") TEXT("the WMStub.lib library does not support Digital Rights Management (DRM).")); return hr; } else if (FAILED(hr)) { Msg(TEXT("Failed to load file in source filter (g_pFileSource->Load())! hr=0x%x\0"), hr); return hr; } // Render the output pins of the ASF reader to build the // remainder of the graph automatically JIF(RenderOutputPins(pGB, g_pReader)); // Since the graph is built and the filters are added to the graph, // the WM ASF reader interface can be released. g_pReader->Release(); g_pReader = NULL; } // Not a Windows Media file, so just render the standard way else { // Have the graph builder construct the appropriate graph automatically JIF(pGB->RenderFile(wFile, NULL)); } } } else { hr = g_pFileSource->Load(wFile, NULL); if( SUCCEEDED( hr ) ) { Msg(TEXT("Successfully loaded file after DRM license acquisition!")); // Render the output pins of the ASF reader to build the // remainder of the graph automatically JIF(RenderOutputPins(pGB, g_pReader)); // Since the graph is built and the filters are added to the graph, // the WM ASF reader interface can be released. g_pReader->Release(); // not really necessary g_pReader = NULL; } else { Msg(TEXT("Failed to Load file after acquiring license! hr=0x%x\0"), hr); } } if( SUCCEEDED( hr ) ) { // QueryInterface for DirectShow interfaces JIF(pGB->QueryInterface(IID_IMediaControl, (void **)&pMC)); JIF(pGB->QueryInterface(IID_IMediaSeeking, (void **)&pMS)); // Query for video interfaces, which may not be relevant for audio files JIF(pGB->QueryInterface(IID_IVideoWindow, (void **)&pVW)); JIF(pGB->QueryInterface(IID_IBasicVideo, (void **)&pBV)); // Query for audio interfaces, which may not be relevant for video-only files JIF(pGB->QueryInterface(IID_IBasicAudio, (void **)&pBA)); // Is this an audio-only file (no video component)? CheckVisibility(); if (!g_bAudioOnly) { // Setup the video window JIF(pVW->put_Owner((OAHWND)ghApp)); JIF(pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN)); JIF(InitVideoWindow(1, 1)); GetFrameStepInterface(); } else { // Initialize the default player size and enable playback menu items JIF(InitPlayerWindow()); EnablePlaybackMenu(TRUE, AUDIO); } // Complete window initialization CheckSizeMenu(ID_FILE_SIZE_NORMAL); ShowWindow(ghApp, SW_SHOWNORMAL); UpdateWindow(ghApp); SetForegroundWindow(ghApp); g_bFullscreen = FALSE; UpdateMainTitle(); #ifdef REGISTER_FILTERGRAPH hr = AddGraphToRot(pGB, &g_dwGraphRegister); if (FAILED(hr)) { Msg(TEXT("Failed to register filter graph with ROT! hr=0x%x"), hr); g_dwGraphRegister = 0; } #endif // Run the graph to play the media file JIF(pMC->Run()); g_psCurrent=Running; SetFocus(ghApp); } return hr; }