Golang通过pcap文件解析TS流,还原TS视频

首发 Golang社区
QRI的头像

QRI

这人还不错哦!

最近在做抓包录像方面的案例,通过tcpdump抓包后再分析包文件,解析出包中的视频等文件信息。先做最简单的部分,针对组播流的抓包录像分析。

TS识别

TS包由4B的包头(header)、可变长度的调整头和净荷(payload)组成;
包头结构定义如下:

struct ts_header{
        char     syn_byte:8;                        // 包头同步字节,0x47
        char     transport_error_indicator:1;       //传送数据包差错指示器
        char    payload_unit_start_indicator:1;     //有效净荷单元开始指示器
        char    transport_priority:1;               //传送优先级
        int        PID:13;                          //包ID
        char    transport_scrambling_control:2;     //传送加扰控制
        char    adaptation_field_control:2;         //调整字段控制
        char    continuity_conunter:4;              //连续计数器 0-15
    }
  • syn_byte:值为0x47,是MPEG-2TS的传送包标识符;

  • transport_error_indicator:值为1时,表示相关的传送包中至少有一个不可纠正的错误位,只有错误位纠正后,该位才能置0;

  • payload_unit_start_indicator:表示TS包的有效净荷带有PES或PSI数据的情况;当TS包的有效净荷带有PES包数据时,payload_unit_start_indicator为1,表示TS包的有效净荷以PES包的第一个字节开始;为0,表示TS包的开始不是PES包;当TS包带有PSI数据时,payload_unit_start_indicator为1,表示TS包带有PSI部分的第一个字节,即第一个字节带有指针pointer_field,为0表示TS包不带有一个PSI部分的第一个字节,即在有效净荷中没有指针pointer_field;对于空包的包,play_unit_start_indicator应该置为0;(这一点尤为重要,在组建自己的section时经常会用到这个)

  • transport_priority:置1表示相关的包比其他具有相同PID但transport_priority为0的包有更高的优先级;

  • PID:表示存储于传送包的有效净荷中数据的类型。

  • transport_scrambling_control:指示TS包有效净荷的加扰方式,如果首部包括调整字段,则不应该被加扰,对于空包,值要置“00”;

  • adaptation_field_control:传送流包首部是否跟随有调整字段和/或有效净荷。

  • continuity_conunter:随着具有相同PID TS包的增加而增加,当达到最大时,又恢复为0,如果调整字段控制值adaptation_field_control为“00”或“10”,则该连续计数器不增加;在TS中,当复用的包可能被作为两个连续的具有相同PID的TS包传送出去时,则复用的传送包与原传送包具有相同的continuity_counter,而adaptation_field_control字段值应为“01”或者”10”。在复用的包中,除了节目参考时钟PCR有效字段的值被重新编码外,原包中每个字节将被复制。

利用syn_byte位来识别TS流,连个47之间的间隔是188,并且连续超过3个(降低干扰造成的误判),那么这条流就是TS,可以字节将原始二进制文件写入到一个空白的ts文件中。

识别代码

// 判断 连续 三个71 中间间隔是否 187
func isTs(p *[]byte) bool{
    var (
        num int // 包含连续 71的个数
    )
    for index,value :=range *p{
        if value!=71 {
            continue
        }
        lastindex:=index
        for {
            ni:=lastindex+188
            if (len(*p)-1)<ni {
                return false
            }
            if (*p)[ni]!=71 {
                break
            }
            num++
            if num>=3 {
                return true
            }
            lastindex=ni
        }
    }
    return false
}

上面代码中用71的原因,47转成十进制就是71,识别到是ts流后,就可以将当前包的Payload保存在文件中,最终生成一个TS文件,这样就完成了对TS流的抓包文件进行视频还原。

发布于 2019-08-08 18:53:44
0
文章被以下专栏收录
Golang社区

golang干货分享

目录