h.264的编码过程
- 格式:doc
- 大小:37.00 KB
- 文档页数:5
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)上质量可接受的视频信号。
•编码器的核心是基于运动补偿预测(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)”。
【知识点】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系统。
【基本定义】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视频编码基本知识一、视频编码技术的发展历程视频编码技术基本是由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)区分"帧"和"场";引入了编码的可分级性技术,如空间可分级性、时间可分级性和信噪比可分级性等。
视频压缩编码标准H.264详解视频压缩编码标准H.264详解——新疆大学2006级工硕郭新军JVT(Joint Video Team,视频联合工作组)于2001年12月在泰国Pattaya 成立。
它由ITU-T和ISO两个国际标准化组织的有关视频编码的专家联合组成。
JVT的工作目标是制定一个新的视频编码标准,以实现视频的高压缩比、高图像质量、良好的网络适应性等目标。
目前JVT的工作已被ITU-T接纳,新的视频压缩编码标准称为H.264标准,该标准也被ISO接纳,称为AVC(Advanced Video Coding)标准,是MPEG-4的第10部分。
H.264标准可分为三档:基本档次(其简单版本,应用面广);主要档次(采用了多项提高图像质量和增加压缩比的技术措施,可用于SDTV、HDTV和DVD等);扩展档次(可用于各种网络的视频流传输)。
H.264不仅比H.263和MPEG-4节约了50%的码率,而且对网络传输具有更好的支持功能。
它引入了面向IP包的编码机制,有利于网络中的分组传输,支持网络中视频的流媒体传输。
H.264具有较强的抗误码特性,可适应丢包率高、干扰严重的无线信道中的视频传输。
H.264支持不同网络资源下的分级编码传输,从而获得平稳的图像质量。
H.264能适应于不同网络中的视频传输,网络亲和性好。
一、H.264视频压缩系统H.264标准压缩系统由视频编码层(VCL)和网络提取层(Network Abstraction Layer,NAL)两部分组成。
VCL中包括VCL编码器与VCL解码器,主要功能是视频数据压缩编码和解码,它包括运动补偿、变换编码、熵编码等压缩单元。
NAL则用于为VCL提供一个与网络无关的统一接口,它负责对视频数在H.264中采用了6阶FIR滤波器的内插获得1/2像素位置的值。
当1/2像素值获得后, 1/4像素值可通过线性内插获得,对于4:1:1的视频格式,亮度信号的1/4 像素精度对应于色度部分的1/8像素的运动矢量,因此需要对色度信号进行1/8像素的内插运算。
H.264(JM12.2)解码流程理解版本: 1时间:2010.2-2010.3邮件:zjhzchen@主要包括以下两个方面:1.解码标准原理2.JM代码中的解码流程一、H.264解码标准解码器功能框图如下:解码器功能框图详细的解码流程如下:详细的解码流程二、JM12.2的解码主控流程解码总流程帧解码流程(decode one frame)解码一帧的流程读一个片(read_new_slice)解码IDR包括图像的帧号,计算POC,为存储图像分配空间,错误恢复的重设置解码IDR灵活移动宏块的初始化(FmoInit)1. mapUnitToSliceGroupMap变量mapUnitToSliceGroupMap的计算流程2. MbToSliceGroupMap函数NextMbAddress( n )的流程图像序列号的计算(decode_poc)参考帧列表的重排序(reorder_lists)解码一个片(decode_one_slice )为直接预测模式做一些准备工作:获取co_located 图像、计算mv_scale解码一个片熵解码:包括解出宏块类型、预测模式、MVD 、CBP 、残差(包括反量化操作)等反变换及运动补偿:反量化反变换、运动补偿、像素重构等写入各个8*8块的预测模式及运动向量到错误隐藏变量中保存相关的片参数计算宏块,块,像素的坐标;宏块结构语法元素的初始化;相邻块的可用性;以及滤波参数开始一个宏块(start_macroblock)开始一个宏块读一个宏块(read_one_macroblock)// intra frame将亮度块中的16个4*4块的预测模式设置为2(直接预测),运动向量置0宏块(也即P_Skip类型宏块)。
无残MVD。
直接利用预测MV得到像素预=像素预测值从NAL中读取运动矢量信息(readMotionInfoFromNAL)从NAL中读运动矢量信息从NAL中读取CBP以及残差信息(readCBPandCoeffsFromNAL)如果当前宏块不是帧内16*16或者I_PCM类型宏块则从码流中读取CBP从NAL中读取CBP和残差信息解码一个宏块(decode_one_macroblock)解码一个宏块的流程注:此处的解码包括预测信息,残差的反变换以及图像的重建将宏块的预测模式以及运动信息写入错误隐藏变量中(ercWriteMBMODEandMV)将预测模式和运动信息写到错误隐藏变量中退出图像(exit_picture)退出图像图像的去块滤波(DeblockPicture)图像的去块滤波图像的错误检测以及处理图像的错误检测以及处理store_picture到解码缓冲区(store_picture_in_dpb)IDR内存管理(idr_memory_management)IDR内存管理adaptive-内存管理控制(adaptive_memory_management)参考图像的自适应内存控制标记过程分配LongTermFrameIdx给一个短期参考图像插入图像到DPB(insert_picture_in_dpb)插入图像到DPBflush-DPB(flush_dpb)将DPBB.fs的参考标记置为0Flush-DPB。
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 ){
}
}。