分析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
    
   

 

转载于:https://www.cnblogs.com/fedorayang/p/5094186.html

很抱歉,我无法提供具体的代码或链接来解释 ffmpeg 库如何解析 TS 。但是,我可以给你一个大致的思路来理解这个过程。 首先,你需要确保已经安装了 ffmpeg 库以及其开发包。然后,你可以编写一个简单的程序来解析 TS 。 以下是一个伪代码示例: ```c #include <stdio.h> #include <libavformat/avformat.h> int main() { av_register_all(); // 注册所有的封装器和解封装器 AVFormatContext *formatContext = NULL; // 创建一个 AVFormatContext 结构体 int ret = avformat_open_input(&formatContext, "input.ts", NULL, NULL); // 打开输入文件 if (ret != 0) { printf("无法打开输入文件\n"); return ret; } ret = avformat_find_stream_info(formatContext, NULL); // 查找信息 if (ret < 0) { printf("无法获取信息\n"); return ret; } av_dump_format(formatContext, 0, "input.ts", 0); // 打印信息 avformat_close_input(&formatContext); // 关闭输入文件 return 0; } ``` 以上示例中,我们使用了 `av_register_all()` 函数来注册所有的封装器和解封装器。然后,我们通过 `avformat_open_input()` 函数打开了输入文件。接下来,使用 `avformat_find_stream_info()` 函数查找信息,并使用 `av_dump_format()` 函数打印信息。最后,使用 `avformat_close_input()` 函数关闭输入文件。 请注意,这只是一个简单的示例,可以帮助你理解 ffmpeg解析 TS 程。实际上,ffmpeg 提供了许多丰富的功能和选项,可以根据你的具体需求来进行深入的解析和处理。你可以查阅 ffmpeg 的官方文档和示例代码来获取更详细的信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值