zoukankan      html  css  js  c++  java
  • 分析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 ", 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 ",
                       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 ");
                            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: ");
            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 ", 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 ", 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 ",
                    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 ", 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 ", 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(" ");
            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(" ");
        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
        
       

  • 相关阅读:
    bzoj 3876: [Ahoi2014&Jsoi2014]支线剧情【有上下界有源汇最小费用最大流】
    bzoj 2055: 80人环游世界【有上下界有源汇最小费用最大流】
    bzoj 2406: 矩阵【二分+有源汇上下界可行流】
    bzoj 4873: [Shoi2017]寿司餐厅【最大权闭合子图】
    bzoj 2007: [Noi2010]海拔【最小割+dijskstra】
    bzoj 2039: [2009国家集训队]employ人员雇佣【最小割】
    bzoj 3996: [TJOI2015]线性代数【最小割】
    bzoj 3158: 千钧一发【最小割】
    bzoj 2597: [Wc2007]剪刀石头布【最小费用最大流】
    bzoj 5120: [2017国家集训队测试]无限之环【最小费用最大流】
  • 原文地址:https://www.cnblogs.com/fedorayang/p/5094186.html
Copyright © 2011-2022 走看看