Author published on included in Git 1、Gerrit的基本介绍 Gerrit 是一个Git服务器,它基于 git 版本控制系统,使用网页界面来进行审阅工作。Gerrit 旨在提供一个轻量级框架,用于在代码入库之前对每个提交进行审阅,更改将上载到 Gerrit,但实际上并不成为项目的一部分,直到它们被审阅和接受 。代码审查是Gerrit的核心功能,但仍是可选的,团队可以决定不进行代码审查而工作。
Gerrit 是一个临时区域, 在提交的代码成为代码库的一部分之前, 可以对其修改进行检查。代码修改的作者将提交作为对 Gerrit 的更改。在Gerrit中,每个更改都存储在暂存区域中,可以在其中进行检查和查看。仅当它被批准并提交时,它才被应用到代码库中。
其实,Gerrit 就相当于是在开发员将本地修改提交到代码仓库之前的一个审核工具。在这个审核工具中,你可以查看该提交者在本次的的提交中的修改,然后再决定是否可以将该修改提交给仓库。
2、Gerrit的页面介绍 2.1、CHANGES菜单 点击 changes 可以查看所在项目的所有审批记录,共有三种状态:open、merged、abandoned。
open:还未审核、审核不通过、审核通过还未提交到远程仓库的提交
merged:审核已通过并已提交到远程仓库的提交
abandoned:已取消审核的提交
2.2、YOUR -> CHANGES 菜单 点击 your -> changes 可以查看当前登录用户的名下的所有审核记录,包括本人提交和本人需审核的。
outgoing reviews:本人待被审核的提交
incoming reviews:别人提交,本人需要审核的提交
recently closed:已关闭的提交,包括已经推送到远程仓库和已经取消审核的
2.3、Repositories 点击 repositories 可以看到自己有权限看到的所有项目。
点击进入某个项目,可以查看该项目的下载链接,共有三种下载方式:
anonymous http:链接里面无用户名,下载时需输入用户名和密码
http:链接里待用户名,下载时无需输入用户名,但需要输入密码
ssh:免密方式,无需输入用户名和密码,但需将本地生成的公钥保存在 Gerrit 网页中
3、在Gerrit上的代码克隆方式 在Gerrit上有三种克隆方式,如上面的 2.3 所示,跟在 github 上克隆代码没什么区别。
在 Gerrit 中,你可以选择 clone with commit-msg hook 选项来进行克隆,该选项在上面的三种克隆方式中都有,该方式会将 Gerrit 上的 commit-msg 脚本拷贝在你的本地仓库中,由此你就可以将代码提交到 Gerrit 中(未验证)。 commit-msg 脚本是使用 Gerrit 的一个非常重要的步骤,不可或缺,后面会介绍。
一、前言 在Linux系统中常用udev或mdev来实现可移动存储设备的节点创建和挂载。这两者功能相似,但是mdev更精简。因此在空间受限的嵌入式设备中,mdev更常用。
二、mdev介绍 mdev有两种用法:
1)/sbin/mdev
2)/sbin/mdev -s
区别在于1是创建或删除发生变化的设备节点,通常在发生热插拔时调用;2是创建所有设备节点,通常在启动脚本中调用。我们看到的/dev下的所有设备,都是系统在启动时通过mdev -s创建的。Linux内核支持hotplug机制,当内核检测到热插拔事件时,会调用/proc/sys/kernel/hotplug这个文件中记录的程序,来处理热插拔事件。因此,只要将/sbin/mdev写入上述的文件,就能实现热插拔时设备节点文件自动更新。
三、实现自动挂载 有几个前提条件必须满足:
1)内核编译时需支持hotplug功能,默认是支持的,可以通过查看是否有/proc/sys/kernel/hotplug这文件来判断是否支持了hotplug。
2)使用Busybox制作rootfs时,需支持mdev
Linux System Utilities ---> [*] mdev [*] Support /etc/mdev.conf [*] Support command execution at device addition/removal 实现步骤:
1.在启动脚本/etc/init.d/rcS中,增加如下内容: mount -t tmpfs mdev /dev mount -t sysfs sysfs /sys mkdir /dev/pts mount -t devpts devpts /dev/pts echo /sbin/mdev > /proc/sys/kernel/hotplug mdev -s 需要注意是,上面的几个目录,可能有的文件系统在别处已经挂载了,这里再次挂载会报错。可以查看一下/etc/fstab这个文件,以及/etc/init.d/inittab文件。如有冲突,注释任何一方均可。
我的/etc/fstab文件:
# <file system> <mount pt> <type> <options> <dump> <pass> proc /proc proc defaults 0 0 devpts /dev/pts devpts defaults,gid=5,mode=620 0 0 #tmpfs /dev/shm tmpfs mode=0777 0 0 tmpfs /tmp tmpfs mode=1777 0 0 tmpfs /run tmpfs mode=0755,nosuid,nodev 0 0 sysfs /sys sysfs defaults 0 0 我的/etc/init.
0.简介 这是一个由 声网Agora WebRTC团队提供的 WebRTC 镜像源,你可以使用此版本代替 Google 官方版本,此镜像保持与Chrome正式版同步,目前为M84。
如遇到问题,请在此地址发帖:https://rtcdeveloper.com/t/topic/14914
官方英文文档,请见:https://www.w3.org/TR/webrtc/
中文文档开源版本,请见:https://github.com/RTC-Developer/WebRTC-Documentation-in-Chinese
1. 环境配置 指定同步目录 export WORKSPACE=`pwd`
安装depot_tools cd $WORKSPACE
rm -rf depot_tools && git clone https://webrtc.bj2.agoralab.co/webrtc-mirror/depot_tools.git
chmod +x $WORKSPACE/depot_tools/cipd
export PATH=$PATH:$WORKSPACE/depot_tools
同步WebRTC mkdir -p $WORKSPACE/webrtc && cd $WORKSPACE/webrtc vi .gclient //添加以下内容 solutions = [ { "name" : "src", "url" : "https://webrtc.bj2.agoralab.co/webrtc-mirror/src.git@65e8d9facab05de13634d777702b2c93288f8849", "deps_file" : "DEPS", "managed" : False, "safesync_url": "", "custom_deps": { }, }, ] target_os = ["linux"] /*根据需要Android, ios*/ //开始同步,时间较久 date; gclient sync; date //出现提示是否使用谷歌的depot_tools,推荐“n”,或者等1分钟提示框超时。 //因为gclient sync获取源码之后,会向谷歌获取其它数据,如果因此报错,不想看到这个错误的话,可以设置代理之后再次sync export http_proxy=x.
前言 H264视频压缩算法现在无疑是所有视频压缩技术中使用最广泛,最流行的。随着 x264/openh264以及ffmpeg等开源库的推出,大多数使用者无需再对H264的细节做过多的研究,这大降低了人们使用H264的成本。
但为了用好H264,我们还是要对H264的基本原理弄清楚才行。今天我们就来看看H264的基本原理。
H264概述 H264压缩技术主要采用了以下几种方法对视频数据进行压缩。包括:
帧内预测压缩,解决的是空域数据冗余问题。 帧间预测压缩(运动估计与补偿),解决的是时域数据冗徐问题。 整数离散余弦变换(DCT),将空间上的相关性变为频域上无关的数据然后进行量化。 CABAC压缩。 经过压缩后的帧分为:I帧,P帧和B帧:
I帧:关键帧,采用帧内压缩技术。 P帧:向前参考帧,在压缩时,只参考前面已经处理的帧。采用帧音压缩技术。 B帧:双向参考帧,在压缩时,它即参考前而的帧,又参考它后面的帧。采用帧间压缩技术。 除了I/P/B帧外,还有图像序列GOP。
GOP:两个I帧之间是一个图像序列,在一个图像序列中只有一个I帧。如下图所示: 下面我们就来详细描述一下H264压缩技术。
H264压缩技术 H264的基本原理其实非常简单,下我们就简单的描述一下H264压缩数据的过程。通过摄像头采集到的视频帧(按每秒 30 帧算),被送到 H264 编码器的缓冲区中。编码器先要为每一幅图片划分宏块。
以下面这张图为例:
划分宏块 H264默认是使用 16X16 大小的区域作为一个宏块,也可以划分成 8X8 大小。
划分好宏块后,计算宏块的象素值。
以此类推,计算一幅图像中每个宏块的像素值,所有宏块都处理完后如下面的样子。
划分子块 H264对比较平坦的图像使用 16X16 大小的宏块。但为了更高的压缩率,还可以在 16X16 的宏块上更划分出更小的子块。子块的大小可以是 8X16、 16X8、 8X8、 4X8、 8X4、 4X4非常的灵活。
上幅图中,红框内的 16X16 宏块中大部分是蓝色背景,而三只鹰的部分图像被划在了该宏块内,为了更好的处理三只鹰的部分图像,H264就在 16X16 的宏块内又划分出了多个子块。
这样再经过帧内压缩,可以得到更高效的数据。下图是分别使用mpeg-2和H264对上面宏块进行压缩后的结果。其中左半部分为MPEG-2子块划分后压缩的结果,右半部分为H264的子块划压缩后的结果,可以看出H264的划分方法更具优势。
宏块划分好后,就可以对H264编码器缓存中的所有图片进行分组了。
帧分组 对于视频数据主要有两类数据冗余,一类是时间上的数据冗余,另一类是空间上的数据冗余。其中时间上的数据冗余是最大的。下面我们就先来说说视频数据时间上的冗余问题。
为什么说时间上的冗余是最大的呢?假设摄像头每秒抓取30帧,这30帧的数据大部分情况下都是相关联的。也有可能不止30帧的的数据,可能几十帧,上百帧的数据都是关联特别密切的。
对于这些关联特别密切的帧,其实我们只需要保存一帧的数据,其它帧都可以通过这一帧再按某种规则预测出来,所以说视频数据在时间上的冗余是最多的。
为了达到相关帧通过预测的方法来压缩数据,就需要将视频帧进行分组。那么如何判定某些帧关系密切,可以划为一组呢?我们来看一下例子,下面是捕获的一组运动的台球的视频帧,台球从右上角滚到了左下角。
H264编码器会按顺序,每次取出两幅相邻的帧进行宏块比较,计算两帧的相似度。如下图:
通过宏块扫描与宏块搜索可以发现这两个帧的关联度是非常高的。进而发现这一组帧的关联度都是非常高的。因此,上面这几帧就可以划分为一组。其算法是:在相邻几幅图像画面中,一般有差别的像素只有10%以内的点,亮度差值变化不超过2%,而色度差值的变化只有1%以内,我们认为这样的图可以分到一组。
在这样一组帧中,经过编码后,我们只保留第一帖的完整数据,其它帧都通过参考上一帧计算出来。我们称第一帧为IDR/I帧,其它帧我们称为P/B帧,这样编码后的数据帧组我们称为GOP。
运动估计与补偿 在H264编码器中将帧分组后,就要计算帧组内物体的运动矢量了。还以上面运动的台球视频帧为例,我们来看一下它是如何计算运动矢量的。
H264编码器首先按顺序从缓冲区头部取出两帧视频数据,然后进行宏块扫描。当发现其中一幅图片中有物体时,就在另一幅图的邻近位置(搜索窗口中)进行搜索。如果此时在另一幅图中找到该物体,那么就可以计算出物体的运动矢量了。下面这幅图就是搜索后的台球移动的位置。
通过上图中台球位置相差,就可以计算出台图运行的方向和距离。H264依次把每一帧中球移动的距离和方向都记录下来就成了下面的样子。
运动矢量计算出来后,将相同部分(也就是绿色部分)减去,就得到了补偿数据。我们最终只需要将补偿数据进行压缩保存,以后在解码时就可以恢复原图了。压缩补偿后的数据只需要记录很少的一点数据。如下所示:
我们把运动矢量与补偿称为帧间压缩技术,它解决的是视频帧在时间上的数据冗余。除了帧间压缩,帧内也要进行数据压缩,帧内数据压缩解决的是空间上的数据冗余。下面我们就来介绍一下帧内压缩技术。
帧内预测 人眼对图象都有一个识别度,对低频的亮度很敏感,对高频的亮度不太敏感。所以基于一些研究,可以将一幅图像中人眼不敏感的数据去除掉。这样就提出了帧内预测技术。
H264的帧内压缩与JPEG很相似。一幅图像被划分好宏块后,对每个宏块可以进行 9 种模式的预测。找出与原图最接近的一种预测模式。
近年来,H265作为新的视频编码标准,应用越来越广发,相较于H264,其在高压缩率、高鲁棒性和错误恢复能力、低延时等方面有很更好的表现,因此H265(HEVC)也在越来越多的场景下逐步替代H264。
1 H265编码方式介绍 有关H265编码知识不做详细描述,这里主要介绍和RTP相关的知识,主要指NALU头部解析及类型介绍。
H265 NALU头部格式如下:
与h264的nal层相比,h265的nal unit header有两个字节构成,从图中可以看出hHEVC的nal包结构与h264有明显的不同,hevc加入了nal所在的时间层的ID,去除了nal_ref_idc,字段解释如下:
F:禁止位,1bit(最高位:15位),必须是0,为1标识无效帧
Type: 帧类型,6bits(9~14位),0-31是vcl nal单元;32-63,是非vcl nal单元,VCL是指携带编码数据的数据流,而non-VCL则是控制数据流。
其类型枚举如下:
LayerID:6 bits,表示NAL所在的Access unit所属的层,该字段是为了HEVC的继续扩展设置,一般为0
TID:3bits,一般为1,此字段指定nal单元加1的时间标识符。时间id的值等于tid-1,tid的值为0是非法的,以确保nal单元报头中至少只有一个比特等于1,以便能够在nal单元头和nal单元有效负载数据中独立考虑启动代码仿真。
通常情况下F为0,layerid为0,TID为1。
H265帧类型与H264不一样,其位置在第一个字节的1~6位(buf[0]&0x7E»1),起始标识位00000001;常见的NALU类型:
40 01,type=32,VPS(视频参数集)
42 01,type=33,SPS(序列参数集)
44 01,type=34,PPS(图像参数及)
4E 01, type=39,SEI(补充增强信息)
26 01,type=19,可能有RADL图像的IDR图像的SS编码数据 IDR
02 01, type=01,被参考的后置图像,且非TSA、非STSA的SS编码数据
H265码流二进制片段如下:
以下帧类型在性能不足时可以丢弃:HEVC_NAL_TRAIL_N、HEVC_NAL_TSA_N、HEVC_NAL_STSA_N、HEVC_NAL_RADL_N、HEVC_NAL_RASL_N。
VPS、SPS、PPS:三者的结构和关系如下图所示:
2 H265码流RTP封装方式 其中RTP对H265裸流封装,与H264类似,分为单一NALU封装模式/组合帧封装模式/分片封装模式,以下分别进行介绍
2.1 单一帧封装模式 针对帧大小小于MTU的可采用单独一帧封装到一个RTP包中,封装格式如下:
其中PayloadHeader一般与NALU Header定义完全一致,DONL:Decoding Order Number。当使用多slice编码模式时使用,用于判断一帧的每个slice是否收齐,一般使用单slice,无此字段,所以通常境况下,单一帧模式封装方式与H264一致,H265帧去掉起始位直接作为负载,这里不做过多接收。
一些是截取的H265单一帧封装的RTP二进制数据:
从type中可以此帧为VPS采用rtp单一封装模式
2.2 组合帧封装方式 当帧较小,且多个帧合并后小于MTU的情况,可以多帧组合封装到一个RTP包中,比如(VPS/SPS/PPS)合并封装,注意多帧合并后大小必须小于MTU,不然会被IP分片,其格式如下:
PayloadHeader 负载头,与H264 NALUheader类似,有F,TYPE,LayerID,TID组成,一般F=0,LayerID=0,TID=1,这里Type必须为48,标识组合包头
不带DONL的组合包封装模式与H264类似,这里不做多说,一般情况下很少用到组合帧封装方式,小于MTU的帧一般是单一帧封装,减少解封装复杂性。
2.3 分片封装模式 当视频帧大于MTU,需要对帧进行分包发送,从而避免IP层分片,这里采用FU分片模式,格式如下:
这里PayloadHeader中F=0,LayerID=0,TID=1,Type必须为49表示FU分片
FU header定义与FU-A定义基本一致,由于NALU Type在H265中为6bits表示,所以这里去掉了R,只保留S/E/TYPE格式如下:
S:1bit,1-表示是首个分片报文,0-非首个分片报文 E:1bit,1-表示最后一个分片报文,0-非最后一个分片报文 FuType:6 bits,对应的NALU type 分片封包后的实例如下:
在流媒体传输领域,经常使用的传输协议是RTP/RTCP,本文将对RTP对H264进行封装的过程进行详解
1 H264基本概念 H264是一种视频压缩的标准,与H265、SVAC等压缩方式一样,主要目的是对视频流进行压缩,以便减少网络传输对网络带宽的占用,H264压缩后的帧类型分为I帧/P帧/B帧。
这里解释下帧类型:
I帧,为关键帧,采用帧内压缩技术,通过H264压缩算法解对完整帧数据进行压缩,因此I帧不依赖其前后帧数据,直接可以解压成raw数据
P帧,为向前参考帧,对raw帧压缩时,需要参考前面的I帧或P帧,采用帧间压缩技术,因此P帧解码不能单独解析,需要依赖前面的帧数据,如果其前面帧有丢失,会导致花屏。
B帧,为双向参考帧,对raw进行压缩时既参考前面的帧,又参考他后面的帧,采用帧间压缩技术,因此其解码是需要前面帧及后面帧同时参与。
在baseline编码规格下,无B帧,在main profile规格下一般有B帧,通常来说B帧参与编码会提高压缩率,降低帧大小,但是会增加编解码复杂性。
H264编码后的码流又NAL(网络抽象层)和VCL(视频编码层)构成,VCL数据传输或者存储之前,会被映射到一个NALU中,H264数据包含一个个的NALU,H.264的编码帧序列包括一系列的NAL单元,每个NAL单元包含一个RBSP,单元的信息头定义了RBSP单元的类型,NAL单元其余部分为RBSP数据,这里对NALU头字节进行i二少,因为RTP封装方式,主要针对NALU头进行处理。
2 NALU Header介绍 NALU头前通常包含一个 StartCode,StartCode 必须是 0x00000001 或者 0x000001,紧接着就是一个字节的nalu header,nalu header格式如下:
这里注意上面的0~7b不是字节内位的高低,只是表示占了多少位,从左到右顺序才表示从高位到低位,其详解如下:
F:forbidden_zero_bit,H264 规范要求该位为 0,占1位,其所在字节的最高位(第7位)
NRI:nal_ref_idc,取值 03,占2位,其在字节的56位,指示该 NALU 重要性,对于 NRI=0的NALU 解码器可以丢弃它而不影响解码,该值越大说明NALU越重要。如果当前NALU属于参考帧的数据,或者是序列参数集,图像参数集等重要信息,则该值必须大于0
Type:NALU 数据类型,占5 位,其在字节的0~4位,取值 0 ~ 31
有关Type在H264码流中的常用取值如下:
以下是截取的H264视频流的二进制数据,结合此二进制数据,我们来分析下其帧类型
0000000109,其中00000001是帧起始位标识,09是nalu header,二进制为00001001,F(7位)为0标识非禁止,NRI(56位)为0标识可丢弃帧,type(04位)为9,表示分隔符,此帧可丢弃,表示分隔符
0000000167,同上面的分析,NALU头为67,二进制为01100111,F=0,NRI=3,type=7,帧类型为SPS帧,非常重要不可丢弃
0000000168,NALU头为68,二进制为01101000,F=0,NRI=3,type=8,帧类型为PPS帧,非常重要不可丢弃
0000000106,NALU头为06,二进制为00000110,F=0,NRI=0,type=6,帧类型为SEI,可丢弃
0000000165,NALU头为65,二进制为01100101,F=0,NRI=3,type=5,帧类型为I帧,非常重要不可丢弃
从上上面的分析可以看出,IDR(SPS/PPS/I)帧通常一起出现,极少数编码单独出现I帧,但是IDR与I帧单独出现也符合规范。
如下为P帧的帧头,可按照上述方式进行解析。
3 RTP封装H264码流 由于H264帧大小差别较大,较小的帧小于MTU,则可单包直接发送,或者多帧组合发送,较大的帧大于MTU需要分片发送,RTP发送H264模式主要有三种:单一NALU模式、组合帧封装模式、分片封装模式,有关组合帧封包和分片封包类型包含好几种,这里介绍常用的两种:STAP-A和FU-A。
这里把RTP头格式先贴出来,具体参数详解看下RFC-3984,后面说明用到
3.1 单一NALU模式 此模式一个RTP包包含一个完整的视频帧,RTP头部之后的一个字节为 NALU Header,之后是NALU数据部分,此视频帧大小需要小于MTU,可以单帧通过网络发送,其RTP封装格式如下:
以SPS为例,SPS一般小于MTU,可采用单NALU封装模式,其封包后的二进制如下:
80 e0 be 8e 8c e8 56 d5 4a 9b 57 b3 67 64 00 29 ad 84 05 45 62 b8 ac 54 74 20 2a 2b 15 c5 62 a3 a1 01 51 58 ae 2b 15 1d 08 0a 8a c5 71 58 a8 e8 40 54 56 2b 8a c5 47 42 02 a2 b1 5c 56 2a 3a 10 24 85 21 39 3c 9f 27 e4 fe 4f c9 f2 79 b9 b3 4d 08 12 42 90 9c 9e 4f 93 f2 7f 27 e4 f9 3c dc d9 a6 b4 03 c0 11 3f 2c a9 00 00 03 00 78 00 00 15 90 60 40 00 3e 80 00 00 11 94 06 f7 be 17 84 42 35