h.264的编码过程
H264编码原理详解

H264编码原理详解前言•在日常生活中我们知道,电脑中的视频文件先要通过视频采集设备对物体进行采集,然后通过编码核心部件得到mp4,rmvb等格式进行保存。
有没有可能不经过上述核心编码部件采集之后直接进行显示呢?答案是可以的。
那为什么还要进行编码呢?答案是原始采集到的视频数据为YUV格式,这种格式不经过处理的话特别大,对于网络传输和永久保存非常不利,为了解决这个问题,就需要对原原始的视频数据进行压缩处理。
而H264则是目前一种流传广泛,成熟的视频压缩算法。
•先来看一个例子在学习H.264编码之前,我们先了解一下在手机相机拍摄视频的过程,如果Camera采集的YUV图像不做任何处理进行传输,那么每秒钟需要传输的数据量是多少?Camera采集的YUV图像通常为YUV420,根据YUV420的采样结构,YUV图像中的一个像素中Y、U、V分量所占比例为1:1/4:1/4,而一个Y分量占1个字节,也就是说对于YUV图像,它的一个像素的大小为(1+1/4+1/4)Y=3/2个字节。
如果直播时的帧率设置为30fps,当分辨率为1280x720,那么每秒需要传输的数据量为1280720(像素)30(帧)3/2(字节)=39.5MB;当分辨率为1920x720,那么每秒需要传输的数据量接近60MB,这对于手机的存储空间有很大考验,因此,我们就必须在拍摄形成视频文件保存在本地之前对采集的视频数据进行压缩编码。
H26X简介H261•目前国际上制定视频编解码技术的组织有两个,一个是“国际电联(ITU-T)”,它制定的标准有H.261、H.263、H.263+等,另一个是“国际标准化组织(ISO)”它制定的标准有MPEG-1、MPEG-2、MPEG-4等。
•H.261是1990年ITU-T制定的一个视频编码标准,属于视频编解码器。
设计的目的是能够在带宽为64kbps的倍数的综合业务数字网(ISDN forIntegrated Services Digital Network)上质量可接受的视频信号。
H.264编码流程图

•编码器的核心是基于运动补偿预测(motion compensated prediction, MCP)。
有两条数据通道:前向通道和重建通道。
在前向通道中,编码器的输入是帧Fn,每帧画面是以16×16像素大小的宏块为单位组成的,每个宏块分别进行帧内或帧间预测编码。
在图中,帧间预测的参考帧被限定为前一帧Fn’,但是实际上,参考帧的数量可以多达五帧。
•当前宏块减去其预测值P得到残差宏块Dn,Dn经过块变换和量化得到量化系数X,对量化变换系数进行重排序和熵编码,得到的系数以及一些用于解码的附加信息(例如宏块预测模式、量化步长、运动矢量信息等)经由网络抽象层NAL (network abstraction layer)进行传输和存储。
•在重建通道中,宏块量化系数X被解码,用于构建重建帧(用于做预测)。
如图所示,系数被反量化、反变换后,产生差值宏块Dn’(由于量化过程引入误差,Dn’与先前的Dn并不一致)。
预测宏块P与Dn’相加构成重建宏块uFn’。
再引入滤波器减小块效应失真,得到重建的Fn’。
在编码器中引入重建通道的目的是为了使编码器和解码器使用相同的参考帧来构成预测宏块P,否则,预测宏块P在编码器和解码器中将不一致,这将造成误差积累或编解码器间的“漂移(drifting)”。
H.264 NAL层解析(0x00000001,编码,打包,NALU)

1.将VCL层输出的SODB封装成nal_unit,Nal_unit是一个通用封装格式,可以适用于有序字节流方式和IP包交换方式。
2.针对不同的传送网络(电路交换|包交换),将nal_unit 封装成针对不同网络的封装格式。
第一步的具体过程:
VCL层输出的比特流SODB(String Of Data Bits),到nal_unit之间,经过了以下三步处理:
20:编码片段扩展
21 – 23:保留
24 – 31:未规定
3.H.264的NAL层处理
结构示意图:
NAL以NALU(NAL unit)为单元来支持编码数据在基于分组交换技术网络中传输。它定义了符合传输层或存储介质要求的数据格式,同时给出头信息,从而提供了视频编码和外部世界的接口。
NALU:定义了可用于基于分组和基于比特流系统的基本格式
(1)NALU的分块以按RTP次序号升序传输;
(2)能够标记第一个和最后一个NALU分块;
(3)可以检测丢失的分块。
NALU合并
一些NALU如SEI、参数集等非常小,将它们合并在一起有利于减少头标开销。已有两种集合分组:
(1)单一时间集合分组(STAP),按时间戳进行组合;
(2)多时间集合分组(MTAP),不同时间戳也可以组合。
具体方法:
nal_unit( NumBytesInNALunit ) {
forbidden_zero_bit
nal_ref_idc
nal_unit_type
NumBytesInRBSP = 0
for( i = 1; i < NumBytesInNALunit; i++ ) {
if( i + 2 < NumBytesInNALunit && next_bits( 24 ) = = 0x000003 ) {
【知识点】H264,H265硬件编解码基础及码流分析

【知识点】H264,H265硬件编解码基础及码流分析前⾔⾳视频开发需要你懂得⾳视频中⼀些基本概念,针对编解码⽽⾔,我们必须提前懂得编解码器的⼀些特性,码流的结构,码流中⼀些重要信息如sps,pps,vps,start code以及基本的⼯作原理,⽽⼤多同学都只是⼀知半解,所以导致代码中的部分内容虽可以简单理解却不知其意,所以,在这⾥总结出了当前主流的H.264,H.265编码相关的原理,以供学习.1. 概览1.1. 为什么要编码众所周知,视频数据原始体积是巨⼤的,以720P 30fps的视频为例,⼀个像素⼤约3个字节,如下所得,每秒钟产⽣87MB,这样计算可得⼀分钟就将产⽣5.22GB。
数据量/每秒=1280*720*33*3/1024/1024=87MB因此,像这样体积重⼤的视频是⽆法在⽹络中直接传输的.⽽视频编码技术也就因运⽽⽣.关于视频编码原理的技术可以参考本⼈其他⽂章,这⾥不做过多描述.1.2. 编码技术经过很多年的开发迭代,已经有很多⼤⽜实现了视频编码技术,其中最主流的有H.264编码,以及新⼀代的H.265编码,⾕歌也开发了VP8,VP9编码技术.对移动端⽽⾔,苹果内部已经实现了如H.264,H.265编码,我们需要使⽤苹果提供的VideoToolbox框架来实现它.1.3. 编码分类软件编码(简称软编):使⽤CPU进⾏编码。
硬件编码(简称硬编):不使⽤CPU进⾏编码,使⽤显卡GPU,专⽤的DSP、FPGA、ASIC芯⽚等硬件进⾏编码。
优缺点软编:实现直接、简单,参数调整⽅便,升级易,但CPU负载重,性能较硬编码低,低码率下质量通常⽐硬编码要好⼀点。
硬编:性能⾼,低码率下通常质量低于硬编码器,但部分产品在GPU硬件平台移植了优秀的软编码算法(如X264)的,质量基本等同于软编码。
iOS系统中的硬编码苹果在iOS 8.0系统之前,没有开放系统的硬件编码解码功能,不过Mac OS系统⼀直有,被称为Video ToolBox的框架来处理硬件的编码和解码,终于在iOS 8.0后,苹果将该框架引⼊iOS系统。
H264熵编码具体算法

CAVLC即基于上下文的自适应变长编码。CAVLC的本 质是变长编码,它的特性主要体现在自适应能力上, CAVLC可以根据已编码句法元素的情况动态的选择编码中 使用的码表,并且随时更新拖尾系数后缀的长度,从而获 得极高的压缩比。H.264标准中使用了CAVLC对4*4模块的 亮度和色度残差数据进行编码。
解析除拖尾系数外的非零系数的幅值level1确定后缀长度suffixlength2根据码流查表96得到前缀levelprefix3根据前缀和后缀得到levelcodelevelprefixsuffixlengthlevelsuffix4levelcode为偶数levellevelcode22levelcode为奇数levellevelcode125根据设定的阈值确定是否updatesuffixlegth6cavlc与uvlc比较在相同码率的情况下用cavlc编码的psnr的值高于用uvlc编码的psnr的值并且随着比特率的增加cavlc的优势更加明显h264avc68cavlc基于上下文自适应的可变长编码69cabac基于上下文的自适应二进制算术熵编码610码率控制611去方块滤波612其余特征cabac1
∴经查表可知码流为0000100 ∴code=0000100
4.3 编码每个拖尾系数的符号 对于每个拖尾系数(±1)只需要指明其符号,
其符号用一个比特表示(0表示+ ,1表示-)。编 码的顺序是按照反向扫描的顺序,从高频数据 开始。 例:设有一个4*4块数据(假定NC=0)
0 3 -1 0
0 -1 1 0
0 3 -1 0 0 -1 1 0
1000
0000 ∴TotalZeros=3 又∵TotalCoeffs(非零系数的数目)=5 ∴查表可得码流为111 ∴code=0000100 011 1 0010 111
X.264,H.264,divX等编码标准介绍

【基本定义】x264是一种免费的、具有更优秀算法的H.264/MPEG-4 AVC视频压缩编码格式。
它同xvid一样都是开源项目,但x264是采用H.264标准的,而xvid是采用MP EG-4早期标准的。
由于H.264是2003年正式发布的最新的视频编码标准,因此,在通常情况下,x264压缩出的视频文件在相同质量下要比xvid压缩出的文件要小,或者也可以说,在相同体积下比xvid压缩出的文件质量要好。
它符合GPL许可证。
[编辑本段]【X.264起源】X.264起源于H.264技术,是H.264的的变种版本。
与H.264相比,X.264是针对业余市场推出的一个免费编码格式,是H.264的子集,只能能实现H.264的部分功能。
X.264多见于网络上流传的重压缩的视频内容[编辑本段]【X.264特点】特点:日前,x264是最新的AVC编码格式之一。
■ 采用CAVLC/CABAC多种算法编码■ 内置所有macroblock格式(16x16, 8x8, and 4x4 )X.264界面■ Inter P:所有的分割块(从16x16到4x4 )■ Inter B:分割块从16x16到8x8■ 码率控制:恒定的分层编制,单次或多次的ABR压制,可选的VBV压制■ 场景剪切侦测■ 支持B-frame■ 能够任意编制B-frame命令行■ 无损模式■ 8x8和4x4的格式能够进行翻转或旋转■ 自定义精确的矩阵模板■ 可在多个CPU平行编码■ 隔行扫描[编辑本段]【技术区别】x264x264是一个基于h.264的免费开源的视频Codec,属于后起之秀,已经受到众多Riper的青睐,但是与Xvid相比,其在解码时对硬件的要求更高。
H.264H.264是由国际电信联盟(ITU-T)所制定的新一代的视频压缩格式。
H.264最具价值的部分无疑是更高的数据压缩比。
在同等的图像质量条件下,H.264的数据压缩比能比当前DVD系统中使用的MPEG-2高2-3倍,比MPEG-4高1.5-2倍。
H.264视频编码介绍资料

H.264解码器
H.264采用的新技术
• H.264标准中诸如帧间预测、变换、量化、熵编码等基本功能模块与 前几个标准(MPEG-1, MPEG-2, MPEG-4, H.261, H.263)并无太大 • • • • • • • 区别,变化主要体现在功能模块的具体细节上。 分层设计 帧间预测编码 帧内预测编码 整数变换 量化处理 熵编码 环路滤波
TTS图解
• 如图所示,搜索步骤如下:
– 第一步:从搜索起点开始,以最大搜索 长度的一半为步长,在周围距离步长的 8个点处进行块匹配计算并比较,图中 用正方形表示,1号为该次搜索最优点。 – 第二步:将步长减半,中心点移到上一 步的最小匹配点,重新在周围距离步长 的8个点处进行块匹配计算并比较,图 中用圆形表示,2号为该次搜索最优点。 – 第三步:在上一步得到的最小匹配点的 中心及周围8个点处找出最匹配点,该 点即为所求,图中用菱形表示,3号为 该次搜索最优点
块的搜索与匹配
• 搜索起点的选择很重要。 • 块搜索算法:
①全搜索法FS ②三步搜索法TTS ③菱形搜索法DS ④六边形搜索法 注:有不少对上述方法的改进及新方法。
• 块匹配准则:
①最小绝对差MAD ②最小均方误差MSE ③归一化互相关函数NCCF ④求和绝对误差SAD
H.264视频编码基本知识

H.264视频编码基本知识一、视频编码技术的发展历程视频编码技术基本是由ISO/IEC制定的MPEG-x和ITU-T制定的H.26x两大系列视频编码国际标准的推出。
从H.261视频编码建议,到H.262/3、MPEG-1/2/4等都有一个共同的不断追求的目标,即在尽可能低的码率(或存储容量)下获得尽可能好的图像质量。
而且,随着市场对图像传输需求的增加,如何适应不同信道传输特性的问题也日益显现出来。
于是IEO/IEC和ITU-T两大国际标准化组织联手制定了视频新标准H.264来解决这些问题。
H.261是最早出现的视频编码建议,目的是规范ISDN网上的会议电视和可视电话应用中的视频编码技术。
它采用的算法结合了可减少时间冗余的帧间预测和可减少空间冗余的DCT变换的混合编码方法。
和ISDN信道相匹配,其输出码率是p×64kbit/s。
p取值较小时,只能传清晰度不太高的图像,适合于面对面的电视电话;p取值较大时(如p>6),可以传输清晰度较好的会议电视图像。
H.263 建议的是低码率图像压缩标准,在技术上是H.261的改进和扩充,支持码率小于64kbit/s的应用。
但实质上H.263以及后来的H.263+和H.263++已发展成支持全码率应用的建议,从它支持众多的图像格式这一点就可看出,如Sub-QCIF、QCIF、CIF、4CIF甚至16CIF等格式。
MPEG-1标准的码率为1.2Mbit/s左右,可提供30帧CIF(352×288)质量的图像,是为CD-ROM光盘的视频存储和播放所制定的。
MPEG-l标准视频编码部分的基本算法与H.261/H.263相似,也采用运动补偿的帧间预测、二维DCT、VLC游程编码等措施。
此外还引入了帧内帧(I)、预测帧(P)、双向预测帧(B)和直流帧(D)等概念,进一步提高了编码效率。
在MPEG-1的基础上,MPEG-2标准在提高图像分辨率、兼容数字电视等方面做了一些改进,例如它的运动矢量的精度为半像素;在编码运算中(如运动估计和DCT)区分"帧"和"场";引入了编码的可分级性技术,如空间可分级性、时间可分级性和信噪比可分级性等。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
H.264编码算法的实现
在H.264编码具体实现过程中,采用了目前国际上应用最广泛的开源编码器X.264作为实现的基础。
X.264和JM系列编码器、T.264编码器相比有着优秀的性能和出色效果。
由于X.264没有提供直接的开发API,所以在本系统中的编码部分重新封装了X.264的编码API,便于软件系统的设计和使用。
以下是本系统中H.264编码的具体实现过程:
1) RGB和YUV颜色空间的转换
在系统中通过Logitech摄像头获得的视频数据为RGB24格式,但是X.264的输入流为标准的YUV(4:2:0)的图像子采样格式。
因此,在编码前需要将RGB颜色空间转换为YUV的颜色空间。
实现的函数调用有InitLookupTable()用于初始化色彩空间转换;
RGB2YUV420(int x_dim, int y_dim, unsigned char *bmp, unsigned char *yuv, int flip);用于实际的转换。
由于人眼的生理特性,经过图像子采样后,实际的图像大小已经减小为采样前的1.5个样本点,即减小了一半的数据量。
2) 设置H.264编码参数
使用x264_param_default(x264_param_t *param)对当前需要编码的图像参数进行设置。
包括数据帧数量(param .i_frame_total)、采样图像的长宽度和高度(param .i_width,param .i_height)、视频数据比特率(param .rc.i_bitrate) 、视频数据帧率(param .i_fps_num)等参数进行设置,以完成编码前预设置。
3) 初始化编码器
将上步中的设置作为编码器初始化的参数,
x264_t*x264_encoder_open ( x264_param_t *param )。
如果初始化失败将返回NULL,在这里需要对编码器初始化结果进行处理。
4) 分配编码空间
如果编码器初始化成功,则需要为本次处理分配内存空间
Void x264_picture_alloc(x264_picture_t *pic, int i_csp, int i_width, int i_height)。
5) 图像编码
将以上步骤初始化后的数据作为编码输入,使用下面的方法进行编码:
int x264_encoder_encode( x264_t *h,x264_nal_t **pp_nal, int
*pi_nal,x264_picture_t *pic_in,x264_picture_t *pic_out );
6) 资源回收
编码完成后,需要回收系统资源和关闭编码器,使用以下函数调用实现回收。
void x264_picture_clean( x264_picture_t *pic );
void x264_encoder_close( x264_t *h );
至此,完成了H.264编码,编码后的数据量将大大减小。
我们可以对编码后的数据做相关的进一步处理。
4 H.264编码算法的完整源代码
文件:VideoEncoderX264.h
class CVideoEncoderX264 :
{
public:
CVideoEncoderX264(void);
~CVideoEncoderX264(void);
virtual bool Connect(CVideoEnDecodeNotify* pNotify, const CVideoEnDecodeItem& Item);
virtual void Release(void);
virtual void Encode(BYTE* pInData, int nLen, BYTE* pOutBuf, int& nOutLen, int& nKeyFrame);
private:
x264_picture_t m_Pic;
x264_t *h;
x264_param_t param;
void Flush(void);
};
文件:VideoEncoderX264.cpp
bool CVideoEncoderX264::Connect(CVideoEnDecodeNotify* pNotify, const CVideoEnDecodeItem& Item)
{
CBase::Connect(pNotify, Item);
ParseSize(Item.m_stSize);
x264_param_default( ¶m );
param.i_threads = 1;
param.i_frame_total = 0;
param.i_width = m_nWidth;
param.i_height = m_nHeight;
param.i_keyint_min = Item.m_nKeyInterval;
param.i_keyint_max = Item.m_nKeyInterval * 10;
param.i_fps_num = Item.m_nFps;*/
param.i_log_level = X264_LOG_NONE;
if( ( h = x264_encoder_open( ¶m ) ) == NULL )
{
return false;
}
x264_picture_alloc( &m_Pic, X264_CSP_I420, param.i_width, param.i_height );
return true;
}
void CVideoEncoderX264::Release(void)
{
Flush();
x264_picture_clean( &m_Pic );
x264_encoder_close( h );
CBase::Release();
}
void CVideoEncoderX264::Encode(BYTE* pInData, int nLen, BYTE* pOutBuf, int& nOutLen, int& nKeyFrame)
{
if(nLen != param.i_width * param.i_height * 3)
return;
param.i_frame_total ++;
memcpy(m_Pic.img.plane[0], pInData, param.i_width * param.i_height); memcpy(m_Pic.img.plane[1], pInData + param.i_width * param.i_height, param.i_width * param.i_height / 4);
memcpy(m_Pic.img.plane[2], pInData + param.i_width * param.i_height * 5 / 4, param.i_width * param.i_height / 4);
m_Pic.i_pts = (int64_t)param.i_frame_total * param.i_fps_den;
static x264_picture_t pic_out;
x264_nal_t *nal = NULL;
int i_nal, i;
if( &m_Pic )
{
m_Pic.i_type = X264_TYPE_AUTO;
m_Pic.i_qpplus1 = 0;
}
//TraceTime("x264_encoder_encode begin");
if( x264_encoder_encode( h, &nal, &i_nal, &m_Pic, &pic_out ) < 0 ) { return;
}
//TraceTime("x264_encoder_encode end");
int nOutCanUse = nOutLen;
nOutLen = 0;
for( i = 0; i < i_nal; i++ )
{
int i_size = 0;
if( ( i_size = x264_nal_encode( pOutBuf + nOutLen, &nOutCanUse, 1, &nal[i] ) ) > 0 )
{
nOutLen += i_size;
nOutCanUse -= i_size;
}
}
nKeyFrame = pic_out.i_type==X264_TYPE_IDR;// ||
(pic_out.i_type==X264_TYPE_I && coCfg->x264_max_ref_frames==1);
}
void CVideoEncoderX264::Flush(void)
{
x264_picture_t pic_out;
x264_nal_t *nal;
int i_nal, i;
int i_file = 0;
if( x264_encoder_encode( h, &nal, &i_nal, NULL, &pic_out ) < 0 ){
}
}。