音视频入门基础:MPEG2-TS专题(15)——FFmpeg源码中,解析PAT表的实现
一、引言
FFmpeg源码中,通过pat_cb函数解析PAT表。
二、pat_cb函数定义
pat_cb函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的源文件libavformat/mpegts.c中:
static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
{
MpegTSContext *ts = filter->u.section_filter.opaque;
MpegTSSectionFilter *tssf = &filter->u.section_filter;
SectionHeader h1, *h = &h1;
const uint8_t *p, *p_end;
int sid, pmt_pid;
int nb_prg = 0;
AVProgram *program;
av_log(ts->stream, AV_LOG_TRACE, "PAT:\n");
hex_dump_debug(ts->stream, section, section_len);
p_end = section + section_len - 4;
p = section;
if (parse_section_header(h, &p, p_end) < 0)
return;
if (h->tid != PAT_TID)
return;
if (!h->current_next)
return;
if (ts->skip_changes)
return;
if (skip_identical(h, tssf))
return;
ts->id = h->id;
for (;;) {
sid = get16(&p, p_end);
if (sid < 0)
break;
pmt_pid = get16(&p, p_end);
if (pmt_pid < 0)
break;
pmt_pid &= 0x1fff;
if (pmt_pid == ts->current_pid)
break;
av_log(ts->stream, AV_LOG_TRACE, "sid=0x%x pid=0x%x\n", sid, pmt_pid);
if (sid == 0x0000) {
/* NIT info */
} else {
MpegTSFilter *fil = ts->pids[pmt_pid];
struct Program *prg;
program = av_new_program(ts->stream, sid);
if (program) {
program->program_num = sid;
program->pmt_pid = pmt_pid;
}
if (fil)
if ( fil->type != MPEGTS_SECTION
|| fil->pid != pmt_pid
|| fil->u.section_filter.section_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);
prg = add_program(ts, sid);
if (prg) {
unsigned prg_idx = prg - ts->prg;
if (prg->nb_pids && prg->pids[0] != pmt_pid)
clear_program(prg);
add_pid_to_program(prg, pmt_pid);
if (prg_idx > nb_prg)
FFSWAP(struct Program, ts->prg[nb_prg], ts->prg[prg_idx]);
if (prg_idx >= nb_prg)
nb_prg++;
} else
nb_prg = 0;
}
}
ts->nb_prg = nb_prg;
if (sid < 0) {
int i,j;
for (j=0; j<ts->stream->nb_programs; j++) {
for (i = 0; i < ts->nb_prg; i++)
if (ts->prg[i].id == ts->stream->programs[j]->id)
break;
if (i==ts->nb_prg && !ts->skip_clear)
clear_avprogram(ts, ts->stream->programs[j]->id);
}
}
}
该函数的作用是:解析TS流中的PAT表,提取出里面的属性。
形参filter:输出型参数,指向一个MpegTSFilter类型变量。
形参section:输入型参数。指向一个Program association section(PAT section)的数据,即一个PAT表去掉了TS Header和pointer_field后的有效数据。
section_len:输入型参数。一个Program association section的长度,单位为字节。
返回值:无
三、pat_cb函数的内部实现分析
pat_cb函数中首先通过下面语句让指针p_end指向PAT表中有效数据的末尾,即CRC_32属性的开头;让指针p指向PAT表的开头,即PAT section中去掉了TS Header和pointer_field后的有效数据:
const uint8_t *p, *p_end;
//...
p_end = section + section_len - 4;
p = section;
通过parse_section_header函数解析Section Header,这样指针h就会得到从Section Header中解析出来的属性。关于parse_section_header函数的用法可以参考:《音视频入门基础:MPEG2-TS专题(13)——FFmpeg源码中,解析Section Header的实现》:
if (parse_section_header(h, &p, p_end) < 0)
return;
宏PAT_TID定义如下:
#define PAT_TID 0x00 /* Program Association section */
判断SectionHeader中的table_id属性是否为PAT_TID(0x00),PAT表的table_id固定为0x00,如果不是,表示这不是PAT表,pat_cb函数直接返回:
if (h->tid != PAT_TID)
return;
判断SectionHeader中的current_next_indicator属性的值,如果值为1,表示该PAT当前有效,接续往下执行;值为0表示下一个PAT有效,pat_cb函数直接返回:
if (!h->current_next)
return;
读取SectionHeader中的program_number属性:
for (;;) {
sid = get16(&p, p_end);
if (sid < 0)
break;
//...
}
读取SectionHeader中的network_PID或program_map_PID属性:
pmt_pid = get16(&p, p_end);
if (pmt_pid < 0)
break;
pmt_pid &= 0x1fff;
如果读取到的network_PID或program_map_PID的值等于当前Section的PID,由于network_PID是NIT的PID,program_map_PID是PMT的PID,当前Section的PID是PAT表的PID,所以这时表示出错了,通过break语句跳出循环:
if (pmt_pid == ts->current_pid)
break;
如果program_number的值为0x0000,变量pmt_pid的值为network_PID(NIT的PID);否则变量pmt_pid的值为program_map_PID(PMT的PID):
if (sid == 0x0000) {
/* NIT info */
} else {
//...
}
数组ts->stream->programs中的每个元素都对应一个PMT表的信息。通过下面代码让ts->stream->programs[i]->program_num赋值为program_number属性的值,让ts->stream->programs[i]->pmt_pid赋值为program_map_PID属性的值,i为该节目是TS流中的第几个节目。使得后续可以通过遍历ts->stream->programs找到对应的PMT表的信息:
MpegTSFilter *fil = ts->pids[pmt_pid];
struct Program *prg;
program = av_new_program(ts->stream, sid);
if (program) {
program->program_num = sid;
program->pmt_pid = pmt_pid;
}
原文地址:https://blog.csdn.net/u014552102/article/details/144148558
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!