in src/record/internal/matroska_read.cpp [1919:2088]
k4a_stream_result_t get_capture(k4a_playback_context_t *context, k4a_capture_t *capture_handle, bool next)
{
RETURN_VALUE_IF_ARG(K4A_STREAM_RESULT_FAILED, context == NULL);
RETURN_VALUE_IF_ARG(K4A_STREAM_RESULT_FAILED, capture_handle == NULL);
track_reader_t *blocks[] = { context->color_track, context->depth_track, context->ir_track };
std::shared_ptr<block_info_t> next_blocks[arraysize(blocks)];
uint64_t timestamp_start_ns = UINT64_MAX;
uint64_t timestamp_end_ns = 0;
// Find the next block for each track
int enabled_tracks = 0;
for (size_t i = 0; i < arraysize(blocks); i++)
{
if (blocks[i] != NULL)
{
enabled_tracks++;
// If the current block is NULL, find the next block before/after the seek timestamp.
if (blocks[i]->current_block == nullptr)
{
next_blocks[i] = find_block(context, blocks[i], context->seek_timestamp_ns);
if (!next && next_blocks[i])
{
next_blocks[i] = next_block(context, next_blocks[i].get(), false);
}
}
else
{
next_blocks[i] = next_block(context, blocks[i]->current_block.get(), next);
}
if (next_blocks[i] && next_blocks[i]->block)
{
// Find the lowest and highest timestamp out of the next blocks
if (next_blocks[i]->sync_timestamp_ns < timestamp_start_ns)
{
timestamp_start_ns = next_blocks[i]->sync_timestamp_ns;
}
if (next_blocks[i]->sync_timestamp_ns > timestamp_end_ns)
{
timestamp_end_ns = next_blocks[i]->sync_timestamp_ns;
}
}
else
{
LOG_TRACE("%s of recording reached", next ? "End" : "Beginning");
blocks[i]->current_block = next_blocks[i];
}
}
}
// Count how many of the blocks are within the sync window
int valid_blocks = 0;
if (enabled_tracks > 0)
{
if (next)
{
timestamp_end_ns = timestamp_start_ns;
}
else
{
timestamp_start_ns = timestamp_end_ns;
}
for (size_t i = 0; i < arraysize(blocks); i++)
{
if (next_blocks[i] && next_blocks[i]->block)
{
// If we're seeking forward, check the start timestamp, otherwise check the end timestamp
if (next && (next_blocks[i]->sync_timestamp_ns - timestamp_start_ns < context->sync_period_ns / 2))
{
valid_blocks++;
if (next_blocks[i]->sync_timestamp_ns > timestamp_end_ns)
{
timestamp_end_ns = next_blocks[i]->sync_timestamp_ns;
}
}
else if (!next && (timestamp_end_ns - next_blocks[i]->sync_timestamp_ns < context->sync_period_ns / 2))
{
valid_blocks++;
if (next_blocks[i]->sync_timestamp_ns < timestamp_start_ns)
{
timestamp_start_ns = next_blocks[i]->sync_timestamp_ns;
}
}
else
{
// Don't use this block as part of the capture
next_blocks[i] = nullptr;
}
}
}
if (valid_blocks < enabled_tracks)
{
// Try filling in any blocks that were missed due to a seek
bool filled = false;
for (size_t i = 0; i < arraysize(blocks); i++)
{
if (blocks[i] != NULL && next_blocks[i] == nullptr && blocks[i]->current_block == nullptr)
{
std::shared_ptr<block_info_t> test_block = find_block(context,
blocks[i],
context->seek_timestamp_ns);
if (next)
{
test_block = next_block(context, test_block.get(), false);
}
if (test_block && test_block->block)
{
if (next && (timestamp_end_ns - test_block->sync_timestamp_ns < context->sync_period_ns / 2))
{
valid_blocks++;
next_blocks[i] = test_block;
filled = true;
}
else if (!next &&
(test_block->sync_timestamp_ns - timestamp_start_ns < context->sync_period_ns / 2))
{
valid_blocks++;
next_blocks[i] = test_block;
filled = true;
}
}
}
}
if (!next && filled)
{
// We seeked to the middle of a capture and then called previous capture, the current state is actually
// for next_capture. Save the state and make a call to previous capture.
for (size_t i = 0; i < arraysize(blocks); i++)
{
if (next_blocks[i])
{
blocks[i]->current_block = next_blocks[i];
}
}
return get_capture(context, capture_handle, false);
}
}
}
LOG_TRACE("Valid blocks: %d/%d, Start: %llu ms, End: %llu ms",
valid_blocks,
enabled_tracks,
timestamp_start_ns / 1_ms,
timestamp_end_ns / 1_ms);
*capture_handle = NULL;
for (size_t i = 0; i < arraysize(blocks); i++)
{
if (next_blocks[i] && next_blocks[i]->block)
{
blocks[i]->current_block = next_blocks[i];
k4a_result_t result = TRACE_CALL(new_capture(context, blocks[i]->current_block.get(), capture_handle));
if (K4A_FAILED(result))
{
if (*capture_handle != NULL)
{
k4a_capture_release(*capture_handle);
*capture_handle = NULL;
}
return K4A_STREAM_RESULT_FAILED;
}
}
}
return valid_blocks == 0 ? K4A_STREAM_RESULT_EOF : K4A_STREAM_RESULT_SUCCEEDED;
}