locked
Play audio from file to speaker with Media Foundation RRS feed

  • Question

  • I'm attempting to play the audio track from an mp4 file to my speaker. I know Media Foundation is able to decode the audio stream as I can play it with the TopoEdit tool.

    In the sample code below I'm not using a media session or topology. I'm attempting to manually connect the media source to the sink writer. The reason I want to do this is that I ultimately intend to be getting the source samples from the network rather than from a file.

    The error I get on the pSinkWriter->WriteSample line when running the sample below is MF_E_INVALIDREQUEST (0xC00D36B2). So I suspect there's something I haven't wired up correctly.

    #include <stdio.h>
    #include <tchar.h>
    #include <mfapi.h>
    #include <mfplay.h>
    #include <mfreadwrite.h>
    
    #pragma comment(lib, "mf.lib")
    #pragma comment(lib, "mfplat.lib")
    #pragma comment(lib, "mfplay.lib")
    #pragma comment(lib, "mfreadwrite.lib")
    #pragma comment(lib, "mfuuid.lib")
    
    #define CHECK_HR(hr, msg) if (hr != S_OK) { printf(msg); printf("Error: %.2X.\n", hr); goto done; }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
        MFStartup(MF_VERSION);
    
        IMFSourceResolver *pSourceResolver = NULL;
        IUnknown* uSource = NULL;
        IMFMediaSource *mediaFileSource = NULL;
        IMFSourceReader *pSourceReader = NULL;
        IMFMediaType *pAudioOutType = NULL;
        IMFMediaType *pFileAudioMediaType = NULL;
        MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;
        IMFMediaSink *pAudioSink = NULL;
        IMFStreamSink *pStreamSink = NULL;
        IMFMediaTypeHandler *pMediaTypeHandler = NULL;
        IMFMediaType *pMediaType = NULL;
        IMFMediaType *pSinkMediaType = NULL;
        IMFSinkWriter *pSinkWriter = NULL;
    
        // Set up the reader for the file.
        CHECK_HR(MFCreateSourceResolver(&pSourceResolver), "MFCreateSourceResolver failed.\n");
    
        CHECK_HR(pSourceResolver->CreateObjectFromURL(
            L"big_buck_bunny.mp4",      // URL of the source.
            MF_RESOLUTION_MEDIASOURCE,  // Create a source object.
            NULL,                       // Optional property store.
            &ObjectType,                // Receives the created object type. 
            &uSource                    // Receives a pointer to the media source.
            ), "Failed to create media source resolver for file.\n");
    
        CHECK_HR(uSource->QueryInterface(IID_PPV_ARGS(&mediaFileSource)), "Failed to create media file source.\n");
    
        CHECK_HR(MFCreateSourceReaderFromMediaSource(mediaFileSource, NULL, &pSourceReader), "Error creating media source reader.\n");
    
        CHECK_HR(pSourceReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, &pFileAudioMediaType), "Error retrieving current media type from first audio stream.\n");
    
        // printf("File Media Type:\n");
        // Dump pFileAudioMediaType.
    
        // Set the audio output type on the source reader.
        CHECK_HR(MFCreateMediaType(&pAudioOutType), "Failed to create audio output media type.\n");
        CHECK_HR(pAudioOutType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), "Failed to set audio output media major type.\n");
        CHECK_HR(pAudioOutType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float), "Failed to set audio output audio sub type (Float).\n");
    
        CHECK_HR(pSourceReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, NULL, pAudioOutType), "Error setting reader audio output type.\n");
    
        // printf("Source Reader Output Type:");
        // Dump pAudioOutType.
    
        CHECK_HR(MFCreateAudioRenderer(NULL, &pAudioSink), "Failed to create audio sink.\n");
    
        CHECK_HR(pAudioSink->GetStreamSinkByIndex(0, &pStreamSink), "Failed to get audio renderer stream by index.\n");
    
        CHECK_HR(pStreamSink->GetMediaTypeHandler(&pMediaTypeHandler), "Failed to get media type handler.\n");
    
        // My speaker has 3 audio types of which I got the furthesr with the third one.
        CHECK_HR(pMediaTypeHandler->GetMediaTypeByIndex(2, &pSinkMediaType), "Failed to get sink media type.\n");
    
        CHECK_HR(pMediaTypeHandler->SetCurrentMediaType(pSinkMediaType), "Failed to set current media type.\n");
    
        // printf("Sink Media Type:\n");
        // Dump pSinkMediaType.
    
        CHECK_HR(MFCreateSinkWriterFromMediaSink(pAudioSink, NULL, &pSinkWriter), "Failed to create sink writer from audio sink.\n");
    
        printf("Read audio samples from file and write to speaker.\n");
    
        IMFSample *audioSample = NULL;
        DWORD streamIndex, flags;
        LONGLONG llAudioTimeStamp;
    
        for (int index = 0; index < 10; index++)
        //while (true)
        {
            // Initial read results in a null pSample??
            CHECK_HR(pSourceReader->ReadSample(
                MF_SOURCE_READER_FIRST_AUDIO_STREAM,
                0,                              // Flags.
                &streamIndex,                   // Receives the actual stream index. 
                &flags,                         // Receives status flags.
                &llAudioTimeStamp,              // Receives the time stamp.
                &audioSample                    // Receives the sample or NULL.
                ), "Error reading audio sample.");
    
            if (flags & MF_SOURCE_READERF_ENDOFSTREAM)
            {
                printf("End of stream.\n");
                break;
            }
            if (flags & MF_SOURCE_READERF_STREAMTICK)
            {
                printf("Stream tick.\n");
                pSinkWriter->SendStreamTick(0, llAudioTimeStamp);
            }
    
            if (!audioSample)
            {
                printf("Null audio sample.\n");
            }
            else
            {
                CHECK_HR(audioSample->SetSampleTime(llAudioTimeStamp), "Error setting the audio sample time.\n");
    
                CHECK_HR(pSinkWriter->WriteSample(0, audioSample), "The stream sink writer was not happy with the sample.\n");
            }
        }
    
    done:
    
        printf("finished.\n");
        getchar();
    
        return 0;
    }

    I've omitted the code that dumps the media types for brevity but their output is shown below. It could well be that I haven't got the media types connected properly.

    File Media Type:
    Audio: MAJOR_TYPE=Audio, PREFER_WAVEFORMATEX=1, {BFBABE79-7434-4D1C-94F0-72A3B9E17188}=0, {7632F0E6-9538-4D61-ACDA-EA29C8C14456}=0, SUBTYPE={00001610-0000-0010-8000-00AA00389B71}, NUM_CHANNELS=2, SAMPLES_PER_SECOND=22050, BLOCK_ALIGNMENT=1, AVG_BYTES_PER_SECOND=8000, BITS_PER_SAMPLE=16, USER_DATA=<BLOB>, {73D1072D-1870-4174-A063-29FF4FF6C11E}={05589F81-C356-11CE-BF01-00AA0055595A}, ALL_SAMPLES_INDEPENDENT=1, FIXED_SIZE_SAMPLES=1, SAMPLE_SIZE=1, MPEG4_SAMPLE_DESCRIPTION=<BLOB>, MPEG4_CURRENT_SAMPLE_ENTRY=0, AVG_BITRATE=64000, 

    Source Reader Output Type:
    Audio: MAJOR_TYPE=Audio, SUBTYPE=Float, 

    Sink Media Type:
    Audio: MAJOR_TYPE=Audio, SUBTYPE=Float, NUM_CHANNELS=2, SAMPLES_PER_SECOND=48000, BLOCK_ALIGNMENT=8, AVG_BYTES_PER_SECOND=384000, BITS_PER_SAMPLE=32, ALL_SAMPLES_INDEPENDENT=1, CHANNEL_MASK=3, 

    Any hints as to where I could look next would be appreciated.


    Monday, February 2, 2015 11:18 AM

Answers

  • Needed:

    pSinkWriter->BeginWriting()

    • Marked as answer by azaclauson Tuesday, February 17, 2015 10:23 AM
    Tuesday, February 17, 2015 10:23 AM

All replies

  • Needed:

    pSinkWriter->BeginWriting()

    • Marked as answer by azaclauson Tuesday, February 17, 2015 10:23 AM
    Tuesday, February 17, 2015 10:23 AM
  • Reader Media Type may be incomplete
    Wednesday, September 23, 2015 5:31 AM