Mercurial > libavformat.hg
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); |