我可以用写我与这个样本了解到图像的视频文件在这里 。 它采用IMFSample
和IMFSinkWriter
。 现在我想音频添加到它。 假设有Audio.wma文件,我想在视频文件中写入该音频。
但无法弄清楚如何做到这样本。 像输入输出类型的设置,事情IMFSample
创建音频缓冲等等这将是一个伟大的,如果有人能告诉我如何将音频添加到使用水槽作家的视频文件。
我可以用写我与这个样本了解到图像的视频文件在这里 。 它采用IMFSample
和IMFSinkWriter
。 现在我想音频添加到它。 假设有Audio.wma文件,我想在视频文件中写入该音频。
但无法弄清楚如何做到这样本。 像输入输出类型的设置,事情IMFSample
创建音频缓冲等等这将是一个伟大的,如果有人能告诉我如何将音频添加到使用水槽作家的视频文件。
媒体基金会是伟大的工作,我确信你将能够快速修改项目完成这件事。
概述:
创建新IMFMediaSource
从音频文件中读取样品,添加音频流水槽,最后交错使用相应的流索引水槽写道。
细节:
修改VideoGenerator::InitializeSinkWriter(..)
函数正确初始化水槽以容纳音频流。 在该功能,正确地创建audioTypeOut和audioTypeIn( IMFMediaType
)。 您可能要mediaTypeOut和mediaTypeIn重命名为videoTypeOut和videoTypeIn为清楚起见,这似乎像下面这样:
ComPtr<IMFMediaType> videoTypeOut; // <-- previously mediaTypeOut
ComPtr<IMFMediaType> videoTypeIn; // <-- previously mediaTypeIn
ComPtr<IMFMediaType> audioTypeOut = nullptr;
ComPtr<IMFMediaType> audioTypeIn = nullptr;
接下来,配置您的视频类型兼容的音频输出类型。 既然你似乎是创建一个Windows媒体视频,你可能会想使用MFAudioFormat_WMAudioV9
。 为了保证每次采样的通道,采样率,和比特是正确的,我一般枚举可用类型和找到所希望的特性,类似于以下(错误检查已被省略):
ComPtr<IMFCollection> availableTypes = nullptr;
HRESULT hr = MFTranscodeGetAudioOutputAvailableTypes(MFAudioFormat_WMAudioV9, MFT_ENUM_FLAG_ALL, NULL, availableTypes.GetAddressOf());
DWORD count = 0;
hr = availableTypes->GetElementCount(&count)); // Get the number of elements in the list.
ComPtr<IUnknown> pUnkAudioType = nullptr;
ComPtr<IMFMediaType> audioOutputType = nullptr;
for (DWORD i = 0; i < count; ++i)
{
hr = availableTypes->GetElement(i, pUnkAudioType.GetAddressOf());
hr = pUnkAudioType.Get()->QueryInterface(IID_PPV_ARGS(audioTypeOut.GetAddressOf()));
// compare channels, sampleRate, and bitsPerSample to target numbers
{
// audioTypeOut is set!
break;
}
audioOutputType.Reset();
}
availableTypes.Reset();
如果audioTypeOut设置成功,这种类型的流添加到水槽,并获得最终得到的指数:
hr = sinkWriter->AddStream(audioTypeOut.Get(), &audioStreamIndex);
audioTypeOut.Reset(); // <-- audioTypeOut not needed anymore
最后,对于水槽,音频输入类型必须设置,这将取决于你正在阅读的文件,以及音频源( IMFMediaSource
)。 马上有更多介绍,但添加了音频输入水槽将类似于以下内容:
ComPtr<IMFMediaType> audioTypeIn = nullptr; // <-- declaration from above
// NOTE: audioReader is an IMFMediaSource used to read the audio file
hr = audioReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, audioTypeIn.GetAddressOf());
hr = sinkWriter->SetInputMediaType(_audioOutStreamIndex, audioTypeIn.Get(), nullptr);
audioTypeIn.Reset();
有可用于创建audioReader(很多例子IMFMediaSource
),并从文件中读取样本,但是这一个是简单和直接的。 该代码是在这里 。
最后,写入音频,你会发现,是很容易,因为宿可以采取直接取样( IMFSample
你从文件中读取)。 你到管理的目标,但是一个解决方案是交织写入(视频/音频)。 音频采样的持续时间被处理,但你需要重订的时间戳。 确保写入水槽,当你有正确的流索引。
阅读使用异步回调样本和:
// if you are using an async callback, the function would look similar to the following:
HRESULT OnReadAudioSample(HRESULT status, DWORD streamIndex, DWORD streamFlags, LONGLONG timestamp, IMFSample *sample)
{
// .. other code
hr = sample->SetSampleTime(timestamp - _baseRecordTime);
hr = sinkWriter->WriteSample(audioStreamIndex, sample);
// .. other code
// trigger the next asyc read...
hr = audioReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, nullptr, nullptr, nullptr, nullptr);
}
阅读样本同步:
// otherwise, you will only use a synchronous read
hr = audioReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, nullptr, &dwFlags, ×tamp, &sample);
hr = sample->SetSampleTime(timestamp - _baseRecordTime);
hr = sinkWriter->WriteSample(audioStreamIndex, sample);
hr = WriteFrame(target.get(), rtStart, rtDuration); // <-- write video frame as before
听起来像一个有趣的小项目。 祝你好运,玩得开心,并希望这有助于!