моя реализация кодировщика получает в качестве входных .wav
байтов файла и дает в качестве вывода .mp3
байтов, записанных в файле.
Так
void co_AudioEncoderMF::start_encoding()
{
...
IMFSinkWriter * sink_writer = nullptr;
//Create sink writer
HRESULT hr = MFCreateSinkWriterFromURL(
L"D:\\buffer\\del\\out\\test_out.mp3",
NULL,
NULL,
&sink_writer
);
...
// Add the stream
hr = sink_writer->AddStream(
ouput_media_type,
&dwWriterStreamIndex
);
// Set input media type
hr = sink_writer->SetInputMediaType(
dwWriterStreamIndex,
input_type,
NULL
);
// Tell the sink writer to accept data
hr = sink_writer->BeginWriting();
...
hr = sink_writer->WriteSample(
dwWriterStreamIndex,
pSample
);
...
}
Итак, я создаю IMFSinkWriter, затем добавляю его в медиатип Stream + set, а затем я могу записывать закодированные байты в файл L"D:\\buffer\\del\\out\\test_out.mp3"
.
Проблема здесь в том, что я не хочу записывать закодированные данные в файл, мне нужно получить их в качестве буфера.
Я вижу, что есть еще один возможный метод
STDAPI MFCreateSinkWriterFromMediaSink(
_In_ IMFMediaSink *pMediaSink,
_In_opt_ IMFAttributes *pAttributes,
_Out_ IMFSinkWriter **ppSinkWriter );
Итак, насколько я понял, он принимает указатель на IMFMediaSink
и выходит на IMFSinkWriter
, с этого момента я понял, что могу реализовать интерфейс IMFMediaSink
, который создаст IMFSinkWriter
и настроит его при вызове метода MFCreateSinkWriterFromMediaSink
. (но я не уверен, что это правильный способ записи закодированных данных в буфер).
Итак, я реализовал IMFMediaSink
#include "co_MediaSink.h"
#include <stdio.h>
#include "co_SinkWriter.h"
co_MediaSink::co_MediaSink()
{
}
co_MediaSink::~co_MediaSink()
{
}
HRESULT co_MediaSink::QueryInterface(REFIID riid, void ** ppvObject)
{
printf("HERE");
*ppvObject = new co_SinkWriter();
return S_OK;
}
ULONG co_MediaSink::AddRef(void)
{
printf("HERE");
return 1;
}
ULONG co_MediaSink::Release(void)
{
printf("HERE");
return 1;
}
HRESULT co_MediaSink::GetCharacteristics(DWORD * pdwCharacteristics)
{
printf("HERE");
return S_OK;
}
HRESULT co_MediaSink::AddStreamSink(DWORD dwStreamSinkIdentifier, IMFMediaType * pMediaType, IMFStreamSink ** ppStreamSink)
{
printf("HERE");
return S_OK;
}
HRESULT co_MediaSink::RemoveStreamSink(DWORD dwStreamSinkIdentifier)
{
printf("HERE");
return S_OK;
}
HRESULT co_MediaSink::GetStreamSinkCount(DWORD * pcStreamSinkCount)
{
printf("HERE");
return S_OK;
}
HRESULT co_MediaSink::GetStreamSinkByIndex(DWORD dwIndex, IMFStreamSink ** ppStreamSink)
{
printf("HERE");
return S_OK;
}
HRESULT co_MediaSink::GetStreamSinkById(DWORD dwStreamSinkIdentifier, IMFStreamSink ** ppStreamSink)
{
printf("HERE");
return S_OK;
}
HRESULT co_MediaSink::SetPresentationClock(IMFPresentationClock * pPresentationClock)
{
printf("HERE");
return S_OK;
}
HRESULT co_MediaSink::GetPresentationClock(IMFPresentationClock ** ppPresentationClock)
{
printf("HERE");
return S_OK;
}
HRESULT co_MediaSink::Shutdown(void)
{
printf("HERE");
return S_OK;
}
Использование ::
IMFSinkWriter * sink_writer = nullptr;
co_MediaSink media_sink;
HRESULT hr = MFCreateSinkWriterFromMediaSink(&media_sink, nullptr, &sink_writer);
Итак, здесь с отладкой я вижу, что после того, как этот MFCreateSinkWriterFromMediaSink
метод был вызван, следующая точка останова отладки - метод входа co_MediaSink::QueryInterface(REFIID riid, void ** ppvObject)
, где мне нужно установить (я думаю) мою IMFSinkWriter
реализацию на этот указатель вывода ppvObject
вот так *ppvObject = new co_SinkWriter();
, но затем я получаю ошибка
Exception thrown at 0x00007FF95B4F8317 (mfreadwrite.dll) in co_Convert.exe: 0xC0000005: Access violation reading location 0x0000000000000000.
Итак, вопросов на самом деле два, первый правильно ли выбран способ записи в буфер и второй - если да, то в чем проблема с Access violation
?
IMFByteStream
из вашей разработки на стороне исходного кода)IMFMediaSink
для потока MP3MFCreateSinkWriterFromMediaSink
создаст IMFsinkWriter
поверх этого медиа-приемника, и вы уже знаете, как работать с приемниками-писателямиТаким образом, вы можете писать на стоковый писатель и принимать части потока байтов MP3 на другом конце.
Есть несколько вопросов: у меня нет идеи создать IMFByteStream
, я могу создать поток на данных, которые у меня есть, но как я могу создать поток на данных, которые я только собираюсь получить? Единственный способ, который я вижу здесь в соответствии с вашим ответом, - это создать пользовательскую реализацию IMFByteStream
, затем передать ее MFCreateMP3MediaSink
получить IMFMediaSink
как выходной параметр (не мой пользовательский), а затем передать его MFCreateSinkWriterFromMediaSink
и, наконец, получить IMFSinkWriter
как выходной параметр. Я так понимаю, когда я пишу в IMFSinkWriter
, он передает все байты в мой кастом IMFByteStream
, верно?
Правильный. Также можно добавить одну вещь к вышеизложенному: вы можете реализовать также реализовать IStream
или, может быть, даже использовать одну из существующих реализаций и использовать MFCreateMFByteStreamOnStream
поверх, если добавить еще один слой, но избежать реализации IMFByteStream
самостоятельно (имеет смысл, если вы не хотите путаница с асинхронными вызовами).
У меня возникли проблемы с реализацией IStream
, не могли бы вы взглянуть, пожалуйста, stackoverflow.com/q/65458867/5709159
Вы можете использовать исходный ридер, чтобы получить закодированный в mp3 буфер. Вам не нужно реализовывать собственный интерфейс.