mpeg2-ts格式解析

时间:2021-11-03 15:54:57
首先,ts主要是用于dvb的传输,ts可以理解成一种传输上的协议,要不怎么叫transport-stream,但是也可以理解成一种封装格式。
不管是ts文件,还是ts实时流,都可以这样来看,它由N个独立的packet构成,每个大小188Bytes。
每个packet都由两部分构成,header和data,header描述了一些关于这个packet的信息,而data就是这个packet所携带的音频数据,视频数据,字幕数据,当然也可能是节目信息数据。

typedef struct _tag_PACKET_HEADER {
    //同步字节,总是0x47(0100 0111),表示这个包是正确的ts包
    unsigned sync_byte: 8; 
    //传输错误指示符,1:暂且定义为本包有个无法修复的错误
    unsigned transport_error_indicator: 1; 
    //负载单位开始指示符,1:PES或者PSI的开始部分,0:其他
    unsigned payload_unit_start_indicator: 1; 
    //传输优先指示符,1:比相同PID的包有更高的优先级
    unsigned transport_priority: 1; 
    //Packet ID
    unsigned PID: 13;
    //加扰控制指示符
    //00:未加扰(俗称清流);01:留着等以后使用
    //10:以even key方式加扰;11:以odd key方式加扰
    unsigned scrambling_control: 2;
    //适配区存在指示符
    //00:留着等以后使用;
    //01:本报不含适配区,只有负载区
    //10:本包只含适配区,没有负载区
    //11:本包不仅含有适配区,还含有负载区
    //其实可以把这两bit分开来理解,第一个bit指示是否有适配区,第二个指示是否有负载区
    unsigned adaptation_field_exist: 2;
    //当本包目前有负载区时,它才回递增
    //例如,当上面的字段为01or11时,本字段才回递增
    unsigned continuity_counter: 4;
} PACKET_HEADER;
以上就是header的结构,可见sizeof(PACKET_HEADER) == 4 Bytes

根据header的情况,我可以推测出剩余的PACKET_DATA最长只有184Bytes了
typedef _tag_PACKET_DATA {
    //0或者更长,依据PACKET_HEADER.adaptation_field_exist的第一bit而定
    struct adaptation_field;
    //0或者更长,依据PACKET_HEADER.adaptation_field_exist的第二bit而定
    struct payload_data
}

下面请看adaptation_field的结构定义:
typedef struct adaptation_field {
    //本区域除了本字节剩下的长度(不包含本字节!!!切记)
    adaptation_field_length: 8;
    //不连续指示符
    //1:本ts包在continuity_counter或者PCR,是处于不连续状态的
    discontinuity_indicator: 1;
    //可随机访问指示符
    //1:本包中的PES包可以启动一个视频/音频序列
    //就是说如果是1,可以从这个包开始牵出该条ES流
    random_access_indicator: 1;
    //es流优先级指示符
    //1:当同pid时,该es流有更高级的优先权
    elementary_stream_priority_indicator: 1;
    //Program Clock Reference,含有“节目时钟参考”标志
    //1:适配区里面含有PCR field字段,0:不含有
    PCR_flag: 1;
    //1:适配区里面含有splice_countdown字段
    splicing_point_flag: 1;
    //1:适配区里面含有private_data_bytes字段
    trasport_private_data_flag: 1;
    //1:适配去里面含有adaptation_field_extension字段
    adaptation_field_extension_flag: 1;

    //下面几个字段依据上面几个指示器的值而存在与否

    //Program Clock Reference,共6个字节,48bits,大端模式存储!
    //33bits是基本的,6个填充bits,9个扩展bits
    //时间参考,至少约100ms会确定一次audio和video之间的同步问题
    PCR: 33+6+9;
    //Original Program Clock Reference
    //原始PCR,当一个ts包被复制到另一个包里面去了,这里保留其原始的PCR值
    OPCR: 33+6+9
    //分隔倒数器,我自己翻译的,求指点
    //表示当一个分割点出现时,从这个ts包起,还剩多少个ts包(有可能是负数)
    splice_countdown: 8;
    //填充字节,全0xFF,目的是为了使得每一个packet的长度为188Bytes
    //这个的结果可以使得码流为恒定值
    //当然,如果一次想携带的内容超过184字节了怎么办?那就得分隔成多个ts packet了
    stuffing_bytes: 不定长;
}

看完adaptation_field了,那struct payload_data呢?即使有,其实也没什么值得看的,payload_data结构就是所携带的纯粹的数据了,那个没什么好说的,但是还是遵守不足184Bytes就填充FF,超过184Bytes就分隔的原则啦。
所以ts包可以这样表示
【header】+【data】 == 【188Bytes】
【header】== 4 Bytes
【data】 == 184 Bytes == 【adaptation_field】+【payload_data+填充】
【adaptation_field】 == adaptation_field->adaptation_field_length
【payload_data+填充】 == 184 - field.adaptation_field_length

如果有兴趣,直接耐住性子看【http://mumudvb.braice.net/mumudrupal/sites/default/files/iso13818-1.pdf 】,会更加详细,透彻地了解mpeg2-ts