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 は難しくてそこまで手が回りませんので今後の課題と致します。
以上です。