使用Media Foundation播放从文件到扬声器的音频

时间:2015-01-30 11:59:15

标签: windows audio ms-media-foundation

我正在尝试将mp4文件中的音轨播放到我的扬声器。我知道Media Foundation能够解码音频流,因为我可以使用TopoEdit工具来播放它。

在下面的示例代码中,我没有使用媒体会话或拓扑。我正在尝试手动将媒体源连接到接收器编写器。我想这样做的原因是我最终打算从网络而不是文件中获取源样本。

运行下面的示例时,我在pSinkWriter-> WriteSample行上遇到的错误是MF_E_INVALIDREQUEST(0xC00D36B2)。所以我怀疑有些东西我没有正确连线。

#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;
}

为了简洁起见,我省略了转储媒体类型的代码,但它们的输出如下所示。很可能我没有正确连接媒体类型。

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, 

关于我在下一步可以看到的任何提示都将不胜感激。

2 个答案:

答案 0 :(得分:1)

我错过了接收器编写器的BeginWriting调用。

CHECK_HR(pSinkWriter->BeginWriting(), "Sink writer begin writing call failed.\n");

扬声器发出了一些声音,但声音非常糟糕,所以还有一些我不知道的东西。

答案 1 :(得分:0)

您为Reader设置的媒体类型不完整。 MF_MT_AUDIO_AVG_BYTES_PER_SECOND MF_MT_AUDIO_BLOCK_ALIGNMENT 和MF_MT_AUDIO_NUM_CHANNELS 不见了。

我会设置您从接收器mediatypehandler中检索的媒体类型。

相关问题