Example #1
0
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;
}