summaryrefslogtreecommitdiff
path: root/ffmpeg/libavformat/mpegts.c
diff options
context:
space:
mode:
Diffstat (limited to 'ffmpeg/libavformat/mpegts.c')
-rw-r--r--ffmpeg/libavformat/mpegts.c320
1 files changed, 264 insertions, 56 deletions
diff --git a/ffmpeg/libavformat/mpegts.c b/ffmpeg/libavformat/mpegts.c
index 85b5146..39b1b5d 100644
--- a/ffmpeg/libavformat/mpegts.c
+++ b/ffmpeg/libavformat/mpegts.c
@@ -29,6 +29,7 @@
#include "libavutil/avassert.h"
#include "libavcodec/bytestream.h"
#include "libavcodec/get_bits.h"
+#include "libavcodec/mathops.h"
#include "avformat.h"
#include "mpegts.h"
#include "internal.h"
@@ -52,7 +53,7 @@ enum MpegTSFilterType {
typedef struct MpegTSFilter MpegTSFilter;
-typedef int PESCallback(MpegTSFilter *f, const uint8_t *buf, int len, int is_start, int64_t pos);
+typedef int PESCallback(MpegTSFilter *f, const uint8_t *buf, int len, int is_start, int64_t pos, int64_t cur_pcr);
typedef struct MpegTSPESFilter {
PESCallback *pes_cb;
@@ -89,6 +90,9 @@ struct Program {
unsigned int id; //program id/service id
unsigned int nb_pids;
unsigned int pids[MAX_PIDS_PER_PROGRAM];
+
+ /** have we found pmt for this program */
+ int pmt_found;
};
struct MpegTSContext {
@@ -98,7 +102,11 @@ struct MpegTSContext {
/** raw packet size, including FEC if present */
int raw_packet_size;
- int pos47;
+ int size_stat[3];
+ int size_stat_count;
+#define SIZE_STAT_THRESHOLD 10
+
+ int64_t pos47_full;
/** if true, all pids are analyzed to find streams */
int auto_guess;
@@ -106,6 +114,9 @@ struct MpegTSContext {
/** compute exact PCR for each transport stream packet */
int mpeg2ts_compute_pcr;
+ /** fix dvb teletext pts */
+ int fix_teletext_pts;
+
int64_t cur_pcr; /**< used to estimate the exact PCR */
int pcr_incr; /**< used to estimate the exact PCR */
@@ -131,16 +142,33 @@ struct MpegTSContext {
int current_pid;
};
-static const AVOption options[] = {
+static const AVOption mpegtsraw_options[] = {
{"compute_pcr", "Compute exact PCR for each transport stream packet.", offsetof(MpegTSContext, mpeg2ts_compute_pcr), AV_OPT_TYPE_INT,
{.i64 = 0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
+ {"ts_packetsize", "Output option carrying the raw packet size.", offsetof(MpegTSContext, raw_packet_size), AV_OPT_TYPE_INT,
+ {.i64 = 0}, 0, 0, AV_OPT_FLAG_METADATA },
{ NULL },
};
static const AVClass mpegtsraw_class = {
.class_name = "mpegtsraw demuxer",
.item_name = av_default_item_name,
- .option = options,
+ .option = mpegtsraw_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static const AVOption mpegts_options[] = {
+ {"fix_teletext_pts", "Try to fix pts values of dvb teletext streams.", offsetof(MpegTSContext, fix_teletext_pts), AV_OPT_TYPE_INT,
+ {.i64 = 1}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
+ {"ts_packetsize", "Output option carrying the raw packet size.", offsetof(MpegTSContext, raw_packet_size), AV_OPT_TYPE_INT,
+ {.i64 = 0}, 0, 0, AV_OPT_FLAG_METADATA },
+ { NULL },
+};
+
+static const AVClass mpegts_class = {
+ .class_name = "mpegts demuxer",
+ .item_name = av_default_item_name,
+ .option = mpegts_options,
.version = LIBAVUTIL_VERSION_INT,
};
@@ -179,10 +207,22 @@ typedef struct PESContext {
uint8_t header[MAX_PES_HEADER_SIZE];
AVBufferRef *buffer;
SLConfigDescr sl;
+ int64_t last_pcr;
} PESContext;
extern AVInputFormat ff_mpegts_demuxer;
+static struct Program * get_program(MpegTSContext *ts, unsigned int programid)
+{
+ int i;
+ for(i=0; i<ts->nb_prg; i++) {
+ if(ts->prg[i].id == programid) {
+ return &ts->prg[i];
+ }
+ }
+ return NULL;
+}
+
static void clear_avprogram(MpegTSContext *ts, unsigned int programid)
{
AVProgram *prg = NULL;
@@ -203,8 +243,10 @@ static void clear_program(MpegTSContext *ts, unsigned int programid)
clear_avprogram(ts, programid);
for(i=0; i<ts->nb_prg; i++)
- if(ts->prg[i].id == programid)
+ if(ts->prg[i].id == programid) {
ts->prg[i].nb_pids = 0;
+ ts->prg[i].pmt_found = 0;
+ }
}
static void clear_programs(MpegTSContext *ts)
@@ -216,26 +258,20 @@ static void clear_programs(MpegTSContext *ts)
static void add_pat_entry(MpegTSContext *ts, unsigned int programid)
{
struct Program *p;
- void *tmp = av_realloc(ts->prg, (ts->nb_prg+1)*sizeof(struct Program));
- if(!tmp)
+ if (av_reallocp_array(&ts->prg, ts->nb_prg + 1, sizeof(*ts->prg)) < 0) {
+ ts->nb_prg = 0;
return;
- ts->prg = tmp;
+ }
p = &ts->prg[ts->nb_prg];
p->id = programid;
p->nb_pids = 0;
+ p->pmt_found = 0;
ts->nb_prg++;
}
static void add_pid_to_pmt(MpegTSContext *ts, unsigned int programid, unsigned int pid)
{
- int i;
- struct Program *p = NULL;
- for(i=0; i<ts->nb_prg; i++) {
- if(ts->prg[i].id == programid) {
- p = &ts->prg[i];
- break;
- }
- }
+ struct Program *p = get_program(ts, programid);
if(!p)
return;
@@ -244,6 +280,15 @@ static void add_pid_to_pmt(MpegTSContext *ts, unsigned int programid, unsigned i
p->pids[p->nb_pids++] = pid;
}
+static void set_pmt_found(MpegTSContext *ts, unsigned int programid)
+{
+ struct Program *p = get_program(ts, programid);
+ if(!p)
+ return;
+
+ p->pmt_found = 1;
+}
+
static void set_pcr_pid(AVFormatContext *s, unsigned int programid, unsigned int pid)
{
int i;
@@ -268,6 +313,17 @@ static int discard_pid(MpegTSContext *ts, unsigned int pid)
int i, j, k;
int used = 0, discarded = 0;
struct Program *p;
+
+ /* If none of the programs have .discard=AVDISCARD_ALL then there's
+ * no way we have to discard this packet
+ */
+ for (k = 0; k < ts->stream->nb_programs; k++) {
+ if (ts->stream->programs[k]->discard == AVDISCARD_ALL)
+ break;
+ }
+ if (k == ts->stream->nb_programs)
+ return 0;
+
for(i=0; i<ts->nb_prg; i++) {
p = &ts->prg[i];
for(j=0; j<p->nb_pids; j++) {
@@ -419,22 +475,19 @@ static void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter)
static int analyze(const uint8_t *buf, int size, int packet_size, int *index){
int stat[TS_MAX_PACKET_SIZE];
int i;
- int x=0;
int best_score=0;
- memset(stat, 0, packet_size*sizeof(int));
+ memset(stat, 0, packet_size*sizeof(*stat));
- for(x=i=0; i<size-3; i++){
+ for(i=0; i<size-3; i++){
if(buf[i] == 0x47 && !(buf[i+1] & 0x80) && buf[i+3] != 0x47){
+ int x = i % packet_size;
stat[x]++;
if(stat[x] > best_score){
best_score= stat[x];
if(index) *index= x;
}
}
-
- x++;
- if(x == packet_size) x= 0;
}
return best_score;
@@ -566,6 +619,7 @@ static const StreamType ISO_types[] = {
{ 0x11, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC_LATM }, /* LATM syntax */
#endif
{ 0x1b, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 },
+ { 0x24, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC },
{ 0x42, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS },
{ 0xd1, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC },
{ 0xea, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1 },
@@ -600,11 +654,17 @@ static const StreamType REGD_types[] = {
{ MKTAG('D','T','S','1'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS },
{ MKTAG('D','T','S','2'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS },
{ MKTAG('D','T','S','3'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS },
+ { MKTAG('H','E','V','C'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC },
{ MKTAG('K','L','V','A'), AVMEDIA_TYPE_DATA, AV_CODEC_ID_SMPTE_KLV },
{ MKTAG('V','C','-','1'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1 },
{ 0 },
};
+static const StreamType METADATA_types[] = {
+ { MKTAG('K','L','V','A'), AVMEDIA_TYPE_DATA, AV_CODEC_ID_SMPTE_KLV },
+ { 0 },
+};
+
/* descriptor present */
static const StreamType DESC_types[] = {
{ 0x6a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, /* AC-3 descriptor */
@@ -808,7 +868,7 @@ static int read_sl_header(PESContext *pes, SLConfigDescr *sl, const uint8_t *buf
/* 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)
+ int64_t pos, int64_t pcr)
{
PESContext *pes = filter->u.pes_filter.opaque;
MpegTSContext *ts = pes->ts;
@@ -818,6 +878,9 @@ static int mpegts_push_data(MpegTSFilter *filter,
if(!ts->pkt)
return 0;
+ if (pcr != -1)
+ pes->last_pcr = pcr;
+
if (is_start) {
if (pes->state == MPEGTS_PAYLOAD && pes->data_index > 0) {
new_pes_packet(pes, ts->pkt);
@@ -932,7 +995,10 @@ static int mpegts_push_data(MpegTSFilter *filter,
pes->pts = AV_NOPTS_VALUE;
pes->dts = AV_NOPTS_VALUE;
if ((flags & 0xc0) == 0x80) {
- pes->dts = pes->pts = ff_parse_pes_pts(r);
+ pes->pts = ff_parse_pes_pts(r);
+ /* video pts is not monotonic, can't be used for dts */
+ if (pes->st->codec->codec_type != AVMEDIA_TYPE_VIDEO)
+ pes->dts = pes->pts;
r += 5;
} else if ((flags & 0xc0) == 0xc0) {
pes->pts = ff_parse_pes_pts(r);
@@ -964,6 +1030,38 @@ static int mpegts_push_data(MpegTSFilter *filter,
p += sl_header_bytes;
buf_size -= sl_header_bytes;
}
+ if (pes->stream_type == 0x15 && buf_size >= 5) {
+ /* skip metadata access unit header */
+ pes->pes_header_size += 5;
+ p += 5;
+ buf_size -= 5;
+ }
+ if (pes->ts->fix_teletext_pts && pes->st->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT) {
+ 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 && f->type == MPEGTS_PES) {
+ PESContext *pcrpes = f->u.pes_filter.opaque;
+ if (pcrpes && pcrpes->last_pcr != -1 && pcrpes->st && pcrpes->st->discard != AVDISCARD_ALL) {
+ // 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 one
+ int64_t pcr = pcrpes->last_pcr / 300;
+ pes->st->pts_wrap_reference = pcrpes->st->pts_wrap_reference;
+ pes->st->pts_wrap_behavior = pcrpes->st->pts_wrap_behavior;
+ if (pes->dts == AV_NOPTS_VALUE || pes->dts < pcr) {
+ pes->pts = pes->dts = pcr;
+ } else if (pes->dts > pcr + 3654 + 9000) {
+ pes->pts = pes->dts = pcr + 3654 + 9000;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
}
break;
case MPEGTS_PAYLOAD:
@@ -1020,6 +1118,7 @@ static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid)
pes->state = MPEGTS_SKIP;
pes->pts = AV_NOPTS_VALUE;
pes->dts = AV_NOPTS_VALUE;
+ pes->last_pcr = -1;
tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes);
if (!tss) {
av_free(pes);
@@ -1157,6 +1256,11 @@ static int parse_MP4SLDescrTag(MP4DescrParseContext *d, int64_t off, int len)
descr->sl.timestamp_res = avio_rb32(&d->pb);
avio_rb32(&d->pb);
descr->sl.timestamp_len = avio_r8(&d->pb);
+ if (descr->sl.timestamp_len > 64) {
+ avpriv_request_sample(NULL, "timestamp_len > 64");
+ descr->sl.timestamp_len = 64;
+ return AVERROR_PATCHWELCOME;
+ }
descr->sl.ocr_len = avio_r8(&d->pb);
descr->sl.au_len = avio_r8(&d->pb);
descr->sl.inst_bitrate_len = avio_r8(&d->pb);
@@ -1391,9 +1495,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
if (st->codec->extradata_size == 4 && memcmp(st->codec->extradata, *pp, 4))
avpriv_request_sample(fc, "DVB sub with multiple IDs");
} else {
- st->codec->extradata = av_malloc(4 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (st->codec->extradata) {
- st->codec->extradata_size = 4;
+ if (!ff_alloc_extradata(st->codec, 4)) {
memcpy(st->codec->extradata, *pp, 4);
}
}
@@ -1426,6 +1528,15 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
case 0x52: /* stream identifier descriptor */
st->stream_identifier = 1 + get8(pp, desc_end);
break;
+ case 0x26: /* metadata descriptor */
+ if (get16(pp, desc_end) == 0xFFFF)
+ *pp += 4;
+ if (get8(pp, desc_end) == 0xFF) {
+ st->codec->codec_tag = bytestream_get_le32(pp);
+ if (st->codec->codec_id == AV_CODEC_ID_NONE)
+ mpegts_find_stream_type(st, st->codec->codec_tag, METADATA_types);
+ }
+ break;
default:
break;
}
@@ -1507,6 +1618,8 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
if (!ts->stream->nb_streams)
ts->stop_parse = 2;
+ set_pmt_found(ts, h->id);
+
for(;;) {
st = 0;
pes = NULL;
@@ -1625,12 +1738,18 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
if (sid == 0x0000) {
/* NIT info */
} else {
+ MpegTSFilter *fil = ts->pids[pmt_pid];
program = av_new_program(ts->stream, sid);
program->program_num = sid;
program->pmt_pid = pmt_pid;
- if (ts->pids[pmt_pid])
- mpegts_close_filter(ts, ts->pids[pmt_pid]);
- mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1);
+ if (fil)
+ if ( fil->type != MPEGTS_SECTION
+ || fil->pid != pmt_pid
+ || fil->u.section_filter.section_cb != pmt_cb)
+ mpegts_close_filter(ts, ts->pids[pmt_pid]);
+
+ if (!ts->pids[pmt_pid])
+ mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1);
add_pat_entry(ts, sid);
add_pid_to_pmt(ts, sid, 0); //add pat pid to program
add_pid_to_pmt(ts, sid, pmt_pid);
@@ -1726,6 +1845,9 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
}
}
+static int parse_pcr(int64_t *ppcr_high, int *ppcr_low,
+ const uint8_t *packet);
+
/* handle one TS packet */
static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
{
@@ -1790,7 +1912,10 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
return 0;
pos = avio_tell(ts->stream->pb);
- ts->pos47= pos % ts->raw_packet_size;
+ if (pos >= 0) {
+ av_assert0(pos >= TS_PACKET_SIZE);
+ ts->pos47_full = pos - TS_PACKET_SIZE;
+ }
if (tss->type == MPEGTS_SECTION) {
if (is_start) {
@@ -1817,17 +1942,70 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
p, p_end - p, 0);
}
}
+
+ // stop find_stream_info from waiting for more streams
+ // when all programs have received a PMT
+ if( ts->stream->ctx_flags & AVFMTCTX_NOHEADER) {
+ int i;
+ for(i=0; i<ts->nb_prg; i++) {
+ if (!ts->prg[i].pmt_found)
+ break;
+ }
+ if (i == ts->nb_prg && ts->nb_prg > 0) {
+ av_log(ts->stream, AV_LOG_DEBUG, "All programs have pmt, headers found\n");
+ ts->stream->ctx_flags &= ~AVFMTCTX_NOHEADER;
+ }
+ }
+
} else {
int ret;
+ int64_t pcr = -1;
+ int64_t pcr_h;
+ int pcr_l;
+ if (parse_pcr(&pcr_h, &pcr_l, packet) == 0)
+ pcr = pcr_h * 300 + pcr_l;
// Note: The position here points actually behind the current packet.
if ((ret = tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start,
- pos - ts->raw_packet_size)) < 0)
+ pos - ts->raw_packet_size, pcr)) < 0)
return ret;
}
return 0;
}
+static void reanalyze(MpegTSContext *ts) {
+ AVIOContext *pb = ts->stream->pb;
+ int64_t pos = avio_tell(pb);
+ if(pos < 0)
+ return;
+ pos -= ts->pos47_full;
+ if (pos == TS_PACKET_SIZE) {
+ ts->size_stat[0] ++;
+ } else if (pos == TS_DVHS_PACKET_SIZE) {
+ ts->size_stat[1] ++;
+ } else if (pos == TS_FEC_PACKET_SIZE) {
+ ts->size_stat[2] ++;
+ }
+
+ ts->size_stat_count ++;
+ if(ts->size_stat_count > SIZE_STAT_THRESHOLD) {
+ int newsize = 0;
+ if (ts->size_stat[0] > SIZE_STAT_THRESHOLD) {
+ newsize = TS_PACKET_SIZE;
+ } else if (ts->size_stat[1] > SIZE_STAT_THRESHOLD) {
+ newsize = TS_DVHS_PACKET_SIZE;
+ } else if (ts->size_stat[2] > SIZE_STAT_THRESHOLD) {
+ newsize = TS_FEC_PACKET_SIZE;
+ }
+ if (newsize && newsize != ts->raw_packet_size) {
+ av_log(ts->stream, AV_LOG_WARNING, "changing packet size to %d\n", newsize);
+ ts->raw_packet_size = newsize;
+ }
+ ts->size_stat_count = 0;
+ memset(ts->size_stat, 0, sizeof(ts->size_stat));
+ }
+}
+
/* XXX: try to find a better synchro over several packets (use
get_packet_size() ?) */
static int mpegts_resync(AVFormatContext *s)
@@ -1841,6 +2019,7 @@ static int mpegts_resync(AVFormatContext *s)
return -1;
if (c == 0x47) {
avio_seek(pb, -1, SEEK_CUR);
+ reanalyze(s->priv_data);
return 0;
}
}
@@ -1850,37 +2029,45 @@ static int mpegts_resync(AVFormatContext *s)
}
/* return -1 if error or EOF. Return 0 if OK. */
-static int read_packet(AVFormatContext *s, uint8_t *buf, int raw_packet_size)
+static int read_packet(AVFormatContext *s, uint8_t *buf, int raw_packet_size, const uint8_t **data)
{
AVIOContext *pb = s->pb;
- int skip, len;
+ int len;
for(;;) {
- len = avio_read(pb, buf, TS_PACKET_SIZE);
+ len = ffio_read_indirect(pb, buf, TS_PACKET_SIZE, data);
if (len != TS_PACKET_SIZE)
return len < 0 ? len : AVERROR_EOF;
/* check packet sync byte */
- if (buf[0] != 0x47) {
+ if ((*data)[0] != 0x47) {
/* find a new packet start */
- avio_seek(pb, -TS_PACKET_SIZE, SEEK_CUR);
+ uint64_t pos = avio_tell(pb);
+ avio_seek(pb, -FFMIN(raw_packet_size, pos), SEEK_CUR);
+
if (mpegts_resync(s) < 0)
return AVERROR(EAGAIN);
else
continue;
} else {
- skip = raw_packet_size - TS_PACKET_SIZE;
- if (skip > 0)
- avio_skip(pb, skip);
break;
}
}
return 0;
}
+static void finished_reading_packet(AVFormatContext *s, int raw_packet_size)
+{
+ AVIOContext *pb = s->pb;
+ int skip = raw_packet_size - TS_PACKET_SIZE;
+ if (skip > 0)
+ avio_skip(pb, skip);
+}
+
static int handle_packets(MpegTSContext *ts, int nb_packets)
{
AVFormatContext *s = ts->stream;
uint8_t packet[TS_PACKET_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
+ const uint8_t *data;
int packet_num, ret = 0;
if (avio_tell(s->pb) != ts->last_pos) {
@@ -1894,6 +2081,7 @@ static int handle_packets(MpegTSContext *ts, int nb_packets)
av_buffer_unref(&pes->buffer);
pes->data_index = 0;
pes->state = MPEGTS_SKIP; /* skip until pes header */
+ pes->last_pcr = -1;
}
ts->pids[i]->last_cc = -1;
}
@@ -1913,10 +2101,11 @@ static int handle_packets(MpegTSContext *ts, int nb_packets)
if (ts->stop_parse > 0)
break;
- ret = read_packet(s, packet, ts->raw_packet_size);
+ ret = read_packet(s, packet, ts->raw_packet_size, &data);
if (ret != 0)
break;
- ret = handle_packet(ts, packet);
+ ret = handle_packet(ts, data);
+ finished_reading_packet(s, ts->raw_packet_size);
if (ret != 0)
break;
}
@@ -1986,6 +2175,15 @@ static int parse_pcr(int64_t *ppcr_high, int *ppcr_low,
return 0;
}
+static void seek_back(AVFormatContext *s, AVIOContext *pb, int64_t pos) {
+
+ /* NOTE: We attempt to seek on non-seekable files as well, as the
+ * probe buffer usually is big enough. Only warn if the seek failed
+ * on files where the seek should work. */
+ if (avio_seek(pb, pos, SEEK_SET) < 0)
+ av_log(s, pb->seekable ? AV_LOG_ERROR : AV_LOG_INFO, "Unable to seek back to the start\n");
+}
+
static int mpegts_read_header(AVFormatContext *s)
{
MpegTSContext *ts = s->priv_data;
@@ -1994,6 +2192,8 @@ static int mpegts_read_header(AVFormatContext *s)
int len;
int64_t pos;
+ ffio_ensure_seekback(pb, s->probesize);
+
/* read the first 8192 bytes to get packet size */
pos = avio_tell(pb);
len = avio_read(pb, buf, sizeof(buf));
@@ -2009,11 +2209,7 @@ static int mpegts_read_header(AVFormatContext *s)
/* normal demux */
/* first do a scan to get all the services */
- /* NOTE: We attempt to seek on non-seekable files as well, as the
- * probe buffer usually is big enough. Only warn if the seek failed
- * on files where the seek should work. */
- if (avio_seek(pb, pos, SEEK_SET) < 0)
- av_log(s, pb->seekable ? AV_LOG_ERROR : AV_LOG_INFO, "Unable to seek back to the start\n");
+ seek_back(s, pb, pos);
mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1);
@@ -2033,6 +2229,7 @@ static int mpegts_read_header(AVFormatContext *s)
int64_t pcrs[2], pcr_h;
int packet_count[2];
uint8_t packet[TS_PACKET_SIZE];
+ const uint8_t *data;
/* only read packets */
@@ -2048,18 +2245,21 @@ static int mpegts_read_header(AVFormatContext *s)
nb_pcrs = 0;
nb_packets = 0;
for(;;) {
- ret = read_packet(s, packet, ts->raw_packet_size);
+ ret = read_packet(s, packet, ts->raw_packet_size, &data);
if (ret < 0)
- return -1;
- pid = AV_RB16(packet + 1) & 0x1fff;
+ goto fail;
+ pid = AV_RB16(data + 1) & 0x1fff;
if ((pcr_pid == -1 || pcr_pid == pid) &&
- parse_pcr(&pcr_h, &pcr_l, packet) == 0) {
+ parse_pcr(&pcr_h, &pcr_l, data) == 0) {
+ finished_reading_packet(s, ts->raw_packet_size);
pcr_pid = pid;
packet_count[nb_pcrs] = nb_packets;
pcrs[nb_pcrs] = pcr_h * 300 + pcr_l;
nb_pcrs++;
if (nb_pcrs >= 2)
break;
+ } else {
+ finished_reading_packet(s, ts->raw_packet_size);
}
nb_packets++;
}
@@ -2075,7 +2275,7 @@ static int mpegts_read_header(AVFormatContext *s)
st->start_time / 1000000.0, pcrs[0] / 27e6, ts->pcr_incr);
}
- avio_seek(pb, pos, SEEK_SET);
+ seek_back(s, pb, pos);
return 0;
fail:
return -1;
@@ -2091,15 +2291,19 @@ static int mpegts_raw_read_packet(AVFormatContext *s,
int64_t pcr_h, next_pcr_h, pos;
int pcr_l, next_pcr_l;
uint8_t pcr_buf[12];
+ const uint8_t *data;
if (av_new_packet(pkt, TS_PACKET_SIZE) < 0)
return AVERROR(ENOMEM);
pkt->pos= avio_tell(s->pb);
- ret = read_packet(s, pkt->data, ts->raw_packet_size);
+ ret = read_packet(s, pkt->data, ts->raw_packet_size, &data);
if (ret < 0) {
av_free_packet(pkt);
return ret;
}
+ if (data != pkt->data)
+ memcpy(pkt->data, data, ts->raw_packet_size);
+ finished_reading_packet(s, ts->raw_packet_size);
if (ts->mpeg2ts_compute_pcr) {
/* compute exact PCR for each packet */
if (parse_pcr(&pcr_h, &pcr_l, pkt->data) == 0) {
@@ -2181,13 +2385,15 @@ static av_unused int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index,
int64_t pos, timestamp;
uint8_t buf[TS_PACKET_SIZE];
int pcr_l, pcr_pid = ((PESContext*)s->streams[stream_index]->priv_data)->pcr_pid;
- pos = ((*ppos + ts->raw_packet_size - 1 - ts->pos47) / ts->raw_packet_size) * ts->raw_packet_size + ts->pos47;
+ int pos47 = ts->pos47_full % ts->raw_packet_size;
+ pos = ((*ppos + ts->raw_packet_size - 1 - pos47) / ts->raw_packet_size) * ts->raw_packet_size + pos47;
while(pos < pos_limit) {
if (avio_seek(s->pb, pos, SEEK_SET) < 0)
return AV_NOPTS_VALUE;
if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
return AV_NOPTS_VALUE;
if (buf[0] != 0x47) {
+ avio_seek(s->pb, -TS_PACKET_SIZE, SEEK_CUR);
if (mpegts_resync(s) < 0)
return AV_NOPTS_VALUE;
pos = avio_tell(s->pb);
@@ -2209,7 +2415,8 @@ static int64_t mpegts_get_dts(AVFormatContext *s, int stream_index,
{
MpegTSContext *ts = s->priv_data;
int64_t pos;
- pos = ((*ppos + ts->raw_packet_size - 1 - ts->pos47) / ts->raw_packet_size) * ts->raw_packet_size + ts->pos47;
+ int pos47 = ts->pos47_full % ts->raw_packet_size;
+ pos = ((*ppos + ts->raw_packet_size - 1 - pos47) / ts->raw_packet_size) * ts->raw_packet_size + pos47;
ff_read_frame_flush(s);
if (avio_seek(s->pb, pos, SEEK_SET) < 0)
return AV_NOPTS_VALUE;
@@ -2224,7 +2431,7 @@ static int64_t mpegts_get_dts(AVFormatContext *s, int stream_index,
if(pkt.dts != AV_NOPTS_VALUE && pkt.pos >= 0){
ff_reduce_index(s, pkt.stream_index);
av_add_index_entry(s->streams[pkt.stream_index], pkt.pos, pkt.dts, 0, 0, AVINDEX_KEYFRAME /* FIXME keyframe? */);
- if(pkt.stream_index == stream_index){
+ if(pkt.stream_index == stream_index && pkt.pos >= *ppos){
*ppos= pkt.pos;
return pkt.dts;
}
@@ -2298,6 +2505,7 @@ AVInputFormat ff_mpegts_demuxer = {
.read_close = mpegts_read_close,
.read_timestamp = mpegts_get_dts,
.flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT,
+ .priv_class = &mpegts_class,
};
AVInputFormat ff_mpegtsraw_demuxer = {