02:H.264学习笔记
H.264组成
- 1、网络提取层 (Network Abstraction Layer,NAL)
- 2、视讯编码层 (Video Coding Layer,VCL)
- a.H.264/AVC影像格式阶层架构
- b.Slice的编码模式
(1) I -slice: slice的全部MB都采用intra-prediction的方式来编码;
(2) P-slice: slice中的MB使用intra-prediction和inter-prediction的方式来编码,但每一个inter-prediction block最多只能使用一个移动向量;
(3) B-slice:与P-slice类似,但每一个inter-prediction block可以使用二个移动向量。B-slice的‘B’是指Bi-predictive(双向预测),除了可由前一张和后一张影像的I(或P、B)-slice外,也能从前二张不同影像的I(或P、B)-slice来做inter- prediction。
(4) SP-slice:即所谓的Switching P slice,为P-slice的一种特殊类型,用来串接两个不同bitrate的bitstream;
(5) SI-slice: 即所谓的Switching I slice,为I-slice的一种特殊类型,除了用来串接两个不同content的bitstream外,也可用来执行随机存取(random access)来达到网络VCR的功能 - c、画面内预测技术(Intra-frame Prediction)
- d、画面间预测技术(Inter-frame Prediction)
码流结构
H.264的功能分为两层,视频编码层(VCL)和网络提取层(NAL)VCL数据即被压缩编码后的视频数据序列。在VCL数据要封装到NAL单元中之后,才可以用来传输或存储。

- SPS:序列参数集,作用于一系列连续的编码图像;
- PSS:图像参数集,作用于编码视频序列中一个或多个独立的图像;
参数集是一个独立的数据单位,不依赖于参数集外的其他句法元素。一个参数集不对应某一个特定的图像或序列,同一序列参数集可以被多个图像参数集引用,同理,同一个图像参数集也可以被多个图像引用。只在编码器认为需要更新参数集的内容时,才会发出新的参数集。
NALU根据nal_unit_type的类型,可以分为:VCL的NAL单元和非VCL的NAL单元,详情如下:


iOS与H.264
1、视频相关的框架
由上到下:
- AVKit
- AVFoundation
- Video Toolbox
- Core Media
- Core Video
其中的AVKit和AVFoudation、VideoToolbox都是使用硬编码和硬解码。
2、相关类介绍
- CVPixelBuffer: 包含未压缩的像素数据,包括图像宽度、高度等;
- CVPixelBufferPool: CVPixelBuffer的缓冲池,因为CVPixelBuffer的创建和销毁代价很大;
- pixelBufferAttributes: CFDictionary包括宽高、像素格式(RGBA、YUV)、使用场景(OpenGL ES、Core Animation)
- CMTime: 64位的value,32位的scale,media的时间格式;
- CMVideoFormatDescription: video的格式,包括宽高、颜色空间、编码格式等;对于H.264的视频,PPS和SPS的数据也在这里;
- CMBlockBuffer:未压缩的图像数据;
- CMSampleBuffer: 存放一个或者多个压缩或未压缩的媒体文件;
- CMClock:时间源
A timing source object.
- CMTimebase:时间控制器,可以设置rate和time;
A timebase represents a timeline that clients can control by setting the rate and time. Each timebase has either a master clock or a master timebase. The rate of the timebase is expressed relative to its master.
CMSampleBuffer的结构:

3、AVKit
使用AVSampleBufferDisplayLayer显示H.264码流

- 初始化
self.videoLayer = [[AVSampleBufferDisplayLayer alloc] init];
self.videoLayer.bounds = self.bounds;
self.videoLayer.position = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
self.videoLayer.videoGravity = AVLayerVideoGravityResizeAspect;
self.videoLayer.backgroundColor = [[UIColor greenColor] CGColor];
//set Timebase
CMTimebaseRef controlTimebase;
CMTimebaseCreateWithMasterClock( CFAllocatorGetDefault(), CMClockGetHostTimeClock(), &controlTimebase );
self.videoLayer.controlTimebase = controlTimebase;
CMTimebaseSetTime(self.videoLayer.controlTimebase, CMTimeMake(5, 1));
CMTimebaseSetRate(self.videoLayer.controlTimebase, 1.0);
// connecting the videolayer with the view
[[self layer] addSublayer:_videoLayer];
- 传入SampleBuffer
__block AVAssetReaderTrackOutput *outVideo = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:video outputSettings:dic];
if( [assetReaderVideo startReading] )
{
[_videoLayer requestMediaDataWhenReadyOnQueue: assetQueue usingBlock: ^{
while( [_videoLayer isReadyForMoreMediaData] )
{
CMSampleBufferRef *sampleVideo = [outVideo copyNextSampleBuffer];
[_videoLayer enqueueSampleBuffer:sampleVideo.data];
}
}];
}
4、MPEG-4封装的H.264码流格式
H.264的原始码流 与 MPEG-4封装的H.264码流格式不同在于:
- SPS和PPS被统一
需要用CMVideoFormatDescriptionCreateFromH264ParameterSets方法 ,统一PPS和SPS
头字节表示帧的长度
(原来的为00 00 01 或者 00 00 00 01)
当我们需要原始H.264码流包装成CMSampleBuffer时,我们可以按照以下步骤:
1、替换头字节长度;
2、用CMBlockBuffer把NALUnit包装起来;
3、把SPS和PPS包装成CMVideoFormatDescription;
4、添加CMTime时间;
5、创建CMSampleBuffer;

当我们需要更新SPS和PPS的时候,调用
VTDecompressionSessionCanAcceptFormatDescription判断是否能接受新的SPS和PPS;
如果不能接受,那么需要新建session来处理frame,注意销毁原来的session;

5、采集摄像头数据
从摄像头采集数据,并用AVAssetWriter写入movieFile

从摄像头采集数据,并VideoToolbox硬编码,获取压缩后的码流
- 按照显示顺序来,添加显示时间;
- 时间只能加不能减,不能重复;
- 异步的请求;(H.264的帧间预测)
- 没有帧之后需要调用complete;
压缩后的码流是MPEG-4封装格式下的码流,要转换成原始码流的格式。
调用CMVideoFormatDescriptionGetH264ParameterSetAtIndex
获取视频的PPS和SPS

6、Single-Pass和Multi-Pass编码
Single-Pass编码

Multi-Pass编码

AVAssetExportSession 优先采用多通道编码,不行再使用单通道编码;
Multi-passes的介绍
其他零碎的知识
视频码率是视频数据(视频色彩量、亮度量、像素量)每秒输出的位数。一般用的单位是kbps。
由于不同的系统会有不同的模式,为了统一,规定在网络传输中使用大端模式,这就是网络字节序。
RTP协议:实时传送协议(Real-time Transport Protocol或简写RTP,也可以写成RTTP)是一个网络传输协议。RTP协议详细说明了在互联网上传递音频和视频的标准数据包格式。
RTCP协议:实时传输控制协议(Real-time Transport Control Protocol或RTP Control Protocol或简写RTCP)是实时传输协议(RTP)的一个姐妹协议。
RTSP协议:RTSP(Real Time Streaming Protocol)是用来控制声音或影像的多媒体串流协议。
RTSP发起/终结流媒体、RTP传输流媒体数据 、RTCP对RTP进行控制,同步。
RTMP协议:RTMP(the Real-time Messaging Protocol)协议作为客户端和服务器端的传输协议,这是一个专门为高效传输视频、音频和数据而设计的 TCP/IP 协议。
HLS协议: HTTP Live Streaming(HLS)是苹果公司(Apple Inc.)实现的基于HTTP的流媒体传输协议。
总结
如果想更深入学习,可以看H.264标准中文版的文档。
链接:https://www.jianshu.com/p/8de09a551a66
02:H.264学习笔记的更多相关文章
- H.264学习笔记5——熵编码之CAVLC
H.264中,4x4的像素块经过变换和量化之后,低频信号集中在左上角,大量高频信号集中在右下角.左边的低频信号相对数值较大,而右下角的大量高频信号都被量化成0.1和-1:变换量化后的残差信息有一定的统 ...
- H.264学习笔记1——相关概念
此处记录学习AVC过程中的一些基本概念,不定时更新. frame:帧,相当于一幅图像,包含一个亮度矩阵和两个色度矩阵. field:场,一帧图像,通过隔行扫描得到奇偶两场,分别称为顶场和底场或奇场和偶 ...
- H.264学习笔记之一(层次结构,NAL,SPS)
一 H.264句法 1.1元素分层结构 H.264编码器输出的Bit流中,每个Bit都隶属于某个句法元素.句法元素被组织成有层次的结构,分别描述各个层次的信息. 图1 H.264分层结构由五层组成,分 ...
- H.264学习笔记
1.帧和场的概念 视频的一场或一帧可用来产生一个编码图像.通常,视频帧可以分成两种类型:连续或隔行视频帧.我们平常看的电视是每秒25帧,即每秒更换25个图像,由于视觉暂留效应,所以人眼不会感到闪烁.每 ...
- H.264学习笔记6——指数哥伦布编码
一.哥伦布码 哥伦布码就是将编码对象分能成等间隔的若干区间(Group),每个Group有一个索引值:Group Id. >对于Group Id采用二元码编码: >对于Group内的编码对 ...
- H.264学习笔记4——变换量化
A.变换量化过程总体介绍 经过帧内(16x16和4x4亮度.8x8色度)和帧间(4x4~16x16亮度.4x4~8x8色度)像素块预测之后,得到预测块的残差,为了压缩残差信息的统计冗余,需要对残差数据 ...
- H.264学习笔记3——帧间预测
帧间预测主要包括运动估计(运动搜索方法.运动估计准则.亚像素插值和运动矢量估计)和运动补偿. 对于H.264,是对16x16的亮度块和8x8的色度块进行帧间预测编码. A.树状结构分块 H.264的宏 ...
- H.264学习笔记2——帧内预测
帧内预测:根据经过反量化和反变换(没有进行去块效应)之后的同一条带内的块进行预测. A.4x4亮度块预测: 用到的像素和预测方向如图: a~f是4x4块中要预测的像素值,A~Q是临块中解码后的参考值. ...
- 每天进步一点点------H.264学习 (一)
分三个阶段学习1.第一个阶段: 学习H.264,首先要把最基本最必要的资料拿在手里.这些资料包括:标准文档+测试模型+经典文章,在本FTP中能找到.首先看 <H.264_MPEG-4 Part ...
随机推荐
- Python 命令行之旅 —— 深入 argparse (一)
作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...
- Seq[找规律]----2019 年百度之星·程序设计大赛 - 初赛一:1005
Seq Accepts: 1249 Submissions: 3956 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 ...
- python编辑已存在的excel坑: BadZipFile: File is not a zip file
背景-原代码如下,期望能自动创建excel,并且可以反复调用编辑: import xlwt,osfrom openpyxl.styles import Font, colors class Write ...
- 如何使用WorkManager执行后台任务(下)
0x00 WorkManager的高级用法 在上一文中已经了解到 WorkManager的基本用法之后,今天来看看它的一些高级用法: 链式任务调用 唯一任务序列 传递参数和获取返回值 0x01 链式任 ...
- .NET中的缓存
构建高性能的应用程序的非常重要一项就是使用缓存.使用缓存可以避免重新从读取服务器端读取数据,节省数据从客户端到服务器间往返的时间,同时也减轻了服务器数据存取的压力.如果客户端非常频繁地读取服务器上的数 ...
- poj3415_Common Substrings
题意 给定两个字符串,求长度大于等于k的公共子串数. 分析 将两个字符串中间加个特殊字符拼接,跑后缀数组. 将题目转化为对每一个后缀求\(\sum_{j=1}^{i-1}lcp(i,j)\),且后缀\ ...
- 如何运用PHP+REDIS解决负载均衡后的session共享问题
一.为什么要使用Session共享? 稍大一些的网站,通常都会有好几个服务器,每个服务器运行着不同功能的模块,使用不同的二级域名,而一个整体性强的网站,用户系统是统一的,即一套用户名.密码在整个网站的 ...
- Leetcode之回溯法专题-78. 子集(Subsets)
Leetcode之回溯法专题-78. 子集(Subsets) 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: nums = ...
- session一致性的解决方案
更多内容,欢迎关注微信公众号:全菜工程师小辉.公众号回复关键词,领取免费学习资料. 什么是session? 服务器为每个用户创建一个会话,存储用户的相关信息,以便多次请求能够定位到同一个上下文,这个相 ...
- POJ - 2516 Minimum Cost 每次要跑K次费用流
传送门:poj.org/problem?id=2516 题意: 有m个仓库,n个买家,k个商品,每个仓库运送不同商品到不同买家的路费是不同的.问为了满足不同买家的订单的最小的花费. 思路: 设立一个源 ...



