Search code examples
c++audiocodecms-media-foundation

The byte stream type of the given URL is unsupported MediaFoundation


I need to create a reader from buffer(that is wav bytes) in order to do it I am using such approach:

void co_AudioEncoderMF::load_from_memory(unsigned char const * data, long data_size)
{
    unsigned char * buf = new unsigned char[data_size]; //JUST FOR TEST IN ORDER TO BE SURE THAT I HAVE THIS DATA
    memcpy(buf, data, data_size);

    IMFMediaType *input_type = nullptr;
    IMFSourceReader *source_reader = nullptr;
    IMFMediaType *ouput_media_type = nullptr;
    IMFSinkWriter *sink_writer = nullptr;
    IStream * stream = nullptr;
    IMFByteStream * byte_stream = nullptr;

    HRESULT hr = InitAndStartCOMLib();

    if (SUCCEEDED(hr))
    {
        hr = create_stream(buf, data_size, &stream);  <---- HERE I CREATE A STREAM
    }

    if (SUCCEEDED(hr))
    {
        hr = MFCreateMFByteStreamOnStream(stream, &byte_stream);
    }

    HGLOBAL hGlobal = nullptr;
    //IMFSourceReader *pReader = nullptr;

    if (SUCCEEDED(hr))
    {
        GetHGlobalFromStream(stream, &hGlobal);
        hr = create_source_reader(byte_stream, &source_reader);   <----- HERE I CREATE A READER
    }
...
}
HRESULT co_AudioEncoderMF::InitAndStartCOMLib()
{
    HRESULT hr = S_OK;
    HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption, nullptr, 0);

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

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

    return hr;
}
HRESULT co_AudioEncoderMF::create_stream(unsigned char const * pData, long dataLen, IStream ** out_stream)
{
    HGLOBAL m_phMem = ::GlobalAlloc(GMEM_MOVEABLE, dataLen);

    if (!m_phMem)
    {
        printf("Error AfxThrowMemoryException");
    }

    LPVOID dest = ::GlobalLock(m_phMem);

    memcpy(dest, pData, dataLen);
    ::GlobalUnlock(m_phMem);

    return CreateStreamOnHGlobal(m_phMem, FALSE /*fDeleteOnRelease*/, out_stream);// NOTE :: in order to get more flexablity need to consider such an approach https://gist.github.com/alekseytimoshchenko/e8f52604fdeb50c8ad7873aeb8281bfa
}
HRESULT co_AudioEncoderMF::create_source_reader(IMFByteStream * in_byte_stream, IMFSourceReader **source_reader)
{
    HRESULT hr = S_OK;

    IMFAttributes * attr = nullptr;
    hr = MFCreateAttributes(&attr, 10);

    if (SUCCEEDED(hr))
    {
        hr = attr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true);
    }
    else
    {
        printf("Error MFCreateAttributes");
    }

    if (SUCCEEDED(hr))
    {
        hr = MFCreateSourceReaderFromByteStream(in_byte_stream, attr, source_reader); <----- AND HERE I GOT MY ERROR ABOUT UNSUPPORTED FORMAT
    }
    else
    {
        printf("Error Atrr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true)");
    }

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

    return hr;
}

I am using the same approach but with mp3 bytes and it is works, I assume that it has a difference, but I don't know how to approve it and solve.


Solution

  • In my case problem was in that I tried to call this method MFCreateSourceReaderFromByteStream on stream that was created on wav bytes, but it didn't includes .wav header. So, I was needed to add a header. I used this method

    /*static*/ void Utils::append_data_to_wav_header(unsigned char * buff, int buff_size, int num_of_channels, int sample_rate, std::vector<unsigned char> & out_buf)
    {
        //*** START OF HEADER
        long idx = 0;
        uint32_t uint_32_buf = buff_size + 44 /*header size*/;
    
        out_buf.resize(uint_32_buf);
        std::string str_buf = "RIFF";
        memcpy(&out_buf[idx], str_buf.c_str(), strlen(str_buf.c_str()));
        idx += (long)strlen(str_buf.c_str());
    
        memcpy(&out_buf[idx], &uint_32_buf, sizeof(uint_32_buf));
        idx += sizeof(uint_32_buf);
    
        str_buf = "WAVE";
        memcpy(&out_buf[idx], str_buf.c_str(), strlen(str_buf.c_str()));
        idx += (long)strlen(str_buf.c_str());
    
        str_buf = "fmt ";
        memcpy(&out_buf[idx], str_buf.c_str(), strlen(str_buf.c_str()));
        idx += (long)strlen(str_buf.c_str());
    
        uint_32_buf = 16;
        memcpy(&out_buf[idx], &uint_32_buf, 1);
        idx += sizeof(uint_32_buf);
    
        uint16_t uint_16_buff = 1;
        memcpy(&out_buf[idx], &uint_16_buff, 1);
        idx += sizeof(uint_16_buff);
    
        uint_16_buff = num_of_channels;
        memcpy(&out_buf[idx], &uint_16_buff, 1);
        idx += sizeof(uint_16_buff);
    
        uint_32_buf = sample_rate;
        memcpy(&out_buf[idx], &uint_32_buf, 1);
        idx += sizeof(uint_32_buf);
    
        uint_32_buf = (sample_rate * 16 * num_of_channels) / 8;
        memcpy(&out_buf[idx], &uint_32_buf, 1);
        idx += sizeof(uint_32_buf);
    
        uint_16_buff = 16 * num_of_channels / 8;
        memcpy(&out_buf[idx], &uint_16_buff, 1);
        idx += sizeof(uint_16_buff);
    
        uint_16_buff = 16;
        memcpy(&out_buf[idx], &uint_16_buff, 1);
        idx += sizeof(uint_16_buff);
    
        str_buf = "data";
        memcpy(&out_buf[idx], str_buf.c_str(), strlen(str_buf.c_str()));
        idx += (long)strlen(str_buf.c_str());
    
        uint_32_buf = buff_size;
        memcpy(&out_buf[idx], &uint_32_buf, 1);
        idx += sizeof(uint_32_buf);
        //*** END OF HEADER
    
        memcpy(&out_buf[idx], buff, buff_size);
        idx += buff_size;
    }