Mesoscopic Programming

タコさんプログラミング専門

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

以上です。