debug shared_buffer stream
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user