locked
MFCreateVideoRenderer and custom EVR presenter RRS feed

  • Question

  • Hello all,

    I've written a custom EVR presenter, and I'd like to use it when I play a video file.

     I have a VideoPlayer class, which uses static functions of a MFHelper class, like in the Video playback sample of the MSDN. I have to say it works well when I use the default renderer.

     

    Here is the steps I do in my code to use it:

    1) Create it in the calling class

     

    m_pEVRPresenter = new EVRPresenter( );
    

     

    First question: is this a correct way of creating a COM object? It doesn't seems to be a problem in my case, but I'm just wondering

    2)  In the OpenUrl, I create the MediaSession, the MediaSource, the PresentationDescriptor, and finally the PlaybackTopology, before I set it to the Session.

    3) I pass a pointer to my EVRPresenter class to the CreatePlaybackTopology function. The pointer is passed through the helpers function, to be used in CreateMediaSinkActivate:

     

    void MFHelper::CreateMediaSinkActivate(
        IMFStreamDescriptor *pSourceSD,     // Pointer to the stream descriptor.
        HWND hVideoWindow,                  // Handle to the video clipping window.
    	IMFVideoPresenter *pVideoPresenter,
        IMFActivate **ppActivate,
    	IMFMediaSink **ppMediaSink
        )
    {
    	CComPtr< IMFMediaTypeHandler > pHandler;
        
    	// Get the media type handler for the stream.
        ThrowIfFail( pSourceSD->GetMediaTypeHandler( &pHandler ) );
    
        // Get the major media type.
        GUID guidMajorType;
        ThrowIfFail( pHandler->GetMajorType( &guidMajorType ) );
    
        // Create an IMFActivate object for the renderer, based on the media type.
        if ( MFMediaType_Audio == guidMajorType )
        {		
    		CComPtr< IMFActivate > pActivate;
    		
    		// Create the audio renderer.
            ThrowIfFail( MFCreateAudioRendererActivate( &pActivate ) );
    
    		*ppActivate = pActivate;
    		(*ppActivate)->AddRef();
        }
        else if ( MFMediaType_Video == guidMajorType )
        {
            // Create the video renderer.
            CComPtr< IMFMediaSink > pSink;
    
    		MFCreateVideoRenderer( __uuidof(IMFMediaSink), (void**)&pSink);
    
    		CComQIPtr< IMFVideoRenderer > pVideoRenderer( pSink );
    
    		ThrowIfFail( pVideoRenderer->InitializeRenderer( NULL, pVideoPresenter ) );
    
    		*ppMediaSink = pSink;
    		(*ppMediaSink)->AddRef();
    
    		/*ThrowIfFail( MFCreateVideoRendererActivate( hVideoWindow, &pActivate ) );
    		ThrowIfFail( pActivate->SetGUID( MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_ACTIVATE, m_clsidPresenter ) );*/
        }
        else
        {
            ThrowCOMError( E_FAIL );
            // Optionally, you could deselect this stream instead of failing.
        }
        
        // Return IMFActivate pointer to caller.
    	
    }
    

     


    I know it's kind of a ugly code, but this is for test for now :)

    4) Back in AddBranchToPartialTopology, if I have a pointer to IMFMediaSink back from CreateMediaSinkActivate, I get a pointer to IMFStreamSink, and call AddOutputNode:

     

    void MFHelper::AddBranchToPartialTopology(
        IMFTopology *pTopology,         // Topology.
        IMFMediaSource *pSource,        // Media source.
        IMFPresentationDescriptor *pPD, // Presentation descriptor.
        IMFVideoPresenter *pVideoPresenter,
    	DWORD iStream,                  // Stream index.
        HWND hVideoWnd                 // Window for video playback.
        )
    {
        CComPtr< IMFStreamDescriptor > pSD;
        CComPtr< IMFActivate > pSinkActivate;
    	CComPtr< IMFMediaSink > pMediaSink;
        CComPtr< IMFTopologyNode > pSourceNode;
        CComPtr< IMFTopologyNode > pOutputNode;
    
        BOOL fSelected = false;
    
        ThrowIfFail( pPD->GetStreamDescriptorByIndex(iStream, &fSelected, &pSD) );
    
        if (fSelected)
        {
            // Create the media sink activation object.
            CreateMediaSinkActivate( pSD, hVideoWnd, pVideoPresenter, &pSinkActivate, &pMediaSink );
    
            // Add a source node for this stream.
            AddSourceNode( pTopology, pSource, pPD, pSD, &pSourceNode );
    
            // Create the output node for the renderer.
            if ( pSinkActivate )
    		{
    			AddOutputNode( pTopology, pSinkActivate, 0, &pOutputNode );
    		}
    		else if ( pMediaSink )
    		{
    			CComPtr< IMFStreamSink > pStreamSink;
    			DWORD streamCount;
    
    			ThrowIfFail( pMediaSink->GetStreamSinkCount( &streamCount ) );
    
    			pMediaSink->GetStreamSinkByIndex( 0, &pStreamSink );
    			
    			AddOutputNode( pTopology, pStreamSink, &pOutputNode );
    
    			//ThrowIfFail( pNode->SetObject( pStreamSink ) );
    		}
    
            // Connect the source node to the output node.
            ThrowIfFail( pSourceNode->ConnectOutput( 0, pOutputNode, 0 ) );
        }
        // else: If not selected, don't add the branch. 
    }
    

     

    5) From now, I have the same function calls as in the Playback sample.

    When I run my application and call VideoPlayer::OpenUrl, the first error I get is in the HandleEvent of VideoPlayer:

    IMFMediaEvent::GetType gets a event of type MESessionTopologyStatus, while IMFMediaEvent::GetStatus gets the error code -1072875847.

    I've checked everything, but I don't find the error.

    Could you tell me what's wrong with my code?

    Thanks in advance

    Tuesday, November 8, 2011 7:13 AM

Answers

  • Well, I could figure what the error was.

    In my D3DPresentEngine class, I had an error while I was trying to set the window HWND, and this error was propagated until the ProcessMessage function.

    Now it "works", until I can set my callback function to get the pointer to the D3DSurface and display it in my WPF application

    Tuesday, November 8, 2011 10:42 AM