h265文件分析(纯c解析代码)
Posted leaffei
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了h265文件分析(纯c解析代码)相关的知识,希望对你有一定的参考价值。
参考链接: 1. HEVC码流解析 https://blog.csdn.net/CrystalShaw/article/details/80624804
2. HEVC编码结构:序列参数集SPS、图像参数集PPS、视频参数集VPS https://blog.csdn.net/lin453701006/article/details/52797104
3. H265码流结构分析 https://blog.csdn.net/u011003120/article/details/83411445#11_H265_4
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <arpa/inet.h> 5 6 #define TAB44 " " 7 #define PRINTF_DEBUG 8 9 #define PRTNTF_STR_LEN 10 10 11 typedef enum e_hevc_nalu_type { 12 HEVC_NAL_TRAIL_N = 0, 13 HEVC_NAL_TRAIL_R = 1, 14 HEVC_NAL_TSA_N = 2, 15 HEVC_NAL_TSA_R = 3, 16 HEVC_NAL_STSA_N = 4, 17 HEVC_NAL_STSA_R = 5, 18 HEVC_NAL_RADL_N = 6, 19 HEVC_NAL_RADL_R = 7, 20 HEVC_NAL_RASL_N = 8, 21 HEVC_NAL_RASL_R = 9, 22 HEVC_NAL_VCL_N10 = 10, 23 HEVC_NAL_VCL_R11 = 11, 24 HEVC_NAL_VCL_N12 = 12, 25 HEVC_NAL_VCL_R13 = 13, 26 HEVC_NAL_VCL_N14 = 14, 27 HEVC_NAL_VCL_R15 = 15, 28 HEVC_NAL_BLA_W_LP = 16, 29 HEVC_NAL_BLA_W_RADL = 17, 30 HEVC_NAL_BLA_N_LP = 18, 31 HEVC_NAL_IDR_W_RADL = 19, 32 HEVC_NAL_IDR_N_LP = 20, 33 HEVC_NAL_CRA_NUT = 21, 34 HEVC_NAL_IRAP_VCL22 = 22, 35 HEVC_NAL_IRAP_VCL23 = 23, 36 HEVC_NAL_RSV_VCL24 = 24, 37 HEVC_NAL_RSV_VCL25 = 25, 38 HEVC_NAL_RSV_VCL26 = 26, 39 HEVC_NAL_RSV_VCL27 = 27, 40 HEVC_NAL_RSV_VCL28 = 28, 41 HEVC_NAL_RSV_VCL29 = 29, 42 HEVC_NAL_RSV_VCL30 = 30, 43 HEVC_NAL_RSV_VCL31 = 31, 44 HEVC_NAL_VPS = 32, 45 HEVC_NAL_SPS = 33, 46 HEVC_NAL_PPS = 34, 47 HEVC_NAL_AUD = 35, 48 HEVC_NAL_EOS_NUT = 36, 49 HEVC_NAL_EOB_NUT = 37, 50 HEVC_NAL_FD_NUT = 38, 51 HEVC_NAL_SEI_PREFIX = 39, 52 HEVC_NAL_SEI_SUFFIX = 40 53 } E_HEVC_NALU_TYPE; 54 55 /******************************************************************************** 56 typedef struct t_h264_nalu_header 57 { 58 unsigned char forbidden_bit:1, nal_reference_idc:2, nal_unit_type:5; 59 } T_H264_NALU_HEADER; (1个字节, hevc header为2个字节) 60 *********************************************************************************/ 61 typedef struct t_h265_nalu_header 62 { 63 unsigned short forbidden_zero_bit:1, nuh_reserved_zero_6bits:6, nal_unit_type:6, nuh_temporal_id_plus1:3; 64 } T_H265_NALU_HEADER; 65 66 typedef struct t_h265_nalu 67 { 68 int startCodeLen; 69 70 T_H265_NALU_HEADER h265NaluHeader; 71 72 unsigned int bodyLen; 73 74 unsigned char *bodyData; 75 } T_H265_NALU; 76 77 /********************************************************************************** 78 1. h265的起始码: 0x000001(3 Bytes)或0x00000001(4 Bytes); 79 2. 文件流中用起始码来区分NALU; 80 3. 如果NALU类型为vps, sps, pps, 或者解码顺序为第一个AU的第一个NALU, 起始码前面再加一个0x00 81 视频流的首个NALU的起始码前加入0x00(4 Bytes的由来). 82 ***********************************************************************************/ 83 static int FindStartCode3Bytes(unsigned char *scData) 84 { 85 int isFind = 0; 86 87 if ((0==scData[0]) && (0==scData[1]) && (1==scData[2])) 88 { 89 isFind = 1; 90 } 91 92 return isFind; 93 } 94 95 static int FindStartCode4Bytes(unsigned char *scData) 96 { 97 int isFind = 0; 98 99 if ((0==scData[0]) && (0==scData[1]) && (0==scData[2]) && (1 == scData[3])) 100 { 101 isFind = 1; 102 } 103 104 return isFind; 105 } 106 107 static int GetNaluDataLen(int startPos, int h265BitsSize, unsigned char *h265Bits) 108 { 109 int parsePos = 0; 110 111 parsePos = startPos; 112 113 while (parsePos < h265BitsSize) 114 { 115 if (FindStartCode3Bytes(&h265Bits[parsePos])) 116 { 117 return parsePos - startPos; 118 } 119 else if (FindStartCode4Bytes(&h265Bits[parsePos])) 120 { 121 return parsePos - startPos; 122 } 123 else 124 { 125 parsePos++; 126 } 127 } 128 129 return parsePos - startPos; // if file is end 130 } 131 132 static void ParseNaluData(const unsigned int naluLen, unsigned char* const nuluData) 133 { 134 static int naluNum = 0; 135 136 unsigned char *data = NULL; 137 unsigned char typeStr[PRTNTF_STR_LEN+1] = {0}; 138 139 T_H265_NALU_HEADER h265NaluHeader = {0}; 140 141 data = nuluData; 142 143 memset(&h265NaluHeader, 0x0, sizeof(T_H265_NALU_HEADER)); 144 145 h265NaluHeader.nal_unit_type = ((data[0]>>1) & 0x3f); 146 147 naluNum++; 148 149 #ifdef PRINTF_DEBUG 150 switch (h265NaluHeader.nal_unit_type) 151 { 152 case HEVC_NAL_TRAIL_N: 153 sprintf(typeStr, "B SLICE"); 154 break; 155 156 case HEVC_NAL_TRAIL_R: 157 sprintf(typeStr, "P SLICE"); 158 break; 159 160 case HEVC_NAL_IDR_W_RADL: 161 sprintf(typeStr, "IDR"); 162 break; 163 164 case HEVC_NAL_VPS: 165 sprintf(typeStr, "VPS"); 166 break; 167 168 case HEVC_NAL_SPS: 169 sprintf(typeStr, "SPS"); 170 break; 171 172 case HEVC_NAL_PPS: 173 sprintf(typeStr, "PPS"); 174 break; 175 176 case HEVC_NAL_SEI_PREFIX: 177 sprintf(typeStr, "SEI"); 178 break; 179 180 default: 181 sprintf(typeStr, "NTYPE(%d)", h265NaluHeader.nal_unit_type); 182 break; 183 } 184 185 printf("%5d| %7s| %8d| ", naluNum, typeStr, naluLen); 186 #endif 187 } 188 189 int main(int argc, char *argv[]) 190 { 191 int fileLen = 0; 192 int naluLen = 0; 193 int h265BitsPos = 0; /* h265, hevc; h264, avc系列, Advanced Video Coding */ 194 195 unsigned char *h265Bits = NULL; 196 unsigned char *naluData = NULL; 197 198 FILE *fp = NULL; 199 200 if (2 != argc) 201 { 202 printf("Usage: flvparse **.flv "); 203 204 return -1; 205 } 206 207 fp = fopen(argv[1], "rb"); 208 if (!fp) 209 { 210 printf("open file[%s] error! ", argv[1]); 211 212 return -1; 213 } 214 215 fseek(fp, 0, SEEK_END); 216 217 fileLen = ftell(fp); 218 219 fseek(fp, 0, SEEK_SET); 220 221 h265Bits = (unsigned char*)malloc(fileLen); 222 if (!h265Bits) 223 { 224 printf("maybe file is too long, or memery is not enough! "); 225 226 fclose(fp); 227 228 return -1; 229 } 230 231 memset(h265Bits, 0x0, fileLen); 232 233 if (fread(h265Bits, 1, fileLen, fp) < 0) 234 { 235 printf("read file data to h265Bits error! "); 236 237 fclose(fp); 238 free(h265Bits); 239 240 h265Bits = NULL; 241 242 return -1; 243 } 244 245 fclose(fp); 246 247 printf("-----+--- NALU Table --+ "); 248 printf(" NUM | TYPE | LEN | "); 249 printf("-----+-------+---------+ "); 250 251 while (h265BitsPos < (fileLen-4)) 252 { 253 if (FindStartCode3Bytes(&h265Bits[h265BitsPos])) 254 { 255 naluLen = GetNaluDataLen(h265BitsPos+3, fileLen, h265Bits); 256 257 naluData = (unsigned char*)malloc(naluLen); 258 if (naluData) 259 { 260 memset(naluData, 0x0, naluLen); 261 262 memcpy(naluData, h265Bits+h265BitsPos+3, naluLen); 263 264 ParseNaluData(naluLen, naluData); 265 266 free(naluData); 267 naluData = NULL; 268 } 269 270 h265BitsPos += (naluLen+3); 271 } 272 else if (FindStartCode4Bytes(&h265Bits[h265BitsPos])) 273 { 274 naluLen = GetNaluDataLen(h265BitsPos+4, fileLen, h265Bits); 275 276 naluData = (unsigned char*)malloc(naluLen); 277 if (naluData) 278 { 279 memset(naluData, 0x0, naluLen); 280 281 memcpy(naluData, h265Bits+h265BitsPos+4, naluLen); 282 283 ParseNaluData(naluLen, naluData); 284 285 free(naluData); 286 naluData = NULL; 287 } 288 289 h265BitsPos += (naluLen+4); 290 } 291 else 292 { 293 h265BitsPos++; 294 } 295 } 296 297 return 0; 298 }
以上是关于h265文件分析(纯c解析代码)的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 创建反汇编解析器实例对象 | 设置汇编解析器显示细节 )(代码片段