从H264的SPS中获取图像长宽
- 格式:doc
- 大小:81.00 KB
- 文档页数:11
H264帧边界识别简介在Symbian平台上实现H264的RTSP流的播放原文:/asddg67/archive/2009/03/23/4017251. aspx 在Symbian平台上实现H264的RTSP流的播放/linzhiji/archive/2010/02/24/5323622.as px H264的数据读取最关键的地方就是如何识别一帧,因为ffmpeg的H264解码是按照一帧一帧解码的,如果送去解码的数据不是完整的一帧可能导致解码失败或者产生马赛克的情况。
以下是我在一个文档中摘取关于帧边界识别的一段,可以方便的解决相关的问题:帧边界识别简介H.264 将构成一帧图像所有nalu 的集合称为一个AU,帧边界识别实际上就是识别AU。
因为H.264 取消帧级语法,所以无法简单地从码流中获取AU。
解码器只有在解码的过程中,通过某些语法元素的组合才能判断一帧图像是否结束。
一般来说,解码器必须在完成一帧新图像的第一个slice_header 语法解码之后,才能知道前一帧图像已经结束。
因此,最严谨的AU 识别步骤如下:步骤1 对码流实施“去03 处理”。
步骤2 解析nalu 语法。
步骤3 解析slice_header 语法。
步骤4 综合判断前后两个nalu 以及对应的slice_header 中的若干个语法元素,看是否发生变化。
如果发生变化,则说明这两个nalu 属于不同的帧,否则说明这两个nalu 属于同一帧。
----结束显然,在解码前完成上述的AU 识别消耗许多CPU 资源,因此不推荐使用AU 方式解码为了提供一种简单的AU 识别方案,H.264 规定一种类型为09 的nalu,即编码器在每次完成一个AU 编码后,在码流中插入一个类型为09 的nalu,在这个前提下,解码器只需要从码流中搜索类型为09 的nalu 即可获得一个AU。
H.264 并不强制要求编码器插入类型为09 的nalu,因此并非所有的码流都具备这种特征。
rfc3984Standards Track [Page 2] RFC 3984 RTP Payload Format for H.264 Video February 2005 1.按照RFC3984协议实现H264视频流媒体nalu单元包起始0x 00 00 00 01H.264 NAL格式及分析器/zsw%5Fdavy/b ... c409cc7cd92ace.html/zsw_davy/blo ... 081312c8fc7acc.html----------------------------------比特流信息----------------------------------------------①NALU(Network Abstract Layer Unit):两标准中的比特流都是以NAL为单位,每个NAL 单元包含一个RBSP,NALU的头信息定义了RBSP所属类型。
类型一般包括序列参数集(SPS)、图像参数集(PPS)、增强信息(SEI)、条带(Slice)等,其中,SPS和PPS 属于参数集,两标准采用参数集机制是为了将一些主要的序列、图像参数(解码图像尺寸、片组数、参考帧数、量化和滤波参数标记等)与其他参数分离,通过解码器先解码出来。
此外,为了增强图像的清晰度,AVS-M添加了图像头(Picture head)信息。
读取NALU流程中,每个NALU前有一个起始码0x000001,为防止内部0x000001序列竞争,H.264编码器在最后一字节前插入一个新的字节——0x03,所以解码器检测到该序列时,需将0x03删掉,而AVS-M只需识别出起始码0x000001。
②读取宏块类型(mb type)和宏块编码模板(cbp):编解码图像以宏块划分,一个宏块由一个16*16亮度块和相应的一个8*8cb和一个8*8cr色度块组成。
(a) 两标准的帧内、帧间预测时宏块的划分是有区别的。
视频图像存储设备的容量计算方法主要有M-JPEG、小波算法、MPEG-4和H.264编码压缩法,因目前采用的编码模式有H.264/MPEG4模式,所以下面以H.264编码压缩模式为例进行计算。
H.264的编码压缩模式和MPEG-4基本一致,公式:C=K*N*Q*T/1024 (单位:G)或C=K*N*V/1024 (单位:G)其中:G:硬盘容量K:硬盘格式化系数,一般取0.7~0.9N: 存储设备的并发存储通道数Q:单个通道每小时所需的存储容量T:视频图像保存时间计算方法:(1)计算单个通道每小时所需的存储容量为Q,单位Mbyte/小时。
Q=d/8*3600/1024其中d是流码,单位是Kbit/s。
码流在存储设备中时可控制调节的。
通常包括限定码流和可变码流(有的录像设置中的称“位率/位率上限”),设置可变码流时可根据设计要求进行选择,一般分辨率采用CIF时,码流选用512Kbit/s;分辨率采用4CIF/D1时,码流选用1.5—2Mbit/s.(CIF=352*288像素,4CIF/D1=420*576像素)(2)确定视频图像保存时间要求确定后单个通道所需的存储容量V,单位MbyteV=Q*H*D其中:H:是每天录像时间(小时)D:是需要保存录像的天数存储设计根据要求,福建工程学院监控系统采用集中式存储解决方案。
具体设计为:在监控中心部署H3C EX1000S IPSAN存储服务器,前端所有摄像头的图像通过监控专网传输到监控中心,集中存储到IPSAN服务器上。
监控平台建成后,还需针对存储需求进行不同码流设计:CIF:图像分辨率为352×288 D1:图像分辨率为720×576采用CIF方式:每路每秒是采用512K进行存储,我们参考512k存储系统按照160个摄像头存储30天的需求,共需要存储容量;(计算公式:存储容量(GB)=(码流/1024/1024/8)×CBR影响系数×60秒×60分钟×24小时×天数)●以512K单路视频图像码流,计算图像存储容量。
监控录像(视频)文件大小计算视频监控系统的前端摄像机分辨率从初的CIF,一直发展到现在的4K,存储和带宽成本不断攀升。
视频编码技术也不断发生变化,同样图像质量下,H.265的码率只有H.264的一半,说明使用H.265编码的录像文件大小为H.264的一半。
那在监控系统中怎么算视频文件的大小及录像硬盘需要容量?1.文件大小计算公式文件大小= 时长×码率÷8或者(音频码率+视频码率)÷8×时长(说明:文件大小单位为kB,码率的单位为Kb /s,时长单位为秒。
)1.1码流码流(Data Rate,也叫码率)是指视频文件在单位时间内使用的数据流量(即:每秒传送的比特数(bit)),是视频编码中画面质量控制中最重要的部分,一般我们用的单位是Kb/s或者Mb/s。
一般来说同样分辨率下,视频文件的码流越大,压缩比就越小,画面质量就越高。
码流越大,说明单位时间内取样率越大,数据流,精度就越高,处理出来的文件就越接近原始文件,图像质量越好,画质越清晰,要求播放设备的解码能力也越高。
常见的录像文件格式的码流:QCIF 256kbPS,CIF 512kbps,DCIF 768kbps,4CIF 1536KBPS,D12048kbps,720P 3096kbps,1080P 4096kbps。
1.2单个通道录像文件大小每小时单个通道录像文件大小(单位MB/小时)=码率大小×3600(1小时3600秒)÷8÷10242.分辨率视频分辨率是指视频成像产品所成图像的大小或尺寸。
常见的视像分辨率有352×288,176×144,640×480,1024×768。
在成像的两组数字中,前者为图片长度,后者为图片的宽度,两者相乘得出的是图片的像素,长宽比一般为4:3。
目前监控行业中主要使用Qcif(176×144)、CIF(352×288)、HALF D1(704×288)、D1(704×576)等几种分辨率。
【知识点】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 中的参考帧列表H264中允许从多至15个帧里面选择1帧或者2帧出来作为参考进行预测,所以必须引入一个列表来管理这些参考图像,对与P slice而言,对应 list0,对于B slice 而言,还需要多一个 list1,因为 B slice 是进行的两次预测!(一个前向一个后向\两个前向\两个后向)参考帧分为 long term / short term 两种,即所谓的长期参考帧和短期参考帧。
其中长期参考帧用 LongTermPicNum来进行索引,而短期参考帧则利用 frame_num 或者 POC 来进行索引(默认索引顺序即初始化顺序),再具体一点:P slice 的短期参考利用 frame_num 来进行索引,且按照降序排列(即离当前图像最近的前向图像排在第0位)B slice 的短期参考利用 POC 来进行索引,对其List0而言,先按照POC降序排列处于其前向的参考帧然后再按照POC升序排列处于其后向的参考帧;对其List1而言,先按照POC升序排列处于其后向的参考帧然后再按照POC降序排列处于其前向的参考帧。
对于每个MB而言,在mb_pred()中会传输其参考索引,以表明该MB从list0\list1中选择哪一个作为参考,而对于一个Slice 而言,可能存在该 Slice 内部大多数MB都选择了某一个索引号较大的参考帧,如设定list0中的索引从0~5,而大多数MB都选择了5,在用哥伦布码进行编码时,将会消耗较多的bit!所以在初始化排序好后,会根据当前 slice 的具体情况,对列表进行重排序,如将此时排在索引5位置的POC与排在0位置的POC进行交换,那么mb_pred()中传输参考索引所需的bit数就大大减少了!其中参考索引重排的语法在ref_pic_list_reordering()中有详细介绍!那么当一帧解完后,如何处理该帧呢?需不需要将其放入参考列表中?所以在h264的bit stream中还传输了dec_ref_pic_marking(),通过mmco这个玩意告诉我们当前的一帧接完后如何处理参考列表!TBD:剩下的一个问题就是,为什么要分长期参考和短期参考呢?以下是来自网上的答案,因为short term参考帧以frame_num做为索引,而frame_num是有最大值的,达到最大值后会进行取模,所以短期参考帧不能长期存在于参考列表中,因为一旦frame_num达到最大值后取模为0,该索引就失去意义了,而长期参考帧则不同!/********************************************************I guess there are two primary differences.1) Short-term reference pictures are indexed by referring to variablesthat are a function of their frame_num value. But frame_num is a modulocounter that wraps over periodically. Therefore there is a limit on howlong a short-term reference picture can remain in the buffer -- itcannot remain there after the frame_num value has wrapped all the wayaround and crossed over the same value again. In contrast, long-termreference pictures are referenced by an index that is explicitlyassigned to them by syntax -- their long-term frame index. So along-term reference picture can stay in the decoded picture buffer aslong as the encoder wants it to.2) There is no use of temporal (picture order count) relationships whenreferencing long-term reference pictures in the decoding process.**********************************************************/。
1. 一些约定2. 描述子(Descriptor)如果有竖线,左边表示entropy_coding_mode_flag=0时使用,竖线右边则为1时使用3. 数据分割片:A:片头和片中每个宏块头数据B:Intra和SI片宏块的编码残差数据C:Inter宏块的编码残差数据IDR片不分割其他片是否分割视情况而定4. 几个概念之间的关系每个NAL单元包含一个RBSPRBSP的头信息定义了RBSP单元的类型SPS:seq_parameter_set_id,帧数,POC约束,参考帧数目,解码图像尺寸和帧场编码模式选择标识等PPS:pic_parameter_set_id,可选的seq_parameter_set_id,熵编码模式选择标识,片组数目,初始量化参数和去方块滤波系数调整标识等5. NAL单元句法1) 每个NAL单元可以有起始码前缀和额外填充单元(填充若干个字节0在起始码前缀前实现每个NAL单元长度对齐-------介质存储)2) 起始码0x000001,填充0x000000防止竞争注意:在RBSP最后,如果没有cabac_zero_word,最后一个字节肯定不是0x00,但是如果最后由一个或者多个cabac_zero_word,则,需要在末尾填上一个0x03.因为码流里除了起始,其他地方绝不能出现0x000001和0x000000所以就连cabac_zero_word出现0x0000,0x0000,中间也要被0x03隔断!3) 每次读一个NAL单元,检测到下个NAL单元起始码,就可以计算出NumBytesInNALunit4) nal_ref_idc:优先级非0:包含序列参数集、序列参数集extension,subset序列参数集, 图像参数集, 参考图像slice, 参考图像的slice data partition, 参考图像slice的NAL单元前缀为0:非参考图像的slice或者slice data partition-1) 序列参数集、序列参数集extension,subset序列参数集, 图像参数集的nal_ref_idc不应为0,如果nal_ref_idc=0且nal_unit_type=1~4,那所有的nal_unit_type=1~4的nal_ref_idc=0-2) nal_unit_type=5时,nal_ref_idc不能为0-3) nal_unit_type=6,9,10,11,12时,nal_ref_idc为05) nal_unit_type:suffix dependent:如果nal_unit_type=14之后的NAL单元的nal_unit_type=1/5,则是VCL,否则不是VCL。
H.264比拼720P 谁才能叫做是真高清随着气温的节节攀升,随着莘莘学子陆续返校,数码播放器行业又呈现了欣欣向荣的景象,09年伊始,一股浓浓的高清风暴就强势袭来,但作为消费者来说,高清的概念仍然不是很清晰,更多的人是凭着直观感觉来判断,显然是不理智的。
如果说支持720P(1280×720分辨率)的视频就可以成为高清,那恐怕就大错特错了,好比当年的Intel推出的迅驰系统,必须要Intel的CPU、Intel指定的主板芯片组、Intel指定的无线网卡,3者合一,才能称为迅驰,高清也类似,除了视频,还要硬件,当然视频同样有着很多格式和编码,这其中充满着奥妙与陷阱,各位一定要小心判断,下面就通过一个实例来讲讲其中的秘密。
关键词一:720P并不重要同是4.3寸屏,同样是480×272分辨率。
PSP播放视频的视觉效果比MP4播放RMVB 的效果好很多,而秘密就在于编码方式上,PSP所采用的就是H.264编码,同样采用的还包括iPod产品,而基本上世界上“全部”多媒体、移动通讯巨头在其与音视频传输的相关领域全部采用了H.264编码。
RMVB的失真就像水滴在纸上,整体模糊,但在分辨率比较低的状况下看起来好一些,而H264则象很多细小的马赛克,在低中高分辨率上都具有优秀表现,而在高分辨率下720P 及以上,就基本是H264与Di×V编码的天下了。
此外,在高清视频压缩小组中,也有一股压缩480P的H.264的热潮,我们了解到RMVB 只在小分辨率的情况下可以拥有较出色的体积,因此而流行,而在高分辨率下,其编码作用的原理对清晰还原画面不利,于是有众多国内的视频压缩高手逐渐采用了480P的H264编码视频作为中等体积大小的视频的首选编码方式。
所以我们才可以在电驴和一些专门制作高清视频的专业论坛,找到许多480P的H.264视频。
关键词之二:H.264清晰的秘密众多视频压缩小组认为480P的H.264编码视频,在电脑上的视频画面播放品质与720P 的RMVB相当。
H264 NAL 头解析分类: linux 学习 2013-06-06 20:43 2535 人阅读 评论(0) 收藏 举报NAL 全称 Network Abstract Layer,即网络抽象层。
在 H.264/AVC 视频编码标准中,整个 系统框架被分为了两个层面:视频编码层面(VCL)和网络抽象层面(NAL)。
其中,前者 负责有效表示视频数据的内容, 而后者则负责格式化数据并提供头信息, 以保证数据适合各 种信道和存储介质上的传输。
NAL 单元是 NAL 的基本语法结构,它包含一个字节的头信息 和一系列来自 VCL 的称为原始字节序列载荷(RBSP)的字节流。
如果 NALU 对应的 Slice 为一帧的开始,则用 4 字节表示,即 0x00000001;否则用 3 字节 表示,0x000001。
NAL Header: forbidden_bit, nal_reference_bit (优先级) 2bit, nal_unit_type (类型) 5bit。
标 识 NAL 单元中的 RBSP 数据类型,其中,nal_unit_type 为 1, 2, 3, 4, 5 的 NAL 单 元称为 VCL 的 NAL 单元,其他类型的 NAL 单元为非 VCL 的 NAL 单元。
0:未规定 1:非 IDR 图像中不采用数据划分的片段 2:非 IDR 图像中 A 类数据划分片段 3:非 IDR 图像中 B 类数据划分片段 4:非 IDR 图像中 C 类数据划分片段 5:IDR 图像的片段 6:补充增强信息(SEI) 7:序列参数集(SPS) 8:图像参数集(PPS) 9:分割符 10:序列结束符 11:流结束符 12:填充数据 13:序列参数集扩展 14:带前缀的 NAL 单元 15:子序列参数集 16 – 18:保留 19:不采用数据划分的辅助编码图像片段 20:编码片段扩展 21 – 23:保留 24 – 31:未规定 NAL 的头占用了一个字节,按照比特自高至低排列可以表示如下: 0AABBBBB其中,AA 用于表示该 NAL 是否可以丢弃(有无被其后的 NAL 参考),00b 表示没有参 考作用,可丢弃,如 B slice、SEI 等,非零——包括 01b、10b、11b——表示该 NAL 不可丢弃,如 SPS、PPS、I Slice、P Slice 等。
H.264编码下基于DCT系数量化值的PSNR估计方法H.264编码下基于DCT系数量化值的PSNR估计方法摘要:视频编码技术的发展为多媒体应用的流畅传输和高清晰度播放提供了基础支持。
在现有的视频编码标准中,H.264是应用最广泛的一种标准,被广泛应用于视频通信领域。
估计图像或视频的质量可以通过峰值信噪比(PSNR)来评估。
本文研究了H.264编码下基于离散余弦变换(DCT)系数数量化值的PSNR估计方法,通过分析编码过程中的DCT系数量化值与原始图像之间的关系,提出了一种基于DCT系数量化值的PSNR估计方法,并通过实验验证了该方法的有效性。
1. 引言视频编码技术能够将视频信号压缩成较小的体积以实现高效的传输和存储。
H.264作为一种视频编码标准,在高质量视频传输和存储方面具有显著优势。
视频质量评估是衡量视频编码算法优劣的一种重要指标。
而PSNR作为一种广泛应用的视频质量评估指标,被广泛用于评估视频质量。
2. H.264编码过程与DCT系数数量化值H.264编码过程包括了若干个关键步骤,其中包括了离散余弦变换(DCT)系数数量化。
DCT变换将图像分解为一系列频率子带,然后进行系数的数量化。
在DCT系数量化过程中,系数的重要程度由其数量化值来表示。
较大的数量化值表示较小的权重。
3. 基于DCT系数量化值的PSNR估计方法本文通过分析H.264编码过程中DCT系数量化值与原始图像之间的关系,提出了一种基于DCT系数量化值的PSNR估计方法。
具体步骤如下:步骤一:获取原始图像和编码后的图像首先,获取原始图像和经过H.264编码后的图像。
原始图像用于作为参考,编码后的图像用于与原始图像进行对比。
步骤二:计算原始图像和编码后的图像的DCT系数量化值利用H.264编码器对原始图像进行编码,得到编码后的图像。
然后,通过解码得到DCT系数量化值。
步骤三:计算DCT系数量化值之间的差异对于原始图像的每个DCT系数量化值,计算其与编码后图像对应位置的DCT系数量化值之间的差异。
从H.264解码器原理图到任务图的分析1. H.264解码器原理图1 H.264解码器原理框图解码器从NAL 接收压缩后的比特流,然后经过嫡解码和重排序,得到量化后宏块系数X ,再经过逆量化、逆变换生成残差系数'n D 。
这一过程和编码器重建码流生成'n D 的过程一致。
使用码流中解出的头信息,解码器从参考帧中得到预测宏块P 和编码器形成的原始预测宏块P 相同。
P 与'n D 相加得到'n F 。
最后对重建图像进行滤波,去除块效应后可得到解码图像。
从NAL 进入熵解码模块的码流的数据速率是不恒定的,因为不同时刻的视频数据被熵编码压缩的程度不一样。
但是经过熵解码和重排序后的数据产生量化系数集2. 系统参数选择表1列举出了各种标准视频格式的分辨率和帧率,表中所列视频格式从上到下分辨率越来越高,但是运算复杂度也越来越大。
因为在大多数场合并不要求高清视频,如视频会议,可视电话等,所以本课题选择了一种分辨率适中的常用的视频格式——CIF(352x288)。
表1 各种标准视频格式的分辨率和帧率以参考文献[1]的系统设计指标作为本课题H.264解码器参数选择依据。
具体参数均列于表格2中。
表2 系统参数表 部分参数的计算:处理单个宏块的时钟个数:****M Bwidth M Bheight ClkNum SysClk width height F(1)其中,*MBwidth MBheight 表示宏块的大小,*width height 表示图像格式的大小;F 代表帧频,SysClk 代表系统时钟。
将表格中的参数代入公式1,计算出系统在54MHz 时钟下处理一个宏块需要4546个时钟周期。
3. H.264解码器任务图的构建根据图1的解码器原理图和表2的参数选取,构造出图2所示的任务流图。
在该图中,除了C7向C6的突发数据量是3072bits(一个宏块),其它任务之间的单次数据交互量均为192bits(一个块)。
H264基础简介前⾔H264是属于视频的编码层的标准格式,视频编码显然是为了压缩⼤⼩。
我们看下⼀个完全没压缩的视频数据⼤⼩。
假设视频是⾼清(1280 * 720),每秒30帧,也就是每秒的数据1280 * 720 *30 / 8(字节) /1024(KB)/1024(MB) = 3.11MB那么90分钟的电影就要16.7GB,这个数据量显然在当前⽹络下是不现实的。
视频压缩的原理就是去除视频冗余部分,下⾯列举下1,时间冗余时间冗余是序列图像(电视图像、动画)和语⾳数据中所经常包含的冗余。
图像序列中的两幅相邻的图像,后⼀幅图像与前⼀幅图像之间有较⼤的相关性,这反映为时间冗余。
同理,在语⾔中,由于⼈在说话时发⾳的⾳频是⼀连续的渐变过程,⽽不是⼀个完全的在时间上独⽴的过程,因⽽存在时间冗余。
2,空间冗余空间冗余是图像数据中经常存在的⼀种冗余。
在同⼀幅图像中,规则物体和规则背景(所谓规则是指表⾯颜⾊分布是有序的⽽不是杂乱⽆章的)的表⾯物理特性具有相关性,这些相关性的光成像结构在数字化图像中就表现为数据冗余。
,3,知识冗余有许多图像的理解与某些基础知识有相当⼤的相关性,例如:⼈脸的图像有固定的结构。
⽐如,嘴的上⽅有⿐⼦。
⿐⼦的上⽅有眼睛,⿐⼦位于正脸图像的中线上等等。
这类规律性的结构可由先验知识相背景知识得到,我们称此类冗余为知识冗余。
4,结构冗余有些图像从⼤域上看存在着⾮常强的纹理结构,例如布纹图像和草席图像,我们说它们在结构上存在冗余。
5,视觉冗余⼈类视觉系统对于图像场的任何变化,并不是都能感知的。
例如,对于图像的编码和解码处理时,由于压缩或量⽐截断引⼊了噪声⽽使图像发⽣了⼀些变化,如果这些变化不能为视觉所感知,则仍认为图像⾜够好。
事实上⼈类视觉系统⼀般的分辨能⼒约为26灰度等级,⽽⼀般图像量化采⽤28灰度等级,这类冗余我们称为视觉冗余。
通常情况下,⼈类视觉系统对亮度变化敏感,⽽对⾊度的变化相对不敏感;在⾼亮度区,⼈眼对亮度变化敏感度下降。
H.264 NALU语法结构补充笔记:关于VCL:VCL层是指视频编码层,VCL NAL 单元是指那些nal_unit_type 值等于1 到5(包括1 和5)的NAL 单元,这些单元都包含了视频数据。
所有其他的NAL 单元都称作非VCL NAL 单元,PPS和SPS都是非VCLNAL单元。
关于字节流NAL单元的格式:(起始码中0的长度)除了流开头的字节流NAL单元,大多字节流NAL单元的开头没有leading_zero_8bits (一个字节的0);nal_unit_type等于7(SPS)或8(PPS)时,或字节流NAL 单元语法结构在解码顺序时包含一个访问单元的第一个NAL单元,码流中会出现zero_byte (一个字节的0);所有字节流NAL的单元的开头,都会存在start_code_prefix_one_3bytes (三个000001字节)。
所以,如果不考虑流的开头,没有特殊性的字节流NAL单元,都是只有3字节的起始码(即起始码中0的个数为2)。
一个访问单元的第一个NAL单元是指:在基本编码图像的最后一个VCL NAL 单元之后的第一个任何下列NAL 单元代表了一个新的访问单元的开始:—访问单元分隔NAL 单元(存在时)—序列参数集NAL 单元(存在时)—图像参数集NAL 单元(存在时)— SEI NAL 单元(存在时)— nal_unit_type 值在14-18 之间(包括)的NAL 单元—基本编码图像的第一个VCL NAL 单元(总是存在)下文转自:/yangzhongxuan/article/details/800349 4名词解释场和帧:视频的一场或一帧可用来产生一个编码图像。
在电视中,为减少大面积闪烁现象,把一帧分成两个隔行的场。
片:每个图象中,若干宏块被排列成片的形式。
片分为I片、B片、P片和其他一些片。
I片只包含I宏块,P片可包含P和I宏块,而B片可包含B和I宏块。
I宏块利用从当前片中已解码的像素作为参考进行帧内预测。
H264码流解析及NALU639 /* bitstream filters */640 REGISTER_BSF(AAC_ADTSTOASC, aac_adtstoasc);641 REGISTER_BSF(CHOMP, chomp);642 REGISTER_BSF(DUMP_EXTRADATA, dump_extradata);643 REGISTER_BSF(H264_MP4TOANNEXB, h264_mp4toannexb);644 REGISTER_BSF(HEVC_MP4TOANNEXB, hevc_mp4toannexb);645 REGISTER_BSF(IMX_DUMP_HEADER, imx_dump_header);646 REGISTER_BSF(MJPEG2JPEG, mjpeg2jpeg);647 REGISTER_BSF(MJPEGA_DUMP_HEADER, mjpega_dump_header);648 REGISTER_BSF(MP3_HEADER_DECOMPRESS, mp3_header_decompress);649 REGISTER_BSF(MPEG4_UNPACK_BFRAMES, mpeg4_unpack_bframes);650 REGISTER_BSF(MOV2TEXTSUB, mov2textsub);651 REGISTER_BSF(NOISE, noise);652 REGISTER_BSF(REMOVE_EXTRADATA, remove_extradata);653 REGISTER_BSF(TEXT2MOVSUB, text2movsub);H264码流的NAL起始字节分析这是⼀段H264码流,00 00 00 01这是对应forbidden_zero_bit的f(1),接着后⾯的nal_ref_idc的u(2),这个怎么解呀,有点晕。
从H264的SPS中获取图像长宽作者:李国帅从开源项目mpegip中选取,并封装。
1,调用方法#include"H264Parser.h"h264_decode_t dec;memset(&dec, 0, sizeof(dec));uint8_t * buffer = (uint8_t*)cbSPS;h264_parse_sequence_parameter_set(&dec, buffer,nSPS * 8);outWidth = dec.pic_width;//1920;//outHeight = dec.pic_height;//1080;//2,H264Parser.h代码#pragma once#ifndef __H264_H__#define __H264_H__ 1#include<stdio.h>#include<math.h>#include"stdint.h"#include"bitstream.h" //在mpegip中得到,就不粘贴了。
typedef unsigned int uint;#define H264_START_CODE 0x000001#define H264_PREVENT_3_BYTE 0x000003#pragma pack(push)#pragma pack(1)typedef struct h264_decode_t{uint8_t profile;uint8_t level;uint32_t chroma_format_idc;uint8_t residual_colour_transform_flag;uint32_t bit_depth_luma_minus8;uint32_t bit_depth_chroma_minus8;uint8_t qpprime_y_zero_transform_bypass_flag;uint8_t seq_scaling_matrix_present_flag;uint32_t log2_max_frame_num_minus4;uint32_t log2_max_pic_order_cnt_lsb_minus4;uint32_t pic_order_cnt_type;uint8_t frame_mbs_only_flag;uint8_t pic_order_present_flag;uint8_t delta_pic_order_always_zero_flag;int32_t offset_for_non_ref_pic;int32_t offset_for_top_to_bottom_field;uint32_t pic_order_cnt_cycle_length;int16_t offset_for_ref_frame[256];uint8_t nal_ref_idc;uint8_t nal_unit_type;uint8_t field_pic_flag;uint8_t bottom_field_flag;uint32_t frame_num;uint32_t idr_pic_id;uint32_t pic_order_cnt_lsb;int32_t delta_pic_order_cnt_bottom;int32_t delta_pic_order_cnt[2];uint32_t pic_width, pic_height;uint32_t slice_type;/* POC state */int32_t pic_order_cnt; /* can be < 0 */uint32_t pic_order_cnt_msb;uint32_t pic_order_cnt_msb_prev;uint32_t pic_order_cnt_lsb_prev;uint32_t frame_num_prev;int32_t frame_num_offset;int32_t frame_num_offset_prev;uint8_t NalHrdBpPresentFlag;uint8_t VclHrdBpPresentFlag;uint8_t CpbDpbDelaysPresentFlag;uint8_t pic_struct_present_flag;uint8_t cpb_removal_delay_length_minus1;uint8_t dpb_output_delay_length_minus1;uint8_t time_offset_length;uint32_t cpb_cnt_minus1;uint8_t initial_cpb_removal_delay_length_minus1; } h264_decode_t;static uint8_t exp_golomb_bits[] ={8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3,3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2,2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};//256static const uint8_t trailing_bits[] = { 0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 };//9#ifdef __cplusplusextern"C" {#endifuint32_t h264_ue(CBitstream *bs){uint32_t bits, read;int bits_left;uint8_t coded;bool done = false;bits = 0;// we want to read 8 bits at a time - if we don't have 8 bits,// read what's left, and shift. The exp_golomb_bits calc remains the// same.while(done == false){bits_left = bs->bits_remain();if(bits_left < 8){read = bs->PeekBits(bits_left) <<(8 - bits_left);done = true;}else{read = bs->PeekBits(8);if(read == 0){bs->GetBits(8);bits += 8;}else{done = true;}}}coded = exp_golomb_bits[read];bs->GetBits(coded);bits += coded;// printf("ue - bits %d\n", bits);return bs->GetBits(bits + 1) - 1;}int32_t h264_se(CBitstream *bs){uint32_t ret;ret = h264_ue(bs);if((ret & 0x1) == 0){ret >>= 1;int32_t temp = 0 - ret;return temp;}return(ret + 1) >> 1;}void h264_check_0s(CBitstream *bs, int count){uint32_t val;val = bs->GetBits(count);if(val != 0){//printf("field error - %d bits should be 0 is %x\n", count, val);}}void scaling_list(uint32_t ix, uint32_t sizeOfScalingList, CBitstream *bs){uint32_t lastScale = 8, nextScale = 8;uint32_t jx;int deltaScale;for(jx = 0; jx < sizeOfScalingList; jx++){if(nextScale != 0){deltaScale = h264_se(bs);nextScale =(lastScale + deltaScale + 256) % 256;//printf(" delta: %d\n", deltaScale);}if(nextScale == 0){lastScale = lastScale;}else{lastScale = nextScale;}//printf(" scaling list[%u][%u]: %u\n", ix, jx, lastScale);}}void h264_parse_sequence_parameter_set(h264_decode_t *dec, uint8_t* Buffer,size_t Buffer_Size){CBitstream ourbs;ourbs.init(Buffer, Buffer_Size);CBitstream *bs = &ourbs;uint32_t type = 0;h264_check_0s(bs, 1);//检查首字节dec->nal_ref_idc = bs->GetBits(2);//NAL 的优先级dec->nal_unit_type = type = bs->GetBits(5);//nal类型if(type != 0x7){return;}uint32_t temp;dec->profile = bs->GetBits(8);//第个字节//printf(" profile: %u\n", dec->profile);temp = bs->GetBits(1);//printf(" constaint_set0_flag: %d\n", temp);temp = bs->GetBits(1);//printf(" constaint_set1_flag: %d\n", temp);temp = bs->GetBits(1);//printf(" constaint_set2_flag: %d\n", temp);temp = bs->GetBits(1);//printf(" constaint_set3_flag: %d\n", temp);h264_check_0s(bs, 4);//第个字节temp = bs->GetBits(8);//第个字节//printf(" level_idc: %u\n", temp);temp = h264_ue(bs);//printf(" seq parameter set id: %u\n", temp);if(dec->profile == 100 || dec->profile == 110 || dec->profile == 122 || dec->profile == 144){dec->chroma_format_idc = h264_ue(bs);if(dec->chroma_format_idc == 3){dec->residual_colour_transform_flag = bs->GetBits(1);}dec->bit_depth_luma_minus8 = h264_ue(bs);dec->bit_depth_chroma_minus8 = h264_ue(bs);dec->qpprime_y_zero_transform_bypass_flag = bs->GetBits(1);dec->seq_scaling_matrix_present_flag = bs->GetBits(1);if(dec->seq_scaling_matrix_present_flag){for(uint32_t ix = 0; ix < 8; ix++){temp = bs->GetBits(1);if(temp){scaling_list(ix, ix < 6 ? 16 : 64, bs);}}}}dec->log2_max_frame_num_minus4 = h264_ue(bs);dec->pic_order_cnt_type = h264_ue(bs);if(dec->pic_order_cnt_type == 0){dec->log2_max_pic_order_cnt_lsb_minus4 = h264_ue(bs);}else if(dec->pic_order_cnt_type == 1){dec->delta_pic_order_always_zero_flag = bs->GetBits(1);temp = h264_se(bs);//printf(" offset_for_non_ref_pic: %d\n", temp);temp = h264_se(bs);//printf(" offset_for_top_to_bottom_field: %d\n",temp);temp = h264_ue(bs);for(uint32_t ix = 0; ix < temp; ix++){temp = h264_se(bs);//printf(" offset_for_ref_frame[%u]: %d\n", ix, temp);}}temp = h264_ue(bs);//printf(" num_ref_frames: %u\n", temp);temp = bs->GetBits(1);//printf(" gaps_in_frame_num_value_allowed_flag: %u\n", temp);uint32_t PicWidthInMbs = h264_ue(bs) + 1;//printf(" pic_width_in_mbs_minus1: %u(%u)\n", PicWidthInMbs - 1, PicWidthInMbs * 16);uint32_t PicHeightInMapUnits = h264_ue(bs) + 1;//printf(" pic_height_in_map_minus1: %u\n", PicHeightInMapUnits - 1);dec->frame_mbs_only_flag = bs->GetBits(1);if(!dec->frame_mbs_only_flag){temp = bs->GetBits(1);//printf(" mb_adaptive_frame_field_flag: %u\n", temp);}temp = bs->GetBits(1);//printf(" direct_8x8_inference_flag: %u\n",temp);temp = bs->GetBits(1);if(temp){temp = h264_ue(bs);//printf(" frame_crop_left_offset: %u\n", temp);temp = h264_ue(bs);//printf(" frame_crop_right_offset: %u\n", temp);temp = h264_ue(bs);//printf(" frame_crop_top_offset: %u\n", temp);temp = h264_ue(bs);//printf(" frame_crop_bottom_offset: %u\n", temp);}//temp = bs->GetBits(1);//if(temp)//{// h264_vui_parameters(dec, bs);//海康sps可能没有这个东西//}dec->pic_width = PicWidthInMbs * 16;dec->pic_height =( 2 - dec->frame_mbs_only_flag ) * PicHeightInMapUnits * 16; }static uint32_t calc_ceil_log2(uint32_t val){uint32_t ix, cval;ix = 0;cval = 1;while(ix < 32){if(cval >= val) return ix;cval <<= 1;ix++;}return ix;}void h264_parse_pic_parameter_set(h264_decode_t *dec, CBitstream *bs){uint32_t num_slice_groups, temp, iGroup;temp = h264_ue(bs);//printf(" pic_parameter_set_id: %u\n", temp);temp = h264_ue(bs);//printf(" seq_parameter_set_id: %u\n", temp);temp = bs->GetBits(1);//printf(" entropy_coding_mode_flag: %u\n",temp);dec->pic_order_present_flag = bs->GetBits(1);//printf(" pic_order_present_flag: %u\n", dec->pic_order_present_flag);num_slice_groups = h264_ue(bs);//printf(" num_slice_groups_minus1: %u\n", num_slice_groups);if(num_slice_groups > 0){temp = h264_ue(bs);//printf(" slice_group_map_type: %u\n", temp);if(temp == 0){for(iGroup = 0; iGroup <= num_slice_groups; iGroup++){temp = h264_ue(bs);//printf(" run_length_minus1[%u]: %u\n", iGroup,temp);}}else if(temp == 2){for(iGroup = 0; iGroup < num_slice_groups; iGroup++){temp = h264_ue(bs);//printf(" top_left[%u]: %u\n", iGroup, temp);temp = h264_ue(bs);//printf(" bottom_right[%u]: %u\n", iGroup, temp);}}else if(temp < 6) // 3, 4, 5{temp = bs->GetBits(1);//printf(" slice_group_change_direction_flag: %u\n", temp);temp = h264_ue(bs);//printf(" slice_group_change_rate_minus1: %u\n", temp);}else if(temp == 6){temp = h264_ue(bs);//printf(" pic_size_in_map_units_minus1: %u\n", temp);uint32_t bits = calc_ceil_log2(num_slice_groups + 1);//printf(" bits - %u\n", bits);for(iGroup = 0; iGroup <= temp; iGroup++){temp = bs->GetBits(bits);//printf(" slice_group_id[%u]: %u\n", iGroup, temp);}}}temp = h264_ue(bs);//printf(" num_ref_idx_l0_active_minus1: %u\n",temp);temp = h264_ue(bs);//printf(" num_ref_idx_l1_active_minus1: %u\n",temp);temp = bs->GetBits(1);//printf(" weighted_pred_flag: %u\n",temp);temp = bs->GetBits(2);//printf(" weighted_bipred_idc: %u\n",temp);temp = h264_se(bs);//printf(" pic_init_qp_minus26: %d\n", temp);temp = h264_se(bs);//printf(" pic_init_qs_minus26: %d\n", temp);temp = h264_se(bs);//printf(" chroma_qp_index_offset: %d\n", temp);temp = bs->GetBits(1);//printf(" deblocking_filter_control_present_flag: %u\n",temp);temp = bs->GetBits(1);//printf(" constrained_intra_pred_flag: %u\n", temp);temp = bs->GetBits(1);//printf(" redundant_pic_cnt_present_flag: %u\n", temp);int bits = bs->bits_remain();if(bits == 0) return;if(bits <= 8){uint8_t trail_check = bs->PeekBits(bits);if(trail_check == trailing_bits[bits]) return;}// we have the extensionsuint8_t transform_8x8_mode_flag = bs->GetBits(1);//printf(" transform_8x8_mode_flag: %u\n", transform_8x8_mode_flag);temp = bs->GetBits(1);//printf(" pic_scaling_matrix_present_flag: %u\n", temp);if(temp){uint max_count = 6 +(2 * transform_8x8_mode_flag);for(uint ix = 0; ix < max_count; ix++){temp = bs->GetBits(1);//printf(" Pic Scaling List[%u] Present Flag: %u\n", ix, temp);if(temp){scaling_list(ix, ix < 6 ? 16 : 64, bs);}}}temp = h264_se(bs);//printf(" second_chroma_qp_index_offset: %u\n",temp);}#ifdef __cplusplus }#endif#pragma pack(pop) #endif。