locked
Compressed Media Samples RRS feed

  • Question

  • Hi,

    I'm working with the "Reading ASF Files tutorial" and I have a problem on the compress part. This tutorial has the following steps:
    Open an ASF file 
    Read the ASF Header Object 
    Create the ASF Splitter 
    Select a Stream for Parsing 
    Generate Compressed Media Samples


    I'm using a .wmv file that has the following length:
    pStream->GetLength: 3845666

    I'm sending the following packet size to read that data into a buffer (I tried with different sizes - with no different result).
    const DWORD cbReadSize = 385000;

    Each packet is parsed using the following function: 
    CHECK_HR(hr = pSplitter->ParseData(pBuffer, 0, 0));
    The result of this method is correct (S_OK).

    But, after that when I'm trying to pull the samples from the splitter:
    CHECK_HR(hr = pSplitter->GetNextSample(&dwStatus, &wStreamID, &pSample));

     

    My pSample (IMFSample) is always NULL.

    Do you know if I need to do somehting else before to get the nex sample, because all the code before that seems to be correct.
    what would be the problem?

    Any help is really appreciate.
    Thanks a lot.

    - Enby.

    Monday, April 6, 2009 9:12 PM

Answers

  • I am not sure what the problem is. I followed the tutorial and got it to work, with one issue though: I couldn't find ReadDataIntoBuffer(), so I tweaked AllocReadFromByteStream() to do the work (see CreateBufferFromByteStream() in the code snippet below). I also changed a bit the tutorial to dump all the samples from all the streams.

    Here is the code I got (should be self contained):

    #include <stdio.h>
    #include <windows.h>
    #include <mfapi.h>
    #include <wmcontainer.h>
    #include <mferror.h>
    
    // some macros
    #define SAFE_RELEASE(x) { if (x) { x->Release(); x = NULL; } }
    #define CHECK_HR(expr) { expr; if (FAILED(hr)) { wprintf_s( L"'" L#expr L"' failed with error code 0x%08lx\n", hr ); goto done; } }
    
    /////////////////////////////////////////////////////////////////////
    HRESULT OpenFile(const WCHAR *sFileName, IMFByteStream **ppStream)
    {
        HRESULT hr = S_OK;
        IMFByteStream *pStream = NULL;
    
        // Open a byte stream for the file.
        CHECK_HR(hr = MFCreateFile(
            MF_ACCESSMODE_READ, 
            MF_OPENMODE_FAIL_IF_NOT_EXIST,
            MF_FILEFLAGS_NONE,
            sFileName,
            &pStream
            ));
    
        // Return the pointer to the caller.
        *ppStream = pStream;
        (*ppStream)->AddRef();
    
    done:
        SAFE_RELEASE(pStream);
        return hr;
    }
    
    /////////////////////////////////////////////////////////////////////
    HRESULT CreateBufferFromByteStream(
        IMFByteStream *pStream,
        DWORD cbToRead,
        IMFMediaBuffer **ppBuffer
        )
    {
        HRESULT hr = S_OK;
        BYTE *pData = NULL;
        DWORD cbRead = 0;   // Actual amount of data read.
    
        IMFMediaBuffer *pBuffer = NULL;
    
        CHECK_HR(hr = MFCreateMemoryBuffer(cbToRead, &pBuffer));
    
        CHECK_HR(hr = pBuffer->Lock(&pData, NULL, NULL));
    
        CHECK_HR(hr = pStream->Read(pData, cbToRead, &cbRead));
    
        CHECK_HR(hr = pBuffer->SetCurrentLength(cbRead));
    
        *ppBuffer = pBuffer;
        (*ppBuffer)->AddRef();
    
    done:
    
        if (pData)
        {
            pBuffer->Unlock();
        }
        SAFE_RELEASE(pBuffer);
        return hr;
    }
    
    /////////////////////////////////////////////////////////////////////
    HRESULT CreateContentInfo(
        IMFByteStream *pStream,            
        IMFASFContentInfo **ppContentInfo  
        )
    {
        HRESULT hr = S_OK;
        QWORD cbHeader = 0;
    
        const DWORD MIN_ASF_HEADER_SIZE = 30;
        
        IMFASFContentInfo *pContentInfo = NULL;
        IMFMediaBuffer *pBuffer = NULL;
    
        // Create the ASF ContentInfo object.
        CHECK_HR(hr = MFCreateASFContentInfo(&pContentInfo));
        
        // Read the first 30 bytes to find the total header size.
        CHECK_HR(hr = pStream->SetCurrentPosition( 0 ));
        CHECK_HR(hr = CreateBufferFromByteStream(pStream, MIN_ASF_HEADER_SIZE, &pBuffer));
    
        CHECK_HR(hr = pContentInfo->GetHeaderSize(pBuffer, &cbHeader));
    
        // Pass the first 30 bytes to the ContentInfo object.
        CHECK_HR(hr = pContentInfo->ParseHeader(pBuffer, 0));
    
        SAFE_RELEASE(pBuffer);
    
        // Read the rest of the header and finish parsing the header.
        CHECK_HR(hr = pStream->SetCurrentPosition( MIN_ASF_HEADER_SIZE ));
        CHECK_HR(hr = CreateBufferFromByteStream(
            pStream, 
            (DWORD)(cbHeader - MIN_ASF_HEADER_SIZE),
            &pBuffer
            ));
    
        CHECK_HR(hr = pContentInfo->ParseHeader(pBuffer, MIN_ASF_HEADER_SIZE));
    
        // Return the pointer to the caller.
        *ppContentInfo = pContentInfo;
        (*ppContentInfo)->AddRef();
    
    done:
        SAFE_RELEASE(pBuffer);
        SAFE_RELEASE(pContentInfo);
        return hr;
    } 
    
    /////////////////////////////////////////////////////////////////////
    HRESULT CreateASFSplitter ( 
                  IMFASFContentInfo* pContentInfo, 
                  IMFASFSplitter** ppSplitter)
    {
        HRESULT hr = S_OK;
    
        IMFASFSplitter *pSplitter = NULL;
    
        // Create the splitter object.
        CHECK_HR (hr = MFCreateASFSplitter(&pSplitter));
    
        // Initialize the splitter to work with specific ASF data.
        CHECK_HR (hr = pSplitter->Initialize(pContentInfo));
    
        // Return the object to the caller.
        *ppSplitter = pSplitter;
        (*ppSplitter)->AddRef();
    
    done:
        SAFE_RELEASE (pSplitter);
        return hr;
    }
    
    /////////////////////////////////////////////////////////////////////
    HRESULT SelectStreams(
        IMFASFContentInfo *pContentInfo, 
        IMFASFSplitter *pSplitter
        )
    {
        HRESULT hr = S_OK;
        DWORD   cStreams = 0;
        WORD   *pwStreamID = NULL;
        GUID    streamType = GUID_NULL;
    
        IMFASFProfile *pProfile = NULL;
    
        // Get the ASF profile from the ContentInfo object.
        CHECK_HR(hr = pContentInfo->GetProfile(&pProfile));
    
        // Loop through all of the streams in the profile.
        CHECK_HR(hr = pProfile->GetStreamCount(&cStreams));
        wprintf_s( L"Number of streams: %i\n", cStreams );
    
        if( !cStreams )
        {
            CHECK_HR( hr = E_UNEXPECTED );
        }
    
        pwStreamID = new WORD[cStreams];
    
        if( !pwStreamID )
        {
            CHECK_HR( hr = E_OUTOFMEMORY );
        }
    
        for (DWORD i = 0; i < cStreams; i++)
        {
            // Get the stream type and stream identifier.
            CHECK_HR(hr = pProfile->GetStream(i, &pwStreamID[i], NULL));
        }
    
        // SelectStreams takes an array of stream identifiers.
        CHECK_HR(hr = pSplitter->SelectStreams(pwStreamID, cStreams));
    
    done:
        delete[] pwStreamID;
        SAFE_RELEASE(pProfile);
        return hr;
    }
    
    /////////////////////////////////////////////////////////////////////
    HRESULT DisplaySamples(
        IMFByteStream *pStream, 
        IMFASFSplitter *pSplitter
        )
    {
        const DWORD cbReadSize = 32768;  // Read size (arbitrary value)
        HRESULT hr = S_OK;
        UINT32 cSamples = 0;
        DWORD   dwStatus;
        WORD    wStreamID;
    
        IMFSample *pSample = NULL;
        IMFMediaBuffer *pBuffer = NULL;
    
        while (TRUE)
        {
            // Read data into the buffer.
            CHECK_HR(hr = CreateBufferFromByteStream( pStream, cbReadSize, &pBuffer ) );
    
            DWORD   cbData;
            CHECK_HR(hr = pBuffer->GetCurrentLength(&cbData));
            wprintf_s( L"Read %iB\n", cbData);
    
            if (cbData == 0)
            {
                break; // End of file.
            }
    
            // Send the data to the ASF splitter.
            CHECK_HR(hr = pSplitter->ParseData(pBuffer, 0, 0));
    
            SAFE_RELEASE( pBuffer );
    
            // Pull samples from the splitter.
            do
            {
                CHECK_HR(hr = pSplitter->GetNextSample(&dwStatus, &wStreamID, &pSample));
    
                if (pSample == NULL)
                {
                    // No samples yet. Parse more data.
                    break;
                }
    
                cSamples++;
    
                // various information about the sample
                DWORD   cBuffers;
                DWORD   cbTotalLength;
                CHECK_HR(hr = pSample->GetBufferCount(&cBuffers));
                CHECK_HR(hr = pSample->GetTotalLength(&cbTotalLength));
    
                BOOL bIsKeyFrame = MFGetAttributeUINT32(pSample, MFSampleExtension_CleanPoint, FALSE);
    
                wprintf_s( L"Sample %03i (Stream: %i, Key-frame: %i, Buffers: %d, Length: %dB", 
                    cSamples,
                    wStreamID,
                    bIsKeyFrame,
                    cBuffers,
                    cbTotalLength
                    );
    
                MFTIME  hnsTime;
                if (SUCCEEDED(pSample->GetSampleTime(&hnsTime)))
                {
                    wprintf_s(L", Time: %ims", hnsTime / 10000);
                }
    
                wprintf_s(L")\n");
    
                SAFE_RELEASE(pSample);
                
            } while (dwStatus & ASF_STATUSFLAGS_INCOMPLETE);
        }
    
        wprintf_s(L"Done\n");
    
    done:
        SAFE_RELEASE(pSample);
        SAFE_RELEASE(pBuffer);
        return hr;
    }
    
    /////////////////////////////////////////////////////////////////////
    int __cdecl wmain(int argc, LPCWSTR argv[])
    {
        if (argc != 2)
        {
            wprintf_s(L"Usage: %s input.wmv", argv[0]);
            return 1;
        }
    
        const WCHAR         *sFileName = argv[1]; 
        HRESULT             hr = S_OK;
    
        IMFByteStream       *pStream = NULL;
        IMFASFContentInfo   *pContentInfo = NULL;
        IMFASFSplitter      *pSplitter = NULL;
    
        wprintf_s(L"Opening '%s'.\n", sFileName);
    
        CHECK_HR(hr = MFStartup(MF_VERSION));
    
        CHECK_HR(hr = OpenFile(sFileName, &pStream));
    
        CHECK_HR(hr = CreateContentInfo(pStream, &pContentInfo));
    
        CHECK_HR(hr = CreateASFSplitter(pContentInfo, &pSplitter));
    
        CHECK_HR(hr = SelectStreams(pContentInfo, pSplitter));
    
        CHECK_HR(hr = DisplaySamples(pStream, pSplitter));
    
    done:
        SAFE_RELEASE(pSplitter);
        SAFE_RELEASE(pContentInfo);
        SAFE_RELEASE(pStream);
        
        (void) MFShutdown();
    
        return FAILED(hr);
    }

    I tried it on the three videos under "C:\Users\Public\Videos\Sample Videos\".

    Hope this helps.
    • Proposed as answer by Enby Tuesday, April 21, 2009 4:35 PM
    • Marked as answer by The March Hare Wednesday, October 7, 2009 5:50 PM
    Thursday, April 16, 2009 12:28 AM

All replies

  • I am not sure what the problem is. I followed the tutorial and got it to work, with one issue though: I couldn't find ReadDataIntoBuffer(), so I tweaked AllocReadFromByteStream() to do the work (see CreateBufferFromByteStream() in the code snippet below). I also changed a bit the tutorial to dump all the samples from all the streams.

    Here is the code I got (should be self contained):

    #include <stdio.h>
    #include <windows.h>
    #include <mfapi.h>
    #include <wmcontainer.h>
    #include <mferror.h>
    
    // some macros
    #define SAFE_RELEASE(x) { if (x) { x->Release(); x = NULL; } }
    #define CHECK_HR(expr) { expr; if (FAILED(hr)) { wprintf_s( L"'" L#expr L"' failed with error code 0x%08lx\n", hr ); goto done; } }
    
    /////////////////////////////////////////////////////////////////////
    HRESULT OpenFile(const WCHAR *sFileName, IMFByteStream **ppStream)
    {
        HRESULT hr = S_OK;
        IMFByteStream *pStream = NULL;
    
        // Open a byte stream for the file.
        CHECK_HR(hr = MFCreateFile(
            MF_ACCESSMODE_READ, 
            MF_OPENMODE_FAIL_IF_NOT_EXIST,
            MF_FILEFLAGS_NONE,
            sFileName,
            &pStream
            ));
    
        // Return the pointer to the caller.
        *ppStream = pStream;
        (*ppStream)->AddRef();
    
    done:
        SAFE_RELEASE(pStream);
        return hr;
    }
    
    /////////////////////////////////////////////////////////////////////
    HRESULT CreateBufferFromByteStream(
        IMFByteStream *pStream,
        DWORD cbToRead,
        IMFMediaBuffer **ppBuffer
        )
    {
        HRESULT hr = S_OK;
        BYTE *pData = NULL;
        DWORD cbRead = 0;   // Actual amount of data read.
    
        IMFMediaBuffer *pBuffer = NULL;
    
        CHECK_HR(hr = MFCreateMemoryBuffer(cbToRead, &pBuffer));
    
        CHECK_HR(hr = pBuffer->Lock(&pData, NULL, NULL));
    
        CHECK_HR(hr = pStream->Read(pData, cbToRead, &cbRead));
    
        CHECK_HR(hr = pBuffer->SetCurrentLength(cbRead));
    
        *ppBuffer = pBuffer;
        (*ppBuffer)->AddRef();
    
    done:
    
        if (pData)
        {
            pBuffer->Unlock();
        }
        SAFE_RELEASE(pBuffer);
        return hr;
    }
    
    /////////////////////////////////////////////////////////////////////
    HRESULT CreateContentInfo(
        IMFByteStream *pStream,            
        IMFASFContentInfo **ppContentInfo  
        )
    {
        HRESULT hr = S_OK;
        QWORD cbHeader = 0;
    
        const DWORD MIN_ASF_HEADER_SIZE = 30;
        
        IMFASFContentInfo *pContentInfo = NULL;
        IMFMediaBuffer *pBuffer = NULL;
    
        // Create the ASF ContentInfo object.
        CHECK_HR(hr = MFCreateASFContentInfo(&pContentInfo));
        
        // Read the first 30 bytes to find the total header size.
        CHECK_HR(hr = pStream->SetCurrentPosition( 0 ));
        CHECK_HR(hr = CreateBufferFromByteStream(pStream, MIN_ASF_HEADER_SIZE, &pBuffer));
    
        CHECK_HR(hr = pContentInfo->GetHeaderSize(pBuffer, &cbHeader));
    
        // Pass the first 30 bytes to the ContentInfo object.
        CHECK_HR(hr = pContentInfo->ParseHeader(pBuffer, 0));
    
        SAFE_RELEASE(pBuffer);
    
        // Read the rest of the header and finish parsing the header.
        CHECK_HR(hr = pStream->SetCurrentPosition( MIN_ASF_HEADER_SIZE ));
        CHECK_HR(hr = CreateBufferFromByteStream(
            pStream, 
            (DWORD)(cbHeader - MIN_ASF_HEADER_SIZE),
            &pBuffer
            ));
    
        CHECK_HR(hr = pContentInfo->ParseHeader(pBuffer, MIN_ASF_HEADER_SIZE));
    
        // Return the pointer to the caller.
        *ppContentInfo = pContentInfo;
        (*ppContentInfo)->AddRef();
    
    done:
        SAFE_RELEASE(pBuffer);
        SAFE_RELEASE(pContentInfo);
        return hr;
    } 
    
    /////////////////////////////////////////////////////////////////////
    HRESULT CreateASFSplitter ( 
                  IMFASFContentInfo* pContentInfo, 
                  IMFASFSplitter** ppSplitter)
    {
        HRESULT hr = S_OK;
    
        IMFASFSplitter *pSplitter = NULL;
    
        // Create the splitter object.
        CHECK_HR (hr = MFCreateASFSplitter(&pSplitter));
    
        // Initialize the splitter to work with specific ASF data.
        CHECK_HR (hr = pSplitter->Initialize(pContentInfo));
    
        // Return the object to the caller.
        *ppSplitter = pSplitter;
        (*ppSplitter)->AddRef();
    
    done:
        SAFE_RELEASE (pSplitter);
        return hr;
    }
    
    /////////////////////////////////////////////////////////////////////
    HRESULT SelectStreams(
        IMFASFContentInfo *pContentInfo, 
        IMFASFSplitter *pSplitter
        )
    {
        HRESULT hr = S_OK;
        DWORD   cStreams = 0;
        WORD   *pwStreamID = NULL;
        GUID    streamType = GUID_NULL;
    
        IMFASFProfile *pProfile = NULL;
    
        // Get the ASF profile from the ContentInfo object.
        CHECK_HR(hr = pContentInfo->GetProfile(&pProfile));
    
        // Loop through all of the streams in the profile.
        CHECK_HR(hr = pProfile->GetStreamCount(&cStreams));
        wprintf_s( L"Number of streams: %i\n", cStreams );
    
        if( !cStreams )
        {
            CHECK_HR( hr = E_UNEXPECTED );
        }
    
        pwStreamID = new WORD[cStreams];
    
        if( !pwStreamID )
        {
            CHECK_HR( hr = E_OUTOFMEMORY );
        }
    
        for (DWORD i = 0; i < cStreams; i++)
        {
            // Get the stream type and stream identifier.
            CHECK_HR(hr = pProfile->GetStream(i, &pwStreamID[i], NULL));
        }
    
        // SelectStreams takes an array of stream identifiers.
        CHECK_HR(hr = pSplitter->SelectStreams(pwStreamID, cStreams));
    
    done:
        delete[] pwStreamID;
        SAFE_RELEASE(pProfile);
        return hr;
    }
    
    /////////////////////////////////////////////////////////////////////
    HRESULT DisplaySamples(
        IMFByteStream *pStream, 
        IMFASFSplitter *pSplitter
        )
    {
        const DWORD cbReadSize = 32768;  // Read size (arbitrary value)
        HRESULT hr = S_OK;
        UINT32 cSamples = 0;
        DWORD   dwStatus;
        WORD    wStreamID;
    
        IMFSample *pSample = NULL;
        IMFMediaBuffer *pBuffer = NULL;
    
        while (TRUE)
        {
            // Read data into the buffer.
            CHECK_HR(hr = CreateBufferFromByteStream( pStream, cbReadSize, &pBuffer ) );
    
            DWORD   cbData;
            CHECK_HR(hr = pBuffer->GetCurrentLength(&cbData));
            wprintf_s( L"Read %iB\n", cbData);
    
            if (cbData == 0)
            {
                break; // End of file.
            }
    
            // Send the data to the ASF splitter.
            CHECK_HR(hr = pSplitter->ParseData(pBuffer, 0, 0));
    
            SAFE_RELEASE( pBuffer );
    
            // Pull samples from the splitter.
            do
            {
                CHECK_HR(hr = pSplitter->GetNextSample(&dwStatus, &wStreamID, &pSample));
    
                if (pSample == NULL)
                {
                    // No samples yet. Parse more data.
                    break;
                }
    
                cSamples++;
    
                // various information about the sample
                DWORD   cBuffers;
                DWORD   cbTotalLength;
                CHECK_HR(hr = pSample->GetBufferCount(&cBuffers));
                CHECK_HR(hr = pSample->GetTotalLength(&cbTotalLength));
    
                BOOL bIsKeyFrame = MFGetAttributeUINT32(pSample, MFSampleExtension_CleanPoint, FALSE);
    
                wprintf_s( L"Sample %03i (Stream: %i, Key-frame: %i, Buffers: %d, Length: %dB", 
                    cSamples,
                    wStreamID,
                    bIsKeyFrame,
                    cBuffers,
                    cbTotalLength
                    );
    
                MFTIME  hnsTime;
                if (SUCCEEDED(pSample->GetSampleTime(&hnsTime)))
                {
                    wprintf_s(L", Time: %ims", hnsTime / 10000);
                }
    
                wprintf_s(L")\n");
    
                SAFE_RELEASE(pSample);
                
            } while (dwStatus & ASF_STATUSFLAGS_INCOMPLETE);
        }
    
        wprintf_s(L"Done\n");
    
    done:
        SAFE_RELEASE(pSample);
        SAFE_RELEASE(pBuffer);
        return hr;
    }
    
    /////////////////////////////////////////////////////////////////////
    int __cdecl wmain(int argc, LPCWSTR argv[])
    {
        if (argc != 2)
        {
            wprintf_s(L"Usage: %s input.wmv", argv[0]);
            return 1;
        }
    
        const WCHAR         *sFileName = argv[1]; 
        HRESULT             hr = S_OK;
    
        IMFByteStream       *pStream = NULL;
        IMFASFContentInfo   *pContentInfo = NULL;
        IMFASFSplitter      *pSplitter = NULL;
    
        wprintf_s(L"Opening '%s'.\n", sFileName);
    
        CHECK_HR(hr = MFStartup(MF_VERSION));
    
        CHECK_HR(hr = OpenFile(sFileName, &pStream));
    
        CHECK_HR(hr = CreateContentInfo(pStream, &pContentInfo));
    
        CHECK_HR(hr = CreateASFSplitter(pContentInfo, &pSplitter));
    
        CHECK_HR(hr = SelectStreams(pContentInfo, pSplitter));
    
        CHECK_HR(hr = DisplaySamples(pStream, pSplitter));
    
    done:
        SAFE_RELEASE(pSplitter);
        SAFE_RELEASE(pContentInfo);
        SAFE_RELEASE(pStream);
        
        (void) MFShutdown();
    
        return FAILED(hr);
    }

    I tried it on the three videos under "C:\Users\Public\Videos\Sample Videos\".

    Hope this helps.
    • Proposed as answer by Enby Tuesday, April 21, 2009 4:35 PM
    • Marked as answer by The March Hare Wednesday, October 7, 2009 5:50 PM
    Thursday, April 16, 2009 12:28 AM

  •  Thanks for your help Matthieu,
      
       I was sending wrong information to the CreateBufferFromByteStream funtion (a different offset on each iteration).
       Now it works !!

    Thank you vey much :D


    - Enby.
    Tuesday, April 21, 2009 4:34 PM