【发布时间】:2019-07-21 17:28:37
【问题描述】:
我正在尝试使用 Microsoft Media Foundation 创建音频可视化工具。为此,我需要截取样本并同时播放它们。使用带拓扑的媒体会话和采样采集器接收器似乎不切实际且过于复杂,因此我试图为此使用接收器读取器和接收器写入器的组合(请参阅Overview of the Media Foundation Architecture 上图像的右半部分) .不幸的是,Audio/Video Playback 并没有真正解释如何做到这一点。 Developing Microsoft Media Foundation Applications 一书在第 92 页包含一个 source-to-sink 循环,但这仍然对我没有帮助。
创建源阅读器工作正常,我正在阅读非零样本。将它们写入接收器写入器(使用流式音频渲染器)不会给我任何错误,但我什么也没听到。我尝试了多种方法,例如选择其他媒体类型并明确选择渲染设备(尽管我只有一个,正如它所指示的那样),但无济于事。请注意,使用媒体会话播放音频效果很好!
我的代码基于这个问题:Play audio from file to speaker with Media Foundation。
这是我此刻的代码:
#include <iostream>
#include <cassert>
#include <mfidl.h>
#include <mfapi.h>
#include <mfreadwrite.h>
#include <Mferror.h>
#pragma comment(lib, "mf")
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mfreadwrite")
#include <winrt/base.h>
#pragma comment(lib, "windowsapp")
void winHr(const HRESULT result) { winrt::check_hresult(result); }
template<class T>
struct ComPtr : winrt::com_ptr<T>
{
auto operator&() noexcept { return this->put(); }
operator T*() noexcept
{
assert(this->get());
return this->get();
}
};
int main() noexcept
{
winHr(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
winHr(MFStartup(MF_VERSION));
{
ComPtr<IMFSourceReader> reader;
winHr(MFCreateSourceReaderFromURL(
LR"(test.wav)",
nullptr, &reader));
constexpr auto inStreamIndex = MF_SOURCE_READER_FIRST_AUDIO_STREAM;
// Select only the audio stream
winHr(reader->SetStreamSelection(MF_SOURCE_READER_ALL_STREAMS, false));
winHr(reader->SetStreamSelection(inStreamIndex, true));
ComPtr<IMFMediaSink> mediaSink;
winHr(MFCreateAudioRenderer(nullptr, &mediaSink));
ComPtr<IMFSinkWriter> writer;
{
ComPtr<IMFStreamSink> streamSink;
winHr(mediaSink->GetStreamSinkByIndex(0, &streamSink));
ComPtr<IMFMediaTypeHandler> typeHandler;
winHr(streamSink->GetMediaTypeHandler(&typeHandler));
ComPtr<IMFMediaType> inputType;
winHr(reader->GetCurrentMediaType(inStreamIndex, &inputType));
ComPtr<IMFMediaType> closestSupportedType;
const auto result = typeHandler->IsMediaTypeSupported(inputType, &closestSupportedType);
if (result == MF_E_INVALIDMEDIATYPE)
{
if (!closestSupportedType)
{
std::cerr << "Media type not supported" << std::endl;
winHr(mediaSink->Shutdown());
goto end; //:o
}
winHr(reader->SetCurrentMediaType(inStreamIndex, nullptr, closestSupportedType));
winHr(typeHandler->SetCurrentMediaType(closestSupportedType));
winHr(MFCreateSinkWriterFromMediaSink(mediaSink, nullptr, &writer));
winHr(writer->SetInputMediaType(0, closestSupportedType, nullptr));
}
else {
winHr(result);
winHr(reader->SetCurrentMediaType(inStreamIndex, nullptr, inputType));
winHr(typeHandler->SetCurrentMediaType(inputType));
winHr(MFCreateSinkWriterFromMediaSink(mediaSink, nullptr, &writer));
winHr(writer->SetInputMediaType(0, inputType, nullptr));
}
}
winHr(writer->BeginWriting());
while (true)
{
ComPtr<IMFSample> sample;
DWORD streamFlags;
MFTIME timestamp;
winHr(reader->ReadSample(inStreamIndex, 0, nullptr, &streamFlags, ×tamp, &sample));
if (streamFlags & MF_SOURCE_READERF_ENDOFSTREAM)
{
winHr(writer->NotifyEndOfSegment(0));
break;
}
if (streamFlags & MF_SOURCE_READERF_STREAMTICK)
winHr(writer->SendStreamTick(0, timestamp));
if (!sample) continue;
winHr(sample->SetSampleTime(timestamp));
winHr(writer->WriteSample(0, sample));
}
winHr(writer->Flush(0));
std::cout << "(Press enter to stop)" << std::endl;
std::cin.get();
winHr(writer->Finalize());
writer.attach(nullptr);
winHr(mediaSink->Shutdown());
}
end:
winHr(MFShutdown());
CoUninitialize();
}
要明确一点:当我运行它时,它会打印出(Press enter to stop),我可以从耳机的噪音(阅读:电子信号的失真)中听到,我可以在短时间内推断出音频端口已打开然后关闭,但没有播放实际音频。我怎样才能让它工作?
编辑 1:我刚刚修复了如果 result != MF_E_INVALIDMEDIATYPE 我没有设置媒体类型,但现在我经常(但不总是,由于某种原因)在 winHr(writer->SetInputMediaType(0, inputType, nullptr)); 行得到 MF_E_TOPO_CODEC_NOT_FOUND。为什么会这样? (在任何情况下仍然没有播放音频。)
编辑 2:显然,当我创建作家时,这很重要,所以现在我只在最后一刻这样做,但现在我收到“不支持媒体类型”错误。也许我需要手动选择一些媒体类型,但我稍后会研究这个——除非有人知道答案。
【问题讨论】:
-
您可以检查此代码是否有效:github.com/sipsorcery/mediafoundationsamples/blob/master/…。检查以下评论后的行“我的扬声器有 3 种音频类型,但我只能使用第三种音频类型。”
-
@VuVirt 感谢您的回复!我已经尝试过类似的代码(来自链接的问题),无论我选择哪种媒体类型索引,它都不起作用;但显然这段代码是不同的,因为类型 3 它确实输出了一些东西 - 但它播放得太快了,可能是因为类型不完全匹配。当然,这已经聊胜于无了,但不幸的是,这远非解决之道。
标签: c++ audio com playback ms-media-foundation