ffmpeg(10) mpegts_read_header part 2

来源:互联网 发布:足球球员数据统计 编辑:程序博客网 时间:2024/05/17 22:31

static int mpegts_read_header(AVFormatContext *s)

--->

// 向ts->pids中注册pid为SDT_PID的packet的回调函数

        mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1);


// 向ts->pids中注册pid为PAT_PID的packet的回调函数
        mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1);

--->

handle_packets(ts, s->probesize / ts->raw_packet_size);

--->

    for (;;) 
    {
        printf("%s : %s : %d, packet_num is: %ld\n", __FILE__, __FUNCTION__, __LINE__, packet_num);
        packet_num++;
        
        if (nb_packets != 0 && packet_num >= nb_packets || ts->stop_parse > 1)
        {
            ret = AVERROR(EAGAIN);
            break;
        }


        if (ts->stop_parse > 0)
            break;

// 每次读取ts->raw_packet_size个字节到*data指向的内存区域中,ts->raw_packet_size的值应该是一个标准TS packet的大小,即188字节
        ret = read_packet(s, packet, ts->raw_packet_size, &data);
        if (ret != 0)
            break;

// 数据读取到*data中后,调用handle_packet对读取到的数据进行处理
        ret = handle_packet(ts, data);

        finished_reading_packet(s, ts->raw_packet_size);
        
        if (ret != 0)
            break;
    }


在函数

/* handle one TS packet */
static int handle_packet(MpegTSContext *ts, const uint8_t *packet)

在这个函数中,

    if (ts->auto_guess && tss == NULL && is_start)
    {
        add_pes_stream(ts, pid, -1);
        tss = ts->pids[pid];
    }

需要注意,如果ts->auto_guess为1,则所有的pid都会去分析,寻找pes;

is_start 则是来自payload_unit_start_indicator,这一位的定义非常重要:

payload_unit_start_indicator– The payload_unit_start_indicator is a 1-bit flag which has normative meaning for 
Transport Stream packets that carry PES packets (refer to 2.4.3.6) or PSI data (refer to 2.4.4). 
When the payload of the Transport Stream packet contains PES packet data, the payload_unit_start_indicator has the 
following significance: a '1' indicates that the payload of this Transport Stream packet will commence with the first byte 
of a PES packet and a '0' indicates no PES packet shall start in this Transport Stream packet. If the 
payload_unit_start_indicator is set to '1', then one and only one PES packet starts in this Transport Stream packet. This 
also applies to private streams of stream_type 6 (refer to Table 2-29). 
When the payload of the Transport Stream packet contains PSI data, the payload_unit_start_indicator has the following 
significance: if the Transport Stream packet carries the first byte of a PSI section, the payload_unit_start_indicator value 
shall be '1', indicating that the first byte of the payload of this Transport Stream packet carries the pointer_field. If the 
Transport Stream packet does not carry the first byte of a PSI section, the payload_unit_start_indicator value shall be '0', 
indicating that there is no pointer_field in the payload. Refer to 2.4.4.1 and 2.4.4.2. This also applies to private streams of
stream_type 5 (refer to Table 2-29). 
For null packets the payload_unit_start_indicator shall be set to '0'. 


在开始时,ts->pids中,只有PAT 和 SDT的 pid Filter不是null,因此其它的数据全部抛弃,只处理PAT 和 SDT packet中的数据:

    if (tss->type == MPEGTS_SECTION)
    {
        if (is_start) 
        {
            /* pointer field present */
            len = *p++;
            if (p + len > p_end)
                return 0;
            
            if (len && cc_ok) 
            {
                /* write remaining section bytes */
                write_section_data(s, 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(s, tss,
                                   p, p_end - p, 1);
            }
        } 
        else 
        {
            if (cc_ok)
            {
                write_section_data(s, 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) 
        {
            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)
            {
                if (ts->stream->nb_streams > 1 || pos > 100000)
                {
                    av_log(ts->stream, AV_LOG_DEBUG, "All programs have pmt, headers found\n");
                    ts->stream->ctx_flags &= ~AVFMTCTX_NOHEADER;
                }
            }
        }


    }

调用函数

static void write_section_data(AVFormatContext *s, MpegTSFilter *tss1,
                               const uint8_t *buf, int buf_size, int is_start)

将数据写入到对应的pid Filter中的uint8_t *section_buf; 中;

然后调用pid Filter中的callback函数处理section_buf中的数据:

        if (crc_valid)
            tss->section_cb(tss1, tss->section_buf, tss->section_h_size);

以PAT为例子,在

static int mpegts_read_header(AVFormatContext *s);

中,将static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) 函数

赋值给 PAT_PID Filter的section_cb,因此,此处调用这个函数,处理写入到

section_buf中的数据:

待续~















0 0