HRESULT GetRefTime( IFilterGraph* pIFilterGraph , REFERENCE_TIME* pref_time ) { if ( pIFilterGraph == NULL || pref_time == NULL ) { return E_POINTER; } IReferenceClock *pIRefClock = NULL; HRESULT hr = pIFilterGraph->QueryInterface( IID_IReferenceClock , (void**)&pIRefClock ); if ( FAILED(hr) ) { return hr; } return pIRefClock->GetTime( pref_time ); }
REFERENCE_TIME getTime() { LARGE_INTEGER tCurr; REFERENCE_TIME rtRet; QueryPerformanceCounterEmulation(&tCurr); if(pc2time(tCurr.QuadPart-tBase.QuadPart) > 60.0) { tBase = tCurr; prc->GetTime(&rtBase); } rtRet = rtBase + (REFERENCE_TIME)(pc2time(tCurr.QuadPart-tBase.QuadPart)*UNITS); if(rtRet < rtBefore) { rtRet = rtBefore; } rtBefore = rtRet; return rtRet; }
const bool CMediaViewer::OpenViewer(HWND hOwnerHwnd, HWND hMessageDrainHwnd, CVideoRenderer::RendererType RendererType, LPCWSTR pszVideoDecoder, LPCWSTR pszAudioDevice) { CTryBlockLock Lock(&m_DecoderLock); if (!Lock.TryLock(LOCK_TIMEOUT)) { SetError(TEXT("タイムアウトエラーです。")); return false; } if (m_bInit) { SetError(TEXT("既にフィルタグラフが構築されています。")); return false; } TRACE(TEXT("CMediaViewer::OpenViewer() フィルタグラフ作成開始\n")); HRESULT hr=S_OK; IPin *pOutput=NULL; IPin *pOutputVideo=NULL; IPin *pOutputAudio=NULL; try { // フィルタグラフマネージャを構築する hr=::CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER, IID_IGraphBuilder,pointer_cast<LPVOID*>(&m_pFilterGraph)); if (FAILED(hr)) { throw CBonException(hr,TEXT("フィルタグラフマネージャを作成できません。")); } #ifdef _DEBUG AddToRot(m_pFilterGraph, &m_dwRegister); #endif // IMediaControlインタフェースのクエリー hr=m_pFilterGraph->QueryInterface(IID_IMediaControl, pointer_cast<void**>(&m_pMediaControl)); if (FAILED(hr)) { throw CBonException(hr,TEXT("メディアコントロールを取得できません。")); } Trace(TEXT("ソースフィルタの接続中...")); /* CBonSrcFilter */ { // インスタンス作成 m_pSrcFilter = static_cast<CBonSrcFilter*>(CBonSrcFilter::CreateInstance(NULL, &hr)); if (m_pSrcFilter == NULL || FAILED(hr)) throw CBonException(hr, TEXT("ソースフィルタを作成できません。")); m_pSrcFilter->SetOutputWhenPaused(RendererType == CVideoRenderer::RENDERER_DEFAULT); // フィルタグラフに追加 hr = m_pFilterGraph->AddFilter(m_pSrcFilter, L"BonSrcFilter"); if (FAILED(hr)) throw CBonException(hr, TEXT("ソースフィルタをフィルタグラフに追加できません。")); // 出力ピンを取得 pOutput = DirectShowUtil::GetFilterPin(m_pSrcFilter, PINDIR_OUTPUT); if (pOutput==NULL) throw CBonException(TEXT("ソースフィルタの出力ピンを取得できません。")); m_pSrcFilter->EnableSync(m_bEnablePTSSync); } Trace(TEXT("MPEG-2 Demultiplexerフィルタの接続中...")); /* MPEG-2 Demultiplexer */ { CMediaType MediaTypeVideo; CMediaType MediaTypeAudio; IMpeg2Demultiplexer *pMpeg2Demuxer; hr=::CoCreateInstance(CLSID_MPEG2Demultiplexer,NULL, CLSCTX_INPROC_SERVER,IID_IBaseFilter, pointer_cast<LPVOID*>(&m_pMp2DemuxFilter)); if (FAILED(hr)) throw CBonException(hr,TEXT("MPEG-2 Demultiplexerフィルタを作成できません。"), TEXT("MPEG-2 Demultiplexerフィルタがインストールされているか確認してください。")); hr=DirectShowUtil::AppendFilterAndConnect(m_pFilterGraph, m_pMp2DemuxFilter,L"Mpeg2Demuxer",&pOutput); if (FAILED(hr)) throw CBonException(hr,TEXT("MPEG-2 Demultiplexerをフィルタグラフに追加できません。")); // この時点でpOutput==NULLのはずだが念のため SAFE_RELEASE(pOutput); // IMpeg2Demultiplexerインタフェースのクエリー hr=m_pMp2DemuxFilter->QueryInterface(IID_IMpeg2Demultiplexer, pointer_cast<void**>(&pMpeg2Demuxer)); if (FAILED(hr)) throw CBonException(hr,TEXT("MPEG-2 Demultiplexerインターフェースを取得できません。"), TEXT("互換性のないスプリッタの優先度がMPEG-2 Demultiplexerより高くなっている可能性があります。")); // 映像メディアフォーマット設定 hr = SetVideoMediaType(&MediaTypeVideo, 1920, 1080); if (FAILED(hr)) throw CBonException(TEXT("メモリが確保できません。")); // 映像出力ピン作成 hr = pMpeg2Demuxer->CreateOutputPin(&MediaTypeVideo, L"Video", &pOutputVideo); if (FAILED(hr)) { pMpeg2Demuxer->Release(); throw CBonException(hr, TEXT("MPEG-2 Demultiplexerの映像出力ピンを作成できません。")); } // 音声メディアフォーマット設定 MediaTypeAudio.InitMediaType(); MediaTypeAudio.SetType(&MEDIATYPE_Audio); MediaTypeAudio.SetSubtype(&MEDIASUBTYPE_NULL); MediaTypeAudio.SetVariableSize(); MediaTypeAudio.SetTemporalCompression(TRUE); MediaTypeAudio.SetSampleSize(0); MediaTypeAudio.SetFormatType(&FORMAT_None); // 音声出力ピン作成 hr=pMpeg2Demuxer->CreateOutputPin(&MediaTypeAudio,L"Audio",&pOutputAudio); pMpeg2Demuxer->Release(); if (FAILED(hr)) throw CBonException(hr,TEXT("MPEG-2 Demultiplexerの音声出力ピンを作成できません。")); // 映像出力ピンのIMPEG2PIDMapインタフェースのクエリー hr=pOutputVideo->QueryInterface(__uuidof(IMPEG2PIDMap),pointer_cast<void**>(&m_pMp2DemuxVideoMap)); if (FAILED(hr)) throw CBonException(hr,TEXT("映像出力ピンのIMPEG2PIDMapを取得できません。")); // 音声出力ピンのIMPEG2PIDMapインタフェースのクエリ hr=pOutputAudio->QueryInterface(__uuidof(IMPEG2PIDMap),pointer_cast<void**>(&m_pMp2DemuxAudioMap)); if (FAILED(hr)) throw CBonException(hr,TEXT("音声出力ピンのIMPEG2PIDMapを取得できません。")); } #ifndef BONTSENGINE_H264_SUPPORT Trace(TEXT("MPEG-2パーサフィルタの接続中...")); /* CMpeg2ParserFilter */ { // インスタンス作成 m_pMpeg2Parser = static_cast<CMpeg2ParserFilter*>(CMpeg2ParserFilter::CreateInstance(NULL, &hr)); if ((!m_pMpeg2Parser) || FAILED(hr)) throw CBonException(hr,TEXT("MPEG-2パーサフィルタを作成できません。")); m_pMpeg2Parser->SetVideoInfoCallback(OnVideoInfo,this); // madVR は映像サイズの変化時に MediaType を設定しないと新しいサイズが適用されない m_pMpeg2Parser->SetAttachMediaType(RendererType==CVideoRenderer::RENDERER_madVR); // フィルタの追加と接続 hr=DirectShowUtil::AppendFilterAndConnect( m_pFilterGraph,m_pMpeg2Parser,L"Mpeg2ParserFilter",&pOutputVideo); if (FAILED(hr)) throw CBonException(hr,TEXT("MPEG-2パーサフィルタをフィルタグラフに追加できません。")); } #else Trace(TEXT("H.264パーサフィルタの接続中...")); /* CH264ParserFilter */ { // インスタンス作成 m_pH264Parser = static_cast<CH264ParserFilter*>(CH264ParserFilter::CreateInstance(NULL, &hr)); if ((!m_pH264Parser) || FAILED(hr)) throw CBonException(TEXT("H.264パーサフィルタを作成できません。")); m_pH264Parser->SetVideoInfoCallback(OnVideoInfo,this); m_pH264Parser->SetAdjustTime(m_bAdjustVideoSampleTime); m_pH264Parser->SetAdjustFrameRate(m_bAdjustFrameRate); // madVR は映像サイズの変化時に MediaType を設定しないと新しいサイズが適用されない m_pH264Parser->SetAttachMediaType(RendererType==CVideoRenderer::RENDERER_madVR); // フィルタの追加と接続 hr=DirectShowUtil::AppendFilterAndConnect( m_pFilterGraph,m_pH264Parser,L"H264ParserFilter",&pOutputVideo); if (FAILED(hr)) throw CBonException(hr,TEXT("H.264パーサフィルタをフィルタグラフに追加できません。")); } #endif // BONTSENGINE_H264_SUPPORT Trace(TEXT("音声デコーダの接続中...")); #if 1 /* CAudioDecFilter */ { // CAudioDecFilterインスタンス作成 m_pAudioDecoder = static_cast<CAudioDecFilter*>(CAudioDecFilter::CreateInstance(NULL, &hr)); if (!m_pAudioDecoder || FAILED(hr)) throw CBonException(hr,TEXT("音声デコーダフィルタを作成できません。")); // フィルタの追加と接続 hr=DirectShowUtil::AppendFilterAndConnect( m_pFilterGraph,m_pAudioDecoder,L"AudioDecFilter",&pOutputAudio); if (FAILED(hr)) throw CBonException(hr,TEXT("音声デコーダフィルタをフィルタグラフに追加できません。")); m_pAudioDecoder->SetJitterCorrection(m_bAdjustAudioStreamTime); if (m_pAudioStreamCallback) m_pAudioDecoder->SetStreamCallback(m_pAudioStreamCallback, m_pAudioStreamCallbackParam); } #else /* 外部AACデコーダを利用すると、チャンネル数が切り替わった際に音が出なくなる、 デュアルモノラルがステレオとして再生される、といった問題が出る */ /* CAacParserFilter */ { CAacParserFilter *m_pAacParser; // CAacParserFilterインスタンス作成 m_pAacParser=static_cast<CAacParserFilter*>(CAacParserFilter::CreateInstance(NULL, &hr)); if (!m_pAacParser || FAILED(hr)) throw CBonException(hr,TEXT("AACパーサフィルタを作成できません。")); // フィルタの追加と接続 hr=DirectShowUtil::AppendFilterAndConnect( m_pFilterGraph,m_pAacParser,L"AacParserFilter",&pOutputAudio); if (FAILED(hr)) throw CBonException(TEXT("AACパーサフィルタをフィルタグラフに追加できません。")); m_pAacParser->Release(); } /* AACデコーダー */ { CDirectShowFilterFinder FilterFinder; // 検索 if(!FilterFinder.FindFilter(&MEDIATYPE_Audio,&MEDIASUBTYPE_AAC)) throw CBonException(TEXT("AACデコーダが見付かりません。"), TEXT("AACデコーダがインストールされているか確認してください。")); WCHAR szAacDecoder[128]; CLSID idAac; bool bConnectSuccess=false; IBaseFilter *pAacDecFilter=NULL; for (int i=0;i<FilterFinder.GetFilterCount();i++){ if (FilterFinder.GetFilterInfo(i,&idAac,szAacDecoder,128)) { if (pszAudioDecoder!=NULL && pszAudioDecoder[0]!='\0' && ::lstrcmpi(szAacDecoder,pszAudioDecoder)!=0) continue; hr=DirectShowUtil::AppendFilterAndConnect(m_pFilterGraph, idAac,szAacDecoder,&pAacDecFilter, &pOutputAudio); if (SUCCEEDED(hr)) { TRACE(TEXT("AAC decoder connected : %s\n"),szAacDecoder); bConnectSuccess=true; break; } } } // どれかのフィルタで接続できたか if (bConnectSuccess) { SAFE_RELEASE(pAacDecFilter); //m_pszAacDecoderName=StdUtil::strdup(szAacDecoder); } else { throw CBonException(TEXT("AACデコーダフィルタをフィルタグラフに追加できません。"), TEXT("設定で有効なAACデコーダが選択されているか確認してください。")); } } #endif /* ユーザー指定の音声フィルタの接続 */ if (m_pszAudioFilterName) { Trace(TEXT("音声フィルタの接続中...")); // 検索 bool bConnectSuccess=false; CDirectShowFilterFinder FilterFinder; if (FilterFinder.FindFilter(&MEDIATYPE_Audio,&MEDIASUBTYPE_PCM)) { WCHAR szAudioFilter[128]; CLSID idAudioFilter; for (int i=0;i<FilterFinder.GetFilterCount();i++) { if (FilterFinder.GetFilterInfo(i,&idAudioFilter,szAudioFilter,128)) { if (::lstrcmpi(m_pszAudioFilterName,szAudioFilter)!=0) continue; hr=DirectShowUtil::AppendFilterAndConnect(m_pFilterGraph, idAudioFilter,szAudioFilter,&m_pAudioFilter, &pOutputAudio,NULL,true); if (SUCCEEDED(hr)) { TRACE(TEXT("音声フィルタ接続 : %s\n"),szAudioFilter); bConnectSuccess=true; } break; } } } if (!bConnectSuccess) { throw CBonException(hr, TEXT("音声フィルタをフィルタグラフに追加できません。"), TEXT("音声フィルタが利用できないか、音声デバイスに対応していない可能性があります。")); } } #ifndef BONTSENGINE_H264_SUPPORT Trace(TEXT("MPEG-2デコーダの接続中...")); /* Mpeg2デコーダー */ { CDirectShowFilterFinder FilterFinder; // 検索 if(!FilterFinder.FindFilter(&MEDIATYPE_Video,&MEDIASUBTYPE_MPEG2_VIDEO)) throw CBonException(TEXT("MPEG-2デコーダが見付かりません。"), TEXT("MPEG-2デコーダがインストールされているか確認してください。")); WCHAR szMpeg2Decoder[128]; CLSID idMpeg2Vid; bool bConnectSuccess=false; for (int i=0;i<FilterFinder.GetFilterCount();i++){ if (FilterFinder.GetFilterInfo(i,&idMpeg2Vid,szMpeg2Decoder,128)) { if (pszVideoDecoder!=NULL && pszVideoDecoder[0]!='\0' && ::lstrcmpi(szMpeg2Decoder,pszVideoDecoder)!=0) continue; hr=DirectShowUtil::AppendFilterAndConnect(m_pFilterGraph, idMpeg2Vid,szMpeg2Decoder,&m_pVideoDecoderFilter, &pOutputVideo,NULL,true); if (SUCCEEDED(hr)) { bConnectSuccess=true; break; } } } // どれかのフィルタで接続できたか if (bConnectSuccess) { m_pszVideoDecoderName=StdUtil::strdup(szMpeg2Decoder); } else { throw CBonException(hr,TEXT("MPEG-2デコーダフィルタをフィルタグラフに追加できません。"), TEXT("設定で有効なMPEG-2デコーダが選択されているか確認してください。\nまた、レンダラを変えてみてください。")); } } #ifndef MPEG2PARSERFILTER_INPLACE /* CyberLinkのデコーダとデフォルトレンダラの組み合わせで 1080x1080(4:3)の映像が正方形に表示される問題に対応 …しようと思ったが変になるので保留 */ if (::StrStrI(m_pszVideoDecoderName, TEXT("CyberLink")) != NULL) m_pMpeg2Parser->SetFixSquareDisplay(true); #endif #else // ndef BONTSENGINE_H264_SUPPORT Trace(TEXT("H.264デコーダの接続中...")); /* H.264デコーダー */ { CDirectShowFilterFinder FilterFinder; // 検索 if(!FilterFinder.FindFilter(&MEDIATYPE_Video,&MEDIASUBTYPE_H264)) throw CBonException(TEXT("H.264デコーダが見付かりません。"), TEXT("H.264デコーダがインストールされているか確認してください。")); WCHAR szH264Decoder[128]; CLSID idH264Decoder; bool bConnectSuccess=false; for (int i=0;i<FilterFinder.GetFilterCount();i++){ if (FilterFinder.GetFilterInfo(i,&idH264Decoder,szH264Decoder,128)) { if (pszVideoDecoder!=NULL && pszVideoDecoder[0]!='\0' && ::lstrcmpi(szH264Decoder,pszVideoDecoder)!=0) continue; hr=DirectShowUtil::AppendFilterAndConnect(m_pFilterGraph, idH264Decoder,szH264Decoder,&m_pVideoDecoderFilter, &pOutputVideo,NULL,true); if (SUCCEEDED(hr)) { bConnectSuccess=true; break; } } } // どれかのフィルタで接続できたか if (bConnectSuccess) { m_pszVideoDecoderName=StdUtil::strdup(szH264Decoder); } else { throw CBonException(hr,TEXT("H.264デコーダフィルタをフィルタグラフに追加できません。"), TEXT("設定で有効なH.264デコーダが選択されているか確認してください。\nまた、レンダラを変えてみてください。")); } } #endif // BONTSENGINE_H264_SUPPORT Trace(TEXT("映像レンダラの構築中...")); if (!CVideoRenderer::CreateRenderer(RendererType,&m_pVideoRenderer)) { throw CBonException(TEXT("映像レンダラを作成できません。"), TEXT("設定で有効なレンダラが選択されているか確認してください。")); } if (!m_pVideoRenderer->Initialize(m_pFilterGraph,pOutputVideo, hOwnerHwnd,hMessageDrainHwnd)) { throw CBonException(m_pVideoRenderer->GetLastErrorException()); } m_VideoRendererType=RendererType; Trace(TEXT("音声レンダラの構築中...")); // 音声レンダラ構築 { bool fOK = false; if (pszAudioDevice != NULL && pszAudioDevice[0] != '\0') { CDirectShowDeviceEnumerator DevEnum; if (DevEnum.CreateFilter(CLSID_AudioRendererCategory, pszAudioDevice, &m_pAudioRenderer)) { m_pszAudioRendererName=StdUtil::strdup(pszAudioDevice); fOK = true; } } if (!fOK) { hr = ::CoCreateInstance(CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, pointer_cast<LPVOID*>(&m_pAudioRenderer)); if (SUCCEEDED(hr)) { m_pszAudioRendererName=StdUtil::strdup(TEXT("DirectSound Renderer")); fOK = true; } } if (fOK) { hr = DirectShowUtil::AppendFilterAndConnect(m_pFilterGraph, m_pAudioRenderer, L"Audio Renderer", &pOutputAudio); if (SUCCEEDED(hr)) { #ifdef _DEBUG if (pszAudioDevice != NULL && pszAudioDevice[0] != '\0') TRACE(TEXT("音声デバイス %s を接続\n"), pszAudioDevice); #endif if (m_bUseAudioRendererClock) { IMediaFilter *pMediaFilter; if (SUCCEEDED(m_pFilterGraph->QueryInterface(IID_IMediaFilter, pointer_cast<void**>(&pMediaFilter)))) { IReferenceClock *pReferenceClock; if (SUCCEEDED(m_pAudioRenderer->QueryInterface(IID_IReferenceClock, pointer_cast<void**>(&pReferenceClock)))) { pMediaFilter->SetSyncSource(pReferenceClock); pReferenceClock->Release(); TRACE(TEXT("グラフのクロックに音声レンダラを選択\n")); } pMediaFilter->Release(); } } fOK = true; } else { fOK = false; } if (!fOK) { hr = m_pFilterGraph->Render(pOutputAudio); if (FAILED(hr)) throw CBonException(hr, TEXT("音声レンダラを接続できません。"), TEXT("設定で有効な音声デバイスが選択されているか確認してください。")); } } else { // 音声デバイスが無い? // Nullレンダラを繋げておく hr = ::CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, pointer_cast<LPVOID*>(&m_pAudioRenderer)); if (SUCCEEDED(hr)) { hr = DirectShowUtil::AppendFilterAndConnect(m_pFilterGraph, m_pAudioRenderer, L"Null Audio Renderer", &pOutputAudio); if (FAILED(hr)) { throw CBonException(hr, TEXT("Null音声レンダラを接続できません。")); } m_pszAudioRendererName=StdUtil::strdup(TEXT("Null Renderer")); TRACE(TEXT("Nullレンダラを接続\n")); } } } /* デフォルトでMPEG-2 Demultiplexerがグラフのクロックに 設定されるらしいが、一応設定しておく */ if (!m_bUseAudioRendererClock) { IMediaFilter *pMediaFilter; if (SUCCEEDED(m_pFilterGraph->QueryInterface( IID_IMediaFilter,pointer_cast<void**>(&pMediaFilter)))) { IReferenceClock *pReferenceClock; if (SUCCEEDED(m_pMp2DemuxFilter->QueryInterface( IID_IReferenceClock,pointer_cast<void**>(&pReferenceClock)))) { pMediaFilter->SetSyncSource(pReferenceClock); pReferenceClock->Release(); TRACE(TEXT("グラフのクロックにMPEG-2 Demultiplexerを選択\n")); } pMediaFilter->Release(); } } // オーナウィンドウ設定 m_hOwnerWnd = hOwnerHwnd; RECT rc; ::GetClientRect(hOwnerHwnd, &rc); m_wVideoWindowX = (WORD)rc.right; m_wVideoWindowY = (WORD)rc.bottom; m_bInit=true; ULONG PID; if (m_wVideoEsPID != PID_INVALID) { PID = m_wVideoEsPID; if (FAILED(m_pMp2DemuxVideoMap->MapPID(1, &PID, MEDIA_ELEMENTARY_STREAM))) m_wVideoEsPID = PID_INVALID; } if (m_wAudioEsPID != PID_INVALID) { PID = m_wAudioEsPID; if (FAILED(m_pMp2DemuxAudioMap->MapPID(1, &PID, MEDIA_ELEMENTARY_STREAM))) m_wAudioEsPID = PID_INVALID; } } catch (CBonException &Exception) { SetError(Exception); if (Exception.GetErrorCode()!=0) { TCHAR szText[MAX_ERROR_TEXT_LEN+32]; int Length; Length=::AMGetErrorText(Exception.GetErrorCode(),szText,MAX_ERROR_TEXT_LEN); ::wsprintf(szText+Length,TEXT("\nエラーコード(HRESULT) 0x%08X"),Exception.GetErrorCode()); SetErrorSystemMessage(szText); } SAFE_RELEASE(pOutput); SAFE_RELEASE(pOutputVideo); SAFE_RELEASE(pOutputAudio); CloseViewer(); TRACE(TEXT("フィルタグラフ構築失敗 : %s\n"), GetLastErrorText()); return false; } SAFE_RELEASE(pOutputVideo); SAFE_RELEASE(pOutputAudio); ClearError(); TRACE(TEXT("フィルタグラフ構築成功\n")); return true; }