视频会议中的音视频处理技术(Media Foundation)
ZeroJiu 愚昧之巅V4

在视频会议中,最基础的的部分应该就是音视频数据的处理了。对于音视频数据的处理,主要是在客户端,涉及到音视频采集、编解码、视频渲染等相关技术。本文接下来的篇幅,会逐点细述这几个相关的技术点。本文所涉及的技术主要是Windows平台下,其他平台请Google。另外,本文的重点在于视频方面,音频暂不详述,同时本文并没有详细的代码,只重点阐述如何实现。

媒体流

对于视频会议来说,客户端的处理内容主要是媒体流:

  • 音频输入流
  • 音频输出流
  • 视频输入流
  • 视频输出流

音频输入流的来源主要有麦克风采集和系统,视频输入流的来源主要是摄像头采集和屏幕录制。而对于音视频的输出,主要是通过扬声器、耳机、显示器等设备。

视频采集

视频采集的主要作用是为视频输入流产生视频数据。一般的笔记本都会自带摄像头,通过Windows Media Foundation提供的API函数MFEnumDeviceSources,我们能够遍历可使用的摄像头。该函数的具体使用方法见链接

每个摄像头都会支持很多格式——不同的分辨率、帧率。一般情况下,我们都会想要一个合适的视频格式。这个格式摄像头有可能不支持,所以在实现摄像头采集时,需要根据我们想要的格式,选择一个最佳匹配。可以按照以下两种匹配原则:

  • 寻找各个属性都最接近的格式
  • 寻找各个属性都相同的格式(帧率大于所需帧率也满足情况)

摄像头支持的视频格式可以通过Presentation Descriptors来获取,有关Presentation Descriptors的具体使用方法见链接

摄像头数据的输出采取异步操作,需要实现IMFSourceReaderCallback接口,并且在OnReadSample函数里输出采集到的视频数据。异步操作的设置需要将MFCreateSourceReaderFromMediaSource的IMFAttributes参数的属性MF_SOURCE_READER_ASYNC_CALLBACK设置为IMFSourceReaderCallback接口的具体实现。

视频采集的具体实现可以参照github上的video_capture项目。该项目实现了Windows/Linux/Mac三个平台下的摄像头采集操作。如果不想了解实现细节,可以直接使用这个开源项目。

视频编码

视频编码支持不少的格式:H263、H264、H265、VP8、VP9,这里重点是目前使用的较为普遍的H264格式。

在Windows下,H264编解码有不少实现,开源的有OpenH264、x264,FFMpeg软编软解使用的应该是x264,硬编硬解应该是对应的显卡商提供的库。Media Foundation较为全面的集成了软编、软解、硬编、硬解、硬件加速编解码。

我在多台PC上测试,发现一个现象:Media Foundation支持H264的软编解、硬编、硬件加速解码,却不支持硬解解码。暂且没有找到为什么不支持,不过对于上述几个编解码的支持,已经够我们在Windows平台下开发高性能的视频会议程序了。

如果需要使用软件编解码,推荐使用OpenH264,因为其实跨平台的,并且在Win7下的支持也做的很好。Media Foundation只能在Windows下使用,并且对于实时数据来说,其仅在Win8以上,才做到了较好的支持。如果Win7就像用Media Foundation,有可能还需要在深入的研究下MSDN的文档——非实时场景挺好用,实时场景稍微欠缺。

我们使用Media Foundation,是因为其硬件编解码能力。使用Media Foundation硬编功能主要按照以下步骤:

1、初始化COM组件Media Foundation组件

2、调用MFTEnumEx枚举硬件编码IMFTransform,调用ActivateObject激活对应硬件编码器。这里需要注意:

  • 硬件编码器采用异步模型,需要设置属性MF_TRANSFORM_ASYNC_UNLOCK为TRUE来解锁硬件编码器;
  • 硬件编码器的输入视频格式为MFVideoFormat_NV12,很多摄像头输出的是YUV、RGB24,需要进行转码,可使用libyuv开源库;
  • 记住调用CoTaskMemFree进行内存释放。

3、设置CodecApi,CodecApi主要用来控制编码器的细节属性;

  • 通过QueryInterface函数可以获取编码器的CodecApi接口实例;
  • 为了高质量,需要设置CODECAPI_AVEncCommonRateControlModeeAVEncCommonRateControlMode_Quality
  • 为了设置低时延,需要设置CODECAPI_AVLowLatencyMode属性为VARIANT_TRUE

4、设置输入输出MediaType

  • 这个比较好设置,按照输入和输出参数设置就行了,但是输入格式必须要设置为MFVideoFormat_NV12应该是必须吧,使用时还是需要对照MSDN来设置

5、初始化事件生成器,由于硬件编码是异步的,因此我们需要获取异步事件,必须要先初始化异步事件生成器。

6、发送初始化消息给MFT,包括下面两个消息:

  • MFT_MESSAGE_NOTIFY_BEGIN_STREAMING
  • MFT_MESSAGE_NOTIFY_START_OF_STREAM

上面是正式硬件编码的准备工作,下面便是编解码的处理过程。

7、将输入NV12格式视频数据填充到ISample中

8、通过事件产生器,获取异步事件,根据事件类型向编码器输入数据和输出数据,事件类型如下:

  • METransformNeedInput:需要输入视频数据
  • METransformHaveOutput:需要输出视频数据

9、对应需要输入视频数据时,需要调用ProcessInput方法来处理输入视频数据,对应需要输出视频数据时,需要调用ProcessOutput方法来处理输出视频数据。

  • 上述调用时一一对应的,出现一次NeedInput调用一次ProcessInput,出现一次HaveOutput调用一次ProcessOutput
  • 有时候会不需要输入数据,这个时候要等待NeedInput事件,在等待过程中,也需要及时的处理数据输出
  • 也有可能一次需要多个输入数据,这就需要用数组将数据保存起来,分别输入。

10、我们前面设置了输出流Media Type,可是在真正的流输出的时候,Media Type有可能改变,也就是ProcessOutput返回错误MF_E_TRANSFORM_STREAM_CHANGE

  • 这个时候,我们需要正确的处理流变化——调用GetOutputAvailableType,并重新设置流格式
  • 并不会因为流格式变化而造成丢帧

11、硬件编码结束的时候,需要发送下列消息给MFT,防止出现丢帧:

  • MFT_MESSAGE_NOTIFY_END_OF_STREAM
  • MFT_MESSAGE_COMMAND_DRAIN

上面两个消息发送完之后,硬件编码器会将存储在编码器内部尚未输出的帧,全部输出,保证了输入帧数和输出帧数一致。

12、调用IMFShutdown接口的shutdown函数来关闭硬件编码器。

实现上述十二个流程,便能实现一个基本的硬件编码器,需要注意,记得释放内存,否则会导致资源泄露——内存爆了。

对于MFT_OUTPUT_DATA_BUFFER接口来说,需要释放两个资源:pEventspSample

视频解码

对于视频解码,目前实现了Media Foundation硬件解码和硬件加速解码,我的机器仅支持H264的硬件加速解码,并不支持硬件解码,所以硬件解码未做测试。硬件解码和硬件加速解码是不一定的,虽然都使用了GPU的性能,但是硬件加速只是将部分解码工作放在GPU那里执行。

硬件加速解码可以认为是软件解码器和硬件解码器的结合,其编码模式遵从软件解码器的编码模式。所以如果想要Media Foundation的软件解码也可以参照下面的步骤。

1、初始化硬件加速解码器,我们需要判断该解码器是否支持MF_SA_D3D_AWARE属性,支持这个属性表明该解码器支持硬件加速;

  • 对于支持硬件加速的解码器,可以将CODECAPI_AVDecVideoAcceleration_H264属性设置为TRUE来启动硬件加速
  • 同时设置CODECAPI_AVLowLatencyMode来启动低时延模式

2、创建D3D设备管理器,并发送给MFT

  • 通过MFT_MESSAGE_SET_D3D_MANAGER消息发送给硬件加速编码器

3、设置输入输出类型,这里需要设置的属性并不多,具体可以参考MSDN上

4、软件编码是采用同步模式,所以不需要异步事件发生器。对于输入数据调用ProcessInput,进而直接得到ProcessOutput输出数据

  • 如果不设置低时延模式,ProcessOutput会一直返回NeedMoreInput,直到等到足够的输入。对于,非实时场景无所谓,对于实时场景影响很大。

5、ProcessOutput输出时,也有可能会出现流格式变化

  • 这个时候,需要遍历可用的输入流,找到合适的输出格式,并重新设置。

上述步骤描述较为简单,和视频编码步骤一致的都省略了,没有细述的请参考视频编码一节。

Powered by Hexo & Theme Keep
This site is deployed on
Unique Visitor Page View