Source reader and custom non-seekable byte stream

702 views Asked by At

I'm implementing a custom IMFByteStream to stream video over a network, but the problem is that I cannot pass its object to the source resolver to create media source, because the CreateObjectFromByteStream is returning an error:

0xc00d36ee : The provided bytestream was expected to be seekable and it is not.

Of course my custom byte stream is not seekable because seeking over the network is not possible. So the question is how can I create a media source using a non-seekable byte stream? My final destination is to create a IMFSourceReader object. The type of the source content is ASF.

2

There are 2 answers

2
Roman Ryltsov On

Your failure supposedly comes from:

During the creation of the media source, the source resolver creates a byte stream for the file from which the media source reads the ASF content. In order for the time conversions to be successful, the byte stream associated with the ASF file must have seeking capabilities; otherwise, the application gets the MF_E_BYTESTREAM_NOT_SEEKABLE error from the Begin... call.

You might try media source properties, but it more looks like a mandatory requirement that the byte stream is seekable. One thing you can do to work this around is to indeed mark the stream implementation as seekable, and implement a wait once there is a read request from position which is not yet available.

1
D.Zadravec On

I have implemented two IMFByteStream interfaces, one is called MediaByteStream which is used for non-storage memory streaming and the other is called StoreByteStream (yes I know) which is used for in-memory storage.

Placing the code below in your IMFByteStream implementation will eliminate your seekable error and have no effect on your ability to stream.

        /// <summary>
        /// Retrieves the characteristics of the byte stream.
        /// </summary>
        /// <param name="pdwCapabilities">Receives a bitwise OR of zero or more flags. The following flags are defined. [out]</param>
        /// <returns>The result of the operation.</returns>
        HRESULT MediaByteStream::GetCapabilities(
            DWORD *pdwCapabilities)
        {
            HRESULT hr = S_OK;

            // Stream can read, can write, can seek.
            *pdwCapabilities = MFBYTESTREAM_IS_READABLE | MFBYTESTREAM_IS_WRITABLE | MFBYTESTREAM_IS_SEEKABLE;

            // Return the result.
            return hr;
        }

You can if you wish to implement the Seek method of the IMFByteStream interface, but in your case (Network streaming) you can just return the seek position.

        /// <summary>
        /// Moves the current position in the stream by a specified offset.
        /// </summary>
        /// <param name="SeekOrigin">Specifies the origin of the seek as a member of the MFBYTESTREAM_SEEK_ORIGIN enumeration. The offset is calculated relative to this position. [in]</param>
        /// <param name="qwSeekOffset">Specifies the new position, as a byte offset from the seek origin. [in]</param>
        /// <param name="dwSeekFlags">Specifies zero or more flags. The following flags are defined. [in]</param>
        /// <param name="pqwCurrentPosition">Receives the new position after the seek. [out]</param>
        /// <returns>The result of the operation.</returns>
        HRESULT MediaByteStream::Seek(
            MFBYTESTREAM_SEEK_ORIGIN SeekOrigin,
            LONGLONG                 qwSeekOffset,
            DWORD                    dwSeekFlags,
            QWORD                    *pqwCurrentPosition)
        {
            HRESULT hr = S_OK;
            _seekRequest = true;

            // Select the seek origin.
            switch (SeekOrigin)
            {
            case MFBYTESTREAM_SEEK_ORIGIN::msoCurrent:
                // If the buffer is less or same.
                if ((qwSeekOffset + _position) < size)
                    _position += qwSeekOffset;
                else
                    _position = size;

                break;

            case MFBYTESTREAM_SEEK_ORIGIN::msoBegin:
            default:
                // If the buffer is less or same.
                if (qwSeekOffset < size)
                    _position = qwSeekOffset;
                else
                    _position = size;

                break;
            }

            // Get the current position in the stream.
            *pqwCurrentPosition = _position;

            // Return the result.
            return hr;
        }