locked
IMFMediaEventGenerator interface RRS feed

  • Question

  • Hi,

      I'm working on the implementation of "Play Unprotected Media Files".
      But, I always get an E_INVALIDARG HRESULT when I'm trying to get the events from the media session, my code look like this:

        HRESULT hr = S_OK;  
        IMFMediaEvent **ppEvent = NULL;  
        // Get the status of the asynchronous operations,  
        hr = ppSession->GetEvent(MF_EVENT_FLAG_NO_WAIT, ppEvent);  
        if(hr ==  E_INVALIDARG)  
            MessageBox(NULL, _T("NULL pointer argument"), _T(""), MB_OK); 

    ppSession is the IMFMediaSession pointer. I Previously did the four steps mentionated in the link above and everything was okay, I also set the topology successfuly. I'm using a .wmv file as my media source (this video works perfectly when I run it using the MFPlay api).

    Any idea is really welcome.

    Thanks in advance.
    Enby.
    Tuesday, March 10, 2009 8:29 PM

Answers

  • In case you would only be targeting Win7, it would actually be much easier to play files using MFPlay.

    The main issue with the code is that it calls IMFMediaSession::Close() right after IMFMediaSession::Start(). Since Start() is asynchronous, the playback is ended before playing anything. The code needs to process events coming from IMFMediaSession and wait for MESessionEnded.

    A couple of other issues (maybe due to the fact that this is only a snippet):
    • the code is leaking memory. Release() needs to be called on all the objects created by MF. This is usually done by calling macros like SAFE_RELEASE or using smart pointers like ATL's CComPtr. IMHO the latter is easier to use (but has some tricks).
    • the function should clean up and exit when a call to some MF function fails (like in the function skeleton given here), otherwise the app may crash (ex: if MFCreateMediaSession() fails in the snippet, ppSession will be NULL and the call to ppSession->Close() will crash).
    • there is no need to wait for events after the call to SetTopology() (except maybe if the topology is needed at some later point).
    • the notation "pp" in "ppSession" means double pointer (ex: IMFMediaSession**), so in the snippet this variable should actually be called "pSession".

    Here is a code sample to playback a video file (it's only a proof of concept; it's a command-line app and it doesn't even process window messages):

    #include <stdio.h>  
    #include <atlbase.h>
    #include <mfapi.h>  
    #include <mfidl.h>  
     
    // some macros  
    #define CHECK_HR(_hr) { hr = (_hr); if( FAILED(hr) ) { wprintf( L"'" L#_hr L"' failed with error code 0x%08lx\n", hr ); goto done; } }
    #define CHECK_NULL(_val, _hr) { if( !(_val) ) { hr = (_hr); wprintf( L"'" L#_val L"' failed with error code 0x%08lx\n", hr ); goto done; } }  
    #define GETLASTHR HRESULT_FROM_WIN32(GetLastError())  
     
    HRESULT PlayUnprotectedMediaFiles( const WCHAR* pwszURL, HWND hwnd )  
    {  
        HRESULT hr = S_OK;  
        CComPtr<IMFMediaSession> spSession;  
        CComPtr<IMFSourceResolver> spSourceResolver;  
        CComPtr<IMFMediaSource> spSource;  
        CComPtr<IUnknown> spSourceUnk;  
        CComPtr<IMFTopology> spTopology;  
        CComPtr<IMFPresentationDescriptor> spPD;  
        MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;  
        DWORD cStreams = 0;  
        PROPVARIANT propvar;  
        PropVariantInit(&propvar);  
     
        //  
        // Create the media session  
        //  
     
        CHECK_HR( CoInitialize( NULL ) );  
        CHECK_HR( MFStartup(MF_VERSION) );  
          
        CHECK_HR( MFCreateMediaSession( NULL, &spSession ) );  
        
        //  
        // Create the media source  
        //  
     
        CHECK_HR( MFCreateSourceResolver( &spSourceResolver ) );  
     
        CHECK_HR( spSourceResolver->CreateObjectFromURL(  
            pwszURL,  
            MF_RESOLUTION_MEDIASOURCE,  
            NULL,  
            &ObjectType,  
            &spSourceUnk  
            ) );  
     
        CHECK_HR( spSourceUnk.QueryInterface( &spSource ) );  
     
        //  
        // Create the topology  
        //  
     
        CHECK_HR( MFCreateTopology(&spTopology) );  
     
        CHECK_HR( spSource->CreatePresentationDescriptor(&spPD) );  
        CHECK_HR( spPD->GetStreamDescriptorCount(&cStreams) );  
     
        for (DWORD iStream = 0; iStream < cStreams; iStream++)  
        {  
            CComPtr<IMFStreamDescriptor> spSD;  
            CComPtr<IMFMediaTypeHandler> spHandler;  
            CComPtr<IMFActivate> spActivate;  
            CComPtr<IMFTopologyNode> spSourceNode;  
            CComPtr<IMFTopologyNode> spOutputNode;  
            BOOL fSelected = FALSE;  
            GUID guidMajorType = GUID_NULL;  
     
            CHECK_HR( spPD->GetStreamDescriptorByIndex( iStream, &fSelected, &spSD ) );  
     
            if( !fSelected )  
            {  
                continue;  
            }  
     
            //  
            // Create an IMFActivate object for the renderer sink, based on the media type.  
            //  
     
            CHECK_HR( spSD->GetMediaTypeHandler(&spHandler) );  
            CHECK_HR( spHandler->GetMajorType(&guidMajorType) );  
       
            if( MFMediaType_Audio == guidMajorType )  
            {  
                CHECK_HR( MFCreateAudioRendererActivate( &spActivate ) );  
            }  
            else if( MFMediaType_Video == guidMajorType )  
            {  
                CHECK_HR( MFCreateVideoRendererActivate( hwnd, &spActivate ) );  
            }  
            else 
            {  
                continue// ignore stream  
            }  
     
            //  
            // Create the source node  
            //  
     
            CHECK_HR( MFCreateTopologyNode( MF_TOPOLOGY_SOURCESTREAM_NODE, &spSourceNode ) );  
            CHECK_HR( spSourceNode->SetUnknown( MF_TOPONODE_SOURCE, spSource ) );  
            CHECK_HR( spSourceNode->SetUnknown( MF_TOPONODE_PRESENTATION_DESCRIPTOR, spPD ) );  
            CHECK_HR( spSourceNode->SetUnknown( MF_TOPONODE_STREAM_DESCRIPTOR, spSD ) );  
            CHECK_HR( spTopology->AddNode( spSourceNode ) );  
     
            //  
            // Create the output node  
            //  
     
            CHECK_HR( MFCreateTopologyNode( MF_TOPOLOGY_OUTPUT_NODE, &spOutputNode ) );  
            CHECK_HR( spOutputNode->SetObject( spActivate ) );  
            CHECK_HR( spTopology->AddNode( spOutputNode ) );  
     
            //  
            // Connect the two nodes (adds intermediate MFTs as necessary)  
            //  
     
            CHECK_HR( spSourceNode->ConnectOutput( 0, spOutputNode, 0));  
        }  
     
        CHECK_HR( spSession->SetTopology( 0, spTopology ) );  
     
        //  
        // Start playback  
        //  
     
        CHECK_HR( spSession->Start( NULL, &propvar ) );  
     
        //  
        // Wait for playback to end  
        // --  
        // Note: call asynchronous BeginGetEvent() if the thread shouldn't get blocked  
        //  
     
        while( TRUE )  
        {  
            CComPtr<IMFMediaEvent> spEvent;  
            MediaEventType type;  
            HRESULT hrStatus;  
     
            CHECK_HR( spSession->GetEvent( 0, &spEvent ) );  
     
            CHECK_HR( spEvent->GetStatus( &hrStatus ) );  
            CHECK_HR( spEvent->GetType( &type ) );  
     
            wprintf( L"Received event %li (hr = 0x%08lx)\n", type, hrStatus );  
     
            CHECK_HR( hrStatus );  
     
            if( MESessionEnded == type )  
            {  
                break;  
            }  
        }  
     
    done:  
        if( spSource )  
        {  
            spSource->Shutdown();  
        }  
        if( spSession )  
        {  
            spSession->Shutdown();  
        }  
     
        (void) MFShutdown();  
        CoUninitialize();  
     
        PropVariantClear(&propvar);    
     
        return hr;  
    }  
     
    int __cdecl wmain(int argc, LPCTSTR argv[])  
    {  
        HRESULT hr = S_OK;  
        HWND hwnd = NULL;  
     
        //  
        // Create a window  
        //  
     
        WNDCLASS wndClass;  
        ZeroMemory(&wndClass, sizeof(wndClass));  
        wndClass.style = CS_HREDRAW | CS_VREDRAW;  
        wndClass.lpfnWndProc = DefWindowProc;  
        wndClass.lpszClassName = L"Test Window";  
        (void) RegisterClass(&wndClass);  
     
        hwnd = CreateWindow(  
            wndClass.lpszClassName,   
            L"Test Window",   
            WS_OVERLAPPED,  
            CW_USEDEFAULT,   
            0,   
            CW_USEDEFAULT,   
            0,   
            NULL,   
            NULL,   
            NULL,   
            NULL);  
        CHECK_NULL( hwnd, GETLASTHR );  
     
        (void) ShowWindow( hwnd, TRUE );  
        (void) UpdateWindow( hwnd );  
     
        //  
        // Play the video  
        //  
     
        CHECK_HR( PlayUnprotectedMediaFiles( L"Bear.wmv", hwnd ) );  
     
    done:  
        if( hwnd )  
        {  
            (void) DestroyWindow( hwnd );  
        }  
     
        return FAILED( hr );  
    }  
     
    • Marked as answer by Mike Wasson Monday, March 23, 2009 3:48 PM
    Thursday, March 19, 2009 9:04 PM

All replies

  • should be:

    IMFMediaEvent *pEvent = NULL;     
          
    hr = ppSession->GetEvent(MF_EVENT_FLAG_NO_WAIT, &pEvent);   
     


    - Mike
    Mike Wasson (SDK Documentation)
    Wednesday, March 11, 2009 3:58 PM
  •  
     Thanks Mike, yes the problem was the pointer parameter.
     but now I have another problem :(, I already implemented all the steps mentioned on the "Play Unprotected Media Files".

    But it seems like when the program execution comes to Starts the media session something happens and all my machine is totally freeze, and I need to restart it.

    My code looks like this:

    void PlayUnprotectedMediaFiles(void)  
    {  
        if(MFStartup(MF_VERSION) == S_OK)  
            MessageBox(NULL, _T("Media Foundation was initialized :D!"), _T(""), MB_OK);  
     
        IMFAttributes *pConfig = NULL;  
        IMFMediaSession *ppSession = NULL;  
     
        if(MFCreateMediaSession(pConfig, &ppSession) == S_OK)  
                MessageBox(NULL, _T("MFCreateMediaSession done"), _T(""), MB_OK);  
     
        // Creating the Media Source  
        const WCHAR *sURL = L"C:\\Butterfly.wmv";  
        IMFMediaSource *pSource = NULL;  
     
        if(CreateMediaSource(sURL, &pSource) == S_OK)  
            MessageBox(NULL, _T("CreateMediaSource done"), _T(""), MB_OK);  
     
        IMFTopology *pTopology = NULL;  
        if(CreatePlaybackTopology(pSource, wndHandle, &pTopology) == S_OK)  
            MessageBox(NULL, _T("CreatePlaybackTopology done"), _T(""), MB_OK);  
     
        // Queue the topology on the media session (This method is asynchronous)  
        if(ppSession->SetTopology(0, pTopology) == S_OK)  
            MessageBox(NULL, _T("SetTopology done"), _T(""), MB_OK);  
     
        HRESULT hr = S_OK;  
        IMFMediaEvent *pEvent = NULL;  
        // Get the status of the asynchronous operations,  
        hr = ppSession->GetEvent(MF_EVENT_FLAG_NO_WAIT, &pEvent);  
        if(hr ==  S_OK)  
            MessageBox(NULL, _T("GetEvent done"), _T(""), MB_OK);  
     
        hr = GetTopologyFromEvent(pEvent, &pTopology);  
        if(hr ==  S_OK)  
            MessageBox(NULL, _T("GetTopologyFromEvent done"), _T(""), MB_OK);  
              
        // Starts the media session  
        hr = StartMediaSession(ppSession);  
        if(hr ==  S_OK)  
            MessageBox(NULL, _T("StartMediaSession done"), _T(""), MB_OK);    
     
        //Closing Media Session  
        ppSession->Close();  
        // Shutdown the Media Source  
        pSource->Shutdown();  
        // Shutdown the Media Source  
        ppSession->Shutdown();  
        // Shutdown Media Foundation  
        MFShutdown();  

    I can see all the messages but the last one "StartMediaSession done", my StartMediaSession function is as follows:
    HRESULT StartMediaSession(IMFMediaSession *ppSession)  
    {         
        HRESULT hr = S_OK;  
     
        PROPVARIANT pvar;  
        PropVariantInit(&pvar);  
     
        hr = ppSession->Start(NULL, &pvar);  
          
        PropVariantClear(&pvar);  
        return hr;  


    Do you know if I need to do something else before call the StartMediaSession function?
    I'm debugging the code and the only that I know is that hr variable on the StartMediaSession has an S_OK but after this all is freeze.

    If you have any suggestion or comment please let me know.
    Thanks in advance.
    -Enby.
    Wednesday, March 11, 2009 8:33 PM
  • In case you would only be targeting Win7, it would actually be much easier to play files using MFPlay.

    The main issue with the code is that it calls IMFMediaSession::Close() right after IMFMediaSession::Start(). Since Start() is asynchronous, the playback is ended before playing anything. The code needs to process events coming from IMFMediaSession and wait for MESessionEnded.

    A couple of other issues (maybe due to the fact that this is only a snippet):
    • the code is leaking memory. Release() needs to be called on all the objects created by MF. This is usually done by calling macros like SAFE_RELEASE or using smart pointers like ATL's CComPtr. IMHO the latter is easier to use (but has some tricks).
    • the function should clean up and exit when a call to some MF function fails (like in the function skeleton given here), otherwise the app may crash (ex: if MFCreateMediaSession() fails in the snippet, ppSession will be NULL and the call to ppSession->Close() will crash).
    • there is no need to wait for events after the call to SetTopology() (except maybe if the topology is needed at some later point).
    • the notation "pp" in "ppSession" means double pointer (ex: IMFMediaSession**), so in the snippet this variable should actually be called "pSession".

    Here is a code sample to playback a video file (it's only a proof of concept; it's a command-line app and it doesn't even process window messages):

    #include <stdio.h>  
    #include <atlbase.h>
    #include <mfapi.h>  
    #include <mfidl.h>  
     
    // some macros  
    #define CHECK_HR(_hr) { hr = (_hr); if( FAILED(hr) ) { wprintf( L"'" L#_hr L"' failed with error code 0x%08lx\n", hr ); goto done; } }
    #define CHECK_NULL(_val, _hr) { if( !(_val) ) { hr = (_hr); wprintf( L"'" L#_val L"' failed with error code 0x%08lx\n", hr ); goto done; } }  
    #define GETLASTHR HRESULT_FROM_WIN32(GetLastError())  
     
    HRESULT PlayUnprotectedMediaFiles( const WCHAR* pwszURL, HWND hwnd )  
    {  
        HRESULT hr = S_OK;  
        CComPtr<IMFMediaSession> spSession;  
        CComPtr<IMFSourceResolver> spSourceResolver;  
        CComPtr<IMFMediaSource> spSource;  
        CComPtr<IUnknown> spSourceUnk;  
        CComPtr<IMFTopology> spTopology;  
        CComPtr<IMFPresentationDescriptor> spPD;  
        MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;  
        DWORD cStreams = 0;  
        PROPVARIANT propvar;  
        PropVariantInit(&propvar);  
     
        //  
        // Create the media session  
        //  
     
        CHECK_HR( CoInitialize( NULL ) );  
        CHECK_HR( MFStartup(MF_VERSION) );  
          
        CHECK_HR( MFCreateMediaSession( NULL, &spSession ) );  
        
        //  
        // Create the media source  
        //  
     
        CHECK_HR( MFCreateSourceResolver( &spSourceResolver ) );  
     
        CHECK_HR( spSourceResolver->CreateObjectFromURL(  
            pwszURL,  
            MF_RESOLUTION_MEDIASOURCE,  
            NULL,  
            &ObjectType,  
            &spSourceUnk  
            ) );  
     
        CHECK_HR( spSourceUnk.QueryInterface( &spSource ) );  
     
        //  
        // Create the topology  
        //  
     
        CHECK_HR( MFCreateTopology(&spTopology) );  
     
        CHECK_HR( spSource->CreatePresentationDescriptor(&spPD) );  
        CHECK_HR( spPD->GetStreamDescriptorCount(&cStreams) );  
     
        for (DWORD iStream = 0; iStream < cStreams; iStream++)  
        {  
            CComPtr<IMFStreamDescriptor> spSD;  
            CComPtr<IMFMediaTypeHandler> spHandler;  
            CComPtr<IMFActivate> spActivate;  
            CComPtr<IMFTopologyNode> spSourceNode;  
            CComPtr<IMFTopologyNode> spOutputNode;  
            BOOL fSelected = FALSE;  
            GUID guidMajorType = GUID_NULL;  
     
            CHECK_HR( spPD->GetStreamDescriptorByIndex( iStream, &fSelected, &spSD ) );  
     
            if( !fSelected )  
            {  
                continue;  
            }  
     
            //  
            // Create an IMFActivate object for the renderer sink, based on the media type.  
            //  
     
            CHECK_HR( spSD->GetMediaTypeHandler(&spHandler) );  
            CHECK_HR( spHandler->GetMajorType(&guidMajorType) );  
       
            if( MFMediaType_Audio == guidMajorType )  
            {  
                CHECK_HR( MFCreateAudioRendererActivate( &spActivate ) );  
            }  
            else if( MFMediaType_Video == guidMajorType )  
            {  
                CHECK_HR( MFCreateVideoRendererActivate( hwnd, &spActivate ) );  
            }  
            else 
            {  
                continue// ignore stream  
            }  
     
            //  
            // Create the source node  
            //  
     
            CHECK_HR( MFCreateTopologyNode( MF_TOPOLOGY_SOURCESTREAM_NODE, &spSourceNode ) );  
            CHECK_HR( spSourceNode->SetUnknown( MF_TOPONODE_SOURCE, spSource ) );  
            CHECK_HR( spSourceNode->SetUnknown( MF_TOPONODE_PRESENTATION_DESCRIPTOR, spPD ) );  
            CHECK_HR( spSourceNode->SetUnknown( MF_TOPONODE_STREAM_DESCRIPTOR, spSD ) );  
            CHECK_HR( spTopology->AddNode( spSourceNode ) );  
     
            //  
            // Create the output node  
            //  
     
            CHECK_HR( MFCreateTopologyNode( MF_TOPOLOGY_OUTPUT_NODE, &spOutputNode ) );  
            CHECK_HR( spOutputNode->SetObject( spActivate ) );  
            CHECK_HR( spTopology->AddNode( spOutputNode ) );  
     
            //  
            // Connect the two nodes (adds intermediate MFTs as necessary)  
            //  
     
            CHECK_HR( spSourceNode->ConnectOutput( 0, spOutputNode, 0));  
        }  
     
        CHECK_HR( spSession->SetTopology( 0, spTopology ) );  
     
        //  
        // Start playback  
        //  
     
        CHECK_HR( spSession->Start( NULL, &propvar ) );  
     
        //  
        // Wait for playback to end  
        // --  
        // Note: call asynchronous BeginGetEvent() if the thread shouldn't get blocked  
        //  
     
        while( TRUE )  
        {  
            CComPtr<IMFMediaEvent> spEvent;  
            MediaEventType type;  
            HRESULT hrStatus;  
     
            CHECK_HR( spSession->GetEvent( 0, &spEvent ) );  
     
            CHECK_HR( spEvent->GetStatus( &hrStatus ) );  
            CHECK_HR( spEvent->GetType( &type ) );  
     
            wprintf( L"Received event %li (hr = 0x%08lx)\n", type, hrStatus );  
     
            CHECK_HR( hrStatus );  
     
            if( MESessionEnded == type )  
            {  
                break;  
            }  
        }  
     
    done:  
        if( spSource )  
        {  
            spSource->Shutdown();  
        }  
        if( spSession )  
        {  
            spSession->Shutdown();  
        }  
     
        (void) MFShutdown();  
        CoUninitialize();  
     
        PropVariantClear(&propvar);    
     
        return hr;  
    }  
     
    int __cdecl wmain(int argc, LPCTSTR argv[])  
    {  
        HRESULT hr = S_OK;  
        HWND hwnd = NULL;  
     
        //  
        // Create a window  
        //  
     
        WNDCLASS wndClass;  
        ZeroMemory(&wndClass, sizeof(wndClass));  
        wndClass.style = CS_HREDRAW | CS_VREDRAW;  
        wndClass.lpfnWndProc = DefWindowProc;  
        wndClass.lpszClassName = L"Test Window";  
        (void) RegisterClass(&wndClass);  
     
        hwnd = CreateWindow(  
            wndClass.lpszClassName,   
            L"Test Window",   
            WS_OVERLAPPED,  
            CW_USEDEFAULT,   
            0,   
            CW_USEDEFAULT,   
            0,   
            NULL,   
            NULL,   
            NULL,   
            NULL);  
        CHECK_NULL( hwnd, GETLASTHR );  
     
        (void) ShowWindow( hwnd, TRUE );  
        (void) UpdateWindow( hwnd );  
     
        //  
        // Play the video  
        //  
     
        CHECK_HR( PlayUnprotectedMediaFiles( L"Bear.wmv", hwnd ) );  
     
    done:  
        if( hwnd )  
        {  
            (void) DestroyWindow( hwnd );  
        }  
     
        return FAILED( hr );  
    }  
     
    • Marked as answer by Mike Wasson Monday, March 23, 2009 3:48 PM
    Thursday, March 19, 2009 9:04 PM
  • Thanks Matthieu for your response :D.
     I'm using Visual C++ 2008 Express Edition and it seems like this version does not contain any atlbase.h header, I'll check my pointers because as you said my problem should be a leaking memory issue.

    Thank you.
    Enby.
    Thursday, March 19, 2009 11:11 PM