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"); }
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; }