ffmpeg--mpegts.c解析PES

解析PES参考13818-1

handle_packets

static int handle_packets(MpegTSContext *ts, int64_t nb_packets)
{
    AVFormatContext *s = ts->stream;
    uint8_t packet[TS_PACKET_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
    const uint8_t *data;
    int64_t packet_num;
    int ret = 0;

    if (avio_tell(s->pb) != ts->last_pos) {
        int i;
        av_log(ts->stream, AV_LOG_TRACE, "Skipping after seek\n");
        /* seek detected, flush pes buffer */
        for (i = 0; i < NB_PID_MAX; i++) {
            if (ts->pids[i]) {
                if (ts->pids[i]->type == MPEGTS_PES) {
                    PESContext *pes = ts->pids[i]->u.pes_filter.opaque;
                    av_buffer_unref(&pes->buffer);
                    pes->data_index = 0;
                    pes->state = MPEGTS_SKIP; /* skip until pes header */
                } else if (ts->pids[i]->type == MPEGTS_SECTION) {
                    ts->pids[i]->u.section_filter.last_ver = -1;
                }
                ts->pids[i]->last_cc = -1;
                ts->pids[i]->last_pcr = -1;
            }
        }
    }

    ts->stop_parse = 0;
    packet_num = 0;
    memset(packet + TS_PACKET_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
    for (;;) {  //进入一个循环
        packet_num++;
        if (nb_packets != 0 && packet_num >= nb_packets ||
            ts->stop_parse > 1) {
            ret = AVERROR(EAGAIN);
            break;
        }
        if (ts->stop_parse > 0)
            break;     //当遇到stop_parse大于0时(解析完一个PES时此值为1),退出循环。
        ret = read_packet(s, packet, ts->raw_packet_size, &data);
        if (ret != 0)
            break;
        ret = handle_packet(ts, data);
        finished_reading_packet(s, ts->raw_packet_size);
        if (ret != 0)
            break;
    }
    ts->last_pos = avio_tell(s->pb);
    return ret;
}

/*

pes->state可能有以下几种情况:

/* TS stream handling */

enum MpegTSState {

    MPEGTS_HEADER = 0,

    MPEGTS_PESHEADER,

    MPEGTS_PESHEADER_FILL,

    MPEGTS_PAYLOAD,

    MPEGTS_SKIP,

};

*/

 mpegts_push_data

/* return non zero if a packet could beconstructed */

static int mpegts_push_data(MpegTSFilter*filter,

                            const uint8_t *buf,int buf_size, int is_start,

                            int64_t pos)

{

   PESContext *pes   = filter->u.pes_filter.opaque;

   MpegTSContext *ts = pes->ts;

   const uint8_t *p;

   int ret, len, code;

   if (!ts->pkt)

       return 0;

   if (is_start) {

       if (pes->state == MPEGTS_PAYLOAD && pes->data_index >0) {

           ret = new_pes_packet(pes, ts->pkt);

           if (ret < 0)

                return ret;

           ts->stop_parse = 1;

       } else {

           reset_pes_packet_state(pes);

       }

       pes->state         =MPEGTS_HEADER;

       pes->ts_packet_pos = pos;

    }

    p = buf;

     //4个字节的TS头,个PES的头,10为填充头

   while (buf_size > 0) {

       switch (pes->state) {

        case MPEGTS_HEADER:

           len = PES_START_SIZE - pes->data_index;

           if (len > buf_size)

                len = buf_size;

           memcpy(pes->header + pes->data_index, p, len);

           pes->data_index += len;

           p += len;

           buf_size -= len;

           if (pes->data_index == PES_START_SIZE) {

                /* we got all the PES orsection header. We can now

                 * decide */

                if (pes->header[0] == 0x00&& pes->header[1] == 0x00 &&

                    pes->header[2] == 0x01){

                    //前三个为00,00,01。

                    /* it must be an MPEG-2 PESstream */

                    code = pes->header[3] |0x100;

                    av_log(pes->stream,AV_LOG_TRACE, "pid=%x pes_code=%#x\n", pes->pid,

                            code);

                    pes->stream_id =pes->header[3];

 

                    if ((pes->st &&pes->st->discard == AVDISCARD_ALL &&

                         (!pes->sub_st ||

                         pes->sub_st->discard == AVDISCARD_ALL)) ||

                        code == 0x1be) /*padding_stream */

                        goto skip;

                    /* stream not present inPMT */

                    if (!pes->st) {

                        if(ts->skip_changes)

                            goto skip;

                          //new stream

                        pes->st =avformat_new_stream(ts->stream, NULL);

                        if (!pes->st)

                            returnAVERROR(ENOMEM);

                        pes->st->id =pes->pid;

                       mpegts_set_stream_info(pes->st, pes, 0, 0);

                    }

                     //得到pes长度

                    pes->total_size =AV_RB16(pes->header + 4);

                    /* NOTE: a zero total sizemeans the PES size is

                     * unbounded */

                    if (!pes->total_size)

                        pes->total_size =MAX_PES_PAYLOAD;

                   /*allocate pes buffer */

                    pes->buffer =av_buffer_alloc(pes->total_size +

                                                 AV_INPUT_BUFFER_PADDING_SIZE);

                    if (!pes->buffer)

                        return AVERROR(ENOMEM);

                    if (code != 0x1bc&& code != 0x1bf && /* program_stream_map, private_stream_2 */

                        code != 0x1f0&& code != 0x1f1 && /* ECM, EMM */

                        code != 0x1ff&& code != 0x1f2 && /* program_stream_directory, DSMCC_stream*/

                        code != 0x1f8) {                  /* ITU-T Rec. H.222.1 type Estream */

                        pes->state =MPEGTS_PESHEADER;

                        if(pes->st->codecpar->codec_id == AV_CODEC_ID_NONE &&!pes->st->request_probe) {

                           av_log(pes->stream, AV_LOG_TRACE,

                                   "pid=%x stream_type=%x probing\n",

                                   pes->pid,

                                   pes->stream_type);

                           pes->st->request_probe = 1;

                        }

                    } else {

                        pes->pes_header_size= 6;

                        pes->state      = MPEGTS_PAYLOAD;

                        pes->data_index = 0;

                    }

                } else {

                    /* otherwise, it should bea table */

                    /* skip packet */

skip:

                    pes->state =MPEGTS_SKIP;

                    continue;

                }

            }

           break;

       /**********************************************/

       /* PES packing parsing */

        case MPEGTS_PESHEADER:

           len = PES_HEADER_SIZE - pes->data_index;

           if (len < 0)

                return AVERROR_INVALIDDATA;

           if (len > buf_size)

                len = buf_size;

           memcpy(pes->header + pes->data_index, p, len);

           pes->data_index += len;

           p += len;

           buf_size -= len;

           if (pes->data_index == PES_HEADER_SIZE) {

                pes->pes_header_size =pes->header[8] + 9;

                pes->state           = MPEGTS_PESHEADER_FILL;

           }

           break;

        case MPEGTS_PESHEADER_FILL:

         //填充字段

           len = pes->pes_header_size - pes->data_index;

           if (len < 0)

                return AVERROR_INVALIDDATA;

           if (len > buf_size)

                len = buf_size;

           memcpy(pes->header + pes->data_index, p, len);

           pes->data_index += len;

           p += len;

           buf_size -= len;

           if (pes->data_index == pes->pes_header_size) {

                const uint8_t *r;

                unsigned int flags, pes_ext,skip;

                //得到pts_dts_flag

                flags = pes->header[7];

                r = pes->header + 9;

                pes->pts = AV_NOPTS_VALUE;

                pes->dts = AV_NOPTS_VALUE;

                //得到pts,dts

                if ((flags & 0xc0) == 0x80){

                    pes->dts = pes->pts =ff_parse_pes_pts(r);

                    r += 5;

                } else if ((flags & 0xc0)== 0xc0) {

                    pes->pts =ff_parse_pes_pts(r);

                    r += 5;

                    pes->dts =ff_parse_pes_pts(r);

                    r += 5;

                }

                pes->extended_stream_id =-1;

                if (flags & 0x01) { /* PESextension */

                    pes_ext = *r++;

                    /* Skip PES private data,program packet sequence counter and P-STD buffer */

                    skip  = (pes_ext >> 4) & 0xb;

                    skip += skip & 0x9;

                    r    += skip;

                    if ((pes_ext & 0x41) ==0x01 &&

                        (r + 2) <=(pes->header + pes->pes_header_size)) {

                        /* PES extension 2 */

                        if ((r[0] & 0x7f)> 0 && (r[1] & 0x80) == 0)

                           pes->extended_stream_id = r[1];

                    }

                }

                /* we got the full header. Weparse it and get the payload */

                pes->state = MPEGTS_PAYLOAD;

                pes->data_index = 0;

                if (pes->stream_type == 0x12&& buf_size > 0) {

                    int sl_header_bytes =read_sl_header(pes, &pes->sl, p, buf_size);

                    pes->pes_header_size +=sl_header_bytes;

                    p += sl_header_bytes;

                    buf_size -=sl_header_bytes;

                }

                if (pes->stream_type == 0x15&& buf_size >= 5) {

                    /* skip metadata accessunit header */

                    pes->pes_header_size +=5;

                    p += 5;

                    buf_size -= 5;

                }

                if (   pes->ts->fix_teletext_pts

                    && (   pes->st->codecpar->codec_id ==AV_CODEC_ID_DVB_TELETEXT

                        ||pes->st->codecpar->codec_id == AV_CODEC_ID_DVB_SUBTITLE)

                    ) {

                    AVProgram *p = NULL;

                    while ((p =av_find_program_from_stream(pes->stream, p, pes->st->index))) {

                        if (p->pcr_pid != -1&& p->discard != AVDISCARD_ALL) {

                            MpegTSFilter *f =pes->ts->pids[p->pcr_pid];

                            if (f) {

                                AVStream *st =NULL;

                                if (f->type== MPEGTS_PES) {

                                    PESContext*pcrpes = f->u.pes_filter.opaque;

                                   if(pcrpes)

                                        st =pcrpes->st;

                                } else if(f->type == MPEGTS_PCR) {

                                    int i;

                                    for (i = 0;i < p->nb_stream_indexes; i++) {

                                       AVStream *pst = pes->stream->streams[p->stream_index[i]];

                                        if(pst->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)

                                            st = pst;

                                    }

                                }

                                if(f->last_pcr != -1 && st && st->discard != AVDISCARD_ALL){

                                    // teletextpackets do not always have correct timestamps,

                                    // thestandard says they should be handled after 40.6 ms at most,

                                    // and thepcr error to this packet should be no more than 100 ms.

                                    // TODO: weshould interpolate the PCR, not just use the last one

                                    int64_t pcr= f->last_pcr / 300;

                                    pes->st->pts_wrap_reference= st->pts_wrap_reference;

                                   pes->st->pts_wrap_behavior = st->pts_wrap_behavior;

                                    if(pes->dts == AV_NOPTS_VALUE || pes->dts < pcr) {

                                        pes->pts = pes->dts = pcr;

                                    } else if(pes->st->codecpar->codec_id == AV_CODEC_ID_DVB_TELETEXT &&

                                              pes->dts > pcr + 3654 + 9000) {

                                        pes->pts = pes->dts = pcr + 3654 +9000;

                                    } else if(pes->st->codecpar->codec_id == AV_CODEC_ID_DVB_SUBTITLE &&

                                              pes->dts > pcr + 10*90000) { //10sec

                                        pes->pts = pes->dts= pcr + 3654 + 9000;

                                    }

                                    break;

                                }

                            }

                        }

                    }

                }

           }

           break;

        case MPEGTS_PAYLOAD:

           //负载部分

           if (pes->buffer) {

                if (pes->data_index > 0&&

                    pes->data_index +buf_size > pes->total_size) {

                    ret = new_pes_packet(pes,ts->pkt);

                    if (ret < 0)

                        return ret;

                    pes->total_size =MAX_PES_PAYLOAD;

                    pes->buffer =av_buffer_alloc(pes->total_size +

                                                 AV_INPUT_BUFFER_PADDING_SIZE);

                    if (!pes->buffer)

                        return AVERROR(ENOMEM);

                    ts->stop_parse = 1;

                } else if (pes->data_index== 0 &&

                           buf_size >pes->total_size) {

                    // pes packet size is <ts size packet and pes data is padded with 0xff

                    // not sure if this islegal in ts but see issue #2392

                    buf_size =pes->total_size;

                }   

               //复制数据。

                memcpy(pes->buffer->data+ pes->data_index, p, buf_size);

                pes->data_index += buf_size;

                /* emit complete packets withknown packet size

                 * decreases demuxer delay forinfrequent packets like subtitles from

                 * a couple of seconds tomilliseconds for properly muxed files.

                 * total_size is the number ofbytes following pes_packet_length

                 * in the pes header, i.e. notcounting the first PES_START_SIZE bytes */

                if (!ts->stop_parse&& pes->total_size < MAX_PES_PAYLOAD &&

                    pes->pes_header_size +pes->data_index == pes->total_size + PES_START_SIZE) {

                    ts->stop_parse = 1;

                    ret = new_pes_packet(pes,ts->pkt);

                    //已获得所有数据,然后将pes的内容赋值给ts->pkt

                    if (ret < 0)

                        return ret;

                }

           }

           buf_size = 0;

           break;

       case MPEGTS_SKIP:

           buf_size = 0;

           break;

       }

    }

   return 0;

}

 new_pes_packet

static int new_pes_packet(PESContext *pes,AVPacket *pkt)

{

   char *sd;

   av_init_packet(pkt);

    pkt->buf  = pes->buffer;

    pkt->data = pes->buffer->data;

    pkt->size = pes->data_index;

   if (pes->total_size != MAX_PES_PAYLOAD &&

       pes->pes_header_size + pes->data_index != pes->total_size +

       PES_START_SIZE) {

       av_log(pes->stream, AV_LOG_WARNING, "PES packet sizemismatch\n");

       pes->flags |= AV_PKT_FLAG_CORRUPT;

    }

   memset(pkt->data + pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE);

   // Separate out the AC3 substream from an HDMV combined TrueHD/AC3 PID

   if (pes->sub_st && pes->stream_type == 0x83 &&pes->extended_stream_id == 0x76)

       pkt->stream_index = pes->sub_st->index;

   else

       pkt->stream_index = pes->st->index;

   pkt->pts = pes->pts;

   pkt->dts = pes->dts;

   /* store position of first TS packet of this PES packet */

   pkt->pos   = pes->ts_packet_pos;

   pkt->flags = pes->flags;

   pes->buffer = NULL;

   reset_pes_packet_state(pes);

    sd = av_packet_new_side_data(pkt, AV_PKT_DATA_MPEGTS_STREAM_ID, 1);

   if (!sd)

       return AVERROR(ENOMEM);

   *sd = pes->stream_id;

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山西茄子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值