मीडिया फाउंडेशन का उपयोग करते समय - "अहस्ताक्षरित चार कास्ट *" कैसे पढ़ें?

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और जहाँ तक मैं देख रहा हूँ इस वजह से मैं बदलने की कोशिश pDataकरने के लिए IUnknown*। प्रश्न है - इसे सही रूप में कैसे बदला जाए?

जवाब

3 RomanR. Nov 23 2020 at 16:10

आप इस तरह से कोनों को नहीं काट सकते:

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

IUnknownअभी तक बाइट के लिए एक और फैंसी उर्फ ​​नहीं है। आपको दस्तावेज़ के रूप में स्ट्रीम का प्रतिनिधित्व करने वाले इंटरफ़ेस पॉइंटर का शाब्दिक आपूर्ति करना चाहिए।

मीडिया फाउंडेशन आपको मेमोरी बाइट्स से पढ़ने का मतलब देता है। आप बनाने के लिए एक एक असली स्ट्रीम बनाने की जरूरत है, IStreamया IRandomAccessStreamया IMFByteStreamdocuemntation प्रति। IMFAttributesडेटा प्रकार को निर्दिष्ट करने के लिए उचित विशेषताओं के साथ बनाई गई आपूर्ति भी करें (जो अन्यथा फ़ाइल के मामले में विस्तार या माइम प्रकार से ली गई है) और फिर स्रोत रीडर एपीआई मीडिया फ़ाइल डेटा के स्रोत के रूप में मेमोरी बाइट्स को संसाधित करने में सक्षम होगा, और उपयुक्त डिकोडर पीसीएम डेटा में ऑडियो (के समान डिकोड हैं इस )।

कुछ आप जल्दी कर सकते हैं: कार्यान्वयन CreateStreamOnHGlobalबनाने के IStreamलिए और अपने बाइट्स को अंतर्निहित बफर में कॉपी करें (डॉक्स देखें)। फिर MFCreateMFByteStreamOnStreamइसके IMFByteStreamऊपर एक रैपर तैयार करेंगे और आप इस रैपर को MFCreateSourceReaderFromByteStreamतर्क के रूप में इस्तेमाल कर सकते हैं ।

1 MichaelChourdakis Nov 23 2020 at 16:20

मैं इस तरह के सामान के लिए एक वेक्टरस्ट्रीम क्लास का उपयोग करता था। कुछ कार्यों को लागू नहीं किया जाता है, लेकिन आपको मूल विचार प्राप्त करना चाहिए।

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 :: वेक्टर <> को एनकैप्सुलेट करता है।