分析ffmpeg解析ts流信息的源码
花费一些时间,然后全部扔了。为了不忘记和抛砖引玉,特发此贴。
ffmpeg解析ts流
1.目的
打算软件方式解析出pat,pmt等码流信息
2.源代码所在位置
下载ffmpeg开源代码,官网http://ffmpeg.org/
具体代码位置libavformat/mpegts.c
3.代码分析
(a)整体分析
mpegts_read_header函数获取ts中节目信息,内部关键代码摘录如下:
seek_back(s, pb, pos);//指向码流开始位置
mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1);//获取pat,pmt信息,我只需要这个
//probesize / ts->raw_packet_size 检查的数据包个数
handle_packets(ts, probesize / ts->raw_packet_size);//处理码流数据包,在这里循环,得到所需信息
(b)分配并配置filter参数
static MpegTSFilter *mpegts_open_filter(MpegTSContext *ts, unsigned int pid,
enum MpegTSFilterType type)
{
MpegTSFilter *filter;
av_dlog(ts->stream, "Filter: pid=0x%x\n", pid);
if (pid >= NB_PID_MAX || ts->pids[pid])
return NULL;
filter = av_mallocz(sizeof(MpegTSFilter));//分配filter
if (!filter)
return NULL;
ts->pids[pid] = filter;//总共有0-0x1fff(8191)pid(8192个,0x1fff无效)
//注意这句话
filter->type = type;
filter->pid = pid;
filter->es_id = -1;
filter->last_cc = -1;
filter->last_pcr= -1;
return filter;
}
static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts,
unsigned int pid,
SectionCallback *section_cb,
void *opaque,
int check_crc)
{
MpegTSFilter *filter;
MpegTSSectionFilter *sec;
if (!(filter = mpegts_open_filter(ts, pid, MPEGTS_SECTION)))//filter分配并初始化成员
return NULL;
sec = &filter->u.section_filter;//ts->filter->section,注意这句话
sec->section_cb = section_cb;
sec->opaque = opaque;
sec->section_buf = av_malloc(MAX_SECTION_SIZE);//section最大4096
sec->check_crc = check_crc;
if (!sec->section_buf) {
av_free(filter);
return NULL;
}
return filter;
}
数据结构,注释
typedef struct MpegTSSectionFilter {
int section_index;//section填充数据时,当前位置指针
int section_h_size;//整个section的长度,根据section计算出来,max4096
uint8_t *section_buf;//
unsigned int check_crc : 1;//
unsigned int end_of_section_reached : 1;
SectionCallback *section_cb;//
void *opaque;
} MpegTSSectionFilter;
struct MpegTSFilter {
int pid;//
int es_id;
int last_cc; /* last cc code (-1 if first packet) *///对应ISO13818-1
int64_t last_pcr;//对应ISO13818-1
enum MpegTSFilterType type;//我只使用scetion类型
union {
MpegTSPESFilter pes_filter;
MpegTSSectionFilter section_filter;//
} u;
};
(c)handle_packets分析
只列出关键代码
handle_packets(MpegTSContext *ts, int64_t nb_packets)//ts对象,nb_packets总共的数据包
{
ts->stop_parse = 0;
packet_num = 0;
for (;;) {
packet_num++;
if (nb_packets != 0 && packet_num >= nb_packets ||/*处理完码流也没有找到信息,返回错误*/
ts->stop_parse > 1) {
ret = AVERROR(EAGAIN);
break;
}
if (ts->stop_parse > 0)//cb设置,退出
break;
ret = read_packet(s, packet, ts->raw_packet_size, &data);//读取单个数据包,读出数据存放在data中
if (ret != 0)
break;
ret = handle_packet(ts, data);//处理单个数据包
if (ret != 0)
break;
}
return ret;
}
//
static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
{
MpegTSFilter *tss;
int len, pid, cc, expected_cc, cc_ok, afc, is_start, is_discontinuity,
has_adaptation, has_payload;
const uint8_t *p, *p_end;
int64_t pos;
pid = AV_RB16(packet + 1) & 0x1fff;//获得pid
if (pid && discard_pid(ts, pid))
return 0;
is_start = packet[1] & 0x40;//对应payload_unit_start_indicator
tss = ts->pids[pid];
if (ts->auto_guess && !tss && is_start) {
add_pes_stream(ts, pid, -1);
tss = ts->pids[pid];
}
if (!tss)
return 0;
ts->current_pid = pid;
afc = (packet[3] >> 4) & 3;//对应adaptation_field_control
if (afc == 0) /* reserved value */
return 0;
has_adaptation = afc & 2;
has_payload = afc & 1;
is_discontinuity = has_adaptation &&
packet[4] != 0 && /* with length > 0 */
(packet[5] & 0x80); /* and discontinuity indicated */
/* continuity check (currently not used) */
cc = (packet[3] & 0xf);
expected_cc = has_payload ? (tss->last_cc + 1) & 0x0f : tss->last_cc;
cc_ok = pid == 0x1FFF || // null packet PID
is_discontinuity ||
tss->last_cc < 0 ||
expected_cc == cc;
tss->last_cc = cc;
if (!cc_ok) {
av_log(ts->stream, AV_LOG_DEBUG,
"Continuity check failed for pid %d expected %d got %d\n",
pid, expected_cc, cc);
if (tss->type == MPEGTS_PES) {
PESContext *pc = tss->u.pes_filter.opaque;
pc->flags |= AV_PKT_FLAG_CORRUPT;
}
}
p = packet + 4;//指向数据位置
if (has_adaptation) {
int64_t pcr_h;
int pcr_l;
if (parse_pcr(&pcr_h, &pcr_l, packet) == 0)
tss->last_pcr = pcr_h * 300 + pcr_l;
/* skip adaptation field */
p += p[0] + 1;//跳过adapt区域
}
/* if past the end of packet, ignore */
p_end = packet + TS_PACKET_SIZE;
if (p >= p_end || !has_payload)
return 0;
pos = avio_tell(ts->stream->pb);
if (pos >= 0) {
av_assert0(pos >= TS_PACKET_SIZE);
ts->pos47_full = pos - TS_PACKET_SIZE;
}
if (tss->type == MPEGTS_SECTION) {//只关心section类型
if (is_start) {
/* pointer field present */
len = *p++;
if (p + len > p_end)
return 0;
if (len && cc_ok) {//指针域指定位置前面的数据,应该是上个section残留的数据,这些数据不常用
//注意计数器正确,并且指针指向的位置前面有数据才处理
/* write remaining section bytes */
write_section_data(ts, tss,
p, len, 0);
/* check whether filter has been closed */
if (!ts->pids[pid])
return 0;
}
p += len;
if (p < p_end) {//注意,开始时,计数器不要求正确
write_section_data(ts, tss,
p, p_end - p, 1);//写入section
}
} else {
if (cc_ok) {
write_section_data(ts, tss,
p, p_end - p, 0);
}
}
// stop find_stream_info from waiting for more streams
// when all programs have received a PMT
if (ts->stream->ctx_flags & AVFMTCTX_NOHEADER && ts->scan_all_pmts <= 0) {
int i;
for (i = 0; i < ts->nb_prg; i++) {
if (!ts->prg[i].pmt_found)
break;
}
if (i == ts->nb_prg && ts->nb_prg > 0) {
int types = 0;
for (i = 0; i < ts->stream->nb_streams; i++) {
AVStream *st = ts->stream->streams[i];
types |= 1<<st->codec->codec_type;
}
if ((types & (1<<AVMEDIA_TYPE_AUDIO) && types & (1<<AVMEDIA_TYPE_VIDEO)) || pos > 100000) {
av_log(ts->stream, AV_LOG_DEBUG, "All programs have pmt, headers found\n");
ts->stream->ctx_flags &= ~AVFMTCTX_NOHEADER;
}
}
}
} else {
int ret;
// Note: The position here points actually behind the current packet.
if (tss->type == MPEGTS_PES) {
if ((ret = tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start,
pos - ts->raw_packet_size)) < 0)
return ret;
}
}
return 0;
}
/**
* Assemble PES packets out of TS packets, and then call the "section_cb"
* function when they are complete.
*/
static void write_section_data(MpegTSContext *ts, MpegTSFilter *tss1,
const uint8_t *buf, int buf_size, int is_start)
{
MpegTSSectionFilter *tss = &tss1->u.section_filter;
int len;
//填充数据
if (is_start) {
memcpy(tss->section_buf, buf, buf_size);
tss->section_index = buf_size;
tss->section_h_size = -1;
tss->end_of_section_reached = 0;
} else {
if (tss->end_of_section_reached)
return;
len = 4096 - tss->section_index;
if (buf_size < len)
len = buf_size;
memcpy(tss->section_buf + tss->section_index, buf, len);
tss->section_index += len;
}
/* compute section length if possible */
if (tss->section_h_size == -1 && tss->section_index >= 3) {//计算section长度
len = (AV_RB16(tss->section_buf + 1) & 0xfff) + 3;
if (len > 4096)
return;
tss->section_h_size = len;
}
if (tss->section_h_size != -1 &&
tss->section_index >= tss->section_h_size) {
int crc_valid = 1;
tss->end_of_section_reached = 1;//接收满
if (tss->check_crc) {
crc_valid = !av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1, tss->section_buf, tss->section_h_size);
if (crc_valid) {
ts->crc_validity[ tss1->pid ] = 100;
}else if (ts->crc_validity[ tss1->pid ] > -10) {
ts->crc_validity[ tss1->pid ]--;
}else
crc_valid = 2;
}
if (crc_valid)
tss->section_cb(tss1, tss->section_buf, tss->section_h_size);//执行回调函数
}
}
(d)callback分析
static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
{
MpegTSContext *ts = filter->u.section_filter.opaque;
SectionHeader h1, *h = &h1;
const uint8_t *p, *p_end;
int sid, pmt_pid;
AVProgram *program;
av_dlog(ts->stream, "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 (ts->skip_changes)
return;
ts->stream->ts_id = h->id;
clear_programs(ts);
for (;;) {
sid = get16(&p, p_end);//对应program_number
if (sid < 0)
break;
pmt_pid = get16(&p, p_end);
if (pmt_pid < 0)
break;
pmt_pid &= 0x1fff;//对应program_map_PID
if (pmt_pid == ts->current_pid)
break;
av_dlog(ts->stream, "sid=0x%x pid=0x%x\n", sid, pmt_pid);
if (sid == 0x0000) {
/* NIT info */
} else {
MpegTSFilter *fil = ts->pids[pmt_pid];
program = av_new_program(ts->stream, sid);
if (program) {
program->program_num = sid;
program->pmt_pid = pmt_pid;//节目的pmt_pid
}
if (fil)//把先前的filter关闭
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);//设置pmt.cb
add_pat_entry(ts, sid);//增加节目项
add_pid_to_pmt(ts, sid, 0); // add pat pid to program
add_pid_to_pmt(ts, sid, pmt_pid);//pmt pid 增加到节目
}
}
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);
}
}
}
//参考ISO13818-1 PMT 表
static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
{
MpegTSContext *ts = filter->u.section_filter.opaque;
SectionHeader h1, *h = &h1;
PESContext *pes;
AVStream *st;
const uint8_t *p, *p_end, *desc_list_end;
int program_info_length, pcr_pid, pid, stream_type;
int desc_list_len;
uint32_t prog_reg_desc = 0; /* registration descriptor */
int mp4_descr_count = 0;
Mp4Descr mp4_descr[MAX_MP4_DESCR_COUNT] = { { 0 } };
int i;
av_dlog(ts->stream, "PMT: len %i\n", section_len);
hex_dump_debug(ts->stream, section, section_len);
p_end = section + section_len - 4;//不包括CRC
p = section;
if (parse_section_header(h, &p, p_end) < 0)
return;
av_dlog(ts->stream, "sid=0x%x sec_num=%d/%d version=%d\n",
h->id, h->sec_num, h->last_sec_num, h->version);
if (h->tid != PMT_TID)
return;
if (!ts->scan_all_pmts && ts->skip_changes)
return;
if (!ts->skip_clear)
clear_program(ts, h->id);
pcr_pid = get16(&p, p_end);//对应 PCR_PID
if (pcr_pid < 0)
return;
pcr_pid &= 0x1fff;
add_pid_to_pmt(ts, h->id, pcr_pid);//把pcr pid放入pid数组
set_pcr_pid(ts->stream, h->id, pcr_pid);
av_dlog(ts->stream, "pcr_pid=0x%x\n", pcr_pid);
program_info_length = get16(&p, p_end);
if (program_info_length < 0)
return;
program_info_length &= 0xfff;//一般program_info_length==0,不用解析
while (program_info_length >= 2) {
uint8_t tag, len;
tag = get8(&p, p_end);
len = get8(&p, p_end);
av_dlog(ts->stream, "program tag: 0x%02x len=%d\n", tag, len);
if (len > program_info_length - 2)
// something else is broken, exit the program_descriptors_loop
break;
program_info_length -= len + 2;
if (tag == 0x1d) { // IOD descriptor
get8(&p, p_end); // scope
get8(&p, p_end); // label
len -= 2;
mp4_read_iods(ts->stream, p, len, mp4_descr + mp4_descr_count,
&mp4_descr_count, MAX_MP4_DESCR_COUNT);
} else if (tag == 0x05 && len >= 4) { // registration descriptor
prog_reg_desc = bytestream_get_le32(&p);
len -= 4;
}
p += len;
}
p += program_info_length;//跳转到elements描述处理
if (p >= p_end)
goto out;
// stop parsing after pmt, we found header
if (!ts->stream->nb_streams)
ts->stop_parse = 2;
set_pmt_found(ts, h->id);//搜索到pmt
for (;;) {
st = 0;
pes = NULL;
stream_type = get8(&p, p_end);//获得 stream_type
if (stream_type < 0)
break;
pid = get16(&p, p_end);//获得 elementary_PID
if (pid < 0)
goto out;
pid &= 0x1fff;
if (pid == ts->current_pid)
goto out;
/* now create stream */
if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) {
pes = ts->pids[pid]->u.pes_filter.opaque;
if (!pes->st) {
pes->st = avformat_new_stream(pes->stream, NULL);
if (!pes->st)
goto out;
pes->st->id = pes->pid;
}
st = pes->st;
} else if (stream_type != 0x13) {
if (ts->pids[pid])
mpegts_close_filter(ts, ts->pids[pid]); // wrongly added sdt filter probably
pes = add_pes_stream(ts, pid, pcr_pid);
if (pes) {
st = avformat_new_stream(pes->stream, NULL);
if (!st)
goto out;
st->id = pes->pid;
}
} else {
int idx = ff_find_stream_index(ts->stream, pid);
if (idx >= 0) {
st = ts->stream->streams[idx];
} else {
st = avformat_new_stream(ts->stream, NULL);
if (!st)
goto out;
st->id = pid;
st->codec->codec_type = AVMEDIA_TYPE_DATA;
}
}
if (!st)
goto out;
if (pes && !pes->stream_type)
mpegts_set_stream_info(st, pes, stream_type, prog_reg_desc);//把节目信息存储起来
add_pid_to_pmt(ts, h->id, pid);
ff_program_add_stream_index(ts->stream, h->id, st->index);
desc_list_len = get16(&p, p_end);
if (desc_list_len < 0)
goto out;
desc_list_len &= 0xfff;
desc_list_end = p + desc_list_len;
if (desc_list_end > p_end)
goto out;
for (;;) {
if (ff_parse_mpeg2_descriptor(ts->stream, st, stream_type, &p,
desc_list_end, mp4_descr,
mp4_descr_count, pid, ts) < 0)
break;
if (pes && prog_reg_desc == AV_RL32("HDMV") &&
stream_type == 0x83 && pes->sub_st) {
ff_program_add_stream_index(ts->stream, h->id,
pes->sub_st->index);
pes->sub_st->codec->codec_tag = st->codec->codec_tag;
}
}
p = desc_list_end;
}
if (!ts->pids[pcr_pid])
mpegts_open_pcr_filter(ts, pcr_pid);
out:
for (i = 0; i < mp4_descr_count; i++)
av_free(mp4_descr[i].dec_config_descr);
}
4.根据上述代码实现psi信息解析
#define PAT_PID 0x0000
#define PAT_TID 0x00
#define PMT_TID 0x02
#define TS_PSI_SECTION_MAX_SIZE 4096
#define SOFT_FILTER_LEN_MAX 16
typedef HI_S32 (*SOFT_SECTION_CB) (const HI_U8 *section, HI_U16 len);
typedef struct SOFT_SECTION_OBJ_T{
HI_U16 pid;
HI_U8 filter[SOFT_FILTER_LEN_MAX];
HI_U16 filter_len;
SOFT_SECTION_CB cb;
HI_S32 last_cc;
HI_S32 section_index;
HI_S32 section_h_size;
HI_BOOL end_of_section_reached;
HI_U8 section_buf[TS_PSI_SECTION_MAX_SIZE];
}SOFT_SECTION_OBJ_T;
static SOFT_SECTION_OBJ_T s_soft_section_obj;
#define PROG_MAP_PID_MAX 16
typedef struct PROG_MAP_PID_T{
HI_U16 program_number;/*16bit*/
HI_U8 reserved;/*3bit*/
HI_U16 program_map_PID;/*13bit*/
}PROG_MAP_PID_T;
typedef struct PAT_TABLE_T{
HI_U8 table_id;/*8bit*/
HI_U8 section_syntax_indicator;/*1bit*/
HI_U8 zero_1;/*1bit*/
HI_U8 reserved1;/*2bit*/
HI_U16 section_length;/*12bit*/
HI_U16 transport_stream_id;/*16bit*/
HI_U8 reserved2;/*2bit*/
HI_U8 version_number;/*5bit*/
HI_U8 current_next_indicator;/*1bit*/
HI_U8 section_number;/*8bit*/
HI_U8 last_section_number;/*8bit*/
PROG_MAP_PID_T map[PROG_MAP_PID_MAX];
HI_U32 CRC_32;/*32bit*/
}PAT_TABLE_T;
#define PMT_ELEMENT_MAX 16
typedef struct PMT_ELEMENT_T{
ML_U8 stream_type;/*8bit*///********
// ML_U8 reserved0;/*3bit*/
ML_U16 elementary_PID;/*13bit*///********
// ML_U8 reserved1;/*4bit*/
ML_U16 ES_info_length;/*12bit*/
// PMT_ES_INFO_T es_info;
}PMT_ELEMENT_T;
typedef struct PMT_TABLE_T{
// ML_U8 table_id; /*8bit*/ //.0x02
// ML_U8 section_syntax_indicator;/*1bit*/ //.1
// ML_U8 reserved0;/*1bit*/
ML_U16 section_length;/*12bit*/ //<=1021
ML_U16 program_number;/*16bit*/
// ML_U8 reserved1;/*2bit*/
// ML_U8 version_number;/*5bit*/
ML_U8 current_nenx_indicator;/*1bit*/ //=====
// ML_U8 section_number;/*8bit*/
// ML_U8 last_section_number;/*8bit*/
// ML_U8 reserved2;/*3bit*/
ML_U16 PCR_PID;/*13bit*///*******
// ML_U8 reserved3;/*4bit*/
ML_U16 proram_info_length;/*12bit*/
// PMT_PROGRAM_INFO_T program_info;
PMT_ELEMENT_T element[PMT_ELEMENT_MAX];
ML_U32 CRC_32;/*32bit*/
}PMT_TABLE_T;
typedef struct BOOT_VIDEO_PSI_INFO_T{
HI_U16 pmt_pid;
}BOOT_VIDEO_PSI_INFO_T;
static BOOT_VIDEO_PSI_INFO_T s_boot_video_psi_info;
static HI_S32 _soft_cb_pat(const HI_U8 *section, HI_U16 len)
{
PAT_TABLE_T pat;
const ML_U8 *p_prg;
ML_U32 i,N;
memset(&pat,0,sizeof(PAT_TABLE_T));
pat.section_number=*(section + 6);
pat.current_next_indicator=(*(section+5))&1;
if(0!=pat.section_number
||0==pat.current_next_indicator)
{
return HI_FAILURE;
}
else
{
pat.last_section_number=*(section + 7);
pat.transport_stream_id= (((HI_U16)(*(section + 3))) << 8) + *(section + 4);
}
pat.section_length= (((HI_U16)((*(section + 1)) & 0x0F)) << 8) + *(section + 2);
p_prg = section + 8;
N = (pat.section_length - 9) >> 2;
if(N>PROG_MAP_PID_MAX)
{
N=PROG_MAP_PID_MAX;
}
for (i = 0; i < N; i++)
{
pat.map[i].program_number=(((HI_U16)(*p_prg)) << 8) + *(p_prg + 1);
pat.map[i].program_map_PID=((((HI_U16)(*(p_prg + 2))) << 8) + *(p_prg + 3)) & 0x1FFF;
p_prg += 4;
if(0!=pat.map[i].program_number)
{
if(0!=pat.map[i].program_map_PID
&&NULL_PID!=pat.map[i].program_map_PID)
{
s_boot_video_psi_info.pmt_pid=pat.map[i].program_map_PID;
return HI_SUCCESS;
}
}
}
return HI_FAILURE;
}
static HI_S32 _soft_cb_pmt(const HI_U8 *section, HI_U16 len)
{
PMT_TABLE_T pmt;
const ML_U8 *p_es;
ML_U8 element_cnt;
ML_U8 i;
memset(&pmt,0,sizeof(PMT_TABLE_T));
if(len<10)
{
return HI_FAILURE;
}
pmt.current_nenx_indicator=(*(section+5))&1;
if(!pmt.current_nenx_indicator)
{
return HI_FAILURE;
}
pmt.section_length= (((HI_U16)((*(section + 1)) & 0x0F)) << 8) + *(section + 2);
pmt.program_number=(((HI_U16)((*(section + 3)))) << 8) + *(section + 4);
pmt.PCR_PID= (((HI_U16)((*(section + 8)) & 0x1F)) << 8) + *(section + 9);
pmt.proram_info_length= (((HI_U16)((*(section + 10)) & 0x0F)) << 8) + *(section + 11);
p_es=section + 12 + pmt.proram_info_length;
element_cnt=0;
while(1)
{
pmt.element[element_cnt].stream_type=*p_es;
pmt.element[element_cnt].elementary_PID=(((HI_U16)((*(p_es + 1)) & 0x1f)) << 8) +*(p_es + 2);
pmt.element[element_cnt].ES_info_length=(((HI_U16)((*(p_es + 3))&0xF)) << 8) + *(p_es + 4);
++element_cnt;
p_es += pmt.element[element_cnt].ES_info_length + 5;
if((p_es-section)>(len-5))
{
break;
}
if(element_cnt>=PMT_ELEMENT_MAX)
{
break;
}
}
for(i=0;i<element_cnt;i++)
{
switch(pmt.element[i].stream_type)
{
case E_SI_STREAM_MPEG1_VID:
case E_SI_STREAM_MPEG2_VID:
s_boot_video_obj.vidPID=pmt.element[i].elementary_PID;
s_boot_video_obj.vidType=pmt.element[i].stream_type;
break;
case E_SI_STREAM_AVCH264_VID:
s_boot_video_obj.vidPID=pmt.element[i].elementary_PID;
s_boot_video_obj.vidType=pmt.element[i].stream_type;
break;
case E_SI_STREAM_MPEG1_AUD:
case E_SI_STREAM_MPEG2_AUD:
s_boot_video_obj.audPID=pmt.element[i].elementary_PID;
s_boot_video_obj.audType=pmt.element[i].stream_type;
break;
case E_SI_STREAM_AC3_AUD:
s_boot_video_obj.audPID=pmt.element[i].elementary_PID;
s_boot_video_obj.audType=pmt.element[i].stream_type;
break;
}
}
s_boot_video_obj.pcrPID=pmt.PCR_PID;
if((NULL_PID!=s_boot_video_obj.vidPID)
&&(0!=s_boot_video_obj.vidPID))
{
s_boot_video_obj.enable=HI_TRUE;
return HI_SUCCESS;
}
return HI_FAILURE;
}
static HI_S32 _soft_write_section(const HI_U8* buf,HI_U16 buf_size,HI_BOOL is_start)
{
HI_S32 len;
if (is_start)
{
memcpy(s_soft_section_obj.section_buf, buf, buf_size);
s_soft_section_obj.section_index = buf_size;
s_soft_section_obj.section_h_size = -1;
s_soft_section_obj.end_of_section_reached =HI_FALSE;
}
else
{
if(s_soft_section_obj.end_of_section_reached)
{
return HI_FAILURE;
}
len = TS_PSI_SECTION_MAX_SIZE - s_soft_section_obj.section_index;
if (buf_size < len)
{
len = buf_size;
}
memcpy(s_soft_section_obj.section_buf + s_soft_section_obj.section_index, buf, len);
s_soft_section_obj.section_index += len;
}
/* compute section length if possible */
if((-1==s_soft_section_obj.section_h_size)
&&(s_soft_section_obj.section_index>=3))
{
len=(((HI_S32)(s_soft_section_obj.section_buf[1]&0x0f))<<8|s_soft_section_obj.section_buf[2])+3;
if(len>TS_PSI_SECTION_MAX_SIZE)
{
return HI_FAILURE;
}
s_soft_section_obj.section_h_size=len;
}
if(-1!=s_soft_section_obj.section_h_size
&& s_soft_section_obj.section_index >= s_soft_section_obj.section_h_size)
{
s_soft_section_obj.end_of_section_reached =HI_TRUE;
return s_soft_section_obj.cb(s_soft_section_obj.section_buf,s_soft_section_obj.section_h_size);
}
return HI_FAILURE;
}
static HI_S32 _soft_handle_packet(HI_U8 *packet)
{
HI_U16 pid;
HI_BOOL is_start;
HI_U8 afc;
HI_BOOL has_adaptation;
HI_BOOL has_payload;
HI_BOOL is_discontinuity;
HI_S32 cc,expected_cc;
HI_BOOL cc_ok;
HI_U8 *p,*p_end;
HI_U16 len;
pid=((ML_U16)(0x1f&packet[1])<<8)|packet[2];
if(pid!=s_soft_section_obj.pid)
{
return HI_FAILURE;
}
is_start = packet[1] & 0x40;
afc = (packet[3] >> 4) & 3;
if (afc == 0) /* reserved value */
{
return HI_FAILURE;
}
has_adaptation = afc & 2;
has_payload = afc & 1;
is_discontinuity = has_adaptation &&
packet[4] != 0 && /* with length > 0 */
(packet[5] & 0x80); /* and discontinuity indicated */
/* continuity check (currently not used) */
cc = (packet[3] & 0xf);
expected_cc = has_payload ? (s_soft_section_obj.last_cc + 1) & 0x0f : s_soft_section_obj.last_cc;
cc_ok = is_discontinuity
||s_soft_section_obj.last_cc < 0
||expected_cc == cc;
s_soft_section_obj.last_cc = cc;
p = packet + 4;
if (has_adaptation)
{
/* skip adaptation field */
p += p[0] + 1;
}
/* if past the end of packet, ignore */
p_end = packet + TS_PACKET_SIZE;
if (p >= p_end || !has_payload)
{
return HI_FAILURE;
}
if (is_start)
{
/* pointer field present */
len = *p++;
if (p + len > p_end)
{
return HI_FAILURE;
}
if (len && cc_ok)
{
/* write remaining section bytes */
return _soft_write_section(p, len, 0);
}
p += len;
if (p < p_end)
{
return _soft_write_section(p, p_end - p, 1);
}
}
else
{
if (cc_ok)
{
return _soft_write_section(p, p_end - p, 0);
}
}
return HI_FAILURE;
}
static HI_S32 _soft_read_packet(HI_U8 *packet)
{
if(TS_PACKET_SIZE!=fread(packet,1,TS_PACKET_SIZE,s_boot_video_obj.fp))
{
LOG_ERROR("\n");
return HI_FAILURE;
}
return HI_SUCCESS;
}
static HI_S32 _soft_packets(HI_U32 size)
{
HI_U8 packet[TS_PACKET_SIZE];
HI_U32 cnt=0;
while(cnt<size)
{
MPIFUNC_CHECK(_soft_read_packet(packet));
cnt+=TS_PACKET_SIZE;
if(HI_SUCCESS==_soft_handle_packet(packet))
{
return HI_SUCCESS;
}
}
return HI_FAILURE;
}
static HI_S32 _soft_section(HI_U16 pid,HI_U8 *filter,HI_U16 filter_len,SOFT_SECTION_CB cb)
{
HI_U16 i;
memset(&s_soft_section_obj,0,sizeof(s_soft_section_obj));
s_soft_section_obj.pid=pid;
for(i=0;i<filter_len;i++)
{
s_soft_section_obj.filter[i]=filter[i];
}
s_soft_section_obj.filter_len=filter_len;
s_soft_section_obj.cb=cb;
s_soft_section_obj.last_cc=-1;
MPIFUNC_CHECK(_boot_video_rewind());
MPIFUNC_CHECK(_soft_packets(BOOT_VIDEO_PROBE_SIZE));
return HI_SUCCESS;
}
static HI_S32 _boot_video_parse_prog_info(void)
{
HI_U8 filter[SOFT_FILTER_LEN_MAX];
HI_U16 filter_len;
memset(filter,0,sizeof(filter));
filter[0]=PAT_TID;
filter_len=1;
if(HI_SUCCESS!=_soft_section(PAT_PID,
filter,filter_len,
_soft_cb_pat))
{
goto ERROR_EXIT;
}
memset(filter,0,sizeof(filter));
filter[0]=PMT_TID;
filter_len=1;
if(HI_SUCCESS!=_soft_section(s_boot_video_psi_info.pmt_pid,
filter,filter_len,
_soft_cb_pmt))
{
goto ERROR_EXIT;
}
return HI_SUCCESS;
ERROR_EXIT:
if(NULL!=s_boot_video_obj.fp)
{
fclose(s_boot_video_obj.fp);
s_boot_video_obj.fp=NULL;
}
LOG_ERROR("\n");
return HI_FAILURE;
}
5.参考文档
ISO/IEC 13818-1
2.4.3 Specification of the Transport Stream syntax and semantics
2.4.4 Program specific information
Annex C Program Specific Information
分析ffmpeg解析ts流信息的源码的更多相关文章
- ffmpeg解析TS流
介绍: MPEG的系统层编码为不同的应用场景设计了两种格式: TS(Transport Stream) 和PS(Program Stream), 它们两者之间不具有层级关系, 在逻辑上,它们两者都 ...
- Thinkphp6源码分析之解析,Thinkphp6路由,Thinkphp6路由源码解析,Thinkphp6请求流程解析,Thinkphp6源码
Thinkphp6源码解析之分析 路由篇-请求流程 0x00 前言: 第一次写这么长的博客,所以可能排版啊,分析啊,什么的可能会比较乱.但是我大致的流程已经觉得是说的够清楚了.几乎是每行源码上都有注释 ...
- [转]Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
Android事件分发机制 该篇文章出处:http://blog.csdn.net/guolin_blog/article/details/9097463 其实我一直准备写一篇关于Android事件分 ...
- Android AsyncTask完全解析,带你从源码的角度彻底理解
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11711405 我们都知道,Android UI是线程不安全的,如果想要在子线程里进 ...
- 【转】Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9153761 记得在前面的文章中,我带大家一起从源码的角度分析了Android中Vi ...
- Spring Security 解析(七) —— Spring Security Oauth2 源码解析
Spring Security 解析(七) -- Spring Security Oauth2 源码解析 在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因 ...
- [学习总结]7、Android AsyncTask完全解析,带你从源码的角度彻底理解
我们都知道,Android UI是线程不安全的,如果想要在子线程里进行UI操作,就需要借助Android的异步消息处理机制.之前我也写过了一篇文章从源码层面分析了Android的异步消息处理机制,感兴 ...
- 45.限流Throttling及源码解析
什么是限流? 限流类似于权限机制,它也决定是否接受当前请求,用于控制客户端在某段时间内允许向API发出请求的次数,也就是频率 假设有客户端(比如爬虫程序)短时间发起大量请求,超过了服务器能够处理的能力 ...
- CBV流程之View源码解析
CBV是基于反射实现根据请求方式不同,执行不同的方法. 请求流程:view源码解析 1.urls.py :请求一定来执行视图下的as_view方法.也可以直接点击as_view()来找源码. 2.vi ...
随机推荐
- eval的对于验证数学公式的用处
var a=10,b=20; var s=a+b+((a/b)+(a+(a-b)))+(11)/a; var r=eval(s); console.log(r); 只要不报错,说明公式正确, 报错公式 ...
- mybatis 3.2.8 + log4j2.0.2 控制台输出sql语句
mybatis3.2.7有一个bug,使用log4j2 (2.0.2)版本时,会找不到类 ,导致启动失败,详见 https://github.com/mybatis/mybatis-3/issues/ ...
- CodeSmith操作Access时字段的排序问题
最近在用CodeSmith操作写ACCESS数据库的代码模版,发现CodeSmith默认的字段顺序与ACCESS中表的字段顺序不一致. 首先在ACCESS数据库中建一个测试表Test,并添加ID.Na ...
- python2.1-原理之琐碎技巧
本系列依据<python学习手册第四版>而写,也算是个学习笔记吧,选择本书的原因在于它不同于第三版,它强调介绍python3.0 ,而会在不同的地方给出2.6版本的区别,:本书侧重介绍原理 ...
- Scala入门之控制结构
package com.dtspark.scala.basics /** * Scala中的基本控制结构有顺序.条件和循环三种方式,这个其它的JVM语言是一致的,但是Scala也有一些高级的流程控制结 ...
- 再记一次w3wp占用CPU过高的解决过程(Dictionary和线程安全)
在此之前项目有发生过两次类似的状况,都得以解决,但最近又会发现偶尔CPU会跑满,虽然之前使用过WinDbg解决过两次问题但人的记忆是不可靠的,今天处理同样问题的时候还是遇到了一些障碍,这一次希望可以记 ...
- Codeforces Round #370(div 2)
A B C :=w= D:两个人得分互不影响很关键 一种是f[i][j]表示前i轮,分差为j的方案数 明显有f[i][j]=f[i-1][j-2k]+2*f[i-1][j-2k+1]+...+(2k+ ...
- matlab中的xcorr 自相关函数
转载自 http://blog.163.com/to_be_myself/blog/static/176060227201101762159227/ Matlab中用于计算自相关函数的指令是xcorr ...
- c++ iterator(迭代器)分类及其使用
前言: 以下的内容为我阅读c++沉思录18,19,20章的笔记以及自己的想法. 正文: 总所周知,c++的stl中提出了iterator的概念,这是C所没有的.在一般的使用中,iterator的行为很 ...
- python环境搭建-在Windows上安装python3.5.2
在Windows上安装Python3.5.2 首先,根据你的Windows版本(64位还是32位)从Python的官方网站下载Python 3.5.2对应的64位安装程序或32位安装程序(网速慢的同学 ...