void AsfContentInfoBuilder::AddStreamSink(WORD streamNumber, AudioEncoderParameters* encoderParameters)
{
  HRESULT hr;

  // First off, get the appropriate Media Foundation MediaType from the encoder, based on the compressor parameters
  // we've specified

  IMFMediaType* mfMediaType = AudioEncoder::GetEncoderMediaType(encoderParameters);

  IMFASFStreamConfig* mfAsfStreamConfig = nullptr;

  do
  {
    if (!SUCCEEDED(hr = _mfAsfProfile->CreateStream(mfMediaType, &mfAsfStreamConfig)))
      break;

    if (!SUCCEEDED(hr = mfAsfStreamConfig->SetStreamNumber(streamNumber)))
      break;

    if (!SUCCEEDED(hr = _mfAsfProfile->SetStream(mfAsfStreamConfig)))
      break;

    // Here's the critical piece needed to make Quality-based VBR encoding work:
    // The audio encoder is instantiated indirectly based on the stream sink,
    // but the stream sink's MediaType alone is not enough to get the audio encoder
    // into a state where it will perform quality-based VBR compression.  That's
    // because some specific properties need to be set on the Media Foundation's
    // transform before we make the call to enumerate the available compression
    // options.  So, the AsfStreamConfig object has an additional property store
    // tacked on to it where we can set these property values that need to be set
    // on the encoder.  Somewhat oddly they're not attached to the AsfStreamConfig,
    // nor are they attached to the AsfProfile object that's used to add stream 
    // sinks.  Rather, this property store is tied to the AsfContentInfo object and
    // the association between the stream sinks and the encoder parameter property
    // store is maintained by the stream number

    if (encoderParameters->IsQualityBasedVbr())
    {
      IPropertyStore *streamPropertyStore;  // TODO when should this be released?

      if (!SUCCEEDED(hr = _mfAsfContentInfo->GetEncodingConfigurationPropertyStore(streamNumber, &streamPropertyStore)))
        break;

      AudioEncoder::SetEncoderPropertiesForQualityBasedVbr(streamPropertyStore, encoderParameters->GetQualityLevel());
    }
  } while (0);

  if (mfAsfStreamConfig) mfAsfStreamConfig->Release();

  if (FAILED(hr))
    throw std::exception("Unable to add stream to the MediaSink");
}
Exemple #2
0
IMFMediaType* MediaSink::GetMediaTypeForStream(WORD streamNumber)
{
  IMFASFStreamConfig *asfStreamConfig = nullptr;
  IMFASFProfile* mfAsfProfile;
  IMFMediaType* mfMediaType = nullptr;
  HRESULT hr;

  do
  {
    if (!SUCCEEDED(hr = _mfAsfContentInfo->GetProfile(&mfAsfProfile)))
      break;

    if (!SUCCEEDED(hr = mfAsfProfile->GetStreamByNumber(streamNumber, &asfStreamConfig)))
      break;

    if (!SUCCEEDED(hr = asfStreamConfig->GetMediaType(&mfMediaType)))
      break;

  } while (0);

  return mfMediaType;
}
HRESULT CASFManager::SetupStreamDecoder (WORD wStreamNumber, 
                                         GUID* pguidCurrentMediaType)
{
    if (! m_pContentInfo)
    {
        return MF_E_NOT_INITIALIZED;
    }

    if (wStreamNumber == 0)
    {
        return E_INVALIDARG;
    }

    IMFASFProfile* pProfile = NULL;
    IMFMediaType* pMediaType = NULL;
    IMFASFStreamConfig *pStream = NULL;

    GUID    guidMajorType = GUID_NULL;
    GUID    guidSubType = GUID_NULL;
    GUID    guidDecoderCategory = GUID_NULL;

    BOOL fIsCompressed = TRUE;

    CLSID *pDecoderCLSIDs = NULL;   // Pointer to an array of CLISDs. 
    UINT32 cDecoderCLSIDs = 0;   // Size of the array.
    
    HRESULT hr = S_OK;

    //Get the profile object that stores stream information
    CHECK_HR(hr =  m_pContentInfo->GetProfile(&pProfile));

    //Get stream configuration object from the profile
    CHECK_HR(hr = pProfile->GetStreamByNumber(wStreamNumber, &pStream));

    //Get the media type
    CHECK_HR(hr = pStream->GetMediaType(&pMediaType));

    //Get the major media type
    CHECK_HR(hr = pMediaType->GetMajorType(&guidMajorType));
        
    //Get the sub media type
    CHECK_HR(hr = pMediaType->GetGUID(MF_MT_SUBTYPE, &guidSubType));
    
    //find out if the media type is compressed
    CHECK_HR(hr = pMediaType->IsCompressedFormat(&fIsCompressed));

    if (fIsCompressed)
    {
        //get decoder category
        if (guidMajorType == MFMediaType_Video)
        {
            guidDecoderCategory = MFT_CATEGORY_VIDEO_DECODER;
        }
        else if (guidMajorType == MFMediaType_Audio)
        {
            guidDecoderCategory = MFT_CATEGORY_AUDIO_DECODER;
        }
        else
        {
            CHECK_HR(hr = MF_E_INVALIDMEDIATYPE);
        }

        // Look for a decoder.
        MFT_REGISTER_TYPE_INFO tinfo;
        tinfo.guidMajorType = guidMajorType;
        tinfo.guidSubtype = guidSubType;

        CHECK_HR(hr = MFTEnum(
            guidDecoderCategory,
            0,                  // Reserved
            &tinfo,             // Input type to match. (Encoded type.)
            NULL,               // Output type to match. (Don't care.)
            NULL,               // Attributes to match. (None.)
            &pDecoderCLSIDs,    // Receives a pointer to an array of CLSIDs.
            &cDecoderCLSIDs     // Receives the size of the array.
            ));

        // MFTEnum can return zero matches.
        if (cDecoderCLSIDs == 0)
        {
            hr = MF_E_TOPO_CODEC_NOT_FOUND;
        }
        else
        {
            //if the CDecoder instance does not exist, create one.
            if (!m_pDecoder)
            {
                CHECK_HR(hr = CDecoder::CreateInstance(&m_pDecoder));
            }
            
            //Load the first MFT in the array for the current media type
            CHECK_HR(hr = m_pDecoder->Initialize(pDecoderCLSIDs[0], pMediaType));
        }
        *pguidCurrentMediaType = guidMajorType;
    }
    else
    {
        // Not compressed. Don't need a decoder. 
         CHECK_HR(hr = MF_E_INVALIDREQUEST);
    }


    TRACE((L"Stream decoder loaded.\n"));

done:

    LOG_MSG_IF_FAILED(L"CASFManager::SetupStreamDecoder failed.\n", hr);
    
    SAFE_RELEASE(pProfile);
    SAFE_RELEASE(pMediaType);
    SAFE_RELEASE(pStream);

    CoTaskMemFree(pDecoderCLSIDs);

    return hr;
}
HRESULT CASFManager::EnumerateStreams (WORD** ppwStreamNumbers, 
                                       GUID** ppguidMajorType, 
                                       DWORD* pcbTotalStreams)
{
    if (!ppwStreamNumbers || !ppguidMajorType || !pcbTotalStreams)
    {
        return E_INVALIDARG;
    }

    if (!m_pContentInfo)
    {
        return MF_E_NOT_INITIALIZED;
    }

    HRESULT hr = S_OK;

    IMFASFStreamConfig* pStream = NULL;
    IMFASFProfile* pProfile = NULL;

    *pcbTotalStreams =0;

    WORD* pwStreamNumbers; 
    GUID* pguidMajorType;   

    CHECK_HR(hr =  m_pContentInfo->GetProfile(&pProfile));

    CHECK_HR(hr = pProfile->GetStreamCount(pcbTotalStreams));

    if (*pcbTotalStreams == 0)
    {
        SAFE_RELEASE(pProfile);

        return E_FAIL;
    }

    //create an array of stream numbers and initialize elements swith 0
    pwStreamNumbers = new WORD[*pcbTotalStreams*sizeof(WORD)];

    if (!pwStreamNumbers)
    {
        hr = E_OUTOFMEMORY;
        goto done;
    }

    ZeroMemory (pwStreamNumbers, *pcbTotalStreams*sizeof(WORD));

    //create an array of guids and initialize elements with GUID_NULL.
    pguidMajorType = new GUID[*pcbTotalStreams*sizeof(GUID)];
    
    if (!pguidMajorType)
    {
        hr = E_OUTOFMEMORY;
        goto done;
    }

    ZeroMemory (pguidMajorType, *pcbTotalStreams*sizeof(GUID));

    //populate the arrays with stream numbers and guids from the profile object
    for (unsigned index = 0; index < *pcbTotalStreams; index++)
    {
        CHECK_HR(hr = pProfile->GetStream(index, &pwStreamNumbers[index], &pStream));

        CHECK_HR(hr = pStream->GetStreamType(&pguidMajorType[index]));

        SAFE_RELEASE(pStream);
    }


    *ppwStreamNumbers = pwStreamNumbers;
    *ppguidMajorType = pguidMajorType;

    TRACE((L"Enumerated streams.\n"));

done:

    LOG_MSG_IF_FAILED(L"CASFManager::EnumerateStreams failed.\n", hr);

    SAFE_RELEASE(pProfile);
    SAFE_RELEASE(pStream);

    if (FAILED (hr))
    {
        SAFE_ARRAY_DELETE(pwStreamNumbers);
        SAFE_ARRAY_DELETE(pguidMajorType);
    }

    return hr;
}