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;中