leaffei

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, nal_unit_type:6, nuh_layer_id: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|\n", 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\n");
203 
204         return -1;
205     }
206 
207     fp = fopen(argv[1], "rb");
208     if (!fp)
209     {
210         printf("open file[%s] error!\n", 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!\n");
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!\n");
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 --+\n");
248     printf(" NUM |  TYPE |   LEN   |\n");
249     printf("-----+-------+---------+\n");
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 }
View Code

  最后如果您觉得本篇对您有帮助,可以打赏下,谢谢!!!

posted on 2019-03-18 17:59  leaffei  阅读(3975)  评论(0编辑  收藏  举报

导航