|
3 | 3 | #include <QThread> |
4 | 4 | #include <QTimer> |
5 | 5 | #include <cerrno> |
6 | | -#include <chrono> |
7 | 6 | #include <cstring> |
8 | | -#include <iomanip> |
9 | | -#include <iostream> |
10 | 7 | #include <libcamera/formats.h> |
11 | 8 | #include <libcamera/framebuffer_allocator.h> |
12 | 9 | #include <qvideoframe.h> |
13 | 10 | #include <sys/mman.h> |
14 | | -#include <thread> |
15 | 11 |
|
16 | 12 | using namespace libcamera; |
17 | 13 |
|
@@ -540,48 +536,33 @@ QImage LibCameraWorker::convertBufferToImage( |
540 | 536 | } |
541 | 537 | } |
542 | 538 | } else if (cfg.pixelFormat == libcamera::formats::YUV420) { |
543 | | - // YUV420 planar format |
| 539 | + // YUV420 planar format (I420) |
544 | 540 | unsigned int width = cfg.size.width; |
545 | 541 | unsigned int height = cfg.size.height; |
546 | | - unsigned int stride = cfg.stride; |
547 | | - |
548 | | - // Use Format_RGB888 - byte order is R, G, B |
549 | 542 | image = QImage(width, height, QImage::Format_RGB888); |
550 | 543 |
|
551 | 544 | const uint8_t *src = static_cast<const uint8_t *>(memory); |
552 | 545 | const uint8_t *yPlane = src; |
553 | | - |
554 | | - // Try standard I420 order first: Y, U, V |
555 | | - const uint8_t *uPlane = src + stride * height; |
556 | | - const uint8_t *vPlane = uPlane + (stride / 2) * (height / 2); |
557 | | - |
558 | | - qDebug() << "[DEBUG] YUV420 conversion: width=" << width << "height=" << height << "stride=" << stride; |
| 546 | + const uint8_t *uPlane = src + width * height; |
| 547 | + const uint8_t *vPlane = uPlane + (width * height / 4); |
559 | 548 |
|
560 | 549 | for (unsigned int y = 0; y < height; y++) { |
561 | | - uint8_t *destRow = image.scanLine(y); |
562 | 550 | for (unsigned int x = 0; x < width; x++) { |
563 | | - int yVal = yPlane[y * stride + x]; |
564 | | - int uVal = uPlane[(y / 2) * (stride / 2) + (x / 2)]; |
565 | | - int vVal = vPlane[(y / 2) * (stride / 2) + (x / 2)]; |
| 551 | + int yVal = yPlane[y * width + x]; |
| 552 | + int uVal = uPlane[(y / 2) * (width / 2) + (x / 2)]; |
| 553 | + int vVal = vPlane[(y / 2) * (width / 2) + (x / 2)]; |
| 554 | + |
| 555 | + auto clamp = [](int val) { return std::max(0, std::min(255, val)); }; |
566 | 556 |
|
567 | | - // YUV to RGB conversion (BT.601) |
568 | 557 | int c = yVal - 16; |
569 | 558 | int d = uVal - 128; |
570 | 559 | int e = vVal - 128; |
571 | 560 |
|
572 | | - int r = (298 * c + 409 * e + 128) >> 8; |
573 | | - int g = (298 * c - 100 * d - 208 * e + 128) >> 8; |
574 | | - int b = (298 * c + 516 * d + 128) >> 8; |
575 | | - |
576 | | - // Clamp values |
577 | | - r = r < 0 ? 0 : (r > 255 ? 255 : r); |
578 | | - g = g < 0 ? 0 : (g > 255 ? 255 : g); |
579 | | - b = b < 0 ? 0 : (b > 255 ? 255 : b); |
| 561 | + int r = clamp((298 * c + 409 * e + 128) >> 8); |
| 562 | + int g = clamp((298 * c - 100 * d - 208 * e + 128) >> 8); |
| 563 | + int b = clamp((298 * c + 516 * d + 128) >> 8); |
580 | 564 |
|
581 | | - // RGB888 format: B at offset 0, G at offset 1, R at offset 2 |
582 | | - destRow[x * 3 + 0] = static_cast<uint8_t>(b); |
583 | | - destRow[x * 3 + 1] = static_cast<uint8_t>(g); |
584 | | - destRow[x * 3 + 2] = static_cast<uint8_t>(r); |
| 565 | + image.setPixel(x, y, qRgb(r, g, b)); |
585 | 566 | } |
586 | 567 | } |
587 | 568 |
|
@@ -612,7 +593,37 @@ bool LibCameraWorker::configureCamera(libcamera::StreamRole role) { |
612 | 593 | unsigned int defaultHeight = cfg.size.height; |
613 | 594 | float aspectRatio = static_cast<float>(defaultWidth) / defaultHeight; |
614 | 595 |
|
615 | | - cfg.pixelFormat = formats::RGB888; |
| 596 | + std::vector<PixelFormat> pixelFormats = cfg.formats().pixelformats(); |
| 597 | + // Search for the best available pixel format in order of preference |
| 598 | + PixelFormat selectedFormat = formats::RGB888; // fallback |
| 599 | + bool formatFound = false; |
| 600 | + |
| 601 | + // Priority order: BGR888, RGB888, YUYV, MJPEG, YUV420 |
| 602 | + std::vector<PixelFormat> preferredFormats = { |
| 603 | + formats::BGR888, |
| 604 | + formats::RGB888, |
| 605 | + formats::YUYV, |
| 606 | + formats::MJPEG, |
| 607 | + formats::YUV420 |
| 608 | + }; |
| 609 | + |
| 610 | + for (const auto &preferred : preferredFormats) { |
| 611 | + for (const auto &available : pixelFormats) { |
| 612 | + if (available == preferred) { |
| 613 | + selectedFormat = preferred; |
| 614 | + formatFound = true; |
| 615 | + qDebug() << "[INFO] Selected pixel format:" << QString::fromStdString(selectedFormat.toString()); |
| 616 | + break; |
| 617 | + } |
| 618 | + } |
| 619 | + if (formatFound) break; |
| 620 | + } |
| 621 | + |
| 622 | + if (!formatFound) { |
| 623 | + qDebug() << "[WARNING] None of the preferred formats available, using default"; |
| 624 | + } |
| 625 | + |
| 626 | + cfg.pixelFormat = selectedFormat; |
616 | 627 | cfg.size.width = 640; |
617 | 628 | cfg.size.height = static_cast<unsigned int>(640.0f / aspectRatio); |
618 | 629 | cfg.bufferCount = 4; |
|
0 commit comments