in src/color/uvc_camerareader.cpp [1118:1289]
void UVCCameraReader::Callback(uvc_frame_t *frame)
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_streaming && frame)
{
void *context = nullptr;
k4a_image_t image = NULL;
uint8_t *buffer = nullptr;
size_t buffer_size = 0;
int stride = 0;
uint64_t framePTS = 0;
uint64_t exposure_time = 0;
uint32_t iso_speed = 0;
uint32_t white_balance = 0;
bool decodeMJPEG = false;
bool drop_image = false;
// Parse metadata
size_t bufferLeft = (size_t)frame->metadata_bytes;
if (bufferLeft >= sizeof(KSCAMERA_METADATA_ITEMHEADER))
{
PKSCAMERA_METADATA_ITEMHEADER pItem = (PKSCAMERA_METADATA_ITEMHEADER)frame->metadata;
while (bufferLeft > 0)
{
switch (pItem->MetadataId)
{
case MetadataId_FrameAlignInfo:
{
PKSCAMERA_CUSTOM_METADATA_FrameAlignInfo pFrameAlignInfo =
(PKSCAMERA_CUSTOM_METADATA_FrameAlignInfo)pItem;
framePTS = pFrameAlignInfo->FramePTS;
}
break;
case MetadataId_CaptureStats:
{
PKSCAMERA_METADATA_CAPTURESTATS pCaptureStats = (PKSCAMERA_METADATA_CAPTURESTATS)pItem;
if (pCaptureStats->Flags & KSCAMERA_METADATA_CAPTURESTATS_FLAG_EXPOSURETIME)
{
exposure_time = pCaptureStats->ExposureTime / 10; // hns to micro-second
}
if (pCaptureStats->Flags & KSCAMERA_METADATA_CAPTURESTATS_FLAG_ISOSPEED)
{
iso_speed = pCaptureStats->IsoSpeed;
}
if (pCaptureStats->Flags & KSCAMERA_METADATA_CAPTURESTATS_FLAG_WHITEBALANCE)
{
white_balance = pCaptureStats->WhiteBalance;
}
}
break;
default:
break;
}
if (pItem->Size == 0)
{
LOG_WARNING("frame metadata id %d has zero buffer size", pItem->MetadataId);
break;
}
bufferLeft -= (size_t)pItem->Size;
if (bufferLeft < sizeof(KSCAMERA_METADATA_ITEMHEADER))
{
break;
}
pItem = reinterpret_cast<PKSCAMERA_METADATA_ITEMHEADER>(reinterpret_cast<uint8_t *>(pItem) +
pItem->Size);
}
}
if (framePTS == 0)
{
// Drop 0 time stamped frame
return;
}
if (m_input_image_format == K4A_IMAGE_FORMAT_COLOR_MJPG &&
m_output_image_format == K4A_IMAGE_FORMAT_COLOR_BGRA32)
{
stride = (int)frame->width * 4;
buffer_size = (size_t)stride * frame->height;
decodeMJPEG = true;
}
else
{
stride = (int)frame->step;
buffer_size = frame->data_bytes;
}
// Allocate K4A Color buffer
buffer = allocator_alloc(ALLOCATION_SOURCE_COLOR, buffer_size);
k4a_result_t result = K4A_RESULT_FROM_BOOL(buffer != NULL);
if (K4A_SUCCEEDED(result))
{
if (decodeMJPEG)
{
// Decode MJPG into BRGA32
result = DecodeMJPEGtoBGRA32((uint8_t *)frame->data, frame->data_bytes, buffer, buffer_size);
if (K4A_FAILED(result))
{
drop_image = true;
}
}
else
{
// Copy to K4A buffer
memcpy(buffer, frame->data, buffer_size);
}
}
if (K4A_SUCCEEDED(result))
{
// The buffer size may be larger than the height * stride for some formats
// so we must use image_create_from_buffer rather than image_create
result = TRACE_CALL(image_create_from_buffer(m_output_image_format,
(int)m_width_pixels,
(int)m_height_pixels,
stride,
buffer,
buffer_size,
uvc_camerareader_free_allocation,
context,
&image));
}
else
{
// cleanup if there was an error
allocator_free(buffer);
}
k4a_capture_t capture = NULL;
if (K4A_SUCCEEDED(result))
{
result = TRACE_CALL(capture_create(&capture));
}
if (K4A_SUCCEEDED(result))
{
// Set metadata
uint64_t ts = (uint64_t)frame->capture_time_finished.tv_sec * 1000000000;
ts += (uint64_t)frame->capture_time_finished.tv_nsec;
image_set_system_timestamp_nsec(image, ts);
image_set_device_timestamp_usec(image, K4A_90K_HZ_TICK_TO_USEC(framePTS));
image_set_exposure_usec(image, exposure_time);
image_set_iso_speed(image, iso_speed);
image_set_white_balance(image, white_balance);
// Set image
capture_set_color_image(capture, image);
}
if (!drop_image)
{
// Calback to color
m_pCallback(result, capture, m_pCallbackContext);
}
if (image)
{
image_dec_ref(image);
}
if (capture)
{
// We guarantee that capture is valid for the duration of the callback function, if someone
// needs it to live longer, then they need to add a ref
capture_dec_ref(capture);
}
}
}