FastLED 3.9.15
Loading...
Searching...
No Matches

◆ plm_demux_seek()

plm_packet_t * fl::third_party::plm_demux_seek ( plm_demux_t * self,
double time,
int type,
int force_intra )

Definition at line 1374 of file pl_mpeg.hpp.

1374 {
1375 if (!plm_demux_has_headers(self)) {
1376 return NULL;
1377 }
1378
1379 // Using the current time, current byte position and the average bytes per
1380 // second for this file, try to jump to a byte position that hopefully has
1381 // packets containing timestamps within one second before to the desired
1382 // seek_time.
1383
1384 // If we hit close to the seek_time scan through all packets to find the
1385 // last one (just before the seek_time) containing an intra frame.
1386 // Otherwise we should at least be closer than before. Calculate the bytes
1387 // per second for the jumped range and jump again.
1388
1389 // The number of retries here is hard-limited to a generous amount. Usually
1390 // the correct range is found after 1--5 jumps, even for files with very
1391 // variable bitrates. If significantly more jumps are needed, there's
1392 // probably something wrong with the file and we just avoid getting into an
1393 // infinite loop. 32 retries should be enough for anybody.
1394
1395 double duration = plm_demux_get_duration(self, type);
1396 long file_size = plm_buffer_get_size(self->buffer);
1397 long byterate = file_size / duration;
1398
1399 double cur_time = self->last_decoded_pts;
1400 double scan_span = 1;
1401
1402 if (seek_time > duration) {
1403 seek_time = duration;
1404 }
1405 else if (seek_time < 0) {
1406 seek_time = 0;
1407 }
1408 seek_time += self->start_time;
1409
1410 for (int retry = 0; retry < 32; retry++) {
1411 int found_packet_with_pts = FALSE;
1412 int found_packet_in_range = FALSE;
1413 long last_valid_packet_start = -1;
1414 double first_packet_time = PLM_PACKET_INVALID_TS;
1415
1416 long cur_pos = plm_buffer_tell(self->buffer);
1417
1418 // Estimate byte offset and jump to it.
1419 long offset = (seek_time - cur_time - scan_span) * byterate;
1420 long seek_pos = cur_pos + offset;
1421 if (seek_pos < 0) {
1422 seek_pos = 0;
1423 }
1424 else if (seek_pos > file_size - 256) {
1425 seek_pos = file_size - 256;
1426 }
1427
1428 plm_demux_buffer_seek(self, seek_pos);
1429
1430 // Scan through all packets up to the seek_time to find the last packet
1431 // containing an intra frame.
1432 while (plm_buffer_find_start_code(self->buffer, type) != -1) {
1433 long packet_start = plm_buffer_tell(self->buffer);
1434 plm_packet_t *packet = plm_demux_decode_packet(self, type);
1435
1436 // Skip packet if it has no PTS
1437 if (!packet || packet->pts == PLM_PACKET_INVALID_TS) {
1438 continue;
1439 }
1440
1441 // Bail scanning through packets if we hit one that is outside
1442 // seek_time - scan_span.
1443 // We also adjust the cur_time and byterate values here so the next
1444 // iteration can be a bit more precise.
1445 if (packet->pts > seek_time || packet->pts < seek_time - scan_span) {
1446 found_packet_with_pts = TRUE;
1447 byterate = (seek_pos - cur_pos) / (packet->pts - cur_time);
1448 cur_time = packet->pts;
1449 break;
1450 }
1451
1452 // If we are still here, it means this packet is in close range to
1453 // the seek_time. If this is the first packet for this jump position
1454 // record the PTS. If we later have to back off, when there was no
1455 // intra frame in this range, we can lower the seek_time to not scan
1456 // this range again.
1457 if (!found_packet_in_range) {
1458 found_packet_in_range = TRUE;
1459 first_packet_time = packet->pts;
1460 }
1461
1462 // Check if this is an intra frame packet. If so, record the buffer
1463 // position of the start of this packet. We want to jump back to it
1464 // later, when we know it's the last intra frame before desired
1465 // seek time.
1466 if (force_intra) {
1467 for (size_t i = 0; i < packet->length - 6; i++) {
1468 // Find the START_PICTURE code
1469 if (
1470 packet->data[i] == 0x00 &&
1471 packet->data[i + 1] == 0x00 &&
1472 packet->data[i + 2] == 0x01 &&
1473 packet->data[i + 3] == 0x00
1474 ) {
1475 // Bits 11--13 in the picture header contain the frame
1476 // type, where 1=Intra
1477 if ((packet->data[i + 5] & 0x38) == 8) {
1478 last_valid_packet_start = packet_start;
1479 }
1480 break;
1481 }
1482 }
1483 }
1484
1485 // If we don't want intra frames, just use the last PTS found.
1486 else {
1487 last_valid_packet_start = packet_start;
1488 }
1489 }
1490
1491 // If there was at least one intra frame in the range scanned above,
1492 // our search is over. Jump back to the packet and decode it again.
1493 if (last_valid_packet_start != -1) {
1494 plm_demux_buffer_seek(self, last_valid_packet_start);
1495 return plm_demux_decode_packet(self, type);
1496 }
1497
1498 // If we hit the right range, but still found no intra frame, we have
1499 // to increases the scan_span. This is done exponentially to also handle
1500 // video files with very few intra frames.
1501 else if (found_packet_in_range) {
1502 scan_span *= 2;
1503 seek_time = first_packet_time;
1504 }
1505
1506 // If we didn't find any packet with a PTS, it probably means we reached
1507 // the end of the file. Estimate byterate and cur_time accordingly.
1508 else if (!found_packet_with_pts) {
1509 byterate = (seek_pos - cur_pos) / (duration - cur_time);
1510 cur_time = duration;
1511 }
1512 }
1513
1514 return NULL;
1515}
fl::UISlider offset("Offset", 0.0f, 0.0f, 1.0f, 0.01f)
#define NULL
void plm_demux_buffer_seek(plm_demux_t *self, size_t pos) FL_NOEXCEPT
Definition pl_mpeg.hpp:1297
size_t plm_buffer_get_size(plm_buffer_t *self) FL_NOEXCEPT
Definition pl_mpeg.hpp:867
double plm_demux_get_duration(plm_demux_t *self, int type) FL_NOEXCEPT
Definition pl_mpeg.hpp:1329
int plm_buffer_find_start_code(plm_buffer_t *self, int code) FL_NOEXCEPT
Definition pl_mpeg.hpp:1078
plm_packet_t * plm_demux_decode_packet(plm_demux_t *self, int type) FL_NOEXCEPT
Definition pl_mpeg.hpp:1567
int plm_demux_has_headers(plm_demux_t *self) FL_NOEXCEPT
Definition pl_mpeg.hpp:1181
size_t plm_buffer_tell(plm_buffer_t *self) FL_NOEXCEPT
Definition pl_mpeg.hpp:945
#define PLM_PACKET_INVALID_TS
Definition pl_mpeg.h:171
#define TRUE
Definition pl_mpeg.hpp:174
#define FALSE
Definition pl_mpeg.hpp:175

References fl::third_party::plm_packet_t::data, FALSE, FL_NOEXCEPT, fl::third_party::plm_packet_t::length, NULL, offset(), plm_buffer_find_start_code(), plm_buffer_get_size(), plm_buffer_tell(), plm_demux_buffer_seek(), plm_demux_decode_packet(), plm_demux_get_duration(), plm_demux_has_headers(), PLM_PACKET_INVALID_TS, fl::third_party::plm_packet_t::pts, and TRUE.

Referenced by plm_seek_frame().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: