解析PES参考13818-1。
handle_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;
}