locked
About writing an Multi-Output MF Source RRS feed

  • Question

  • I'm trying to write an multi-output MF source (output one video and one audio stream). And I meet some problems mentioned in the following. I create two stream descriptors in CreatePresentationDescriptor and select these two streams. But when I use GetStreamDescriptorByIndex in ValidatePresentationDescriptor to detect these two streams are selected or not, the second stream is not selected. Does only one stream can be selected once at a time in the same presentation? Or did I miss anything? Thanks a lot!
    Tuesday, May 15, 2007 9:51 AM

Answers

  • That code looks alright.  I tried building it, and if I call ValidatePresentationDescriptor() right after CreatePresentationDescriptor(), it works as expected with both streams selected.  This seems to mean that something else is deselecting one of the streams after you create the PD, or you are passing a different PD into the validation function.  You might try setting a breakpoint on DeselectStream to see who's calling it.
    Wednesday, May 30, 2007 12:00 AM

All replies

  • You can select more than one stream in the same presentation. 

     

    Is there any other code changing the stream selections between when you create the presentation descriptor and when you perform the validation?   Can you post a snippet of code showing how you are creating and selecting the streams?

    Friday, May 25, 2007 9:59 PM
  • Hello Matthew,

     

    Thanks for ur reply. The codes for creating the presentation descriptor and performing the validation are shown as follows. For this media source, I try to output one 352 x 240 YUY2 video stream and one wav stream with 44.1 kHz sampling rate.

     

    HRESULT CMultiOutputSource::CreatePresentationDescriptor()
    {
        HRESULT hr = S_OK;
        LARGE_INTEGER i64data;
       
        IMFMediaType *pMediaTypeVideo = NULL;
        IMFStreamDescriptor *pStreamDescriptorVideo = NULL;
        IMFMediaTypeHandler *pHandlerVideo = NULL;

      IMFMediaType *pMediaTypeAudio = NULL;
        IMFStreamDescriptor *pStreamDescriptorAudio = NULL;
        IMFMediaTypeHandler *pHandlerAudio = NULL;
        WAVEFORMATEX  WaveFormat = {0};

      IMFStreamDescriptor *ppStreamDescriptor[2];

      // Create an empty media type.
        hr = MFCreateMediaType(&pMediaTypeVideo);

      // Initialize the media type from the WAVEFORMATEX structure.
        if (SUCCEEDED(hr))
        {
            // Temp workaround - use legacy media type functions
           hr = pMediaTypeVideo->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
           hr = pMediaTypeVideo->SetGUID(MF_MT_SUBTYPE, MEDIASUBTYPE_YUY2);
           i64data.HighPart = 352;
           i64data.LowPart  = 240;
           hr = pMediaTypeVideo->SetUINT64(MF_MT_FRAME_SIZE, (UINT64)i64data.QuadPart);
           i64data.HighPart = 29970;
           i64data.LowPart  = 1000;
           hr = pMediaTypeVideo->SetUINT64(MF_MT_FRAME_RATE, (UINT64)i64data.QuadPart);
           i64data.HighPart = 1;
           i64data.LowPart  = 1;
           hr = pMediaTypeVideo->SetUINT64(MF_MT_PIXEL_ASPECT_RATIO, (UINT64)i64data.QuadPart);
           hr = pMediaTypeVideo->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
           hr = pMediaTypeVideo->SetUINT32(MF_MT_DEFAULT_STRIDE, 0);

        }

        // Create the stream descriptor.
          if (SUCCEEDED(hr))
          {
               hr = MFCreateStreamDescriptor(
                0,          // stream identifier
                1,          // Number of media types.
                &pMediaTypeVideo, // Array of media types
                &pStreamDescriptorVideo
                );
           }

        // Set the default media type on the media type handler.
          if (SUCCEEDED(hr))
          {
              hr = pStreamDescriptorVideo->GetMediaTypeHandler(&pHandlerVideo);
          }

        if (SUCCEEDED(hr))
          {
              hr = pHandlerVideo->SetCurrentMediaType(pMediaTypeVideo);
          }

        // Create an empty media type.
          hr = MFCreateMediaType(&pMediaTypeAudio);

        // Initialize the media type from the WAVEFORMATEX structure.
          if (SUCCEEDED(hr))
          {
              hr = pMediaTypeAudio->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
              hr = pMediaTypeAudio->SetGUID(MF_MT_SUBTYPE, MEDIASUBTYPE_WAVE);

            // Temp workaround - use legacy media type functions
             WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
             WaveFormat.nChannels  = 2;
             WaveFormat.nSamplesPerSec = 44100;
             WaveFormat.wBitsPerSample = 16;
             WaveFormat.nBlockAlign = 4;
             WaveFormat.nAvgBytesPerSec = 176400;
             memcpy(&m_WaveFormat, &WaveFormat, sizeof(WAVEFORMATEX));
             hr = MFInitMediaTypeFromWaveFormatEx(pMediaTypeAudio, &WaveFormat, sizeof(WAVEFORMATEX));
          }

        // Create the stream descriptor.
          if (SUCCEEDED(hr))
          {
               hr = MFCreateStreamDescriptor(
                0,          // stream identifier
                1,          // Number of media types.
                &pMediaTypeAudio, // Array of media types
                &pStreamDescriptorAudio
                );
           }

        // Set the default media type on the media type handler.
          if (SUCCEEDED(hr))
          {
               hr = pStreamDescriptorAudio->GetMediaTypeHandler(&pHandlerAudio);
          }

        if (SUCCEEDED(hr))
          {
               hr = pHandlerAudio->SetCurrentMediaType(pMediaTypeAudio);
          }

        ppStreamDescriptor[0] = pStreamDescriptorVideo;
          ppStreamDescriptor[1] = pStreamDescriptorAudio;

        // Create the presentation descriptor.
          if (SUCCEEDED(hr))
          {
            hr = MFCreatePresentationDescriptor(
                2,      // Number of stream descriptors
                ppStreamDescriptor, // Array of stream descriptors
                &m_pPresentationDescriptor
                );
           }

        // Select the first and second stream
          if (SUCCEEDED(hr))
          {
               hr = m_pPresentationDescriptor->SelectStream(0);
          }

        // Select the first stream
          if (SUCCEEDED(hr))
          {
               hr = m_pPresentationDescriptor->SelectStream(1);
          }


         SAFE_RELEASE(pMediaTypeVideo);
         SAFE_RELEASE(pMediaTypeAudio);
        SAFE_RELEASE(pStreamDescriptorVideo);
        SAFE_RELEASE(pStreamDescriptorAudio);
        SAFE_RELEASE(pHandlerVideo);
        SAFE_RELEASE(pHandlerAudio);

      return hr;

    }

     

    HRESULT CMultiOutputSource::ValidatePresentationDescriptor(IMFPresentationDescriptor *pPD)
    {
        HRESULT hr;

      assert(pPD != NULL);

      IMFStreamDescriptor *pVideoStreamDescriptor = NULL;
        IMFStreamDescriptor *pAudioStreamDescriptor = NULL;
        IMFMediaTypeHandler *pVideoHandler = NULL;
        IMFMediaTypeHandler *pAudioHandler = NULL;
        IMFMediaType        *pMediaType = NULL;
        IMFVideoMediaType   *pVideoType = NULL;
        IMFAudioMediaType   *pAudioType = NULL;
        const WAVEFORMATEX  *pFormat = NULL;

      DWORD cStreamDescriptors = 0;
        BOOL fSelected = FALSE;

      // Make sure there is only two stream.
        hr = pPD->GetStreamDescriptorCount(&cStreamDescriptors);

      if (SUCCEEDED(hr))
        {
            if (cStreamDescriptors > 2)
            {
                hr = MF_E_UNSUPPORTED_REPRESENTATION;
            }
        }

      // Get the stream descriptor.
        if (SUCCEEDED(hr))
        {
            hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pVideoStreamDescriptor);
        }

      

    // Make sure it's selected. (This media source has only one stream, so it
        // is not useful to deselect the only stream.)
        if (SUCCEEDED(hr))
        {
            if (!fSelected)
            {
                hr = MF_E_UNSUPPORTED_REPRESENTATION;
            }
        }


        // Get the media type handler, so that we can get the media type.
        if (SUCCEEDED(hr))
        {
            hr = pVideoStreamDescriptor->GetMediaTypeHandler(&pVideoHandler);
        }
        if (SUCCEEDED(hr))
        {
            hr = pVideoHandler->GetCurrentMediaType(&pMediaType);
        }
      
        if (SUCCEEDED(hr))
        {
            hr = pMediaType->QueryInterface(IID_IMFVideoMediaType, (void**)&pVideoType);
        }

     

    fSelected = FALSE;
        // Get the stream descriptor.
        if (SUCCEEDED(hr))
        {
            hr = pPD->GetStreamDescriptorByIndex(1, &fSelected, &pAudioStreamDescriptor);
        }

        // Make sure it's selected. (This media source has only one stream, so it
        // is not useful to deselect the only stream.)
        if (SUCCEEDED(hr))
        {
            if (!fSelected)
            {
                hr = MF_E_UNSUPPORTED_REPRESENTATION;
            }
        }


        // Get the media type handler, so that we can get the media type.
        if (SUCCEEDED(hr))
        {
            hr = pAudioStreamDescriptor->GetMediaTypeHandler(&pAudioHandler);
        }
        if (SUCCEEDED(hr))
        {
            hr = pAudioHandler->GetCurrentMediaType(&pMediaType);
        }

     if (SUCCEEDED(hr))
        {
            hr = pMediaType->QueryInterface(IID_IMFAudioMediaType, (void**)&pAudioType);
        }

      if (SUCCEEDED(hr))
        {
            pFormat = pAudioType->GetAudioFormat();
            if (pFormat == NULL)
            {
                hr = MF_E_INVALIDMEDIATYPE;
            }
        }

        if (SUCCEEDED(hr))
        {
            if (memcmp(pFormat, &m_WaveFormat, sizeof(WAVEFORMATEX)) != 0)
            {
                hr = MF_E_INVALIDMEDIATYPE;
            }
        }


        SAFE_RELEASE(pVideoStreamDescriptor);
        SAFE_RELEASE(pAudioStreamDescriptor);
        SAFE_RELEASE(pVideoHandler);
        SAFE_RELEASE(pAudioHandler);
        SAFE_RELEASE(pMediaType);
        SAFE_RELEASE(pVideoType);
        SAFE_RELEASE(pAudioType);
        return hr;

    }

    Tuesday, May 29, 2007 7:52 AM
  • That code looks alright.  I tried building it, and if I call ValidatePresentationDescriptor() right after CreatePresentationDescriptor(), it works as expected with both streams selected.  This seems to mean that something else is deselecting one of the streams after you create the PD, or you are passing a different PD into the validation function.  You might try setting a breakpoint on DeselectStream to see who's calling it.
    Wednesday, May 30, 2007 12:00 AM