【秒懂音视频开发】23_H.264编码
本文主要介绍一种非常流行的视频编码:H.264。
计算一下:10秒钟1080p(1920x1080)、30fps的YUV420P原始视频,需要占用多大的存储空间?
- (10 * 30) * (1920 * 1080) * 1.5 = 933120000字节 ≈ 889.89MB
- 可以看得出来,原始视频的体积是非常巨大的
由于网络带宽和硬盘存储空间都是非常有限的,因此,需要先使用视频编码技术(比如H.264编码)对原始视频进行压缩,然后再进行存储和分发。H.264编码的压缩比可以达到至少是100:1。
简介
H.264,又称为MPEG-4 Part 10,Advanced Video Coding。
- 译为:MPEG-4第10部分,高级视频编码
- 简称:MPEG-4 AVC
H.264是迄今为止视频录制、压缩和分发的最常用格式。截至2019年9月,已有91%的视频开发人员使用了该格式。H.264提供了明显优于以前任何标准的压缩性能。H.264因其是蓝光盘的其中一种编解码标准而著名,所有蓝光盘播放器都必须能解码H.264。
编码器
H.264标准允许制造厂商自由地开发具有竞争力的创新产品,它并没有定义一个编码器,而是定义了编码器应该产生的输出码流。
x264是一款免费的高性能的H.264开源编码器。x264编码器在FFmpeg中的名称是libx264。
AVCodec *codec = avcodec_find_encoder_by_name("libx264");
解码器
H.264标准中定义了一个解码方法,但是制造厂商可以自由地开发可选的具有竞争力的、新的解码器,前提是他们能够获得与标准中采用的方法同样的结果。
FFmpeg默认已经内置了一个H.264的解码器,名称是h264。
AVCodec *codec1 = avcodec_find_decoder_by_name("h264");
// 或者
AVCodec *codec2 = avcodec_find_decoder(AV_CODEC_ID_H264);
编码过程与原理
H.264的编程过程比较复杂,本文只介绍大体的框架和脉络,具体细节就不展开了。
大体可以归纳为以下几个主要步骤:
- 划分帧类型
- 帧内/帧间编码
- 变换 + 量化
- 滤波
- 熵编码
划分帧类型
有统计结果表明:在连续的几帧图像中,一般只有10%以内的像素有差别,亮度的差值变化不超过2%,而色度的差值变化只在1%以内。
GOP
于是可以将一串连续的相似的帧归到一个图像群组(Group Of Pictures,GOP)。
GOP中的帧可以分为3种类型:
- I帧(I Picture、I Frame、Intra Coded Picture),译为:帧内编码图像,也叫做关键帧(Keyframe)
- 是视频的第一帧,也是GOP的第一帧,一个GOP只有一个I帧
- 编码
- 对整帧图像数据进行编码
- 解码
- 仅用当前I帧的编码数据就可以解码出完整的图像
- 是一种自带全部信息的独立帧,无需参考其他图像便可独立进行解码,可以简单理解为一张静态图像
- P帧(I Picture、I Frame、Predictive Coded Picture),译为:预测编码图像
- 编码
- 并不会对整帧图像数据进行编码
- 以前面的I帧或P帧作为参考帧,只编码当前P帧与参考帧的差异数据
- 解码
- 需要先解码出前面的参考帧,再结合差异数据解码出当前P帧完整的图像
- 编码
- B帧(B Picture、B Frame、Bipredictive Coded Picture),译为:前后预测编码图像
- 编码
- 并不会对整帧图像数据进行编码
- 同时以前面、后面的I帧或P帧作为参考帧,只编码当前B帧与前后参考帧的差异数据
- 因为可参考的帧变多了,所以只需要存储更少的差异数据
- 解码
- 需要先解码出前后的参考帧,再结合差异数据解码出当前B帧完整的图像
- 编码
不难看出,编码后的数据大小:I帧 > P帧 > B帧。
在较早的视频编码标准(例如MPEG-2)中,P帧只能使用一个参考帧,而一些现代视频编码标准(比如H.264),允许使用多个参考帧。
GOP的长度
GOP的长度表示GOP的帧数。GOP的长度需要控制在合理范围,以平衡视频质量、视频大小(网络带宽)和seek效果(拖动、快进的响应速度)等。
加大GOP长度有利于减小视频文件大小,但也不宜设置过大,太大则会导致GOP后部帧的画面失真,影响视频质量
由于P、B帧的复杂度大于I帧,GOP值过大,过多的P、B帧会影响编码效率,使编码效率降低
如果设置过小的GOP值,视频文件会比较大,则需要提高视频的输出码率,以确保画面质量不会降低,故会增加网络带宽
GOP长度也是影响视频seek响应速度的关键因素,seek时播放器需要定位到离指定位置最近的前一个I帧,如果GOP太大意味着距离指定位置可能越远(需要解码的参考帧就越多)、seek响应的时间(缓冲时间)也越长
GOP的类型
GOP又可以分为开放(Open)、封闭(Closed)两种。
- Open
- 前一个GOP的B帧可以参考下一个GOP的I帧
- Closed
- 前一个GOP的B帧不能参考下一个GOP的I帧
- GOP不能以B帧结尾
需要注意的是:
由于P帧、B帧都对前面的参考帧(P帧、I帧)有依赖性,因此,一旦前面的参考帧出现数据错误,就会导致后面的P帧、B帧也出现数据错误,而且这种错误还会继续向后传播
对于普通的I帧,其后的P帧和B帧可以参考该普通I帧之前的其他I帧
在Closed GOP中,有一种特殊的I帧,叫做IDR帧(Instantaneous Decoder Refresh,译为:即时解码刷新)。
- 当遇到IDR帧时,会清空参考帧队列
- 如果前一个序列出现重大错误,在这里可以获得重新同步的机会,使错误不会继续往下传播
- 一个IDR帧之后的所有帧,永远都不会参考该IDR帧之前的帧
- 视频播放时,播放器一般都支持随机seek(拖动)到指定位置,而播放器直接选择到指定位置附近的IDR帧进行播放最为便捷,因为可以明确知道该IDR帧之后的所有帧都不会参考其之前的其他I帧,从而避免较为复杂的反向解析
帧内/帧间编码
I帧采用的是帧内(Intra Frame)编码,处理的是空间冗余。
P帧、B帧采用的是帧间(Inter Frame)编码,处理的是时间冗余。
划分宏块
在进行编码之前,首先要将一张完整的帧切割成多个宏块(Macroblock),H.264中的宏块大小通常是16x16。
宏块可以进一步拆分为多个更小的变换块(Transform blocks)、预测块(Prediction blocks)。
变换块的尺寸有:16x16、8x8、4x4
预测块的尺寸有:16×16、16×8、8×16、8×8、8×4、4×8、4×4
帧内编码
帧内编码,也称帧内预测。以4x4的预测块为例,共有9种可选的预测模式。
利用帧内预测技术,可以得到预测帧,最终只需要保留预测模式信息、以及预测帧与原始帧的残差值。
编码器会选取最佳预测模式,使预测帧更加接近原始帧,减少相互间的差异,提高编码的压缩效率。
帧间编码
帧间编码,也称帧间预测,用到了运动补偿(Motion compensation)技术。
编码器利用块匹配算法,尝试在先前已编码的帧(称为参考帧)上搜索与正在编码的块相似的块。如果编码器搜索成功,则可以使用称为运动矢量的向量对块进行编码,该向量指向匹配块在参考帧处的位置。
在大多数情况下,编码器将成功执行,但是找到的块可能与它正在编码的块不完全匹配。这就是编码器将计算它们之间差异的原因。这些残差值称为预测误差,需要进行变换并将其发送给解码器。
综上所述,如果编码器在参考帧上成功找到匹配块,它将获得指向匹配块的运动矢量和预测误差。使用这两个元素,解码器将能够恢复该块的原始像素。
如果一切顺利,该算法将能够找到一个几乎没有预测误差的匹配块,因此,一旦进行变换,运动矢量加上预测误差的总大小将小于原始编码的大小。
如果块匹配算法未能找到合适的匹配,则预测误差将是可观的。因此,运动矢量的总大小加上预测误差将大于原始编码。在这种情况下,编码器将产生异常,并为该特定块发送原始编码。
变换与量化
接下来对残差值进行DCT变换(Discrete Cosine Transform,译为离散余弦变换)。
规格
H.264的主要规格有:
- Baseline Profile(BP)
- 支持I/P帧,只支持无交错(Progressive)和CAVLC
- 一般用于低阶或需要额外容错的应用,比如视频通话、手机视频等即时通信领域
- Extended Profile(XP)
- 在Baseline的基础上增加了额外的功能,支持流之间的切换,改进误码性能
- 支持I/P/B/SP/SI帧,只支持无交错(Progressive)和CAVLC
- 适合于视频流在网络上的传输场合,比如视频点播
- Main Profile(MP)
- 提供I/P/B帧,支持无交错(Progressive)和交错(Interlaced),支持CAVLC和CABAC
- 用于主流消费类电子产品规格如低解码(相对而言)的MP4、便携的视频播放器、PSP和iPod等
- High Profile(HiP)
- 最常用的规格
- 在Main的基础上增加了8x8内部预测、自定义量化、无损视频编码和更多的YUV格式(如4:4:4)
- High 4:2:2 Profile(Hi422P)
- High 4:4:4 Predictive Profile(Hi444PP)
- High 4:2:2 Intra Profile
- High 4:4:4 Intra Profile
- 用于广播及视频碟片存储(蓝光影片),高清电视的应用
【秒懂音视频开发】23_H.264编码的更多相关文章
- 【秒懂音视频开发】14_AAC编码
AAC(Advanced Audio Coding,译为:高级音频编码),是由Fraunhofer IIS.杜比实验室.AT&T.Sony.Nokia等公司共同开发的有损音频编码和文件格式. ...
- 【秒懂音视频开发】02_Windows开发环境搭建
音视频开发库的选择 每个主流平台基本都有自己的音视频开发库(API),用以处理音视频数据,比如: iOS:AVFoundation.AudioUnit等 Android:MediaPlayer.Med ...
- 【秒懂音视频开发】26_RTMP服务器搭建
从本节开始,正式开启流媒体相关的内容. 流媒体 基本概念 流媒体(Streaming media),也叫做:流式媒体. 是指将一连串的多媒体数据压缩后,经过互联网分段发送数据,在互联网上即时传输影音以 ...
- 【秒懂音视频开发】18_详解YUV
本文的主角是多媒体领域非常重要的一个概念:YUV. 简介 YUV,是一种颜色编码方法,跟RGB是同一个级别的概念,广泛应用于多媒体领域中. 也就是说,图像中每1个像素的颜色信息,除了可以用RGB的方式 ...
- 【秒懂音视频开发】05_Qt开发基础
控件的基本使用 为了更好地学习Qt控件的使用,建议创建项目时先不要生成ui文件. 打开mainwindow.cpp,在MainWindow的构造函数中编写界面的初始化代码. 窗口设置 MainWind ...
- 【秒懂音视频开发】12_播放WAV
对于WAV文件来说,可以直接使用ffplay命令播放,而且不用像PCM那样增加额外的参数.因为WAV的文件头中已经包含了相关的音频参数信息. ffplay in.wav 接下来演示一下如何使用SDL播 ...
- 【秒懂音视频开发】21_显示BMP图片
文本的主要内容是:使用SDL显示一张BMP图片,算是为后面的<播放YUV>做准备. 为什么是显示BMP图片?而不是显示JPG或PNG图片? 因为SDL内置了加载BMP的API,使用起来会更 ...
- Android IOS WebRTC 音视频开发总结(八十五)-- 使用WebRTC广播网络摄像头视频(下)
本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...
- WebRTC 音视频开发
WebRTC 音视频开发 webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译 ...
随机推荐
- SqlServer存储过程的创建与使用
什么是存储过程? T-SQL中的存储过程,非常类似于net语言中的方法,它可以重复调用.当存储过程执行一次后,可以将语句缓存中,这样下次执行的时候直接使用缓存中的语句. 这样就可以提高存储过程的性能. ...
- 前端常见的请求数据汇总(GET POST)
前端在请求接口的时候要和后端人员配合好,根据后端提供的接口文档来进行开发,一般请求类型有这几种 1.GET请求 GET请求一般会将数据放到URL后 GET请求对所发信息量的限制是2000个字符 GET ...
- ss 命令简介
1. 简介 ss 使用 netlink 与内核 tcp_diag 模块通信获取 socket 信息,用法和输出结果类似于 netstat 命令 语法格式如下 ss [options] [ FILTER ...
- Linux常用命令-基础部分
Linux介绍 Linux是一款开源的操作系统,免费,开源,安全,高效,处理高并发非常强悍,很多企业级开发项目都部署在Linux/UNIX上. 创始人:Linus Torvalds 林纳斯 Linux ...
- 北航OO第二单元作业总结(2.1~2.3)
在经过第一单元初步认识面向对象编程思想后,本蒟蒻开始了第二单元--多线程部分的学习.本单元的作业是构造符合条件的"目的选层电梯"模型,自行设计调度算法,进行合理调度,完成所有乘客的 ...
- 【剑指offer】7:斐波那契数列
题目描述: 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1).假设 n≤39 解题思路: 斐波拉契数列:1,1,2,3,5,8--,总结 ...
- Mysql 添加 create_time, update_time 创建时间 更新时间 自动更新
# 添加 创建 更新 时间字段 ALTER TABLE `表名` ADD COLUMN `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTA ...
- HashMap、ConcurrentHashMap 1.7和1.8对比
本篇内容是学习的记录,可能会有所不足. 一:JDK1.7中的HashMap JDK1.7的hashMap是由数组 + 链表组成 /** 1 << 4,表示1,左移4位,变成10000,即1 ...
- Manachar's Algorithm
1.模板 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAX=21000020; 4 char s[MAX], ...
- TP5 验证-内置规则
系统内置的验证规则如下: 格式验证类 require 验证某个字段必须,例如: 'name'=>'require' number 或者 integer 验证某个字段的值是否为数字(采用filte ...