mirror of
https://github.com/LibreELEC/LibreELEC.tv.git
synced 2025-07-29 13:46:49 +00:00
ffmpeg: add xbmc upstream patch
Signed-off-by: Stephan Raue <stephan@openelec.tv>
This commit is contained in:
parent
20ffb104ee
commit
f7f65ecdfe
@ -0,0 +1,337 @@
|
|||||||
|
From b2d3b83a73d71833f84485adb8a6f4c0959b4c4e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Harald Axmann <harald.axmann@hotmail.com>
|
||||||
|
Date: Sun, 16 Dec 2012 16:07:36 +0100
|
||||||
|
Subject: [PATCH] lavf: Provide a monotonic timestamp to the outside world
|
||||||
|
|
||||||
|
This detects and removes single timestamp wraps, which fixes seeking for affected video files.
|
||||||
|
---
|
||||||
|
libavformat/avformat.h | 37 +++++++++++
|
||||||
|
libavformat/options.c | 1 +
|
||||||
|
libavformat/utils.c | 123 ++++++++++++++++++++++++++++++++++---
|
||||||
|
3 files changed, 151 insertions(+), 10 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
|
||||||
|
index c76ac71..40f71cb 100644
|
||||||
|
--- a/libavformat/avformat.h
|
||||||
|
+++ b/libavformat/avformat.h
|
||||||
|
@@ -627,6 +627,13 @@ enum AVStreamParseType {
|
||||||
|
#define AV_DISPOSITION_VISUAL_IMPAIRED 0x0100 /**< stream for visual impaired audiences */
|
||||||
|
#define AV_DISPOSITION_CLEAN_EFFECTS 0x0200 /**< stream without voice */
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Options for behavior on timestamp wrap detection.
|
||||||
|
+ */
|
||||||
|
+#define AV_PTS_WRAP_IGNORE 0 ///< ignore the wrap
|
||||||
|
+#define AV_PTS_WRAP_ADD_OFFSET 1 ///< add the format specific offset on wrap detection
|
||||||
|
+#define AV_PTS_WRAP_SUB_OFFSET -1 ///< subtract the format specific offset on wrap detection
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Stream structure.
|
||||||
|
* New fields can be added to the end with minor version bumps.
|
||||||
|
@@ -857,6 +864,24 @@ enum AVStreamParseType {
|
||||||
|
|
||||||
|
int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */
|
||||||
|
#endif
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Internal data to check for wrapping of the time stamp
|
||||||
|
+ */
|
||||||
|
+ int64_t pts_wrap_reference;
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Options for behavior, when a wrap is detected.
|
||||||
|
+ *
|
||||||
|
+ * Defined by AV_PTS_WRAP_ values.
|
||||||
|
+ *
|
||||||
|
+ * If correction is enabled, there are two possibilities:
|
||||||
|
+ * If the first time stamp is near the wrap point, the wrap offset
|
||||||
|
+ * will be subtracted, which will create negative time stamps.
|
||||||
|
+ * Otherwise the offset will be added.
|
||||||
|
+ */
|
||||||
|
+ int pts_wrap_behavior;
|
||||||
|
+
|
||||||
|
} AVStream;
|
||||||
|
|
||||||
|
#define AV_PROGRAM_RUNNING 1
|
||||||
|
@@ -878,6 +903,10 @@ enum AVStreamParseType {
|
||||||
|
int program_num;
|
||||||
|
int pmt_pid;
|
||||||
|
int pcr_pid;
|
||||||
|
+
|
||||||
|
+ int64_t pts_wrap_reference; ///< reference dts for wrap detection
|
||||||
|
+ int pts_wrap_behavior; ///< behavior on wrap detection
|
||||||
|
+
|
||||||
|
} AVProgram;
|
||||||
|
|
||||||
|
#define AVFMTCTX_NOHEADER 0x0001 /**< signal that no header is present
|
||||||
|
@@ -1234,6 +1263,14 @@ enum AVStreamParseType {
|
||||||
|
/* av_seek_frame() support */
|
||||||
|
int64_t data_offset; /**< offset of the first packet */
|
||||||
|
#endif
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Correct single timestamp overflows
|
||||||
|
+ * - encoding: unused
|
||||||
|
+ * - decoding: Set by user via AVOPtions (NO direct access)
|
||||||
|
+ */
|
||||||
|
+ unsigned int correct_ts_overflow;
|
||||||
|
+
|
||||||
|
} AVFormatContext;
|
||||||
|
|
||||||
|
typedef struct AVPacketList {
|
||||||
|
diff --git a/libavformat/options.c b/libavformat/options.c
|
||||||
|
index 31acbd3..666d05e 100644
|
||||||
|
--- a/libavformat/options.c
|
||||||
|
+++ b/libavformat/options.c
|
||||||
|
@@ -127,6 +127,7 @@ static const AVClass *format_child_class_next(const AVClass *prev)
|
||||||
|
{"careful", "consider things that violate the spec and have not been seen in the wild as errors", 0, AV_OPT_TYPE_CONST, {.dbl = AV_EF_CAREFUL }, INT_MIN, INT_MAX, D, "err_detect"},
|
||||||
|
{"compliant", "consider all spec non compliancies as errors", 0, AV_OPT_TYPE_CONST, {.dbl = AV_EF_COMPLIANT }, INT_MIN, INT_MAX, D, "err_detect"},
|
||||||
|
{"aggressive", "consider things that a sane encoder shouldnt do as an error", 0, AV_OPT_TYPE_CONST, {.dbl = AV_EF_AGGRESSIVE }, INT_MIN, INT_MAX, D, "err_detect"},
|
||||||
|
+{"correct_ts_overflow", "correct single timestamp overflows", OFFSET(correct_ts_overflow), AV_OPT_TYPE_INT, {.dbl = 1}, 0, 1, D},
|
||||||
|
{NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
diff --git a/libavformat/utils.c b/libavformat/utils.c
|
||||||
|
index 63f89dd..89e5ed4 100644
|
||||||
|
--- a/libavformat/utils.c
|
||||||
|
+++ b/libavformat/utils.c
|
||||||
|
@@ -122,6 +122,27 @@ static void frac_add(AVFrac *f, int64_t incr)
|
||||||
|
f->num = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/**
|
||||||
|
+ * Wrap a given time stamp, if there is an indication for an overflow
|
||||||
|
+ *
|
||||||
|
+ * @param st stream
|
||||||
|
+ * @param timestamp the time stamp to wrap
|
||||||
|
+ * @return resulting time stamp
|
||||||
|
+ */
|
||||||
|
+static int64_t wrap_timestamp(AVStream *st, int64_t timestamp)
|
||||||
|
+{
|
||||||
|
+ if (st->pts_wrap_behavior != AV_PTS_WRAP_IGNORE &&
|
||||||
|
+ st->pts_wrap_reference != AV_NOPTS_VALUE && timestamp != AV_NOPTS_VALUE) {
|
||||||
|
+ if (st->pts_wrap_behavior == AV_PTS_WRAP_ADD_OFFSET &&
|
||||||
|
+ timestamp < st->pts_wrap_reference)
|
||||||
|
+ return timestamp + (1LL<<st->pts_wrap_bits);
|
||||||
|
+ else if (st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET &&
|
||||||
|
+ timestamp >= st->pts_wrap_reference)
|
||||||
|
+ return timestamp - (1LL<<st->pts_wrap_bits);
|
||||||
|
+ }
|
||||||
|
+ return timestamp;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/** head of registered input format linked list */
|
||||||
|
static AVInputFormat *first_iformat = NULL;
|
||||||
|
/** head of registered output format linked list */
|
||||||
|
@@ -798,6 +819,8 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||||
|
}
|
||||||
|
|
||||||
|
st= s->streams[pkt->stream_index];
|
||||||
|
+ pkt->dts = wrap_timestamp(st, pkt->dts);
|
||||||
|
+ pkt->pts = wrap_timestamp(st, pkt->pts);
|
||||||
|
|
||||||
|
switch(st->codec->codec_type){
|
||||||
|
case AVMEDIA_TYPE_VIDEO:
|
||||||
|
@@ -948,8 +971,67 @@ static int is_intra_only(AVCodecContext *enc){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_index)
|
||||||
|
+{
|
||||||
|
+ if (s->correct_ts_overflow && st->pts_wrap_bits != 64 &&
|
||||||
|
+ st->pts_wrap_reference == AV_NOPTS_VALUE && st->first_dts != AV_NOPTS_VALUE) {
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ // reference time stamp should be 60 s before first time stamp
|
||||||
|
+ int64_t pts_wrap_reference = st->first_dts - av_rescale(60, st->time_base.den, st->time_base.num);
|
||||||
|
+ // if first time stamp is not more than 1/8 and 60s before the wrap point, subtract rather than add wrap offset
|
||||||
|
+ int pts_wrap_behavior = (st->first_dts < (1LL<<st->pts_wrap_bits) - (1LL<<st->pts_wrap_bits-3)) ||
|
||||||
|
+ (st->first_dts < (1LL<<st->pts_wrap_bits) - av_rescale(60, st->time_base.den, st->time_base.num)) ?
|
||||||
|
+ AV_PTS_WRAP_ADD_OFFSET : AV_PTS_WRAP_SUB_OFFSET;
|
||||||
|
+
|
||||||
|
+ AVProgram *first_program = av_find_program_from_stream(s, NULL, stream_index);
|
||||||
|
+
|
||||||
|
+ if (!first_program) {
|
||||||
|
+ int default_stream_index = av_find_default_stream_index(s);
|
||||||
|
+ if (s->streams[default_stream_index]->pts_wrap_reference == AV_NOPTS_VALUE) {
|
||||||
|
+ for (i=0; i<s->nb_streams; i++) {
|
||||||
|
+ s->streams[i]->pts_wrap_reference = pts_wrap_reference;
|
||||||
|
+ s->streams[i]->pts_wrap_behavior = pts_wrap_behavior;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ else {
|
||||||
|
+ st->pts_wrap_reference = s->streams[default_stream_index]->pts_wrap_reference;
|
||||||
|
+ st->pts_wrap_behavior = s->streams[default_stream_index]->pts_wrap_behavior;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ else {
|
||||||
|
+ AVProgram *program = first_program;
|
||||||
|
+ while (program) {
|
||||||
|
+ if (program->pts_wrap_reference != AV_NOPTS_VALUE) {
|
||||||
|
+ pts_wrap_reference = program->pts_wrap_reference;
|
||||||
|
+ pts_wrap_behavior = program->pts_wrap_behavior;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ program = av_find_program_from_stream(s, program, stream_index);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // update every program with differing pts_wrap_reference
|
||||||
|
+ program = first_program;
|
||||||
|
+ while(program) {
|
||||||
|
+ if (program->pts_wrap_reference != pts_wrap_reference) {
|
||||||
|
+ for (i=0; i<program->nb_stream_indexes; i++) {
|
||||||
|
+ s->streams[program->stream_index[i]]->pts_wrap_reference = pts_wrap_reference;
|
||||||
|
+ s->streams[program->stream_index[i]]->pts_wrap_behavior = pts_wrap_behavior;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ program->pts_wrap_reference = pts_wrap_reference;
|
||||||
|
+ program->pts_wrap_behavior = pts_wrap_behavior;
|
||||||
|
+ }
|
||||||
|
+ program = av_find_program_from_stream(s, program, stream_index);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return 1;
|
||||||
|
+ }
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void update_initial_timestamps(AVFormatContext *s, int stream_index,
|
||||||
|
- int64_t dts, int64_t pts)
|
||||||
|
+ int64_t dts, int64_t pts, AVPacket *pkt)
|
||||||
|
{
|
||||||
|
AVStream *st= s->streams[stream_index];
|
||||||
|
AVPacketList *pktl= s->packet_buffer;
|
||||||
|
@@ -973,6 +1055,16 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index,
|
||||||
|
if(st->start_time == AV_NOPTS_VALUE && pktl->pkt.pts != AV_NOPTS_VALUE)
|
||||||
|
st->start_time= pktl->pkt.pts;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ if (update_wrap_reference(s, st, stream_index) && st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) {
|
||||||
|
+ // correct first time stamps to negative values
|
||||||
|
+ st->first_dts = wrap_timestamp(st, st->first_dts);
|
||||||
|
+ st->cur_dts = wrap_timestamp(st, st->cur_dts);
|
||||||
|
+ pkt->dts = wrap_timestamp(st, pkt->dts);
|
||||||
|
+ pkt->pts = wrap_timestamp(st, pkt->pts);
|
||||||
|
+ pts = wrap_timestamp(st, pts);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (st->start_time == AV_NOPTS_VALUE)
|
||||||
|
st->start_time = pts;
|
||||||
|
}
|
||||||
|
@@ -1104,7 +1196,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
|
||||||
|
/* PTS = presentation timestamp */
|
||||||
|
if (pkt->dts == AV_NOPTS_VALUE)
|
||||||
|
pkt->dts = st->last_IP_pts;
|
||||||
|
- update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts);
|
||||||
|
+ update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts, pkt);
|
||||||
|
if (pkt->dts == AV_NOPTS_VALUE)
|
||||||
|
pkt->dts = st->cur_dts;
|
||||||
|
|
||||||
|
@@ -1131,7 +1223,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
|
||||||
|
/* presentation is not delayed : PTS and DTS are the same */
|
||||||
|
if(pkt->pts == AV_NOPTS_VALUE)
|
||||||
|
pkt->pts = pkt->dts;
|
||||||
|
- update_initial_timestamps(s, pkt->stream_index, pkt->pts, pkt->pts);
|
||||||
|
+ update_initial_timestamps(s, pkt->stream_index, pkt->pts, pkt->pts, pkt);
|
||||||
|
if(pkt->pts == AV_NOPTS_VALUE)
|
||||||
|
pkt->pts = st->cur_dts;
|
||||||
|
pkt->dts = pkt->pts;
|
||||||
|
@@ -1147,7 +1239,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
|
||||||
|
if(pkt->dts == AV_NOPTS_VALUE)
|
||||||
|
pkt->dts= st->pts_buffer[0];
|
||||||
|
if(st->codec->codec_id == CODEC_ID_H264){ // we skipped it above so we try here
|
||||||
|
- update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts); // this should happen on the first packet
|
||||||
|
+ update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts, pkt); // this should happen on the first packet
|
||||||
|
}
|
||||||
|
if(pkt->dts > st->cur_dts)
|
||||||
|
st->cur_dts = pkt->dts;
|
||||||
|
@@ -1550,6 +1642,7 @@ int ff_add_index_entry(AVIndexEntry **index_entries,
|
||||||
|
int av_add_index_entry(AVStream *st,
|
||||||
|
int64_t pos, int64_t timestamp, int size, int distance, int flags)
|
||||||
|
{
|
||||||
|
+ timestamp = wrap_timestamp(st, timestamp);
|
||||||
|
return ff_add_index_entry(&st->index_entries, &st->nb_index_entries,
|
||||||
|
&st->index_entries_allocated_size, pos,
|
||||||
|
timestamp, size, distance, flags);
|
||||||
|
@@ -1602,6 +1695,12 @@ int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+static int64_t ff_read_timestamp(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit,
|
||||||
|
+ int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t ))
|
||||||
|
+{
|
||||||
|
+ return wrap_timestamp(s->streams[stream_index], read_timestamp(s, stream_index, ppos, pos_limit));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags)
|
||||||
|
{
|
||||||
|
AVInputFormat *avif= s->iformat;
|
||||||
|
@@ -1689,7 +1788,7 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
|
||||||
|
|
||||||
|
if(ts_min == AV_NOPTS_VALUE){
|
||||||
|
pos_min = s->data_offset;
|
||||||
|
- ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
|
||||||
|
+ ts_min = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp);
|
||||||
|
if (ts_min == AV_NOPTS_VALUE)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
@@ -1705,7 +1804,7 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
|
||||||
|
pos_max = filesize - 1;
|
||||||
|
do{
|
||||||
|
pos_max -= step;
|
||||||
|
- ts_max = read_timestamp(s, stream_index, &pos_max, pos_max + step);
|
||||||
|
+ ts_max = ff_read_timestamp(s, stream_index, &pos_max, pos_max + step, read_timestamp);
|
||||||
|
step += step;
|
||||||
|
}while(ts_max == AV_NOPTS_VALUE && pos_max >= step);
|
||||||
|
if (ts_max == AV_NOPTS_VALUE)
|
||||||
|
@@ -1713,7 +1812,7 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
int64_t tmp_pos= pos_max + 1;
|
||||||
|
- int64_t tmp_ts= read_timestamp(s, stream_index, &tmp_pos, INT64_MAX);
|
||||||
|
+ int64_t tmp_ts= ff_read_timestamp(s, stream_index, &tmp_pos, INT64_MAX, read_timestamp);
|
||||||
|
if(tmp_ts == AV_NOPTS_VALUE)
|
||||||
|
break;
|
||||||
|
ts_max= tmp_ts;
|
||||||
|
@@ -1760,7 +1859,7 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
|
||||||
|
pos= pos_limit;
|
||||||
|
start_pos= pos;
|
||||||
|
|
||||||
|
- ts = read_timestamp(s, stream_index, &pos, INT64_MAX); //may pass pos_limit instead of -1
|
||||||
|
+ ts = ff_read_timestamp(s, stream_index, &pos, INT64_MAX, read_timestamp); //may pass pos_limit instead of -1
|
||||||
|
if(pos == pos_max)
|
||||||
|
no_change++;
|
||||||
|
else
|
||||||
|
@@ -1788,9 +1887,9 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
|
||||||
|
ts = (flags & AVSEEK_FLAG_BACKWARD) ? ts_min : ts_max;
|
||||||
|
#if 0
|
||||||
|
pos_min = pos;
|
||||||
|
- ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
|
||||||
|
+ ts_min = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp);
|
||||||
|
pos_min++;
|
||||||
|
- ts_max = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
|
||||||
|
+ ts_max = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp);
|
||||||
|
av_dlog(s, "pos=0x%"PRIx64" %"PRId64"<=%"PRId64"<=%"PRId64"\n",
|
||||||
|
pos, ts_min, target_ts, ts_max);
|
||||||
|
#endif
|
||||||
|
@@ -2992,6 +3091,8 @@ AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c)
|
||||||
|
st->cur_dts = 0;
|
||||||
|
st->first_dts = AV_NOPTS_VALUE;
|
||||||
|
st->probe_packets = MAX_PROBE_PACKETS;
|
||||||
|
+ st->pts_wrap_reference = AV_NOPTS_VALUE;
|
||||||
|
+ st->pts_wrap_behavior = AV_PTS_WRAP_IGNORE;
|
||||||
|
|
||||||
|
/* default pts setting is MPEG-like */
|
||||||
|
avpriv_set_pts_info(st, 33, 1, 90000);
|
||||||
|
@@ -3025,6 +3126,8 @@ AVProgram *av_new_program(AVFormatContext *ac, int id)
|
||||||
|
program->discard = AVDISCARD_NONE;
|
||||||
|
}
|
||||||
|
program->id = id;
|
||||||
|
+ program->pts_wrap_reference = AV_NOPTS_VALUE;
|
||||||
|
+ program->pts_wrap_behavior = AV_PTS_WRAP_IGNORE;
|
||||||
|
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
--
|
||||||
|
1.7.10
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user