Skip to content

Commit 3b6b249

Browse files
committed
add more debugging information
1 parent 204ca79 commit 3b6b249

1 file changed

Lines changed: 169 additions & 66 deletions

File tree

src/libcameracamera.cpp

Lines changed: 169 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -444,20 +444,29 @@ void LibCameraWorker::processCompletedRequest(Request *request) {
444444

445445
const std::map<const Stream *, FrameBuffer *> &buffers = request->buffers();
446446

447-
// Return buffer to free list (with lock)
448-
{
447+
if (request->status() == Request::RequestCancelled) {
448+
// Return buffer to free list (with lock)
449449
std::lock_guard<std::mutex> lock(mBufferMutex);
450450
for (auto it = buffers.begin(); it != buffers.end(); ++it) {
451451
mBuffersInFlight.erase(it->second);
452452
mFreeBuffers.push_back(it->second);
453453
}
454-
}
455-
456-
if (request->status() == Request::RequestCancelled) {
457454
return;
458455
}
459456

457+
// IMPORTANT: Convert image BEFORE returning buffer to free list!
458+
// Otherwise the buffer may be reused before we read it
460459
QImage preview = convertBufferToImage(buffers);
460+
461+
// Now return buffer to free list (with lock)
462+
{
463+
std::lock_guard<std::mutex> lock(mBufferMutex);
464+
for (auto it = buffers.begin(); it != buffers.end(); ++it) {
465+
mBuffersInFlight.erase(it->second);
466+
mFreeBuffers.push_back(it->second);
467+
}
468+
}
469+
461470
if (!preview.isNull()) {
462471
Q_EMIT frameReady(preview);
463472
}
@@ -477,134 +486,228 @@ QImage LibCameraWorker::convertBufferToImage(
477486
const Stream *stream = it->first;
478487
FrameBuffer *buffer = it->second;
479488

480-
const FrameBuffer::Plane &plane = buffer->planes().front();
481-
void *memory =
482-
mmap(NULL, plane.length, PROT_READ, MAP_SHARED, plane.fd.get(), 0);
483-
484-
if (memory == MAP_FAILED) {
485-
qDebug() << "[ERROR] Failed to mmap framebuffer memory:"
486-
<< strerror(errno);
489+
const StreamConfiguration &cfg = stream->configuration();
490+
Span<const FrameBuffer::Plane> planes = buffer->planes();
491+
492+
// Log buffer metadata for debugging
493+
const FrameMetadata &metadata = buffer->metadata();
494+
qDebug() << "[DEBUG] convertBufferToImage: format=" << QString::fromStdString(cfg.pixelFormat.toString())
495+
<< " size=" << cfg.size.width << "x" << cfg.size.height
496+
<< " stride=" << cfg.stride
497+
<< " num_planes=" << planes.size()
498+
<< " metadata_status=" << metadata.status;
499+
500+
for (size_t i = 0; i < planes.size() && i < metadata.planes().size(); i++) {
501+
qDebug() << "[DEBUG] Plane" << i << ": fd=" << planes[i].fd.get()
502+
<< " offset=" << planes[i].offset
503+
<< " length=" << planes[i].length
504+
<< " bytesused=" << metadata.planes()[i].bytesused;
505+
}
506+
507+
// Check if buffer has data
508+
if (metadata.planes().empty() || metadata.planes()[0].bytesused == 0) {
509+
qDebug() << "[ERROR] Buffer is empty - bytesused=0";
487510
return QImage();
488511
}
489512

490-
const StreamConfiguration &cfg = stream->configuration();
491-
492-
if (cfg.pixelFormat == libcamera::formats::RGB888) {
493-
QImage temp(static_cast<const uchar *>(memory),
494-
cfg.size.width,
495-
cfg.size.height,
496-
cfg.stride,
497-
QImage::Format_BGR888);
498-
qDebug() << "[DEBUG] RGB888 conversion complete, image size:" << temp.size();
499-
image = temp.copy();
500-
} else if (cfg.pixelFormat == libcamera::formats::BGR888) {
501-
QImage temp(static_cast<const uchar *>(memory),
502-
cfg.size.width,
503-
cfg.size.height,
504-
cfg.stride,
505-
QImage::Format_BGR888);
506-
qDebug() << "[DEBUG] BGR888 conversion complete, image size:" << temp.size();
507-
image = temp.copy();
508-
} else if (cfg.pixelFormat == libcamera::formats::MJPEG) {
509-
size_t size = buffer->metadata().planes()[0].bytesused;
510-
image.loadFromData(static_cast<const uchar *>(memory), static_cast<int>(size), "JPEG");
511-
qDebug() << "[DEBUG] MJPEG conversion complete, image size:" << image.size();
512-
} else if (cfg.pixelFormat == libcamera::formats::YUYV) {
513-
// Use OpenCV for YUYV to RGB conversion
514-
cv::Mat yuyv(cfg.size.height, cfg.size.width, CV_8UC2,
515-
const_cast<void*>(memory), cfg.stride);
516-
cv::Mat rgb;
517-
cv::cvtColor(yuyv, rgb, cv::COLOR_YUV2RGB_YUYV);
513+
// For single-plane formats (RGB, BGR, MJPEG, YUYV)
514+
if (cfg.pixelFormat == libcamera::formats::RGB888 ||
515+
cfg.pixelFormat == libcamera::formats::BGR888 ||
516+
cfg.pixelFormat == libcamera::formats::MJPEG ||
517+
cfg.pixelFormat == libcamera::formats::YUYV) {
518+
519+
const FrameBuffer::Plane &plane = planes.front();
520+
void *memory = mmap(NULL, plane.length, PROT_READ, MAP_SHARED,
521+
plane.fd.get(), plane.offset);
522+
523+
if (memory == MAP_FAILED) {
524+
qDebug() << "[ERROR] Failed to mmap framebuffer memory:" << strerror(errno);
525+
return QImage();
526+
}
527+
528+
if (cfg.pixelFormat == libcamera::formats::RGB888) {
529+
QImage temp(static_cast<const uchar *>(memory),
530+
cfg.size.width,
531+
cfg.size.height,
532+
cfg.stride,
533+
QImage::Format_BGR888);
534+
qDebug() << "[DEBUG] RGB888 conversion complete, image size:" << temp.size();
535+
image = temp.copy();
536+
} else if (cfg.pixelFormat == libcamera::formats::BGR888) {
537+
QImage temp(static_cast<const uchar *>(memory),
538+
cfg.size.width,
539+
cfg.size.height,
540+
cfg.stride,
541+
QImage::Format_BGR888);
542+
qDebug() << "[DEBUG] BGR888 conversion complete, image size:" << temp.size();
543+
image = temp.copy();
544+
} else if (cfg.pixelFormat == libcamera::formats::MJPEG) {
545+
size_t size = metadata.planes()[0].bytesused;
546+
image.loadFromData(static_cast<const uchar *>(memory), static_cast<int>(size), "JPEG");
547+
qDebug() << "[DEBUG] MJPEG conversion complete, image size:" << image.size();
548+
} else if (cfg.pixelFormat == libcamera::formats::YUYV) {
549+
cv::Mat yuyv(cfg.size.height, cfg.size.width, CV_8UC2,
550+
const_cast<void*>(memory), cfg.stride);
551+
cv::Mat rgb;
552+
cv::cvtColor(yuyv, rgb, cv::COLOR_YUV2RGB_YUYV);
553+
554+
image = QImage(rgb.data, rgb.cols, rgb.rows, rgb.step,
555+
QImage::Format_RGB888).copy();
556+
qDebug() << "[DEBUG] YUYV conversion complete (OpenCV), image size:" << image.size();
557+
}
558+
559+
munmap(memory, plane.length);
518560

519-
image = QImage(rgb.data, rgb.cols, rgb.rows, rgb.step,
520-
QImage::Format_RGB888).copy();
521-
qDebug() << "[DEBUG] YUYV conversion complete (OpenCV), image size:" << image.size();
522561
} else if (cfg.pixelFormat == libcamera::formats::YUV420) {
523562
// Use OpenCV for YUV420 (I420) to RGB conversion
524563
unsigned int width = cfg.size.width;
525564
unsigned int height = cfg.size.height;
526565
unsigned int stride = cfg.stride;
527566

528-
Span<const FrameBuffer::Plane> planes = buffer->planes();
529-
530567
qDebug() << "[DEBUG] YUV420: width=" << width << " height=" << height
531568
<< " stride=" << stride << " num_planes=" << planes.size();
532569

570+
// Check if all planes share the same fd (contiguous buffer with offsets)
571+
bool samefd = true;
533572
if (planes.size() >= 3) {
534-
// Multi-plane format - map each plane separately and copy to contiguous buffer
573+
int fd0 = planes[0].fd.get();
574+
for (size_t i = 1; i < planes.size(); i++) {
575+
if (planes[i].fd.get() != fd0) {
576+
samefd = false;
577+
break;
578+
}
579+
}
580+
}
581+
qDebug() << "[DEBUG] YUV420: planes share same fd:" << samefd;
582+
583+
if (planes.size() >= 3 && samefd) {
584+
// All planes share same fd - map once with the total size
585+
// Calculate total size needed
586+
size_t totalSize = 0;
587+
for (size_t i = 0; i < planes.size(); i++) {
588+
size_t endOffset = planes[i].offset + planes[i].length;
589+
if (endOffset > totalSize) totalSize = endOffset;
590+
}
591+
592+
qDebug() << "[DEBUG] YUV420 same-fd: totalSize=" << totalSize;
593+
594+
void *memory = mmap(NULL, totalSize, PROT_READ, MAP_SHARED,
595+
planes[0].fd.get(), 0);
596+
597+
if (memory == MAP_FAILED) {
598+
qDebug() << "[ERROR] Failed to mmap YUV420 buffer:" << strerror(errno);
599+
return QImage();
600+
}
601+
602+
// Get pointers to each plane using their offsets
603+
const uint8_t *yData = static_cast<const uint8_t*>(memory) + planes[0].offset;
604+
const uint8_t *uData = static_cast<const uint8_t*>(memory) + planes[1].offset;
605+
const uint8_t *vData = static_cast<const uint8_t*>(memory) + planes[2].offset;
606+
607+
// Debug: Check first bytes of each plane
608+
qDebug() << "[DEBUG] Y plane first byte:" << (int)yData[0];
609+
qDebug() << "[DEBUG] U plane first byte:" << (int)uData[0];
610+
qDebug() << "[DEBUG] V plane first byte:" << (int)vData[0];
611+
612+
// Create contiguous I420 buffer for OpenCV
613+
size_t ySize = stride * height;
614+
size_t uvStride = stride / 2;
615+
size_t uvSize = uvStride * (height / 2);
616+
std::vector<uint8_t> i420Buffer(ySize + 2 * uvSize);
617+
618+
memcpy(i420Buffer.data(), yData, ySize);
619+
memcpy(i420Buffer.data() + ySize, uData, uvSize);
620+
memcpy(i420Buffer.data() + ySize + uvSize, vData, uvSize);
621+
622+
cv::Mat yuv(height * 3 / 2, stride, CV_8UC1, i420Buffer.data());
623+
cv::Mat rgb;
624+
cv::cvtColor(yuv, rgb, cv::COLOR_YUV2RGB_I420);
625+
626+
if (stride != width) {
627+
rgb = rgb(cv::Rect(0, 0, width, height)).clone();
628+
}
629+
630+
image = QImage(rgb.data, rgb.cols, rgb.rows, rgb.step,
631+
QImage::Format_RGB888).copy();
632+
633+
qDebug() << "[DEBUG] YUV420 same-fd conversion complete, image size:" << image.size();
634+
635+
munmap(memory, totalSize);
636+
637+
} else if (planes.size() >= 3) {
638+
// Different fds for each plane - map each separately
535639
void *yMem = mmap(NULL, planes[0].length, PROT_READ, MAP_SHARED,
536-
planes[0].fd.get(), 0);
640+
planes[0].fd.get(), planes[0].offset);
537641
void *uMem = mmap(NULL, planes[1].length, PROT_READ, MAP_SHARED,
538-
planes[1].fd.get(), 0);
642+
planes[1].fd.get(), planes[1].offset);
539643
void *vMem = mmap(NULL, planes[2].length, PROT_READ, MAP_SHARED,
540-
planes[2].fd.get(), 0);
644+
planes[2].fd.get(), planes[2].offset);
541645

542646
if (yMem == MAP_FAILED || uMem == MAP_FAILED || vMem == MAP_FAILED) {
543-
qDebug() << "[ERROR] Failed to mmap YUV420 planes";
647+
qDebug() << "[ERROR] Failed to mmap YUV420 planes:" << strerror(errno);
544648
if (yMem != MAP_FAILED) munmap(yMem, planes[0].length);
545649
if (uMem != MAP_FAILED) munmap(uMem, planes[1].length);
546650
if (vMem != MAP_FAILED) munmap(vMem, planes[2].length);
547-
munmap(memory, plane.length);
548651
return QImage();
549652
}
550653

551-
// Create contiguous I420 buffer for OpenCV
552-
// I420 layout: Y plane (height rows), U plane (height/2 rows), V plane (height/2 rows)
553654
size_t ySize = stride * height;
554655
size_t uvStride = stride / 2;
555656
size_t uvSize = uvStride * (height / 2);
556657
std::vector<uint8_t> i420Buffer(ySize + 2 * uvSize);
557658

558-
// Copy Y plane
559659
memcpy(i420Buffer.data(), yMem, ySize);
560-
// Copy U plane
561660
memcpy(i420Buffer.data() + ySize, uMem, uvSize);
562-
// Copy V plane
563661
memcpy(i420Buffer.data() + ySize + uvSize, vMem, uvSize);
564662

565-
// Create OpenCV Mat wrapping the I420 data (height * 3/2 rows, stride columns)
566663
cv::Mat yuv(height * 3 / 2, stride, CV_8UC1, i420Buffer.data());
567664
cv::Mat rgb;
568665
cv::cvtColor(yuv, rgb, cv::COLOR_YUV2RGB_I420);
569666

570-
// Crop to actual width if stride != width
571667
if (stride != width) {
572668
rgb = rgb(cv::Rect(0, 0, width, height)).clone();
573669
}
574670

575671
image = QImage(rgb.data, rgb.cols, rgb.rows, rgb.step,
576672
QImage::Format_RGB888).copy();
577673

578-
qDebug() << "[DEBUG] YUV420 multi-plane conversion complete (OpenCV)";
674+
qDebug() << "[DEBUG] YUV420 multi-fd conversion complete, image size:" << image.size();
579675

580676
munmap(yMem, planes[0].length);
581677
munmap(uMem, planes[1].length);
582678
munmap(vMem, planes[2].length);
583679

584680
} else {
585-
// Single plane - all data contiguous, use OpenCV directly
586-
// The buffer contains Y, U, V planes contiguously
587-
cv::Mat yuv(height * 3 / 2, stride, CV_8UC1,
588-
const_cast<void*>(memory));
681+
// Single plane - all data contiguous
682+
const FrameBuffer::Plane &plane = planes.front();
683+
void *memory = mmap(NULL, plane.length, PROT_READ, MAP_SHARED,
684+
plane.fd.get(), plane.offset);
685+
686+
if (memory == MAP_FAILED) {
687+
qDebug() << "[ERROR] Failed to mmap YUV420 buffer:" << strerror(errno);
688+
return QImage();
689+
}
690+
691+
cv::Mat yuv(height * 3 / 2, stride, CV_8UC1, const_cast<void*>(memory));
589692
cv::Mat rgb;
590693
cv::cvtColor(yuv, rgb, cv::COLOR_YUV2RGB_I420);
591694

592-
// Crop to actual width if stride != width
593695
if (stride != width) {
594696
rgb = rgb(cv::Rect(0, 0, width, height)).clone();
595697
}
596698

597699
image = QImage(rgb.data, rgb.cols, rgb.rows, rgb.step,
598700
QImage::Format_RGB888).copy();
599701

600-
qDebug() << "[DEBUG] YUV420 single-plane conversion complete (OpenCV)";
702+
qDebug() << "[DEBUG] YUV420 single-plane conversion complete, image size:" << image.size();
703+
704+
munmap(memory, plane.length);
601705
}
602706
} else {
603707
qDebug() << "[ERROR] Unsupported pixel format:"
604708
<< QString::fromStdString(cfg.pixelFormat.toString());
605709
}
606710

607-
munmap(memory, plane.length);
608711
break;
609712
}
610713

0 commit comments

Comments
 (0)