Media Foundationを使用する場合、「unsigned char const *」から読み取る方法は?

Nov 23 2020

私はそのような実装を持っています

void coAudioPlayerSampleGrabber::test(SoundDataType dataType,
    unsigned char const * pData,
    int64_t dataLen)
{
    HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);

    IMFSourceReader *pReader = NULL;
    IMFByteStream * spByteStream = NULL;

    HRESULT hr = S_OK;
    // Initialize the COM library.
    hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

    // Initialize the Media Foundation platform.
    if (SUCCEEDED(hr))
    {
        hr = MFStartup(MF_VERSION);
    }

    hr = MFCreateMFByteStreamOnStreamEx((IUnknown*)pData, &spByteStream);

    if (FAILED(hr))
    {
        printf("Error MFCreateMFByteStreamOnStreamEx");
    }

    IMFAttributes * Atrr = NULL;
    hr = MFCreateAttributes(&Atrr, 10);

    if (FAILED(hr))
    {
        printf("Error MFCreateAttributes");
    }

    hr = Atrr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true);

    if (FAILED(hr))
    {
        printf("Error Atrr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true)");
    }

    hr = MFCreateSourceReaderFromByteStream(spByteStream, Atrr, &pReader);

    if (FAILED(hr))
    {
        printf("Error MFCreateSourceReaderFromByteStream");
    }

    if (FAILED(hr))
    {
        printf("Error opening input file");
    }

    IMFMediaType *pAudioType = NULL;    // Represents the PCM audio format.
    hr = ConfigureAudioStream(dataType, pReader, &pAudioType);

    if (FAILED(hr))
    {
        printf("Error ConfigureAudioStream");
    }

    IMFSample *pSample = NULL;
    IMFMediaBuffer *pBuffer = NULL;
    BYTE *pAudioData = NULL;
    DWORD cbBuffer = 0;

    std::vector<SampleData> samples_vec;

    while (true) 
    {
        DWORD dwFlags = 0;
        hr = pReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, NULL, &dwFlags, NULL, &pSample);
        
        if (FAILED(hr)) { break; }
        if (dwFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
        {
            printf("Type change - not supported by WAVE file format.\n");
            break;
        }
        if (dwFlags & MF_SOURCE_READERF_ENDOFSTREAM)
        {
            printf("End of input file.\n");
            break;
        }

        hr = pSample->ConvertToContiguousBuffer(&pBuffer);

        if (FAILED(hr)) { break; }

        hr = pBuffer->Lock(&pAudioData, NULL, &cbBuffer);
        if (FAILED(hr)) { break; }
        //Do something with the pAudioData which is an array of unsigned chars of lenth cbBuffer

        SampleData tmp;

        tmp.pAudioData = new byte[cbBuffer];
        memcpy(tmp.pAudioData, pAudioData, cbBuffer);
        tmp.cbBuffer = cbBuffer;
        samples_vec.push_back(tmp);

        // Unlock the buffer.
        hr = pBuffer->Unlock();
        pAudioData = NULL;
        if (FAILED(hr)) { break; }
    }

    SafeRelease(&pReader);
    SafeRelease(&pSample);
    SafeRelease(&pBuffer);
    SafeRelease(&spByteStream);
    SafeRelease(&Atrr);

    // Shut down Media Foundation.
    MFShutdown();
    CoUninitialize();
}

ご覧のとおり、データとサイズへのポインタがあります。これは実際には、デコードする必要のあるデータです。問題はここにあることです

hr = MFCreateMFByteStreamOnStreamEx((IUnknown*)pData, &spByteStream);

エラーが発生しました。access violationこれは、に変換しようとしたためです。質問は-それを正しく変換する方法は?pDataIUnknown*

回答

3 RomanR. Nov 23 2020 at 16:10

このように角を切ることはできません:

unsigned char const * pData;
...
hr = MFCreateMFByteStreamOnStreamEx((IUnknown*)pData, &spByteStream);

IUnknownバイトのもう1つの派手なエイリアスではありません。文書化されているように、ストリームを表すインターフェイスポインタを文字通り提供することになっています。

Media Foundationは、メモリバイトから読み取る手段を提供します。あなたは本当のストリームを作成し、作成する必要があるIStreamか、IRandomAccessStreamまたはIMFByteStreamdocuemntationごと。また、IMFAttributesデータ型を指定するための適切な属性(ファイルの場合は拡張子またはMIMEタイプから派生)を作成したものを提供すると、ソースリーダーAPIはメディアファイルデータのソースとしてメモリバイトを処理でき、適切なデコーダー(に似たPCMデータにオーディオデコードうこの)。

あなたが実際に素早く行うことができます何か:CreateStreamOnHGlobal作成するためのIStream実装を、基礎となるバッファにあなたのバイトをコピー(ドキュメントを参照してください)。次にMFCreateMFByteStreamOnStream、IMFByteStreamその上にwrapprを作成し、このラッパーをMFCreateSourceReaderFromByteStream引数として使用できます。

1 MichaelChourdakis Nov 23 2020 at 16:20

私はそのようなものにVectorStreamクラスを使用していました。一部の関数は実装されていませんが、基本的な考え方を理解する必要があります。

class VectorStream : public IStream
{
public:

    bool ReadOnly = false;
    ULONG r = 1;
    std::vector<char> d;
    size_t p = 0;
    VectorStream()
    {
    }


    void Clear()
    {
        d.clear();
        p = 0;

    }

    // IUnknown
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(
        /* [in] */ REFIID riid,
        /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject)
    {
        if (riid == __uuidof(IUnknown) || riid == __uuidof(IStream))
        {
            *ppvObject = (IStream*)this;
            r++;
            return S_OK;
        }
        return E_NOINTERFACE;
    }

    virtual ULONG STDMETHODCALLTYPE AddRef(void)
    {
        return ++r;
    }

    virtual ULONG STDMETHODCALLTYPE Release(void)
    {
        return --r;
    }

    HRESULT __stdcall Clone(
        IStream** ppstm
    )
    {
        return E_NOTIMPL;
    }

    HRESULT __stdcall Commit(
        DWORD grfCommitFlags
    )
    {
        return S_OK;
    }

    HRESULT __stdcall CopyTo(
        IStream* pstm,
        ULARGE_INTEGER cb,
        ULARGE_INTEGER* pcbRead,
        ULARGE_INTEGER* pcbWritten
    )
    {
        return E_NOINTERFACE;
    }

    HRESULT __stdcall LockRegion(
        ULARGE_INTEGER libOffset,
        ULARGE_INTEGER cb,
        DWORD          dwLockType
    )
    {
        return S_OK;
    }

    HRESULT __stdcall UnlockRegion(
        ULARGE_INTEGER libOffset,
        ULARGE_INTEGER cb,
        DWORD          dwLockType
    )
    {
        return S_OK;

    }

    HRESULT __stdcall Revert()
    {
        return E_NOTIMPL;
    }

    HRESULT __stdcall Seek(
        LARGE_INTEGER  dlibMove,
        DWORD          dwOrigin,
        ULARGE_INTEGER* plibNewPosition
    )
    {
        LARGE_INTEGER lo = { 0 };
        if (dwOrigin == STREAM_SEEK_SET)
        {
            p = dlibMove.QuadPart;
        }
        if (dwOrigin == STREAM_SEEK_CUR)
        {
            p += dlibMove.QuadPart;
        }
        if (dwOrigin == STREAM_SEEK_END)
        {
            p = d.size() - dlibMove.QuadPart;
        }
        if (p >= d.size())
            p = d.size();
        if (plibNewPosition)
            plibNewPosition->QuadPart = p;
        return S_OK;
    }


    HRESULT __stdcall SetSize(
        ULARGE_INTEGER libNewSize
    )
    {
        d.resize(libNewSize.QuadPart);
        return S_OK;
    }

    int eb = 0;
    HRESULT __stdcall Stat(
        STATSTG* pstatstg,
        DWORD   grfStatFlag
    )
    {
        pstatstg->type = STGTY_STREAM;
        pstatstg->cbSize.QuadPart = d.size();
        pstatstg->grfLocksSupported = true;
        return S_OK;
    }


    unsigned long long readbytes = 0;
    HRESULT __stdcall Read(
        void* pv,
        ULONG cb,
        ULONG* pcbRead
    )
    {
        auto av = d.size() - p;
        if (cb < av)
            av = cb;
        memcpy(pv, d.data() + p, av);
        p += av;
        if (pcbRead)
            *pcbRead = (ULONG)av;
//      if (av < cb)
    //      return S_FALSE;
        return S_OK;

    }


    HRESULT __stdcall Write(
        const void* pv,
        ULONG      cb,
        ULONG* pcbWritten
    )
    {
        if (ReadOnly)
            return STG_E_ACCESSDENIED;
        if (d.size() < (p + cb))
        {
            auto exc = (p + cb) - d.size();
            d.resize(d.size() + exc);
        }
        memcpy(d.data() + p, pv, cb);
        p += cb;
        if (pcbWritten)
            *pcbWritten = cb;
        return S_OK;
    }
};

std :: vector <>をIStreamにカプセル化します。