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:
Michael Niedermayer
2004-04-12 16:50:03 +00:00
parent ee77723580
commit 8d14a25c3e
5 changed files with 198 additions and 413 deletions

View File

@@ -1076,12 +1076,12 @@ static int find_prev_start_code(ByteIOContext *pb, int *size_ptr)
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.
*/
static int mpegps_read_pes_header(AVFormatContext *s,
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;
int len, size, startcode, c, flags, header_len;
@@ -1089,18 +1089,10 @@ static int mpegps_read_pes_header(AVFormatContext *s,
last_pos = -1;
redo:
if (find_next) {
/* next start code (should be immediately after) */
m->header_state = 0xff;
size = MAX_SYNC_SIZE;
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));
if (startcode < 0)
return -EIO;
@@ -1205,7 +1197,7 @@ static int mpegps_read_pes_header(AVFormatContext *s,
int i;
for(i=0; i<s->nb_streams; i++){
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
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)
return len;
@@ -1295,7 +1287,7 @@ static int mpegps_read_close(AVFormatContext *s)
}
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;
int64_t pos, pts, dts;
@@ -1306,7 +1298,7 @@ static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index,
#endif
url_fseek(&s->pb, pos, SEEK_SET);
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) {
#ifdef DEBUG_SEEK
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) {
break;
}
if (find_next) {
url_fskip(&s->pb, len);
} else {
url_fseek(&s->pb, pos, SEEK_SET);
}
url_fskip(&s->pb, len);
}
#ifdef DEBUG_SEEK
printf("pos=0x%llx dts=0x%llx %0.3f\n", pos, dts, dts / 90000.0);
#endif
*ppos = pos;
return dts;
}
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;
return dts*AV_TIME_BASE/90000;
}
#ifdef CONFIG_ENCODERS
@@ -1532,7 +1384,8 @@ AVInputFormat mpegps_demux = {
mpegps_read_header,
mpegps_read_packet,
mpegps_read_close,
mpegps_read_seek,
NULL, //mpegps_read_seek,
mpegps_read_dts,
};
int mpegps_init(void)