如何正确实现 IStream (MediaFoundation)?

问题描述

总体思路是获取一个 IMFSinkWriter 将数据写入缓冲区。有这样一个实现

bool co_AudioEncoderMF::start_encoding_to()
{
    bool result = false;
    co_Stream stream;
    IMFByteStream * byte_stream = nullptr;
    IMFMediaSink * media_sink = nullptr;
    IMFSinkWriter * sink_writer = nullptr;

    HRESULT hr = MFCreateMFByteStreamOnStream(&stream,&byte_stream);

    if (SUCCEEDED(hr) && byte_stream != nullptr)
    {
        hr = MFCreateMP3MediaSink(byte_stream,&media_sink);
    }
    
    if (SUCCEEDED(hr) && media_sink != nullptr)
    {
        hr = MFCreateSinkWriterFromMediaSink(media_sink,nullptr,&sink_writer);
    }

    if (SUCCEEDED(hr) && sink_writer != nullptr)
    {
        result = start_encoding_to(sink_writer,m_source_reader);
    }

    return result;
}

在这里我创建了一个实现 co_Stream 的类 IStream(一个最小的实现,仅用于测试)

co_Stream.h

#pragma once
#include <ObjIdlbase.h>
#include <vector>

class co_Stream: public IStream
{
    //Constructors
public:
    co_Stream();
    ~co_Stream();

    //Public Methods
public:
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(
        /* [in] */ REFIID riid,/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject) override;

    virtual ULONG STDMETHODCALLTYPE AddRef(void) override;

    virtual ULONG STDMETHODCALLTYPE Release(void) override;

    virtual /* [local] */ HRESULT STDMETHODCALLTYPE Read(
        /* [annotation] */
        _Out_writes_bytes_to_(cb,*pcbRead)  void *pv,/* [annotation][in] */
        _In_  ULONG cb,/* [annotation] */
        _Out_opt_  ULONG *pcbRead) override;

    virtual /* [local] */ HRESULT STDMETHODCALLTYPE Write(
        /* [annotation] */
        _In_reads_bytes_(cb)  const void *pv,/* [annotation] */
        _Out_opt_  ULONG *pcbWritten) override;

    virtual /* [local] */ HRESULT STDMETHODCALLTYPE Seek(
        /* [in] */ LARGE_INTEGER dlibMove,/* [in] */ DWORD dwOrigin,/* [annotation] */
        _Out_opt_  ULARGE_INTEGER *plibNewPosition) override;

    virtual HRESULT STDMETHODCALLTYPE SetSize(
        /* [in] */ ULARGE_INTEGER libNewSize) override;

    virtual /* [local] */ HRESULT STDMETHODCALLTYPE CopyTo(
        /* [annotation][unique][in] */
        _In_  IStream *pstm,/* [in] */ ULARGE_INTEGER cb,/* [annotation] */
        _Out_opt_  ULARGE_INTEGER *pcbRead,/* [annotation] */
        _Out_opt_  ULARGE_INTEGER *pcbWritten) override;

    virtual HRESULT STDMETHODCALLTYPE Commit(
        /* [in] */ DWORD grfCommitFlags) override;

    virtual HRESULT STDMETHODCALLTYPE Revert(void) override;

    virtual HRESULT STDMETHODCALLTYPE LockRegion(
        /* [in] */ ULARGE_INTEGER libOffset,/* [in] */ DWORD dwLockType) override;

    virtual HRESULT STDMETHODCALLTYPE UnlockRegion(
        /* [in] */ ULARGE_INTEGER libOffset,/* [in] */ DWORD dwLockType) override;

    virtual HRESULT STDMETHODCALLTYPE Stat(
        /* [out] */ __RPC__out STATSTG *pstatstg,/* [in] */ DWORD grfStatFlag) override;

    virtual HRESULT STDMETHODCALLTYPE Clone(
        /* [out] */ __RPC__deref_out_opt IStream **ppstm) override;

    //Private Members
private:
    LONG m_cRef; // Reference count.
    std::vector<unsigned char> m_buffer;
    long m_buf_position = 0;
};

co_Stream.cpp

#include "co_Stream.h"
#include <iostream>
#include <mfplay.h>

co_Stream::co_Stream()
{
    m_cRef = 0;
}


co_Stream::~co_Stream()
{
}

HRESULT co_Stream::QueryInterface(REFIID riid,void ** ppvObject)
{
    if (riid == IID_IMFGetService)
    {
        *ppvObject = (LPVOID)this;
        AddRef();
        return NOERROR;
    }
    
    return E_NOINTERFACE;
}

ULONG co_Stream::AddRef(void)
{
    InterlockedIncrement(&m_cRef);
    return m_cRef;
}

ULONG co_Stream::Release(void)
{
    InterlockedDecrement(&m_cRef);
    return m_cRef;
}

HRESULT co_Stream::Read(void * pv,ULONG cb,ULONG * pcbRead)
{
    std::cout << "HERE" << std::endl;
    
    if (!m_buffer.empty() && m_buffer.size() < cb)
    {
        memcpy(pv,&m_buffer[0],cb);
        return NOERROR;
    }

    return ERROR;
}

HRESULT co_Stream::Write(const void * pv,ULONG * pcbWritten)
{
    std::cout << "HERE" << std::endl;

    m_buffer.resize(cb);
    memcpy(&m_buffer[0],pv,cb);

    return NOERROR;
}

HRESULT co_Stream::Seek(LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER * plibNewPosition)
{
    std::cout << "HERE" << std::endl;
    return NOERROR;
}

HRESULT co_Stream::SetSize(ULARGE_INTEGER libNewSize)
{
    std::cout << "HERE" << std::endl;
    return NOERROR;
}

HRESULT co_Stream::CopyTo(IStream * pstm,ULARGE_INTEGER cb,ULARGE_INTEGER * pcbRead,ULARGE_INTEGER * pcbWritten)
{
    std::cout << "HERE" << std::endl;
    return NOERROR;
}

HRESULT co_Stream::Commit(DWORD grfCommitFlags)
{
    std::cout << "HERE" << std::endl;
    return NOERROR;
}

HRESULT co_Stream::Revert(void)
{
    std::cout << "HERE" << std::endl;
    return NOERROR;
}

HRESULT co_Stream::LockRegion(ULARGE_INTEGER libOffset,DWORD dwLockType)
{
    std::cout << "HERE" << std::endl;
    return NOERROR;
}

HRESULT co_Stream::UnlockRegion(ULARGE_INTEGER libOffset,DWORD dwLockType)
{
    std::cout << "HERE" << std::endl;
    return NOERROR;
}

HRESULT co_Stream::Stat(STATSTG * pstatstg,DWORD grfStatFlag)
{
    std::cout << "HERE" << std::endl;
    return NOERROR;
}

HRESULT co_Stream::Clone(IStream ** ppstm)
{
    std::cout << "HERE" << std::endl;
    return NOERROR;
}

这个想法是,这个方法 MFCreateMFByteStreamOnStream 将采用我的 IStream 实现并作为 out param IMFByteStream 返回,然后我需要创建一个接收器,最后创建接收器编写器。然后,每次我调用 writer 时,我都会在 IStream 实现中获取这些字节以供进一步使用。

但是在我调用 MFCreateMFByteStreamOnStream 并将 IStream 的实现作为参数传递后,我得到 IMFByteStream - null 作为输出参数。

在调试中,我看到在 IStream 实现中,我收到了 QueryInterface -> AddRef -> Read() -> Release()

我做错了什么?

编辑

这是我目前的实现

#include "co_Stream.h"
#include <iostream>
#include <mfplay.h>

co_Stream::co_Stream()
{
    m_cRef = 0;
}


co_Stream::~co_Stream()
{
}

HRESULT co_Stream::QueryInterface(REFIID riid,void ** ppvObject)
{
    return E_NOINTERFACE;
}

ULONG co_Stream::AddRef(void)
{
    InterlockedIncrement(&m_cRef);
    return m_cRef;
}

ULONG co_Stream::Release(void)
{
    InterlockedDecrement(&m_cRef);
    return m_cRef;
}

HRESULT co_Stream::Read(void * pv,ULONG * pcbRead)
{
    //This method is redundant in current implementation because it is needed only to write in buffer.
    return NOERROR;
}

HRESULT co_Stream::Write(const void * pv,ULONG * pcbWritten)
{
    m_buffer.resize(cb);
    memcpy(&m_buffer[0],DWORD grfStatFlag)
{
    std::cout << "HERE" << std::endl;
    return NOERROR;
}

HRESULT co_Stream::Clone(IStream ** ppstm)
{
    std::cout << "HERE" << std::endl;
    return NOERROR;
}

当我的方法 co_AudioEncoderMF::start_encoding_to()(在我的问题 co_AudioEncoderMF::start_encoding_to 上)接到电话时,我在 seekstat 收到电话,但我没有收到如果我需要进行缓冲区实现 (std::vector<unsigned char> m_buffer),请了解如何实现。

但无论如何,目前我没有遇到任何崩溃或错误,而且我的 Write 方法也没有被调用。

在y代码下面我有这样的方法

...
                hr = sink_writer->WriteSample(
                    dwWriterStreamIndex,pSample
                );
...

我看到 pSample 数据存在并且 dwWriterStreamIndex 具有值,但是当调用此方法时,我在 {{1} 的实现中没有收到 Write 调用}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)