流媒体基础(视频编码/H264/RTP/RTSP/SDP)

目录

0、概述

1、视频编码

1.1 组织

1.2 视频编码原理

2、色彩空间

3、H264

3.1 基本概念

3.2 H264结构

4、视频文件格式、视频封装格式

5、RTSP

6、我的开源


 

0、概述

        本文介绍了视频编码原理、H264编码格式、RTP/RTSP/SDP,适合新手入门,从视频编码到rtsp实时流传输,帮助新手理解。

1、视频编码

        是指压缩编码。在计算机的世界中,一切都是0 和1 组成的,音视频的数据量庞大,如果按照裸流数据存储的话,那将需要耗费非常大的存储空间,也不利于传送。而音视频中,其实包含了大量0 和1 的重复数据,因此可以通过一定的算法来压缩这些0和1 的数据。特别在视频中,由于画面是逐渐过渡的,因此整个视频中,包含了大量画面/像素的重复,这正好提供了非常大的压缩空间。因此,编码可以大大减小音视频数据的大小,让音视频更容易存储和传送。

        那么,未经编码的原始音视频,数据量至底有多大?以一个分辨率1920×1280,帧率30 的视频为例:共:1920×1280=2,073,600(Pixels 像素),每个像素点是24bit;也就是:每幅图片2073600×24=49766400 bit,8 bit(位)=1 byte(字节);所以:49766400bit=6220800byte≈6.22MB。这是一幅1920×1280 图片的原始大小(6.22MB),再乘以帧率30。也就是说:每秒视频的大小是186.6MB,每分钟大约是11GB,一部90 分钟的电影,约是1000GB。

1.1 组织

        音视频编解码的国际标准

        ITU(国际电信联盟)

        ISO/IEC

        JVTJoint Video Team,视频联合工作组)

         1)ITU 提出了H.261H.262H.263H.263+H.263++,这些统称为H.26X 系列,主要应用于实时视频通信领域,如会议电视、可视电话等;

     2)ISO/IEC 提出了MPEG1MPEG2MPEG4MPEG7MPEG21,统称为MPEG系列。       

     3)ITU 和ISO/IEC 一开始是各自捣鼓,后来,两边成立了一个联合小组,名叫JVTJointVideo Team,视频联合工作组)。

1.2 视频编码原理

        原始视频压缩的目的是去除冗余信息,可以去除的冗余包括:

        空间冗余:图像相邻像素之间有较强的相关性

        时间冗余:视频序列的相邻图像之间内容相似

        编码冗余:不同像素值出现的概率不同

        视觉冗余:人的视觉系统对某些细节不敏感

        知识冗余:规律性的结构可由先验知识和背景知识得到

        视频编码技术优先消除的目标,就是空间冗余和时间冗余。

数据压缩是怎么分类的?

        无损压缩(Lossless):

        压缩前、解压缩后图像完全一致X=X',压缩比低(2:1~3:1)。典型格式例如:Winzip,JPEG-LS。

        有损压缩(Lossy):

        压缩前解压缩后图像不一致X≠X',压缩比高(10:1~20:1),利用人的视觉系统的特性。典型格式例如:MPEG-2,H.264/AVC,AVS。

        形象的比喻就是把每帧都作为一张图片,采用JPEG 的编码格式对图片进行压缩,这种编码只考虑了一张图片内的冗余信息压缩,如图1,绿色的部分就是当前待编码的区域,灰色就是尚未编码的区域,绿色区域可以根据已经编码的部分进行预测(绿色的左边,下边,左下等)。

        编码就是为了压缩。要实现压缩,就要设计各种算法,将视频数据中的冗余信息去除。

        举个例子:如果一幅图(1920×1080 分辨率),全是红色的,我有没有必要说2073600次[255,0,0]?我只要说一次[255,0,0],然后再说2073599 次“同上”。

        但是帧和帧之间因为时间的相关性,后续开发出了一些比较高级的编码器可以采用帧间编码,简单点说就是通过搜索算法选定了帧上的某些区域,然后通过计算当前帧和前后参考帧的向量差进行编码的一种形式,通过下面两个图2 连续帧我们可以看到,滑雪的同学是向前位移的,但实际上是雪景在向后位移,P 帧通过参考帧(I 或其他P 帧)就可以进行编码了,编码之后的大小非常小,压缩比非常高。

        如果一段1 分钟的视频,有十几秒画面是不动的,或者,有80%的图像面积,整个过程都是不变(不动)的。那么,是不是这块存储开销,就可以节约掉了?

        运动估计和补偿

        我们来通过一个例子看一下。

        这有两个帧:

        人在动,背景是没有动的。第一帧是I 帧,第二帧是P 帧。两个帧之间的差值,就是如下:

        也就是说,图中的部分像素,进行了移动。移动轨迹如下:

        这个,就是运动估计和补偿。

        视频编码过程如下:

2、色彩空间

        这里我们只讲常用到的两种色彩空间。

        1RGB:RGB 的颜色模式应该是我们最熟悉的一种,在现在的电子设备中应用广泛。通过R G B 三种基础色,可以混合出所有的颜色。

        2YUV:这里着重讲一下YUV,这种色彩空间并不是我们熟悉的。这是一种亮度与色度分离的色彩格式。早期的电视都是黑白的,即只有亮度值,即Y。有了彩色电视以后,加入了UV 两种色度,形成现在的YUV,也叫YCbCr。

        Y:亮度,就是灰度值。除了表示亮度信号外,还含有较多的绿色通道量;

        U:蓝色通道与亮度的差值;

        V:红色通道与亮度的差值。

        如下图,可以看到Y、V、U 3 个分量的效果差值:

        采用YUV 有什么优势呢?

        人眼对亮度敏感,对色度不敏感,因此减少部分UV 的数据量,人眼却无法感知出来,这样可以通过压缩UV 的分辨率,在不影响观感的前提下,减小视频的体积。

        视频通信系统之所以要采用YUV,而不是RGB,主要是因为RGB 信号不利于压缩。

        主流的采样方式有三种

        1YUV4:4:4;YCbcr

        2YUV4:2:2

        3YUV4:2:0

        如何理解帧和场图像?一帧图像包括两场——顶场,底场:

        逐行与隔行图像

        逐行图像是指:一帧图像的两场在同一时间得到,ttop=tbot

        隔行图像是指:一帧图像的两场在不同时间得到, ttop≠tbot

3、H264

3.1 基本概念

        IPB

        I 帧:帧内编码帧(intra picture),采用帧内压缩去掉空间冗余信息。

        P 帧:前向预测编码帧(predictive-frame),采用帧间编码(前向运动估计),同时利用空间和时间上的相关性。简单来说,采用运动补偿(motion compensation)算法来去掉冗余信息。参考前面的I 帧或者P 帧。

        B 帧:双向预测内插编码帧(bi-directional interpolated prediction frame),既考虑源图像序列前面的已编码帧,又顾及源图像序列后面的已编码帧之间的冗余信息,来压缩传输数据量的编码图像,也称为双向编码帧。参考前面一个的I 帧或者P 帧及其后面的一个P 帧。

        IDR 帧(关键帧):在编码解码中为了方便,将GOP 中首个I 帧要和其他I 帧区别开,把第一个I 帧叫IDR,这样方便控制编码和解码流程,所以IDR 帧一定是I 帧,但I 帧不一定是IDR 帧;IDR 帧的作用是立刻刷新,使错误不致传播,从IDR 帧开始算新的序列开始编码。I 帧有被跨帧参考的可能,IDR 不会。I 帧不用参考任何帧,但是之后的P 帧和B 帧是有可能参考这个I 帧之前的帧的

        PTS DTS

        DTS(Decoding Time Stamp)是标识读入内存中bit 流在什么时候开始送入解码器中进行解码。也就是解码顺序的时间戳。

        PTS(Presentation Time Stamp)用于度量解码后的视频帧什么时候被显示出来。在没有B 帧的情况下,DTS 和PTS 的输出顺序是一样的,一旦存在B 帧,PTS 和DTS 则会不同。也就是显示顺序的时间戳。

        GOP:即Group of picture(图像组),指两个I 帧之间的距离,Reference(参考周期)指两个P 帧之间的距离。一个I 帧所占用的字节数大于一个P 帧,一个P 帧所占用的字节数大于一个B 帧。所以在码率不变的前提下,GOP 值越大,P、B 帧的数量会越多,平均每个I、P、B 帧所占用的字节数就越多,也就更容易获取较好的图像质量;Reference 越大,B 帧的数量越多,同理也更容易获得较好的图像质量。

        简而言之:

        字节大小:I > P > B

        解码顺序:I -> P -> B

        “块(Block)”与“宏块(MacroBlock)”

        如果总是按照像素来算,数据量会比较大,所以,一般都是把图像切割为不同的“块(Block)”或“宏块(MacroBlock)”,对它们进行计算。一个宏块一般为16 像素×16 像素。

3.2 H264结构

        H264 压缩方式

        H264 采用的核心算法是帧内压缩和帧间压缩,帧内压缩是生成I 帧的算法,帧间压缩是生成B 帧和P 帧的算法。

        VCL 层是对核心算法引擎、块、宏块及片的语法级别的定义,负责有效表示视频数据的内容,最终输出编码完的数据SODB

        NAL 层定义了片级以上的语法级别(如序列参数集参数集和图像参数集,针对网络传输,后面会描述到),负责以网络所要求的恰当方式去格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传输。NAL 层将SODB 打包成RBSP 然后加上NAL 头组成一个NALU 单元,具体NAL 单元的组成也会在后面详细描述。

        SODB: 数据比特串,是编码后的原始数据;

        RBSP: 原始字节序列载荷,是在原始编码数据后面添加了结尾比特,一个bit“1”和若干个比特“0”,用于字节对齐

        NALU 的起始码为0x000001 或0x00000001(起始码包括两种:3 字节(0x000001)和4 字节(0x00000001),起始码用来分割NALU

        仿校验字节(0x03):

        H264 规定,当检测到0x000000 时,也可以表示当前NALU 的结束。那这样就会产生一个问题,就是如果在NALU 的内部,出现了0x000001 或0x000000时该怎么办?在RBSP 基础上填加了仿校验字节(0x03)它的原因是:需要填加每组NALU 之前的开始码StartCodePrefix,如果该NALU 对应的slice为一帧的开始则用4 位字节表示,0x00000001,否则用3 位字节表示0x000001.为了使NALU 主体中不包括与开始码相冲突的,在编码时,每遇到两个字节连续为0,就插入一个字节的0x03。解码时将0x03 去掉。也称为脱壳操作。

        想要完成准确无误视频的解码,除了需要VCL 层编码出来的视频帧数据,同时还需要传输序列参数集和图像参数集等等,所以RBSP 不单纯只保存I/B/P 帧的数据编码信息,还有其他信息也可能出现在里面。SPS、PPS、IDR 和SLICE 是NAL 单元某一类型的数据。

        NAL 单元是作为实际视频数据传输的基本单元,NALU 头是用来标识后面RBSP 是什么类型的数据,同时记录RBSP 数据是否会被其他帧参考以及网络传输是否有错误

        NAL 头

        NAL 单元的头部是由forbidden_bit(1bit)nal_reference_bit(2bits)(优先级),nal_unit_type(5bits)(类型)三个部分组成的,组成如图所示:

        1、F(forbiden):禁止位,占用NAL 头的第一个位,当禁止位值为1 时表示语法错误;

        2、NRI:参考级别,占用NAL 头的第二到第三个位;值越大,该NAL 越重要。

        3、Type:Nal 单元数据类型,也就是标识该NAL 单元的数据类型是哪种,占用NAL 头的第四到第8 个位;

        NAL 分为VCL 和非VCL NAL 单元。在图中有介绍(图表中DIR 应该为IDR),其中SPSSEIPPS 等非VCL 的NAL 参数对解码和显示视频都是很有用的。

        参数集(Parameter sets),参数集是携带解码参数的NAL 单元,参数集对于正确解码是非常重要的,在一个有损耗的传输场景中,传输过程中比特列或包可能丢失或损坏,在这种网络环境下,参数集可以通过高质量的服务来发送,比如向前纠错机制或优先级机制。Parameter sets 与其之外的句法元素之间的关系如下图所示:

        非VCL 的NAL 数据类型:

        1)、SPS(序列参数集):SPS 对如标识符、帧数以及参考帧数目、解码图像尺寸和帧场模式等解码参数进行标识记录。

        2)、PPS(图像参数集):PPS 对如熵编码类型、有效参考图像的数目和初始化等解码参数进行标志记录。

        3)、SEI(补充增强信息):这部分参数可作为H264 的比特流数据而被传输,每一个SEI信息被封装成一个NAL 单元。SEI 对于解码器来说可能是有用的,但是对于基本的解码过程来说,并不是必须的。

        序列参数集(spsNAL 单元必须在传送所有以此参数集为参考的其他NAL 单元之前传送,不过允许这些NAL 单元中间出现重复的序列参数集NAL 单元。所谓重复的详细解释为:序列参数集NAL 单元都有其专门的标识,如果两个序列参数集NAL 单元的标识相同,就可以认为后一个只不过是前一个的拷贝,而非新的序列参数集。

        图像参数集(pps)NAL 单元必须在所有以此参数集为参考的其他NAL 单元之前传送,不过允许这些NAL 单元中间出现重复的图像参数集NAL 单元,这一点与上述的序列参数集NAL 单元是相同

        VCL 的NAL 数据类型

        1)、头信息块,包括宏块类型,量化参数,运动矢量。这些信息是最重要的,因为离开他们,被的数据块种的码元都无法使用。该数据分块称为A 类数据分块。

        2)、帧内编码信息数据块,称为B 类数据分块。它包含帧内编码宏块类型,帧内编码系数。对应的slice 来说,B 类数据分块的可用性依赖于A 类数据分块。和帧间编码信息数据块不通的是,帧内编码信息能防止进一步的偏差,因此比帧间编码信息更重要。

        3)、帧间编码信息数据块,称为C 类数据分块。它包含帧间编码宏块类型,帧间编码系数。它通常是slice 种最大的一部分。帧间编码信息数据块是不重要的一部分。它所包含的信息并不提供编解码器之间的同步。C 类数据分块的可用性也依赖于A 类数据分块,但于B类数据分块无关。

以上三种数据块每种分割被单独的存放在一个NAL 单元中,因此可以被单独传输。

        H264 的NAL 单元与片,宏之间的联系

        1 帧(一幅图像) = 1~N 个片(slice) //也可以说1 到多个片为一个片组

        1 个片= 1~N 个宏块(Marcroblock)

        1 个宏块= 16X16 的YUV 数据(原始视频采集数据)

        同时有几点需要说明一下,这样能便于理解NAL 单元:

        (1)、如果不采用FMO(灵活宏块排序) 机制,则一幅图像只有一个片组;

        (2)、如果不使用多个片,则一个片组只有一个片;

        (3)、如果不采用DP(数据分割)机制,则一个片就是一个NALU,一个NALU 也就是一个片。否则,一个片的组成需要由三个NALU 组成,也就是上面说到的A、B、C 类数据块。

        下图是H264视频文件结构,每个NALU用起始码隔开:

4、视频文件格式、视频封装格式

        视频格式那么多,MP4/RMVB/MKV/AVI 等,这些视频格式与编码压缩标准mpeg4,H.264.H.265 等有什么关系?下面通过引入下面三个概念来介绍视频压缩知识。分别是:

        视频文件格式(简称:文件格式),

        视频封装格式(简称:视频格式),

        视频编码方式(简称:视频编码)

一,视频文件格式(简称:文件格式)

        我们知道Windows 系统中的文件名都有后缀,例如1.doc,2.wps,3.psd 等等。Windows 设置后缀名的目的是让系统中的应用程序来识别并关联这些文件,让相应的文件由相应的应用程序打开。例如你双击1.doc 文件,它会知道让Microsoft Office 去打开,而不会用Photoshop 去打开这个文件。所以常见的视频文件格式如1.avi,2.mpg 这些都叫做视频的文件格式,它由你电脑上安装的视频播放器关联。

二,视频封装格式(简称:视频格式):

        AVI,MPEG,VOB 是一种视频封装格式,相当于一种储存视频信息的容器。它是由相应的公司开发出来的。我们可以在自己的电脑上看到的1.avi,2.mpg,3.vob 这些视频文件格式的后缀名即采用相应的视频封装格式的名称。以下集中介绍几种封装格式:

        视频数据的封装

        封装:就是封装格式,简单来说,就是将已经编码压缩好的视频轨和音频轨按照一定的格式放到一个文件中。

三、视频编码方式

        H264就是视频编码格式,用来压缩原始视频的。

5、RTSP

RTSP单独出了一个系列

RTSP系列:

        RTSP系列一:RTSP协议介绍

        RTSP系列二:RTSP协议鉴权

        RTSP系列三:RTP协议介绍

        RTSP系列四:RTSP Server/Client实战项目 

6、我的开源

        我的开源:
        1、Nvidia视频硬解码、渲染、软/硬编码并写入MP4文件。项目地址:https://github.com/BreakingY/Nvidia-Video-Codec
        2、Jetson Jetpack5.x视频编解码。项目地址:https://github.com/BreakingY/jetpack-dec-enc
        3、音视频(H264/H265/AAC)封装、解封装、编解码pipeline,支持NVIDIA、昇腾DVPP硬编解码。项目地址:https://github.com/BreakingY/Media-Codec-Pipeline
        4、simple rtsp server,小而高效的rtsp服务器,支持H264、H265、AAC、PCMA;支持TCP、UDP;支持鉴权。项目地址:https://github.com/BreakingY/simple-rtsp-server

        5、simple rtsp client,rtsp客户端,支持TCP、UDP、H264、H265、AAC、PCMA,支持鉴权。项目地址:https://github.com/BreakingY/simple-rtsp-client

        6、libflv,flv muxer/demuxer,支持H264/H265、AAC。地址:https://github.com/BreakingY/libflv

        7、mpeg2 ts ps muxer/demuxer,支持H264/H265/MPEG1 audio/MP3/AAC/AAC_LATM/G711。项目地址:https://github.com/BreakingY/libmpeg2core

 

posted @   BreakingY  阅读(53)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示