最近实验了下如何让WebRTC支持H264编码,记录下,供有需要的人参考。

说明一下,我是在 Ubuntu Server 14.04 下编译的 WebRTC ,使用 native(C++) api 开发 WebRTC 应用。所以我的调整都是基于 native 代码。

最终的效果是浏览器可以用H264发送视频,也可以接收H264视频。

注意,WebRTC 使用 OpenH264 来做 encoder (见 h264_encoder_impl.cc),使用 ffmpeg 来做 decoder (见 h264_decoder_impl.cc )。

代码版本

本文对应的代码是2017年2月8号的,可以使用 gclient revinfo -a来查看具体版本,如下:

编译选项调整

WebRTC可以支持H264,但在Linux下编译时,默认没有打开。

rtc_use_h264,这个开关控制了是否使用 H264 (对应C++代码中的宏 WEBRTC_USE_H264),在 webrtc/webrtc.gni 文件中定义:

rtc_use_h264 = proprietary_codecs && !is_android && !is_ios

proprietary_codecs 在 build/config/features.gni 中定义:

proprietary_codecs = is_chrome_branded || is_chromecast

我在 Linux 下编译,branded 默认是 Chromium ,所以,proprietary_codecs 默认就是 false 。

想来想去,只好通过 gn gen 时传入 args 来调整比较方便,使用下面的命令来生成 ninja 构建文件:

gn gen out/h264Debug --args="proprietary_codecs=true"

执行完毕后,可以使用下列命令验证一下:

gn args out/h264Debug --list=proprietary_codecs
gn args out/h264Debug --list=rtc_use_h264

看到 Current Value 为 true,就说明这个选项已经生效了。

打开 rtc_use_h264 ,OpenH264 的编码支持就使能了。

WebRTC内部会使用 ffmpeg 来解码 H264 (见 h264_decoder_impl.cc ),与 ffmpeg 相关的还有一个选项——rtc_initialize_ffmpeg,这个也得为 true ,否则 ffmpeg 的 avcodec 不会初始化,用不成。

rtc_initialize_ffmpeg 定义在 webrtc/webrtc.gni 中定义:

rtc_initialize_ffmpeg = !build_with_crhome

因为我们为 native 开发而编译,build_with_chrome 默认为 false ,所以 rtc_initialize_ffmpeg 默认为 true ,不用调整。

rtc_initialize_ffmpeg 开关对应一个 C++ 代码中的宏 WEBRTC_INITIALIZE_FFMPEG 。

要使用 ffmpeg 的 h264 decoder 功能,还需要修改一个宏: FFMPEG_H264_DECODER。在 config.h 文件中,路径是 third_party/chromium/config/chromium/linux/x64。原来定义如下:

#define CONFIG_H264_DECODER 0

修改为 1 即可。这样 avcodec_register_all() 方法才会把 H264 decoder 注册到系统中。

等下,实际上还有一部分非常重要的工作要做。因为 linux 下编译 WebRtc ,默认生成的 ninja 构建文件中,没有 ffmpeg 的 h264 decoder 对应的源码,所以即便你打开 FFMPEG_H264_DECODER 也不管用,必须得修改 third_party/ffmpeg/ffmpeg_generated.gni 文件,找到包含 h264的那些条件,打开即可。

注:因为我一开始编译时没有打开 H264 支持,所以在修改了ffmpeg_generated.gni 文件后,使用 gn gen 生成 ninja 构建文件时,指定了一个新的目录,然后把 ffmpeg 相关的 ninja 文件(三个),拷贝到了原来的构建目录中,然后使用 ninja ffmpeg 命令来编译出 so 文件。

codec 的顺序调整

网页使用 WebRTC 发送 SDP ,进行协商时,默认的 codec 顺序是:

  1. VP8
  2. VP9
  3. H264

在 C++ 代码里,会默认选择第一个来匹配(从PeerConnection::CreateAnswer/SetRemoteDescription两个方法跟进去,可以看到)。所以,我们要修改 C++ 代码,来改变这个选择逻辑。

WebRtcVideoChannel2(webrtcvideoengine2.cc)使用的 codec ,来自 InternalEncoderFactory类(internalencoderfactory.cc),不管是作为发送端还是接收端,编码格式都来自这里。

在InternalEncoderFactory的构造函数里,可以调整 codec 的顺序,默认代码如下:

supported_codecs_.push_back(cricket::VideoCodec(kVp8CodecName));
if (webrtc::VP9Encoder::IsSupported())supported_codecs_.push_back(cricket::VideoCodec(kVp9CodecName));
if (webrtc::H264Encoder::IsSupported()) {cricket::VideoCodec codec(kH264CodecName);// TODO(magjed): Move setting these parameters into webrtc::H264Encoder// instead.codec.SetParam(kH264FmtpProfileLevelId,kH264ProfileLevelConstrainedBaseline);codec.SetParam(kH264FmtpLevelAsymmetryAllowed, "1");supported_codecs_.push_back(std::move(codec));
}supported_codecs_.push_back(cricket::VideoCodec(kRedCodecName));
supported_codecs_.push_back(cricket::VideoCodec(kUlpfecCodecName));
....

只要把 H264 那个 codec 调整到前面即可。

做了这个调整,Native app 作为发送视频的一端,在 SDP 协商时, H264 的支持就会放在前面,另外一端如果支持 H264 解码,就会优先选择 H264 格式,两边就能以 H264 来交互视频流了。

浏览器作为发送视频的一端时,它发过来的视频格式顺序是 VP8、VP9、H264,Native C++代码中会根据这个顺序来调整本地的 codec 的顺序,代码在 mediasession.cc 中:

template <class C>
static void NegotiateCodecs(const std::vector<C>& local_codecs,const std::vector<C>& offered_codecs,std::vector<C>* negotiated_codecs) {for (const C& ours : local_codecs) {C theirs;// Note that we intentionally only find one matching codec for each of our// local codecs, in case the remote offer contains duplicate codecs.if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {C negotiated = ours;negotiated.IntersectFeedbackParams(theirs);if (IsRtxCodec(negotiated)) {const auto apt_it =theirs.params.find(kCodecParamAssociatedPayloadType);// FindMatchingCodec shouldn't return something with no apt value.RTC_DCHECK(apt_it != theirs.params.end());negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);}if (CodecNamesEq(ours.name.c_str(), kH264CodecName)) {webrtc::H264::GenerateProfileLevelIdForAnswer(ours.params, theirs.params, &negotiated.params);}negotiated.id = theirs.id;negotiated.name = theirs.name;negotiated_codecs->push_back(std::move(negotiated));}}// RFC3264: Although the answerer MAY list the formats in their desired// order of preference, it is RECOMMENDED that unless there is a// specific reason, the answerer list formats in the same relative order// they were present in the offer.std::unordered_map<int, int> payload_type_preferences;int preference = static_cast<int>(offered_codecs.size() + 1);for (const C& codec : offered_codecs) {payload_type_preferences[codec.id] = preference--;}std::sort(negotiated_codecs->begin(), negotiated_codecs->end(),[&payload_type_preferences](const C& a, const C& b) {return payload_type_preferences[a.id] >payload_type_preferences[b.id];});
}

最后那个 sort 调用,根据发送端的 codec 顺序重新调整了我们支持的解码格式的顺序。所以,我们在这里也需要修改一下,把排序的部分去掉,或者针对 H264 去掉。

重新编译

使用下列命令,可以编译特定模块:

ninja pc (针对 mediasession.cc )
ninja media (针对 internalencoderfactory.cc 和 webrtcvideoengine2.cc )
ninja ffmpeg (针对 ffmpeg )

然后再编译你自己的 native app 。


相关阅读:

  • WebRTC学习资料大全
  • Ubuntu 14.04下编译WebRTC
  • WebRTC源码中turnserver的使用方法
  • 打开 WebRTC 的日志(native api)

让WebRTC支持H264编解码相关推荐

  1. WebRTC android 端支持H264编解码

    一.WebRTC源码中默认使用的H264编解码的库 1.WebRTC源码的video_coding模块中,包含了H264编解码相关的类 打开画红线的两个头文件,分别可以看到解码类中导入了ffmpeg的 ...

  2. CrossWalk WebView添加支持WebRTC及H264编解码

    前言 1.WebView简介 WebView是Android平台上的一个非常重要的系统组件,用于将一个显示浏览器页面的窗口嵌入到应用程序,并提供一组接口让开发者定制一些页面加载及JavaScript对 ...

  3. TightVNC H264编解码(一)

    时光流逝,时间过的真快啊!疲于工作,发现近一个多月没写文章了.此文算是对最近的工作做个总结吧.经过尽二个月的不断摸索,TightVNC终于支持H264编解码了,前期真正编写H264编解码器只花了一周左 ...

  4. webrtc默认使用h264编解码

    webrtc默认选择的是vp8编解码,要修改为默认h264编解码,则需要编码和解码都修改,需要做到下面三步 编译支持 编译时候增加属性 proprietary_codecs,设为true 例如: /. ...

  5. Linux下通过v4l2获取视频设备名、支持的编解码及视频size列表实现

    早些时候给出了在Windows下通过dshow获取视频设备信息的实现,包括获取视频设备名.获取每种视频设备支持的编解码格式列表.每种编解码格式支持的video size列表,见:https://blo ...

  6. 通过Windows DShow获取设备名、支持的编解码及视频size列表实现

    之前在https://blog.csdn.net/fengbingchun/article/details/102641967中介绍过通过DShow获取Camera视频的实现,即调用VideoCapt ...

  7. 音视频开发系列--H264编解码总结

    一.概述 H264,通常也被称之为H264/AVC(或者H.264/MPEG-4 AVC或MPEG-4/H.264 AVC) 对摄像头采集的每一帧视频需要进行编码,由于视频中存在空间和时间的冗余,需要 ...

  8. H264编解码SPS、PPS参数说明

    H264编解码参数说明 一.H264码流分层 1.NAL层 ①.如何判断帧类型(是图像参考帧还是I.P帧等)? ②. 帧格式 ③. [SPS格式解析代码分析 ParseAndRewriteSps方法 ...

  9. ffmpeg H264 编解码配置

    ffmpeg H264编解码前面有文章介绍下,本文主要介绍一些参数配置. 编码: int InitEncoderCodec( int iWidth, int iHeight) {AVCodec * p ...

最新文章

  1. 一位刚刚成功上岸的智能车队员对于参赛经历总结与对比赛的建议
  2. Groovy在Spring中的简单使用实例
  3. C++中图的简单表示法
  4. EXTASPNET C# ASP.NET sql server 调用存储过程超时,解决方法
  5. 点击查询后在表格中获取控件的值
  6. 快速上手系列:传智播客Java基础笔记
  7. BigDecimal——大十进制-货币型-双精度-精确运算
  8. (转)姚期智:呼之欲出的量子计算机,和它漫长的最后一英里(全文)
  9. Notepad2 巧妙替换回车换行符
  10. 一种标准地图服务转矢量Shapefile方法
  11. AutoJs学习-多点取色
  12. 瓦楞机自动排单技术收藏
  13. android广告id,谷歌广告 ID 获取
  14. 产品读书《失控:全人类的最终命运和结局》KK
  15. Amazon,我们完全不能接受 — 因此我们必须变更 Elastic 许可协议
  16. navicat for mysql 12 破解工具 亲测可用
  17. 【游戏面包屑】时间回溯·逆流吧
  18. win10系统potplay播放器关闭自动更新方法
  19. IMWEB小白DAY3-制作个人名片
  20. android相册管理系统下载安装,云象相册管理

热门文章

  1. 今天推荐一下网友张迪的博客
  2. 上游模式用于实验室用冷冻机压力和真空度的高精度控制
  3. swagger 2.9.2
  4. StatQuest-MachineLearning-Lesson1~5
  5. 软件架构发展历程分享
  6. 各项的语言资源,从入门到精通
  7. 源生的html属性js,源生JS怎样实现todolist功能
  8. 使用Dockerfile文件构建镜像
  9. 项目经验 需求评审与技术评审
  10. STF安装与使用(windows)