in src/record/internal/matroska_read.cpp [389:762]
k4a_result_t parse_recording_config(k4a_playback_context_t *context)
{
RETURN_VALUE_IF_ARG(K4A_RESULT_FAILED, context == NULL);
RETURN_VALUE_IF_ARG(K4A_RESULT_FAILED, context->segment_info == nullptr);
context->timecode_scale = GetChild<KaxTimecodeScale>(*context->segment_info).GetValue();
if (K4A_FAILED(parse_tracks(context)))
{
LOG_ERROR("Reading track data failed.", 0);
return K4A_RESULT_FAILED;
}
context->color_track = find_track(context, "COLOR", "K4A_COLOR_TRACK");
context->depth_track = find_track(context, "DEPTH", "K4A_DEPTH_TRACK");
context->ir_track = find_track(context, "IR", "K4A_IR_TRACK");
if (context->ir_track == NULL)
{
// Support legacy IR track naming.
context->ir_track = find_track(context, "DEPTH_IR", NULL);
}
context->imu_track = find_track(context, "IMU", "K4A_IMU_TRACK");
// Read device calibration attachment
context->calibration_attachment = get_attachment_by_tag(context, "K4A_CALIBRATION_FILE");
if (context->calibration_attachment == NULL)
{
context->calibration_attachment = get_attachment_by_name(context, "calibration.json");
}
if (context->calibration_attachment == NULL)
{
// The rest of the recording can still be read if no device calibration blob exists.
LOG_WARNING("Device calibration is missing from recording.", 0);
}
uint64_t frame_period_ns = 0;
if (context->color_track)
{
if (context->color_track->type != track_video)
{
LOG_ERROR("Color track is not a video track.", 0);
return K4A_RESULT_FAILED;
}
frame_period_ns = context->color_track->frame_period_ns;
RETURN_IF_ERROR(read_bitmap_info_header(context->color_track));
context->record_config.color_resolution = K4A_COLOR_RESOLUTION_OFF;
for (size_t i = 0; i < arraysize(color_resolutions); i++)
{
uint32_t width, height;
if (k4a_convert_resolution_to_width_height(color_resolutions[i], &width, &height))
{
if (context->color_track->width == width && context->color_track->height == height)
{
context->record_config.color_resolution = color_resolutions[i];
break;
}
}
}
if (context->record_config.color_resolution == K4A_COLOR_RESOLUTION_OFF)
{
LOG_WARNING("The color resolution is not officially supported: %dx%d. You cannot get the calibration "
"information for this color resolution",
context->color_track->width,
context->color_track->height);
}
context->record_config.color_track_enabled = true;
context->record_config.color_format = context->color_track->format;
context->color_format_conversion = context->color_track->format;
}
else
{
context->record_config.color_resolution = K4A_COLOR_RESOLUTION_OFF;
// Set to a default color format if color track is disabled.
context->record_config.color_format = K4A_IMAGE_FORMAT_CUSTOM;
context->color_format_conversion = K4A_IMAGE_FORMAT_CUSTOM;
}
KaxTag *depth_mode_tag = get_tag(context, "K4A_DEPTH_MODE");
if (depth_mode_tag == NULL && (context->depth_track || context->ir_track))
{
LOG_ERROR("K4A_DEPTH_MODE tag is missing.", 0);
return K4A_RESULT_FAILED;
}
std::string depth_mode_str;
uint32_t depth_width = 0;
uint32_t depth_height = 0;
context->record_config.depth_mode = K4A_DEPTH_MODE_OFF;
if (depth_mode_tag != NULL)
{
depth_mode_str = get_tag_string(depth_mode_tag);
for (size_t i = 0; i < arraysize(depth_modes); i++)
{
if (depth_mode_str == depth_modes[i].second)
{
if (k4a_convert_depth_mode_to_width_height(depth_modes[i].first, &depth_width, &depth_height))
{
context->record_config.depth_mode = depth_modes[i].first;
break;
}
}
}
if (context->record_config.depth_mode == K4A_DEPTH_MODE_OFF)
{
// Try to find the mode matching strings in the legacy modes
for (size_t i = 0; i < arraysize(legacy_depth_modes); i++)
{
if (depth_mode_str == legacy_depth_modes[i].second)
{
if (k4a_convert_depth_mode_to_width_height(legacy_depth_modes[i].first,
&depth_width,
&depth_height))
{
context->record_config.depth_mode = legacy_depth_modes[i].first;
break;
}
}
}
}
if (context->record_config.depth_mode == K4A_DEPTH_MODE_OFF)
{
LOG_ERROR("Unsupported depth mode: %s", depth_mode_str.c_str());
return K4A_RESULT_FAILED;
}
}
if (context->depth_track)
{
if (context->depth_track->type != track_video)
{
LOG_ERROR("Depth track is not a video track.", 0);
return K4A_RESULT_FAILED;
}
if (frame_period_ns == 0)
{
frame_period_ns = context->depth_track->frame_period_ns;
}
else if (frame_period_ns != context->depth_track->frame_period_ns)
{
LOG_ERROR("Track frame durations don't match (Depth): %llu ns != %llu ns",
frame_period_ns,
context->depth_track->frame_period_ns);
return K4A_RESULT_FAILED;
}
if (context->depth_track->width != depth_width || context->depth_track->height != depth_height)
{
LOG_ERROR("Unsupported depth resolution / mode: %dx%d (%s)",
context->depth_track->width,
context->depth_track->height,
depth_mode_str.c_str());
return K4A_RESULT_FAILED;
}
RETURN_IF_ERROR(read_bitmap_info_header(context->depth_track));
context->record_config.depth_track_enabled = true;
}
if (context->ir_track)
{
if (context->ir_track->type != track_video)
{
LOG_ERROR("IR track is not a video track.", 0);
return K4A_RESULT_FAILED;
}
if (frame_period_ns == 0)
{
frame_period_ns = context->ir_track->frame_period_ns;
}
else if (frame_period_ns != context->ir_track->frame_period_ns)
{
LOG_ERROR("Track frame durations don't match (IR): %llu ns != %llu ns",
frame_period_ns,
context->ir_track->frame_period_ns);
return K4A_RESULT_FAILED;
}
if (context->depth_track)
{
if (context->ir_track->width != context->depth_track->width ||
context->ir_track->height != context->depth_track->height)
{
LOG_ERROR("Depth and IR track have different resolutions: Depth %dx%d, IR %dx%d",
context->depth_track->width,
context->depth_track->height,
context->ir_track->width,
context->ir_track->height);
return K4A_RESULT_FAILED;
}
}
else if (context->ir_track->width != depth_width || context->ir_track->height != depth_height)
{
LOG_ERROR("Unsupported IR resolution / depth mode: %dx%d (%s)",
context->ir_track->width,
context->ir_track->height,
depth_mode_str.c_str());
return K4A_RESULT_FAILED;
}
RETURN_IF_ERROR(read_bitmap_info_header(context->ir_track));
if (context->ir_track->format == K4A_IMAGE_FORMAT_DEPTH16)
{
context->ir_track->format = K4A_IMAGE_FORMAT_IR16;
}
context->record_config.ir_track_enabled = true;
}
context->sync_period_ns = frame_period_ns;
if (frame_period_ns > 0)
{
switch (1_s / frame_period_ns)
{
case 5:
context->record_config.camera_fps = K4A_FRAMES_PER_SECOND_5;
break;
case 15:
context->record_config.camera_fps = K4A_FRAMES_PER_SECOND_15;
break;
case 30:
context->record_config.camera_fps = K4A_FRAMES_PER_SECOND_30;
break;
default:
LOG_ERROR("Unsupported recording frame period: %llu ns (%llu fps)",
frame_period_ns,
(1_s / frame_period_ns));
return K4A_RESULT_FAILED;
}
}
else
{
// Default to 30 fps if no video tracks are enabled.
context->record_config.camera_fps = K4A_FRAMES_PER_SECOND_30;
}
// Read depth_delay_off_color_usec and set offsets for each builtin track accordingly.
KaxTag *depth_delay_tag = get_tag(context, "K4A_DEPTH_DELAY_NS");
if (depth_delay_tag != NULL)
{
int64_t depth_delay_ns;
std::istringstream depth_delay_str(get_tag_string(depth_delay_tag));
depth_delay_str >> depth_delay_ns;
if (!depth_delay_str.fail())
{
assert(depth_delay_ns / 1000 <= INT32_MAX);
context->record_config.depth_delay_off_color_usec = (int32_t)(depth_delay_ns / 1000);
// Only set positive delays so that we don't wrap around near 0.
if (depth_delay_ns > 0 && context->color_track)
{
context->color_track->sync_delay_ns = (uint64_t)depth_delay_ns;
}
else if (depth_delay_ns < 0)
{
if (context->depth_track)
context->depth_track->sync_delay_ns = (uint64_t)(-depth_delay_ns);
if (context->ir_track)
context->ir_track->sync_delay_ns = (uint64_t)(-depth_delay_ns);
}
}
else
{
LOG_ERROR("Tag K4A_DEPTH_DELAY_NS contains invalid value: %s", get_tag_string(depth_delay_tag).c_str());
return K4A_RESULT_FAILED;
}
}
else
{
context->record_config.depth_delay_off_color_usec = 0;
}
if (context->imu_track)
{
if (context->imu_track->type == track_subtitle)
{
context->record_config.imu_track_enabled = true;
}
else
{
LOG_WARNING("IMU track is not correct type, treating as a custom track.", 0);
context->imu_track = nullptr;
}
}
// Read wired_sync_mode and subordinate_delay_off_master_usec.
KaxTag *sync_mode_tag = get_tag(context, "K4A_WIRED_SYNC_MODE");
if (sync_mode_tag != NULL)
{
bool sync_mode_found = false;
std::string sync_mode_str = get_tag_string(sync_mode_tag);
for (size_t i = 0; i < arraysize(external_sync_modes); i++)
{
if (sync_mode_str == external_sync_modes[i].second)
{
context->record_config.wired_sync_mode = external_sync_modes[i].first;
sync_mode_found = true;
break;
}
}
if (!sync_mode_found)
{
LOG_ERROR("Unsupported wired sync mode: %s", sync_mode_str.c_str());
return K4A_RESULT_FAILED;
}
if (context->record_config.wired_sync_mode == K4A_WIRED_SYNC_MODE_SUBORDINATE)
{
KaxTag *subordinate_delay_tag = get_tag(context, "K4A_SUBORDINATE_DELAY_NS");
if (subordinate_delay_tag != NULL)
{
uint64_t subordinate_delay_ns;
std::istringstream subordinate_delay_str(get_tag_string(subordinate_delay_tag));
subordinate_delay_str >> subordinate_delay_ns;
if (!subordinate_delay_str.fail())
{
assert(subordinate_delay_ns / 1000 <= UINT32_MAX);
context->record_config.subordinate_delay_off_master_usec = (uint32_t)(subordinate_delay_ns / 1000);
}
else
{
LOG_ERROR("Tag K4A_SUBORDINATE_DELAY_NS contains invalid value: %s",
get_tag_string(subordinate_delay_tag).c_str());
return K4A_RESULT_FAILED;
}
}
else
{
context->record_config.subordinate_delay_off_master_usec = 0;
}
}
else
{
context->record_config.subordinate_delay_off_master_usec = 0;
}
}
else
{
context->record_config.wired_sync_mode = K4A_WIRED_SYNC_MODE_STANDALONE;
context->record_config.subordinate_delay_off_master_usec = 0;
}
KaxTag *start_offset_tag = get_tag(context, "K4A_START_OFFSET_NS");
if (start_offset_tag != NULL)
{
uint64_t start_offset_ns;
std::istringstream start_offset_str(get_tag_string(start_offset_tag));
start_offset_str >> start_offset_ns;
if (!start_offset_str.fail())
{
assert(start_offset_ns / 1000 <= UINT32_MAX);
context->record_config.start_timestamp_offset_usec = (uint32_t)(start_offset_ns / 1000);
}
else
{
LOG_ERROR("Tag K4A_START_OFFSET_NS contains invalid value: %s", get_tag_string(start_offset_tag).c_str());
return K4A_RESULT_FAILED;
}
}
else
{
context->record_config.start_timestamp_offset_usec = 0;
}
return K4A_RESULT_SUCCEEDED;
}