您的位置:首页 > 娱乐 > 明星 > 保定网络营销_网页设计制作手机网站_seo的含义是什么意思_今天的新闻 最新消息

保定网络营销_网页设计制作手机网站_seo的含义是什么意思_今天的新闻 最新消息

2024/12/23 23:40:50 来源:https://blog.csdn.net/u014552102/article/details/144539429  浏览:    关键词:保定网络营销_网页设计制作手机网站_seo的含义是什么意思_今天的新闻 最新消息
保定网络营销_网页设计制作手机网站_seo的含义是什么意思_今天的新闻 最新消息

一、引言

FFmpeg源码在解析完PMT表后,会得到该节目包含的视频和音频信息,从而找到音视频流。TS流的音视频流包含在PES流中。FFmpeg源码通过调用函数指针tss->u.pes_filter.pes_cb指向的回调函数解析PES流的PES packet:

/* handle one TS packet */
static int handle_packet(MpegTSContext *ts, const uint8_t *packet, int64_t pos)
{
//...if (tss->type == MPEGTS_SECTION) {//...}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;
//...
}

而函数指针tss->u.pes_filter.pes_cb指向的回调函数是mpegts_push_data函数。

二、mpegts_push_data函数的定义

mpegts_push_data函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的源文件libavformat/mpegts.c中:

/* return non zero if a packet could be constructed */
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;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;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 or section header. We can now* decide */if (pes->header[0] == 0x00 && pes->header[1] == 0x00 &&pes->header[2] == 0x01) {/* it must be an MPEG-2 PES stream */pes->stream_id = pes->header[3];av_log(pes->stream, AV_LOG_TRACE, "pid=%x stream_id=%#x\n", pes->pid, pes->stream_id);if ((pes->st && pes->st->discard == AVDISCARD_ALL &&(!pes->sub_st ||pes->sub_st->discard == AVDISCARD_ALL)) ||pes->stream_id == STREAM_ID_PADDING_STREAM)goto skip;/* stream not present in PMT */if (!pes->st) {if (ts->skip_changes)goto skip;if (ts->merge_pmt_versions)goto skip; /* wait for PMT to merge new stream */pes->st = avformat_new_stream(ts->stream, NULL);if (!pes->st)return AVERROR(ENOMEM);pes->st->id = pes->pid;mpegts_set_stream_info(pes->st, pes, 0, 0);}pes->PES_packet_length = AV_RB16(pes->header + 4);/* NOTE: zero length means the PES size is unbounded */if (pes->stream_id != STREAM_ID_PROGRAM_STREAM_MAP &&pes->stream_id != STREAM_ID_PRIVATE_STREAM_2 &&pes->stream_id != STREAM_ID_ECM_STREAM &&pes->stream_id != STREAM_ID_EMM_STREAM &&pes->stream_id != STREAM_ID_PROGRAM_STREAM_DIRECTORY &&pes->stream_id != STREAM_ID_DSMCC_STREAM &&pes->stream_id != STREAM_ID_TYPE_E_STREAM) {FFStream *const pes_sti = ffstream(pes->st);pes->state = MPEGTS_PESHEADER;if (pes->st->codecpar->codec_id == AV_CODEC_ID_NONE && !pes_sti->request_probe) {av_log(pes->stream, AV_LOG_TRACE,"pid=%x stream_type=%x probing\n",pes->pid,pes->stream_type);pes_sti->request_probe = 1;}} else {pes->pes_header_size = 6;pes->state      = MPEGTS_PAYLOAD;pes->data_index = 0;}} else {/* otherwise, it should be a 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;flags = pes->header[7];r = pes->header + 9;pes->pts = AV_NOPTS_VALUE;pes->dts = AV_NOPTS_VALUE;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) { /* PES extension */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. We parse 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 == STREAM_TYPE_METADATA &&pes->stream_id == STREAM_ID_METADATA_STREAM &&pes->st->codecpar->codec_id == AV_CODEC_ID_SMPTE_KLV &&buf_size >= 5) {/* skip metadata access unit header - see MISB ST 1402 */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;int pcr_found = 0;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 && !f->discard) {// teletext packets do not always have correct timestamps,// the standard says they should be handled after 40.6 ms at most,// and the pcr error to this packet should be no more than 100 ms.// TODO: we should interpolate the PCR, not just use the last oneint64_t pcr = f->last_pcr / 300;pcr_found = 1;if (st) {const FFStream *const sti = ffstream(st);FFStream *const pes_sti   = ffstream(pes->st);pes_sti->pts_wrap_reference = sti->pts_wrap_reference;pes_sti->pts_wrap_behavior  = sti->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) { //10secpes->pts = pes->dts = pcr + 3654 + 9000;}break;}}}}if (pes->st->codecpar->codec_id == AV_CODEC_ID_DVB_TELETEXT &&!pcr_found) {av_log(pes->stream, AV_LOG_VERBOSE,"Forcing DTS/PTS to be unset for a ""non-trustworthy PES packet for PID %d as ""PCR hasn't been received yet.\n",pes->pid);pes->dts = pes->pts = AV_NOPTS_VALUE;}}}break;case MPEGTS_PAYLOAD:do {int max_packet_size = ts->max_packet_size;if (pes->PES_packet_length && pes->PES_packet_length + PES_START_SIZE > pes->pes_header_size)max_packet_size = pes->PES_packet_length + PES_START_SIZE - pes->pes_header_size;if (pes->data_index > 0 &&pes->data_index + buf_size > max_packet_size) {ret = new_pes_packet(pes, ts->pkt);if (ret < 0)return ret;pes->PES_packet_length = 0;max_packet_size = ts->max_packet_size;ts->stop_parse = 1;} else if (pes->data_index == 0 &&buf_size > max_packet_size) {// pes packet size is < ts size packet and pes data is padded with 0xff// not sure if this is legal in ts but see issue #2392buf_size = max_packet_size;}if (!pes->buffer) {pes->buffer = buffer_pool_get(ts, max_packet_size);if (!pes->buffer)return AVERROR(ENOMEM);}memcpy(pes->buffer->data + pes->data_index, p, buf_size);pes->data_index += buf_size;/* emit complete packets with known packet size* decreases demuxer delay for infrequent packets like subtitles from* a couple of seconds to milliseconds for properly muxed files. */if (!ts->stop_parse && pes->PES_packet_length &&pes->pes_header_size + pes->data_index == pes->PES_packet_length + PES_START_SIZE) {ts->stop_parse = 1;ret = new_pes_packet(pes, ts->pkt);pes->state = MPEGTS_SKIP;if (ret < 0)return ret;}} while (0);buf_size = 0;break;case MPEGTS_SKIP:buf_size = 0;break;}}return 0;
}

该函数的作用就是:解析TS流中的PES流的PES packet(PES包)。即解析TS流中的一个PES packet。

形参filter:输出型参数,指向一个MpegTSFilter类型变量。

形参buf:输入型参数。存放一个transport packet(TS包)去掉TS Header后的有效数据,即ES packet的数据。

形参buf_size:输入型参数。形参buf指向的缓冲区的大小。

形参is_start:输入型参数。如果值为true,表示该transport packet的TS Header的payload_unit_start_indicator属性的值为1,说明携带的是PES的第一个包。

形参pos:输入型参数,文件位置指针当前位置相对于TS文件的文件首的偏移字节数 减去 188字节。

返回值:返回0表示解析成功,返回一个负数表示出错。

三、mpegts_push_data函数的内部实现分析

mpegts_push_data函数内部使用了状态机的设计模式,会根据枚举变量pes->state的值执行不同的处理逻辑,pes->state取值如下:

/* TS stream handling */enum MpegTSState {MPEGTS_HEADER = 0,MPEGTS_PESHEADER,MPEGTS_PESHEADER_FILL,MPEGTS_PAYLOAD,MPEGTS_SKIP,
};

mpegts_push_data函数中首先判断形参is_start的值,如果为true,说明携带的是PES的第一个包。让pes->state赋值为MPEGTS_HEADER:

    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;}

下面分情况讨论。

(一)pes->state的值为MPEGTS_HEADER

pes->state的值为MPEGTS_HEADER时,mpegts_push_data函数会执行下面代码块解析该PES packet的PES packet header中的固定长度部分:

        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 or section header. We can now* decide */if (pes->header[0] == 0x00 && pes->header[1] == 0x00 &&pes->header[2] == 0x01) {/* it must be an MPEG-2 PES stream */pes->stream_id = pes->header[3];av_log(pes->stream, AV_LOG_TRACE, "pid=%x stream_id=%#x\n", pes->pid, pes->stream_id);if ((pes->st && pes->st->discard == AVDISCARD_ALL &&(!pes->sub_st ||pes->sub_st->discard == AVDISCARD_ALL)) ||pes->stream_id == STREAM_ID_PADDING_STREAM)goto skip;/* stream not present in PMT */if (!pes->st) {if (ts->skip_changes)goto skip;if (ts->merge_pmt_versions)goto skip; /* wait for PMT to merge new stream */pes->st = avformat_new_stream(ts->stream, NULL);if (!pes->st)return AVERROR(ENOMEM);pes->st->id = pes->pid;mpegts_set_stream_info(pes->st, pes, 0, 0);}pes->PES_packet_length = AV_RB16(pes->header + 4);/* NOTE: zero length means the PES size is unbounded */if (pes->stream_id != STREAM_ID_PROGRAM_STREAM_MAP &&pes->stream_id != STREAM_ID_PRIVATE_STREAM_2 &&pes->stream_id != STREAM_ID_ECM_STREAM &&pes->stream_id != STREAM_ID_EMM_STREAM &&pes->stream_id != STREAM_ID_PROGRAM_STREAM_DIRECTORY &&pes->stream_id != STREAM_ID_DSMCC_STREAM &&pes->stream_id != STREAM_ID_TYPE_E_STREAM) {FFStream *const pes_sti = ffstream(pes->st);pes->state = MPEGTS_PESHEADER;if (pes->st->codecpar->codec_id == AV_CODEC_ID_NONE && !pes_sti->request_probe) {av_log(pes->stream, AV_LOG_TRACE,"pid=%x stream_type=%x probing\n",pes->pid,pes->stream_type);pes_sti->request_probe = 1;}} else {pes->pes_header_size = 6;pes->state      = MPEGTS_PAYLOAD;pes->data_index = 0;}} else {/* otherwise, it should be a table *//* skip packet */
skip:pes->state = MPEGTS_SKIP;continue;}}

宏PES_START_SIZE定义在libavformat/mpegts.c中,值为6,表示PES packet header中的固定长度部分总共占6个字节:

#define PES_START_SIZE  6

上述代码块中,首先将该PES packet的PES packet header中的固定长度部分拷贝到数组pes->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;

判断PES packet header中的packet_start_code_prefix属性的值是否为0x000001,如果是,说明这是PES packet,读取stream_id属性的值,赋值给变量pes->stream_id:

                /* we got all the PES or section header. We can now* decide */if (pes->header[0] == 0x00 && pes->header[1] == 0x00 &&pes->header[2] == 0x01) {/* it must be an MPEG-2 PES stream */pes->stream_id = pes->header[3];av_log(pes->stream, AV_LOG_TRACE, "pid=%x stream_id=%#x\n", pes->pid, pes->stream_id);//...
}

如果在之前解析PMT表的时候没有找到该PES流对应的音视频流,跳过本次循环:

                    /* stream not present in PMT */if (!pes->st) {if (ts->skip_changes)goto skip;if (ts->merge_pmt_versions)goto skip; /* wait for PMT to merge new stream */pes->st = avformat_new_stream(ts->stream, NULL);if (!pes->st)return AVERROR(ENOMEM);pes->st->id = pes->pid;mpegts_set_stream_info(pes->st, pes, 0, 0);}

读取PES_packet_length属性的值,赋值给变量pes->PES_packet_length:

                    pes->PES_packet_length = AV_RB16(pes->header + 4);/* NOTE: zero length means the PES size is unbounded */

通过PES packet header中的stream_id的值判断PES packet header中是否存在Optional PES header,如果存在,让pes->state赋值为MPEGTS_PESHEADER:

                    if (pes->stream_id != STREAM_ID_PROGRAM_STREAM_MAP &&pes->stream_id != STREAM_ID_PRIVATE_STREAM_2 &&pes->stream_id != STREAM_ID_ECM_STREAM &&pes->stream_id != STREAM_ID_EMM_STREAM &&pes->stream_id != STREAM_ID_PROGRAM_STREAM_DIRECTORY &&pes->stream_id != STREAM_ID_DSMCC_STREAM &&pes->stream_id != STREAM_ID_TYPE_E_STREAM) {FFStream *const pes_sti = ffstream(pes->st);pes->state = MPEGTS_PESHEADER;if (pes->st->codecpar->codec_id == AV_CODEC_ID_NONE && !pes_sti->request_probe) {av_log(pes->stream, AV_LOG_TRACE,"pid=%x stream_type=%x probing\n",pes->pid,pes->stream_type);pes_sti->request_probe = 1;}} else {pes->pes_header_size = 6;pes->state      = MPEGTS_PAYLOAD;pes->data_index = 0;}

(二)pes->state的值为MPEGTS_PESHEADER

pes->state的值为MPEGTS_PESHEADER时,mpegts_push_data函数会执行下面代码块:

        /**********************************************//* 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;

宏PES_HEADER_SIZE定义在libavformat/mpegts.c中,值为9,表示PES packet header中的固定长度部分 + Optional PES header中的PES_header_data_length属性之前的部分(包含PES_header_data_length属性)总共占9个字节:

#define PES_HEADER_SIZE 9

上述代码块中,首先将该PES packet的Optional PES header中的PES_header_data_length属性之前的部分(包含PES_header_data_length属性)拷贝到pes->header + pes->data_index指向的缓冲区中:

            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;

读取Optional PES header中的PES_header_data_length属性,赋值给变量pes->pes_header_size。让变量pes->state赋值为MPEGTS_PESHEADER_FILL:

            if (pes->data_index == PES_HEADER_SIZE) {pes->pes_header_size = pes->header[8] + 9;pes->state           = MPEGTS_PESHEADER_FILL;}

(三)pes->state的值为MPEGTS_PESHEADER_FILL

pes->state的值为MPEGTS_PESHEADER_FILL时,mpegts_push_data函数会执行下面代码块:

            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;flags = pes->header[7];r = pes->header + 9;pes->pts = AV_NOPTS_VALUE;pes->dts = AV_NOPTS_VALUE;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) { /* PES extension */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. We parse 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 == STREAM_TYPE_METADATA &&pes->stream_id == STREAM_ID_METADATA_STREAM &&pes->st->codecpar->codec_id == AV_CODEC_ID_SMPTE_KLV &&buf_size >= 5) {/* skip metadata access unit header - see MISB ST 1402 */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;int pcr_found = 0;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 && !f->discard) {// teletext packets do not always have correct timestamps,// the standard says they should be handled after 40.6 ms at most,// and the pcr error to this packet should be no more than 100 ms.// TODO: we should interpolate the PCR, not just use the last oneint64_t pcr = f->last_pcr / 300;pcr_found = 1;if (st) {const FFStream *const sti = ffstream(st);FFStream *const pes_sti   = ffstream(pes->st);pes_sti->pts_wrap_reference = sti->pts_wrap_reference;pes_sti->pts_wrap_behavior  = sti->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) { //10secpes->pts = pes->dts = pcr + 3654 + 9000;}break;}}}}if (pes->st->codecpar->codec_id == AV_CODEC_ID_DVB_TELETEXT &&!pcr_found) {av_log(pes->stream, AV_LOG_VERBOSE,"Forcing DTS/PTS to be unset for a ""non-trustworthy PES packet for PID %d as ""PCR hasn't been received yet.\n",pes->pid);pes->dts = pes->pts = AV_NOPTS_VALUE;}}}break;

上述代码块中,首先将该PES packet的Optional PES header中的可选字段占用的总字节数,以及包含在此PES packet header的任何填充字节拷贝到pes->header + pes->data_index指向的缓冲区中:

            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;

读取Optional PES header中的PTS_DTS_flags、ESCR_flag、ES_rate_flag、DSM_trick_mode_flag、additional_copy_info_flag、PES_CRC_flag、PES_extension_flag这7个属性(这7个属性加起来总共1个字节),赋值给变量flags:

                const uint8_t *r;unsigned int flags, pes_ext, skip;flags = pes->header[7];r = pes->header + 9;pes->pts = AV_NOPTS_VALUE;pes->dts = AV_NOPTS_VALUE;

如果Optional PES header中的PTS_DTS_flags属性的值为'10',表示PES packet header中会存在PTS。读取PTS的值赋值给变量pes->pts,让pes->dts也等于PTS:

                if ((flags & 0xc0) == 0x80) {pes->dts = pes->pts = ff_parse_pes_pts(r);r += 5;}

如果PTS_DTS_flags属性的值为'11',PES packet header中会同时存在PTS和DTS,读取PTS的值赋值给变量pes->pts,读取DTS的值赋值给变量pes->dts:

                if ((flags & 0xc0) == 0x80) {//...} else if ((flags & 0xc0) == 0xc0) {pes->pts = ff_parse_pes_pts(r);r += 5;pes->dts = ff_parse_pes_pts(r);r += 5;}

如果PES_extension_flag属性的值为1,表示PES packet header有PES_extension域,解析PES_extension域:

                if (flags & 0x01) { /* PES extension */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];}}

至此,mpegts_push_data函数已解析完整个PES packet header,让变量pes->state赋值为MPEGTS_PAYLOAD:

                /* we got the full header. We parse it and get the payload */pes->state = MPEGTS_PAYLOAD;pes->data_index = 0;

(四)pes->state的值为MPEGTS_PAYLOAD

pes->state的值为MPEGTS_PAYLOAD时,mpegts_push_data函数会执行下面代码块:

case MPEGTS_PAYLOAD:do {int max_packet_size = ts->max_packet_size;if (pes->PES_packet_length && pes->PES_packet_length + PES_START_SIZE > pes->pes_header_size)max_packet_size = pes->PES_packet_length + PES_START_SIZE - pes->pes_header_size;if (pes->data_index > 0 &&pes->data_index + buf_size > max_packet_size) {ret = new_pes_packet(pes, ts->pkt);if (ret < 0)return ret;pes->PES_packet_length = 0;max_packet_size = ts->max_packet_size;ts->stop_parse = 1;} else if (pes->data_index == 0 &&buf_size > max_packet_size) {// pes packet size is < ts size packet and pes data is padded with 0xff// not sure if this is legal in ts but see issue #2392buf_size = max_packet_size;}if (!pes->buffer) {pes->buffer = buffer_pool_get(ts, max_packet_size);if (!pes->buffer)return AVERROR(ENOMEM);}memcpy(pes->buffer->data + pes->data_index, p, buf_size);pes->data_index += buf_size;/* emit complete packets with known packet size* decreases demuxer delay for infrequent packets like subtitles from* a couple of seconds to milliseconds for properly muxed files. */if (!ts->stop_parse && pes->PES_packet_length &&pes->pes_header_size + pes->data_index == pes->PES_packet_length + PES_START_SIZE) {ts->stop_parse = 1;ret = new_pes_packet(pes, ts->pkt);pes->state = MPEGTS_SKIP;if (ret < 0)return ret;}} while (0);buf_size = 0;break;

上述代码块的主要作用就是将该PES packet的PES packet data bytes(PES包的负载)拷贝到pes->buffer->data + pes->data_index指向的缓冲区中:

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

ts->pkt指向一个AVPacket类型的变量,让ts->pkt得到该PES packet的数据:

                /* emit complete packets with known packet size* decreases demuxer delay for infrequent packets like subtitles from* a couple of seconds to milliseconds for properly muxed files. */if (!ts->stop_parse && pes->PES_packet_length &&pes->pes_header_size + pes->data_index == pes->PES_packet_length + PES_START_SIZE) {ts->stop_parse = 1;ret = new_pes_packet(pes, ts->pkt);pes->state = MPEGTS_SKIP;if (ret < 0)return ret;}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com