debug shared_buffer stream

This commit is contained in:
Maik Jurischka
2026-01-30 16:29:19 +01:00
parent cc97528eca
commit 9f0eac870f
12 changed files with 805 additions and 16 deletions

View File

@@ -11,7 +11,7 @@
#include <iostream>
CameraController::CameraController(std::shared_ptr<VxCamera> camera)
: camera_(camera), gstPipeline_("videoconvert ! autovideosink") {
: camera_(camera), gstPipeline_("fakesink") {
streamingEngine_ = std::make_shared<StreamingEngine>(camera);
}
@@ -154,8 +154,15 @@ std::string CameraController::handleSetExposure(const std::string& mode, const s
const int flag = (mode == "auto") ? 1 : 0;
const long expValue = value.empty() ? 0 : std::stol(value);
if (VxSetUVCImageProcessing(camera_, VX_UVC_IMAGE_PROPERTIES::UVC_IMAGE_EXPOSURE,
expValue, flag) != 0) {
std::cout << "[DEBUG] Setting exposure: mode=" << mode << " (flag=" << flag
<< "), value=" << expValue << std::endl;
const int result = VxSetUVCImageProcessing(camera_, VX_UVC_IMAGE_PROPERTIES::UVC_IMAGE_EXPOSURE,
expValue, flag);
std::cout << "[DEBUG] VxSetUVCImageProcessing returned: " << result << std::endl;
if (result != 0) {
return createErrorResponse("Failed to set exposure");
}
@@ -249,8 +256,15 @@ std::string CameraController::handleSetGamma(const std::string& value) {
std::string CameraController::handleSetGain(const std::string& value) {
try {
const long val = std::stol(value);
if (VxSetUVCImageProcessing(camera_, VX_UVC_IMAGE_PROPERTIES::UVC_IMAGE_GAIN,
val, 0) != 0) {
std::cout << "[DEBUG] Setting gain: value=" << val << std::endl;
const int result = VxSetUVCImageProcessing(camera_, VX_UVC_IMAGE_PROPERTIES::UVC_IMAGE_GAIN,
val, 0);
std::cout << "[DEBUG] VxSetUVCImageProcessing (gain) returned: " << result << std::endl;
if (result != 0) {
return createErrorResponse("Failed to set gain");
}
return createSuccessResponse("Gain set successfully");

View File

@@ -128,6 +128,19 @@ bool SharedMemoryWriter::writeFrame(const uint8_t* data, const size_t size,
// 3. Copy frame data
memcpy(frame_data, data, size);
// Debug: Log every 60 frames
static uint64_t debug_counter = 0;
if (++debug_counter % 60 == 0) {
std::cout << "[SHM] Frame #" << frame_counter_
<< " written. write_seq=" << header->write_sequence.load()
<< " size=" << size
<< " first 4 bytes: ";
for (int i = 0; i < 4 && i < size; i++) {
printf("%02x ", frame_data[i]);
}
std::cout << std::endl;
}
// 4. Increment sequence (even = write complete)
header->write_sequence.fetch_add(1, std::memory_order_release);

View File

@@ -10,6 +10,8 @@
#include <iostream>
#include <chrono>
#include <utility>
#include <algorithm>
#include <cstring>
StreamingEngine::StreamingEngine(std::shared_ptr<VxCamera> camera)
: camera_(std::move(camera)), running_(false), currentFormat_(), bufferSize_(0) {
@@ -44,26 +46,41 @@ bool StreamingEngine::start(const std::string& gstPipeline) {
return false;
}
// Start camera streaming
if (VxStartStreaming(camera_) != 0) {
std::cerr << "Failed to start camera streaming" << std::endl;
return false;
}
// Ensure camera is not already streaming (clean slate)
VxStopStreaming(camera_);
// Get current format to allocate buffer
// Get current format to allocate buffer BEFORE starting streaming
std::vector<VxFormat> fmtList;
if (VxGetFormatList(camera_, fmtList) != 0 || fmtList.empty()) {
std::cerr << "Failed to get format list" << std::endl;
VxStopStreaming(camera_);
return false;
}
currentFormat_ = fmtList[0];
// Ensure format is properly set before streaming
if (VxSetFormat(camera_, currentFormat_) != 0) {
std::cerr << "Failed to set format before streaming" << std::endl;
return false;
}
std::cout << "Starting stream with format: " << currentFormat_.width << "x"
<< currentFormat_.height << " @ " << currentFormat_.framerate << " fps" << std::endl;
// Start camera streaming
const int startResult = VxStartStreaming(camera_);
if (startResult != 0) {
std::cerr << "Failed to start camera streaming (error code: " << startResult << ")" << std::endl;
return false;
}
// Allocate buffer (assume worst case: uncompressed)
const size_t calculatedBufferSize = currentFormat_.width * currentFormat_.height * 4;
bufferSize_ = calculatedBufferSize;
buffer_ = std::make_unique<uint8_t[]>(bufferSize_);
// Allocate RGB conversion buffer for shared memory
rgbBuffer_ = std::make_unique<uint8_t[]>(currentFormat_.width * currentFormat_.height * 3);
// Start GStreamer pipeline if configured
if (useGStreamer) {
gstPipeline_->setPipelineDescription(gstPipeline);
@@ -130,6 +147,18 @@ void StreamingEngine::acquisitionLoop() {
const VX_CAPTURE_RESULT result = VxGetImage(camera_, buffer_.get(), &dataSize, 1000);
if (result == VX_CAPTURE_RESULT::VX_SUCCESS && dataSize > 0) {
// Debug: Check buffer immediately after VxGetImage (every 60 frames)
static uint64_t captureCount = 0;
captureCount++;
if (captureCount % 60 == 1) {
std::cout << "\n[RAW BUFFER Frame #" << captureCount << "] Right after VxGetImage:" << std::endl;
std::cout << "[RAW] First 16 bytes: ";
for (int i = 0; i < 16; i++) {
printf("%02x ", buffer_.get()[i]);
}
std::cout << std::endl;
}
// Get timestamp for frame
const uint64_t timestamp_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
@@ -147,6 +176,15 @@ void StreamingEngine::acquisitionLoop() {
// Push frame to GStreamer pipeline if active
if (gstPipeline_->isRunning()) {
// Debug: Check buffer before GStreamer push
if (captureCount % 60 == 1) {
std::cout << "[BEFORE GST] First 16 bytes: ";
for (int i = 0; i < 16; i++) {
printf("%02x ", buffer_.get()[i]);
}
std::cout << std::endl;
}
if (!gstPipeline_->pushBuffer(buffer_.get(), dataSize,
currentFormat_.width, currentFormat_.height,
formatStr)) {
@@ -154,12 +192,68 @@ void StreamingEngine::acquisitionLoop() {
}
}
// Push frame to shared memory if enabled
// Push frame to shared memory if enabled (always as RGB)
if (shmWriter_ && shmWriter_->isCreated()) {
if (!shmWriter_->writeFrame(buffer_.get(), dataSize,
static uint64_t shmFrameCount = 0;
shmFrameCount++;
const uint8_t* frameData = buffer_.get();
size_t frameSize = dataSize;
std::string outputFormat = "RGB";
// Debug: Print every 60 frames to see current data
if (shmFrameCount % 60 == 1) {
std::cout << "\n[DEBUG SHM Frame #" << shmFrameCount << "] Input format: " << formatStr
<< " | Size: " << dataSize << std::endl;
std::cout << "[DEBUG] First 16 input bytes (hex): ";
for (int i = 0; i < 16 && i < dataSize; i++) {
printf("%02x ", buffer_.get()[i]);
}
std::cout << std::endl;
// For UYVY, show interpretation
if (currentFormat_.format == VX_IMAGE_FORMAT::UYVY) {
std::cout << "[DEBUG] UYVY: U=" << (int)buffer_.get()[0]
<< " Y0=" << (int)buffer_.get()[1]
<< " V=" << (int)buffer_.get()[2]
<< " Y1=" << (int)buffer_.get()[3] << std::endl;
}
}
// Convert to RGB if needed
if (currentFormat_.format != VX_IMAGE_FORMAT::RGB) {
frameSize = convertToRGB(buffer_.get(), rgbBuffer_.get(),
currentFormat_.width, currentFormat_.height,
formatStr, timestamp_ns)) {
currentFormat_.format);
frameData = rgbBuffer_.get();
// Debug: Print every 60 frames after conversion
if (shmFrameCount % 60 == 1) {
std::cout << "[DEBUG] RGB output - First 12 bytes: ";
for (int i = 0; i < 12 && i < frameSize; i++) {
printf("%02x ", frameData[i]);
}
std::cout << "\n[DEBUG] First 2 RGB pixels: R=" << (int)frameData[0]
<< " G=" << (int)frameData[1] << " B=" << (int)frameData[2]
<< " | R=" << (int)frameData[3] << " G=" << (int)frameData[4]
<< " B=" << (int)frameData[5] << std::endl;
}
}
if (!shmWriter_->writeFrame(frameData, frameSize,
currentFormat_.width, currentFormat_.height,
outputFormat, timestamp_ns)) {
std::cerr << "Failed to write frame to shared memory" << std::endl;
} else {
// Debug: Print info every 30 frames
if (shmFrameCount % 30 == 0) {
std::cout << "[DEBUG] SHM: Written " << shmFrameCount << " frames. "
<< "Last frame first 8 bytes: ";
for (int i = 0; i < 8 && i < frameSize; i++) {
printf("%02x ", frameData[i]);
}
std::cout << std::endl;
}
}
}
@@ -223,3 +317,110 @@ void StreamingEngine::disableSharedMemory() {
std::cout << "Shared memory disabled" << std::endl;
}
}
size_t StreamingEngine::convertToRGB(const uint8_t* src, uint8_t* dst, const int width, const int height, const VX_IMAGE_FORMAT format) {
const size_t rgbSize = width * height * 3;
// Helper lambda for safe clamping
auto clamp = [](int value) -> uint8_t {
if (value < 0) return 0;
if (value > 255) return 255;
return static_cast<uint8_t>(value);
};
switch (format) {
case VX_IMAGE_FORMAT::BGR: {
// BGR to RGB: swap R and B channels
for (int i = 0; i < width * height; i++) {
dst[i * 3 + 0] = src[i * 3 + 2]; // R = B
dst[i * 3 + 1] = src[i * 3 + 1]; // G = G
dst[i * 3 + 2] = src[i * 3 + 0]; // B = R
}
return rgbSize;
}
case VX_IMAGE_FORMAT::YUY2: {
// YUY2 (YUYV) to RGB conversion
// Format: Y0 U Y1 V (4 bytes = 2 pixels)
for (int i = 0; i < width * height / 2; i++) {
const int y0 = src[i * 4 + 0];
const int u = src[i * 4 + 1];
const int y1 = src[i * 4 + 2];
const int v = src[i * 4 + 3];
const int c0 = y0 - 16;
const int c1 = y1 - 16;
const int d = u - 128;
const int e = v - 128;
// First pixel (RGB)
const int r0 = (298 * c0 + 409 * e + 128) >> 8;
const int g0 = (298 * c0 - 100 * d - 208 * e + 128) >> 8;
const int b0 = (298 * c0 + 516 * d + 128) >> 8;
dst[i * 6 + 0] = clamp(r0);
dst[i * 6 + 1] = clamp(g0);
dst[i * 6 + 2] = clamp(b0);
// Second pixel (RGB)
const int r1 = (298 * c1 + 409 * e + 128) >> 8;
const int g1 = (298 * c1 - 100 * d - 208 * e + 128) >> 8;
const int b1 = (298 * c1 + 516 * d + 128) >> 8;
dst[i * 6 + 3] = clamp(r1);
dst[i * 6 + 4] = clamp(g1);
dst[i * 6 + 5] = clamp(b1);
}
return rgbSize;
}
case VX_IMAGE_FORMAT::UYVY: {
// UYVY to RGB conversion
// Format: U Y0 V Y1 (4 bytes = 2 pixels)
for (int i = 0; i < width * height / 2; i++) {
const int u = src[i * 4 + 0];
const int y0 = src[i * 4 + 1];
const int v = src[i * 4 + 2];
const int y1 = src[i * 4 + 3];
const int c0 = y0 - 16;
const int c1 = y1 - 16;
const int d = u - 128;
const int e = v - 128;
// First pixel (RGB)
const int r0 = (298 * c0 + 409 * e + 128) >> 8;
const int g0 = (298 * c0 - 100 * d - 208 * e + 128) >> 8;
const int b0 = (298 * c0 + 516 * d + 128) >> 8;
dst[i * 6 + 0] = clamp(r0);
dst[i * 6 + 1] = clamp(g0);
dst[i * 6 + 2] = clamp(b0);
// Second pixel (RGB)
const int r1 = (298 * c1 + 409 * e + 128) >> 8;
const int g1 = (298 * c1 - 100 * d - 208 * e + 128) >> 8;
const int b1 = (298 * c1 + 516 * d + 128) >> 8;
dst[i * 6 + 3] = clamp(r1);
dst[i * 6 + 4] = clamp(g1);
dst[i * 6 + 5] = clamp(b1);
}
return rgbSize;
}
case VX_IMAGE_FORMAT::RGB: {
// Already RGB, just copy
std::memcpy(dst, src, rgbSize);
return rgbSize;
}
default: {
std::cerr << "Unsupported format for RGB conversion, copying as-is" << std::endl;
// Copy as-is for unsupported formats
const size_t copySize = std::min(rgbSize, static_cast<size_t>(width * height * 4));
std::memcpy(dst, src, copySize);
return copySize;
}
}
}

View File

@@ -98,7 +98,7 @@ int main() {
std::cout << "License: CC BY-NC-SA 4.0 -> https://creativecommons.org/licenses/by-nc-sa/4.0/" << std::endl;
std::cout << "========================================" << std::endl << std::endl;
std::cout << "Control socket: " << socketPath << std::endl;
std::cout << "Default pipeline: videoconvert ! autovideosink" << std::endl;
std::cout << "Default pipeline: fakesink (no display)" << std::endl;
std::cout << "\nQuick start:" << std::endl;
std::cout << R"( echo '{"command":"start_stream"}' | socat - UNIX-CONNECT:)" << socketPath << std::endl;
std::cout << "\nTo change pipeline before starting:" << std::endl;