|
|
|
@ -28,6 +28,7 @@ |
|
|
|
|
#include "avformat.h" |
|
|
|
|
#include "mpegts.h" |
|
|
|
|
#include "internal.h" |
|
|
|
|
#include "seek.h" |
|
|
|
|
|
|
|
|
|
/* 1.0 second at 24Mbit/s */ |
|
|
|
|
#define MAX_SCAN_PACKETS 32000 |
|
|
|
@ -1521,29 +1522,81 @@ static int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index, |
|
|
|
|
return timestamp; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){ |
|
|
|
|
MpegTSContext *ts = s->priv_data; |
|
|
|
|
uint8_t buf[TS_PACKET_SIZE]; |
|
|
|
|
static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags); |
|
|
|
|
|
|
|
|
|
static int read_seek2(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t target_ts, int64_t max_ts, int flags) |
|
|
|
|
{ |
|
|
|
|
int64_t pos; |
|
|
|
|
|
|
|
|
|
if(av_seek_frame_binary(s, stream_index, target_ts, flags) < 0) |
|
|
|
|
return -1; |
|
|
|
|
int64_t ts_ret, ts_adj; |
|
|
|
|
int stream_index_gen_search; |
|
|
|
|
AVStream *st; |
|
|
|
|
AVParserState *backup; |
|
|
|
|
|
|
|
|
|
pos= url_ftell(s->pb); |
|
|
|
|
backup = ff_store_parser_state(s); |
|
|
|
|
|
|
|
|
|
for(;;) { |
|
|
|
|
url_fseek(s->pb, pos, SEEK_SET); |
|
|
|
|
if (get_buffer(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE) |
|
|
|
|
// detect direction of seeking for search purposes
|
|
|
|
|
flags |= (target_ts - min_ts > (uint64_t)(max_ts - target_ts)) ? AVSEEK_FLAG_BACKWARD : 0; |
|
|
|
|
|
|
|
|
|
if (flags & AVSEEK_FLAG_BYTE) { |
|
|
|
|
/* use position directly, we will search starting from it */ |
|
|
|
|
pos = target_ts; |
|
|
|
|
} else { |
|
|
|
|
/* search for some position with good timestamp match */ |
|
|
|
|
if(stream_index < 0){ |
|
|
|
|
stream_index_gen_search = av_find_default_stream_index(s); |
|
|
|
|
if (stream_index_gen_search < 0) { |
|
|
|
|
ff_restore_parser_state(s, backup); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
st = s->streams[stream_index_gen_search]; |
|
|
|
|
/* timestamp for default must be expressed in AV_TIME_BASE units */ |
|
|
|
|
ts_adj = av_rescale(target_ts, st->time_base.den, AV_TIME_BASE * (int64_t)st->time_base.num); |
|
|
|
|
} else { |
|
|
|
|
ts_adj = target_ts; |
|
|
|
|
stream_index_gen_search = stream_index; |
|
|
|
|
} |
|
|
|
|
pos = av_gen_search(s, stream_index_gen_search, ts_adj, |
|
|
|
|
0, INT64_MAX, -1, |
|
|
|
|
AV_NOPTS_VALUE, |
|
|
|
|
AV_NOPTS_VALUE, |
|
|
|
|
flags, &ts_ret, mpegts_get_pcr); |
|
|
|
|
if (pos < 0) { |
|
|
|
|
ff_restore_parser_state(s, backup); |
|
|
|
|
return -1; |
|
|
|
|
// pid = AV_RB16(buf + 1) & 0x1fff;
|
|
|
|
|
if(buf[1] & 0x40) break; |
|
|
|
|
pos += ts->raw_packet_size; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
url_fseek(s->pb, pos, SEEK_SET); |
|
|
|
|
|
|
|
|
|
/* search for actual matching keyframe/starting position for all streams */ |
|
|
|
|
if (ff_gen_syncpoint_search(s, stream_index, pos, min_ts, target_ts, max_ts, flags) < 0) { |
|
|
|
|
ff_restore_parser_state(s, backup); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ff_free_parser_state(s, backup); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags) |
|
|
|
|
{ |
|
|
|
|
int ret; |
|
|
|
|
if (flags & AVSEEK_FLAG_BACKWARD) { |
|
|
|
|
ret = read_seek2(s, stream_index, INT64_MIN, target_ts, target_ts, flags & ~AVSEEK_FLAG_BACKWARD); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
// for compatibility reasons, seek to best-fitting timestamp
|
|
|
|
|
ret = read_seek2(s, stream_index, INT64_MIN, target_ts, INT64_MAX, flags & ~AVSEEK_FLAG_BACKWARD); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
ret = read_seek2(s, stream_index, target_ts, target_ts, INT64_MAX, flags); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
// for compatibility reasons, seek to best-fitting timestamp
|
|
|
|
|
ret = read_seek2(s, stream_index, INT64_MIN, target_ts, INT64_MAX, flags); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**************************************************************/ |
|
|
|
|
/* parsing functions - called from other demuxers such as RTP */ |
|
|
|
|
|
|
|
|
@ -1608,6 +1661,7 @@ AVInputFormat mpegts_demuxer = { |
|
|
|
|
read_seek, |
|
|
|
|
mpegts_get_pcr, |
|
|
|
|
.flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT, |
|
|
|
|
.read_seek2 = read_seek2, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
AVInputFormat mpegtsraw_demuxer = { |
|
|
|
@ -1621,4 +1675,5 @@ AVInputFormat mpegtsraw_demuxer = { |
|
|
|
|
read_seek, |
|
|
|
|
mpegts_get_pcr, |
|
|
|
|
.flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT, |
|
|
|
|
.read_seek2 = read_seek2, |
|
|
|
|
}; |
|
|
|
|