从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 等。
从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。