comparison mpeg.c @ 355:46029c682234 libavformat

seeking stuff adaptively change middle position selection algo for seeking, this avoids some ugly worstcases of the interpolated variant avoid backward search for mpeg where possible, its 17 times slower then forward according to my benchmark
author michael
date Sat, 17 Jan 2004 20:26:44 +0000
parents 6770ca07abe2
children 72c7cf2f3a7a
comparison
equal deleted inserted replaced
354:6770ca07abe2 355:46029c682234
1035 } 1035 }
1036 1036
1037 static int mpegps_read_seek(AVFormatContext *s, 1037 static int mpegps_read_seek(AVFormatContext *s,
1038 int stream_index, int64_t timestamp) 1038 int stream_index, int64_t timestamp)
1039 { 1039 {
1040 int64_t pos_min, pos_max, pos; 1040 int64_t pos_min, pos_max, pos, pos_limit;
1041 int64_t dts_min, dts_max, dts; 1041 int64_t dts_min, dts_max, dts;
1042 int index; 1042 int index, no_change;
1043 AVStream *st; 1043 AVStream *st;
1044 1044
1045 timestamp = (timestamp * 90000) / AV_TIME_BASE; 1045 timestamp = (timestamp * 90000) / AV_TIME_BASE;
1046 1046
1047 #ifdef DEBUG_SEEK 1047 #ifdef DEBUG_SEEK
1055 return -1; 1055 return -1;
1056 } 1056 }
1057 1057
1058 dts_max= 1058 dts_max=
1059 dts_min= AV_NOPTS_VALUE; 1059 dts_min= AV_NOPTS_VALUE;
1060 pos_limit= -1; //gcc falsely says it may be uninitalized
1060 1061
1061 st= s->streams[stream_index]; 1062 st= s->streams[stream_index];
1062 if(st->index_entries){ 1063 if(st->index_entries){
1063 AVIndexEntry *e; 1064 AVIndexEntry *e;
1064 1065
1078 if(index < st->nb_index_entries){ 1079 if(index < st->nb_index_entries){
1079 e= &st->index_entries[index]; 1080 e= &st->index_entries[index];
1080 assert(e->timestamp >= timestamp); 1081 assert(e->timestamp >= timestamp);
1081 pos_max= e->pos; 1082 pos_max= e->pos;
1082 dts_max= e->timestamp; 1083 dts_max= e->timestamp;
1084 pos_limit= pos_max - e->min_distance;
1083 #ifdef DEBUG_SEEK 1085 #ifdef DEBUG_SEEK
1084 printf("unsing cached pos_max=0x%llx dts_max=%0.3f\n", 1086 printf("unsing cached pos_max=0x%llx dts_max=%0.3f\n",
1085 pos_max,dts_max / 90000.0); 1087 pos_max,dts_max / 90000.0);
1086 #endif 1088 #endif
1087 } 1089 }
1097 } 1099 }
1098 } 1100 }
1099 if(dts_max == AV_NOPTS_VALUE){ 1101 if(dts_max == AV_NOPTS_VALUE){
1100 pos_max = url_filesize(url_fileno(&s->pb)) - 1; 1102 pos_max = url_filesize(url_fileno(&s->pb)) - 1;
1101 dts_max = mpegps_read_dts(s, stream_index, &pos_max, 0); 1103 dts_max = mpegps_read_dts(s, stream_index, &pos_max, 0);
1102 } 1104 pos_limit= pos_max;
1103 1105 }
1104 while (pos_min <= pos_max) { 1106
1107 no_change=0;
1108 while (pos_min < pos_limit) {
1105 #ifdef DEBUG_SEEK 1109 #ifdef DEBUG_SEEK
1106 printf("pos_min=0x%llx pos_max=0x%llx dts_min=%0.3f dts_max=%0.3f\n", 1110 printf("pos_min=0x%llx pos_max=0x%llx dts_min=%0.3f dts_max=%0.3f\n",
1107 pos_min, pos_max, 1111 pos_min, pos_max,
1108 dts_min / 90000.0, dts_max / 90000.0); 1112 dts_min / 90000.0, dts_max / 90000.0);
1109 #endif 1113 #endif
1110 if (timestamp <= dts_min) { 1114 int64_t start_pos;
1111 pos = pos_min; 1115 assert(pos_limit <= pos_max);
1112 goto found; 1116
1113 } else if (timestamp >= dts_max) { 1117 if(no_change==0){
1114 pos = pos_max; 1118 int64_t approximate_keyframe_distance= pos_max - pos_limit;
1115 goto found; 1119 // interpolate position (better than dichotomy)
1120 pos = (int64_t)((double)(pos_max - pos_min) *
1121 (double)(timestamp - dts_min) /
1122 (double)(dts_max - dts_min)) + pos_min - approximate_keyframe_distance;
1123 }else if(no_change==1){
1124 // bisection, if interpolation failed to change min or max pos last time
1125 pos = (pos_min + pos_limit)>>1;
1126 }else{
1127 // linear search if bisection failed, can only happen if there are very few or no keframes between min/max
1128 pos=pos_min;
1129 }
1130 if(pos <= pos_min)
1131 pos= pos_min + 1;
1132 else if(pos > pos_limit)
1133 pos= pos_limit;
1134 start_pos= pos;
1135
1136 // read the next timestamp
1137 dts = mpegps_read_dts(s, stream_index, &pos, 1);
1138 if(pos == pos_max)
1139 no_change++;
1140 else
1141 no_change=0;
1142 #ifdef DEBUG_SEEK
1143 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);
1144 #endif
1145 assert(dts != AV_NOPTS_VALUE);
1146 if (timestamp < dts) {
1147 pos_limit = start_pos - 1;
1148 pos_max = pos;
1149 dts_max = dts;
1116 } else { 1150 } else {
1117 /* interpolate position (better than dichotomy) */ 1151 pos_min = pos;
1118 pos = (int64_t)((double)(pos_max - pos_min) * 1152 dts_min = dts;
1119 (double)(timestamp - dts_min) / 1153 /* check if we are lucky */
1120 (double)(dts_max - dts_min)) + pos_min; 1154 if (timestamp == dts)
1121 }
1122 #ifdef DEBUG_SEEK
1123 printf("pos=0x%llx\n", pos);
1124 #endif
1125 /* read the next timestamp */
1126 dts = mpegps_read_dts(s, stream_index, &pos, 1);
1127 /* check if we are lucky */
1128 if (dts == AV_NOPTS_VALUE) {
1129 /* should never happen */
1130 pos = pos_min;
1131 goto found;
1132 } else if (timestamp == dts) {
1133 goto found;
1134 } else if (timestamp < dts) {
1135 pos_max = pos;
1136 dts_max = mpegps_read_dts(s, stream_index, &pos_max, 0);
1137 if (dts_max == AV_NOPTS_VALUE) {
1138 /* should never happen */
1139 break; 1155 break;
1140 } else if (timestamp >= dts_max) { 1156 }
1141 pos = pos_max; 1157 }
1142 goto found; 1158
1143 }
1144 } else {
1145 pos_min = pos + 1;
1146 dts_min = mpegps_read_dts(s, stream_index, &pos_min, 1);
1147 if (dts_min == AV_NOPTS_VALUE) {
1148 /* should never happen */
1149 goto found;
1150 } else if (timestamp <= dts_min) {
1151 goto found;
1152 }
1153 }
1154 }
1155 pos = pos_min; 1159 pos = pos_min;
1156 found:
1157 #ifdef DEBUG_SEEK 1160 #ifdef DEBUG_SEEK
1158 pos_min = pos; 1161 pos_min = pos;
1159 dts_min = mpegps_read_dts(s, stream_index, &pos_min, 1); 1162 dts_min = mpegps_read_dts(s, stream_index, &pos_min, 1);
1160 pos_min++; 1163 pos_min++;
1161 dts_max = mpegps_read_dts(s, stream_index, &pos_min, 1); 1164 dts_max = mpegps_read_dts(s, stream_index, &pos_min, 1);