MpegTS流解复用程序实现(解复用得到PES和ES)

MpegTS基础看这几篇博文:

MpegTS基础

MpegTS之TS,PES,ES结构分析

 

TS流复用和解复用是一个相逆的过程。TS解复用得到的是音视频的PES裸流。一般来讲,每个TS包的长度是188个字节,也有一种204个字节的,就是在每个包后面加上16个字节的RS冗余校验信息。在这里分析188个字节的情况,其余的都类似了。

从文件中循环读取188个字节的包,然后对包进行逐字节分析,分析流程如下:

TS包的标志是首字节以0x47开头

如下图是一个ts包:

按位解析,得到pid,flag,错误标志,负载类型,PSI, PMI等信息。

源码分析如下:该源码是从一开源工具tsDemux截取,所有的ts流的解析过程无非也就是整么一个过程了。

 

[cpp]  view plain  copy
 
 print?
  1. <span style="font-family:SimHei;font-size:18px;">int ts::demuxer::demux_ts_packet(const char* ptr)  
  2. {  
  3.     u_int32_t timecode = 0;  
  4.   
  5.     const char* end_ptr = ptr + 188;  
  6.   
  7.     if (ptr[0] != 0x47)            // ts sync byte  
  8.         return -1;  
  9.     u_int16_t pid = to_int(ptr + 1);//get 2, 3 Byte  
  10.     u_int8_t flags = to_byte(ptr + 3);  
  11.   
  12.     bool transport_error = pid & 0x8000;  
  13.     /*ts带有PES包时,1:负载是PES,0:负载不是PES 
  14.       ts带有PSI数据时,1:带有PSI部分的第一个字节 0:不带有PSI部分的第一个字节 
  15.     */  
  16.     bool payload_unit_start_indicator = pid & 0x4000;  
  17.     bool adaptation_field_exist = flags & 0x20;  
  18.     bool payload_data_exist = flags & 0x10;  
  19.     u_int8_t continuity_counter = flags & 0x0f;  
  20.     //get PID  
  21.     pid &= 0x1fff;  
  22.   
  23.     if (transport_error)  
  24.         return -2;  
  25.   
  26.     //empty payload  
  27.     if (pid == 0x1fff || !payload_data_exist)  
  28.         return 0;  
  29.   
  30.     ptr += 4;  
  31.   
  32.     // skip adaptation field  
  33.     if (adaptation_field_exist)  
  34.     {  
  35.         ptr += to_byte(ptr) + 1;  
  36.         if (ptr >= end_ptr)  
  37.             return -3;  
  38.     }  
  39.   
  40.     stream& s = streams[pid];  
  41.   
  42.     if (!pid || (s.channel != 0xffff && s.type == 0xff))  
  43.     {  
  44.         // PSI  
  45.         if (payload_unit_start_indicator)  
  46.         {  
  47.             // begin of PSI table  
  48.             ptr++;  
  49.   
  50.             if (ptr >= end_ptr)  
  51.                 return -4;  
  52.   
  53.             if (*ptr != 0x00 && *ptr != 0x02)  
  54.                 return 0;  
  55.   
  56.             if (end_ptr - ptr < 3)  
  57.                 return -5;  
  58.   
  59.             u_int16_t l = to_int(ptr + 1);  
  60.   
  61.             if (l & 0x3000 != 0x3000)  
  62.                 return -6;  
  63.   
  64.             l &= 0x0fff;  
  65.   
  66.             ptr += 3;  
  67.   
  68.             int len = end_ptr - ptr;  
  69.   
  70.             if (l > len)  
  71.             {  
  72.                 if (l > ts::table::max_buf_len)  
  73.                     return -7;  
  74.   
  75.                 s.psi.reset();  
  76.   
  77.                 memcpy(s.psi.buf, ptr, len);  
  78.                 s.psi.offset += len;  
  79.                 s.psi.len = l;  
  80.   
  81.                 return 0;  
  82.             }  
  83.             else  
  84.                 end_ptr = ptr + l;  
  85.         }  
  86.         else  
  87.         {  
  88.             // next part of PSI  
  89.             if (!s.psi.offset)  
  90.                 return -8;  
  91.   
  92.             int len = end_ptr - ptr;  
  93.   
  94.             if (len > ts::table::max_buf_len - s.psi.offset)  
  95.                 return -9;  
  96.   
  97.             memcpy(s.psi.buf + s.psi.offset, ptr, len);  
  98.             s.psi.offset += len;  
  99.   
  100.             if (s.psi.offset < s.psi.len)  
  101.                 return 0;  
  102.             else  
  103.             {  
  104.                 ptr = s.psi.buf;  
  105.                 end_ptr = ptr + s.psi.len;  
  106.             }  
  107.         }  
  108.   
  109.         if (!pid)  
  110.         {  
  111.             // PAT  
  112.             ptr += 5;  
  113.   
  114.             if (ptr >= end_ptr)  
  115.                 return -10;  
  116.   
  117.             int len = end_ptr - ptr - 4;  
  118.   
  119.             if (len < 0 || len % 4)  
  120.                 return -11;  
  121.   
  122.             int n = len / 4;  
  123.   
  124.             for (int i = 0; i < n; i++, ptr += 4)  
  125.             {  
  126.                 u_int16_t channel = to_int(ptr);  
  127.                 u_int16_t pid = to_int(ptr + 2);  
  128.   
  129.                 if (pid & 0xe000 != 0xe000)  
  130.                     return -12;  
  131.   
  132.                 pid &= 0x1fff;  
  133.   
  134.                 if (!demuxer::channel || demuxer::channel == channel)  
  135.                 {  
  136.                     stream& ss = streams[pid];  
  137.                     ss.channel = channel;  
  138.                     ss.type = 0xff;  
  139.                 }  
  140.             }  
  141.         }  
  142.         else  
  143.         {  
  144.             // PMT  
  145.             ptr += 7;  
  146.   
  147.             if (ptr >= end_ptr)  
  148.                 return -13;  
  149.   
  150.             u_int16_t info_len = to_int(ptr) & 0x0fff;  
  151.   
  152.             ptr += info_len + 2;  
  153.             end_ptr -= 4;  
  154.   
  155.             if (ptr >= end_ptr)  
  156.                 return -14;  
  157.   
  158.             while (ptr < end_ptr)  
  159.             {  
  160.                 if (end_ptr - ptr < 5)  
  161.                     return -15;  
  162.   
  163.                 u_int8_t type = to_byte(ptr);  
  164.                 u_int16_t pid = to_int(ptr + 1);  
  165.   
  166.                 if (pid & 0xe000 != 0xe000)  
  167.                     return -16;  
  168.   
  169.                 pid &= 0x1fff;  
  170.   
  171.                 info_len = to_int(ptr + 3) & 0x0fff;  
  172.   
  173.                 ptr += 5 + info_len;  
  174.   
  175.                 // ignore unknown streams  
  176.                 if (validate_type(type))  
  177.                 {  
  178.                     stream& ss = streams[pid];  
  179.   
  180.                     if (ss.channel != s.channel || ss.type != type)  
  181.                     {  
  182.                         ss.channel = s.channel;  
  183.                         ss.type = type;  
  184.                         ss.id = ++s.id;  
  185.   
  186.                         if (!parse_only && !ss.file.is_opened())  
  187.                         {  
  188.                             if (dst.length())  
  189.                                 ss.file.open(file::out, false, "%s%c%strack_%i.%s", dst.c_str(), os_slash, prefix.c_str(), pid, get_stream_ext(get_stream_type(ss.type)));  
  190.                             else  
  191.                                 ss.file.open(file::out, false, "%strack_%i.%s", prefix.c_str(), pid, get_stream_ext(get_stream_type(ss.type)));  
  192.                               
  193.                             if (es_parse)  
  194.                                 ss.file.open(file::out, true, "%ses_strack_%i.%s", prefix.c_str(), pid, "es");  
  195.                                   
  196.                         }  
  197.                     }  
  198.                 }  
  199.             }  
  200.   
  201.             if (ptr != end_ptr)  
  202.                 return -18;  
  203.         }  
  204.     }  
  205.     else  
  206.     {  
  207.         if (s.type != 0xff)  
  208.         {  
  209.             // PES  
  210.   
  211.             if (payload_unit_start_indicator)//等于true代表一个PES包的开始  
  212.             {  
  213.                 s.psi.reset();  
  214.                 s.psi.len = 9;  
  215.             }  
  216.   
  217.             while (s.psi.offset<s.psi.len)  
  218.             {  
  219.                 int len = end_ptr - ptr;  
  220.   
  221.                 if (len <= 0)  
  222.                     return 0;  
  223.   
  224.                 int n = s.psi.len - s.psi.offset;  
  225.   
  226.                 if (len>n)  
  227.                     len = n;  
  228.   
  229.                 memcpy(s.psi.buf + s.psi.offset, ptr, len);  
  230.                 s.psi.offset += len;  
  231.   
  232.                 ptr += len;  
  233.   
  234.                 if (s.psi.len == 9)  
  235.                     s.psi.len += to_byte(s.psi.buf + 8);  
  236.             }  
  237.   
  238.             if (s.psi.len)  
  239.             {  
  240.                 if (memcmp(s.psi.buf, "\x00\x00\x01", 3))  
  241.                     return -19;  
  242.   
  243.                 s.stream_id = to_byte(s.psi.buf + 3);  
  244.   
  245.                 u_int8_t flags = to_byte(s.psi.buf + 7);  
  246.   
  247.                 s.frame_num++;  
  248.   
  249.                 switch (flags & 0xc0)  
  250.                 {  
  251.                 case 0x80:          // PTS only 音频包PTS和DTS相同,所以只有PTS  
  252.                 {  
  253.                                         u_int64_t pts = decode_pts(s.psi.buf + 9);  
  254.   
  255.                                         if (dump == 2)  
  256.                                             printf("%.4x: %llu\n", pid, pts);  
  257.                                         else if (dump == 3)  
  258.                                             printf("%.4x: track=%.4x.%.2i, type=%.2x, stream=%.2x, pts=%llums\n", pid, s.channel, s.id, s.type, s.stream_id, pts / 90);  
  259.   
  260.                                         if (s.dts > 0 && pts > s.dts)  
  261.                                             s.frame_length = pts - s.dts;  
  262.                                         s.dts = pts;  
  263.   
  264.                                         if (pts > s.last_pts)  
  265.                                             s.last_pts = pts;  
  266.   
  267.                                         if (!s.first_pts)  
  268.                                             s.first_pts = pts;  
  269.                 }  
  270.                     break;  
  271.                 case 0xc0:          // PTS,DTS 视频包含有PTS和DTS  
  272.                 {  
  273.                                         u_int64_t pts = decode_pts(s.psi.buf + 9);  
  274.                                         u_int64_t dts = decode_pts(s.psi.buf + 14);  
  275.   
  276.                                         if (dump == 2)  
  277.                                             printf("%.4x: %llu %llu\n", pid, pts, dts);  
  278.                                         else if (dump == 3)  
  279.                                             printf("%.4x: track=%.4x.%.2i, type=%.2x, stream=%.2x, pts=%llums, dts=%llums\n", pid, s.channel, s.id, s.type, s.stream_id, pts / 90, dts / 90);  
  280.   
  281.                                         if (s.dts > 0 && dts > s.dts)  
  282.                                             s.frame_length = dts - s.dts;  
  283.                                         s.dts = dts;  
  284.   
  285.                                         if (pts > s.last_pts)  
  286.                                             s.last_pts = pts;  
  287.   
  288.                                         if (!s.first_dts)  
  289.                                             s.first_dts = dts;  
  290.                 }  
  291.                     break;  
  292.                 }  
  293.   
  294.                 if (pes_output && s.file.is_opened())  
  295.                 {  
  296.                     s.file.write(s.psi.buf, s.psi.len, false);//将PES包头信息存入文件  
  297.                 }  
  298.                 s.psi.reset();  
  299.             }  
  300.   
  301.             if (s.frame_num)  
  302.             {  
  303.                 int len = end_ptr - ptr;  
  304.   
  305.                 if (s.file.is_opened())  
  306.                 {  
  307.                     s.file.write(ptr, len, true);//此处获取的是ES包  
  308.                 }  
  309.             }  
  310.         }  
  311.     }  
  312.   
  313.     return 0;  
  314. }</span>  

 

[html]  view plain  copy
 
 print?
  1.   

 

该代码是根据TSDemux工程修改,源项目只能解复用得到PES,在此基础上修改能同时获取音视频的PES,ES共4个文件。需要详细学习TS的同学可以研究下。

源代码已经上传到CSDN:

http://download.csdn.net/detail/rootusers/8426227

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值