zoukankan      html  css  js  c++  java
  • ts文件分析(纯c解析代码)

    参考链接: 1. MPEG-2 TS码流分析 https://blog.csdn.net/zhubin215130/article/details/8958567

    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}
    ", 
    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}
    ", 
    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}
    ", 
    175                         offset, tsHeader.pid, tsHeader.continuity_counter);
    176             }
    177             else
    178             {
    179                 printf("0x%08x Transport Packet{PID = 0x%x, Payload = NO, Counter = %d}
    ", 
    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}
    ", 
    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}
    ", 
    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
    ", 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
    ", 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
    ", 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)
    ", 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] = '';
    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}
    ", 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}
    ", TAB46, TAB44, pes.streamId);
    486     }
    487     
    488     printf("%s%s%s packet_length = %d, PES_header_data_length = %d
    ", TAB46, TAB44, TAB44, pes.pesLength, pes.pesHeaderLen);
    489     printf("%s%s%s PTS: %s(%lld), DTS: %s(%lld)
    ", 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
    ");
    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!
    ", 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

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

  • 相关阅读:
    Nhibernate对象转JSON
    C# Windows服务
    C# 接收http请求
    C# XML 基础解系
    C# XML 序列化与反序列化
    C# Newtonsoft.Json 应用
    C# 读取自定义XML
    对图片添加水印
    iText: 对pdf文件添加水印
    java对Office文件处理技术(介绍)
  • 原文地址:https://www.cnblogs.com/leaffei/p/10559040.html
Copyright © 2011-2022 走看看