Tips #031 Vista & DirectShow の MPEG-2 フリーズエラー対策
何とかフリーズ対策できました
フィルタ情報およびピン情報から当該メディアが MPEG-2 形式であるかどうか分りました。
しかしピン情報では MP4 も MPEG-2 形式となるみたいでした。
MP4 はサードパーティのデコーダしか対応してないので問題ありません。
問題なのは Vista の MPEG-2 デコーダなのでフィルタ名称の方で判定してはじくようにしました。
それは "Microsoft MPEG-2 Video Decoder" という名前でした。
BOOL MovieView :: OpenFile( LPCTSTR path ) { WCHAR wtext[ _MAX_PATH ]; TCHAR text[ _MAX_PATH ]; BOOL result = TRUE; IEnumFilters * pEnum = NULL; IBaseFilter * pFilter = NULL; FILTER_INFO filterInfo; RECT rc; SIZE size; REFTIME frame; LONGLONG seek, stop; LONG tmax; INT list[ 2 ]; if ( FAILED( CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, ( void ** ) & pGraph ) ) || pGraph == NULL ) { result = FALSE; } else { MultiByteToWideChar( CP_ACP, 0, path, -1, wtext, sizeof wtext / sizeof ( WCHAR ) ); if ( FAILED( pGraph->RenderFile( wtext, NULL ) ) ) { result = FALSE; } else { if ( FAILED( pGraph->EnumFilters( & pEnum ) ) && pEnum != NULL ) { result = FALSE; } else { pEnum->Reset(); while ( result && SUCCEEDED( pEnum->Next( 1, & pFilter, NULL ) ) && pFilter != NULL ) { if ( SUCCEEDED( pFilter->QueryFilterInfo( & filterInfo ) ) ) { WideCharToMultiByte( CP_ACP, 0, filterInfo.achName, -1, text, sizeof text / sizeof ( TCHAR ), NULL, NULL ); if ( strcmp( text, _T( "Microsoft MPEG-2 Video Decoder" ) ) == 0 ) { MessageBox( hwnd, _T( "Microsoft MPEG-2 Video Decoder は再生できません" ), pszAppName, MB_ICONINFORMATION ); result = FALSE; } if ( filterInfo.pGraph != NULL ) { filterInfo.pGraph->Release(); } } pFilter->Release(); pFilter = NULL; } pEnum->Release(); pEnum = NULL; } } } if ( result && SUCCEEDED( pGraph->QueryInterface( IID_IBasicAudio, ( void ** ) & pAudio ) ) && SUCCEEDED( pGraph->QueryInterface( IID_IBasicVideo2, ( void ** ) & pVideo ) ) && SUCCEEDED( pGraph->QueryInterface( IID_IVideoWindow, ( void ** ) & pWindow ) ) && SUCCEEDED( pGraph->QueryInterface( IID_IVideoFrameStep, ( void ** ) & pStep ) ) && SUCCEEDED( pGraph->QueryInterface( IID_IMediaControl, ( void ** ) & pControl ) ) && SUCCEEDED( pGraph->QueryInterface( IID_IMediaSeeking, ( void ** ) & pSeeking ) ) && SUCCEEDED( pGraph->QueryInterface( IID_IMediaEventEx, ( void ** ) & pEvent ) ) ) { pVideo->GetVideoSize( & size.cx, & size.cy ); pVideo->get_AvgTimePerFrame( & frame ); pWindow->put_WindowStyle( WS_CHILD | WS_CLIPSIBLINGS ); pWindow->put_Owner( ( OAHWND ) hwnd ); pWindow->put_MessageDrain( ( OAHWND ) hwnd ); pSeeking->GetPositions( & seek, & stop ); if ( stop > 0 ) { if ( frame != 0.0f ) { nFrame = ( LONGLONG ) ( frame * 10000000 ); } else { bChecking = TRUE; dwTime = timeGetTime(); } tmax = ( LONG ) ( stop / nFrame ); SendMessage( hTrackBar, TBM_SETRANGEMAX, FALSE, tmax ); } GetClientRect( pApp->hStatBar, & rc ); list[ 0 ] = ( rc.right - rc.left ) - ( sizeFont.cx * ( nColumn * 2 + 3 ) ) - 2 * GetSystemMetrics( SM_CXDLGFRAME ); list[ 1 ] = -1; SendMessage( pApp->hStatBar, WM_SETFONT, ( WPARAM ) pApp->hFixedFont, 0 ); SendMessage( pApp->hStatBar, SB_SETPARTS, 2, ( LPARAM ) & list ); GetWindowRect( hTrackBar, & rc ); nFullWidth = size.cx; nFullHeight = size.cy + ( rc.bottom - rc.top ); for ( nColumn = 0; tmax > 0; tmax /= 10 ) { nColumn++; } UpdateSize(); pEvent->SetNotifyWindow( ( OAHWND ) hwnd, WM_GRAPHNOTIFY, 0 ); pControl->Run(); StartTimer(); return TRUE; } return FALSE; }
MPEG-2 フィルタをサードパーティのに変えてやれば Vista でも再生可能かと思われますが、
何しろ DirectShow は難しくてそこまで手が回りませんので今後の課題と致します。
以上です。