【开源项目】H264码流格式解析

目录

  • 1.概述
  • 2.头文件的定义
    • 2.1 基础头文件(base.h)
    • 2.2 H264码流读取文件(bs.h)
      • 2.2.1 单比特读取函数(bs_read_u1)
      • 2.2.2 指数哥伦布无符号编码(bs_read_ue)
      • 2.2.3 指数哥伦布有符号编码(bs_read_se)
    • 2.3 H264码流定义头文件(h264_parser.h)
  • 3.cpp文件
    • 3.1 H264分析(h264_parser.cpp)
    • 3.2 码流解析(parser.cpp)
  • 4.程序运行结果
  • 5.小结

参考:
李迟:完成一个分析H264码流的工具
雷博:视音频编解码学习工程:H.264分析器
码流介绍:H.264 入门篇 - 01 (Bitstream)
哥伦布编码:音视频从入门到精通——指数哥伦布码原理

1.概述

码流解析可以深入的剖析视频流当中语法元素存储的方式,这对于理解码流有很大的帮助作用,本文参考雷博和李迟的开源代码,结合2021年8月份新的H264视频编码标准,做了一些微调和注释,尽管有些地方还有待改进,但实现了主要功能。这个开源项目提出的另一个作用是替代那些昂贵的视频码流分析软件如VQA,目前只有打印输出分析的内容,但未来会改成可操作性界面。下面对代码进行定义和解释

2.头文件的定义

2.1 基础头文件(base.h)

base.h文件的定义,定义了ERROR打印信息,其中__FILE__是当前文件,__LINE__是当前行,__func__是当前函数,最后的error是打印的错误信息,这样方便定位出错的地方,这在代码量比较大的工程里面非常实用

#pragma once
#ifndef _BASE_H_
#define _BASE_H_
#define ERROR(error) printf("%s:%d:%s:%s\n", __FILE__, __LINE__, __func__,  error)
#endif // !_BASE_H_

2.2 H264码流读取文件(bs.h)

码流头文件由h264bitstream给出,定义了码流读取的方式,作者是Alex Izvorski,这里用作开源应该没问题

/** h264bitstream - a library for reading and writing H.264 video* Copyright (C) 2005-2007 Auroras Entertainment, LLC* Copyright (C) 2008-2011 Avail-TVN** Written by Alex Izvorski <aizvorski@gmail.com> and Alex Giladi <alex.giladi@gmail.com>** This library is free software; you can redistribute it and/or* modify it under the terms of the GNU Lesser General Public* License as published by the Free Software Foundation; either* version 2.1 of the License, or (at your option) any later version.** This library is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU* Lesser General Public License for more details.** You should have received a copy of the GNU Lesser General Public* License along with this library; if not, write to the Free Software* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA*/#ifndef _H264_BS_H
#define _H264_BS_H        1#include <stdint.h>
#include <stdlib.h>
#include <string.h>#ifdef __cplusplus
extern "C" {
#endiftypedef struct
{uint8_t* start;uint8_t* p;uint8_t* end;int bits_left;
} bs_t;#define _OPTIMIZE_BS_ 1#if ( _OPTIMIZE_BS_ > 0 )
#ifndef FAST_U8
#define FAST_U8
#endif
#endifstatic bs_t* bs_new(uint8_t* buf, size_t size);
static void bs_free(bs_t* b);
static bs_t* bs_clone(bs_t* dest, const bs_t* src);
static bs_t* bs_init(bs_t* b, uint8_t* buf, size_t size);
static uint32_t bs_byte_aligned(bs_t* b);
static int bs_eof(bs_t* b);
static int bs_overrun(bs_t* b);
static int bs_pos(bs_t* b);static uint32_t bs_peek_u1(bs_t* b);
static uint32_t bs_read_u1(bs_t* b);
static uint32_t bs_read_u(bs_t* b, int n);
static uint32_t bs_read_f(bs_t* b, int n);
static uint32_t bs_read_u8(bs_t* b);
static uint32_t bs_read_ue(bs_t* b);
static int32_t  bs_read_se(bs_t* b);static void bs_write_u1(bs_t* b, uint32_t v);
static void bs_write_u(bs_t* b, int n, uint32_t v);
static void bs_write_f(bs_t* b, int n, uint32_t v);
static void bs_write_u8(bs_t* b, uint32_t v);
static void bs_write_ue(bs_t* b, uint32_t v);
static void bs_write_se(bs_t* b, int32_t v);static int bs_read_bytes(bs_t* b, uint8_t* buf, int len);
static int bs_write_bytes(bs_t* b, uint8_t* buf, int len);
static int bs_skip_bytes(bs_t* b, int len);
static uint32_t bs_next_bits(bs_t* b, int nbits);
// IMPLEMENTATIONstatic inline bs_t* bs_init(bs_t* b, uint8_t* buf, size_t size)
{b->start = buf;b->p = buf;b->end = buf + size;b->bits_left = 8;return b;
}static inline bs_t* bs_new(uint8_t* buf, size_t size)
{bs_t* b = (bs_t*)malloc(sizeof(bs_t));bs_init(b, buf, size);return b;
}static inline void bs_free(bs_t* b)
{free(b);
}static inline bs_t* bs_clone(bs_t* dest, const bs_t* src)
{dest->start = src->p;dest->p = src->p;dest->end = src->end;dest->bits_left = src->bits_left;return dest;
}static inline uint32_t bs_byte_aligned(bs_t* b)
{return (b->bits_left == 8);
}static inline int bs_eof(bs_t * b) { if (b->p >= b->end) { return 1; } else { return 0; } }static inline int bs_overrun(bs_t * b) { if (b->p > b->end) { return 1; } else { return 0; } }static inline int bs_pos(bs_t * b) { if (b->p > b->end) { return (b->end - b->start); } else { return (b->p - b->start); } }static inline int bs_bytes_left(bs_t * b) { return (b->end - b->p); }static inline uint32_t bs_read_u1(bs_t * b)
{uint32_t r = 0;b->bits_left--;if (!bs_eof(b)){r = ((*(b->p)) >> b->bits_left) & 0x01;}if (b->bits_left == 0) { b->p++; b->bits_left = 8; }return r;
}static inline void bs_skip_u1(bs_t * b)
{b->bits_left--;if (b->bits_left == 0) { b->p++; b->bits_left = 8; }
}static inline uint32_t bs_peek_u1(bs_t * b)
{uint32_t r = 0;if (!bs_eof(b)){r = ((*(b->p)) >> (b->bits_left - 1)) & 0x01;}return r;
}static inline uint32_t bs_read_u(bs_t * b, int n)
{uint32_t r = 0;int i;for (i = 0; i < n; i++){r |= (bs_read_u1(b) << (n - i - 1));}return r;
}static inline void bs_skip_u(bs_t * b, int n)
{int i;for (i = 0; i < n; i++){bs_skip_u1(b);}
}static inline uint32_t bs_read_f(bs_t * b, int n) { return bs_read_u(b, n); }static inline uint32_t bs_read_u8(bs_t * b)
{
#ifdef FAST_U8if (b->bits_left == 8 && !bs_eof(b)) // can do fast read{uint32_t r = b->p[0];b->p++;return r;}
#endifreturn bs_read_u(b, 8);
}static inline uint32_t bs_read_ue(bs_t * b)
{int32_t r = 0;int i = 0;while ((bs_read_u1(b) == 0) && (i < 32) && (!bs_eof(b))){i++;}r = bs_read_u(b, i);r += (1 << i) - 1;return r;
}static inline int32_t bs_read_se(bs_t * b)
{int32_t r = bs_read_ue(b);if (r & 0x01){r = (r + 1) / 2;}else{r = -(r / 2);}return r;
}static inline void bs_write_u1(bs_t * b, uint32_t v)
{b->bits_left--;if (!bs_eof(b)){// FIXME this is slow, but we must clear bit first// is it better to memset(0) the whole buffer during bs_init() instead? // if we don't do either, we introduce pretty nasty bugs(*(b->p)) &= ~(0x01 << b->bits_left);(*(b->p)) |= ((v & 0x01) << b->bits_left);}if (b->bits_left == 0) { b->p++; b->bits_left = 8; }
}static inline void bs_write_u(bs_t * b, int n, uint32_t v)
{int i;for (i = 0; i < n; i++){bs_write_u1(b, (v >> (n - i - 1)) & 0x01);}
}static inline void bs_write_f(bs_t * b, int n, uint32_t v) { bs_write_u(b, n, v); }static inline void bs_write_u8(bs_t * b, uint32_t v)
{
#ifdef FAST_U8if (b->bits_left == 8 && !bs_eof(b)) // can do fast write{b->p[0] = v;b->p++;return;}
#endifbs_write_u(b, 8, v);
}static inline void bs_write_ue(bs_t * b, uint32_t v)
{static const int len_table[256] ={1,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,};int len;if (v == 0){bs_write_u1(b, 1);}else{v++;if (v >= 0x01000000){len = 24 + len_table[v >> 24];}else if (v >= 0x00010000){len = 16 + len_table[v >> 16];}else if (v >= 0x00000100){len = 8 + len_table[v >> 8];}else{len = len_table[v];}bs_write_u(b, 2 * len - 1, v);}
}static inline void bs_write_se(bs_t * b, int32_t v)
{if (v <= 0){bs_write_ue(b, -v * 2);}else{bs_write_ue(b, v * 2 - 1);}
}static inline int bs_read_bytes(bs_t * b, uint8_t * buf, int len)
{int actual_len = len;if (b->end - b->p < actual_len) { actual_len = b->end - b->p; }if (actual_len < 0) { actual_len = 0; }memcpy(buf, b->p, actual_len);if (len < 0) { len = 0; }b->p += len;return actual_len;
}static inline int bs_write_bytes(bs_t * b, uint8_t * buf, int len)
{int actual_len = len;if (b->end - b->p < actual_len) { actual_len = b->end - b->p; }if (actual_len < 0) { actual_len = 0; }memcpy(b->p, buf, actual_len);if (len < 0) { len = 0; }b->p += len;return actual_len;
}static inline int bs_skip_bytes(bs_t * b, int len)
{int actual_len = len;if (b->end - b->p < actual_len) { actual_len = b->end - b->p; }if (actual_len < 0) { actual_len = 0; }if (len < 0) { len = 0; }b->p += len;return actual_len;
}static inline uint32_t bs_next_bits(bs_t * bs, int nbits)
{bs_t b;bs_clone(&b, bs);return bs_read_u(&b, nbits);
}static inline uint64_t bs_next_bytes(bs_t * bs, int nbytes)
{int i = 0;uint64_t val = 0;if ((nbytes > 8) || (nbytes < 1)) { return 0; }if (bs->p + nbytes > bs->end) { return 0; }for (i = 0; i < nbytes; i++) { val = (val << 8) | bs->p[i]; }return val;
}#define bs_print_state(b) fprintf( stderr,  "%s:%d@%s: b->p=0x%02hhX, b->left = %d\n", __FILE__, __LINE__, __FUNCTION__, *b->p, b->bits_left )
#ifdef __cplusplus
}
#endif
#endif

上面定义了很多读取的函数,主要看看bs_read_u1、bs_read_ue和bs_read_se这几个函数。

2.2.1 单比特读取函数(bs_read_u1)

static inline uint32_t bs_read_u1(bs_t * b)
{uint32_t r = 0;// 剩余比特数减1b->bits_left--;if (!bs_eof(b)) // 没有到文件尾部{r = ((*(b->p)) >> b->bits_left) & 0x01; // 取出下一个比特}// 如果剩余的比特数为0,则移动到下一个字节if (b->bits_left == 0) { b->p++; b->bits_left = 8; }return r;
}

2.2.2 指数哥伦布无符号编码(bs_read_ue)

指数哥伦布无符号编码参考别人的记录,其编码方式为 前缀(prefix) + 1 + 后缀(suffix),其中prefix都为0,suffix的长度和prefix长度一致,codeNum的计算方式为
c o d e N u m = 2 l e a d i n g Z e r o B i t s − 1 + r e a d b i t s ( l e a d i n g Z e r o B i t s ) codeNum=2^{leadingZeroBits}-1+read_bits(leadingZeroBits) codeNum=2leadingZeroBits1+readbits(leadingZeroBits)
在这里插入图片描述
例如 00111,前缀是2个0,分割是中间而对1,后缀是2个1,,计算的codeNum=2^2-1+3=6

static inline uint32_t bs_read_ue(bs_t * b)
{int32_t r = 0;int i = 0;// 检查前面有多少个0while ((bs_read_u1(b) == 0) && (i < 32) && (!bs_eof(b))){i++;}// 读取i个比特数r = bs_read_u(b, i);// codeNum = 2^leadingZeroBits - 1 + bs_read_u(b, i)r += (1 << i) - 1;return r;
}

2.2.3 指数哥伦布有符号编码(bs_read_se)

指数哥伦布有符号编码是基于无符号编码,使用指数哥伦布无符号编码计算出来的值输入到下面的公式中,计算有符号编码
C o d e N u m = ( − 1 ) k + 1 C e i l ( k 2 ) CodeNum=(-1)^{k+1}Ceil(\frac{k}{2}) CodeNum=(1)k+1Ceil(2k)

static inline int32_t bs_read_se(bs_t * b)
{int32_t r = bs_read_ue(b);if (r & 0x01){r = (r + 1) / 2;}else{r = -(r / 2);}return r;
}

2.3 H264码流定义头文件(h264_parser.h)

h264_parser.h文件的定义,主要内容包括:
(1)定义NAL、SLICE、AUD等宏信息
(2)定义pps、sps、slice header等结构体信息,这些结构体信息存储了具体的码流信息,在解析的时候会存储在这里
(3)定义读取结构体信息的函数,如read_seq_parameter_set等
(4)定义打印输出信息的函数,如debug_pps等

这里稍微修改了一些部分包括ChromaArrayType等,做了一些注释

#pragma once
#ifndef _H264_PARSER_H_
#define _H264_PARSER_H_#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include "base.h"
#include "bs.h"
#include "parser.h"#define BUFSIZE 32 * 1024 * 1024#define Extended_SAR 255//Table 7-1 NAL unit type codes
#define NAL_UNIT_TYPE_UNSPECIFIED                    0    // Unspecified
#define NAL_UNIT_TYPE_CODED_SLICE_NON_IDR            1    // Coded slice of a non-IDR picture
#define NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A   2    // Coded slice data partition A
#define NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_B   3    // Coded slice data partition B
#define NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_C   4    // Coded slice data partition C
#define NAL_UNIT_TYPE_CODED_SLICE_IDR                5    // Coded slice of an IDR picture
#define NAL_UNIT_TYPE_SEI                            6    // Supplemental enhancement information (SEI)
#define NAL_UNIT_TYPE_SPS                            7    // Sequence parameter set
#define NAL_UNIT_TYPE_PPS                            8    // Picture parameter set
#define NAL_UNIT_TYPE_AUD                            9    // Access unit delimiter
#define NAL_UNIT_TYPE_END_OF_SEQUENCE               10    // End of sequence
#define NAL_UNIT_TYPE_END_OF_STREAM                 11    // End of stream
#define NAL_UNIT_TYPE_FILLER                        12    // Filler data
#define NAL_UNIT_TYPE_SPS_EXT                       13    // Sequence parameter set extension// 14..18    // Reserved
#define NAL_UNIT_TYPE_CODED_SLICE_AUX               19    // Coded slice of an auxiliary coded picture without partitioning// 20..23    // Reserved// 24..31    // Unspecified//7.4.3 Table 7-6. Name association to slice_type
#define SH_SLICE_TYPE_P        0        // P (P slice)
#define SH_SLICE_TYPE_B        1        // B (B slice)
#define SH_SLICE_TYPE_I        2        // I (I slice)
#define SH_SLICE_TYPE_SP       3        // SP (SP slice)
#define SH_SLICE_TYPE_SI       4        // SI (SI slice)
//as per footnote to Table 7-6, the *_ONLY slice types indicate that all other slices in that picture are of the same type
#define SH_SLICE_TYPE_P_ONLY    5        // P (P slice)
#define SH_SLICE_TYPE_B_ONLY    6        // B (B slice)
#define SH_SLICE_TYPE_I_ONLY    7        // I (I slice)
#define SH_SLICE_TYPE_SP_ONLY   8        // SP (SP slice)
#define SH_SLICE_TYPE_SI_ONLY   9        // SI (SI slice)//7.4.2.4 Table 7-5 Meaning of primary_pic_type
#define AUD_PRIMARY_PIC_TYPE_I       0                // I
#define AUD_PRIMARY_PIC_TYPE_IP      1                // I, P
#define AUD_PRIMARY_PIC_TYPE_IPB     2                // I, P, B
#define AUD_PRIMARY_PIC_TYPE_SI      3                // SI
#define AUD_PRIMARY_PIC_TYPE_SISP    4                // SI, SP
#define AUD_PRIMARY_PIC_TYPE_ISI     5                // I, SI
#define AUD_PRIMARY_PIC_TYPE_ISIPSP  6                // I, SI, P, SP
#define AUD_PRIMARY_PIC_TYPE_ISIPSPB 7                // I, SI, P, SP, B//D.1 SEI payload syntax
#define SEI_TYPE_BUFFERING_PERIOD 0
#define SEI_TYPE_PIC_TIMING       1
#define SEI_TYPE_PAN_SCAN_RECT    2
#define SEI_TYPE_FILLER_PAYLOAD   3
#define SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35  4
#define SEI_TYPE_USER_DATA_UNREGISTERED  5
#define SEI_TYPE_RECOVERY_POINT   6
#define SEI_TYPE_DEC_REF_PIC_MARKING_REPETITION 7
#define SEI_TYPE_SPARE_PIC        8
#define SEI_TYPE_SCENE_INFO       9
#define SEI_TYPE_SUB_SEQ_INFO    10
#define SEI_TYPE_SUB_SEQ_LAYER_CHARACTERISTICS  11
#define SEI_TYPE_SUB_SEQ_CHARACTERISTICS  12
#define SEI_TYPE_FULL_FRAME_FREEZE  13
#define SEI_TYPE_FULL_FRAME_FREEZE_RELEASE  14
#define SEI_TYPE_FULL_FRAME_SNAPSHOT  15
#define SEI_TYPE_PROGRESSIVE_REFINEMENT_SEGMENT_START  16
#define SEI_TYPE_PROGRESSIVE_REFINEMENT_SEGMENT_END  17
#define SEI_TYPE_MOTION_CONSTRAINED_SLICE_GROUP_SET  18
#define SEI_TYPE_FILM_GRAIN_CHARACTERISTICS  19
#define SEI_TYPE_DEBLOCKING_FILTER_DISPLAY_PREFERENCE  20
#define SEI_TYPE_STEREO_VIDEO_INFO  21//Table 7-1 NAL unit type codes
#define NAL_UNIT_TYPE_UNSPECIFIED                    0    // Unspecified
#define NAL_UNIT_TYPE_CODED_SLICE_NON_IDR            1    // Coded slice of a non-IDR picture
#define NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A   2    // Coded slice data partition A
#define NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_B   3    // Coded slice data partition B
#define NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_C   4    // Coded slice data partition C
#define NAL_UNIT_TYPE_CODED_SLICE_IDR                5    // Coded slice of an IDR picture
#define NAL_UNIT_TYPE_SEI                            6    // Supplemental enhancement information (SEI)
#define NAL_UNIT_TYPE_SPS                            7    // Sequence parameter set
#define NAL_UNIT_TYPE_PPS                            8    // Picture parameter set
#define NAL_UNIT_TYPE_AUD                            9    // Access unit delimiter
#define NAL_UNIT_TYPE_END_OF_SEQUENCE               10    // End of sequence
#define NAL_UNIT_TYPE_END_OF_STREAM                 11    // End of stream
#define NAL_UNIT_TYPE_FILLER                        12    // Filler data
#define NAL_UNIT_TYPE_SPS_EXT                       13    // Sequence parameter set extension// 14..18    // Reserved
#define NAL_UNIT_TYPE_CODED_SLICE_AUX               19    // Coded slice of an auxiliary coded picture without partitioning// 20..23    // Reserved// 24..31    // Unspecifiedtypedef unsigned char uint8_t;typedef enum {NALU_TYPE_SLICE = 1,NALU_TYPE_DPA = 2,NALU_TYPE_DPB = 3,NALU_TYPE_DPC = 4,NALU_TYPE_IDR = 5,NALU_TYPE_SEI = 6,NALU_TYPE_SPS = 7,NALU_TYPE_PPS = 8,NALU_TYPE_AUD = 9,NALU_TYPE_EOSEQ = 10,NALU_TYPE_EOSTREAM = 11,NALU_TYPE_FILL = 12,
} NALU_TYPE;typedef enum {NALU_PRIORITY_DISPOSABLE = 0,NALU_PRIRITY_LOW = 1,NALU_PRIORITY_HIGH = 2,NALU_PRIORITY_HIGHEST = 3
} NALU_PRIORITY;// 下面的定义来自于2021年8月的ITU英文文档,中文文档更新的比较慢
typedef struct h264_nal
{int forbidden_zero_bit;int nal_ref_idc;int nal_unit_type;void* parsed; // FIXMEint sizeof_parsed;
} h264_nal_t;typedef struct h264_sei
{int payload_type;int payload_size;uint8_t* payload;
} h264_sei_t;typedef struct h264_sps {int profile_idc;int constraint_set0_flag;int constraint_set1_flag;int constraint_set2_flag;int constraint_set3_flag;int constraint_set4_flag;int constraint_set5_flag;int reserved_zero_2bits;		// u(2), equal to 0int level_idc;int seq_parameter_set_id;int chroma_format_idc;int separate_colour_plane_flag;int bit_depth_luma_minus8;int bit_depth_chroma_minus8;int qpprime_y_zero_transform_bypass_flag;int seq_scaling_matrix_present_flag;int seq_scaling_list_present_flag[12];int* ScalingList4x4[16];int UseDefaultScaningMatrix4x4Flag[6];int* ScalingList8x8[64];int UseDefaultScaningMatrix8x8Flag[6];int log2_max_frame_num_minus4;int pic_order_cnt_type;int log2_max_pic_order_cnt_lsb_minus4;int delta_pic_order_always_zero_flag;int offset_for_non_ref_pic;int offset_for_top_to_bottom_field;int num_ref_frames_in_pic_order_cnt_cycle;int offset_for_ref_frame[256];int max_num_ref_frames;int gaps_in_frame_num_value_allowed_flag;int pic_width_in_mbs_minus1;int pic_height_in_map_units_minus1;int frame_mbs_only_flag;int mb_adaptive_frame_field_flag;int direct_8x8_inference_flag;int frame_cropping_flag;int frame_crop_left_offset;int frame_crop_right_offset;int frame_crop_top_offset;int frame_crop_bottom_offset;int vui_parameters_present_flag;struct {int aspect_ratio_info_present_flag;int aspect_ratio_idc;int sar_width;int sar_height;int overscan_info_present_flag;int overscan_appropriate_flag;int video_signal_type_present_flag;int video_format;int video_full_range_flag;int colour_description_present_flag;int colour_primaries;int transfer_characteristics;int matrix_coefficients;int chroma_loc_info_present_flag;int chroma_sample_loc_type_top_field;int chroma_sample_loc_type_bottom_field;int timing_info_present_flag;int num_units_in_tick;int time_scale;int fixed_frame_rate_flag;int nal_hrd_parameters_present_flag;int vcl_hrd_parameters_present_flag;int low_delay_hrd_flag;int pic_struct_present_flag;int bitstream_restriction_flag;int motion_vectors_over_pic_boundaries_flag;int max_bytes_per_pic_denom;int max_bits_per_mb_denom;int log2_max_mv_length_horizontal;int log2_max_mv_length_vertical;int max_num_reorder_frames;int max_dec_frame_buffering;} vui;struct {int cpb_cnt_minus1;int bit_rate_scale;int cpb_size_scale;int bit_rate_value_minus1[32];int cpb_size_value_minus1[32];int cbr_flag[32];int initial_cpb_removal_delay_length_minus1;int cpb_removal_delay_length_minus1;int dpb_removal_delay_length_minus1;int time_offset_length;} hrd;// chroma array type// chroma_forma_idc = chroma_format_idc// 如果separate_colour_plane_flag为1,则ChromaArrayType为0int ChromaArrayType= 0; 
} h264_sps_t;typedef struct h264_pps {int pic_parameter_set_id;int seq_parameter_set_id;int entropy_coding_mode_flag;int bottom_field_pic_order_in_frame_present_flag;int num_slice_groups_minus1;int slice_group_map_type;int run_length_minus1[8];int top_left[8];int bottom_right[8];int slice_group_change_direction_flag;int slice_group_change_rate_minus1;int pic_size_in_map_units_minus1;int slice_group_id[256]; // 这里为什么是256?int num_ref_idx_l0_default_active_minus1;int num_ref_idx_l1_default_active_minus1;int weighted_pred_flag;int weighted_bipred_idc;int pic_init_qp_minus26;int pic_init_qs_minus26;int chroma_qp_index_offset;int deblocking_filter_control_present_flag;int constrained_intra_pred_flag;int redundant_pic_cnt_present_flag;// 是否有更多的数据int more_rbsp_data;int transform_8x8_mode_flag;int pic_scaling_matrix_present_flag;int pic_scaling_list_present_flag[12];int* ScalingList4x4[16];int UseDefaultScalingMatrix4x4[6];int* ScalingList8x8[64];int UseDefaultScalingMatrix8x8[6];int second_chroma_qp_index_offset;
} h264_pps_t;typedef struct h264_slice_header
{int first_mb_in_slice;int slice_type;int pic_parameter_set_id;int colour_plane_id;		// 雷博没有写这个字段int frame_num;int field_pic_flag;int bottom_field_flag;int idr_pic_id;int pic_order_cnt_lsb;int delta_pic_order_cnt_bottom;int delta_pic_order_cnt[2];int redundant_pic_cnt;int direct_spatial_mv_pred_flag;int num_ref_idx_active_override_flag;int num_ref_idx_l0_active_minus1;int num_ref_idx_l1_active_minus1;// ...// ref_pic_list_mvc_modification(),如果nal_type == 20或21时使用这个语法元素// 这里先不记录// ref pic list modification// 在雷博的文章中,记录的是 ref pic list reorder,但是新标准文档中似乎记录的是modificationstruct {int ref_pic_list_modification_flag_l0;int ref_pic_list_modification_flag_l1;// set array, what size?int modification_of_pic_nums_idc;int abs_diff_pic_num_minus1;int long_term_pic_num;} rplm;// predictive weight table struct {int luma_log2_weight_denom;int chroma_log2_weight_denom;int luma_weight_l0_flag[64];int luma_weight_l0[64];int luma_offset_l0[64];int chroma_weight_l0_flag[64];int chroma_weight_l0[64][2];int chroma_offset_l0[64][2];int luma_weight_l1_flag[64];int luma_weight_l1[64];int luma_offset_l1[64];int chroma_weight_l1_flag[64];int chroma_weight_l1[64][2];int chroma_offset_l1[64][2];} pwt;// dec ref pic markingstruct {int no_output_of_prior_pics_flag;int long_term_reference_flag;int adaptive_ref_pic_marking_mode_flag;// set arrayint memory_management_control_operation;int difference_of_pic_nums_minus1;int long_term_pic_num;int long_term_frame_idx;int max_long_term_frame_idx_plus1;} drpm;int cabac_init_idc;int slice_qp_delta;int sp_for_switch_flag;int slice_qs_delta;int disable_deblocking_filter_idc;int slice_alpha_c0_offset_div2;int slice_beta_offset_div2;int slice_group_change_cycle;
} h264_slice_header_t;typedef struct h264_aud
{int primary_pic_type;
} h264_aud_t;typedef struct h264_slice_data_rbsp
{int rbsp_size;uint8_t* rbsp_buf;
} h264_slice_data_rbsp_t;typedef struct
{h264_nal_t* nal;h264_sps_t* sps;h264_pps_t* pps;h264_aud_t* aud;h264_sei_t* sei; //This is a TEMP pointer at whats in h->seis...    int num_seis;h264_slice_header_t* sh;h264_slice_data_rbsp_t* slice_data;h264_sps_t* sps_table[32];h264_pps_t* pps_table[256];h264_sei_t** seis;} h264_stream_t;h264_stream_t* h264_new();
void h264_free(h264_stream_t* h);int find_nal_unit(uint8_t* buf, int size, int* nal_start, int* nal_end);
int nal_to_rbsp(const uint8_t* nal_buf, int* nal_size, uint8_t* rbsp_buf, int* rbsp_size);// 7.3.1 NAL unit syntax
void read_nal_unit(h264_stream_t* h, uint8_t* buf, int size);// 7.3.2.1 Sequence parameter set data syntax
void read_sequence_parameter_set_rbsp(h264_stream_t* h, bs_t* b);// 7.3.2.1.1 Scaling list syntax syntax
void read_scaling_list(bs_t* b, int* scaling_list, int size, int use_default_scaling_matrix_flag);// 7.3.2.2 Picture parameter set RBSP syntax
void read_picture_parameter_set_rbsp(h264_stream_t* h, bs_t* b);// 7.3.2.3 Supplemental enhancement information RBSP syntax
void read_sei_rbsp(h264_stream_t* h, bs_t* b);// 7.3.2.3.1 Supplemental enhancement information message syntax
void read_sei_message(h264_stream_t* h, bs_t* b);// 7.3.2.8 Slice layer without partitioning RBSP syntax
void read_slice_layer_rbsp(h264_stream_t* h, bs_t* b);// 7.3.2.10 RBSP slice trailing bits syntax
void read_rbsp_slice_trailing_bits(h264_stream_t* h, bs_t* b);// 7.3.2.11 RBSP trailing bits bits syntax
void read_rbsp_trailing_bits(h264_stream_t* h, bs_t* b);// 7.3.3 Slice header syntax
void read_slice_header(h264_stream_t* h, bs_t* b);// 7.3.3.1 Reference picture list modification syntax
void read_ref_pic_list_modification(h264_stream_t* h, bs_t* b);// 7.3.3.2 Prediction weight table syntax
void read_pred_weight_table(h264_stream_t* h, bs_t* b);// 7.3.3.3 Decoded refernece picture marking syntax
void read_dec_ref_pic_marking(h264_stream_t* h, bs_t* b);// D.1 SEI payload syntax
void read_sei_payload(h264_stream_t* h, bs_t* b, int payloadType, int payloadSize);// E.1.1 VUI parameters syntax
void read_vui_parameters(h264_stream_t* h, bs_t* b);// E.1.2 HRD parameters syntax
void read_hrd_parameters(h264_stream_t* h, bs_t* b);// debug info
void debug_nal(h264_stream_t* h, h264_nal_t* nal);
void debug_sps(h264_stream_t* h);
void debug_pps(h264_stream_t* h);
void debug_slice_header(h264_stream_t* h);
void debug_aud(h264_stream_t* h);
void debug_seis(h264_stream_t* h);
void debug_bytes(uint8_t* buf, int len);#endif // !_H264_PARSER_H_

3.cpp文件

3.1 H264分析(h264_parser.cpp)

函数定义了具体如何读取sps、pps和slice header当中的信息,可以参考2021年8月的H264标准中定义的语法元素

#include "h264_parser.h"/**Calculate the log base 2 of the argument, rounded up.Zero or negative arguments return zeroIdea from http://www.southwindsgames.com/blog/2009/01/19/fast-integer-log2-function-in-cc/*/
int intlog2(int x)
{int log = 0;if (x < 0) { x = 0; }while ((x >> log) > 0){log++;}if (log > 0 && x == 1 << (log - 1)) { log--; }return log;
}h264_stream_t* h264_new()
{h264_stream_t* h = (h264_stream_t*)calloc(1, sizeof(h264_stream_t));h->nal = (h264_nal_t*)calloc(1, sizeof(h264_nal_t));// initialize tablesfor (int i = 0; i < 32; i++) { h->sps_table[i] = (h264_sps_t*)calloc(1, sizeof(h264_sps_t)); }for (int i = 0; i < 256; i++) { h->pps_table[i] = (h264_pps_t*)calloc(1, sizeof(h264_pps_t)); }h->sps = h->sps_table[0];h->pps = h->pps_table[0];h->aud = (h264_aud_t*)calloc(1, sizeof(h264_aud_t));h->num_seis = 0;h->seis = NULL;h->sei = NULL;  //This is a TEMP pointer at whats in h->seis...h->sh = (h264_slice_header_t*)calloc(1, sizeof(h264_slice_header_t));return h;
}void sei_free(h264_sei_t* s)
{if (s->payload != NULL) free(s->payload);free(s);
}void h264_free(h264_stream_t * h)
{free(h->nal);for (int i = 0; i < 32; i++) { free(h->sps_table[i]); }for (int i = 0; i < 256; i++) { free(h->pps_table[i]); }free(h->aud);if (h->seis != NULL){for (int i = 0; i < h->num_seis; i++){h264_sei_t* sei = h->seis[i];sei_free(sei);}free(h->seis);}free(h->sh);free(h);
}int _read_ff_coded_number(bs_t* b)
{int n1 = 0;int n2;do{n2 = bs_read_u8(b);n1 += n2;} while (n2 == 0xff);return n1;
}void read_sei_end_bits(h264_stream_t * h, bs_t * b)
{// if the message doesn't end at a byte borderif (!bs_byte_aligned(b)){if (!bs_read_u1(b))//fprintf(stderr, "WARNING: bit_equal_to_one is 0!!!!\n");ERROR("WARNING: bit_equal_to_one is 0");while (!bs_byte_aligned(b)){if (bs_read_u1(b))// fprintf(stderr, "WARNING: bit_equal_to_zero is 1!!!!\n");ERROR("WARNING: bit_equal_to_zero is 1");}}read_rbsp_trailing_bits(h, b);
}
// 这里减去5,是为了将format对齐。在ffmpeg中,使用的是%5
int is_slice_type(int slice_type, int cmp_type)
{if (slice_type >= 5) { slice_type -= 5; }if (cmp_type >= 5) { cmp_type -= 5; }if (slice_type == cmp_type) { return 1; }else { return 0; }
}// 7.3.1 Nal unit syntax
void read_nal_unit(h264_stream_t* h, uint8_t* buf, int size)
{h264_nal_t* nal = h->nal;bs_t* b = bs_new(buf, size);nal->forbidden_zero_bit = bs_read_f(b, 1);nal->nal_ref_idc = bs_read_u(b, 2);nal->nal_unit_type = bs_read_u(b, 5);nal->parsed = NULL;nal->sizeof_parsed = 0;bs_free(b);int nal_size = size;int rbsp_size = size;uint8_t* rbsp_buf = (uint8_t*)malloc(rbsp_size);// 在rbsp中,存在0x000003这样的分段码,函数会去掉这个分段码,将数据放到rbsp_buf中int rc = nal_to_rbsp(buf, &nal_size, rbsp_buf, &rbsp_size);if (rc < 0) {ERROR("transfer nal to rbsp failed");free(rbsp_buf);return;} // handle conversion errorb = bs_new(rbsp_buf, rbsp_size);switch (nal->nal_unit_type){/*if nal_unit_type == 14 || nal_unit_type == 20 || nal_unit_type == 21{if (nal_unit_type != 21){svc_extension_flag; }else {avc_3d_extension_flag; // specified in Annex J}if (svc_extension_flag){nal_unit_header_svc_extension(); // specified in Annex G}else if (avc_3d_extension_flag){nal_unit_header_3davc_extension(); // specified in Annex J} else{nal_unit_header_mvc_extension(); // specified in Annex H}}*/case NAL_UNIT_TYPE_CODED_SLICE_IDR:case NAL_UNIT_TYPE_CODED_SLICE_NON_IDR:case NAL_UNIT_TYPE_CODED_SLICE_AUX://printf("find slice\n");read_slice_layer_rbsp(h, b);break;case NAL_UNIT_TYPE_SPS://printf("find sps\n");read_sequence_parameter_set_rbsp(h, b);break;case NAL_UNIT_TYPE_PPS://printf("find pps\n");read_picture_parameter_set_rbsp(h, b);break;case NAL_UNIT_TYPE_SEI://printf("find sei\n");read_sei_rbsp(h, b);break;};
}// 7.3.2.1 Sequence parameter set RBSP syntax
void read_sequence_parameter_set_rbsp(h264_stream_t* h, bs_t* b)
{int profile_idc = bs_read_u(b, 8);int constraint_set0_flag = bs_read_u1(b);int constraint_set1_flag = bs_read_u1(b);int constraint_set2_flag = bs_read_u1(b);int constraint_set3_flag = bs_read_u1(b);int constraint_set4_flag = bs_read_u1(b);int constraint_set5_flag = bs_read_u1(b);int reserved_zero_2bits = bs_read_u(b, 2);int level_idc = bs_read_u8(b);int seq_parameter_set_id = bs_read_ue(b);// 当编码器产生新的序列集时,应该使用新的seq_parameter_set_id// 即使用新的序列参数集,而不是改变原有sps的信息,这在视频源切换的情况下会出现h->sps = h->sps_table[seq_parameter_set_id];h264_sps_t* sps = h->sps;memset(sps, 0, sizeof(h264_sps_t));sps->profile_idc = profile_idc;sps->constraint_set0_flag = constraint_set0_flag;sps->constraint_set1_flag = constraint_set1_flag;sps->constraint_set2_flag = constraint_set2_flag;sps->constraint_set3_flag = constraint_set3_flag;sps->constraint_set4_flag = constraint_set4_flag;sps->constraint_set5_flag = constraint_set5_flag;sps->reserved_zero_2bits = reserved_zero_2bits;sps->level_idc = level_idc;sps->seq_parameter_set_id = seq_parameter_set_id;// 根据profile idc确定sps的一些参数if (profile_idc == 100 || // High profileprofile_idc == 110 || // High10 profileprofile_idc == 122 || // High422 profileprofile_idc == 244 || // High444 Predictive profileprofile_idc == 44  || // Cavlc444 profileprofile_idc == 83  || // Scalable Constrained High profile (SVC)profile_idc == 86  || // Scalable High Intra profile (SVC)profile_idc == 118 || // Stereo High profile (MVC)profile_idc == 128 || // Multiview High profile (MVC)profile_idc == 138 || // Multiview Depth High profile (MVCD)profile_idc == 139 || // High444 Intraprofile_idc == 134 || // High10 Intraprofile_idc == 135)	  // High422 Intra{sps->chroma_format_idc = bs_read_ue(b);sps->ChromaArrayType = sps->chroma_format_idc;if (sps->chroma_format_idc == 3){sps->separate_colour_plane_flag = bs_read_u1(b);if (sps->separate_colour_plane_flag){sps->ChromaArrayType = 0;}}sps->bit_depth_luma_minus8 = bs_read_ue(b);sps->bit_depth_chroma_minus8 = bs_read_ue(b);sps->qpprime_y_zero_transform_bypass_flag = bs_read_u1(b);sps->seq_scaling_matrix_present_flag = bs_read_u1(b);if (sps->seq_scaling_matrix_present_flag){for (int i = 0; i < ((sps->chroma_format_idc != 3) ? 8 : 12); i++){sps->seq_scaling_list_present_flag[i] = bs_read_u1(b);if (sps->seq_scaling_list_present_flag[i]){if (i < 6){read_scaling_list(b, sps->ScalingList4x4[i], 16, sps->UseDefaultScaningMatrix4x4Flag[i]);}else{read_scaling_list(b, sps->ScalingList8x8[i - 6], 64, sps->UseDefaultScaningMatrix8x8Flag[i]);}}}}}sps->log2_max_frame_num_minus4 = bs_read_ue(b);sps->pic_order_cnt_type = bs_read_ue(b);if (sps->pic_order_cnt_type == 0){sps->log2_max_pic_order_cnt_lsb_minus4 = bs_read_ue(b);}else if (sps->pic_order_cnt_type == 1){sps->delta_pic_order_always_zero_flag = bs_read_u1(b);sps->offset_for_non_ref_pic = bs_read_se(b);sps->offset_for_top_to_bottom_field = bs_read_se(b);sps->num_ref_frames_in_pic_order_cnt_cycle = bs_read_ue(b);for (int i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++){sps->offset_for_ref_frame[i] = bs_read_se(b);}}sps->max_num_ref_frames = bs_read_ue(b);sps->gaps_in_frame_num_value_allowed_flag = bs_read_u1(b);sps->pic_width_in_mbs_minus1 = bs_read_ue(b);sps->pic_height_in_map_units_minus1 = bs_read_ue(b);sps->frame_mbs_only_flag = bs_read_u1(b);if (!sps->frame_mbs_only_flag){sps->mb_adaptive_frame_field_flag = bs_read_u1(b);}sps->direct_8x8_inference_flag = bs_read_u1(b);sps->frame_cropping_flag = bs_read_u1(b);if (sps->frame_cropping_flag){sps->frame_crop_left_offset = bs_read_ue(b);sps->frame_crop_right_offset = bs_read_ue(b);sps->frame_crop_top_offset = bs_read_ue(b);sps->frame_crop_bottom_offset = bs_read_ue(b);}sps->vui_parameters_present_flag = bs_read_u1(b);// vui infoif (sps->vui_parameters_present_flag){read_vui_parameters(h, b);}// trailing bitsread_rbsp_trailing_bits(h, b);
}// 7.3.2.1.1 Scaling list syntax syntax
void read_scaling_list(bs_t* b, int* scaling_list, int size, int use_default_scaling_matrix_flag)
{int last_scale = 8;int next_scale = 8;int delta_scale = 0;for (int j = 0; j < size; j++){if (next_scale != 0){delta_scale = bs_read_se(b);next_scale = (last_scale + delta_scale + 256) % 256;use_default_scaling_matrix_flag = (j == 0 && next_scale == 0);}scaling_list[j] = (next_scale == 0) ? last_scale : next_scale;last_scale = scaling_list[j];}
}// E.1.1 VUI parameters syntax
void read_vui_parameters(h264_stream_t* h, bs_t* b)
{h264_sps* sps = h->sps;sps->vui.aspect_ratio_info_present_flag = bs_read_u1(b);if (sps->vui.aspect_ratio_info_present_flag){sps->vui.aspect_ratio_idc = bs_read_u8(b);if (sps->vui.aspect_ratio_idc == Extended_SAR){sps->vui.sar_width = bs_read_u(b, 16);sps->vui.sar_height = bs_read_u(b, 16);}}sps->vui.overscan_info_present_flag = bs_read_u1(b);if (sps->vui.overscan_info_present_flag){sps->vui.overscan_appropriate_flag = bs_read_u1(b);}sps->vui.video_signal_type_present_flag = bs_read_u1(b);if (sps->vui.video_signal_type_present_flag){sps->vui.video_format = bs_read_u(b, 3);sps->vui.video_full_range_flag = bs_read_u1(b);sps->vui.colour_description_present_flag = bs_read_u1(b);if (sps->vui.colour_description_present_flag){sps->vui.colour_primaries = bs_read_u8(b);sps->vui.transfer_characteristics = bs_read_u8(b);sps->vui.matrix_coefficients = bs_read_u8(b);}}sps->vui.chroma_loc_info_present_flag = bs_read_u1(b);if (sps->vui.chroma_loc_info_present_flag){sps->vui.chroma_sample_loc_type_top_field = bs_read_ue(b);sps->vui.chroma_sample_loc_type_bottom_field = bs_read_ue(b);}sps->vui.timing_info_present_flag = bs_read_u1(b);if (sps->vui.timing_info_present_flag){sps->vui.num_units_in_tick = bs_read_u(b, 32);sps->vui.time_scale = bs_read_u(b, 32);sps->vui.fixed_frame_rate_flag = bs_read_u(b, 1);}// hrd infosps->vui.nal_hrd_parameters_present_flag = bs_read_u1(b);if (sps->vui.nal_hrd_parameters_present_flag){read_hrd_parameters(h, b);}// vcl infosps->vui.vcl_hrd_parameters_present_flag = bs_read_u1(b);if (sps->vui.vcl_hrd_parameters_present_flag){read_hrd_parameters(h, b); // why hrd?}if (sps->vui.nal_hrd_parameters_present_flag || sps->vui.vcl_hrd_parameters_present_flag){sps->vui.low_delay_hrd_flag = bs_read_u1(b);}sps->vui.pic_struct_present_flag = bs_read_u1(b);sps->vui.bitstream_restriction_flag = bs_read_u1(b);if (sps->vui.bitstream_restriction_flag){sps->vui.motion_vectors_over_pic_boundaries_flag = bs_read_u1(b);sps->vui.max_bytes_per_pic_denom = bs_read_ue(b);sps->vui.max_bits_per_mb_denom = bs_read_ue(b);sps->vui.log2_max_mv_length_horizontal = bs_read_ue(b);sps->vui.log2_max_mv_length_vertical = bs_read_ue(b);sps->vui.max_num_reorder_frames = bs_read_ue(b);sps->vui.max_dec_frame_buffering = bs_read_ue(b);}
}// E.1.2 HRD parameters syntax
void read_hrd_parameters(h264_stream_t* h, bs_t* b)
{h264_sps* sps = h->sps;sps->hrd.cpb_cnt_minus1 = bs_read_ue(b);sps->hrd.bit_rate_scale = bs_read_u(b, 4);sps->hrd.cpb_size_scale = bs_read_u(b, 4);for (int sched_sel_idx = 0; sched_sel_idx <= sps->hrd.cpb_cnt_minus1; sched_sel_idx++){sps->hrd.bit_rate_value_minus1[sched_sel_idx] = bs_read_ue(b);sps->hrd.cpb_size_value_minus1[sched_sel_idx] = bs_read_ue(b);sps->hrd.cbr_flag[sched_sel_idx] = bs_read_u1(b);}sps->hrd.initial_cpb_removal_delay_length_minus1 = bs_read_u(b, 5);sps->hrd.cpb_removal_delay_length_minus1 = bs_read_u(b, 5);sps->hrd.dpb_removal_delay_length_minus1 = bs_read_u(b, 5);sps->hrd.time_offset_length = bs_read_u(b, 5);
}int more_rbsp_data(h264_stream_t * h, bs_t * b)
{// 雷博原有的代码有bug,这里无法正确解析后面到来的data//if (bs_eof(b)) { return 0; }//if (bs_peek_u1(b) == 1) { return 0; } // if next bit is 1, we've reached the stop bit//return 1;// see FFmpeg h264_ps.cint profile_idc = h->sps->profile_idc;int constraint_set_flags = 0;constraint_set_flags |= h->sps->constraint_set0_flag << 0;   // constraint_set0_flagconstraint_set_flags |= h->sps->constraint_set1_flag << 1;   // constraint_set1_flagconstraint_set_flags |= h->sps->constraint_set2_flag << 2;   // constraint_set2_flagconstraint_set_flags |= h->sps->constraint_set3_flag << 3;   // constraint_set3_flagconstraint_set_flags |= h->sps->constraint_set4_flag << 4;   // constraint_set4_flagconstraint_set_flags |= h->sps->constraint_set5_flag << 5;   // constraint_set5_flagif ((profile_idc == 66 || profile_idc == 77 ||profile_idc == 88) && (constraint_set_flags & 7)) {ERROR("Current profile doesn't provide more RBSP data in PPS, skipping");return 0;}return 1;
}// 7.3.2.2 Picture parameter set RBSP syntax
void read_picture_parameter_set_rbsp(h264_stream_t* h, bs_t* b)
{int pps_id = bs_read_ue(b);h264_pps_t* pps = h->pps = h->pps_table[pps_id];memset(pps, 0, sizeof(h264_pps_t));pps->pic_parameter_set_id = pps_id;pps->seq_parameter_set_id = bs_read_ue(b);pps->entropy_coding_mode_flag = bs_read_u1(b);pps->bottom_field_pic_order_in_frame_present_flag = bs_read_u1(b);pps->num_slice_groups_minus1 = bs_read_ue(b);if (pps->num_slice_groups_minus1 > 0){pps->slice_group_map_type = bs_read_ue(b);if (pps->slice_group_map_type == 0){for (int i_group = 0; i_group <= pps->num_slice_groups_minus1; i_group++){pps->run_length_minus1[i_group] = bs_read_ue(b);}}else if (pps->slice_group_map_type == 2){for (int i_group = 0; i_group <= pps->num_slice_groups_minus1; i_group++){pps->top_left[i_group] = bs_read_ue(b);pps->bottom_right[i_group] = bs_read_ue(b);}}else if (pps->slice_group_map_type == 3 || pps->slice_group_map_type == 4 || pps->slice_group_map_type == 5){pps->slice_group_change_direction_flag = bs_read_u1(b);pps->slice_group_change_rate_minus1 = bs_read_ue(b);}else if (pps->slice_group_map_type == 6){pps->pic_size_in_map_units_minus1 = bs_read_ue(b);for (int i = 0; i <= pps->pic_size_in_map_units_minus1; i++){pps->slice_group_id[i] = bs_read_u(b, intlog2(pps->num_slice_groups_minus1 + 1)); // reaplace u(v)}}}pps->num_ref_idx_l0_default_active_minus1 = bs_read_ue(b);pps->num_ref_idx_l1_default_active_minus1 = bs_read_ue(b);pps->weighted_pred_flag = bs_read_u1(b);pps->weighted_bipred_idc = bs_read_u(b, 2);pps->pic_init_qp_minus26 = bs_read_se(b);pps->pic_init_qs_minus26 = bs_read_se(b);pps->chroma_qp_index_offset = bs_read_se(b);pps->deblocking_filter_control_present_flag = bs_read_u1(b);pps->constrained_intra_pred_flag = bs_read_u1(b);pps->redundant_pic_cnt_present_flag = bs_read_u1(b);pps->more_rbsp_data = more_rbsp_data(h, b);if (pps->more_rbsp_data){pps->transform_8x8_mode_flag = bs_read_u1(b);pps->pic_scaling_matrix_present_flag = bs_read_u1(b);if (pps->pic_scaling_matrix_present_flag){for (int i = 0; i < 6 + ((h->sps->chroma_format_idc != 3) ? 2 : 6) * pps->transform_8x8_mode_flag; i++){pps->pic_scaling_list_present_flag[i] = bs_read_u1(b);if (pps->pic_scaling_list_present_flag){if (i < 6){read_scaling_list(b, pps->ScalingList4x4[i], 16, pps->UseDefaultScalingMatrix4x4[i]);}else{read_scaling_list(b, pps->ScalingList8x8[i - 6], 64, pps->UseDefaultScalingMatrix8x8[i - 6]);}}}}pps->second_chroma_qp_index_offset = bs_read_se(b);}read_rbsp_trailing_bits(h, b);
}// 7.3.2.3 Supplemental enhancement information RBSP syntax
void read_sei_rbsp(h264_stream_t * h, bs_t * b)
{int i;for (i = 0; i < h->num_seis; i++){sei_free(h->seis[i]);}h->num_seis = 0;do {h->num_seis++;h->seis = (h264_sei_t * *)realloc(h->seis, h->num_seis * sizeof(h264_sei_t*));// sei newh264_sei_t* s = (h264_sei_t*)malloc(sizeof(h264_sei_t));memset(s, 0, sizeof(h264_sei_t));s->payload = NULL;h->seis[h->num_seis - 1] = s;h->sei = h->seis[h->num_seis - 1];read_sei_message(h, b);} while (!(bs_eof(b) || bs_peek_u1(b) == 1)); // 检查是否有更多数据read_rbsp_trailing_bits(h, b);
}// 7.3.2.3.1 Supplemental enhancement information message syntax
void read_sei_message(h264_stream_t* h, bs_t* b)
{h->sei->payload_type = _read_ff_coded_number(b);h->sei->payload_size = _read_ff_coded_number(b);read_sei_payload(h, b, h->sei->payload_type, h->sei->payload_size);
}// D.1 SEI payload syntax
void read_sei_payload(h264_stream_t* h, bs_t* b, int payloadType, int payloadSize)
{h264_sei_t* s = h->sei;s->payload = (uint8_t*)malloc(payloadSize);int i;for (i = 0; i < payloadSize; i++)s->payload[i] = bs_read_u(b, 8);read_sei_end_bits(h, b);
}// 7.3.2.8 Slice layer without partitioning RBSP syntax
void read_slice_layer_rbsp(h264_stream_t* h, bs_t* b)
{read_slice_header(h, b);h264_slice_data_rbsp_t* slice_data = h->slice_data;if (slice_data != NULL){if (slice_data->rbsp_buf != NULL) free(slice_data->rbsp_buf);uint8_t * sptr = b->p + (!!b->bits_left); // CABAC-specific: skip alignment bits, if there are anyslice_data->rbsp_size = b->end - sptr;slice_data->rbsp_buf = (uint8_t*)malloc(slice_data->rbsp_size);memcpy(slice_data->rbsp_buf, sptr, slice_data->rbsp_size);// ugly hack: since next NALU starts at byte border, we are going to be padded by trailing_bits;return;}// FIXME should read or skip data//slice_data( ); /* all categories of slice_data( ) syntax */read_rbsp_slice_trailing_bits(h, b);
}// 7.3.2.10 RBSP slice trailing bits syntax
void read_rbsp_slice_trailing_bits(h264_stream_t* h, bs_t* b)
{read_rbsp_trailing_bits(h, b);int cabac_zero_word;if (h->pps->entropy_coding_mode_flag){while (!bs_eof(b)){cabac_zero_word = bs_read_f(b, 16); // equal to 0x0000}}
}// 7.3.2.11 RBSP trailing bits syntax
void read_rbsp_trailing_bits(h264_stream_t * h, bs_t * b)
{int rbsp_stop_one_bit = bs_read_f(b, 1); // equal to 1while (!bs_byte_aligned(b)){int rbsp_alignment_zero_bit = bs_read_f(b, 1); // equal to 0}
}// 7.3.3 Slice header syntax
void read_slice_header(h264_stream_t* h, bs_t* b)
{h264_slice_header_t* sh = h->sh;memset(sh, 0, sizeof(h264_slice_header_t));h264_sps_t* sps = h->sps; // h->sps;h264_pps_t* pps = h->pps;//h->pps;h264_nal_t* nal = h->nal;sh->first_mb_in_slice = bs_read_ue(b);sh->slice_type = bs_read_ue(b);sh->pic_parameter_set_id = bs_read_ue(b);if (h->sps->separate_colour_plane_flag == 1){sh->colour_plane_id = bs_read_u(b, 2);}sh->frame_num = bs_read_u(b, sps->log2_max_frame_num_minus4 + 4); // was u(v)if (!h->sps->frame_mbs_only_flag){sh->field_pic_flag = bs_read_u1(b);if (sh->field_pic_flag){sh->bottom_field_flag = bs_read_u1(b);}}if (nal->nal_unit_type == 5){sh->idr_pic_id = bs_read_ue(b);}if (h->sps->pic_order_cnt_type == 0){// sh->pic_order_cnt_lsb_bytes = sps->log2_max_pic_order_cnt_lsb_minus4 + 4;// sh->pic_order_cnt_lsb = bs_read_u(b, sh->pic_order_cnt_lsb_bytes); // was u(v)// sh->pic_order_cnt_lsb = bs_read_u(b, sps->log2_max_frame_num_minus4 + 4);sh->pic_order_cnt_lsb = bs_read_u(b, sps->log2_max_pic_order_cnt_lsb_minus4 + 4); // was u(v)if (h->pps->bottom_field_pic_order_in_frame_present_flag && !sh->field_pic_flag){sh->delta_pic_order_cnt_bottom = bs_read_se(b);}}if (h->sps->pic_order_cnt_type == 1 && !h->sps->delta_pic_order_always_zero_flag){sh->delta_pic_order_cnt[0] = bs_read_se(b);if (h->pps->bottom_field_pic_order_in_frame_present_flag && !sh->field_pic_flag){sh->delta_pic_order_cnt[1] = bs_read_se(b);}}if (h->pps->redundant_pic_cnt_present_flag){sh->redundant_pic_cnt = bs_read_ue(b);}if (is_slice_type(h->sh->slice_type, SH_SLICE_TYPE_B)){sh->direct_spatial_mv_pred_flag = bs_read_u1(b);}if (is_slice_type(h->sh->slice_type, SH_SLICE_TYPE_P) || is_slice_type(h->sh->slice_type, SH_SLICE_TYPE_SP) || is_slice_type(h->sh->slice_type, SH_SLICE_TYPE_B)){sh->num_ref_idx_active_override_flag = bs_read_u1(b);if (sh->num_ref_idx_active_override_flag){sh->num_ref_idx_l0_active_minus1 = bs_read_ue(b);if (is_slice_type(h->sh->slice_type, SH_SLICE_TYPE_B)){sh->num_ref_idx_l1_active_minus1 = bs_read_ue(b);}}}if (h->nal->nal_unit_type == 20 || h->nal->nal_unit_type == 21){// ref_pic_list_mvc_modification}else // rplm {read_ref_pic_list_modification(h, b);}// pwtif ((pps->weighted_pred_flag && (is_slice_type(sh->slice_type, SH_SLICE_TYPE_P) || is_slice_type(sh->slice_type, SH_SLICE_TYPE_SP))) ||(pps->weighted_bipred_idc == 1 && is_slice_type(sh->slice_type, SH_SLICE_TYPE_B))){read_pred_weight_table(h, b);}if (h->nal->nal_ref_idc != 0){read_dec_ref_pic_marking(h, b);}if (pps->entropy_coding_mode_flag && !is_slice_type(sh->slice_type, SH_SLICE_TYPE_I) && !is_slice_type(sh->slice_type, SH_SLICE_TYPE_SI)){sh->cabac_init_idc = bs_read_ue(b);}sh->slice_qp_delta = bs_read_se(b);if (is_slice_type(sh->slice_type, SH_SLICE_TYPE_SP) || is_slice_type(sh->slice_type, SH_SLICE_TYPE_SI)){if (is_slice_type(sh->slice_type, SH_SLICE_TYPE_SP)){sh->sp_for_switch_flag = bs_read_u1(b);}sh->slice_qs_delta = bs_read_se(b);}if (pps->deblocking_filter_control_present_flag){sh->disable_deblocking_filter_idc = bs_read_ue(b);if (sh->disable_deblocking_filter_idc != 1){sh->slice_alpha_c0_offset_div2 = bs_read_se(b);sh->slice_beta_offset_div2 = bs_read_se(b);}}if (pps->num_slice_groups_minus1 > 0 &&pps->slice_group_map_type >= 3 && pps->slice_group_map_type <= 5){sh->slice_group_change_cycle = bs_read_u(b, intlog2(pps->pic_size_in_map_units_minus1 +pps->slice_group_change_rate_minus1 + 1));}
}// 7.3.3.1 Reference picture list modification syntax 
void read_ref_pic_list_modification(h264_stream_t * h, bs_t * b)
{h264_slice_header* sh = h->sh;int i = 0;if (!is_slice_type(sh->slice_type, SH_SLICE_TYPE_I) && !is_slice_type(sh->slice_type, SH_SLICE_TYPE_SI)){sh->rplm.ref_pic_list_modification_flag_l0 = bs_read_u1(b);if (sh->rplm.ref_pic_list_modification_flag_l0){do{sh->rplm.modification_of_pic_nums_idc = bs_read_ue(b);if (sh->rplm.modification_of_pic_nums_idc == 0 ||sh->rplm.modification_of_pic_nums_idc == 1){sh->rplm.abs_diff_pic_num_minus1 = bs_read_ue(b);}else if (sh->rplm.modification_of_pic_nums_idc == 2){sh->rplm.long_term_pic_num = bs_read_ue(b);}} while (sh->rplm.modification_of_pic_nums_idc != 3 && ! bs_eof(b));}}i = 0;if (is_slice_type(sh->slice_type, SH_SLICE_TYPE_B)){sh->rplm.ref_pic_list_modification_flag_l1 = bs_read_u1(b);if (sh->rplm.ref_pic_list_modification_flag_l1){do{sh->rplm.modification_of_pic_nums_idc = bs_read_ue(b);if (sh->rplm.modification_of_pic_nums_idc == 0 ||sh->rplm.modification_of_pic_nums_idc == 1){sh->rplm.abs_diff_pic_num_minus1 = bs_read_ue(b);}else if (sh->rplm.modification_of_pic_nums_idc == 2){sh->rplm.long_term_pic_num = bs_read_ue(b);}} while (sh->rplm.modification_of_pic_nums_idc != 3 && !bs_eof(b));}}
}// 7.3.3.2 Prediction weight table syntax
void read_pred_weight_table(h264_stream_t * h, bs_t * b)
{h264_slice_header_t* sh = h->sh;h264_sps_t* sps = h->sps;h264_pps_t* pps = h->pps;int i, j;sh->pwt.luma_log2_weight_denom = bs_read_ue(b);if (sps->ChromaArrayType != 0){sh->pwt.chroma_log2_weight_denom = bs_read_ue(b);}for (i = 0; i <= sh->num_ref_idx_l0_active_minus1; i++){sh->pwt.luma_weight_l0_flag[i] = bs_read_u1(b);if (sh->pwt.luma_weight_l0_flag[i]){sh->pwt.luma_weight_l0[i] = bs_read_se(b);sh->pwt.luma_offset_l0[i] = bs_read_se(b);}if (sps->ChromaArrayType != 0){sh->pwt.chroma_weight_l0_flag[i] = bs_read_u1(b);if (sh->pwt.chroma_weight_l0_flag[i]){for (j = 0; j < 2; j++){sh->pwt.chroma_weight_l0[i][j] = bs_read_se(b);sh->pwt.chroma_offset_l0[i][j] = bs_read_se(b);}}}}if (is_slice_type(sh->slice_type, SH_SLICE_TYPE_B)){for (i = 0; i <= sh->num_ref_idx_l1_active_minus1; i++){sh->pwt.luma_weight_l1_flag[i] = bs_read_u1(b);if (sh->pwt.luma_weight_l1_flag[i]){sh->pwt.luma_weight_l1[i] = bs_read_se(b);sh->pwt.luma_offset_l1[i] = bs_read_se(b);}if (sps->ChromaArrayType != 0){sh->pwt.chroma_weight_l1_flag[i] = bs_read_u1(b);if (sh->pwt.chroma_weight_l1_flag[i]){for (j = 0; j < 2; j++){sh->pwt.chroma_weight_l1[i][j] = bs_read_se(b);sh->pwt.chroma_offset_l1[i][j] = bs_read_se(b);}}}}}
}// 7.3.3.3 Decoded reference picture marking syntax
void read_dec_ref_pic_marking(h264_stream_t * h, bs_t * b)
{h264_slice_header_t* sh = h->sh;h264_sps_t* sps = h->sps;h264_pps_t* pps = h->pps;int i = 0;if (h->nal->nal_unit_type == 5){sh->drpm.no_output_of_prior_pics_flag = bs_read_u1(b);sh->drpm.long_term_reference_flag = bs_read_u1(b);}else{sh->drpm.adaptive_ref_pic_marking_mode_flag = bs_read_u1(b);if (sh->drpm.adaptive_ref_pic_marking_mode_flag){do{sh->drpm.memory_management_control_operation = bs_read_ue(b);if (sh->drpm.memory_management_control_operation == 1 ||sh->drpm.memory_management_control_operation == 3){sh->drpm.difference_of_pic_nums_minus1 = bs_read_ue(b);}if (sh->drpm.memory_management_control_operation == 2){sh->drpm.long_term_pic_num = bs_read_ue(b);}if (sh->drpm.memory_management_control_operation == 3 ||sh->drpm.memory_management_control_operation == 6){sh->drpm.long_term_frame_idx = bs_read_ue(b);}if (sh->drpm.memory_management_control_operation == 4){sh->drpm.max_long_term_frame_idx_plus1 = bs_read_ue(b);}} while (sh->drpm.memory_management_control_operation != 0 && !bs_eof(b));}}
}// skip 0x000003 in EBSP (Encapsulated Byte Sequence Payload),
// then we have RBSP(Raw Byte Squence Payload)
int nal_to_rbsp(const uint8_t * nal_buf, int* nal_size, uint8_t * rbsp_buf, int* rbsp_size)
{int i;int j = 0;int count = 0;for (i = 1; i < *nal_size; i++){// in NAL unit, 0x000000, 0x000001 or 0x000002 shall not occur at any byte-aligned positionif ((count == 2) && (nal_buf[i] < 0x03)){return -1;}if ((count == 2) && (nal_buf[i] == 0x03)){// check the 4th byte after 0x000003, except when cabac_zero_word is used, in which case the last three bytes of this NAL unit must be 0x000003if ((i < *nal_size - 1) && (nal_buf[i + 1] > 0x03)){return -1;}// if cabac_zero_word is used, the final byte of this NAL unit(0x03) is discarded, and the last two bytes of RBSP must be 0x0000if (i == *nal_size - 1){break;}i++;count = 0;}if (j >= *rbsp_size){// error, not enough spacereturn -1;}rbsp_buf[j] = nal_buf[i];if (nal_buf[i] == 0x00){count++;}else{count = 0;}j++;}*nal_size = i;*rbsp_size = j;return j;
}/**Find the beginning and end of a NAL (Network Abstraction Layer) unit in a byte buffer containing H264 bitstream data.@param[in]   buf        the buffer@param[in]   size       the size of the buffer@param[out]  nal_start  the beginning offset of the nal@param[out]  nal_end    the end offset of the nal@return                 the length of the nal, or 0 if did not find start of nal, or -1 if did not find end of nal*/
int find_nal_unit(uint8_t * buf, int size, int* nal_start, int* nal_end)
{int i;// find start*nal_start = 0;*nal_end = 0;i = 0;while (   //( next_bits( 24 ) != 0x000001 && next_bits( 32 ) != 0x00000001 )(buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0x01) &&(buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0 || buf[i + 3] != 0x01)){i++; // skip leading zeroif (i + 4 >= size) { return 0; } // did not find nal start}if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0x01) // ( next_bits( 24 ) != 0x000001 ){i++;}if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0x01) { /* error, should never happen */ return 0; }i += 3;*nal_start = i;while (   //( next_bits( 24 ) != 0x000000 && next_bits( 24 ) != 0x000001 )(buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0) &&(buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0x01)){i++;// FIXME the next line fails when reading a nal that ends exactly at the end of the dataif (i + 3 >= size) { *nal_end = size; return -1; } // did not find nal end, stream ended first}*nal_end = i;return (*nal_end - *nal_start);
}// debug info
void debug_nal(h264_stream_t* h, h264_nal_t* nal)
{printf("==================== NAL ====================\n");printf(" forbidden_zero_bit : %d \n", nal->forbidden_zero_bit);printf(" nal_ref_idc : %d \n", nal->nal_ref_idc);// TODO make into subroutineconst char* nal_unit_type_name;switch (nal->nal_unit_type){case  NAL_UNIT_TYPE_UNSPECIFIED:                   nal_unit_type_name = "Unspecified"; break;case  NAL_UNIT_TYPE_CODED_SLICE_NON_IDR:           nal_unit_type_name = "Coded slice of a non-IDR picture"; break;case  NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A:  nal_unit_type_name = "Coded slice data partition A"; break;case  NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_B:  nal_unit_type_name = "Coded slice data partition B"; break;case  NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_C:  nal_unit_type_name = "Coded slice data partition C"; break;case  NAL_UNIT_TYPE_CODED_SLICE_IDR:               nal_unit_type_name = "Coded slice of an IDR picture"; break;case  NAL_UNIT_TYPE_SEI:                           nal_unit_type_name = "Supplemental enhancement information (SEI)"; break;case  NAL_UNIT_TYPE_SPS:                           nal_unit_type_name = "Sequence parameter set"; break;case  NAL_UNIT_TYPE_PPS:                           nal_unit_type_name = "Picture parameter set"; break;case  NAL_UNIT_TYPE_AUD:                           nal_unit_type_name = "Access unit delimiter"; break;case  NAL_UNIT_TYPE_END_OF_SEQUENCE:               nal_unit_type_name = "End of sequence"; break;case  NAL_UNIT_TYPE_END_OF_STREAM:                 nal_unit_type_name = "End of stream"; break;case  NAL_UNIT_TYPE_FILLER:                        nal_unit_type_name = "Filler data"; break;case  NAL_UNIT_TYPE_SPS_EXT:                       nal_unit_type_name = "Sequence parameter set extension"; break;// 14..18    // Reservedcase  NAL_UNIT_TYPE_CODED_SLICE_AUX:               nal_unit_type_name = "Coded slice of an auxiliary coded picture without partitioning"; break;// 20..23    // Reserved// 24..31    // Unspecifieddefault:                                           nal_unit_type_name = "Unknown"; break;}printf(" nal_unit_type : %d ( %s ) \n", nal->nal_unit_type, nal_unit_type_name);if (nal->nal_unit_type == NAL_UNIT_TYPE_CODED_SLICE_NON_IDR) { debug_slice_header(h); }else if (nal->nal_unit_type == NAL_UNIT_TYPE_CODED_SLICE_IDR) { debug_slice_header(h); }else if (nal->nal_unit_type == NAL_UNIT_TYPE_SPS) { debug_sps(h); }else if (nal->nal_unit_type == NAL_UNIT_TYPE_PPS) { debug_pps(h); }else if (nal->nal_unit_type == NAL_UNIT_TYPE_AUD) { debug_aud(h); }else if (nal->nal_unit_type == NAL_UNIT_TYPE_SEI) { debug_seis(h); }
}void debug_sps(h264_stream_t* h)
{h264_sps_t* sps = h->sps;printf("======= SPS =======\n");printf(" profile_idc : %d \n", sps->profile_idc);printf(" constraint_set0_flag : %d \n", sps->constraint_set0_flag);printf(" constraint_set1_flag : %d \n", sps->constraint_set1_flag);printf(" constraint_set2_flag : %d \n", sps->constraint_set2_flag);printf(" constraint_set3_flag : %d \n", sps->constraint_set3_flag);printf(" constraint_set4_flag : %d \n", sps->constraint_set4_flag);printf(" constraint_set5_flag : %d \n", sps->constraint_set5_flag);printf(" reserved_zero_2bits : %d \n", sps->reserved_zero_2bits);printf(" level_idc : %d \n", sps->level_idc);printf(" seq_parameter_set_id : %d \n", sps->seq_parameter_set_id);int profile_idc = sps->profile_idc;if (profile_idc == 100 || profile_idc == 110 ||profile_idc == 122 || profile_idc == 244 || profile_idc == 44  ||profile_idc == 83  || profile_idc == 86  || profile_idc == 118 ||profile_idc == 128 || profile_idc == 138 || profile_idc == 139 ||profile_idc == 134 || profile_idc == 135){printf(" chroma_format_idc : %d \n", sps->chroma_format_idc);if (sps->chroma_format_idc == 3){printf(" separate_colour_plane_flag : %d \n", sps->separate_colour_plane_flag);}printf(" bit_depth_luma_minus8 : %d \n", sps->bit_depth_luma_minus8);printf(" bit_depth_chroma_minus8 : %d \n", sps->bit_depth_chroma_minus8);printf(" qpprime_y_zero_transform_bypass_flag : %d \n", sps->qpprime_y_zero_transform_bypass_flag);printf(" seq_scaling_matrix_present_flag : %d \n", sps->seq_scaling_matrix_present_flag);}//  int seq_scaling_list_present_flag[8];//  void* ScalingList4x4[6];//  int UseDefaultScalingMatrix4x4Flag[6];//  void* ScalingList8x8[2];//  int UseDefaultScalingMatrix8x8Flag[2];printf(" log2_max_frame_num_minus4 : %d \n", sps->log2_max_frame_num_minus4);printf(" pic_order_cnt_type : %d \n", sps->pic_order_cnt_type);if (sps->pic_order_cnt_type == 0){printf("   log2_max_pic_order_cnt_lsb_minus4 : %d \n", sps->log2_max_pic_order_cnt_lsb_minus4);}else if (sps->pic_order_cnt_type == 1){printf("   delta_pic_order_always_zero_flag : %d \n", sps->delta_pic_order_always_zero_flag);printf("   offset_for_non_ref_pic : %d \n", sps->offset_for_non_ref_pic);printf("   offset_for_top_to_bottom_field : %d \n", sps->offset_for_top_to_bottom_field);printf("   num_ref_frames_in_pic_order_cnt_cycle : %d \n", sps->num_ref_frames_in_pic_order_cnt_cycle);for (int i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++){//  int offset_for_ref_frame[256];}}printf(" max_num_ref_frames : %d \n", sps->max_num_ref_frames);printf(" gaps_in_frame_num_value_allowed_flag : %d \n", sps->gaps_in_frame_num_value_allowed_flag);printf(" pic_width_in_mbs_minus1 : %d \n", sps->pic_width_in_mbs_minus1);printf(" pic_height_in_map_units_minus1 : %d \n", sps->pic_height_in_map_units_minus1);printf(" frame_mbs_only_flag : %d \n", sps->frame_mbs_only_flag);if (!sps->frame_mbs_only_flag){printf(" mb_adaptive_frame_field_flag : %d \n", sps->mb_adaptive_frame_field_flag);}printf(" direct_8x8_inference_flag : %d \n", sps->direct_8x8_inference_flag);printf(" frame_cropping_flag : %d \n", sps->frame_cropping_flag);if (sps->frame_cropping_flag){printf("   frame_crop_left_offset : %d \n", sps->frame_crop_left_offset);printf("   frame_crop_right_offset : %d \n", sps->frame_crop_right_offset);printf("   frame_crop_top_offset : %d \n", sps->frame_crop_top_offset);printf("   frame_crop_bottom_offset : %d \n", sps->frame_crop_bottom_offset);}printf(" vui_parameters_present_flag : %d \n", sps->vui_parameters_present_flag);if (sps->vui_parameters_present_flag){printf("=== VUI ===\n");printf(" aspect_ratio_info_present_flag : %d \n", sps->vui.aspect_ratio_info_present_flag);if (sps->vui.aspect_ratio_info_present_flag){printf("   aspect_ratio_idc : %d \n", sps->vui.aspect_ratio_idc);if (sps->vui.aspect_ratio_idc == Extended_SAR){printf("     sar_width : %d \n", sps->vui.sar_width);printf("     sar_height : %d \n", sps->vui.sar_height);}}printf(" overscan_info_present_flag : %d \n", sps->vui.overscan_info_present_flag);if (sps->vui.overscan_info_present_flag){printf("   overscan_appropriate_flag : %d \n", sps->vui.overscan_appropriate_flag);}printf(" video_signal_type_present_flag : %d \n", sps->vui.video_signal_type_present_flag);if (sps->vui.video_signal_type_present_flag){printf("   video_format : %d \n", sps->vui.video_format);printf("   video_full_range_flag : %d \n", sps->vui.video_full_range_flag);printf("   colour_description_present_flag : %d \n", sps->vui.colour_description_present_flag);if (sps->vui.colour_description_present_flag){printf("     colour_primaries : %d \n", sps->vui.colour_primaries);printf("   transfer_characteristics : %d \n", sps->vui.transfer_characteristics);printf("   matrix_coefficients : %d \n", sps->vui.matrix_coefficients);}}printf(" chroma_loc_info_present_flag : %d \n", sps->vui.chroma_loc_info_present_flag);if (sps->vui.chroma_loc_info_present_flag){printf("   chroma_sample_loc_type_top_field : %d \n", sps->vui.chroma_sample_loc_type_top_field);printf("   chroma_sample_loc_type_bottom_field : %d \n", sps->vui.chroma_sample_loc_type_bottom_field);}printf(" timing_info_present_flag : %d \n", sps->vui.timing_info_present_flag);if (sps->vui.timing_info_present_flag){printf("   num_units_in_tick : %d \n", sps->vui.num_units_in_tick);printf("   time_scale : %d \n", sps->vui.time_scale);printf("   fixed_frame_rate_flag : %d \n", sps->vui.fixed_frame_rate_flag);}printf(" nal_hrd_parameters_present_flag : %d \n", sps->vui.nal_hrd_parameters_present_flag);printf(" vcl_hrd_parameters_present_flag : %d \n", sps->vui.vcl_hrd_parameters_present_flag);if (sps->vui.nal_hrd_parameters_present_flag || sps->vui.vcl_hrd_parameters_present_flag){printf("   low_delay_hrd_flag : %d \n", sps->vui.low_delay_hrd_flag);}printf(" pic_struct_present_flag : %d \n", sps->vui.pic_struct_present_flag);printf(" bitstream_restriction_flag : %d \n", sps->vui.bitstream_restriction_flag);if (sps->vui.bitstream_restriction_flag){printf("   motion_vectors_over_pic_boundaries_flag : %d \n", sps->vui.motion_vectors_over_pic_boundaries_flag);printf("   max_bytes_per_pic_denom : %d \n", sps->vui.max_bytes_per_pic_denom);printf("   max_bits_per_mb_denom : %d \n", sps->vui.max_bits_per_mb_denom);printf("   log2_max_mv_length_horizontal : %d \n", sps->vui.log2_max_mv_length_horizontal);printf("   log2_max_mv_length_vertical : %d \n", sps->vui.log2_max_mv_length_vertical);printf("   max_num_reorder_frames : %d \n", sps->vui.max_num_reorder_frames);printf("   max_dec_frame_buffering : %d \n", sps->vui.max_dec_frame_buffering);}if (sps->vui.nal_hrd_parameters_present_flag || sps->vui.vcl_hrd_parameters_present_flag){printf("=== HRD ===\n");printf(" cpb_cnt_minus1 : %d \n", sps->hrd.cpb_cnt_minus1);printf(" bit_rate_scale : %d \n", sps->hrd.bit_rate_scale);printf(" cpb_size_scale : %d \n", sps->hrd.cpb_size_scale);int SchedSelIdx;for (SchedSelIdx = 0; SchedSelIdx <= sps->hrd.cpb_cnt_minus1; SchedSelIdx++){printf("   bit_rate_value_minus1[%d] : %d \n", SchedSelIdx, sps->hrd.bit_rate_value_minus1[SchedSelIdx]); // up to cpb_cnt_minus1, which is <= 31printf("   cpb_size_value_minus1[%d] : %d \n", SchedSelIdx, sps->hrd.cpb_size_value_minus1[SchedSelIdx]);printf("   cbr_flag[%d] : %d \n", SchedSelIdx, sps->hrd.cbr_flag[SchedSelIdx]);}printf(" initial_cpb_removal_delay_length_minus1 : %d \n", sps->hrd.initial_cpb_removal_delay_length_minus1);printf(" cpb_removal_delay_length_minus1 : %d \n", sps->hrd.cpb_removal_delay_length_minus1);printf(" dpb_removal_delay_length_minus1 : %d \n", sps->hrd.dpb_removal_delay_length_minus1);printf(" time_offset_length : %d \n", sps->hrd.time_offset_length);}}
}void debug_pps(h264_stream_t* h)
{h264_pps_t* pps = h->pps;printf("======= PPS =======\n");printf(" pic_parameter_set_id : %d \n", pps->pic_parameter_set_id);printf(" seq_parameter_set_id : %d \n", pps->seq_parameter_set_id);printf(" entropy_coding_mode_flag : %d \n", pps->entropy_coding_mode_flag);printf(" bottom_field_pic_order_in_frame_present_flag : %d \n", pps->bottom_field_pic_order_in_frame_present_flag);printf(" num_slice_groups_minus1 : %d \n", pps->num_slice_groups_minus1);if (pps->num_slice_groups_minus1 > 0){printf(" slice_group_map_type : %d \n", pps->slice_group_map_type);int slice_group_map_type = pps->slice_group_map_type;if (slice_group_map_type == 0){for (int i = 0; i <= pps->num_slice_groups_minus1; i++){printf(" run_length_minus1[%d] : %d \n", i, pps->run_length_minus1[i]);}}else if (slice_group_map_type == 2){for (int i = 0; i < pps->num_slice_groups_minus1; i++){printf(" top_left[%d] : %d \n", i, pps->top_left[i]);printf(" bottom_right[%d] : %d \n", i, pps->bottom_right[i]);}}else if (slice_group_map_type == 3 || slice_group_map_type == 4 || slice_group_map_type == 5){printf(" slice_group_change_direction_flag : %d \n", pps->slice_group_change_direction_flag);printf(" slice_group_change_rate_minus1 : %d \n", pps->slice_group_change_rate_minus1);}else if (slice_group_map_type == 6){printf(" pic_size_in_map_units_minus1 : %d \n", pps->pic_size_in_map_units_minus1);for (int i = 0; i <= pps->pic_size_in_map_units_minus1; i++){printf(" slice_group_id[%d] : %d \n", pps->slice_group_id[i]);}}}//  int run_length_minus1[8]; // up to num_slice_groups_minus1, which is <= 7 in Baseline and Extended, 0 otheriwse//  int top_left[8];//  int bottom_right[8];//  int slice_group_change_direction_flag;//  int slice_group_change_rate_minus1;//  int pic_size_in_map_units_minus1;//  int slice_group_id[256]; // FIXME what size?printf(" num_ref_idx_l0_default_active_minus1 : %d \n", pps->num_ref_idx_l0_default_active_minus1);printf(" num_ref_idx_l1_default_active_minus1 : %d \n", pps->num_ref_idx_l1_default_active_minus1);printf(" weighted_pred_flag : %d \n", pps->weighted_pred_flag);printf(" weighted_bipred_idc : %d \n", pps->weighted_bipred_idc);printf(" pic_init_qp_minus26 : %d \n", pps->pic_init_qp_minus26);printf(" pic_init_qs_minus26 : %d \n", pps->pic_init_qs_minus26);printf(" chroma_qp_index_offset : %d \n", pps->chroma_qp_index_offset);printf(" deblocking_filter_control_present_flag : %d \n", pps->deblocking_filter_control_present_flag);printf(" constrained_intra_pred_flag : %d \n", pps->constrained_intra_pred_flag);printf(" redundant_pic_cnt_present_flag : %d \n", pps->redundant_pic_cnt_present_flag);if (pps->more_rbsp_data){printf(" transform_8x8_mode_flag : %d \n", pps->transform_8x8_mode_flag);printf(" pic_scaling_matrix_present_flag : %d \n", pps->pic_scaling_matrix_present_flag);//  int pic_scaling_list_present_flag[8];//  void* ScalingList4x4[6];//  int UseDefaultScalingMatrix4x4Flag[6];//  void* ScalingList8x8[2];//  int UseDefaultScalingMatrix8x8Flag[2];printf(" second_chroma_qp_index_offset : %d \n", pps->second_chroma_qp_index_offset);}
}void debug_slice_header(h264_stream_t* h)
{h264_slice_header_t* sh = h->sh;printf("======= Slice Header =======\n");printf(" first_mb_in_slice : %d \n", sh->first_mb_in_slice);const char* slice_type_name;switch (sh->slice_type){case SH_SLICE_TYPE_P:       slice_type_name = "P slice"; break;case SH_SLICE_TYPE_B:       slice_type_name = "B slice"; break;case SH_SLICE_TYPE_I:       slice_type_name = "I slice"; break;case SH_SLICE_TYPE_SP:      slice_type_name = "SP slice"; break;case SH_SLICE_TYPE_SI:      slice_type_name = "SI slice"; break;case SH_SLICE_TYPE_P_ONLY:  slice_type_name = "P slice only"; break;case SH_SLICE_TYPE_B_ONLY:  slice_type_name = "B slice only"; break;case SH_SLICE_TYPE_I_ONLY:  slice_type_name = "I slice only"; break;case SH_SLICE_TYPE_SP_ONLY: slice_type_name = "SP slice only"; break;case SH_SLICE_TYPE_SI_ONLY: slice_type_name = "SI slice only"; break;default:                    slice_type_name = "Unknown"; break;}printf(" slice_type : %d ( %s ) \n", sh->slice_type, slice_type_name);printf(" pic_parameter_set_id : %d \n", sh->pic_parameter_set_id);if (h->sps->separate_colour_plane_flag == 1){printf(" colour_plane_id : %d \n", sh->colour_plane_id);}printf(" frame_num : %d \n", sh->frame_num);if (!h->sps->frame_mbs_only_flag){printf(" field_pic_flag : %d \n", sh->field_pic_flag);if (sh->field_pic_flag){printf(" bottom_field_flag : %d \n", sh->bottom_field_flag);}}if (h->nal->nal_unit_type == 5){printf(" idr_pic_id : %d \n", sh->idr_pic_id);}if (h->sps->pic_order_cnt_type == 0){printf(" pic_order_cnt_lsb : %d \n", sh->pic_order_cnt_lsb);if (h->pps->bottom_field_pic_order_in_frame_present_flag && !sh->field_pic_flag){printf(" delta_pic_order_cnt_bottom : %d \n", sh->delta_pic_order_cnt_bottom);}}if (h->sps->pic_order_cnt_type == 1 && !h->sps->delta_pic_order_always_zero_flag){// int delta_pic_order_cnt[ 2 ];printf(" delta_pic_order_cnt[0] : %d \n", sh->delta_pic_order_cnt[0]);if (h->pps->bottom_field_pic_order_in_frame_present_flag && !sh->field_pic_flag){printf(" delta_pic_order_cnt[1] : %d \n", sh->delta_pic_order_cnt[1]);}}if (h->pps->redundant_pic_cnt_present_flag){printf(" redundant_pic_cnt : %d \n", sh->redundant_pic_cnt);}if (is_slice_type(h->sh->slice_type, SH_SLICE_TYPE_B)){printf(" direct_spatial_mv_pred_flag : %d \n", sh->direct_spatial_mv_pred_flag);}if (is_slice_type(h->sh->slice_type, SH_SLICE_TYPE_P) || is_slice_type(h->sh->slice_type, SH_SLICE_TYPE_SP) || is_slice_type(h->sh->slice_type, SH_SLICE_TYPE_B)){printf(" num_ref_idx_active_override_flag : %d \n", sh->num_ref_idx_active_override_flag);if (sh->num_ref_idx_active_override_flag){printf(" num_ref_idx_l0_active_minus1 : %d \n", sh->num_ref_idx_l0_active_minus1);if (is_slice_type(sh->slice_type, SH_SLICE_TYPE_B)){printf(" num_ref_idx_l1_active_minus1 : %d \n", sh->num_ref_idx_l1_active_minus1);}}}//if (h->nal->nal_unit_type == 20 || h->nal->nal_unit_type == 21)//{//	// ref_pic_list_mvc_modification; // speficied in Annex H//}//else //{//	// ref_pic_list_modification()//}if (h->pps->entropy_coding_mode_flag && !is_slice_type(sh->slice_type, SH_SLICE_TYPE_I) && !is_slice_type(sh->slice_type, SH_SLICE_TYPE_SI)){printf(" cabac_init_idc : %d \n", sh->cabac_init_idc);}printf(" slice_qp_delta : %d \n", sh->slice_qp_delta);if (is_slice_type(sh->slice_type, SH_SLICE_TYPE_SP) || is_slice_type(sh->slice_type, SH_SLICE_TYPE_SI)){if (is_slice_type(sh->slice_type, SH_SLICE_TYPE_SP)){printf(" sp_for_switch_flag : %d \n", sh->sp_for_switch_flag);}printf(" slice_qs_delta : %d \n", sh->slice_qs_delta);}if (h->pps->deblocking_filter_control_present_flag){printf(" disable_deblocking_filter_idc : %d \n", sh->disable_deblocking_filter_idc);if (sh->disable_deblocking_filter_idc != 1){printf(" slice_alpha_c0_offset_div2 : %d \n", sh->slice_alpha_c0_offset_div2);printf(" slice_beta_offset_div2 : %d \n", sh->slice_beta_offset_div2);}}if (h->pps->num_slice_groups_minus1 > 0 && h->pps->slice_group_map_type >= 3 && h->pps->slice_group_map_type <= 5){printf(" slice_group_change_cycle : %d \n", sh->slice_group_change_cycle);}// debug rplm infoif (h->nal->nal_unit_type == 20 || h->nal->nal_unit_type == 21){// ref_pic_list_mvc_modification; // speficied in Annex H}else{// ref_pic_list_modification()printf("=== Ref Pic List Modification ===\n");if (!is_slice_type(sh->slice_type, SH_SLICE_TYPE_I) && !is_slice_type(sh->slice_type, SH_SLICE_TYPE_SI)){printf(" ref_pic_list_modification_flag_l0 : %d \n", sh->rplm.ref_pic_list_modification_flag_l0);if (sh->rplm.ref_pic_list_modification_flag_l0){printf(" modification_of_pic_nums_idc : %d \n", sh->rplm.modification_of_pic_nums_idc);printf(" abs_diff_pic_num_minus1 : %d \n", sh->rplm.abs_diff_pic_num_minus1);printf(" long_term_pic_num : %d \n", sh->rplm.long_term_pic_num);}}if (is_slice_type(sh->slice_type, SH_SLICE_TYPE_B)){printf(" ref_pic_list_modification_flag_l1 : %d \n", sh->rplm.ref_pic_list_modification_flag_l1);if (sh->rplm.ref_pic_list_modification_flag_l1){printf(" modification_of_pic_nums_idc : %d \n", sh->rplm.modification_of_pic_nums_idc);printf(" abs_diff_pic_num_minus1 : %d \n", sh->rplm.abs_diff_pic_num_minus1);printf(" long_term_pic_num : %d \n", sh->rplm.long_term_pic_num);}}}// debug pwt infoif ((h->pps->weighted_pred_flag && (is_slice_type(sh->slice_type, SH_SLICE_TYPE_P) || is_slice_type(sh->slice_type, SH_SLICE_TYPE_SP))) ||h->pps->weighted_bipred_idc == 1 && is_slice_type(sh->slice_type, SH_SLICE_TYPE_B)){printf("=== Prediction Weight Table ===\n");printf(" luma_log2_weight_denom : %d \n", sh->pwt.luma_log2_weight_denom);printf(" chroma_log2_weight_denom : %d \n", sh->pwt.chroma_log2_weight_denom);for (int i = 0; i <= sh->num_ref_idx_l0_active_minus1; i++){if (sh->pwt.luma_weight_l0_flag[i]){printf(" luma_weight_l0_flag[%d] : %d \n", i, sh->pwt.luma_weight_l0_flag[i]);printf(" luma_weight_l0[%d] : %d \n", i, sh->pwt.luma_weight_l0[i]);printf(" luma_offset_l0[%d] : %d \n", i, sh->pwt.luma_offset_l0[i]);}if (h->sps->ChromaArrayType != 0){printf(" chroma_weight_l0_flag[%d] : %d \n", i, sh->pwt.chroma_weight_l0_flag[i]);if (sh->pwt.chroma_weight_l0_flag[i]){for (int j = 0; j < 2; j++){printf(" chroma_weight_l0[%d][%d] : %d \n", i, j, sh->pwt.chroma_weight_l0[i][j]);printf(" chroma_offset_l0[%d][%d] : %d \n", i, j, sh->pwt.chroma_offset_l0[i][j]);}}}}for (int i = 0; i <= sh->num_ref_idx_l1_active_minus1; i++){if (sh->pwt.luma_weight_l1_flag[i]){printf(" luma_weight_l1_flag[%d] : %d \n", i, sh->pwt.luma_weight_l1_flag[i]);printf(" luma_weight_l1[%d] : %d \n", i, sh->pwt.luma_weight_l1[i]);printf(" luma_offset_l1[%d] : %d \n", i, sh->pwt.luma_offset_l1[i]);}if (h->sps->ChromaArrayType != 0){printf(" chroma_weight_l1_flag[%d] : %d \n", i, sh->pwt.chroma_weight_l1_flag[i]);if (sh->pwt.chroma_weight_l1_flag[i]){for (int j = 0; j < 2; j++){printf(" chroma_weight_l1[%d][%d] : %d \n", i, j, sh->pwt.chroma_weight_l1[i][j]);printf(" chroma_offset_l1[%d][%d] : %d \n", i, j, sh->pwt.chroma_offset_l1[i][j]);}}}}// int luma_weight_l0[64];// int luma_offset_l0[64];//    printf(" chroma_weight_l0_flag : %d \n", sh->pwt.chroma_weight_l0_flag );// int chroma_weight_l0[64][2];// int chroma_offset_l0[64][2];// int luma_weight_l1[64];// int luma_offset_l1[64];//    printf(" chroma_weight_l1_flag : %d \n", sh->pwt.chroma_weight_l1_flag );// int chroma_weight_l1[64][2];// int chroma_offset_l1[64][2];}// debug drpm infoif (h->nal->nal_ref_idc != 0){printf("=== Decoded Ref Pic Marking ===\n");if (h->nal->nal_unit_type == 5){printf(" no_output_of_prior_pics_flag : %d \n", sh->drpm.no_output_of_prior_pics_flag);printf(" long_term_reference_flag : %d \n", sh->drpm.long_term_reference_flag);}else {printf(" adaptive_ref_pic_marking_mode_flag : %d \n", sh->drpm.adaptive_ref_pic_marking_mode_flag);if (sh->drpm.adaptive_ref_pic_marking_mode_flag){printf(" memory_management_control_operation : %d \n", sh->drpm.memory_management_control_operation);printf(" difference_of_pic_nums_minus1 : %d \n", sh->drpm.difference_of_pic_nums_minus1);printf(" long_term_pic_num : %d \n", sh->drpm.long_term_pic_num);printf(" max_long_term_frame_idx_plus1 : %d \n", sh->drpm.max_long_term_frame_idx_plus1);}}}
}void debug_aud(h264_stream_t* h)
{h264_aud_t* aud = h->aud;printf("======= Access Unit Delimiter =======\n");const char* primary_pic_type_name;switch (aud->primary_pic_type){case AUD_PRIMARY_PIC_TYPE_I:       primary_pic_type_name = "I"; break;case AUD_PRIMARY_PIC_TYPE_IP:      primary_pic_type_name = "I, P"; break;case AUD_PRIMARY_PIC_TYPE_IPB:     primary_pic_type_name = "I, P, B"; break;case AUD_PRIMARY_PIC_TYPE_SI:      primary_pic_type_name = "SI"; break;case AUD_PRIMARY_PIC_TYPE_SISP:    primary_pic_type_name = "SI, SP"; break;case AUD_PRIMARY_PIC_TYPE_ISI:     primary_pic_type_name = "I, SI"; break;case AUD_PRIMARY_PIC_TYPE_ISIPSP:  primary_pic_type_name = "I, SI, P, SP"; break;case AUD_PRIMARY_PIC_TYPE_ISIPSPB: primary_pic_type_name = "I, SI, P, SP, B"; break;default: primary_pic_type_name = "Unknown"; break;}printf(" primary_pic_type : %d ( %s ) \n", aud->primary_pic_type, primary_pic_type_name);
}void debug_seis(h264_stream_t* h)
{h264_sei_t** seis = h->seis;int num_seis = h->num_seis;printf("======= SEI =======\n");const char* sei_type_name;int i;for (i = 0; i < num_seis; i++){h264_sei_t* s = seis[i];switch (s->payload_type){case SEI_TYPE_BUFFERING_PERIOD:          sei_type_name = "Buffering period"; break;case SEI_TYPE_PIC_TIMING:                sei_type_name = "Pic timing"; break;case SEI_TYPE_PAN_SCAN_RECT:             sei_type_name = "Pan scan rect"; break;case SEI_TYPE_FILLER_PAYLOAD:            sei_type_name = "Filler payload"; break;case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35: sei_type_name = "User data registered ITU-T T35"; break;case SEI_TYPE_USER_DATA_UNREGISTERED:    sei_type_name = "User data unregistered"; break;case SEI_TYPE_RECOVERY_POINT:            sei_type_name = "Recovery point"; break;case SEI_TYPE_DEC_REF_PIC_MARKING_REPETITION: sei_type_name = "Dec ref pic marking repetition"; break;case SEI_TYPE_SPARE_PIC:                 sei_type_name = "Spare pic"; break;case SEI_TYPE_SCENE_INFO:                sei_type_name = "Scene info"; break;case SEI_TYPE_SUB_SEQ_INFO:              sei_type_name = "Sub seq info"; break;case SEI_TYPE_SUB_SEQ_LAYER_CHARACTERISTICS: sei_type_name = "Sub seq layer characteristics"; break;case SEI_TYPE_SUB_SEQ_CHARACTERISTICS:   sei_type_name = "Sub seq characteristics"; break;case SEI_TYPE_FULL_FRAME_FREEZE:         sei_type_name = "Full frame freeze"; break;case SEI_TYPE_FULL_FRAME_FREEZE_RELEASE: sei_type_name = "Full frame freeze release"; break;case SEI_TYPE_FULL_FRAME_SNAPSHOT:       sei_type_name = "Full frame snapshot"; break;case SEI_TYPE_PROGRESSIVE_REFINEMENT_SEGMENT_START: sei_type_name = "Progressive refinement segment start"; break;case SEI_TYPE_PROGRESSIVE_REFINEMENT_SEGMENT_END: sei_type_name = "Progressive refinement segment end"; break;case SEI_TYPE_MOTION_CONSTRAINED_SLICE_GROUP_SET: sei_type_name = "Motion constrained slice group set"; break;case SEI_TYPE_FILM_GRAIN_CHARACTERISTICS: sei_type_name = "Film grain characteristics"; break;case SEI_TYPE_DEBLOCKING_FILTER_DISPLAY_PREFERENCE: sei_type_name = "Deblocking filter display preference"; break;case SEI_TYPE_STEREO_VIDEO_INFO:         sei_type_name = "Stereo video info"; break;default: sei_type_name = "Unknown"; break;}printf("=== %s ===\n", sei_type_name);printf(" payloadType : %d \n", s->payload_type);printf(" payloadSize : %d \n", s->payload_size);printf(" payload : ");debug_bytes(s->payload, s->payload_size);}
}void debug_bytes(uint8_t* buf, int len)
{int i;for (i = 0; i < len; i++){printf("%02X ", buf[i]);if ((i + 1) % 16 == 0) { printf("\n"); }}printf("\n");
}

3.2 码流解析(parser.cpp)

码流解析参考了雷博的videoEye代码,改了一下原有代码中的bug,最后的地方需要多读取一个NALU

#pragma pack(1)
#pragma warning(disable : 4996)#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include "streamer.h"
#include "bs.h"
#include "h264_parser.h"int h264_parser(const char* h264_name)
{FILE* h264_bitstream = NULL;h264_nal_t*n;h264_bitstream = fopen(h264_name, "rb");if (!h264_bitstream) {ERROR("failed to open input file");return -1;}n = (h264_nal_t*)calloc(1, sizeof(h264_nal_t));if (n == NULL) {ERROR("Alloc NALU Error");return 0;}uint8_t *p = (uint8_t*)calloc(BUFSIZE, sizeof(uint8_t));if (p == NULL) {free(n);ERROR("failed to alloc nalu buffer");return 0;}h264_stream_t* h = h264_new();int data_offset = 0;int nal_num = 0;//printf("-----+-------- NALU Table ------+---------+\n");//printf(" NUM |    POS  |    IDC |  TYPE |   LEN   |\n");//printf("-----+---------+--------+-------+---------+\n");size_t rsz = 0;size_t sz = 0;int nal_start, nal_end;int len = 0;int debug = 1;int nal_cnt = 0;while (1) {rsz = fread(p + sz, 1, BUFSIZE - sz, h264_bitstream);if (!rsz) {ERROR("read stram failed");break;}sz += rsz;while (find_nal_unit(p, sz, &nal_start, &nal_end) > 0) {p += nal_start;read_nal_unit(h, p, nal_end - nal_start);if (debug){debug_bytes(p - 4, nal_end - nal_start + 4 >= 16 ? 16 : nal_end - nal_start + 4);debug_nal(h, h->nal);}p += (nal_end - nal_start);sz -= nal_end;}// 这里需要多执行一次,对于最后一个NALU而言,确定其大小必须依靠更后一个NALU,但更后一个NALU是不存在的find_nal_unit(p, sz, &nal_start, &nal_end);}
}int parser()
{const char* h264_name = "output.h264";h264_parser(h264_name);return 0;
}

4.程序运行结果

这里和H264/H264Analyzer进行码流的对比一致,不过还需要和一些大的码流分析器进行对比,看看有没有细节的错误,不过后续再改善

==================== NAL ====================forbidden_zero_bit : 0 nal_ref_idc : 3 nal_unit_type : 7 ( Sequence parameter set ) 
======= SPS =======profile_idc : 100 constraint_set0_flag : 0 constraint_set1_flag : 0 constraint_set2_flag : 0 constraint_set3_flag : 0 constraint_set4_flag : 0 constraint_set5_flag : 0 reserved_zero_2bits : 0 level_idc : 31 seq_parameter_set_id : 0 chroma_format_idc : 1 bit_depth_luma_minus8 : 0 bit_depth_chroma_minus8 : 0 qpprime_y_zero_transform_bypass_flag : 0 seq_scaling_matrix_present_flag : 0 log2_max_frame_num_minus4 : 0 pic_order_cnt_type : 2 max_num_ref_frames : 3 gaps_in_frame_num_value_allowed_flag : 0 pic_width_in_mbs_minus1 : 79 pic_height_in_map_units_minus1 : 44 frame_mbs_only_flag : 1 direct_8x8_inference_flag : 1 frame_cropping_flag : 0 vui_parameters_present_flag : 1 
=== VUI ===aspect_ratio_info_present_flag : 0 overscan_info_present_flag : 0 video_signal_type_present_flag : 0 chroma_loc_info_present_flag : 0 timing_info_present_flag : 1 num_units_in_tick : 1 time_scale : 50 fixed_frame_rate_flag : 0 nal_hrd_parameters_present_flag : 0 vcl_hrd_parameters_present_flag : 0 pic_struct_present_flag : 0 bitstream_restriction_flag : 1 motion_vectors_over_pic_boundaries_flag : 1 max_bytes_per_pic_denom : 0 max_bits_per_mb_denom : 0 log2_max_mv_length_horizontal : 11 log2_max_mv_length_vertical : 11 max_num_reorder_frames : 0 max_dec_frame_buffering : 3 ==================== NAL ====================forbidden_zero_bit : 0 nal_ref_idc : 3 nal_unit_type : 8 ( Picture parameter set ) 
======= PPS =======pic_parameter_set_id : 0 seq_parameter_set_id : 0 entropy_coding_mode_flag : 1 bottom_field_pic_order_in_frame_present_flag : 0 num_slice_groups_minus1 : 0 num_ref_idx_l0_default_active_minus1 : 2 num_ref_idx_l1_default_active_minus1 : 0 weighted_pred_flag : 1 weighted_bipred_idc : 0 pic_init_qp_minus26 : -3 pic_init_qs_minus26 : 0 chroma_qp_index_offset : -2 deblocking_filter_control_present_flag : 1 constrained_intra_pred_flag : 0 redundant_pic_cnt_present_flag : 0 transform_8x8_mode_flag : 1 pic_scaling_matrix_present_flag : 0 second_chroma_qp_index_offset : -2 ==================== NAL ====================forbidden_zero_bit : 0 nal_ref_idc : 0 nal_unit_type : 6 ( Supplemental enhancement information (SEI) ) 
======= SEI =======
=== User data unregistered ===payloadType : 5 payloadSize : 620 payload : // ... 这里数据太多不显示==================== NAL ====================forbidden_zero_bit : 0 nal_ref_idc : 3 nal_unit_type : 5 ( Coded slice of an IDR picture ) 
======= Slice Header =======first_mb_in_slice : 0 slice_type : 7 ( I slice only ) pic_parameter_set_id : 0 frame_num : 0 idr_pic_id : 0 slice_qp_delta : -4 disable_deblocking_filter_idc : 0 slice_alpha_c0_offset_div2 : 0 slice_beta_offset_div2 : 0 
=== Ref Pic List Modification ===
=== Decoded Ref Pic Marking ===no_output_of_prior_pics_flag : 0 long_term_reference_flag : 0 ==================== NAL ====================forbidden_zero_bit : 0 nal_ref_idc : 2 nal_unit_type : 1 ( Coded slice of a non-IDR picture ) 
======= Slice Header =======first_mb_in_slice : 0 slice_type : 5 ( P slice only ) pic_parameter_set_id : 0 frame_num : 1 num_ref_idx_active_override_flag : 1 num_ref_idx_l0_active_minus1 : 0 cabac_init_idc : 0 slice_qp_delta : -1 disable_deblocking_filter_idc : 0 slice_alpha_c0_offset_div2 : 0 slice_beta_offset_div2 : 0 
=== Ref Pic List Modification ===ref_pic_list_modification_flag_l0 : 0 
=== Prediction Weight Table ===luma_log2_weight_denom : 0 chroma_log2_weight_denom : 0 chroma_weight_l0_flag[0] : 0 chroma_weight_l1_flag[0] : 0 
=== Decoded Ref Pic Marking ===adaptive_ref_pic_marking_mode_flag : 0 

5.小结

在写这个代码过程中,为了避免中间的语法元素错误,按照2021年8月的H264标准语法元素逐句写的,发现确实有些地方和雷博不太一样,例如separate_colour_plane_flag,rplm的名称等等。另外,还有一些细节的bug例如读取nal没有完全读取到。通过这样的一个工程,能够对码流有一个比较全面的理解。

后续应该可以增加一些可操作性界面,增加h265的分析,还可以增加packet解码,进行图像展示

CSDN : https://blog.csdn.net/weixin_42877471
Github : https://github.com/DoFulangChen

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3226663.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【独家揭秘】视频号矩阵系统源码,智能多平台管理,发布效率飙升的秘密武器!

在如今这个信息爆炸的时代&#xff0c;视频内容已经成为人们获取信息和娱乐的重要方式。然而&#xff0c;对于众多内容创作者和企业来说&#xff0c;如何高效地将视频内容发布到各大平台&#xff0c;提升品牌曝光度和用户互动&#xff0c;一直是一个头疼的问题。今天&#xff0…

获超九成Gartner用户力推!FortiGate连续五年斩获“客户之选”称号

近日&#xff0c;Gartner Peer Insights™ 网络防火墙客户之选报告发布&#xff0c;Fortinet 连续第五年荣登这项权威榜单。该评选结果源于广大用户对 Fortinet 防火墙产品的真实反馈&#xff0c;是客户选择 Fortinet 的重要参考依据&#xff0c;也是FortiGate能够占据全球防火…

springboot大学生竞赛管理系统-计算机毕业设计源码37276

摘 要 随着教育信息化的不断发展&#xff0c;大学生竞赛已成为高校教育的重要组成部分。传统的竞赛组织和管理方式存在着诸多问题&#xff0c;如信息不透明、效率低下、管理不便等。为了解决这些问题&#xff0c;提高竞赛组织和管理效率&#xff0c;本文设计并实现了一个基于Sp…

在目标检测数据集上微调Florence-2

Florence-2是由微软开源的轻量级视觉-语言模型,采用MIT许可。该模型在任务如图像描述、目标检测、定位和分割中展示了强大的零样本和微调能力。 图1。图示展示了每个任务所表达的空间层次和语义细粒度水平。来源:Florence-2:推进多种视觉任务的统一表示。 该模型将图…

【SVN的使用- SVN的基本命令-SVN命令简写-注意事项-解决冲突 Objective-C语言】

一、SVN的更新命令:update 1.服务器如果新建了一个文件夹,yuanxing,版本变成6了, 我现在本地还只有三个文件夹,版本5, 终端里边,我们敲一个svn update, 我这儿就多了一个yuanxing文件夹, 这个就是更新,就是把服务器最新的代码下载下来, 假设服务器上大家提交了这…

短视频剪辑软件-剪映必备快捷键大全 沈阳短视频剪辑培训

对于用剪映电脑版的朋友来说 快捷键是很重要的 那么剪映专业版有哪些快捷键呢 今天总结了一下快捷键大全 赶快收藏吧 1、基础功能 复制&#xff1a;Ctrl&#xff0b;C 粘贴&#xff1a;Ctrl&#xff0b;v 分割&#xff1a;Ctrl B 删除&#xff1a;Back 新建草稿&…

广汇汽车:救得起来吗?

五折奔驰、六折宝马...BBA们“腰斩式”大降价后正在引发连锁反应。 国内第二大汽车经销商——广汇汽车&#xff0c;还好吗&#xff1f; 受新能源品牌冲击&#xff0c;近年来奔驰、宝马等豪华燃油品牌销量低迷&#xff0c;纷纷开启降价模式&#xff0c;首当其冲的就是以广汇汽车…

使用Sui索引框架支持自定义数据导入

Sui索引框架通过强大的数据导入框架提供对Sui链上数据的定制化访问。它允许任何相关软件&#xff0c;无论是在链上还是链下运行&#xff0c;收集原始链上数据和派生数据。 利用Sui索引框架创建定制的数据流&#xff0c;开发者可以轻松构建响应链上事件的软件和产品。 链上数据…

消息称台积电下周开始试产 2nm 芯片,有望率先用于苹果 iPhone 17

消息称台积电下周开始试产 2nm 芯片&#xff0c;有望率先用于苹果 iPhone 17 &#x1f4a1;&#x1f4f1; 大家好&#xff0c;我是猫头虎&#xff0c;科技自媒体博主 &#x1f431;&#x1f42f;&#xff0c;带你洞察科技世界的每一个细节&#xff01;&#x1f525; 关于猫头…

windows远程桌面到 Linux系统(Ubuntu:22.04)—— 安装xrdp软件

1、在Linux系统上安装xrdp软件 sudo apt update sudo apt install xrdp2、安装完成后&#xff0c;需要开启xrdp服务 sudo systemctl start xrdp sudo systemctl enable xrdp打印返回 Synchronizing state of xrdp.service with SysV service script with /lib/systemd/system…

人生苦短,我用Python+Docker

今天用一个简单的例子&#xff0c;介绍下如何使用Docker进行Python部署。 前期准备 本地需要有Python环境&#xff1b; 一个Linux的服务器并已经装好Docker &#xff1b; 能把代码上传到服务端的工具。 本文的本地环境是Win10Python3.12&#xff0c;服务器使用Ubuntu的云服…

TikTok短视频矩阵系统源码:创新驱动的内容生态引擎

在全球化的数字媒体时代&#xff0c;短视频已成为连接创作者与观众的桥梁。TikTok作为全球领先的短视频社交平台&#xff0c;其背后的短视频矩阵系统源码是支撑这一平台创新与成长的关键。本文将深入探讨TikTok短视频矩阵系统源码如何通过多账号管理、AI自动生成文案、批量剪辑…

开发个人Go-ChatGPT--6 OpenUI

开发个人Go-ChatGPT–6 OpenUI Open-webui Open WebUI 是一种可扩展、功能丰富且用户友好的自托管 WebUI&#xff0c;旨在完全离线运行。它支持各种 LLM 运行器&#xff0c;包括 Ollama 和 OpenAI 兼容的 API。 功能 由于总所周知的原由&#xff0c;OpenAI 的接口需要密钥才…

弱电工程质量保修期是多久?

弱电工程是电力工程的一个分类&#xff0c;弱电可以向人们提供照明用电和空调用电&#xff0c;为人们的生活带来了极大的便利。弱电工程作为一类工程项目存在质量保证问题&#xff0c;在施工完成后需要进行质量检修&#xff0c;施工队应该向业主提供一定的质量保修期&#xff0…

[ACM独立出版]2024年虚拟现实、图像和信号处理国际学术会议(ICVISP 2024)

[ACM独立出版]2024年虚拟现实、图像和信号处理国际学术会议&#xff08;ICVISP 2024&#xff09; 2024 International Conference on Virtual Reality, Image and Signal Processing 最新消息ICVISP 2024-已通过ACM出版申请投稿免费参会&#xff0c;口头汇报或海报展示(可获得…

Python requests爬虫

Python的requests库是一个强大且易于使用的HTTP库&#xff0c;用于发送HTTP请求和处理响应。它是Python中最受欢迎的网络爬虫框架之一&#xff0c;被广泛用于从网页中提取数据、爬取网站和进行API调用。 使用requests库&#xff0c;你可以轻松地发送各种HTTP请求&#xff0c;包…

element el-upload 粘贴上传图片

对form中的某一个el-form-item添加 paste.native 事件&#xff0c;事件绑定方法名 handlePaste也可以在其他控件中添加事件监听&#xff0c;这里在当前form-item 这个块使用了&#xff0c;只有当你点击目标区域时才有效。 <el-form-item label"备注图片" paste.n…

仕考网:事业单位b类考试考什么?

事业单位B类考试科目为《职业能力倾向测验(B类)》和《综合应用能力(B类)》两项&#xff0c;旨在全面评估应试者在多个领域的基本素质和专业能力。涵盖历史、自然科学、时事政治以及法律等关键方面&#xff0c;以确保选拔出的人员能够适应事业单位社会科学专技类岗位的需求。考试…

MQTT是什么,物联网

写文思路&#xff1a; 以下从几个方面介绍MQTT&#xff0c;包括&#xff1a;MQTT是什么&#xff0c;MQTT和webSocket的结合&#xff0c;以及使用场景&#xff0c; 一、MQTT是什么 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的发布/订阅消息…

Linux上安装JDK 1.8:详细步骤与环境配置

感谢您阅读本文&#xff0c;欢迎“一键三连”。作者定会不负众望&#xff0c;按时按量创作出更优质的内容。 ❤️ 1. 毕业设计专栏&#xff0c;毕业季咱们不慌&#xff0c;上千款毕业设计等你来选。 安装 JDK 1.8 在 Linux 上的步骤&#xff1a; 1.下载 JDK 1.8 JDK 1.8 可以…