comparison nut.c @ 437:50bae308f71e libavformat

moving nearly identical binary search code from nut/mpeg/asf to utils.c
author michael
date Mon, 12 Apr 2004 16:50:03 +0000
parents 145cd93d0c86
children 6635c1e75087
comparison
equal deleted inserted replaced
436:dd042d607ec9 437:50bae308f71e
1105 1105
1106 if(flags & FLAG_PTS){ 1106 if(flags & FLAG_PTS){
1107 if(flags & FLAG_FULL_PTS){ 1107 if(flags & FLAG_FULL_PTS){
1108 pts= get_v(bc); 1108 pts= get_v(bc);
1109 if(frame_type && key_frame){ 1109 if(frame_type && key_frame){
1110 int64_t av_pts= pts * AV_TIME_BASE * stream->rate_den / stream->rate_num;
1110 av_add_index_entry( 1111 av_add_index_entry(
1111 s->streams[stream_id], 1112 s->streams[stream_id],
1112 frame_start, 1113 frame_start,
1113 pts, 1114 av_pts,
1114 frame_start - nut->stream[stream_id].last_sync_pos, 1115 frame_start - nut->stream[stream_id].last_sync_pos,
1115 AVINDEX_KEYFRAME); 1116 AVINDEX_KEYFRAME);
1116 nut->stream[stream_id].last_sync_pos= frame_start; 1117 nut->stream[stream_id].last_sync_pos= frame_start;
1117 assert(nut->packet_start == frame_start); 1118 assert(nut->packet_start == frame_start);
1118 } 1119 }
1229 nut->written_packet_size= -1; 1230 nut->written_packet_size= -1;
1230 } 1231 }
1231 } 1232 }
1232 } 1233 }
1233 1234
1234 static int64_t read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit){ 1235 static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit){
1235 NUTContext *nut = s->priv_data; 1236 NUTContext *nut = s->priv_data;
1237 StreamContext *stream;
1236 ByteIOContext *bc = &s->pb; 1238 ByteIOContext *bc = &s->pb;
1237 int64_t pos, pts; 1239 int64_t pos, pts;
1238 uint64_t code; 1240 uint64_t code;
1239 int frame_code,step, flags, stream_id, i; 1241 int frame_code,step, flags, stream_id, i;
1240 av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%lld,%lld)\n", stream_index, *pos_arg, pos_limit); 1242 av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%lld,%lld)\n", stream_index, *pos_arg, pos_limit);
1303 if(stream_id==-1) 1305 if(stream_id==-1)
1304 stream_id= get_v(bc); 1306 stream_id= get_v(bc);
1305 if(stream_id >= s->nb_streams) 1307 if(stream_id >= s->nb_streams)
1306 goto resync; 1308 goto resync;
1307 1309
1308 pts= get_v(bc); 1310 stream= &nut->stream[stream_id];
1311 pts= get_v(bc) * AV_TIME_BASE * stream->rate_den / stream->rate_num;
1309 1312
1310 if(flags & FLAG_KEY_FRAME){ 1313 if(flags & FLAG_KEY_FRAME){
1311 av_add_index_entry( 1314 av_add_index_entry(
1312 s->streams[stream_id], 1315 s->streams[stream_id],
1313 pos, 1316 pos,
1334 } 1337 }
1335 } 1338 }
1336 return AV_NOPTS_VALUE; 1339 return AV_NOPTS_VALUE;
1337 } 1340 }
1338 1341
1339 #define DEBUG_SEEK
1340 static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts){ 1342 static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts){
1341 NUTContext *nut = s->priv_data; 1343 NUTContext *nut = s->priv_data;
1342 StreamContext *stream; 1344 int64_t pos;
1343 int64_t pos_min, pos_max, pos, pos_limit; 1345 int i;
1344 int64_t ts_min, ts_max, ts; 1346
1345 int64_t start_pos; 1347 if(av_seek_frame_binary(s, stream_index, target_ts) < 0)
1346 int index, no_change,i; 1348 return -1;
1347 AVStream *st;
1348
1349 if (stream_index < 0) {
1350 stream_index = av_find_default_stream_index(s);
1351 if (stream_index < 0)
1352 return -1;
1353 }
1354 stream= &nut->stream[stream_index];
1355 target_ts= (av_rescale(target_ts, stream->rate_num, stream->rate_den) + AV_TIME_BASE/2) / AV_TIME_BASE;
1356
1357 #ifdef DEBUG_SEEK
1358 av_log(s, AV_LOG_DEBUG, "read_seek: %d %lld\n", stream_index, target_ts);
1359 #endif
1360
1361 ts_max=
1362 ts_min= AV_NOPTS_VALUE;
1363 pos_limit= -1; //gcc falsely says it may be uninitalized
1364
1365 st= s->streams[stream_index];
1366 if(st->index_entries){
1367 AVIndexEntry *e;
1368
1369 index= av_index_search_timestamp(st, target_ts);
1370 e= &st->index_entries[index];
1371
1372 if(e->timestamp <= target_ts || e->pos == e->min_distance){
1373 pos_min= e->pos;
1374 ts_min= e->timestamp;
1375 #ifdef DEBUG_SEEK
1376 av_log(s, AV_LOG_DEBUG, "unsing cached pos_min=0x%llx dts_min=%lld\n",
1377 pos_min,ts_min);
1378 #endif
1379 }else{
1380 assert(index==0);
1381 }
1382 index++;
1383 if(index < st->nb_index_entries){
1384 e= &st->index_entries[index];
1385 assert(e->timestamp >= target_ts);
1386 pos_max= e->pos;
1387 ts_max= e->timestamp;
1388 pos_limit= pos_max - e->min_distance;
1389 #ifdef DEBUG_SEEK
1390 av_log(s, AV_LOG_DEBUG, "unsing cached pos_max=0x%llx pos_limit=0x%llx dts_max=%lld\n",
1391 pos_max,pos_limit, ts_max);
1392 #endif
1393 }
1394 }
1395
1396 if(ts_min == AV_NOPTS_VALUE){
1397 pos_min = 0;
1398 ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
1399 if (ts_min == AV_NOPTS_VALUE)
1400 return -1;
1401 }
1402
1403 if(ts_max == AV_NOPTS_VALUE){
1404 int step= 1024;
1405 pos_max = url_filesize(url_fileno(&s->pb)) - 1;
1406 do{
1407 pos_max -= step;
1408 ts_max = read_timestamp(s, stream_index, &pos_max, pos_max + step);
1409 step += step;
1410 }while(ts_max == AV_NOPTS_VALUE && pos_max >= step);
1411 if (ts_max == AV_NOPTS_VALUE)
1412 return -1;
1413
1414 for(;;){
1415 int64_t tmp_pos= pos_max + 1;
1416 int64_t tmp_ts= read_timestamp(s, stream_index, &tmp_pos, INT64_MAX);
1417 if(tmp_ts == AV_NOPTS_VALUE)
1418 break;
1419 ts_max= tmp_ts;
1420 pos_max= tmp_pos;
1421 }
1422 pos_limit= pos_max;
1423 }
1424
1425 no_change=0;
1426 while (pos_min < pos_limit) {
1427 #ifdef DEBUG_SEEK
1428 av_log(s, AV_LOG_DEBUG, "pos_min=0x%llx pos_max=0x%llx dts_min=%lld dts_max=%lld\n",
1429 pos_min, pos_max,
1430 ts_min, ts_max);
1431 #endif
1432 assert(pos_limit <= pos_max);
1433
1434 if(no_change==0){
1435 int64_t approximate_keyframe_distance= pos_max - pos_limit;
1436 // interpolate position (better than dichotomy)
1437 pos = (int64_t)((double)(pos_max - pos_min) *
1438 (double)(target_ts - ts_min) /
1439 (double)(ts_max - ts_min)) + pos_min - approximate_keyframe_distance;
1440 }else if(no_change==1){
1441 // bisection, if interpolation failed to change min or max pos last time
1442 pos = (pos_min + pos_limit)>>1;
1443 }else{
1444 // linear search if bisection failed, can only happen if there are very few or no keframes between min/max
1445 pos=pos_min;
1446 }
1447 if(pos <= pos_min)
1448 pos= pos_min + 1;
1449 else if(pos > pos_limit)
1450 pos= pos_limit;
1451 start_pos= pos;
1452
1453 ts = read_timestamp(s, stream_index, &pos, INT64_MAX); //may pass pos_limit instead of -1
1454 if(pos == pos_max)
1455 no_change++;
1456 else
1457 no_change=0;
1458 #ifdef DEBUG_SEEK
1459 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);
1460 #endif
1461 assert(ts != AV_NOPTS_VALUE);
1462 if (target_ts < ts) {
1463 pos_limit = start_pos - 1;
1464 pos_max = pos;
1465 ts_max = ts;
1466 } else {
1467 pos_min = pos;
1468 ts_min = ts;
1469 /* check if we are lucky */
1470 if (target_ts == ts)
1471 break;
1472 }
1473 }
1474
1475 pos = pos_min;
1476 #ifdef DEBUG_SEEK
1477 pos_min = pos;
1478 ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
1479 pos_min++;
1480 ts_max = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
1481 av_log(s, AV_LOG_DEBUG, "pos=0x%llx %lld<=%lld<=%lld\n",
1482 pos, ts_min, target_ts, ts_max);
1483 #endif
1484 /* do the seek */
1485 url_fseek(&s->pb, pos, SEEK_SET);
1486 1349
1487 nut->written_packet_size= -1; 1350 nut->written_packet_size= -1;
1351 pos= url_ftell(&s->pb);
1488 for(i=0; i<s->nb_streams; i++) 1352 for(i=0; i<s->nb_streams; i++)
1489 nut->stream[i].last_sync_pos= pos; 1353 nut->stream[i].last_sync_pos= pos;
1490 1354
1491 return 0; 1355 return 0;
1492 } 1356 }
1511 nut_probe, 1375 nut_probe,
1512 nut_read_header, 1376 nut_read_header,
1513 nut_read_packet, 1377 nut_read_packet,
1514 nut_read_close, 1378 nut_read_close,
1515 nut_read_seek, 1379 nut_read_seek,
1380 nut_read_timestamp,
1516 .extensions = "nut", 1381 .extensions = "nut",
1517 }; 1382 };
1518 1383
1519 #ifdef CONFIG_ENCODERS 1384 #ifdef CONFIG_ENCODERS
1520 static AVOutputFormat nut_oformat = { 1385 static AVOutputFormat nut_oformat = {