媒体基础:将G711 PCMU写入mp4

Posted

技术标签:

【中文标题】媒体基础:将G711 PCMU写入mp4【英文标题】:Media foundation: Writing G711 PCMU to mp4 【发布时间】:2020-02-12 16:43:32 【问题描述】:

我们有一个要求(Windows UWP 应用程序)将从相机接收的音频和视频数据(RTP 数据包)以 mp4 格式存储。视频格式为 h264,音频为 g711 pcmu

我们正在使用 media Foundation(c# using MF .Net) sinkWriter 将视频数据写入 mp4,效果很好。我想知道如何将音频样本写入 mp4。我尝试了以下方法:

private void SetupAudioMediaType(out IMFMediaType mediaType, in Guid audiosubType)
    
    HResult hr = HResult.S_OK;

    hr = MFExtern.MFCreateMediaType(out mediaType);
    if (!hr.Succeeded())
    
        Debug.Fail("MFCreateMediaType for audio failed " + hr.ToString());
        return;
    

    hr = mediaType.SetGUID(MFAttributesClsid.MF_MT_MAJOR_TYPE, MFMediaType.Audio);
    if (!hr.Succeeded())
    
        Debug.Fail("Set MF_MT_MAJOR_TYPE media-out failed " + hr.ToString());
        return ;
    
    hr = mediaType.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, audioSubType);
    if (!hr.Succeeded())
    
        Debug.Fail("Set MF_MT_SUBTYPE media-out failed " + hr.ToString());
        return ;
    

    hr = mediaType.SetUINT32(MFAttributesClsid.MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000);
    if (!hr.Succeeded())
    
        Debug.Fail("Set MF_MT_AUDIO_SAMPLES_PER_SECOND media-out failed " + hr.ToString());
        return 
    

    hr = mediaType.SetUINT32(MFAttributesClsid.MF_MT_AUDIO_NUM_CHANNELS, 1);
    if (!hr.Succeeded())
    
        Debug.Fail("Set MF_MT_AUDIO_NUM_CHANNELS media-out failed " + hr.ToString());
        return ;
    

    hr = mediaType.SetUINT32(MFAttributesClsid.MF_MT_AUDIO_BITS_PER_SAMPLE, 8);
    if (!hr.Succeeded())
    
        Debug.Fail("Set MF_MT_AUDIO_BITS_PER_SAMPLE media-out failed " + hr.ToString());
        return ;
    

    return errorCode;




private MultiplexerErrorCode SetupAudio()

    HResult hr = HResult.S_OK;

    IMFMediaType mediaTypeOut = null;
    IMFMediaType mediaTypeIn = null;

    SetupAudioMediaType(out mediaTypeOut, MFMediaType.AAC);  // or mp3 (MP4 in windows support mp3 or aac)
    if (errorCode != MultiplexerErrorCode.Success)
    
        Debug.Fail("setupAudioMediaType output failed:", errorCode.ToString());
    
    else
    
        hr = sinkWriter.AddStream(mediaTypeOut, out audioStreamIndex);
        if (!hr.Succeeded())
        
            Debug.Fail("AddStream  audio  failed " + hr.ToString());
        
        else
        
            Guid PcmuAudioSubType = (new FourCC(7,0,0,0)).ToMediaSubtype();   //PCMU
            SetupAudioMediaType(out mediaTypeIn, PcmuAudioSubType);
            hr = sinkWriter.SetInputMediaType(audioStreamIndex, mediaTypeIn, null);
            if (!hr.Succeeded())
            
                Debug.Fail("SetInputMediaType audio  failed " + hr.ToString());
            
        
    

    return ;

SetInputMediaType 返回错误 MF_E_INVALIDMEDIATYPE。根据我的分析,以下是错误的原因

1) 我认为 PCMU 输入类型不受支持。应该是PCM。这种理解正确吗?如果是这样,这是否意味着我必须将 PCMU 解码为 PCM。如果是这样,是否有任何 Windows c# API 可以做到这一点?一旦解码完成,输出 pcm 中每个样本的位数是多少。是16吗?

2) 即使我提供 pcm 作为输入类型,SetInputMediaType 也会返回 MF_E_INVALIDMEDIATYPE 错误。是不是因为 aac 编码器只支持 44.1 & 48Khz 的采样率。 (mp3 支持 32 Khz,...)。如果我的理解是正确的,我该如何克服这个问题。我应该上采样吗?如果有怎么办?

3)有没有更简单的方法可以将 pcmu(每秒 8000 个样本,每个样本 8 位)连同视频帧一起写入 mp4

【问题讨论】:

如果您使用的是 C#,那么解码音频的快速方法是使用 NAudio。要深入了解,请参阅codeproject.com/Articles/501521/…。 【参考方案1】:

对于 1) 和 3),请阅读:muxing-only-audio-into-mp4-ffmpeg-failed

对于 2)

将 G711 解码为 PCM(CLSID_MULawCodecWrapper:92B66080-5E2D-449E-90C4-C41F268E5514) 使用音频重采样器 (Audio Resampler DSP) 将重新采样的 PCM 编码为 AAC (AAC Encoder)

也许 CLSID_MULawCodecWrapper 能够重新采样。 也许您会遇到音频/视频同步问题。

【讨论】:

非常感谢。我将检查 CLSID_MULawCodecWrapper 并检查音频重采样器。如果我通过 PCM 输入(48000Hz,每个样本 16 位),我想检查我的代码是否有效。我的代码有效,我得到了可播放的音频(.m4a 文件 aac 编解码器)。但是,如果我更改为 mp3(.mp3 文件和音频子类型为 .mp3),我会得到 MF_E_INVALIDMEDIATYPE 。为什么 mp3 媒体类型会出错。从文档中我看到它支持 PCM,采样率为 48000Hz,每个样本的位数为 16,通道数为 1。我是否应该提供更多属性。我的配置有什么问题

以上是关于媒体基础:将G711 PCMU写入mp4的主要内容,如果未能解决你的问题,请参考以下文章

媒体基础 MP4 编码:IMFSinkWriter 不接受 PCM 输入

流媒体开发7ffmpeg基础命令

Go语学习笔记 - 实现将mp4通过rtmp推送流媒体服务

如何在媒体基础上定制视频媒体/流接收器请求RGB32帧?

多媒体文件格式:MP4 格式

用户选择是下载还是流式传输mp4媒体