/* Adds the video and audio stream to the H.264 writer sink. */ HRESULT ConfigureEncoder(IMFMediaType *pVideoType, DWORD *videoStreamIndex, DWORD *audioStreamIndex, IMFSinkWriter *pWriter) { IMFMediaType *pVideoOutType = NULL; IMFMediaType *pAudioOutType = NULL; // Configure the video stream. CHECK_HR(MFCreateMediaType(&pVideoOutType), L"Configure encoder failed to create media type for video output sink."); CHECK_HR(pVideoOutType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), L"Failed to set video writer attribute, media type."); CHECK_HR(pVideoOutType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264), L"Failed to set video writer attribute, video format (H.264)."); CHECK_HR(pVideoOutType->SetUINT32(MF_MT_AVG_BITRATE, 240 * 1000), L"Failed to set video writer attribute, bit rate."); CHECK_HR(CopyAttribute(pVideoType, pVideoOutType, MF_MT_FRAME_SIZE), L"Failed to set video writer attribute, frame size."); CHECK_HR(CopyAttribute(pVideoType, pVideoOutType, MF_MT_FRAME_RATE), L"Failed to set video writer attribute, frame rate."); CHECK_HR(CopyAttribute(pVideoType, pVideoOutType, MF_MT_PIXEL_ASPECT_RATIO), L"Failed to set video writer attribute, aspect ratio."); CHECK_HR(CopyAttribute(pVideoType, pVideoOutType, MF_MT_INTERLACE_MODE), L"Failed to set video writer attribute, interlace mode.");; CHECK_HR(pWriter->AddStream(pVideoOutType, videoStreamIndex), L"Failed to add the video stream to the sink writer."); pVideoOutType->Release(); // Configure the audio stream. // See http://msdn.microsoft.com/en-us/library/windows/desktop/dd742785(v=vs.85).aspx for AAC encoder settings. // http://msdn.microsoft.com/en-us/library/ff819476%28VS.85%29.aspx CHECK_HR(MFCreateMediaType(&pAudioOutType), L"Configure encoder failed to create media type for audio output sink."); CHECK_HR(pAudioOutType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), L"Failed to set audio writer attribute, media type."); CHECK_HR(pAudioOutType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_AAC), L"Failed to set audio writer attribute, audio format (AAC)."); CHECK_HR(pAudioOutType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, 2), L"Failed to set audio writer attribute, number of channels."); CHECK_HR(pAudioOutType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16), L"Failed to set audio writer attribute, bits per sample."); CHECK_HR(pAudioOutType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), L"Failed to set audio writer attribute, samples per second."); CHECK_HR(pAudioOutType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 16000), L"Failed to set audio writer attribute, average bytes per second."); //CHECK_HR( pAudioOutType->SetUINT32( MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 0x29 ), L"Failed to set audio writer attribute, level indication."); CHECK_HR(pWriter->AddStream(pAudioOutType, audioStreamIndex), L"Failed to add the audio stream to the sink writer."); pAudioOutType->Release(); return S_OK; }
// 创建sink writer. 返回流索引. HRESULT VideoEncoder::CreateSinkWriter(IMFSinkWriter** ppSinkWriter, DWORD* pStreamIndex) { HRESULT hr = S_OK; if (this->m_outputFile == L"") { return ERROR_FILE_INVALID; } // 创建sink writer. *ppSinkWriter = nullptr; IMFSinkWriter *pSinkWriter = nullptr; IMFMediaType* pOutputMediaType = nullptr; IMFMediaType *pInMediaType = nullptr; CheckHR(MFCreateSinkWriterFromURL(this->m_outputFile.c_str(), nullptr, nullptr, &pSinkWriter)); // 创建和配置输出媒体类型. CheckHR(MFCreateMediaType(&pOutputMediaType)); CheckHR(pOutputMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)); CheckHR(pOutputMediaType->SetGUID(MF_MT_SUBTYPE, this->m_outputVideoFormat)); CheckHR(pOutputMediaType->SetUINT32(MF_MT_AVG_BITRATE, this->m_videoBitRate)); CheckHR(pOutputMediaType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive)); CheckHR(MFSetAttributeSize(pOutputMediaType, MF_MT_FRAME_SIZE, this->m_frameWidth, this->m_frameHeight)); CheckHR(MFSetAttributeRatio(pOutputMediaType, MF_MT_FRAME_RATE, (UINT32)this->m_fps, 1)); CheckHR(MFSetAttributeRatio(pOutputMediaType, MF_MT_PIXEL_ASPECT_RATIO, 1, 1)); DWORD streamIndex; CheckHR(pSinkWriter->AddStream(pOutputMediaType, &streamIndex)); // 设置输入的媒体类型. CheckHR(MFCreateMediaType(&pInMediaType)); CheckHR(pInMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)); CheckHR(pInMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32)); CheckHR(pInMediaType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive)); // 输入的步幅信息不为所有输出编码解码器需要.但某些编解码器需要它,如 H.264. // 如果步幅是去掉,或设置为负值,H.264 将从下到上处理图像. CheckHR(pInMediaType->SetUINT32(MF_MT_DEFAULT_STRIDE, this->m_frameStride)); CheckHR(MFSetAttributeSize(pInMediaType, MF_MT_FRAME_SIZE, this->m_frameWidth, this->m_frameHeight)); CheckHR(MFSetAttributeRatio(pInMediaType, MF_MT_FRAME_RATE, (UINT32)this->m_fps, 1)); CheckHR(MFSetAttributeRatio(pInMediaType, MF_MT_PIXEL_ASPECT_RATIO, 1, 1)); CheckHR(pSinkWriter->SetInputMediaType(streamIndex, pInMediaType, nullptr)); // 开始编写. CheckHR(pSinkWriter->BeginWriting()); *ppSinkWriter = pSinkWriter; (*ppSinkWriter)->AddRef(); *pStreamIndex = streamIndex; cleanup: if (!SUCCEEDED(hr)) { DWORD error = GetLastError(); this->m_logFileStream << "意外错误: " << error << endl; } SafeRelease(&pSinkWriter); SafeRelease(&pOutputMediaType); return hr; }
HRESULT EncodeTransform::SetOutputMediaType() { if (!mpEncoder) { return MF_E_NOT_INITIALIZED; } IMFMediaType* pMediaTypeOut = NULL; HRESULT hr = MFCreateMediaType(&pMediaTypeOut); // Set the output media type. if (SUCCEEDED(hr)) { hr = MFCreateMediaType(&pMediaTypeOut); } if (SUCCEEDED(hr)) { hr = pMediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); } if (SUCCEEDED(hr)) { hr = pMediaTypeOut->SetGUID(MF_MT_SUBTYPE, cVideoEncodingFormat); } if (SUCCEEDED(hr)) { hr = pMediaTypeOut->SetUINT32(MF_MT_AVG_BITRATE, VIDEO_BIT_RATE); } if (SUCCEEDED(hr)) { hr = MFSetAttributeRatio(pMediaTypeOut, MF_MT_FRAME_RATE, VIDEO_FPS, 1); } if (SUCCEEDED(hr)) { hr = MFSetAttributeSize(pMediaTypeOut, MF_MT_FRAME_SIZE, mStreamWidth, mStreamHeight); } if (SUCCEEDED(hr)) { hr = pMediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive); } if (SUCCEEDED(hr)) { hr = pMediaTypeOut->SetUINT32(MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_Base); } if (SUCCEEDED(hr)) { hr = MFSetAttributeRatio(pMediaTypeOut, MF_MT_PIXEL_ASPECT_RATIO, 1, 1); } if (SUCCEEDED(hr)) { hr = mpEncoder->SetOutputType(0, pMediaTypeOut, 0); } return hr; }
static HRESULT CreateAudioMediaType(const WWMFPcmFormat &fmt, IMFMediaType** ppMediaType) { HRESULT hr; IMFMediaType *pMediaType = NULL; *ppMediaType = NULL; HRG(MFCreateMediaType(&pMediaType) ); HRG(pMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio)); HRG(pMediaType->SetGUID(MF_MT_SUBTYPE, (fmt.sampleFormat == WWMFBitFormatInt) ? MFAudioFormat_PCM : MFAudioFormat_Float)); HRG(pMediaType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, fmt.nChannels)); HRG(pMediaType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, fmt.sampleRate)); HRG(pMediaType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, fmt.FrameBytes())); HRG(pMediaType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, fmt.BytesPerSec())); HRG(pMediaType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, fmt.bits)); HRG(pMediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE)); if (0 != fmt.dwChannelMask) { HRG(pMediaType->SetUINT32(MF_MT_AUDIO_CHANNEL_MASK, fmt.dwChannelMask)); } if (fmt.bits != fmt.validBitsPerSample) { HRG(pMediaType->SetUINT32(MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, fmt.validBitsPerSample)); } *ppMediaType = pMediaType; pMediaType = NULL; //< prevent release end: SafeRelease(&pMediaType); return hr; }
int select_input_mediatype(IMFTransform *transform, int in_stream_id, ADTSData adts, UINT8 *user_data, UINT32 user_data_len, GUID audio_format) { HRESULT hr = S_OK; IMFMediaType *t; // actually you can get rid of the whole block of searching and filtering mess // if you know the exact parameters of your media stream hr = MFCreateMediaType(&t); if (FAILED(hr)) { ReportError(L"Unable to create an empty MediaType", hr); return -1; } // basic definition t->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio); t->SetGUID(MF_MT_SUBTYPE, audio_format); // see https://docs.microsoft.com/en-us/windows/desktop/medfound/aac-decoder#example-media-types // and https://docs.microsoft.com/zh-cn/windows/desktop/api/mmreg/ns-mmreg-heaacwaveinfo_tag // for the meaning of the byte array below // for integrate into a larger project, it is recommended to wrap the parameters into a struct // and pass that struct into the function // const UINT8 aac_data[] = { 0x01, 0x00, 0xfe, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x11, 0x90 }; // 0: raw aac 1: adts 2: adif 3: latm/laos t->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 1); t->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, adts.channels); t->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, adts.samplerate); // 0xfe = 254 = "unspecified" t->SetUINT32(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 254); t->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1); t->SetBlob(MF_MT_USER_DATA, user_data, user_data_len); hr = transform->SetInputType(in_stream_id, t, 0); if (FAILED(hr)) { ReportError(L"failed to select input types for MFT", hr); return -1; } return 0; }
/** 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; }
TargetFileMediaFoundation::TargetFileMediaFoundation( const DataTargetRef &dataTarget, size_t sampleRate, size_t numChannels, SampleType sampleType, const std::string &extension ) : TargetFile( dataTarget, sampleRate, numChannels, sampleType ), mStreamIndex( 0 ) { MediaFoundationInitializer::initMediaFoundation(); ::IMFSinkWriter *sinkWriter; HRESULT hr = ::MFCreateSinkWriterFromURL( dataTarget->getFilePath().wstring().c_str(), NULL, NULL, &sinkWriter ); if( hr != S_OK ) { string errorString = string( "TargetFileMediaFoundation: Failed to create SinkWriter from URL: " ) + dataTarget->getFilePath().string(); if( hr == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) ) errorString += ", file not found."; throw AudioFileExc( errorString ); } mSinkWriter = ci::msw::makeComUnique( sinkWriter ); mSampleSize = getBytesPerSample( mSampleType ); const UINT32 bitsPerSample = 8 * mSampleSize; const WORD blockAlignment = mNumChannels * mSampleSize; const DWORD averageBytesPerSecond = mSampleRate * blockAlignment; // Set the output media type. IMFMediaType *mediaType; hr = ::MFCreateMediaType( &mediaType ); CI_ASSERT( hr == S_OK ); auto mediaTypeManaged = ci::msw::makeComUnique( mediaType ); hr = mediaType->SetGUID( MF_MT_MAJOR_TYPE, MFMediaType_Audio ); CI_ASSERT( hr == S_OK ); const ::GUID audioFormat = getMfAudioFormat( mSampleType ); hr = mediaType->SetGUID( MF_MT_SUBTYPE, audioFormat ); CI_ASSERT( hr == S_OK ); hr = mediaType->SetUINT32( MF_MT_AUDIO_SAMPLES_PER_SECOND, (UINT32)mSampleRate ); CI_ASSERT( hr == S_OK ); hr = mediaType->SetUINT32( MF_MT_AUDIO_BITS_PER_SAMPLE, bitsPerSample ); CI_ASSERT( hr == S_OK ); hr = mediaType->SetUINT32( MF_MT_AUDIO_BLOCK_ALIGNMENT, blockAlignment ); CI_ASSERT( hr == S_OK ); hr = mediaType->SetUINT32( MF_MT_AUDIO_AVG_BYTES_PER_SECOND, averageBytesPerSecond ); CI_ASSERT( hr == S_OK ); hr = mediaType->SetUINT32( MF_MT_AUDIO_NUM_CHANNELS, (UINT32)mNumChannels ); CI_ASSERT( hr == S_OK ); hr = mediaType->SetUINT32( MF_MT_ALL_SAMPLES_INDEPENDENT, 1 ); CI_ASSERT( hr == S_OK ); hr = mediaType->SetUINT32( MF_MT_FIXED_SIZE_SAMPLES, 1 ); CI_ASSERT( hr == S_OK ); hr = mSinkWriter->AddStream( mediaType, &mStreamIndex ); CI_ASSERT( hr == S_OK ); // Tell the sink writer to start accepting data. hr = mSinkWriter->BeginWriting(); CI_ASSERT( hr == S_OK ); }
HRESULT EncodeTransform::SetInputMediaType() { if (!mpEncoder) { return MF_E_NOT_INITIALIZED; } IMFMediaType* pMediaTypeIn = NULL; HRESULT hr = MFCreateMediaType(&pMediaTypeIn); // Set the input media type. if (SUCCEEDED(hr)) { hr = pMediaTypeIn->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); } if (SUCCEEDED(hr)) { hr = pMediaTypeIn->SetGUID(MF_MT_SUBTYPE, cVideoInputFormat); } if (SUCCEEDED(hr)) { hr = pMediaTypeIn->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive); } if (SUCCEEDED(hr)) { hr = MFSetAttributeSize(pMediaTypeIn, MF_MT_FRAME_SIZE, mStreamWidth, mStreamHeight); } if (SUCCEEDED(hr)) { hr = MFSetAttributeRatio(pMediaTypeIn, MF_MT_FRAME_RATE, VIDEO_FPS, 1); } if (SUCCEEDED(hr)) { hr = MFSetAttributeRatio(pMediaTypeIn, MF_MT_PIXEL_ASPECT_RATIO, 1, 1); } if (SUCCEEDED(hr)) { hr = mpEncoder->SetInputType(0, pMediaTypeIn, 0); // if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) { std::cout << "MF_E_TRANSFORM_TYPE_NOT_SET -> 0xC00D6D60L: You must set the output type first" << std::endl; } if (hr == MF_E_INVALIDMEDIATYPE) { std::cout << "MF_E_INVALIDMEDIATYPE -> 0xc00d36b4: the data specified for the media type is invalid, inconsistent, or not supported by this object" << std::endl; } #if defined(CODECAPI_AVLowLatencyMode) // Win8 only hr = mpEncoder->QueryInterface(IID_PPV_ARGS(&mpCodecAPI)); if (SUCCEEDED(hr)) { VARIANT var; var.vt = VT_UI4; var.ulVal = eAVEncCommonRateControlMode_Quality; hr = mpCodecAPI->SetValue(&CODECAPI_AVEncCommonRateControlMode, &var); if (FAILED(hr)){printf("Failed to set rate control mode.\n");} var.vt = VT_BOOL; var.boolVal = VARIANT_TRUE; hr = mpCodecAPI->SetValue(&CODECAPI_AVLowLatencyMode, &var); if (FAILED(hr)){ printf("Failed to enable low latency mode.\n"); } // This property controls the quality level when the encoder is not using a constrained bit rate. The AVEncCommonRateControlMode property determines whether the bit rate is constrained. VARIANT quality; InitVariantFromUInt32(50, &quality); hr = mpCodecAPI->SetValue(&CODECAPI_AVEncCommonQuality, &quality); if (FAILED(hr)){ printf("Failed to adjust quality mode.\n"); } } #endif } return hr; }
VideoCompressorResult VideoCompressor::OpenFile(const String &Filename, UINT Width, UINT Height, UINT BitRate, UINT FrameRate, UINT AudioDeviceIndex, Clock *Timer) { VideoCompressorResult Result = VideoCompressorResultSuccess; _Width = Width; _Height = Height; _CapturingAudio = (AudioDeviceIndex != 0xFFFFFFFF); _Clock = Timer; HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); //PersistentAssert(SUCCEEDED(hr), "CoInitializeEx failed"); hr = MFStartup(MF_VERSION); PersistentAssert(SUCCEEDED(hr), "MFStartup failed"); hr = MFCreateSinkWriterFromURL( UnicodeString(Filename).CString(), NULL, NULL, &_Writer ); PersistentAssert(SUCCEEDED(hr), "MFCreateSinkWriterFromURL failed"); const UINT RawBufferSize = Width * Height * 4; IMFMediaType *OutputMediaType; MFCreateMediaType(&OutputMediaType); InitMediaType(OutputMediaType, MFVideoFormat_H264, BitRate, Width, Height, FrameRate); IMFMediaType *InputMediaType; MFCreateMediaType(&InputMediaType); InitMediaType(InputMediaType, MFVideoFormat_RGB32, RawBufferSize, Width, Height, FrameRate); DWORD VideoStreamIndex; hr = _Writer->AddStream(OutputMediaType, &VideoStreamIndex); PersistentAssert(SUCCEEDED(hr), "AddStream failed"); OutputMediaType->Release(); /*hr = MFTRegisterLocalByCLSID( __uuidof(CColorConvertDMO), MFT_CATEGORY_VIDEO_PROCESSOR, L"", MFT_ENUM_FLAG_SYNCMFT, 0, NULL, 0, NULL ); PersistentAssert(SUCCEEDED(hr), "MFTRegisterLocalByCLSID failed");*/ hr = _Writer->SetInputMediaType(VideoStreamIndex, InputMediaType, NULL); InputMediaType->Release(); if(FAILED(hr)) { if(Width > 1920 || Height > 1080) { MessageBox(NULL, "The maximum resolution for H.264 video is 1920x1080.", "Invalid Window Dimensions", MB_OK | MB_ICONERROR); } else { MessageBox(NULL, "There was an error when attempting to initialize video capture. The maximum resolution for H.264 video is 1920x1080.", "Invalid Window Dimensions", MB_OK | MB_ICONERROR); } _Writer->Release(); _Writer = NULL; _Clock = NULL; return VideoCompressorResultFailure; } if(_CapturingAudio) { // // Setup the output media type // IMFMediaType *OutputAudioType; hr = MFCreateMediaType( &OutputAudioType ); PersistentAssert(SUCCEEDED(hr), "MFCreateMediaType failed"); const UINT SamplesPerSecond = 44100; const UINT AverageBytesPerSecond = 24000; const UINT ChannelCount = 2; const UINT BitsPerSample = 16; OutputAudioType->SetGUID( MF_MT_MAJOR_TYPE, MFMediaType_Audio ) ; OutputAudioType->SetGUID( MF_MT_SUBTYPE, MFAudioFormat_AAC ) ; OutputAudioType->SetUINT32( MF_MT_AUDIO_SAMPLES_PER_SECOND, SamplesPerSecond ) ; OutputAudioType->SetUINT32( MF_MT_AUDIO_BITS_PER_SAMPLE, BitsPerSample ) ; OutputAudioType->SetUINT32( MF_MT_AUDIO_NUM_CHANNELS, ChannelCount ) ; OutputAudioType->SetUINT32( MF_MT_AUDIO_AVG_BYTES_PER_SECOND, AverageBytesPerSecond ) ; OutputAudioType->SetUINT32( MF_MT_AUDIO_BLOCK_ALIGNMENT, 1 ) ; //OutputAudioType->SetUINT32( MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 0x29 ) ; DWORD AudioStreamIndex; hr = _Writer->AddStream( OutputAudioType, &AudioStreamIndex ); PersistentAssert(SUCCEEDED(hr), "AddStream failed"); // // Setup the input media type // IMFMediaType *InputAudioType; MFCreateMediaType( &InputAudioType ); InputAudioType->SetGUID( MF_MT_MAJOR_TYPE, MFMediaType_Audio ); InputAudioType->SetGUID( MF_MT_SUBTYPE, MFAudioFormat_PCM ); InputAudioType->SetUINT32( MF_MT_AUDIO_BITS_PER_SAMPLE, BitsPerSample ); InputAudioType->SetUINT32( MF_MT_AUDIO_SAMPLES_PER_SECOND, SamplesPerSecond ); InputAudioType->SetUINT32( MF_MT_AUDIO_NUM_CHANNELS, ChannelCount ); hr = _Writer->SetInputMediaType( AudioStreamIndex, InputAudioType, NULL ); PersistentAssert(SUCCEEDED(hr), "SetInputMediaType failed"); _AudioCapture.StartCapture(this, AudioDeviceIndex); } hr = _Writer->BeginWriting(); PersistentAssert(SUCCEEDED(hr), "BeginWriting failed"); hr = MFCreateSample(&_Sample); PersistentAssert(SUCCEEDED(hr), "MFCreateSample failed"); hr = MFCreateMemoryBuffer(RawBufferSize, &_Buffer); _Buffer->SetCurrentLength(RawBufferSize); _Sample->AddBuffer(_Buffer); return Result; }
bool initialise() { UINT32 videoDeviceCount = 0; IMFAttributes *videoConfig = NULL; IMFActivate **videoDevices = NULL; WCHAR *webcamFriendlyName; CHECK_HR(MFTRegisterLocalByCLSID( __uuidof(CColorConvertDMO), MFT_CATEGORY_VIDEO_PROCESSOR, L"", MFT_ENUM_FLAG_SYNCMFT, 0, NULL, 0, NULL ), "Error registering colour converter DSP.\n"); // Get the first available webcam. CHECK_HR(MFCreateAttributes(&videoConfig, 1), "Error creating video configuation.\n"); // Request video capture devices. CHECK_HR(videoConfig->SetGUID( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID), "Error initialising video configuration object."); CHECK_HR(MFEnumDeviceSources(videoConfig, &videoDevices, &videoDeviceCount), "Error enumerating video devices.\n"); CHECK_HR(videoDevices[WEBCAM_DEVICE_INDEX]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &webcamFriendlyName, NULL), "Error retrieving vide device friendly name.\n"); wprintf(L"First available webcam: %s\n", webcamFriendlyName); CHECK_HR(videoDevices[WEBCAM_DEVICE_INDEX]->ActivateObject(IID_PPV_ARGS(&videoSource)), "Error activating video device.\n"); // Create a source reader. CHECK_HR(MFCreateSourceReaderFromMediaSource( videoSource, videoConfig, &_videoReader), "Error creating video source reader.\n"); //ListModes(_videoReader); CHECK_HR(_videoReader->GetCurrentMediaType( (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, &videoSourceOutputType), "Error retrieving current media type from first video stream.\n"); Console::WriteLine(GetMediaTypeDescription(videoSourceOutputType)); // Note the webcam needs to support this media type. The list of media types supported can be obtained using the ListTypes function in MFUtility.h. MFCreateMediaType(&pSrcOutMediaType); pSrcOutMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); //pSrcOutMediaType->SetGUID(MF_MT_SUBTYPE, WMMEDIASUBTYPE_I420); pSrcOutMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB24); MFSetAttributeSize(pSrcOutMediaType, MF_MT_FRAME_SIZE, CAMERA_RESOLUTION_WIDTH, CAMERA_RESOLUTION_HEIGHT); CHECK_HR(MFSetAttributeRatio(pSrcOutMediaType, MF_MT_FRAME_RATE, TARGET_FRAME_RATE, 1), "Failed to set frame rate on video device out type.\n"); CHECK_HR(_videoReader->SetCurrentMediaType(0, NULL, pSrcOutMediaType), "Failed to set media type on source reader.\n"); //CHECK_HR(_videoReader->SetCurrentMediaType(0, NULL, videoSourceOutputType), "Failed to setdefault media type on source reader.\n"); // Create H.264 encoder. CHECK_HR(CoCreateInstance(CLSID_CMSH264EncoderMFT, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&spTransformUnk), "Failed to create H264 encoder MFT.\n"); CHECK_HR(spTransformUnk->QueryInterface(IID_PPV_ARGS(&_pTransform)), "Failed to get IMFTransform interface from H264 encoder MFT object.\n"); MFCreateMediaType(&pMFTOutputMediaType); pMFTOutputMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); pMFTOutputMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264); //pMFTOutputMediaType->SetUINT32(MF_MT_AVG_BITRATE, 240000); CHECK_HR(pMFTOutputMediaType->SetUINT32(MF_MT_AVG_BITRATE, TARGET_AVERAGE_BIT_RATE), "Failed to set average bit rate on H264 output media type.\n"); CHECK_HR(MFSetAttributeSize(pMFTOutputMediaType, MF_MT_FRAME_SIZE, CAMERA_RESOLUTION_WIDTH, CAMERA_RESOLUTION_HEIGHT), "Failed to set frame size on H264 MFT out type.\n"); CHECK_HR(MFSetAttributeRatio(pMFTOutputMediaType, MF_MT_FRAME_RATE, TARGET_FRAME_RATE, 1), "Failed to set frame rate on H264 MFT out type.\n"); CHECK_HR(MFSetAttributeRatio(pMFTOutputMediaType, MF_MT_PIXEL_ASPECT_RATIO, 1, 1), "Failed to set aspect ratio on H264 MFT out type.\n"); pMFTOutputMediaType->SetUINT32(MF_MT_INTERLACE_MODE, 2); // 2 = Progressive scan, i.e. non-interlaced. pMFTOutputMediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); //CHECK_HR(MFSetAttributeRatio(pMFTOutputMediaType, MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_Base), "Failed to set profile on H264 MFT out type.\n"); //CHECK_HR(pMFTOutputMediaType->SetDouble(MF_MT_MPEG2_LEVEL, 3.1), "Failed to set level on H264 MFT out type.\n"); //CHECK_HR(pMFTOutputMediaType->SetUINT32(MF_MT_MAX_KEYFRAME_SPACING, 10), "Failed to set key frame interval on H264 MFT out type.\n"); //CHECK_HR(pMFTOutputMediaType->SetUINT32(CODECAPI_AVEncCommonQuality, 100), "Failed to set H264 codec qulaity.\n"); //hr = pAttributes->SetUINT32(CODECAPI_AVEncMPVGOPSize, 1) CHECK_HR(_pTransform->SetOutputType(0, pMFTOutputMediaType, 0), "Failed to set output media type on H.264 encoder MFT.\n"); MFCreateMediaType(&pMFTInputMediaType); pMFTInputMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); pMFTInputMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_IYUV); CHECK_HR(MFSetAttributeSize(pMFTInputMediaType, MF_MT_FRAME_SIZE, CAMERA_RESOLUTION_WIDTH, CAMERA_RESOLUTION_HEIGHT), "Failed to set frame size on H264 MFT out type.\n"); CHECK_HR(MFSetAttributeRatio(pMFTInputMediaType, MF_MT_FRAME_RATE, TARGET_FRAME_RATE, 1), "Failed to set frame rate on H264 MFT out type.\n"); CHECK_HR(MFSetAttributeRatio(pMFTInputMediaType, MF_MT_PIXEL_ASPECT_RATIO, 1, 1), "Failed to set aspect ratio on H264 MFT out type.\n"); pMFTInputMediaType->SetUINT32(MF_MT_INTERLACE_MODE, 2); CHECK_HR(_pTransform->SetInputType(0, pMFTInputMediaType, 0), "Failed to set input media type on H.264 encoder MFT.\n"); CHECK_HR(_pTransform->GetInputStatus(0, &mftStatus), "Failed to get input status from H.264 MFT.\n"); if (MFT_INPUT_STATUS_ACCEPT_DATA != mftStatus) { printf("E: ApplyTransform() pTransform->GetInputStatus() not accept data.\n"); goto done; } //Console::WriteLine(GetMediaTypeDescription(pMFTOutputMediaType)); CHECK_HR(_pTransform->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, NULL), "Failed to process FLUSH command on H.264 MFT.\n"); CHECK_HR(_pTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL), "Failed to process BEGIN_STREAMING command on H.264 MFT.\n"); CHECK_HR(_pTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, NULL), "Failed to process START_OF_STREAM command on H.264 MFT.\n"); memset(&_outputDataBuffer, 0, sizeof _outputDataBuffer); return true; done: printf("MediaFoundationH264LiveSource initialisation failed.\n"); return false; }
STDMETHODIMP CDecWMV9MFT::InitDecoder(AVCodecID codec, const CMediaType *pmt) { HRESULT hr = S_OK; DbgLog((LOG_TRACE, 10, L"CDecWMV9MFT::InitDecoder(): Initializing WMV9 MFT decoder")); DestroyDecoder(false); BITMAPINFOHEADER *pBMI = nullptr; REFERENCE_TIME rtAvg = 0; DWORD dwARX = 0, dwARY = 0; videoFormatTypeHandler(*pmt, &pBMI, &rtAvg, &dwARX, &dwARY); size_t extralen = 0; BYTE *extra = nullptr; getExtraData(*pmt, nullptr, &extralen); if (extralen > 0) { extra = (BYTE *)av_mallocz(extralen + FF_INPUT_BUFFER_PADDING_SIZE); getExtraData(*pmt, extra, &extralen); } if (codec == AV_CODEC_ID_VC1 && extralen) { size_t i = 0; for (i = 0; i < (extralen - 4); i++) { uint32_t code = AV_RB32(extra + i); if ((code & ~0xFF) == 0x00000100) break; } if (i == 0) { memmove(extra + 1, extra, extralen); *extra = 0; extralen++; } else if (i > 1) { DbgLog((LOG_TRACE, 10, L"-> VC-1 Header at position %u (should be 0 or 1)", i)); } } if (extralen > 0) { m_vc1Header = new CVC1HeaderParser(extra, extralen, codec); } /* Create input type */ m_nCodecId = codec; IMFMediaType *pMTIn = nullptr; MF.CreateMediaType(&pMTIn); pMTIn->SetUINT32(MF_MT_COMPRESSED, TRUE); pMTIn->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, FALSE); pMTIn->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, FALSE); pMTIn->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); pMTIn->SetGUID(MF_MT_SUBTYPE, VerifySubtype(codec, pmt->subtype)); MFSetAttributeSize(pMTIn, MF_MT_FRAME_SIZE, pBMI->biWidth, pBMI->biHeight); UINT32 rateNum = 0, rateDen = 0; MF.AverageTimePerFrameToFrameRate(rtAvg, &rateNum, &rateDen); MFSetAttributeRatio(pMTIn, MF_MT_FRAME_RATE, rateNum, rateDen); pMTIn->SetBlob(MF_MT_USER_DATA, extra, (UINT32)extralen); av_freep(&extra); hr = m_pMFT->SetInputType(0, pMTIn, 0); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"-> Failed to set input type on MFT")); return hr; } /* Create output type */ hr = SelectOutputType(); SafeRelease(&pMTIn); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"-> Failed to set output type on MFT")); return hr; } IMFMediaType *pMTOut = nullptr; m_pMFT->GetOutputCurrentType(0, &pMTOut); m_bInterlaced = MFGetAttributeUINT32(pMTOut, MF_MT_INTERLACE_MODE, MFVideoInterlace_Unknown) > MFVideoInterlace_Progressive; SafeRelease(&pMTOut); m_bManualReorder = (codec == AV_CODEC_ID_VC1) && !(m_pCallback->GetDecodeFlags() & LAV_VIDEO_DEC_FLAG_ONLY_DTS); return S_OK; }
/** Add stream to topology */ FIntPoint FImfVideoPlayer::AddStreamToTopology( IMFTopology* Topology, IMFPresentationDescriptor* PresentationDesc, IMFStreamDescriptor* StreamDesc, FImfSampleGrabberCallback* SampleGrabberCallback ) { FIntPoint OutDimensions = FIntPoint( ForceInit ); HRESULT HResult = S_OK; IMFActivate* SinkActivate = NULL; { IMFMediaTypeHandler* Handler = NULL; HResult = StreamDesc->GetMediaTypeHandler( &Handler ); check( SUCCEEDED( HResult ) ); GUID MajorType; HResult = Handler->GetMajorType( &MajorType ); check( SUCCEEDED( HResult ) ); /* Audio stream */ if( MajorType == MFMediaType_Audio ) { /* No audio required */ Handler->Release( ); return FIntPoint( ForceInit ); } /* Video stream */ else if( MajorType == MFMediaType_Video ) { IMFMediaType* OutputType = NULL; HResult = Handler->GetCurrentMediaType( &OutputType ); check( SUCCEEDED( HResult ) ); IMFMediaType* InputType = NULL; HResult = MFCreateMediaType( &InputType ); UINT32 Width = 0, Height = 0; HResult = MFGetAttributeSize( OutputType, MF_MT_FRAME_SIZE, &Width, &Height ); check( SUCCEEDED( HResult ) ); HResult = InputType->SetGUID( MF_MT_MAJOR_TYPE, MFMediaType_Video ); check( SUCCEEDED( HResult ) ); HResult = InputType->SetGUID( MF_MT_SUBTYPE, MFVideoFormat_RGB32 ); check( SUCCEEDED( HResult ) ); HResult = InputType->SetUINT32( MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE ); check( SUCCEEDED( HResult ) ); HResult = MFCreateSampleGrabberSinkActivate( InputType, SampleGrabberCallback, &SinkActivate ); check( SUCCEEDED( HResult ) ); InputType->Release( ); OutputType->Release( ); OutDimensions = FIntPoint( Width, Height ); } Handler->Release( ); } IMFTopologyNode* SourceNode = NULL; { HResult = MFCreateTopologyNode( MF_TOPOLOGY_SOURCESTREAM_NODE, &SourceNode ); check( SUCCEEDED( HResult ) ); HResult = SourceNode->SetUnknown( MF_TOPONODE_SOURCE, MediaSource ); check( SUCCEEDED( HResult ) ); HResult = SourceNode->SetUnknown( MF_TOPONODE_PRESENTATION_DESCRIPTOR, PresentationDesc ); check( SUCCEEDED( HResult ) ); HResult = SourceNode->SetUnknown( MF_TOPONODE_STREAM_DESCRIPTOR, StreamDesc ); check( SUCCEEDED( HResult ) ); HResult = Topology->AddNode( SourceNode ); check( SUCCEEDED( HResult ) ); } IMFTopologyNode* OutputNode = NULL; { HResult = MFCreateTopologyNode( MF_TOPOLOGY_OUTPUT_NODE, &OutputNode ); check( SUCCEEDED( HResult ) ); HResult = OutputNode->SetObject( SinkActivate ); check( SUCCEEDED( HResult ) ); HResult = OutputNode->SetUINT32( MF_TOPONODE_STREAMID, 0 ); check( SUCCEEDED( HResult ) ); HResult = OutputNode->SetUINT32( MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, 0 ); check( SUCCEEDED( HResult ) ); HResult = Topology->AddNode( OutputNode ); check( SUCCEEDED( HResult ) ); } HResult = SourceNode->ConnectOutput( 0, OutputNode, 0 ); check( SUCCEEDED( HResult ) ); SourceNode->Release( ); OutputNode->Release( ); SinkActivate->Release( ); return OutDimensions; }