TS Header
PAT
PMT
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <arpa/inet.h>
5
6 #define TAB44 " "
7 #define TAB46 " "
8 #define PRINTF_DEBUG
9
10 #define TS_PAT_PID 0x0
11
12 #define TS_PAT_TABLE_PID 0x0
13 #define TS_PMT_TABLE_PID 0x2
14
15 #define MAX_PDTS_LEN 5
16 #define MAX_TS_PROGRAM_NUM 8
17 #define MAX_TS_STREAM_NUM 8
18 #define MAX_PDTS_STRING_LEN 12
19 #define MAX_TS_PACKET_LEN 188 /* 204, 188+16字节的CRC */
20
21
22 /******************************************************************
23 视频
24 MPEG-1 Video:stream_type为0x01
25 MPEG-2 Video:stream_type为0x02
26 AVC(H264):stream_type为0x1b
27 VC-1:stream_type为0xea
28
29 音频
30 Mpeg-1 Audio:stream_type为0x03
31 Mpeg-2 Audio:stream_type为0x04
32 Mpeg-2 AAC:stream_type为0x0f
33 Mpeg-4 AAC:stream_type为0x11
34 LPCM:stream_type为0x80
35 AC3:stream_type为0x81或0x06
36 DTS:stream_type为0x82
37 Dolby TrueHD:stream_type为0x83
38 AC3-Plus:stream_type为0x84
39 DTS_HD:stream_type为0x85
40 DTS-MA:stream_type为0x86
41 AC3-Plus_SEC:steam_type为0xa1
42 DTS_HD_SEC:stream_type为0xa2
43
44 字幕
45 PGS:stream_type为0x90
46 IGS:steam_type为0x91,暂不支持
47 Text Subtitle:stream_type为0x92
48 ********************************************************************/
49 typedef enum t_ts_stream_type
50 {
51 E_STREAM_TYPE_MPEG1_VIDEO = 0x01,
52 E_STREAM_TYPE_MPEG2_VIDEO = 0x02,
53 E_STREAM_TYPE_AVC_VIDEO = 0x1B,
54 E_STREAM_TYPE_VC1_VIDEO = 0xEA,
55 E_STREAM_TYPE_MPEG1_AUDIO = 0x03,
56 E_STREAM_TYPE_MPEG2_AUDIO = 0x04,
57 E_STREAM_TYPE_MPEG2_AAC = 0x0F,
58 E_STREAM_TYPE_MPEG4_AAC = 0x11,
59 E_STREAM_TYPE_AC3 = 0x81,
60 } T_TS_STREAM_TYPE;
61
62 /* 4 bytes */
63 typedef struct t_ts_packet_header
64 {
65 unsigned char sync_byte;
66 unsigned short transport_error_indictor:1, playload_unit_start_indictor:1, transport_priority:1, pid:13;
67 unsigned char transport_scrambling_control:2, adaptation_field_control:2, continuity_counter:4;
68 } T_TS_PACKET_HEADER;
69
70 /* PAT */
71 typedef struct t_ts_program
72 {
73 unsigned short program_number;
74 unsigned short program_map_pid;
75 } T_TS_PROGRAM;
76
77 typedef struct t_ts_pat
78 {
79 unsigned char table_id;
80 unsigned short section_len;
81 unsigned char version_num:5;
82 unsigned short programNum;
83
84 T_TS_PROGRAM programs[MAX_TS_PROGRAM_NUM];
85 } T_TS_PAT;
86
87 /* PMT */
88 typedef struct t_ts_stream
89 {
90 unsigned char stream_type;
91 unsigned short elementary_pid;
92 } T_TS_STREAM;
93
94 typedef struct t_ts_pmt
95 {
96 unsigned short pmtIsFind;
97 unsigned char table_id;
98 unsigned short section_len;
99 unsigned short program_number;
100 unsigned char version_num:5;
101 unsigned short program_info_length;
102
103 unsigned short streamNum;
104
105 T_TS_STREAM streams[MAX_TS_STREAM_NUM];
106 } T_TS_PMT;
107
108 /* PES */
109 typedef struct t_ts_pes
110 {
111 unsigned char streamId;
112
113 unsigned short pesLength;
114
115 long long pts;
116 long long dts;
117
118 unsigned char ptsStr[MAX_PDTS_STRING_LEN+1];
119 unsigned char dtsStr[MAX_PDTS_STRING_LEN+1];
120
121 unsigned char pesHeaderLen;
122 } T_TS_PES;
123
124 T_TS_PAT g_TsPat = {0};
125 T_TS_PMT g_TsPmt[MAX_TS_PROGRAM_NUM] = {0};
126
127 static void ParseTsHeader(unsigned char* const headerData, T_TS_PACKET_HEADER *tsPacketHeader)
128 {
129 static int tsPacketNum = 0;
130
131 int offset = 0;
132
133 unsigned char *data = NULL;
134
135 T_TS_PACKET_HEADER tsHeader = {0};
136
137 memset(&tsHeader, 0x0, sizeof(tsHeader));
138
139 data = headerData;
140
141 tsHeader.sync_byte = data[0];
142 tsHeader.transport_error_indictor = ((data[1]>>7)&0x1);
143 tsHeader.playload_unit_start_indictor = ((data[1]>>6)&0x1);
144 tsHeader.transport_priority = ((data[1]>>5)&0x1);
145 tsHeader.pid = (((data[1]&0x1f)<<8) | data[2]);
146 tsHeader.transport_scrambling_control = ((data[3]>>6)&0x3);
147 tsHeader.adaptation_field_control = ((data[3]>>4)&0x3);
148 tsHeader.continuity_counter = data[3]&0xf;
149
150 memcpy(tsPacketHeader, &tsHeader, sizeof(tsHeader));
151
152 #ifdef PRINTF_DEBUG
153 offset = tsPacketNum*MAX_TS_PACKET_LEN;
154
155 switch (tsHeader.adaptation_field_control)
156 {
157 case 1:
158 if (tsHeader.playload_unit_start_indictor)
159 {
160 printf("0x%08x Transport Packet{PID = 0x%x, Payload = YES(%d), Counter = %d, Start indicactor}\n",
161 offset, tsHeader.pid, MAX_TS_PACKET_LEN-4, tsHeader.continuity_counter);
162 }
163 else
164 {
165 printf("0x%08x Transport Packet{PID = 0x%x, Payload = YES(%d), Counter = %d}\n",
166 offset, tsHeader.pid, MAX_TS_PACKET_LEN-4, tsHeader.continuity_counter);
167 }
168
169 break;
170
171 case 2:
172 if (tsHeader.playload_unit_start_indictor)
173 {
174 printf("0x%08x Transport Packet{PID = 0x%x, Payload = NO, Counter = %d, Start indicactor}\n",
175 offset, tsHeader.pid, tsHeader.continuity_counter);
176 }
177 else
178 {
179 printf("0x%08x Transport Packet{PID = 0x%x, Payload = NO, Counter = %d}\n",
180 offset, tsHeader.pid, tsHeader.continuity_counter);
181 }
182
183 break;
184
185 case 3:
186 if (tsHeader.playload_unit_start_indictor)
187 {
188 printf("0x%08x Transport Packet{PID = 0x%x, Payload = YES(%d), Counter = %d, Start indicactor}\n",
189 offset, tsHeader.pid, MAX_TS_PACKET_LEN-4-1-data[4], tsHeader.continuity_counter);
190 }
191 else
192 {
193 printf("0x%08x Transport Packet{PID = 0x%x, Payload = YES(%d), Counter = %d}\n",
194 offset, tsHeader.pid, MAX_TS_PACKET_LEN-4-1-data[4], tsHeader.continuity_counter);
195 }
196
197 break;
198
199 default:
200 break;
201
202 }
203
204 tsPacketNum++;
205 #endif
206 }
207
208 static void ParseTsPat(unsigned char* const patData, T_TS_PAT *tsPat)
209 {
210 int i = 0;
211 int sectionLen = 0;
212
213 unsigned char *data = NULL;
214
215 T_TS_PAT pat = {0};
216
217 memset(&pat, 0x0, sizeof(pat));
218
219 data = patData;
220
221 pat.table_id = data[0];
222
223 if (TS_PAT_TABLE_PID != pat.table_id)
224 {
225 return;
226 }
227
228 sectionLen = ((data[1]&0xf)<<8) | data[2];
229 pat.section_len = sectionLen;
230
231 pat.version_num = ((data[5]>>1) & 0x1f);
232
233 data += 8;
234 sectionLen -= (5+4); /* len is after section_len and not have crc */
235
236 while (sectionLen>0)
237 {
238 if (i >= MAX_TS_PROGRAM_NUM)
239 {
240 break;
241 }
242
243 pat.programs[i].program_number = ((data[0]<<8) | data[1]);
244
245 if (0 != pat.programs[i].program_number)
246 {
247 pat.programs[i].program_map_pid = (((data[2]&0x1f)<<8) | data[3]);
248 }
249
250 data += 4;
251 sectionLen -= 4;
252
253 i++;
254
255 pat.programNum = i;
256 }
257
258 memcpy(tsPat, &pat, sizeof(pat));
259
260 #ifdef PRINTF_DEBUG
261 printf("%s%s Program Association Table, version: %d\n", TAB46, TAB44, pat.version_num);
262
263 for (i=0; i<pat.programNum; i++)
264 {
265 printf("%s%s%s program_number: %d, program_map_PID: 0x%x\n", TAB46, TAB44, TAB44, pat.programs[i].program_number, pat.programs[i].program_map_pid);
266 }
267 #endif
268 }
269
270 static void ParseTsPmt(unsigned char* const pmtData, T_TS_PMT *tsPmt)
271 {
272 int i = 0;
273 int sectionLen = 0;
274 int program_info_length = 0;
275 int es_info_length = 0;
276
277 unsigned char *data = NULL;
278
279 T_TS_PMT pmt = {0};
280
281 memset(&pmt, 0x0, sizeof(pmt));
282
283 data = pmtData;
284
285 pmt.table_id = data[0];
286
287 if (TS_PMT_TABLE_PID != pmt.table_id)
288 {
289 return;
290 }
291
292 sectionLen = ((data[1]&0xf)<<8) | data[2];
293 pmt.section_len = sectionLen;
294
295 pmt.program_number = data[3]<<8 | data[4];
296
297 pmt.version_num = ((data[5]>>1) & 0x1f);
298
299 data += 10;
300 sectionLen -= (7+4);
301
302 program_info_length = ((data[0]&0xf)<<8) | data[1];
303
304 data += 2;
305 sectionLen -= 2;
306
307 data += program_info_length;
308 sectionLen -= program_info_length;
309
310 while (sectionLen > 0)
311 {
312 if (i >= MAX_TS_STREAM_NUM)
313 {
314 break;
315 }
316
317 pmt.streams[i].stream_type = data[0];
318 pmt.streams[i].elementary_pid = (((data[1]&0x1f)<<8) | data[2]);
319
320 es_info_length = ((data[3]&0xf)<<8) | data[4];
321
322 data += 5;
323 sectionLen -= 5;
324
325 data += es_info_length;
326 sectionLen -= es_info_length;
327
328 i++;
329
330 pmt.streamNum = i;
331 }
332
333 pmt.pmtIsFind = 1;
334
335 memcpy(tsPmt, &pmt, sizeof(pmt));
336
337 #ifdef PRINTF_DEBUG
338 printf("%s%s Program Map Table, version: %d\n", TAB46, TAB44, pmt.version_num);
339
340 for (i=0; i<pmt.streamNum; i++)
341 {
342 printf("%s%s%s stream_type: 0x%x(%d), elementary_pid: 0x%x(%d)\n", TAB46, TAB44, TAB44, pmt.streams[i].stream_type, pmt.streams[i].stream_type,
343 pmt.streams[i].elementary_pid, pmt.streams[i].elementary_pid);
344 }
345 #endif
346 }
347
348 static void getPdts(unsigned char *pdtsData, long long *pdts, unsigned char *pdtsString)
349 {
350 int hour = 0;
351 int minute = 0;
352 int second = 0;
353 int msecond = 0;
354
355 long long pts = 0;
356 long long pts2Ms = 0;
357
358 unsigned char ptsStr[MAX_PDTS_STRING_LEN+1] = {0};
359
360 /* 5个字节转33位的值 */
361 pts = (((pdtsData[0]>>1) & 0x7) << 30) | (pdtsData[1] << 22) | (((pdtsData[2]>>1) & 0x7f) << 15) | (pdtsData[3] << 7) | (pdtsData[4]>>1 & 0x7f);
362
363 /* 90KHz, 1000ms/90 */
364 pts2Ms = pts/90;
365
366 hour = pts2Ms/(60*60*1000);
367 minute = (pts2Ms - hour * (60*60*1000)) / (60*1000);
368 second = (pts2Ms - hour * (60*60*1000) - minute * (60*1000)) / 1000;
369 msecond = pts2Ms - hour * (60*60*1000) - minute * (60*1000) - second * 1000;
370
371 sprintf(ptsStr, "%02d:%02d:%02d:%03d", hour, minute, second, msecond);
372
373 ptsStr[MAX_PDTS_STRING_LEN] = '\0';
374
375 memcpy(pdtsString, ptsStr, MAX_PDTS_STRING_LEN);
376
377 *pdts = pts;
378 }
379
380 /**************************************************************************************
381 1. 根据playload_unit_start_indictor=1, 只解析这个ts包(该字段指示section, pes等的起始标识,
382 若要拼包则根据这个字段, 一个整包结束这个字段会置0);
383 2. 这里暂时不获取所有的pes包去解析, 只解析PES的头;
384 3. 可能的问题是一个ts包可能有填充字段, 根据此字段的指示adaptation_field_control(判断有无填充),
385 然后4字节包头后的第5个字节指示填充字段的长度, 若该长度大于一个ts包的长度, 则在此处是解析
386 不到PES的数据的, 真正的PES数据应该在下一包;
387 4. adaptation_field_control(适配域控制): 表示包头是否有调整字段或有效负载.
388 '00'为ISO/IEC未来使用保留;
389 '01'仅含有效载荷, 无调整字段;
390 '10'无有效载荷, 仅含调整字段;
391 '11'调整字段后为有效载荷, 调整字段中的前一个字节表示调整字段的长度length, 有效载荷开始的位置应再偏移length个字节;
392 空包应为'10'.
393 ** 这个地方有一个未证实的(基本不会错), 记录下来: adapt=1时, 貌似对于PSI/SI数据在第5个字节会写一个00(代码处理的地方为main(),ParseTsPat(&tsPacket[4+1], &g_TsPat)),
394 对于pes数据若为1, 直接跟有效数据(代码处理的地方为ParsePes(), data += (4+1+data[4]).
395 5. 此处还有一个需说明的, 有时会发现packet_length为0. 这个比较特殊, 标准里有说明.
396 因为pes_packet_length为16个字节, 最大只能支持到65535, 当一个pes包大于这个数值的时候,
397 处理方法是这个值为0, 实际的大小由上层协议决定.(只有当ts传输pes的时候才能这么做,
398 通过根据playload_unit_start_indictor=1/0就可以确定这个pes包的真实长度.)
399 6. 对于H264, 可能的就是将SPS, PPS等信息(数据量比较小)放到一个ts包中.
400 ***************************************************************************************/
401 static void ParsePes(unsigned char* const pesData, T_TS_PACKET_HEADER* const tsHeader)
402 {
403 unsigned char pts_dts_flag;
404
405 unsigned char *data = NULL;
406
407 unsigned char pts[MAX_PDTS_LEN+1] = {0};
408 unsigned char dts[MAX_PDTS_LEN+1] = {0};
409
410 T_TS_PES pes = {0};
411
412 data = pesData;
413
414 memset(&pes, 0x0, sizeof(pes));
415
416 /* deal adaptation */
417 if ((0 == tsHeader->adaptation_field_control)
418 || (2 == tsHeader->adaptation_field_control))
419 {
420 return;
421 }
422
423 if (1 == tsHeader->adaptation_field_control)
424 {
425 data += 4;
426 }
427 else /* 3 */
428 {
429 /* header(4) + adaptlen(1) + adaptdata(adaptlen) */
430 data += (4+1+data[4]);
431 }
432
433
434 data += 3; /* start code 00 00 01*/
435
436 pes.streamId = data[0];
437 pes.pesLength = (data[1]<<8) | data[2];
438
439 data += 3; /* streamid(1) + pes_len(2) */
440
441 pts_dts_flag = data[1]>>6 & 0x3;
442
443 pes.pesHeaderLen = data[2];
444
445 data += 3;
446
447 switch (pts_dts_flag)
448 {
449 case 0: /* 00, no pts, dts */
450 break;
451
452 case 2: /* 10, only pts*/
453 memset(pts, 0x0, sizeof(pts));
454
455 memcpy(pts, data, MAX_PDTS_LEN);
456
457 getPdts(pts, &pes.pts, pes.ptsStr);
458
459 break;
460
461 case 3: /* 11 pts & dts*/
462 memset(pts, 0x0, sizeof(pts));
463 memset(dts, 0x0, sizeof(dts));
464
465 memcpy(pts, data, MAX_PDTS_LEN);
466 memcpy(dts, data+MAX_PDTS_LEN, MAX_PDTS_LEN);
467
468 getPdts(pts, &pes.pts, pes.ptsStr);
469 getPdts(dts, &pes.dts, pes.dtsStr);
470
471 break;
472
473 default:
474 break;
475 }
476
477 #ifdef PRINTF_DEBUG
478 if ((pes.streamId>=0xC0) && (pes.streamId<=0xDF))
479 {
480 printf("%s%s PES Packet(Audio) {stream_id = 0x%x}\n", TAB46, TAB44, pes.streamId);
481 }
482
483 if ((pes.streamId>=0xE0) && (pes.streamId<=0xEF))
484 {
485 printf("%s%s PES Packet(Video) {stream_id = 0x%x}\n", TAB46, TAB44, pes.streamId);
486 }
487
488 printf("%s%s%s packet_length = %d, PES_header_data_length = %d\n", TAB46, TAB44, TAB44, pes.pesLength, pes.pesHeaderLen);
489 printf("%s%s%s PTS: %s(%lld), DTS: %s(%lld)\n", TAB46, TAB44, TAB46, pes.ptsStr, pes.pts, pes.dtsStr, pes.dts);
490 #endif
491
492 /*
493 1. todo: this test video is h264, parse pes data;
494 2. get pes data, find h264 startcode, parse nual.
495 */
496 }
497
498 int main(int argc, char *argv[])
499 {
500 int i = 0;
501 int j = 0;
502 int k = 0;
503 int patIsFind = 0;
504 int allPmtIsFind = 0;
505
506 unsigned char tsPacket[MAX_TS_PACKET_LEN] = {0};
507
508 T_TS_PACKET_HEADER tsPacketHeader = {0};
509
510 FILE *fp = NULL;
511
512 if (2 != argc)
513 {
514 printf("Usage: tsparse **.ts\n");
515
516 return -1;
517 }
518
519 memset(&g_TsPat, 0x0, sizeof(T_TS_PAT));
520 memset(g_TsPmt, 0x0, sizeof(g_TsPmt));
521
522 fp = fopen(argv[1], "rb");
523 if (!fp)
524 {
525 printf("open file[%s] error!\n", argv[1]);
526
527 return -1;
528 }
529
530 while (1)
531 {
532 memset(tsPacket, 0x0, MAX_TS_PACKET_LEN);
533 memset(&tsPacketHeader, 0x0, sizeof(tsPacketHeader));
534
535 if (MAX_TS_PACKET_LEN != fread(tsPacket, 1, MAX_TS_PACKET_LEN, fp))
536 {
537 break;
538 }
539
540 ParseTsHeader(tsPacket, &tsPacketHeader);
541
542 /* pat->pmt->(audio/video pid)->video data */
543 if (0 == patIsFind)
544 {
545 if (TS_PAT_PID == tsPacketHeader.pid)
546 {
547 /* 4(header) + 1(adapt len)*/
548 ParseTsPat(&tsPacket[4+1], &g_TsPat);
549
550 patIsFind = 1;
551 }
552 }
553
554 if ((1 == patIsFind) && (1 != allPmtIsFind))
555 {
556 for (i=0; i<g_TsPat.programNum; i++)
557 {
558 if ((g_TsPat.programs[i].program_map_pid == tsPacketHeader.pid)
559 && (0 == g_TsPmt[j].pmtIsFind))
560 {
561 ParseTsPmt(&tsPacket[4+1], &g_TsPmt[j]);
562
563 j++;
564 }
565 }
566
567 for (i=0; i<g_TsPat.programNum; i++)
568 {
569 if (0 == g_TsPmt[i].pmtIsFind)
570 {
571 break;
572 }
573 }
574
575 if (i == g_TsPat.programNum)
576 {
577 allPmtIsFind = 1;
578 }
579 }
580
581 if (allPmtIsFind)
582 {
583 for (i=0; i<g_TsPat.programNum; i++)
584 {
585 for (k=0; k<g_TsPmt[i].streamNum; k++)
586 {
587 if ((g_TsPmt[i].streams[k].elementary_pid == tsPacketHeader.pid)
588 && (1 == tsPacketHeader.playload_unit_start_indictor))
589 {
590 ParsePes(tsPacket, &tsPacketHeader);
591 }
592 }
593 }
594 }
595 }
596
597 fclose(fp);
598 }
View Code