【问题标题】:How to create sink writer from buffer?如何从缓冲区创建接收器写入器?
【发布时间】:2020-12-24 14:09:07
【问题描述】:

我的编码器实现将.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,然后将其添加到 straem + set mediatype 中,然后我可以将编码字节写入输出文件 L"D:\\buffer\\del\\out\\test_out.mp3"

这里的问题是我不想将编码数据写入输出文件,我需要将其作为缓冲区。

我知道还有另一种可能的方法

STDAPI MFCreateSinkWriterFromMediaSink(
    _In_ IMFMediaSink *pMediaSink,
    _In_opt_ IMFAttributes *pAttributes,
    _Out_ IMFSinkWriter **ppSinkWriter );

所以,据我所知,它需要指针指向 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 编码的缓冲区。您不需要实现自定义接口。

标签: c++ audio codec ms-media-foundation


【解决方案1】:
  1. 已实现字节流以接受数据(您在源端开发中已经熟悉IMFByteStream 概念)
  2. MFCreateMP3MediaSink(这是上述任务的关键 API)为 MP3 流创建 IMFMediaSink 的实现
  3. MFCreateSinkWriterFromMediaSink 将在此媒体接收器上创建一个IMFsinkWriter,您已经知道如何与接收器编写者合作

这样您可以写入接收器写入器并在另一端接受部分 MP3 字节流。

【讨论】:

  • 有几个问题:我没有创建IMFByteStream 的想法,我可以在我拥有的数据上创建流,但是如何在我只是的数据上创建流去取回?根据您的回答,我在这里看到的唯一方法是创建IMFByteStream 的自定义实现,然后将其传递给MFCreateMP3MediaSink 获取IMFMediaSink 作为输出参数(不是我的自定义),然后将其传递给MFCreateSinkWriterFromMediaSink 最后得到IMFSinkWriter 作为输出参数。我的理解是,当我写信给IMFSinkWriter 时,它会将所有字节传递给我的自定义IMFByteStream,对吧?
  • 正确。还有一件事要添加到上面:您还可以实现IStream,或者甚至可以使用现有实现之一并在 if 之上使用MFCreateMFByteStreamOnStream 以添加更多层,但避免自己实现IMFByteStream(如果你不想搞乱异步调用)。
  • 我遇到了IStream 实现的问题,请您看看stackoverflow.com/q/65458867/5709159
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-14
  • 1970-01-01
  • 1970-01-01
  • 2016-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多