X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmpegts.c;h=68e3a7681721e19241c43ca02c66c2d650d5c567;hb=bd4640375e24fc0aa8846d9ee42cebe3c1fa9c12;hp=ad3cd824f40236291d0ceaa9c94762cbfb75c487;hpb=3074f03a074de3aab79639d261cbd0ccc265b5b4;p=ffmpeg diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index ad3cd824f40..68e3a768172 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -25,6 +25,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/log.h" #include "libavutil/dict.h" +#include "libavutil/mathematics.h" #include "libavutil/opt.h" #include "libavcodec/bytestream.h" #include "avformat.h" @@ -163,6 +164,7 @@ typedef struct PESContext { enum MpegTSState state; /* used to get the format */ int data_index; + int flags; /**< copied to the AVPacket flags */ int total_size; int pes_header_size; int extended_stream_id; @@ -635,6 +637,12 @@ static void new_pes_packet(PESContext *pes, AVPacket *pkt) pkt->destruct = av_destruct_packet; pkt->data = pes->buffer; pkt->size = pes->data_index; + + if(pes->total_size != MAX_PES_PAYLOAD && + pes->pes_header_size + pes->data_index != pes->total_size + 6) { + av_log(pes->stream, AV_LOG_WARNING, "PES packet size mismatch\n"); + pes->flags |= AV_PKT_FLAG_CORRUPT; + } memset(pkt->data+pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE); // Separate out the AC3 substream from an HDMV combined TrueHD/AC3 PID @@ -646,12 +654,14 @@ static void new_pes_packet(PESContext *pes, AVPacket *pkt) pkt->dts = pes->dts; /* store position of first TS packet of this PES packet */ pkt->pos = pes->ts_packet_pos; + pkt->flags = pes->flags; /* reset pts values */ pes->pts = AV_NOPTS_VALUE; pes->dts = AV_NOPTS_VALUE; pes->buffer = NULL; pes->data_index = 0; + pes->flags = 0; } /* return non zero if a packet could be constructed */ @@ -1268,7 +1278,8 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) { AVFormatContext *s = ts->stream; MpegTSFilter *tss; - int len, pid, cc, cc_ok, afc, is_start; + 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; @@ -1284,19 +1295,36 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) if (!tss) return 0; + 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); - cc_ok = (tss->last_cc < 0) || ((((tss->last_cc + 1) & 0x0f) == cc)); + 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_WARNING, "Continuity Check Failed\n"); + if(tss->type == MPEGTS_PES) { + PESContext *pc = tss->u.pes_filter.opaque; + pc->flags |= AV_PKT_FLAG_CORRUPT; + } + } - /* skip adaptation field */ - afc = (packet[3] >> 4) & 3; - p = packet + 4; - if (afc == 0) /* reserved value */ - return 0; - if (afc == 2) /* adaptation field only */ + if (!has_payload) return 0; - if (afc == 3) { + p = packet + 4; + if (has_adaptation) { /* skip adapation field */ p += p[0] + 1; } @@ -1397,7 +1425,22 @@ static int handle_packets(MpegTSContext *ts, int nb_packets) { AVFormatContext *s = ts->stream; uint8_t packet[TS_PACKET_SIZE]; - int packet_num, ret; + int packet_num, ret = 0; + + if (avio_tell(s->pb) != ts->last_pos) { + int i; +// av_dlog("Skipping after seek\n"); + /* seek detected, flush pes buffer */ + for (i = 0; i < NB_PID_MAX; i++) { + if (ts->pids[i] && ts->pids[i]->type == MPEGTS_PES) { + PESContext *pes = ts->pids[i]->u.pes_filter.opaque; + av_freep(&pes->buffer); + ts->pids[i]->last_cc = -1; + pes->data_index = 0; + pes->state = MPEGTS_SKIP; /* skip until pes header */ + } + } + } ts->stop_parse = 0; packet_num = 0; @@ -1409,12 +1452,13 @@ static int handle_packets(MpegTSContext *ts, int nb_packets) break; ret = read_packet(s, packet, ts->raw_packet_size); if (ret != 0) - return ret; + break; ret = handle_packet(ts, packet); if (ret != 0) - return ret; + break; } - return 0; + ts->last_pos = avio_tell(s->pb); + return ret; } static int mpegts_probe(AVProbeData *p) @@ -1485,17 +1529,6 @@ static int mpegts_read_header(AVFormatContext *s, int len; int64_t pos; -#if FF_API_FORMAT_PARAMETERS - if (ap) { - if (ap->mpeg2ts_compute_pcr) - ts->mpeg2ts_compute_pcr = ap->mpeg2ts_compute_pcr; - if(ap->mpeg2ts_raw){ - av_log(s, AV_LOG_ERROR, "use mpegtsraw_demuxer!\n"); - return -1; - } - } -#endif - /* read the first 1024 bytes to get packet size */ pos = avio_tell(pb); len = avio_read(pb, buf, sizeof(buf)); @@ -1513,7 +1546,7 @@ static int mpegts_read_header(AVFormatContext *s, /* normal demux */ /* first do a scaning to get all the services */ - if (avio_seek(pb, pos, SEEK_SET) < 0) + if (pb->seekable && avio_seek(pb, pos, SEEK_SET) < 0) av_log(s, AV_LOG_ERROR, "Unable to seek back to the start\n"); mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1); @@ -1634,18 +1667,6 @@ static int mpegts_read_packet(AVFormatContext *s, MpegTSContext *ts = s->priv_data; int ret, i; - if (avio_tell(s->pb) != ts->last_pos) { - /* seek detected, flush pes buffer */ - for (i = 0; i < NB_PID_MAX; i++) { - if (ts->pids[i] && ts->pids[i]->type == MPEGTS_PES) { - PESContext *pes = ts->pids[i]->u.pes_filter.opaque; - av_freep(&pes->buffer); - pes->data_index = 0; - pes->state = MPEGTS_SKIP; /* skip until pes header */ - } - } - } - ts->pkt = pkt; ret = handle_packets(ts, 0); if (ret < 0) { @@ -1663,8 +1684,6 @@ static int mpegts_read_packet(AVFormatContext *s, } } - ts->last_pos = avio_tell(s->pb); - return ret; } @@ -1885,15 +1904,15 @@ void ff_mpegts_parse_close(MpegTSContext *ts) } AVInputFormat ff_mpegts_demuxer = { - "mpegts", - NULL_IF_CONFIG_SMALL("MPEG-2 transport stream format"), - sizeof(MpegTSContext), - mpegts_probe, - mpegts_read_header, - mpegts_read_packet, - mpegts_read_close, - read_seek, - mpegts_get_pcr, + .name = "mpegts", + .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 transport stream format"), + .priv_data_size = sizeof(MpegTSContext), + .read_probe = mpegts_probe, + .read_header = mpegts_read_header, + .read_packet = mpegts_read_packet, + .read_close = mpegts_read_close, + .read_seek = read_seek, + .read_timestamp = mpegts_get_pcr, .flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT, #ifdef USE_SYNCPOINT_SEARCH .read_seek2 = read_seek2, @@ -1901,15 +1920,14 @@ AVInputFormat ff_mpegts_demuxer = { }; AVInputFormat ff_mpegtsraw_demuxer = { - "mpegtsraw", - NULL_IF_CONFIG_SMALL("MPEG-2 raw transport stream format"), - sizeof(MpegTSContext), - NULL, - mpegts_read_header, - mpegts_raw_read_packet, - mpegts_read_close, - read_seek, - mpegts_get_pcr, + .name = "mpegtsraw", + .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 raw transport stream format"), + .priv_data_size = sizeof(MpegTSContext), + .read_header = mpegts_read_header, + .read_packet = mpegts_raw_read_packet, + .read_close = mpegts_read_close, + .read_seek = read_seek, + .read_timestamp = mpegts_get_pcr, .flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT, #ifdef USE_SYNCPOINT_SEARCH .read_seek2 = read_seek2,