近期实验了下怎样让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支持H264编解码的更多相关文章

  1. ffmpeg H264 编解码配置

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

  2. 转:关于视频H264编解码的应用实现

    转:http://blog.csdn.net/scalerzhangjie/article/details/8273410 项目要用到视频编解码,最近半个月都在搞,说实话真是走了很多弯路,浪费了很多时 ...

  3. H264 编解码协议

    1.概述 H264是MPEG-4标准所定义的最新编码格式,同时也是技术含量最高.代表最新技术水平的视频编码格式之一,标准写法应该是H.264.H.264视频格式是经过有损压缩的,但是在技术上尽可能做到 ...

  4. H264 编解码框架简单介绍

    阅读完H264/AVC 编解码器的介绍,脑海中仅仅是留下下面三条: 1.H264并没有明白规定一个编解码器怎样实现,仅仅是规定了一个编码后的视频比特流的句法,和该比特流的解码方法,这个与MPEG 类似 ...

  5. 【FFMPEG】各种音视频编解码学习详解 h264 ,mpeg4 ,aac 等所有音视频格式

    目录(?)[-] 编解码学习笔记二codec类型 编解码学习笔记三Mpeg系列Mpeg 1和Mpeg 2 编解码学习笔记四Mpeg系列Mpeg 4 编解码学习笔记五Mpeg系列AAC音频 编解码学习笔 ...

  6. 聊聊视频中的编解码器,你所不知道的h264、h265、vp8、vp9和av1编解码库

    你知道FFmpeg吗?了解过h264/h265/vp8/vp9编解码库吗? 我们日常生活中使用最广泛的五种视频编码:H264(AVC).H265(HEVC).vp8.vp9.av1都分别是什么?由哪些 ...

  7. iOS8系统H264视频硬件编解码说明

    公司项目原因,接触了一下视频流H264的编解码知识,之前项目使用的是FFMpeg多媒体库,利用CPU做视频的编码和解码,俗称为软编软解.该方法比较通用,但是占用CPU资源,编解码效率不高.一般系统都会 ...

  8. 集显也能硬件编码:Intel SDK && 各种音视频编解码学习详解

    http://blog.sina.com.cn/s/blog_4155bb1d0100soq9.html INTEL MEDIA SDK是INTEL推出的基于其内建显示核心的编解码技术,我们在播放高清 ...

  9. 我的Android进阶之旅------>Android中编解码学习笔记

    编解码学习笔记(一):基本概念 媒体业务是网络的主要业务之间.尤其移动互联网业务的兴起,在运营商和应用开发商中,媒体业务份量极重,其中媒体的编解码服务涉及需求分析.应用开发.释放license收费等等 ...

随机推荐

  1. MySQL不能启动 Can't start server : Bind on unix socket: Permission denied

    转载博客地址:http://www.linuxidc.com/Linux/2010-04/25709.htm MySQL服务器突然不能启动,查看最后的启动日志如下: 080825 09:38:04 m ...

  2. 微博(MicroBlog)

    ylbtech_Miscellaneos  Inner 新浪微博  www.weibo.com 搜狐微博 http://t.sohu.com 网易微博 http://t.163.com/session ...

  3. LLVM每日谈之二十 Everything &amp;&amp; Clang driver

    作者:史宁宁(snsn1984) 近期在读<Getting Started with LLVM Core Libraries>.这是读的第一本LLVM的书.非常多地方尽管讲的是自己知道的东 ...

  4. redis批量删除多个keys

    Redis的官网redis.io,大家可以查看很多命令的使用方法 说明:删除单个key比较简单,直接使用命令del xxxkey,批量删除多个keys可利用如下命令: 假设:redis的安装目录如下: ...

  5. .Net程序测试阿里云OSS开放存储服务

    阿里云官网有提供OSS相关的操作API文档和.Net程序的 SDK,也可以在这里下载OSS相关文件 但是API文档里面的都是通过http请求和响应的消息来描述如何操作OSS的 而一般在程序中需要的是O ...

  6. jsp中URL传递中文參数的处理

    在页面的url中使用encodeURI(encodeURI(中文)).对中文进行编码.并在server的java程序中使用URLDecoder.decode(中文, "UTF-8" ...

  7. sql习题练习

    表结构: create database MyCompany go use MyCompany go create table Departments ( Department_ID ,) prima ...

  8. vue-router 运行机制 及 底层原理

    1.测试页面 index.html <!DOCTYPE html> <html lang="en"> <head> <meta chars ...

  9. STL学习笔记(变序性算法)

    变序性算法改变元素的次序,但不改变元素值. 这些算法不能用于关联式容器,因为在关联式容器中,元素有一定的次序,不能随意变动. 逆转元素次序 void reverse(BidirectionalIter ...

  10. 【DB2】db2命令Export与Import

    环境准备 1.新建表 qinys@Linux:~> db2 "create table tb1(id int,dt timestamp,name varchar(100))" ...