Как создать стоковую запись из буфера?

моя реализация кодировщика получает в качестве входных .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?

Вы можете использовать исходный ридер, чтобы получить закодированный в mp3 буфер. Вам не нужно реализовывать собственный интерфейс.

mofo77 25.12.2020 19:20
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
212
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
  1. Внедрите поток байтов для приема данных (вы уже знакомы с концепцией IMFByteStream из вашей разработки на стороне исходного кода)
  2. Попросите MFCreateMP3MediaSink (это ключевой API для указанной задачи) создать реализацию IMFMediaSink для потока MP3
  3. MFCreateSinkWriterFromMediaSink создаст IMFsinkWriter поверх этого медиа-приемника, и вы уже знаете, как работать с приемниками-писателями

Таким образом, вы можете писать на стоковый писатель и принимать части потока байтов MP3 на другом конце.

Есть несколько вопросов: у меня нет идеи создать IMFByteStream, я могу создать поток на данных, которые у меня есть, но как я могу создать поток на данных, которые я только собираюсь получить? Единственный способ, который я вижу здесь в соответствии с вашим ответом, - это создать пользовательскую реализацию IMFByteStream, затем передать ее MFCreateMP3MediaSink получить IMFMediaSink как выходной параметр (не мой пользовательский), а затем передать его MFCreateSinkWriterFromMediaSink и, наконец, получить IMFSinkWriter как выходной параметр. Я так понимаю, когда я пишу в IMFSinkWriter, он передает все байты в мой кастом IMFByteStream, верно?

Sirop4ik 25.12.2020 19:00

Правильный. Также можно добавить одну вещь к вышеизложенному: вы можете реализовать также реализовать IStream или, может быть, даже использовать одну из существующих реализаций и использовать MFCreateMFByteStreamOnStream поверх, если добавить еще один слой, но избежать реализации IMFByteStream самостоятельно (имеет смысл, если вы не хотите путаница с асинхронными вызовами).

Roman R. 25.12.2020 19:05

У меня возникли проблемы с реализацией IStream, не могли бы вы взглянуть, пожалуйста, stackoverflow.com/q/65458867/5709159

Sirop4ik 26.12.2020 18:23

Другие вопросы по теме