【问题标题】:Audio sample adding to a video using Sink Writer in Windows Media Foundation在 Windows Media Foundation 中使用 Sink Writer 添加到视频的音频示例
【发布时间】:2014-12-08 07:05:28
【问题描述】:

我可以使用通过此示例here 学到的图像编写视频文件。它使用IMFSampleIMFSinkWriter。现在我想给它添加音频。假设有 Audio.wma 文件,我希望将此音频写入该视频文件中。

但无法在此示例中弄清楚如何做到这一点。诸如输入和输出类型设置、IMFSample 创建音频缓冲区等。如果有人能告诉我如何使用接收器写入器将音频添加到视频文件中,那就太好了。

【问题讨论】:

    标签: audio windows-runtime c++-cx ms-media-foundation


    【解决方案1】:

    Media Foundation 非常适合与之合作,我相信您将能够快速修改您的项目以完成这项工作。

    概述:
    创建新的IMFMediaSource 以从音频文件中读取样本,将音频流添加到接收器,最后使用相应的流索引交错接收器写入。

    详情:

    修改VideoGenerator::InitializeSinkWriter(..) 函数以正确初始化接收器以适应音频流。在该函数中,正确创建 audioTypeOutaudioTypeIn (IMFMediaType)。为了清楚起见,您可能需要将 mediaTypeOutmediaTypeIn 重命名为 videoTypeOutvideoTypeIn,如下所示:

    ComPtr<IMFMediaType>  videoTypeOut;  // <-- previously mediaTypeOut
    ComPtr<IMFMediaType>  videoTypeIn;   // <-- previously mediaTypeIn
    ComPtr<IMFMediaType>  audioTypeOut = nullptr;
    ComPtr<IMFMediaType>  audioTypeIn = nullptr;
    

    接下来,配置与您的视频类型兼容的输出音频类型。由于您似乎正在创建 Windows 媒体视频,因此您可能希望使用 MFAudioFormat_WMAudioV9。为了确保通道、采样率和每个样本的位数都是正确的,我一般会枚举可用的类型并找到所需的特征,类似于以下(省略了错误检查):

    ComPtr<IMFCollection> availableTypes = nullptr;
    HRESULT hr = MFTranscodeGetAudioOutputAvailableTypes(MFAudioFormat_WMAudioV9, MFT_ENUM_FLAG_ALL, NULL, availableTypes.GetAddressOf());
    
    DWORD count = 0;
    hr = availableTypes->GetElementCount(&count));  // Get the number of elements in the list.
    
    ComPtr<IUnknown>     pUnkAudioType = nullptr;
    ComPtr<IMFMediaType> audioOutputType = nullptr;
    for (DWORD i = 0; i < count; ++i)
    {
        hr = availableTypes->GetElement(i, pUnkAudioType.GetAddressOf());
        hr = pUnkAudioType.Get()->QueryInterface(IID_PPV_ARGS(audioTypeOut.GetAddressOf()));
    
        // compare channels, sampleRate, and bitsPerSample to target numbers
        {
            // audioTypeOut is set!
            break;
        }
    
        audioOutputType.Reset();
    }
    
    availableTypes.Reset();
    

    如果 audioTypeOut 设置成功,则将该类型的流添加到接收器并获取结果索引:

    hr = sinkWriter->AddStream(audioTypeOut.Get(), &audioStreamIndex);
    audioTypeOut.Reset();  // <-- audioTypeOut not needed anymore
    

    最后,对于接收器,必须设置音频输入类型,这将取决于您正在阅读的文件和音频源 (IMFMediaSource)。稍后会详细介绍,但将音频输入添加到接收器将类似于以下内容:

    ComPtr<IMFMediaType> audioTypeIn = nullptr;  // <-- declaration from above
    // NOTE: audioReader is an IMFMediaSource used to read the audio file
    hr = audioReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, audioTypeIn.GetAddressOf());
    hr = sinkWriter->SetInputMediaType(_audioOutStreamIndex, audioTypeIn.Get(), nullptr);
    audioTypeIn.Reset();
    

    有许多示例可用于创建 audioReader (IMFMediaSource) 并从文件中读取样本,但 this one 简单直接。代码是here

    最后,您会发现编写音频非常简单,因为 sink 可以直接获取您从文件中读取的样本 (IMFSample)。您可以管理写入,但一种解决方案是交错写入(视频/音频)。处理音频样本的持续时间,但您需要重新设置时间戳。确保写入接收器时具有正确的流索引。

    使用异步回调读取样本:

    // if you are using an async callback, the function would look similar to the following:
    HRESULT OnReadAudioSample(HRESULT status, DWORD streamIndex, DWORD streamFlags, LONGLONG timestamp, IMFSample *sample)
    {
        // .. other code
        hr = sample->SetSampleTime(timestamp - _baseRecordTime);
        hr = sinkWriter->WriteSample(audioStreamIndex, sample);
        // .. other code
    
        // trigger the next asyc read...
        hr = audioReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, nullptr, nullptr, nullptr, nullptr);
    }
    

    同步读取样本:

    // otherwise, you will only use a synchronous read
    hr = audioReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, nullptr, &dwFlags, &timestamp, &sample);
    hr = sample->SetSampleTime(timestamp - _baseRecordTime);
    hr = sinkWriter->WriteSample(audioStreamIndex, sample);
    hr = WriteFrame(target.get(), rtStart, rtDuration);  // <-- write video frame as before
    

    听起来是一个有趣的小项目。祝你好运,玩得开心,希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 2019-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多