int select_output_mediatype(IMFTransform *transform, int out_stream_id, GUID audio_format) { HRESULT hr = S_OK; UINT32 tmp; IMFMediaType *t; // If you know what you need and what you are doing, you can specify the condition instead of searching // but it's better to use search since MFT may or may not support your output parameters for (DWORD i = 0; ; i++) { hr = transform->GetOutputAvailableType(out_stream_id, i, &t); if (hr == MF_E_NO_MORE_TYPES || hr == E_NOTIMPL) { return 0; } if (FAILED(hr)) { ReportError(L"failed to get output types for MFT", hr); return -1; } hr = t->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &tmp); if (FAILED(hr)) continue; // select PCM-16 format if (tmp == 16) { hr = transform->SetOutputType(out_stream_id, t, 0); if (FAILED(hr)) { ReportError(L"failed to select output types for MFT", hr); return -1; } return 0; } else { continue; } return -1; } ReportError(L"MFT: Unable to find preferred output format", E_NOTIMPL); return -1; }
/** Cobbled together from: http://msdn.microsoft.com/en-us/library/dd757929(v=vs.85).aspx and http://msdn.microsoft.com/en-us/library/dd317928(VS.85).aspx -- Albert If anything in here fails, just bail. I'm not going to decode HRESULTS. -- Bill */ bool SoundSourceMediaFoundation::configureAudioStream(const AudioSourceConfig& audioSrcCfg) { HRESULT hr; // deselect all streams, we only want the first hr = m_pSourceReader->SetStreamSelection( MF_SOURCE_READER_ALL_STREAMS, false); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to deselect all streams"; return false; } hr = m_pSourceReader->SetStreamSelection( kStreamIndex, true); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to select first audio stream"; return false; } IMFMediaType* pAudioType = nullptr; hr = m_pSourceReader->GetCurrentMediaType( kStreamIndex, &pAudioType); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to get current media type from stream"; return false; } //------ Get bitrate from the file, before we change it to get uncompressed audio UINT32 avgBytesPerSecond; hr = pAudioType->GetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &avgBytesPerSecond); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "error getting MF_MT_AUDIO_AVG_BYTES_PER_SECOND"; return false; } setBitrate( (avgBytesPerSecond * 8) / 1000); //------ hr = pAudioType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to set major type to audio"; safeRelease(&pAudioType); return false; } hr = pAudioType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to set subtype format to float"; safeRelease(&pAudioType); return false; } hr = pAudioType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, true); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to set all samples independent"; safeRelease(&pAudioType); return false; } hr = pAudioType->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, true); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to set fixed size samples"; safeRelease(&pAudioType); return false; } hr = pAudioType->SetUINT32( MF_MT_AUDIO_BITS_PER_SAMPLE, kBitsPerSample); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to set bits per sample:" << kBitsPerSample; safeRelease(&pAudioType); return false; } const UINT sampleSize = kLeftoverSize * kBytesPerSample; hr = pAudioType->SetUINT32( MF_MT_SAMPLE_SIZE, sampleSize); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to set sample size:" << sampleSize; safeRelease(&pAudioType); return false; } UINT32 numChannels; hr = pAudioType->GetUINT32( MF_MT_AUDIO_NUM_CHANNELS, &numChannels); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to get actual number of channels"; return false; } else { qDebug() << "Number of channels in input stream" << numChannels; } if (audioSrcCfg.hasValidChannelCount()) { numChannels = audioSrcCfg.getChannelCount(); hr = pAudioType->SetUINT32( MF_MT_AUDIO_NUM_CHANNELS, numChannels); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to set number of channels:" << numChannels; safeRelease(&pAudioType); return false; } qDebug() << "Requested number of channels" << numChannels; } UINT32 samplesPerSecond; hr = pAudioType->GetUINT32( MF_MT_AUDIO_SAMPLES_PER_SECOND, &samplesPerSecond); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to get samples per second"; return false; } else { qDebug() << "Samples per second in input stream" << samplesPerSecond; } if (audioSrcCfg.hasValidSamplingRate()) { samplesPerSecond = audioSrcCfg.getSamplingRate(); hr = pAudioType->SetUINT32( MF_MT_AUDIO_SAMPLES_PER_SECOND, samplesPerSecond); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to set samples per second:" << samplesPerSecond; safeRelease(&pAudioType); return false; } qDebug() << "Requested samples per second" << samplesPerSecond; } // Set this type on the source reader. The source reader will // load the necessary decoder. hr = m_pSourceReader->SetCurrentMediaType( kStreamIndex, nullptr, pAudioType); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to set media type"; safeRelease(&pAudioType); return false; } // Finally release the reference before reusing the pointer safeRelease(&pAudioType); // Get the resulting output format. hr = m_pSourceReader->GetCurrentMediaType( kStreamIndex, &pAudioType); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to retrieve completed media type"; return false; } // Ensure the stream is selected. hr = m_pSourceReader->SetStreamSelection( kStreamIndex, true); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to select first audio stream (again)"; return false; } hr = pAudioType->GetUINT32( MF_MT_AUDIO_NUM_CHANNELS, &numChannels); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to get actual number of channels"; return false; } setChannelCount(numChannels); hr = pAudioType->GetUINT32( MF_MT_AUDIO_SAMPLES_PER_SECOND, &samplesPerSecond); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to get the actual sample rate"; return false; } setSamplingRate(samplesPerSecond); UINT32 leftoverBufferSizeInBytes = 0; hr = pAudioType->GetUINT32(MF_MT_SAMPLE_SIZE, &leftoverBufferSizeInBytes); if (FAILED(hr)) { qWarning() << kLogPreamble << hr << "failed to get sample buffer size (in bytes)"; return false; } DEBUG_ASSERT((leftoverBufferSizeInBytes % kBytesPerSample) == 0); m_sampleBuffer.resetCapacity(leftoverBufferSizeInBytes / kBytesPerSample); DEBUG_ASSERT(m_sampleBuffer.getCapacity() > 0); qDebug() << kLogPreamble << "Sample buffer capacity" << m_sampleBuffer.getCapacity(); // Finally release the reference safeRelease(&pAudioType); return true; }
MediaFoundationTransform::MediaFoundationTransform(IMFActivate *activationObj, WmaEncodingFormat encodingFormat) { UINT32 nameLen; // Transform name is an MFActivate object property, so get that first activationObj->GetString(MFT_FRIENDLY_NAME_Attribute, _transformName, sizeof(_transformName), &nameLen); HRESULT hr = activationObj->ActivateObject(IID_PPV_ARGS(&_mfEncoder)); hr = _mfEncoder->QueryInterface(IID_PPV_ARGS(&_propertyStore)); // Configure the tranform to perform the requested compression format switch (encodingFormat) { case WmaEncodingFormat::Lossless: SetBooleanProperty(MFPKEY_VBRENABLED, true); SetBooleanProperty(MFPKEY_CONSTRAIN_ENUMERATED_VBRQUALITY, true); SetUint32Property(MFPKEY_DESIRED_VBRQUALITY, 100); break; case WmaEncodingFormat::Quality_10: SetBooleanProperty(MFPKEY_VBRENABLED, true); SetBooleanProperty(MFPKEY_CONSTRAIN_ENUMERATED_VBRQUALITY, true); SetUint32Property(MFPKEY_DESIRED_VBRQUALITY, 10); break; case WmaEncodingFormat::Quality_25: SetBooleanProperty(MFPKEY_VBRENABLED, true); SetBooleanProperty(MFPKEY_CONSTRAIN_ENUMERATED_VBRQUALITY, true); SetUint32Property(MFPKEY_DESIRED_VBRQUALITY, 25); break; case WmaEncodingFormat::Quality_50: SetBooleanProperty(MFPKEY_VBRENABLED, true); SetBooleanProperty(MFPKEY_CONSTRAIN_ENUMERATED_VBRQUALITY, true); SetUint32Property(MFPKEY_DESIRED_VBRQUALITY, 50); break; case WmaEncodingFormat::Quality_75: SetBooleanProperty(MFPKEY_VBRENABLED, true); SetBooleanProperty(MFPKEY_CONSTRAIN_ENUMERATED_VBRQUALITY, true); SetUint32Property(MFPKEY_DESIRED_VBRQUALITY, 75); break; case WmaEncodingFormat::Quality_90: SetBooleanProperty(MFPKEY_VBRENABLED, true); SetBooleanProperty(MFPKEY_CONSTRAIN_ENUMERATED_VBRQUALITY, true); SetUint32Property(MFPKEY_DESIRED_VBRQUALITY, 90); break; case WmaEncodingFormat::Quality_98: SetBooleanProperty(MFPKEY_VBRENABLED, true); SetBooleanProperty(MFPKEY_CONSTRAIN_ENUMERATED_VBRQUALITY, true); SetUint32Property(MFPKEY_DESIRED_VBRQUALITY, 98); break; } hr = _propertyStore->Commit(); // enumerate output types and try to find the appropriate one for our purposes DWORD index = 0; while (true) { IMFMediaType *mediaType; hr = _mfEncoder->GetOutputAvailableType(0, index++, &mediaType); if (hr == MF_E_NO_MORE_TYPES) break; // Get the AM_MEDIA_TYPE structure from the media type, in case we want to need // to differentiate between Standard and Pro WMA codecs in the future... AM_MEDIA_TYPE *amMediaType; mediaType->GetRepresentation(AM_MEDIA_TYPE_REPRESENTATION, (LPVOID *) &amMediaType); WAVEFORMATEX *waveFormat = (WAVEFORMATEX *) amMediaType->pbFormat; // there's only a few things we're interested in with the output type, so only bother grabbing those values UINT32 channelCount; UINT32 samplesPerSecond; UINT32 bitsPerSample; hr = mediaType->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &channelCount); hr = mediaType->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &samplesPerSecond); hr = mediaType->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &bitsPerSample); if ((channelCount == 2) && (bitsPerSample == 16) && (samplesPerSecond == 44100)) { _mfMediaType = mediaType; // IMFActivate *areYouFuckingSerious; // activationObj->ShutdownObject(); // _mfEncoder->Release(); // hr = MFCreateWMAEncoderActivate(mediaType, _propertyStore, &areYouFuckingSerious); // hr = areYouFuckingSerious->ActivateObject(IID_PPV_ARGS(&_mfEncoder)); break; } } index = 0; }