Я пытаюсь создать аудио-визуализатор, используя Microsoft Media Foundation.Для этого мне нужно перехватить сэмплы и одновременно их воспроизвести.Использование мультимедийного сеанса с топологией и приемником захвата образцов кажется непрактичным и чрезмерно сложным, поэтому я пытаюсь использовать для этого комбинацию Sink Reader и Sink Writer (см. Правую половину изображения на ОбзорМедиа Фонд Архитектура ).К сожалению, Воспроизведение аудио / видео не совсем объясняет, как это сделать.Книга Разработка приложений Microsoft Media Foundation содержит цикл от источника до приемника на стр. 92, но это все равно мне не очень помогает.
Создание Source Reader работает хорошо, и ячтение ненулевых образцов.Запись их в Sink Writer (который использует Streaming Audio Renderer) не дает мне никаких ошибок, но я ничего не слышу.Я пробовал несколько вещей, таких как выбор других типов мультимедиа и явный выбор устройства рендеринга (хотя у меня есть только один, как указано), но безрезультатно.Обратите внимание, что воспроизведение аудио с использованием Media Session работает нормально!
Я основал свой код на этом вопросе: Воспроизведение аудио из файла на динамик с помощью 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
, я не устанавливал тип носителя, но теперь я часто (но не всегда, дляпочему-то) получить MF_E_TOPO_CODEC_NOT_FOUND
на линии winHr(writer->SetInputMediaType(0, inputType, nullptr));
.С чего бы это?(В любом случае звук не воспроизводится.)
Редактировать 2: Очевидно, это имеет значение, когда я создаю писателя, так что теперь я делаю это только в последний момент, но теперь я получаю "Mediaтип не поддерживается "ошибка.Может быть, мне нужно вручную выбрать какой-либо тип носителя, но я рассмотрю это позже - если кто-то не знает ответа.