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바이트에 대한 또 다른 멋진 별칭이 아닙니다. 문서화 된대로 스트림을 나타내는 인터페이스 포인터를 문자 그대로 제공해야합니다.

Media Foundation은 메모리 바이트에서 읽는 방법을 제공합니다. 당신은 진짜 스트림을 생성, 작성해야 IStream하거나 IRandomAccessStream또는 IMFByteStreamdocuemntation 당. 또한 IMFAttributes데이터 유형을 지정하기 위해 생성 한 적절한 속성을 제공합니다 (그렇지 않으면 파일의 경우 확장자 또는 MIME 유형에서 파생 됨). 그러면 Source Reader 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;
    }
};

IStream에서 std :: vector <>를 캡슐화합니다.