ffmpeg——ts相关信息

1.ES PES TS
这里写图片描述
TS流与PS流的区别在于TS流的包结构是固定长度的,而PS流的包结构是可变长度。 PS包与TS包在结构上的这种差异,导致了它们对传输误码具有不同的抵抗能力。在信道环境较为恶劣,传输误码较高时,一般采用TS码流;而在信道环境较好,传输误码较低时,一般采用PS码流。由于TS码流具有较强的抵抗传输误码的能力,因此目前在传输媒体中进行传输的MPEG-2码流 基本上都采用了TS码流的包格。

每个ES都由若干个存取单元(AU)组成,每个视频AU或音频AU都是由头部和编码数据两部分组成,1个AU相当于编码的1幅视频图像或1个音频帧,也可以说,每个AU实际上是编码数据流的显示单元,即相当于解码的1幅视频图像或1个音频帧的取样。

PES是打包过的ES,已经插入PTS和DTS,一般一个PES是一帧图像。
PES经过打包成TS或PS流,往往一个PES会分存到多个TS包中。
这里写图片描述

2.PSI PAT PMT
节目专用信息PSI(Program Specific Information)

管理各种类型的TS数据包,需要有些特殊的TS包来确立各个TS数据包之间的关系。这些特殊的TS包里所包含的信息就是节目专用信息。

MPEG-2中,规定的对PSI信息的描述方法有以下几种:
• 1、表Table: 节目信息的结构性的描述;
–节目关联表Program Association Table (PAT) 0x0000

–节目映射表Program Map Tables (PMT) PAT指定

–条件接收表Conditional Access Table (CAT) 0x0001

–网络信息表Network Information Table(NIT) 0x0010

–传送流描述表Transport Stream Description Table (TSDT)
• 2、段Section: 将表格的内容映射到TS流中;
专用段 Private_ section

• 3、描述符Descriptor:提供有关节目构成(视频流、音频流、语言、层次、系统时钟和码率等多方面)的信息;
ITU-T Rec.H.222.0|ISO /IEC 13818-1 中定义的 PSI表可被分成一段或多段置于传输流分组中。一段就是一个语法结构,用来将 ITU-T Rec.H.222.0|ISO /IEC 13818-1 中定义的 PSI表映射到传输流分组中。

1个PAT表中包含N个PMT表的索引信息
而1个PMT表中又包含视频PES 音频PES等索引信息
这里写图片描述
在解析TS流的时候,首先寻找PAT表,根据PAT获取所有PMT表的PID;再寻找PMT表,获取该频段所有节目数据并保存。这样,只需要知道节目的PID就可以根据PacketHeade给出的PID过滤出不同的Packet,从而观看不同的节目。

Section:
一个section可能包含一个或多个TS包。对接收到的TS包数据,根据不同的PID过滤出相应的TS包,然后去掉包头,把相关的多个TS包有效数据组织起来形成section数据返回给相应的应用开发者调用。

当PSI的长度大于184bytes时,要对这个表进行分割,形成section来传送。分段机制主要是将一个数据表分割成多个数据段,在PSI表到TS包的转换中,section起到了中介作用,section的长度可变。
这里写图片描述
PAT:0x0000 包含了多个program_number(16bits)和program_map_ID(13bits),用于定义多个频道
PMT:0x03e8 包含了一个program_number,用于链接到PAT,找到对应的频道;
多个stream_type(8bit)和elementary_PID(13bits),用于定义包含的是音频、视频、字幕流,及其PID
普通的TS数据包:根据其PID,找到对应的频道

http://blog.csdn.net/qingfengtsing/article/details/55668911
https://wenku.baidu.com/view/b9df867602768e9951e738d2.html
http://blog.csdn.net/zxh821112/article/details/17587215

3.mpegts.c
一,结构体

struct MpegTSFilter {//ts过滤器,根据ts包的PID进行过滤
    int pid;
    int es_id;
    int last_cc; /* last cc code (-1 if first packet) */
    int64_t last_pcr;
    enum MpegTSFilterType type;//过滤器类型,包括pes、section、pcr
    union {
        MpegTSPESFilter pes_filter;//pes过滤器
        MpegTSSectionFilter section_filter;//section过滤器
    } u;
};

typedef struct MpegTSSectionFilter
struct Program
struct MpegTSContext
typedef struct PESContext
typedef struct AVProgram

二,回调函数
pmt_cb //接收pmt表
pat_cb //接收pat表
sdt_cb //接收sdt表

pes_cb //获得pes
section_cb //获得section
http://blog.csdn.net/u010380485/article/details/54234185

4.pat_cb pmt_cb

typedef struct SectionHeader {
    uint8_t tid;// table_id
    uint16_t id;   // transport_stream_id
    uint8_t version;
    uint8_t sec_num; // section_number
    uint8_t last_sec_num;
} SectionHeader;

typedef struct AVProgram {
    int            id;
    int            flags;
    enum AVDiscard discard;        ///< selects which program to discard and which to feed to the caller
    unsigned int   *stream_index;
    unsigned int   nb_stream_indexes;
    AVDictionary *metadata;
    int program_num;
    int pmt_pid;
    int pcr_pid;
    /*****************************************************************
     * All fields below this line are not part of the public API. They
     * may not be used outside of libavformat and can be changed and
     * removed at will.
     * New public fields should be added right above.
     *****************************************************************
     */
    int64_t start_time;
    int64_t end_time;
    int64_t pts_wrap_reference;    ///< reference dts for wrap detection
    int pts_wrap_behavior;         ///< behavior on wrap detection
} AVProgram;




    1. typedef struct TS_PAT_Program  
    2. {  
    3.     unsigned program_number   :  16;  //节目号  
    4.     unsigned program_map_PID :  13; // 节目映射表的PID,节目号大于0时对应的PID,每个节目对应一个  
    5. }TS_PAT_Program  



static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
{
   for (;;)
   {
        sid = get16(&p, p_end); // program number
        pmt_pid = get16(&p, p_end);  // program map pid
           pmt_pid &= 0x1fff;
          if (pmt_pid == ts->current_pid)
            break;

          //建立program number 与 program map pid之间的对应关系,program number 为0,表示pmt_pid是network_PID;
          program = av_new_program(ts->stream, sid);// 创建Program
            if (program) {
                program->program_num = sid;
                program->pmt_pid = pmt_pid;
            }

           f (fil)
                if (   fil->type != MPEGTS_SECTION
                    || fil->pid != pmt_pid
                    || fil->u.section_filter.section_cb != pmt_cb)   //回到函数pmt_cb
                    mpegts_close_filter(ts, ts->pids[pmt_pid]);


           if (!ts->pids[pmt_pid])
                mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1);//为指定pid的ts packet创建filter,此处是创建PMT的filter(可能存在PID不同的多个PMT)

           add_pat_entry(ts, sid); // sid is program number
           //分别将PAT和PMT的PID加入到Program的pid list中,即pids数组中
           add_pid_to_pmt(ts, sid, 0); // add pat pid to program
           add_pid_to_pmt(ts, sid, pmt_pid); // sid <--> pmt_pid
   }
}



static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
{//传入每个节目的PMT数据,解析出这个节目的组成,包含的音视频ES, PMT的PID是在pat_cb中解析出来的

    pes->st     = avformat_new_stream(pes->stream, NULL);//创建AVStream
}

http://blog.csdn.net/xiruanliuwei/article/details/28345499

5.handle_packet

static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
{//解析TS包
  if (ts->auto_guess && !tss && is_start) {//如果ts->auto_guess为1,则所有的pid都会去分析,寻找pes;
        add_pes_stream(ts, pid, -1);
        tss = ts->pids[pid];
    }
  //is_start 则是来自payload_unit_start_indicator,这一位的定义非常重要

  //在开始时,ts->pids中,只有PAT 和 SDT的 pid Filter不是null,因此其它的数据全部抛弃,只处理PAT 和 SDT packet中的数据
  if (tss->type == MPEGTS_SECTION)
  {
  }

}


write_section_data()//将数据写入到对应的pid Filter中的uint8_t *section_buf;中

猜你喜欢

转载自blog.csdn.net/u012868357/article/details/80221314