mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
moving nearly identical binary search code from nut/mpeg/asf to utils.c
Originally committed as revision 3003 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
ee77723580
commit
8d14a25c3e
@ -422,6 +422,8 @@ static int asf_get_packet(AVFormatContext *s)
|
|||||||
int rsize = 9;
|
int rsize = 9;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
if((url_ftell(&s->pb) - s->data_offset) % asf->packet_size)
|
||||||
|
return -1;
|
||||||
assert((url_ftell(&s->pb) - s->data_offset) % asf->packet_size == 0);
|
assert((url_ftell(&s->pb) - s->data_offset) % asf->packet_size == 0);
|
||||||
|
|
||||||
c = get_byte(pb);
|
c = get_byte(pb);
|
||||||
@ -705,7 +707,7 @@ static void asf_reset_header(AVFormatContext *s)
|
|||||||
asf->asf_st= NULL;
|
asf->asf_st= NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t asf_read_pts(AVFormatContext *s, int64_t *ppos, int stream_index)
|
static int64_t asf_read_pts(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit)
|
||||||
{
|
{
|
||||||
ASFContext *asf = s->priv_data;
|
ASFContext *asf = s->priv_data;
|
||||||
AVPacket pkt1, *pkt = &pkt1;
|
AVPacket pkt1, *pkt = &pkt1;
|
||||||
@ -718,15 +720,19 @@ static int64_t asf_read_pts(AVFormatContext *s, int64_t *ppos, int stream_index)
|
|||||||
for(i=0; i<s->nb_streams; i++){
|
for(i=0; i<s->nb_streams; i++){
|
||||||
start_pos[i]= pos;
|
start_pos[i]= pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pos= (pos+asf->packet_size-1-s->data_offset)/asf->packet_size*asf->packet_size+ s->data_offset;
|
||||||
|
*ppos= pos;
|
||||||
|
url_fseek(&s->pb, pos, SEEK_SET);
|
||||||
|
|
||||||
//printf("asf_read_pts\n");
|
//printf("asf_read_pts\n");
|
||||||
url_fseek(&s->pb, pos*asf->packet_size + s->data_offset, SEEK_SET);
|
|
||||||
asf_reset_header(s);
|
asf_reset_header(s);
|
||||||
for(;;){
|
for(;;){
|
||||||
if (av_read_frame(s, pkt) < 0){
|
if (av_read_frame(s, pkt) < 0){
|
||||||
av_log(s, AV_LOG_INFO, "seek failed\n");
|
av_log(s, AV_LOG_INFO, "seek failed\n");
|
||||||
return AV_NOPTS_VALUE;
|
return AV_NOPTS_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pts= pkt->pts;
|
pts= pkt->pts;
|
||||||
|
|
||||||
av_free_packet(pkt);
|
av_free_packet(pkt);
|
||||||
@ -736,10 +742,10 @@ static int64_t asf_read_pts(AVFormatContext *s, int64_t *ppos, int stream_index)
|
|||||||
asf_st= s->streams[i]->priv_data;
|
asf_st= s->streams[i]->priv_data;
|
||||||
|
|
||||||
assert((asf_st->packet_pos - s->data_offset) % asf->packet_size == 0);
|
assert((asf_st->packet_pos - s->data_offset) % asf->packet_size == 0);
|
||||||
pos= (asf_st->packet_pos - s->data_offset) / asf->packet_size;
|
pos= asf_st->packet_pos;
|
||||||
|
|
||||||
av_add_index_entry(s->streams[i], pos, pts, pos - start_pos[i] + 1, AVINDEX_KEYFRAME);
|
av_add_index_entry(s->streams[i], pos, pts, pos - start_pos[i] + 1, AVINDEX_KEYFRAME);
|
||||||
start_pos[i]= pos + 1;
|
start_pos[i]= asf_st->packet_pos + 1;
|
||||||
|
|
||||||
if(pkt->stream_index == stream_index)
|
if(pkt->stream_index == stream_index)
|
||||||
break;
|
break;
|
||||||
@ -755,112 +761,13 @@ static int64_t asf_read_pts(AVFormatContext *s, int64_t *ppos, int stream_index)
|
|||||||
static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts)
|
static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts)
|
||||||
{
|
{
|
||||||
ASFContext *asf = s->priv_data;
|
ASFContext *asf = s->priv_data;
|
||||||
AVStream *st;
|
|
||||||
int64_t pos;
|
|
||||||
int64_t pos_min, pos_max, pts_min, pts_max, cur_pts, pos_limit;
|
|
||||||
int no_change;
|
|
||||||
|
|
||||||
if (stream_index == -1)
|
|
||||||
stream_index= av_find_default_stream_index(s);
|
|
||||||
|
|
||||||
if (asf->packet_size <= 0)
|
if (asf->packet_size <= 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
pts_max=
|
if(av_seek_frame_binary(s, stream_index, pts)<0)
|
||||||
pts_min= AV_NOPTS_VALUE;
|
return -1;
|
||||||
pos_max= pos_limit= -1; // gcc thinks its uninitalized
|
|
||||||
|
|
||||||
st= s->streams[stream_index];
|
|
||||||
if(st->index_entries){
|
|
||||||
AVIndexEntry *e;
|
|
||||||
int index;
|
|
||||||
|
|
||||||
index= av_index_search_timestamp(st, pts);
|
|
||||||
e= &st->index_entries[index];
|
|
||||||
if(e->timestamp <= pts){
|
|
||||||
pos_min= e->pos;
|
|
||||||
pts_min= e->timestamp;
|
|
||||||
#ifdef DEBUG_SEEK
|
|
||||||
printf("unsing cached pos_min=0x%llx dts_min=%0.3f\n",
|
|
||||||
pos_min,pts_min / 90000.0);
|
|
||||||
#endif
|
|
||||||
}else{
|
|
||||||
assert(index==0);
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
if(index < st->nb_index_entries){
|
|
||||||
e= &st->index_entries[index];
|
|
||||||
assert(e->timestamp >= pts);
|
|
||||||
pos_max= e->pos;
|
|
||||||
pts_max= e->timestamp;
|
|
||||||
pos_limit= pos_max - e->min_distance;
|
|
||||||
#ifdef DEBUG_SEEK
|
|
||||||
printf("unsing cached pos_max=0x%llx dts_max=%0.3f\n",
|
|
||||||
pos_max,pts_max / 90000.0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pts_min == AV_NOPTS_VALUE){
|
|
||||||
pos_min = 0;
|
|
||||||
pts_min = asf_read_pts(s, &pos_min, stream_index);
|
|
||||||
if (pts_min == AV_NOPTS_VALUE) return -1;
|
|
||||||
}
|
|
||||||
if(pts_max == AV_NOPTS_VALUE){
|
|
||||||
pos_max = (url_filesize(url_fileno(&s->pb)) - 1 - s->data_offset) / asf->packet_size; //FIXME wrong
|
|
||||||
pts_max = s->duration; //FIXME wrong
|
|
||||||
pos_limit= pos_max;
|
|
||||||
}
|
|
||||||
|
|
||||||
no_change=0;
|
|
||||||
while (pos_min < pos_limit) {
|
|
||||||
int64_t start_pos;
|
|
||||||
assert(pos_limit <= pos_max);
|
|
||||||
|
|
||||||
if(no_change==0){
|
|
||||||
int64_t approximate_keyframe_distance= pos_max - pos_limit;
|
|
||||||
// interpolate position (better than dichotomy)
|
|
||||||
pos = (int64_t)((double)(pos_max - pos_min) *
|
|
||||||
(double)(pts - pts_min) /
|
|
||||||
(double)(pts_max - pts_min)) + pos_min - approximate_keyframe_distance;
|
|
||||||
}else if(no_change==1){
|
|
||||||
// bisection, if interpolation failed to change min or max pos last time
|
|
||||||
pos = (pos_min + pos_limit)>>1;
|
|
||||||
}else{
|
|
||||||
// linear search if bisection failed, can only happen if there are very few or no keyframes between min/max
|
|
||||||
pos=pos_min;
|
|
||||||
}
|
|
||||||
if(pos <= pos_min)
|
|
||||||
pos= pos_min + 1;
|
|
||||||
else if(pos > pos_limit)
|
|
||||||
pos= pos_limit;
|
|
||||||
start_pos= pos;
|
|
||||||
|
|
||||||
// read the next timestamp
|
|
||||||
cur_pts = asf_read_pts(s, &pos, stream_index);
|
|
||||||
if(pos == pos_max)
|
|
||||||
no_change++;
|
|
||||||
else
|
|
||||||
no_change=0;
|
|
||||||
|
|
||||||
#ifdef DEBUG_SEEK
|
|
||||||
printf("%Ld %Ld %Ld / %Ld %Ld %Ld target:%Ld limit:%Ld start:%Ld\n", pos_min, pos, pos_max, pts_min, cur_pts, pts_max, pts, pos_limit, start_pos);
|
|
||||||
#endif
|
|
||||||
assert (cur_pts != AV_NOPTS_VALUE);
|
|
||||||
if (pts < cur_pts) {
|
|
||||||
pos_limit = start_pos - 1;
|
|
||||||
pos_max = pos;
|
|
||||||
pts_max = cur_pts;
|
|
||||||
} else {
|
|
||||||
pos_min = pos;
|
|
||||||
pts_min = cur_pts;
|
|
||||||
/* check if we are lucky */
|
|
||||||
if (pts == cur_pts)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pos = pos_min;
|
|
||||||
url_fseek(&s->pb, pos*asf->packet_size + s->data_offset, SEEK_SET);
|
|
||||||
asf_reset_header(s);
|
asf_reset_header(s);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -874,6 +781,7 @@ static AVInputFormat asf_iformat = {
|
|||||||
asf_read_packet,
|
asf_read_packet,
|
||||||
asf_read_close,
|
asf_read_close,
|
||||||
asf_read_seek,
|
asf_read_seek,
|
||||||
|
asf_read_pts,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_ENCODERS
|
#ifdef CONFIG_ENCODERS
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LIBAVFORMAT_BUILD 4611
|
#define LIBAVFORMAT_BUILD 4612
|
||||||
|
|
||||||
#define LIBAVFORMAT_VERSION_INT FFMPEG_VERSION_INT
|
#define LIBAVFORMAT_VERSION_INT FFMPEG_VERSION_INT
|
||||||
#define LIBAVFORMAT_VERSION FFMPEG_VERSION
|
#define LIBAVFORMAT_VERSION FFMPEG_VERSION
|
||||||
@ -167,6 +167,11 @@ typedef struct AVInputFormat {
|
|||||||
units) relative to the frames in stream component stream_index */
|
units) relative to the frames in stream component stream_index */
|
||||||
int (*read_seek)(struct AVFormatContext *,
|
int (*read_seek)(struct AVFormatContext *,
|
||||||
int stream_index, int64_t timestamp);
|
int stream_index, int64_t timestamp);
|
||||||
|
/**
|
||||||
|
* gets the next timestamp in AV_TIME_BASE units.
|
||||||
|
*/
|
||||||
|
int64_t (*read_timestamp)(struct AVFormatContext *s, int stream_index,
|
||||||
|
int64_t *pos, int64_t pos_limit);
|
||||||
/* can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER */
|
/* can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER */
|
||||||
int flags;
|
int flags;
|
||||||
/* if extensions are defined, then no probe is done. You should
|
/* if extensions are defined, then no probe is done. You should
|
||||||
@ -555,6 +560,7 @@ int av_find_default_stream_index(AVFormatContext *s);
|
|||||||
int av_index_search_timestamp(AVStream *st, int timestamp);
|
int av_index_search_timestamp(AVStream *st, int timestamp);
|
||||||
int av_add_index_entry(AVStream *st,
|
int av_add_index_entry(AVStream *st,
|
||||||
int64_t pos, int64_t timestamp, int distance, int flags);
|
int64_t pos, int64_t timestamp, int distance, int flags);
|
||||||
|
int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts);
|
||||||
|
|
||||||
/* media file output */
|
/* media file output */
|
||||||
int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap);
|
int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap);
|
||||||
|
@ -1076,12 +1076,12 @@ static int find_prev_start_code(ByteIOContext *pb, int *size_ptr)
|
|||||||
return start_code;
|
return start_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read the next (or previous) PES header. Return its position in ppos
|
/* read the next PES header. Return its position in ppos
|
||||||
(if not NULL), and its start code, pts and dts.
|
(if not NULL), and its start code, pts and dts.
|
||||||
*/
|
*/
|
||||||
static int mpegps_read_pes_header(AVFormatContext *s,
|
static int mpegps_read_pes_header(AVFormatContext *s,
|
||||||
int64_t *ppos, int *pstart_code,
|
int64_t *ppos, int *pstart_code,
|
||||||
int64_t *ppts, int64_t *pdts, int find_next)
|
int64_t *ppts, int64_t *pdts)
|
||||||
{
|
{
|
||||||
MpegDemuxContext *m = s->priv_data;
|
MpegDemuxContext *m = s->priv_data;
|
||||||
int len, size, startcode, c, flags, header_len;
|
int len, size, startcode, c, flags, header_len;
|
||||||
@ -1089,18 +1089,10 @@ static int mpegps_read_pes_header(AVFormatContext *s,
|
|||||||
|
|
||||||
last_pos = -1;
|
last_pos = -1;
|
||||||
redo:
|
redo:
|
||||||
if (find_next) {
|
|
||||||
/* next start code (should be immediately after) */
|
/* next start code (should be immediately after) */
|
||||||
m->header_state = 0xff;
|
m->header_state = 0xff;
|
||||||
size = MAX_SYNC_SIZE;
|
size = MAX_SYNC_SIZE;
|
||||||
startcode = find_next_start_code(&s->pb, &size, &m->header_state);
|
startcode = find_next_start_code(&s->pb, &size, &m->header_state);
|
||||||
} else {
|
|
||||||
if (last_pos >= 0)
|
|
||||||
url_fseek(&s->pb, last_pos, SEEK_SET);
|
|
||||||
size = MAX_SYNC_SIZE;
|
|
||||||
startcode = find_prev_start_code(&s->pb, &size);
|
|
||||||
last_pos = url_ftell(&s->pb) - 4;
|
|
||||||
}
|
|
||||||
//printf("startcode=%x pos=0x%Lx\n", startcode, url_ftell(&s->pb));
|
//printf("startcode=%x pos=0x%Lx\n", startcode, url_ftell(&s->pb));
|
||||||
if (startcode < 0)
|
if (startcode < 0)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
@ -1205,7 +1197,7 @@ static int mpegps_read_pes_header(AVFormatContext *s,
|
|||||||
int i;
|
int i;
|
||||||
for(i=0; i<s->nb_streams; i++){
|
for(i=0; i<s->nb_streams; i++){
|
||||||
if(startcode == s->streams[i]->id) {
|
if(startcode == s->streams[i]->id) {
|
||||||
av_add_index_entry(s->streams[i], *ppos, dts, 0, 0 /* FIXME keyframe? */);
|
av_add_index_entry(s->streams[i], *ppos, dts*AV_TIME_BASE/90000, 0, 0 /* FIXME keyframe? */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1224,7 +1216,7 @@ static int mpegps_read_packet(AVFormatContext *s,
|
|||||||
int64_t pts, dts, dummy_pos; //dummy_pos is needed for the index building to work
|
int64_t pts, dts, dummy_pos; //dummy_pos is needed for the index building to work
|
||||||
|
|
||||||
redo:
|
redo:
|
||||||
len = mpegps_read_pes_header(s, &dummy_pos, &startcode, &pts, &dts, 1);
|
len = mpegps_read_pes_header(s, &dummy_pos, &startcode, &pts, &dts);
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
@ -1295,7 +1287,7 @@ static int mpegps_read_close(AVFormatContext *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index,
|
static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index,
|
||||||
int64_t *ppos, int find_next)
|
int64_t *ppos, int64_t pos_limit)
|
||||||
{
|
{
|
||||||
int len, startcode;
|
int len, startcode;
|
||||||
int64_t pos, pts, dts;
|
int64_t pos, pts, dts;
|
||||||
@ -1306,7 +1298,7 @@ static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index,
|
|||||||
#endif
|
#endif
|
||||||
url_fseek(&s->pb, pos, SEEK_SET);
|
url_fseek(&s->pb, pos, SEEK_SET);
|
||||||
for(;;) {
|
for(;;) {
|
||||||
len = mpegps_read_pes_header(s, &pos, &startcode, &pts, &dts, find_next);
|
len = mpegps_read_pes_header(s, &pos, &startcode, &pts, &dts);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
#ifdef DEBUG_SEEK
|
#ifdef DEBUG_SEEK
|
||||||
printf("none (ret=%d)\n", len);
|
printf("none (ret=%d)\n", len);
|
||||||
@ -1317,153 +1309,13 @@ static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index,
|
|||||||
dts != AV_NOPTS_VALUE) {
|
dts != AV_NOPTS_VALUE) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (find_next) {
|
url_fskip(&s->pb, len);
|
||||||
url_fskip(&s->pb, len);
|
|
||||||
} else {
|
|
||||||
url_fseek(&s->pb, pos, SEEK_SET);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_SEEK
|
#ifdef DEBUG_SEEK
|
||||||
printf("pos=0x%llx dts=0x%llx %0.3f\n", pos, dts, dts / 90000.0);
|
printf("pos=0x%llx dts=0x%llx %0.3f\n", pos, dts, dts / 90000.0);
|
||||||
#endif
|
#endif
|
||||||
*ppos = pos;
|
*ppos = pos;
|
||||||
return dts;
|
return dts*AV_TIME_BASE/90000;
|
||||||
}
|
|
||||||
|
|
||||||
static int mpegps_read_seek(AVFormatContext *s,
|
|
||||||
int stream_index, int64_t timestamp)
|
|
||||||
{
|
|
||||||
int64_t pos_min, pos_max, pos, pos_limit;
|
|
||||||
int64_t dts_min, dts_max, dts;
|
|
||||||
int index, no_change;
|
|
||||||
AVStream *st;
|
|
||||||
|
|
||||||
timestamp = (timestamp * 90000) / AV_TIME_BASE;
|
|
||||||
|
|
||||||
#ifdef DEBUG_SEEK
|
|
||||||
printf("read_seek: %d %0.3f\n", stream_index, timestamp / 90000.0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* XXX: find stream_index by looking at the first PES packet found */
|
|
||||||
if (stream_index < 0) {
|
|
||||||
stream_index = av_find_default_stream_index(s);
|
|
||||||
if (stream_index < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
dts_max=
|
|
||||||
dts_min= AV_NOPTS_VALUE;
|
|
||||||
pos_limit= -1; //gcc falsely says it may be uninitalized
|
|
||||||
|
|
||||||
st= s->streams[stream_index];
|
|
||||||
if(st->index_entries){
|
|
||||||
AVIndexEntry *e;
|
|
||||||
|
|
||||||
index= av_index_search_timestamp(st, timestamp);
|
|
||||||
e= &st->index_entries[index];
|
|
||||||
if(e->timestamp <= timestamp){
|
|
||||||
pos_min= e->pos;
|
|
||||||
dts_min= e->timestamp;
|
|
||||||
#ifdef DEBUG_SEEK
|
|
||||||
printf("unsing cached pos_min=0x%llx dts_min=%0.3f\n",
|
|
||||||
pos_min,dts_min / 90000.0);
|
|
||||||
#endif
|
|
||||||
}else{
|
|
||||||
assert(index==0);
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
if(index < st->nb_index_entries){
|
|
||||||
e= &st->index_entries[index];
|
|
||||||
assert(e->timestamp >= timestamp);
|
|
||||||
pos_max= e->pos;
|
|
||||||
dts_max= e->timestamp;
|
|
||||||
pos_limit= pos_max - e->min_distance;
|
|
||||||
#ifdef DEBUG_SEEK
|
|
||||||
printf("unsing cached pos_max=0x%llx dts_max=%0.3f\n",
|
|
||||||
pos_max,dts_max / 90000.0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(dts_min == AV_NOPTS_VALUE){
|
|
||||||
pos_min = 0;
|
|
||||||
dts_min = mpegps_read_dts(s, stream_index, &pos_min, 1);
|
|
||||||
if (dts_min == AV_NOPTS_VALUE) {
|
|
||||||
/* we can reach this case only if no PTS are present in
|
|
||||||
the whole stream */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(dts_max == AV_NOPTS_VALUE){
|
|
||||||
pos_max = url_filesize(url_fileno(&s->pb)) - 1;
|
|
||||||
dts_max = mpegps_read_dts(s, stream_index, &pos_max, 0);
|
|
||||||
pos_limit= pos_max;
|
|
||||||
}
|
|
||||||
|
|
||||||
no_change=0;
|
|
||||||
while (pos_min < pos_limit) {
|
|
||||||
#ifdef DEBUG_SEEK
|
|
||||||
printf("pos_min=0x%llx pos_max=0x%llx dts_min=%0.3f dts_max=%0.3f\n",
|
|
||||||
pos_min, pos_max,
|
|
||||||
dts_min / 90000.0, dts_max / 90000.0);
|
|
||||||
#endif
|
|
||||||
int64_t start_pos;
|
|
||||||
assert(pos_limit <= pos_max);
|
|
||||||
|
|
||||||
if(no_change==0){
|
|
||||||
int64_t approximate_keyframe_distance= pos_max - pos_limit;
|
|
||||||
// interpolate position (better than dichotomy)
|
|
||||||
pos = (int64_t)((double)(pos_max - pos_min) *
|
|
||||||
(double)(timestamp - dts_min) /
|
|
||||||
(double)(dts_max - dts_min)) + pos_min - approximate_keyframe_distance;
|
|
||||||
}else if(no_change==1){
|
|
||||||
// bisection, if interpolation failed to change min or max pos last time
|
|
||||||
pos = (pos_min + pos_limit)>>1;
|
|
||||||
}else{
|
|
||||||
// linear search if bisection failed, can only happen if there are very few or no keframes between min/max
|
|
||||||
pos=pos_min;
|
|
||||||
}
|
|
||||||
if(pos <= pos_min)
|
|
||||||
pos= pos_min + 1;
|
|
||||||
else if(pos > pos_limit)
|
|
||||||
pos= pos_limit;
|
|
||||||
start_pos= pos;
|
|
||||||
|
|
||||||
// read the next timestamp
|
|
||||||
dts = mpegps_read_dts(s, stream_index, &pos, 1);
|
|
||||||
if(pos == pos_max)
|
|
||||||
no_change++;
|
|
||||||
else
|
|
||||||
no_change=0;
|
|
||||||
#ifdef DEBUG_SEEK
|
|
||||||
printf("%Ld %Ld %Ld / %Ld %Ld %Ld target:%Ld limit:%Ld start:%Ld noc:%d\n", pos_min, pos, pos_max, dts_min, dts, dts_max, timestamp, pos_limit, start_pos, no_change);
|
|
||||||
#endif
|
|
||||||
assert(dts != AV_NOPTS_VALUE);
|
|
||||||
if (timestamp < dts) {
|
|
||||||
pos_limit = start_pos - 1;
|
|
||||||
pos_max = pos;
|
|
||||||
dts_max = dts;
|
|
||||||
} else {
|
|
||||||
pos_min = pos;
|
|
||||||
dts_min = dts;
|
|
||||||
/* check if we are lucky */
|
|
||||||
if (timestamp == dts)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = pos_min;
|
|
||||||
#ifdef DEBUG_SEEK
|
|
||||||
pos_min = pos;
|
|
||||||
dts_min = mpegps_read_dts(s, stream_index, &pos_min, 1);
|
|
||||||
pos_min++;
|
|
||||||
dts_max = mpegps_read_dts(s, stream_index, &pos_min, 1);
|
|
||||||
printf("pos=0x%llx %0.3f<=%0.3f<=%0.3f\n",
|
|
||||||
pos, dts_min / 90000.0, timestamp / 90000.0, dts_max / 90000.0);
|
|
||||||
#endif
|
|
||||||
/* do the seek */
|
|
||||||
url_fseek(&s->pb, pos, SEEK_SET);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_ENCODERS
|
#ifdef CONFIG_ENCODERS
|
||||||
@ -1532,7 +1384,8 @@ AVInputFormat mpegps_demux = {
|
|||||||
mpegps_read_header,
|
mpegps_read_header,
|
||||||
mpegps_read_packet,
|
mpegps_read_packet,
|
||||||
mpegps_read_close,
|
mpegps_read_close,
|
||||||
mpegps_read_seek,
|
NULL, //mpegps_read_seek,
|
||||||
|
mpegps_read_dts,
|
||||||
};
|
};
|
||||||
|
|
||||||
int mpegps_init(void)
|
int mpegps_init(void)
|
||||||
|
@ -1107,10 +1107,11 @@ static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code, int fram
|
|||||||
if(flags & FLAG_FULL_PTS){
|
if(flags & FLAG_FULL_PTS){
|
||||||
pts= get_v(bc);
|
pts= get_v(bc);
|
||||||
if(frame_type && key_frame){
|
if(frame_type && key_frame){
|
||||||
|
int64_t av_pts= pts * AV_TIME_BASE * stream->rate_den / stream->rate_num;
|
||||||
av_add_index_entry(
|
av_add_index_entry(
|
||||||
s->streams[stream_id],
|
s->streams[stream_id],
|
||||||
frame_start,
|
frame_start,
|
||||||
pts,
|
av_pts,
|
||||||
frame_start - nut->stream[stream_id].last_sync_pos,
|
frame_start - nut->stream[stream_id].last_sync_pos,
|
||||||
AVINDEX_KEYFRAME);
|
AVINDEX_KEYFRAME);
|
||||||
nut->stream[stream_id].last_sync_pos= frame_start;
|
nut->stream[stream_id].last_sync_pos= frame_start;
|
||||||
@ -1231,8 +1232,9 @@ av_log(s, AV_LOG_DEBUG, "steping back to %lld next %d\n", pos, size);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit){
|
static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit){
|
||||||
NUTContext *nut = s->priv_data;
|
NUTContext *nut = s->priv_data;
|
||||||
|
StreamContext *stream;
|
||||||
ByteIOContext *bc = &s->pb;
|
ByteIOContext *bc = &s->pb;
|
||||||
int64_t pos, pts;
|
int64_t pos, pts;
|
||||||
uint64_t code;
|
uint64_t code;
|
||||||
@ -1305,7 +1307,8 @@ av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%lld,%lld)\n", stream_index, *pos_a
|
|||||||
if(stream_id >= s->nb_streams)
|
if(stream_id >= s->nb_streams)
|
||||||
goto resync;
|
goto resync;
|
||||||
|
|
||||||
pts= get_v(bc);
|
stream= &nut->stream[stream_id];
|
||||||
|
pts= get_v(bc) * AV_TIME_BASE * stream->rate_den / stream->rate_num;
|
||||||
|
|
||||||
if(flags & FLAG_KEY_FRAME){
|
if(flags & FLAG_KEY_FRAME){
|
||||||
av_add_index_entry(
|
av_add_index_entry(
|
||||||
@ -1336,155 +1339,16 @@ av_log(s, AV_LOG_DEBUG, "syncing from %lld\n", nut->packet_start+1);
|
|||||||
return AV_NOPTS_VALUE;
|
return AV_NOPTS_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DEBUG_SEEK
|
|
||||||
static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts){
|
static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts){
|
||||||
NUTContext *nut = s->priv_data;
|
NUTContext *nut = s->priv_data;
|
||||||
StreamContext *stream;
|
int64_t pos;
|
||||||
int64_t pos_min, pos_max, pos, pos_limit;
|
int i;
|
||||||
int64_t ts_min, ts_max, ts;
|
|
||||||
int64_t start_pos;
|
|
||||||
int index, no_change,i;
|
|
||||||
AVStream *st;
|
|
||||||
|
|
||||||
if (stream_index < 0) {
|
if(av_seek_frame_binary(s, stream_index, target_ts) < 0)
|
||||||
stream_index = av_find_default_stream_index(s);
|
return -1;
|
||||||
if (stream_index < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
stream= &nut->stream[stream_index];
|
|
||||||
target_ts= (av_rescale(target_ts, stream->rate_num, stream->rate_den) + AV_TIME_BASE/2) / AV_TIME_BASE;
|
|
||||||
|
|
||||||
#ifdef DEBUG_SEEK
|
|
||||||
av_log(s, AV_LOG_DEBUG, "read_seek: %d %lld\n", stream_index, target_ts);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ts_max=
|
|
||||||
ts_min= AV_NOPTS_VALUE;
|
|
||||||
pos_limit= -1; //gcc falsely says it may be uninitalized
|
|
||||||
|
|
||||||
st= s->streams[stream_index];
|
|
||||||
if(st->index_entries){
|
|
||||||
AVIndexEntry *e;
|
|
||||||
|
|
||||||
index= av_index_search_timestamp(st, target_ts);
|
|
||||||
e= &st->index_entries[index];
|
|
||||||
|
|
||||||
if(e->timestamp <= target_ts || e->pos == e->min_distance){
|
|
||||||
pos_min= e->pos;
|
|
||||||
ts_min= e->timestamp;
|
|
||||||
#ifdef DEBUG_SEEK
|
|
||||||
av_log(s, AV_LOG_DEBUG, "unsing cached pos_min=0x%llx dts_min=%lld\n",
|
|
||||||
pos_min,ts_min);
|
|
||||||
#endif
|
|
||||||
}else{
|
|
||||||
assert(index==0);
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
if(index < st->nb_index_entries){
|
|
||||||
e= &st->index_entries[index];
|
|
||||||
assert(e->timestamp >= target_ts);
|
|
||||||
pos_max= e->pos;
|
|
||||||
ts_max= e->timestamp;
|
|
||||||
pos_limit= pos_max - e->min_distance;
|
|
||||||
#ifdef DEBUG_SEEK
|
|
||||||
av_log(s, AV_LOG_DEBUG, "unsing cached pos_max=0x%llx pos_limit=0x%llx dts_max=%lld\n",
|
|
||||||
pos_max,pos_limit, ts_max);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ts_min == AV_NOPTS_VALUE){
|
|
||||||
pos_min = 0;
|
|
||||||
ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
|
|
||||||
if (ts_min == AV_NOPTS_VALUE)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ts_max == AV_NOPTS_VALUE){
|
|
||||||
int step= 1024;
|
|
||||||
pos_max = url_filesize(url_fileno(&s->pb)) - 1;
|
|
||||||
do{
|
|
||||||
pos_max -= step;
|
|
||||||
ts_max = read_timestamp(s, stream_index, &pos_max, pos_max + step);
|
|
||||||
step += step;
|
|
||||||
}while(ts_max == AV_NOPTS_VALUE && pos_max >= step);
|
|
||||||
if (ts_max == AV_NOPTS_VALUE)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
for(;;){
|
|
||||||
int64_t tmp_pos= pos_max + 1;
|
|
||||||
int64_t tmp_ts= read_timestamp(s, stream_index, &tmp_pos, INT64_MAX);
|
|
||||||
if(tmp_ts == AV_NOPTS_VALUE)
|
|
||||||
break;
|
|
||||||
ts_max= tmp_ts;
|
|
||||||
pos_max= tmp_pos;
|
|
||||||
}
|
|
||||||
pos_limit= pos_max;
|
|
||||||
}
|
|
||||||
|
|
||||||
no_change=0;
|
|
||||||
while (pos_min < pos_limit) {
|
|
||||||
#ifdef DEBUG_SEEK
|
|
||||||
av_log(s, AV_LOG_DEBUG, "pos_min=0x%llx pos_max=0x%llx dts_min=%lld dts_max=%lld\n",
|
|
||||||
pos_min, pos_max,
|
|
||||||
ts_min, ts_max);
|
|
||||||
#endif
|
|
||||||
assert(pos_limit <= pos_max);
|
|
||||||
|
|
||||||
if(no_change==0){
|
|
||||||
int64_t approximate_keyframe_distance= pos_max - pos_limit;
|
|
||||||
// interpolate position (better than dichotomy)
|
|
||||||
pos = (int64_t)((double)(pos_max - pos_min) *
|
|
||||||
(double)(target_ts - ts_min) /
|
|
||||||
(double)(ts_max - ts_min)) + pos_min - approximate_keyframe_distance;
|
|
||||||
}else if(no_change==1){
|
|
||||||
// bisection, if interpolation failed to change min or max pos last time
|
|
||||||
pos = (pos_min + pos_limit)>>1;
|
|
||||||
}else{
|
|
||||||
// linear search if bisection failed, can only happen if there are very few or no keframes between min/max
|
|
||||||
pos=pos_min;
|
|
||||||
}
|
|
||||||
if(pos <= pos_min)
|
|
||||||
pos= pos_min + 1;
|
|
||||||
else if(pos > pos_limit)
|
|
||||||
pos= pos_limit;
|
|
||||||
start_pos= pos;
|
|
||||||
|
|
||||||
ts = read_timestamp(s, stream_index, &pos, INT64_MAX); //may pass pos_limit instead of -1
|
|
||||||
if(pos == pos_max)
|
|
||||||
no_change++;
|
|
||||||
else
|
|
||||||
no_change=0;
|
|
||||||
#ifdef DEBUG_SEEK
|
|
||||||
av_log(s, AV_LOG_DEBUG, "%Ld %Ld %Ld / %Ld %Ld %Ld target:%Ld limit:%Ld start:%Ld noc:%d\n", pos_min, pos, pos_max, ts_min, ts, ts_max, target_ts, pos_limit, start_pos, no_change);
|
|
||||||
#endif
|
|
||||||
assert(ts != AV_NOPTS_VALUE);
|
|
||||||
if (target_ts < ts) {
|
|
||||||
pos_limit = start_pos - 1;
|
|
||||||
pos_max = pos;
|
|
||||||
ts_max = ts;
|
|
||||||
} else {
|
|
||||||
pos_min = pos;
|
|
||||||
ts_min = ts;
|
|
||||||
/* check if we are lucky */
|
|
||||||
if (target_ts == ts)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = pos_min;
|
|
||||||
#ifdef DEBUG_SEEK
|
|
||||||
pos_min = pos;
|
|
||||||
ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
|
|
||||||
pos_min++;
|
|
||||||
ts_max = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
|
|
||||||
av_log(s, AV_LOG_DEBUG, "pos=0x%llx %lld<=%lld<=%lld\n",
|
|
||||||
pos, ts_min, target_ts, ts_max);
|
|
||||||
#endif
|
|
||||||
/* do the seek */
|
|
||||||
url_fseek(&s->pb, pos, SEEK_SET);
|
|
||||||
|
|
||||||
nut->written_packet_size= -1;
|
nut->written_packet_size= -1;
|
||||||
|
pos= url_ftell(&s->pb);
|
||||||
for(i=0; i<s->nb_streams; i++)
|
for(i=0; i<s->nb_streams; i++)
|
||||||
nut->stream[i].last_sync_pos= pos;
|
nut->stream[i].last_sync_pos= pos;
|
||||||
|
|
||||||
@ -1513,6 +1377,7 @@ static AVInputFormat nut_iformat = {
|
|||||||
nut_read_packet,
|
nut_read_packet,
|
||||||
nut_read_close,
|
nut_read_close,
|
||||||
nut_read_seek,
|
nut_read_seek,
|
||||||
|
nut_read_timestamp,
|
||||||
.extensions = "nut",
|
.extensions = "nut",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -997,6 +997,156 @@ int av_index_search_timestamp(AVStream *st, int wanted_timestamp)
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DEBUG_SEEK
|
||||||
|
|
||||||
|
int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts){
|
||||||
|
AVInputFormat *avif= s->iformat;
|
||||||
|
int64_t pos_min, pos_max, pos, pos_limit;
|
||||||
|
int64_t ts_min, ts_max, ts;
|
||||||
|
int64_t start_pos;
|
||||||
|
int index, no_change;
|
||||||
|
AVStream *st;
|
||||||
|
|
||||||
|
if (stream_index < 0) {
|
||||||
|
stream_index = av_find_default_stream_index(s);
|
||||||
|
if (stream_index < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_SEEK
|
||||||
|
av_log(s, AV_LOG_DEBUG, "read_seek: %d %lld\n", stream_index, target_ts);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ts_max=
|
||||||
|
ts_min= AV_NOPTS_VALUE;
|
||||||
|
pos_limit= -1; //gcc falsely says it may be uninitalized
|
||||||
|
|
||||||
|
st= s->streams[stream_index];
|
||||||
|
if(st->index_entries){
|
||||||
|
AVIndexEntry *e;
|
||||||
|
|
||||||
|
index= av_index_search_timestamp(st, target_ts);
|
||||||
|
e= &st->index_entries[index];
|
||||||
|
|
||||||
|
if(e->timestamp <= target_ts || e->pos == e->min_distance){
|
||||||
|
pos_min= e->pos;
|
||||||
|
ts_min= e->timestamp;
|
||||||
|
#ifdef DEBUG_SEEK
|
||||||
|
av_log(s, AV_LOG_DEBUG, "unsing cached pos_min=0x%llx dts_min=%lld\n",
|
||||||
|
pos_min,ts_min);
|
||||||
|
#endif
|
||||||
|
}else{
|
||||||
|
assert(index==0);
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
if(index < st->nb_index_entries){
|
||||||
|
e= &st->index_entries[index];
|
||||||
|
assert(e->timestamp >= target_ts);
|
||||||
|
pos_max= e->pos;
|
||||||
|
ts_max= e->timestamp;
|
||||||
|
pos_limit= pos_max - e->min_distance;
|
||||||
|
#ifdef DEBUG_SEEK
|
||||||
|
av_log(s, AV_LOG_DEBUG, "unsing cached pos_max=0x%llx pos_limit=0x%llx dts_max=%lld\n",
|
||||||
|
pos_max,pos_limit, ts_max);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ts_min == AV_NOPTS_VALUE){
|
||||||
|
pos_min = s->data_offset;
|
||||||
|
ts_min = avif->read_timestamp(s, stream_index, &pos_min, INT64_MAX);
|
||||||
|
if (ts_min == AV_NOPTS_VALUE)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ts_max == AV_NOPTS_VALUE){
|
||||||
|
int step= 1024;
|
||||||
|
pos_max = url_filesize(url_fileno(&s->pb)) - 1;
|
||||||
|
do{
|
||||||
|
pos_max -= step;
|
||||||
|
ts_max = avif->read_timestamp(s, stream_index, &pos_max, pos_max + step);
|
||||||
|
step += step;
|
||||||
|
}while(ts_max == AV_NOPTS_VALUE && pos_max >= step);
|
||||||
|
if (ts_max == AV_NOPTS_VALUE)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
int64_t tmp_pos= pos_max + 1;
|
||||||
|
int64_t tmp_ts= avif->read_timestamp(s, stream_index, &tmp_pos, INT64_MAX);
|
||||||
|
if(tmp_ts == AV_NOPTS_VALUE)
|
||||||
|
break;
|
||||||
|
ts_max= tmp_ts;
|
||||||
|
pos_max= tmp_pos;
|
||||||
|
}
|
||||||
|
pos_limit= pos_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
no_change=0;
|
||||||
|
while (pos_min < pos_limit) {
|
||||||
|
#ifdef DEBUG_SEEK
|
||||||
|
av_log(s, AV_LOG_DEBUG, "pos_min=0x%llx pos_max=0x%llx dts_min=%lld dts_max=%lld\n",
|
||||||
|
pos_min, pos_max,
|
||||||
|
ts_min, ts_max);
|
||||||
|
#endif
|
||||||
|
assert(pos_limit <= pos_max);
|
||||||
|
|
||||||
|
if(no_change==0){
|
||||||
|
int64_t approximate_keyframe_distance= pos_max - pos_limit;
|
||||||
|
// interpolate position (better than dichotomy)
|
||||||
|
pos = (int64_t)((double)(pos_max - pos_min) *
|
||||||
|
(double)(target_ts - ts_min) /
|
||||||
|
(double)(ts_max - ts_min)) + pos_min - approximate_keyframe_distance;
|
||||||
|
}else if(no_change==1){
|
||||||
|
// bisection, if interpolation failed to change min or max pos last time
|
||||||
|
pos = (pos_min + pos_limit)>>1;
|
||||||
|
}else{
|
||||||
|
// linear search if bisection failed, can only happen if there are very few or no keframes between min/max
|
||||||
|
pos=pos_min;
|
||||||
|
}
|
||||||
|
if(pos <= pos_min)
|
||||||
|
pos= pos_min + 1;
|
||||||
|
else if(pos > pos_limit)
|
||||||
|
pos= pos_limit;
|
||||||
|
start_pos= pos;
|
||||||
|
|
||||||
|
ts = avif->read_timestamp(s, stream_index, &pos, INT64_MAX); //may pass pos_limit instead of -1
|
||||||
|
if(pos == pos_max)
|
||||||
|
no_change++;
|
||||||
|
else
|
||||||
|
no_change=0;
|
||||||
|
#ifdef DEBUG_SEEK
|
||||||
|
av_log(s, AV_LOG_DEBUG, "%Ld %Ld %Ld / %Ld %Ld %Ld target:%Ld limit:%Ld start:%Ld noc:%d\n", pos_min, pos, pos_max, ts_min, ts, ts_max, target_ts, pos_limit, start_pos, no_change);
|
||||||
|
#endif
|
||||||
|
assert(ts != AV_NOPTS_VALUE);
|
||||||
|
if (target_ts < ts) {
|
||||||
|
pos_limit = start_pos - 1;
|
||||||
|
pos_max = pos;
|
||||||
|
ts_max = ts;
|
||||||
|
} else {
|
||||||
|
pos_min = pos;
|
||||||
|
ts_min = ts;
|
||||||
|
/* check if we are lucky */
|
||||||
|
if (target_ts == ts)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = pos_min;
|
||||||
|
#ifdef DEBUG_SEEK
|
||||||
|
pos_min = pos;
|
||||||
|
ts_min = avif->read_timestamp(s, stream_index, &pos_min, INT64_MAX);
|
||||||
|
pos_min++;
|
||||||
|
ts_max = avif->read_timestamp(s, stream_index, &pos_min, INT64_MAX);
|
||||||
|
av_log(s, AV_LOG_DEBUG, "pos=0x%llx %lld<=%lld<=%lld\n",
|
||||||
|
pos, ts_min, target_ts, ts_max);
|
||||||
|
#endif
|
||||||
|
/* do the seek */
|
||||||
|
url_fseek(&s->pb, pos, SEEK_SET);
|
||||||
|
st->cur_dts = ts_min;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int av_seek_frame_generic(AVFormatContext *s,
|
static int av_seek_frame_generic(AVFormatContext *s,
|
||||||
int stream_index, int64_t timestamp)
|
int stream_index, int64_t timestamp)
|
||||||
{
|
{
|
||||||
@ -1047,8 +1197,11 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp)
|
|||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return av_seek_frame_generic(s, stream_index, timestamp);
|
if(s->iformat->read_timestamp)
|
||||||
|
return av_seek_frame_binary(s, stream_index, timestamp);
|
||||||
|
else
|
||||||
|
return av_seek_frame_generic(s, stream_index, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************/
|
/*******************************************************/
|
||||||
|
Loading…
Reference in New Issue
Block a user