Wie kann man bei Verwendung von Media Foundation aus "unsigned char const *" lesen?

Nov 23 2020

Ich habe eine solche Implementierung

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();
}

Wie Sie sehen können, habe ich einen Zeiger auf Daten und Größe. Dies sind tatsächlich meine Daten, die ich zum Dekodieren benötige. Problem ist das hier

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

Ich habe einen Fehler access violationund soweit ich sehe , ist dies, weil ich versuche , zu konvertieren pDatazu IUnknown*. Die Frage ist - wie man es richtig konvertiert?

Antworten

3 RomanR. Nov 23 2020 at 16:10

Sie können solche Ecken nicht schneiden:

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

IUnknownist kein weiterer ausgefallener Alias ​​für ein Byte. Sie sollten buchstäblich den Schnittstellenzeiger angeben, der den Stream darstellt, wie dokumentiert.

Media Foundation bietet Ihnen die Möglichkeit, aus Speicherbytes zu lesen. Sie müssen einen echten Stream erstellen IStreamoder IRandomAccessStreamoder IMFByteStreampro Dokumentation. Geben IMFAttributesSie außerdem an, dass Sie die richtigen Attribute erstellt haben, um den Datentyp anzugeben (der ansonsten im Fall einer Datei von der Erweiterung oder dem MIME-Typ abgeleitet ist). Anschließend kann die Source Reader-API Speicherbytes als Quelle für Mediendateidaten und einen geeigneten Decoder verarbeiten würde Audio in PCM-Daten dekodieren (ähnlich wie diese ).

Etwas, das Sie ganz schnell tun können: Implementierung CreateStreamOnHGlobalerstellen IStreamund Ihre Bytes in den zugrunde liegenden Puffer kopieren (siehe Dokumente). Dann MFCreateMFByteStreamOnStreamwürde ein IMFByteStreamWrappr darüber erstellt, und Sie können diesen Wrapper als MFCreateSourceReaderFromByteStreamArgument verwenden.

1 MichaelChourdakis Nov 23 2020 at 16:20

Ich habe für solche Sachen eine VectorStream-Klasse verwendet. Einige Funktionen sind nicht implementiert, aber Sie sollten die Grundidee bekommen.

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;
    }
};

Es kapselt std :: vector <> in einem IStream.