static int mpegts_read_packet(AVFormatContext *s, AVPacket *pkt)
{
xxxx
ret = handle_packets(ts, 0);
xxxx
}
static int handle_packets(MpegTSContext *ts, int nb_packets)
{
xxxx
ts->stop_parse = 0;
packet_num = 0;
memset(packet + TS_PACKET_SIZE, 0, FF_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) //收到完整的pes包,stop_parse会置为'1'
break;
ret = read_packet(s, packet, ts->raw_packet_size, &data); //读取一个TS包(TS_PACKET_SIZE)
if (ret != 0)
break;
ret = handle_packet(ts, data); //处理读取的TS包(状态机)
finished_reading_packet(s, ts->raw_packet_size);
if (ret != 0)
break;
}
ts->last_pos = avio_tell(s->pb);
return ret;
}
/* handle one TS packet */
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;
if (pid && discard_pid(ts, pid))
return 0;
is_start = packet[1] & 0x40;
tss = ts->pids[pid];
if (ts->auto_guess && tss == NULL && 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;
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\n",
pid, expected_cc, cc);
if (tss->type == MPEGTS_PES) {
PESContext *pc = tss->u.pes_filter.opaque;
pc->flags |= AV_PKT_FLAG_CORRUPT; //PES包损坏
}
}
if (!has_payload && tss->type != MPEGTS_PCR)
return 0;
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 || (p == p_end && tss->type != MPEGTS_PCR))
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) { //PSI包处理
xxxx
}else {
int ret;
int64_t pcr_h;
int pcr_l;
if (parse_pcr(&pcr_h, &pcr_l, packet) == 0)
tss->last_pcr = pcr_h * 300 + pcr_l;
// Note: The position here points actually behind the current packet.
if (tss->type == MPEGTS_PES) { //PES包处理
if ((ret = tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start,
pos - ts->raw_packet_size)) < 0) //mpegts_push_data
return ret;
}
}
return 0;
}
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 len, code;
if (!ts->pkt)
return 0;
if (is_start) {
if (pes->state == MPEGTS_PAYLOAD && pes->data_index > 0) { //当前包还没处理完,新的包到来。
new_pes_packet(pes, ts->pkt); //把pes的数据传给pkt(提交给上层)
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: //解析pes包头部
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 mpeg2 PES stream */
code = pes->header[3] | 0x100;
av_dlog(pes->stream, "pid=%x pes_code=%#x\n", pes->pid,
code);
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 in PMT */
if (!pes->st) {
if (ts->skip_changes)
goto skip;
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->total_size = AV_RB16(pes->header + 4);
/* NOTE: a zero total size means 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 +
FF_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 E stream */
pes->state = MPEGTS_PESHEADER;
if (pes->st->codec->codec_id == AV_CODEC_ID_NONE && !pes->st->request_probe) {
av_dlog(pes->stream,
"pid=%x stream_type=%x probing\n",
pes->pid,
pes->stream_type);
av_log(pes->stream, AV_LOG_WARNING, "----request_probe\n");
pes->st->request_probe = 1;
}
} else {
pes->state = MPEGTS_PAYLOAD;
pes->data_index = 0;
}
} else {
/* otherwise, it should be a table */
/* skip packet */
skip:
pes->state = MPEGTS_SKIP;
continue;
}
}
break;
xxxx
case MPEGTS_PAYLOAD:
if (pes->buffer) {
if (pes->data_index > 0 &&
pes->data_index + buf_size > pes->total_size) { //加上新的数据超出一个pes包的长度(当前包结束) ???
new_pes_packet(pes, ts->pkt); //把pes的数据传给pkt(提交给上层)
pes->total_size = MAX_PES_PAYLOAD;
pes->buffer = av_buffer_alloc(pes->total_size +
FF_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 is legal in ts but see issue #2392
buf_size = pes->total_size;
}
memcpy(pes->buffer->data + pes->data_index, p, buf_size); //拷贝数据到pes->buffer(可能还没拷完整个pes packet的数据)
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.
* total_size is the number of bytes following pes_packet_length
* in the pes header, i.e. not counting 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; //数据已经拷贝完,停止解析。
new_pes_packet(pes, ts->pkt); //把pes的数据传给pkt(提交给上层)
}
}
buf_size = 0;
break;
case MPEGTS_SKIP:
buf_size = 0;
break;
}
}
return 0;
}
posted on 2016-05-18 11:30
lfc 阅读(734)
评论(0) 编辑 收藏 引用