Merge branch 'CR_8516_fix_qt_window_zejian.su' into 'jh7110-master'
CR_8516: Fix the qt window size and simplify the qt ping-pang buffer See merge request sdk/buildroot!158
This commit is contained in:
@@ -1,284 +0,0 @@
|
||||
From 2982813d58c13077c06d1c3c44cd60b0b93d1f4e Mon Sep 17 00:00:00 2001
|
||||
From: "zejian.su" <zejian.su@starfivetech.com>
|
||||
Date: Thu, 12 Oct 2023 11:54:09 +0800
|
||||
Subject: [PATCH 1/4] Make libcamera-hello run normally
|
||||
|
||||
---
|
||||
core/libcamera_app.cpp | 53 ++++++++++++++------------
|
||||
preview/drm_preview.cpp | 84 +++++++++++++++++++++++++++++++++++------
|
||||
2 files changed, 100 insertions(+), 37 deletions(-)
|
||||
|
||||
diff --git a/core/libcamera_app.cpp b/core/libcamera_app.cpp
|
||||
index d3a6b63..cc76e9b 100644
|
||||
--- a/core/libcamera_app.cpp
|
||||
+++ b/core/libcamera_app.cpp
|
||||
@@ -247,23 +247,24 @@ void LibcameraApp::ConfigureViewfinder()
|
||||
if (!configuration_)
|
||||
throw std::runtime_error("failed to generate viewfinder configuration");
|
||||
|
||||
- Size size(1280, 960);
|
||||
- auto area = camera_->properties().get(properties::PixelArrayActiveAreas);
|
||||
+ //Size size(1280, 960);
|
||||
+ Size size = configuration_->at(0).size;
|
||||
+ //auto area = camera_->properties().get(properties::PixelArrayActiveAreas);
|
||||
if (options_->viewfinder_width && options_->viewfinder_height)
|
||||
size = Size(options_->viewfinder_width, options_->viewfinder_height);
|
||||
- else if (area)
|
||||
- {
|
||||
- // The idea here is that most sensors will have a 2x2 binned mode that
|
||||
- // we can pick up. If it doesn't, well, you can always specify the size
|
||||
- // you want exactly with the viewfinder_width/height options_->
|
||||
- size = (*area)[0].size() / 2;
|
||||
- // If width and height were given, we might be switching to capture
|
||||
- // afterwards - so try to match the field of view.
|
||||
- if (options_->width && options_->height)
|
||||
- size = size.boundedToAspectRatio(Size(options_->width, options_->height));
|
||||
- size.alignDownTo(2, 2); // YUV420 will want to be even
|
||||
- LOG(2, "Viewfinder size chosen is " << size.toString());
|
||||
- }
|
||||
+ //else if (area)
|
||||
+ //{
|
||||
+ // // The idea here is that most sensors will have a 2x2 binned mode that
|
||||
+ // // we can pick up. If it doesn't, well, you can always specify the size
|
||||
+ // // you want exactly with the viewfinder_width/height options_->
|
||||
+ // size = (*area)[0].size() / 2;
|
||||
+ // // If width and height were given, we might be switching to capture
|
||||
+ // // afterwards - so try to match the field of view.
|
||||
+ // if (options_->width && options_->height)
|
||||
+ // size = size.boundedToAspectRatio(Size(options_->width, options_->height));
|
||||
+ // size.alignDownTo(2, 2); // YUV420 will want to be even
|
||||
+ // LOG(2, "Viewfinder size chosen is " << size.toString());
|
||||
+ //}
|
||||
|
||||
// Finally trim the image size to the largest that the preview can handle.
|
||||
Size max_size;
|
||||
@@ -275,7 +276,7 @@ void LibcameraApp::ConfigureViewfinder()
|
||||
}
|
||||
|
||||
// Now we get to override any of the default settings from the options_->
|
||||
- configuration_->at(0).pixelFormat = libcamera::formats::YUV420;
|
||||
+ //configuration_->at(0).pixelFormat = libcamera::formats::YUV420;
|
||||
configuration_->at(0).size = size;
|
||||
if (options_->viewfinder_buffer_count > 0)
|
||||
configuration_->at(0).bufferCount = options_->viewfinder_buffer_count;
|
||||
@@ -286,7 +287,7 @@ void LibcameraApp::ConfigureViewfinder()
|
||||
lores_size.alignDownTo(2, 2);
|
||||
if (lores_size.width > size.width || lores_size.height > size.height)
|
||||
throw std::runtime_error("Low res image larger than viewfinder");
|
||||
- configuration_->at(lores_stream_num).pixelFormat = libcamera::formats::YUV420;
|
||||
+ //configuration_->at(lores_stream_num).pixelFormat = libcamera::formats::YUV420;
|
||||
configuration_->at(lores_stream_num).size = lores_size;
|
||||
configuration_->at(lores_stream_num).bufferCount = configuration_->at(0).bufferCount;
|
||||
}
|
||||
@@ -297,7 +298,7 @@ void LibcameraApp::ConfigureViewfinder()
|
||||
if (have_raw_stream)
|
||||
{
|
||||
configuration_->at(raw_stream_num).size = options_->viewfinder_mode.Size();
|
||||
- configuration_->at(raw_stream_num).pixelFormat = mode_to_pixel_format(options_->viewfinder_mode);
|
||||
+ //configuration_->at(raw_stream_num).pixelFormat = mode_to_pixel_format(options_->viewfinder_mode);
|
||||
configuration_->at(raw_stream_num).bufferCount = configuration_->at(0).bufferCount;
|
||||
}
|
||||
|
||||
@@ -335,8 +336,9 @@ void LibcameraApp::ConfigureStill(unsigned int flags)
|
||||
configuration_->at(0).pixelFormat = libcamera::formats::BGR888;
|
||||
else if (flags & FLAG_STILL_RGB)
|
||||
configuration_->at(0).pixelFormat = libcamera::formats::RGB888;
|
||||
- else
|
||||
- configuration_->at(0).pixelFormat = libcamera::formats::YUV420;
|
||||
+ else {
|
||||
+ //configuration_->at(0).pixelFormat = libcamera::formats::YUV420;
|
||||
+ }
|
||||
if ((flags & FLAG_STILL_BUFFER_MASK) == FLAG_STILL_DOUBLE_BUFFER)
|
||||
configuration_->at(0).bufferCount = 2;
|
||||
else if ((flags & FLAG_STILL_BUFFER_MASK) == FLAG_STILL_TRIPLE_BUFFER)
|
||||
@@ -358,8 +360,8 @@ void LibcameraApp::ConfigureStill(unsigned int flags)
|
||||
configuration_->at(1).pixelFormat = mode_to_pixel_format(options_->mode);
|
||||
}
|
||||
configuration_->at(1).bufferCount = configuration_->at(0).bufferCount;
|
||||
-
|
||||
configureDenoise(options_->denoise == "auto" ? "cdn_hq" : options_->denoise);
|
||||
+
|
||||
setupCapture();
|
||||
|
||||
streams_["still"] = configuration_->at(0).stream();
|
||||
@@ -392,7 +394,7 @@ void LibcameraApp::ConfigureVideo(unsigned int flags)
|
||||
|
||||
// Now we get to override any of the default settings from the options_->
|
||||
StreamConfiguration &cfg = configuration_->at(0);
|
||||
- cfg.pixelFormat = libcamera::formats::YUV420;
|
||||
+ //cfg.pixelFormat = libcamera::formats::YUV420;
|
||||
cfg.bufferCount = 6; // 6 buffers is better than 4
|
||||
if (options_->buffer_count > 0)
|
||||
cfg.bufferCount = options_->buffer_count;
|
||||
@@ -431,7 +433,7 @@ void LibcameraApp::ConfigureVideo(unsigned int flags)
|
||||
if (lores_size.width > configuration_->at(0).size.width ||
|
||||
lores_size.height > configuration_->at(0).size.height)
|
||||
throw std::runtime_error("Low res image larger than video");
|
||||
- configuration_->at(lores_index).pixelFormat = libcamera::formats::YUV420;
|
||||
+ //configuration_->at(lores_index).pixelFormat = libcamera::formats::YUV420;
|
||||
configuration_->at(lores_index).size = lores_size;
|
||||
configuration_->at(lores_index).bufferCount = configuration_->at(0).bufferCount;
|
||||
}
|
||||
@@ -959,8 +961,9 @@ void LibcameraApp::previewThread()
|
||||
preview_cond_var_.wait(lock);
|
||||
}
|
||||
|
||||
- if (item.stream->configuration().pixelFormat != libcamera::formats::YUV420)
|
||||
- throw std::runtime_error("Preview windows only support YUV420");
|
||||
+ if (item.stream->configuration().pixelFormat != libcamera::formats::YUV420 &&
|
||||
+ item.stream->configuration().pixelFormat != libcamera::formats::NV12)
|
||||
+ throw std::runtime_error("Preview windows only support YUV420 and NV12");
|
||||
|
||||
StreamInfo info = GetStreamInfo(item.stream);
|
||||
FrameBuffer *buffer = item.completed_request->buffers[item.stream];
|
||||
diff --git a/preview/drm_preview.cpp b/preview/drm_preview.cpp
|
||||
index 4d6cf0d..38fc6a2 100644
|
||||
--- a/preview/drm_preview.cpp
|
||||
+++ b/preview/drm_preview.cpp
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <drm_mode.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
+#include <fcntl.h>
|
||||
+#include <libcamera/formats.h>
|
||||
|
||||
#include "core/options.hpp"
|
||||
|
||||
@@ -48,6 +50,7 @@ private:
|
||||
void findPlane();
|
||||
int drmfd_;
|
||||
int conId_;
|
||||
+ drmModeConnector *con_;
|
||||
uint32_t crtcId_;
|
||||
int crtcIdx_;
|
||||
uint32_t planeId_;
|
||||
@@ -93,10 +96,21 @@ void DrmPreview::findCrtc()
|
||||
if (con->encoder_id)
|
||||
{
|
||||
enc = drmModeGetEncoder(drmfd_, con->encoder_id);
|
||||
- if (enc->crtc_id)
|
||||
- {
|
||||
- crtc = drmModeGetCrtc(drmfd_, enc->crtc_id);
|
||||
- }
|
||||
+ //if (enc->crtc_id)
|
||||
+ //{
|
||||
+ // crtc = drmModeGetCrtc(drmfd_, enc->crtc_id);
|
||||
+ //}
|
||||
+ } else
|
||||
+ {
|
||||
+ enc = drmModeGetEncoder(drmfd_, con->encoders[0]);
|
||||
+ }
|
||||
+
|
||||
+ if (enc->crtc_id)
|
||||
+ {
|
||||
+ crtc = drmModeGetCrtc(drmfd_, enc->crtc_id);
|
||||
+ } else
|
||||
+ {
|
||||
+ crtc = drmModeGetCrtc(drmfd_, res->crtcs[0]);
|
||||
}
|
||||
|
||||
if (!conId_ && crtc)
|
||||
@@ -158,6 +172,8 @@ void DrmPreview::findCrtc()
|
||||
throw std::runtime_error("connector supports no mode");
|
||||
}
|
||||
|
||||
+ con_ = c;
|
||||
+
|
||||
if (options_->fullscreen || width_ == 0 || height_ == 0)
|
||||
{
|
||||
drmModeCrtc *crtc = drmModeGetCrtc(drmfd_, crtcId_);
|
||||
@@ -225,10 +241,13 @@ void DrmPreview::findPlane()
|
||||
|
||||
DrmPreview::DrmPreview(Options const *options) : Preview(options), last_fd_(-1), first_time_(true)
|
||||
{
|
||||
- drmfd_ = drmOpen("vc4", NULL);
|
||||
+ //drmfd_ = drmOpen("vc4", NULL);
|
||||
+ drmfd_ = drmOpen("starfive", NULL);
|
||||
if (drmfd_ < 0)
|
||||
throw std::runtime_error("drmOpen failed: " + std::string(ERRSTR));
|
||||
|
||||
+ drmSetClientCap(drmfd_, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
|
||||
+
|
||||
x_ = options_->preview_x;
|
||||
y_ = options_->preview_y;
|
||||
width_ = options_->preview_width;
|
||||
@@ -243,7 +262,8 @@ DrmPreview::DrmPreview(Options const *options) : Preview(options), last_fd_(-1),
|
||||
|
||||
conId_ = 0;
|
||||
findCrtc();
|
||||
- out_fourcc_ = DRM_FORMAT_YUV420;
|
||||
+ //out_fourcc_ = DRM_FORMAT_YUV420;
|
||||
+ out_fourcc_ = DRM_FORMAT_NV12;
|
||||
findPlane();
|
||||
}
|
||||
catch (std::exception const &e)
|
||||
@@ -347,6 +367,7 @@ static void setup_colour_space(int fd, int plane_id, std::optional<libcamera::Co
|
||||
|
||||
void DrmPreview::makeBuffer(int fd, size_t size, StreamInfo const &info, Buffer &buffer)
|
||||
{
|
||||
+ unsigned int width = info.width, height = info.height, stride = info.stride;
|
||||
if (first_time_)
|
||||
{
|
||||
first_time_ = false;
|
||||
@@ -361,13 +382,52 @@ void DrmPreview::makeBuffer(int fd, size_t size, StreamInfo const &info, Buffer
|
||||
if (drmPrimeFDToHandle(drmfd_, fd, &buffer.bo_handle))
|
||||
throw std::runtime_error("drmPrimeFDToHandle failed for fd " + std::to_string(fd));
|
||||
|
||||
- uint32_t offsets[4] =
|
||||
- { 0, info.stride * info.height, info.stride * info.height + (info.stride / 2) * (info.height / 2) };
|
||||
- uint32_t pitches[4] = { info.stride, info.stride / 2, info.stride / 2 };
|
||||
- uint32_t bo_handles[4] = { buffer.bo_handle, buffer.bo_handle, buffer.bo_handle };
|
||||
-
|
||||
- if (drmModeAddFB2(drmfd_, info.width, info.height, out_fourcc_, bo_handles, pitches, offsets, &buffer.fb_handle, 0))
|
||||
+ if (out_fourcc_ == DRM_FORMAT_YUV420) {
|
||||
+ uint32_t offsets[4] = { 0, stride * height, stride * height + (stride / 2) * (height / 2) };
|
||||
+ uint32_t pitches[4] = { stride, stride / 2, stride / 2 };
|
||||
+ uint32_t bo_handles[4] = { buffer.bo_handle, buffer.bo_handle, buffer.bo_handle };
|
||||
+
|
||||
+ if (drmModeAddFB2(drmfd_, width, height, out_fourcc_, bo_handles, pitches, offsets, &buffer.fb_handle, 0))
|
||||
+ throw std::runtime_error("YUV420 drmModeAddFB2 failed: " + std::string(ERRSTR));
|
||||
+ } else if (out_fourcc_ == DRM_FORMAT_NV12 || out_fourcc_ == DRM_FORMAT_NV21) {
|
||||
+ uint32_t offsets[4] = { 0, stride * height};
|
||||
+ uint32_t pitches[4] = { stride, stride};
|
||||
+ uint32_t bo_handles[4] = { buffer.bo_handle, buffer.bo_handle};
|
||||
+
|
||||
+ if (drmModeAddFB2(drmfd_, width, height, out_fourcc_, bo_handles, pitches, offsets, &buffer.fb_handle, 0))
|
||||
+ throw std::runtime_error("NV12/21 drmModeAddFB2 failed: " + std::string(ERRSTR));
|
||||
+ } else
|
||||
throw std::runtime_error("drmModeAddFB2 failed: " + std::string(ERRSTR));
|
||||
+
|
||||
+ /* find preferred mode */
|
||||
+ drmModeModeInfo *modeptr = NULL, *preferred = NULL;
|
||||
+ for (int m = 0; m < con_->count_modes; m++) {
|
||||
+ modeptr = &con_->modes[m];
|
||||
+ if (modeptr->hdisplay == width && modeptr->vdisplay == height) {
|
||||
+ preferred = modeptr;
|
||||
+ std::cout << "find the matched mode, modes index= "
|
||||
+ << m << ", " << width << "x" << height << std::endl;
|
||||
+ break;
|
||||
+ }
|
||||
+ if (modeptr->type & DRM_MODE_TYPE_PREFERRED) {
|
||||
+ preferred = modeptr;
|
||||
+ std::cout << "find perferred mode, modes index= " << m << std::endl;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!preferred)
|
||||
+ preferred = &con_->modes[0];
|
||||
+
|
||||
+ // set default
|
||||
+ if (drmModeSetCrtc(drmfd_, crtcId_, buffer.fb_handle, 0, 0,
|
||||
+ (uint32_t *)&conId_, 1, preferred)) {
|
||||
+ throw std::runtime_error("drmModeSetCrtc() failed");
|
||||
+ }
|
||||
+
|
||||
+ screen_width_ = preferred->hdisplay;
|
||||
+ screen_height_ = preferred->vdisplay;
|
||||
+ width_ = width;
|
||||
+ height_ = height;
|
||||
}
|
||||
|
||||
void DrmPreview::Show(int fd, libcamera::Span<uint8_t> span, StreamInfo const &info)
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
From d02d3b3a6c0abdfd8a89ee92447df7d8d48639d5 Mon Sep 17 00:00:00 2001
|
||||
From: "zejian.su" <zejian.su@starfivetech.com>
|
||||
Date: Thu, 12 Oct 2023 11:55:47 +0800
|
||||
Subject: [PATCH 2/4] Make libcamera-jpeg run normally
|
||||
|
||||
---
|
||||
apps/libcamera_jpeg.cpp | 28 +++++----
|
||||
core/CMakeLists.txt | 2 +-
|
||||
core/cvt_color_format.cpp | 119 ++++++++++++++++++++++++++++++++++++++
|
||||
image/jpeg.cpp | 1 +
|
||||
4 files changed, 134 insertions(+), 16 deletions(-)
|
||||
create mode 100755 core/cvt_color_format.cpp
|
||||
|
||||
diff --git a/apps/libcamera_jpeg.cpp b/apps/libcamera_jpeg.cpp
|
||||
index 05a632b..b791960 100644
|
||||
--- a/apps/libcamera_jpeg.cpp
|
||||
+++ b/apps/libcamera_jpeg.cpp
|
||||
@@ -15,6 +15,8 @@
|
||||
using namespace std::placeholders;
|
||||
using libcamera::Stream;
|
||||
|
||||
+void NV12ToYUV420(const libcamera::Span<uint8_t> &mem, std::vector<libcamera::Span<uint8_t>> &yuv420, StreamInfo &info);
|
||||
+
|
||||
class LibcameraJpegApp : public LibcameraApp
|
||||
{
|
||||
public:
|
||||
@@ -61,10 +63,19 @@ static void event_loop(LibcameraJpegApp &app)
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
if (options->timeout && now - start_time > std::chrono::milliseconds(options->timeout))
|
||||
{
|
||||
+ Stream *stream = app.ViewfinderStream();
|
||||
+ StreamInfo info = app.GetStreamInfo(stream);
|
||||
+ CompletedRequestPtr &payload = std::get<CompletedRequestPtr>(msg.payload);
|
||||
+ const std::vector<libcamera::Span<uint8_t>> mem = app.Mmap(payload->buffers[stream]);
|
||||
+ std::vector<libcamera::Span<uint8_t>> yuv420;
|
||||
+
|
||||
+ NV12ToYUV420(mem[0], yuv420, info);
|
||||
app.StopCamera();
|
||||
app.Teardown();
|
||||
- app.ConfigureStill();
|
||||
- app.StartCamera();
|
||||
+
|
||||
+ jpeg_save(yuv420, info, payload->metadata, options->output, app.CameraModel(), options);
|
||||
+ delete[] yuv420[0].data();
|
||||
+ return;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -72,19 +83,6 @@ static void event_loop(LibcameraJpegApp &app)
|
||||
app.ShowPreview(completed_request, app.ViewfinderStream());
|
||||
}
|
||||
}
|
||||
- // In still capture mode, save a jpeg and quit.
|
||||
- else if (app.StillStream())
|
||||
- {
|
||||
- app.StopCamera();
|
||||
- LOG(1, "Still capture image received");
|
||||
-
|
||||
- Stream *stream = app.StillStream();
|
||||
- StreamInfo info = app.GetStreamInfo(stream);
|
||||
- CompletedRequestPtr &payload = std::get<CompletedRequestPtr>(msg.payload);
|
||||
- const std::vector<libcamera::Span<uint8_t>> mem = app.Mmap(payload->buffers[stream]);
|
||||
- jpeg_save(mem, info, payload->metadata, options->output, app.CameraModel(), options);
|
||||
- return;
|
||||
- }
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
|
||||
index b601538..5d9ee30 100644
|
||||
--- a/core/CMakeLists.txt
|
||||
+++ b/core/CMakeLists.txt
|
||||
@@ -7,7 +7,7 @@ find_package(Boost REQUIRED COMPONENTS program_options)
|
||||
add_custom_target(VersionCpp ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR} -P ${CMAKE_CURRENT_LIST_DIR}/version.cmake)
|
||||
set_source_files_properties(version.cpp PROPERTIES GENERATED 1)
|
||||
|
||||
-add_library(libcamera_app libcamera_app.cpp post_processor.cpp version.cpp options.cpp)
|
||||
+add_library(libcamera_app libcamera_app.cpp post_processor.cpp version.cpp options.cpp cvt_color_format.cpp)
|
||||
add_dependencies(libcamera_app VersionCpp)
|
||||
|
||||
set_target_properties(libcamera_app PROPERTIES PREFIX "" IMPORT_PREFIX "" VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR})
|
||||
diff --git a/core/cvt_color_format.cpp b/core/cvt_color_format.cpp
|
||||
new file mode 100755
|
||||
index 0000000..9ff2b6b
|
||||
--- /dev/null
|
||||
+++ b/core/cvt_color_format.cpp
|
||||
@@ -0,0 +1,119 @@
|
||||
+/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
+/*
|
||||
+ * Copyright (C) 2023, Starfive Technology Co., Ltd.
|
||||
+ *
|
||||
+ * cvt_color_format.cpp - convert other format to yuv420.
|
||||
+ */
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+#include <unistd.h>
|
||||
+#include <sys/types.h>
|
||||
+#include "core/still_options.hpp"
|
||||
+
|
||||
+void NV12ToYUV420(const uint8_t *mem, uint8_t *dst, const StreamInfo &info)
|
||||
+{
|
||||
+ const uint8_t *src = mem;
|
||||
+ uint32_t width = info.width, height = info.height, stride = info.stride;
|
||||
+ uint8_t *u = dst + height * stride;
|
||||
+ uint8_t *v = u + ((height * width) >> 2);
|
||||
+ uint32_t i;
|
||||
+
|
||||
+ memcpy(dst, src, height * stride);
|
||||
+
|
||||
+ src += height * stride;
|
||||
+ for(i = 0; i < (height * width) >> 2; i++, src += 2)
|
||||
+ u[i] = src[0], v[i] = src[1];
|
||||
+}
|
||||
+
|
||||
+void NV12ToYUV420(const libcamera::Span<uint8_t> &mem, uint8_t *dst, const StreamInfo &info)
|
||||
+{
|
||||
+ NV12ToYUV420((const uint8_t *)(mem.data()), dst, info);
|
||||
+/*
|
||||
+ const uint8_t *src = mem.data();
|
||||
+ uint32_t width = info.width, height = info.height, stride = info.stride;
|
||||
+ uint8_t *u = dst + height * stride;
|
||||
+ uint8_t *v = u + ((height * width) >> 2);
|
||||
+ uint32_t i;
|
||||
+
|
||||
+ memcpy(dst, src, height * stride);
|
||||
+
|
||||
+ src += height * stride;
|
||||
+ for(i = 0; i < (height * width) >> 2; i++, src += 2)
|
||||
+ u[i] = src[0], v[i] = src[1];
|
||||
+*/
|
||||
+}
|
||||
+
|
||||
+void NV12ToYUV420(const libcamera::Span<uint8_t> &mem, std::vector<libcamera::Span<uint8_t>> &yuv420, StreamInfo &info)
|
||||
+{
|
||||
+ uint32_t imgBufSize = info.height * info.stride + ((info.height * info.width) >> 1);
|
||||
+ uint8_t * yuv420Buf = new uint8_t[imgBufSize];
|
||||
+
|
||||
+ if(!yuv420Buf)
|
||||
+ throw std::runtime_error("fail to apply memory");
|
||||
+
|
||||
+ yuv420.push_back(libcamera::Span<uint8_t>(yuv420Buf, imgBufSize));
|
||||
+
|
||||
+ NV12ToYUV420(mem, yuv420Buf, info);
|
||||
+ info.pixel_format = libcamera::formats::YUV420;
|
||||
+}
|
||||
+
|
||||
+template<int R>
|
||||
+void NV12ToRGB888(const libcamera::Span<uint8_t> &mem, uint8_t *dst, const StreamInfo &info)
|
||||
+{
|
||||
+ uint32_t width = info.width, height = info.height, stride = info.stride;
|
||||
+ const uint8_t *yRow = mem.data();
|
||||
+ const uint8_t *uv = yRow + height * stride;
|
||||
+ int ri = R ? 2 : 0;
|
||||
+
|
||||
+ for(uint32_t i = 0; i < height; i++, yRow += stride, dst += 3 * width)
|
||||
+ {
|
||||
+ const uint8_t * curUV = uv;
|
||||
+ uint8_t * curDst = dst;
|
||||
+ for(uint32_t j = 0; j < width; j++, curDst += 3)
|
||||
+ {
|
||||
+ int32_t y = (int32_t)yRow[j] - 16;
|
||||
+ int32_t u = (int32_t)curUV[0] - 128;
|
||||
+ int32_t v = (int32_t)curUV[1] - 128;
|
||||
+ int32_t val;
|
||||
+
|
||||
+ val = (1192 * y + 2066 * u - v) >> 10;
|
||||
+ curDst[ri] = val < 0 ? 0 : (val > 255 ? 255 : (uint8_t)val);
|
||||
+ val = (1192 * y - 401 * u - 833 * v) >> 10;
|
||||
+ curDst[1] = val < 0 ? 0 : (val > 255 ? 255 : (uint8_t)val);
|
||||
+ val = (1192 * y - 2 * u + 1634 * v) >> 10;
|
||||
+ curDst[2 - ri] = val < 0 ? 0 : (val > 255 ? 255 : (uint8_t)val);
|
||||
+
|
||||
+ if(j & 1)
|
||||
+ curUV += 2;
|
||||
+ }
|
||||
+ if(i & 1)
|
||||
+ uv += width;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+template<int R>
|
||||
+void RGB888FromNV12(const libcamera::Span<uint8_t> &mem, std::vector<libcamera::Span<uint8_t>> &rgb888, StreamInfo &info)
|
||||
+{
|
||||
+ uint32_t imgBufSize = info.height * info.width * 3;
|
||||
+ uint8_t * rgb888Buf = new uint8_t[imgBufSize];
|
||||
+
|
||||
+ if(!rgb888Buf)
|
||||
+ throw std::runtime_error("fail to apply memory");
|
||||
+
|
||||
+ rgb888.push_back(libcamera::Span<uint8_t>(rgb888Buf, imgBufSize));
|
||||
+
|
||||
+ NV12ToRGB888<R>(mem, rgb888Buf, info);
|
||||
+ info.stride = 3 * info.width;
|
||||
+}
|
||||
+
|
||||
+void NV12ToRGB888(const libcamera::Span<uint8_t> &mem, std::vector<libcamera::Span<uint8_t>> &rgb888, StreamInfo &info)
|
||||
+{
|
||||
+ RGB888FromNV12<0>(mem, rgb888, info);
|
||||
+ info.pixel_format = libcamera::formats::RGB888;
|
||||
+}
|
||||
+
|
||||
+void NV12ToBGR888(const libcamera::Span<uint8_t> &mem, std::vector<libcamera::Span<uint8_t>> &rgb888, StreamInfo &info)
|
||||
+{
|
||||
+ RGB888FromNV12<2>(mem, rgb888, info);
|
||||
+ info.pixel_format = libcamera::formats::BGR888;
|
||||
+}
|
||||
\ No newline at end of file
|
||||
diff --git a/image/jpeg.cpp b/image/jpeg.cpp
|
||||
index e3516ef..872f5c6 100644
|
||||
--- a/image/jpeg.cpp
|
||||
+++ b/image/jpeg.cpp
|
||||
@@ -447,6 +447,7 @@ static void create_exif_data(std::vector<libcamera::Span<uint8_t>> const &mem, S
|
||||
exif = exif_data_new();
|
||||
if (!exif)
|
||||
throw std::runtime_error("failed to allocate EXIF data");
|
||||
+
|
||||
exif_data_set_byte_order(exif, exif_byte_order);
|
||||
|
||||
// First add some fixed EXIF tags.
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
From f79f0914c3f8e740cf653da0dd14e5664760188d Mon Sep 17 00:00:00 2001
|
||||
From: "zejian.su" <zejian.su@starfivetech.com>
|
||||
Date: Thu, 12 Oct 2023 11:56:48 +0800
|
||||
Subject: [PATCH 3/4] Make libcamera-still run normally
|
||||
|
||||
---
|
||||
apps/libcamera_still.cpp | 137 +++++++++++++++++++++++++--------------
|
||||
image/dng.cpp | 1 -
|
||||
2 files changed, 88 insertions(+), 50 deletions(-)
|
||||
|
||||
diff --git a/apps/libcamera_still.cpp b/apps/libcamera_still.cpp
|
||||
index 856f1be..bd44818 100644
|
||||
--- a/apps/libcamera_still.cpp
|
||||
+++ b/apps/libcamera_still.cpp
|
||||
@@ -74,22 +74,79 @@ static void update_latest_link(std::string const &filename, StillOptions const *
|
||||
}
|
||||
}
|
||||
|
||||
+void cvtRawData(const libcamera::Span<uint8_t> &mem, std::vector<libcamera::Span<uint8_t>> &packRaw, StreamInfo &info)
|
||||
+{
|
||||
+ const uint8_t *src = (uint8_t *)mem.data();
|
||||
+ uint32_t width = info.width, height = info.height;
|
||||
+ uint32_t bufSize = (width * height) + ((width * height) >> 1);
|
||||
+ uint8_t * dstBuf = new uint8_t[bufSize];
|
||||
+ uint8_t * dst = dstBuf;
|
||||
+ uint32_t srcStride = ((width * 12 / 8 + 8 * 16 - 1) / (8 * 16)) * 128;
|
||||
+
|
||||
+ if(!dst)
|
||||
+ throw std::runtime_error("fail to apply memory");
|
||||
+
|
||||
+ for(uint32_t i = 0; i < height; i++, src += srcStride, dst += (3 * width) >> 1) {
|
||||
+ const uint8_t *srcRow = src;
|
||||
+ uint8_t * dstRow = dst;
|
||||
+ for(uint32_t j = 0; j < width; j += 2, srcRow += 3, dstRow += 3) {
|
||||
+ dstRow[0] = ((srcRow[1] & 0xf) << 4) | (srcRow[0] >> 4);
|
||||
+ dstRow[1] = srcRow[2];
|
||||
+ dstRow[2] = (srcRow[1] & 0xf0) | (srcRow[0] & 0xf);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ packRaw.push_back(libcamera::Span<uint8_t>(dstBuf, bufSize));
|
||||
+
|
||||
+ if(libcamera::formats::SRGGB12 == info.pixel_format)
|
||||
+ info.pixel_format = libcamera::formats::SRGGB12_CSI2P;
|
||||
+ else if(libcamera::formats::SGRBG12 == info.pixel_format)
|
||||
+ info.pixel_format = libcamera::formats::SGRBG12_CSI2P;
|
||||
+ else if(libcamera::formats::SBGGR12 == info.pixel_format)
|
||||
+ info.pixel_format = libcamera::formats::SBGGR12_CSI2P;
|
||||
+ else if(libcamera::formats::SGBRG12 == info.pixel_format)
|
||||
+ info.pixel_format = libcamera::formats::SGBRG12_CSI2P;
|
||||
+ else
|
||||
+ throw std::runtime_error("unsupported Bayer format");
|
||||
+ info.stride = (3 * width) >> 1;
|
||||
+}
|
||||
+
|
||||
+void NV12ToYUV420(const libcamera::Span<uint8_t> &mem, std::vector<libcamera::Span<uint8_t>> &yuv420, StreamInfo &info);
|
||||
+void NV12ToRGB888(const libcamera::Span<uint8_t> &mem, std::vector<libcamera::Span<uint8_t>> &rgb888, StreamInfo &info);
|
||||
+void NV12ToBGR888(const libcamera::Span<uint8_t> &mem, std::vector<libcamera::Span<uint8_t>> &rgb888, StreamInfo &info);
|
||||
+
|
||||
static void save_image(LibcameraStillApp &app, CompletedRequestPtr &payload, Stream *stream,
|
||||
std::string const &filename)
|
||||
{
|
||||
StillOptions const *options = app.GetOptions();
|
||||
StreamInfo info = app.GetStreamInfo(stream);
|
||||
const std::vector<libcamera::Span<uint8_t>> mem = app.Mmap(payload->buffers[stream]);
|
||||
- if (stream == app.RawStream())
|
||||
- dng_save(mem, info, payload->metadata, filename, app.CameraModel(), options);
|
||||
- else if (options->encoding == "jpg")
|
||||
- jpeg_save(mem, info, payload->metadata, filename, app.CameraModel(), options);
|
||||
- else if (options->encoding == "png")
|
||||
- png_save(mem, info, filename, options);
|
||||
- else if (options->encoding == "bmp")
|
||||
- bmp_save(mem, info, filename, options);
|
||||
- else
|
||||
- yuv_save(mem, info, filename, options);
|
||||
+ if (stream == app.RawStream()) {
|
||||
+ std::vector<libcamera::Span<uint8_t>> packRaw;
|
||||
+ cvtRawData(mem[0], packRaw, info);
|
||||
+ dng_save(packRaw, info, payload->metadata, filename, app.CameraModel(), options);
|
||||
+ delete[] packRaw[0].data();
|
||||
+ } else if (options->encoding == "jpg") {
|
||||
+ std::vector<libcamera::Span<uint8_t>> yuv420;
|
||||
+ NV12ToYUV420(mem[0], yuv420, info);
|
||||
+ jpeg_save(yuv420, info, payload->metadata, filename, app.CameraModel(), options);
|
||||
+ delete[] yuv420[0].data();
|
||||
+ } else if (options->encoding == "png") {
|
||||
+ std::vector<libcamera::Span<uint8_t>> rgb888;
|
||||
+ NV12ToBGR888(mem[0], rgb888, info);
|
||||
+ png_save(rgb888, info, filename, options);
|
||||
+ delete[] rgb888[0].data();
|
||||
+ } else if (options->encoding == "bmp") {
|
||||
+ std::vector<libcamera::Span<uint8_t>> rgb888;
|
||||
+ NV12ToRGB888(mem[0], rgb888, info);
|
||||
+ bmp_save(rgb888, info, filename, options);
|
||||
+ delete[] rgb888[0].data();
|
||||
+ } else {
|
||||
+ std::vector<libcamera::Span<uint8_t>> yuv420;
|
||||
+ NV12ToYUV420(mem[0], yuv420, info);
|
||||
+ yuv_save(yuv420, info, filename, options);
|
||||
+ delete[] yuv420[0].data();
|
||||
+ }
|
||||
LOG(2, "Saved image " << info.width << " x " << info.height << " to file " << filename);
|
||||
}
|
||||
|
||||
@@ -193,7 +250,7 @@ static void event_loop(LibcameraStillApp &app)
|
||||
}
|
||||
}
|
||||
else
|
||||
- app.ConfigureViewfinder();
|
||||
+ app.ConfigureStill();
|
||||
app.StartCamera();
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
auto timelapse_time = start_time;
|
||||
@@ -234,7 +291,7 @@ static void event_loop(LibcameraStillApp &app)
|
||||
// In viewfinder mode, run until the timeout or keypress. When that happens,
|
||||
// if the "--autofocus-on-capture" option was set, trigger an AF scan and wait
|
||||
// for it to complete. Then switch to capture mode if an output was requested.
|
||||
- if (app.ViewfinderStream())
|
||||
+ if (app.StillStream())
|
||||
{
|
||||
LOG(2, "Viewfinder frame " << count);
|
||||
timelapse_frames++;
|
||||
@@ -280,47 +337,29 @@ static void event_loop(LibcameraStillApp &app)
|
||||
keypressed = false;
|
||||
af_wait_state = AF_WAIT_NONE;
|
||||
timelapse_time = std::chrono::high_resolution_clock::now();
|
||||
+
|
||||
+ save_images(app, completed_request);
|
||||
+ if (!options->metadata.empty())
|
||||
+ save_metadata(options, completed_request->metadata);
|
||||
+
|
||||
app.StopCamera();
|
||||
app.Teardown();
|
||||
- app.ConfigureStill(still_flags);
|
||||
- if (options->af_on_capture)
|
||||
- {
|
||||
- libcamera::ControlList cl;
|
||||
- cl.set(libcamera::controls::AfMode, libcamera::controls::AfModeAuto);
|
||||
- cl.set(libcamera::controls::AfTrigger, libcamera::controls::AfTriggerCancel);
|
||||
- app.SetControls(cl);
|
||||
- }
|
||||
- app.StartCamera();
|
||||
- }
|
||||
- else
|
||||
- app.ShowPreview(completed_request, app.ViewfinderStream());
|
||||
- }
|
||||
- // In still capture mode, save a jpeg. Go back to viewfinder if in timelapse mode,
|
||||
- // otherwise quit.
|
||||
- else if (app.StillStream())
|
||||
- {
|
||||
- app.StopCamera();
|
||||
- LOG(1, "Still capture image received");
|
||||
- save_images(app, completed_request);
|
||||
- if (!options->metadata.empty())
|
||||
- save_metadata(options, completed_request->metadata);
|
||||
- timelapse_frames = 0;
|
||||
- if (!options->immediate && (options->timelapse || options->signal || options->keypress))
|
||||
- {
|
||||
- app.Teardown();
|
||||
- app.ConfigureViewfinder();
|
||||
- if (options->af_on_capture && options->afMode_index == -1)
|
||||
- {
|
||||
- libcamera::ControlList cl;
|
||||
- cl.set(libcamera::controls::AfMode, libcamera::controls::AfModeAuto);
|
||||
- cl.set(libcamera::controls::AfTrigger, libcamera::controls::AfTriggerCancel);
|
||||
- app.SetControls(cl);
|
||||
- }
|
||||
- app.StartCamera();
|
||||
- af_wait_state = AF_WAIT_NONE;
|
||||
+ if (!options->immediate && (options->timelapse || options->signal || options->keypress)){
|
||||
+ app.ConfigureStill(still_flags);
|
||||
+ if (options->af_on_capture)
|
||||
+ {
|
||||
+ libcamera::ControlList cl;
|
||||
+ cl.set(libcamera::controls::AfMode, libcamera::controls::AfModeAuto);
|
||||
+ cl.set(libcamera::controls::AfTrigger, libcamera::controls::AfTriggerCancel);
|
||||
+ app.SetControls(cl);
|
||||
+ }
|
||||
+ app.StartCamera();
|
||||
+ }
|
||||
+ else
|
||||
+ return;
|
||||
}
|
||||
else
|
||||
- return;
|
||||
+ app.ShowPreview(completed_request, app.StillStream());
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/image/dng.cpp b/image/dng.cpp
|
||||
index fbc02bb..98cb5e7 100644
|
||||
--- a/image/dng.cpp
|
||||
+++ b/image/dng.cpp
|
||||
@@ -151,7 +151,6 @@ void dng_save(std::vector<libcamera::Span<uint8_t>> const &mem, StreamInfo const
|
||||
std::string const &filename, std::string const &cam_model, StillOptions const *options)
|
||||
{
|
||||
// Check the Bayer format and unpack it to u16.
|
||||
-
|
||||
auto it = bayer_formats.find(info.pixel_format);
|
||||
if (it == bayer_formats.end())
|
||||
throw std::runtime_error("unsupported Bayer format");
|
||||
--
|
||||
2.34.1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,28 +0,0 @@
|
||||
From 2faf0e97fa4f1fdf8a2d22407966ea8747581eff Mon Sep 17 00:00:00 2001
|
||||
From: "zejian.su" <zejian.su@starfivetech.com>
|
||||
Date: Mon, 30 Oct 2023 17:35:05 +0800
|
||||
Subject: [PATCH] Let the option: width, height work again.
|
||||
|
||||
Signed-off-by: zejian.su <zejian.su@starfivetech.com>
|
||||
---
|
||||
core/libcamera_app.cpp | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/core/libcamera_app.cpp b/core/libcamera_app.cpp
|
||||
index cc76e9b..a49e31d 100644
|
||||
--- a/core/libcamera_app.cpp
|
||||
+++ b/core/libcamera_app.cpp
|
||||
@@ -252,6 +252,10 @@ void LibcameraApp::ConfigureViewfinder()
|
||||
//auto area = camera_->properties().get(properties::PixelArrayActiveAreas);
|
||||
if (options_->viewfinder_width && options_->viewfinder_height)
|
||||
size = Size(options_->viewfinder_width, options_->viewfinder_height);
|
||||
+ else if (options_->width && options_->height)
|
||||
+ {
|
||||
+ size = Size(options_->width, options_->height);
|
||||
+ }
|
||||
//else if (area)
|
||||
//{
|
||||
// // The idea here is that most sensors will have a 2x2 binned mode that
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
From 0327a137e069e0cfbdd775f7c40f03e088b765d6 Mon Sep 17 00:00:00 2001
|
||||
From: "zejian.su" <zejian.su@starfivetech.com>
|
||||
Date: Wed, 8 Nov 2023 09:23:01 +0800
|
||||
Subject: [PATCH 2/2] Make the qt preview work in debian. 1. Fill the NV12 data
|
||||
into the QT buffer. 2. For the low performance of QWidget, reduce the FPS to
|
||||
15.
|
||||
|
||||
Signed-off-by: zejian.su <zejian.su@starfivetech.com>
|
||||
---
|
||||
preview/preview.cpp | 37 ++++++++++++++-----------------------
|
||||
preview/qt_preview.cpp | 20 ++++++++++++++++----
|
||||
2 files changed, 30 insertions(+), 27 deletions(-)
|
||||
|
||||
diff --git a/preview/preview.cpp b/preview/preview.cpp
|
||||
index b67edb3..d2c511a 100644
|
||||
--- a/preview/preview.cpp
|
||||
+++ b/preview/preview.cpp
|
||||
@@ -19,47 +19,38 @@ Preview *make_preview(Options const *options)
|
||||
if (options->nopreview)
|
||||
return make_null_preview(options);
|
||||
#if QT_PRESENT
|
||||
- else if (options->qt_preview)
|
||||
+ else
|
||||
{
|
||||
Preview *p = make_qt_preview(options);
|
||||
if (p)
|
||||
LOG(1, "Made QT preview window");
|
||||
return p;
|
||||
}
|
||||
-#endif
|
||||
- else
|
||||
+#else
|
||||
+ try
|
||||
+ {
|
||||
+ throw std::runtime_error("qt5 libraries unavailable.");
|
||||
+ }
|
||||
+ catch(std::exception const &e)
|
||||
{
|
||||
try
|
||||
{
|
||||
-#if LIBEGL_PRESENT
|
||||
- Preview *p = make_egl_preview(options);
|
||||
+#if LIBDRM_PRESENT
|
||||
+ Preview *p = make_drm_preview(options);
|
||||
if (p)
|
||||
- LOG(1, "Made X/EGL preview window");
|
||||
+ LOG(1, "Made DRM preview window");
|
||||
return p;
|
||||
#else
|
||||
- throw std::runtime_error("egl libraries unavailable.");
|
||||
+ throw std::runtime_error("drm libraries unavailable.");
|
||||
#endif
|
||||
}
|
||||
catch (std::exception const &e)
|
||||
{
|
||||
- try
|
||||
- {
|
||||
-#if LIBDRM_PRESENT
|
||||
- Preview *p = make_drm_preview(options);
|
||||
- if (p)
|
||||
- LOG(1, "Made DRM preview window");
|
||||
- return p;
|
||||
-#else
|
||||
- throw std::runtime_error("drm libraries unavailable.");
|
||||
-#endif
|
||||
- }
|
||||
- catch (std::exception const &e)
|
||||
- {
|
||||
- LOG(1, "Preview window unavailable");
|
||||
- return make_null_preview(options);
|
||||
- }
|
||||
+ LOG(1, "Preview window unavailable");
|
||||
+ return make_null_preview(options);
|
||||
}
|
||||
}
|
||||
+#endif
|
||||
|
||||
return nullptr; // prevents compiler warning in debug builds
|
||||
}
|
||||
diff --git a/preview/qt_preview.cpp b/preview/qt_preview.cpp
|
||||
index f595db7..8196a8e 100644
|
||||
--- a/preview/qt_preview.cpp
|
||||
+++ b/preview/qt_preview.cpp
|
||||
@@ -58,7 +58,7 @@ protected:
|
||||
class QtPreview : public Preview
|
||||
{
|
||||
public:
|
||||
- QtPreview(Options const *options) : Preview(options)
|
||||
+ QtPreview(Options const *options) : Preview(options), frame_counter_(0)
|
||||
{
|
||||
window_width_ = options->preview_width;
|
||||
window_height_ = options->preview_height;
|
||||
@@ -83,6 +83,12 @@ public:
|
||||
void SetInfoText(const std::string &text) override { main_window_->setWindowTitle(QString::fromStdString(text)); }
|
||||
virtual void Show(int fd, libcamera::Span<uint8_t> span, StreamInfo const &info) override
|
||||
{
|
||||
+ if((frame_counter_++) & 1) {
|
||||
+ // Return the buffer to the camera system.
|
||||
+ done_callback_(fd);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
// Quick and simple nearest-neighbour-ish resampling is used here.
|
||||
// We further share U,V samples between adjacent output pixel pairs
|
||||
// (even when downscaling) to speed up the conversion.
|
||||
@@ -131,6 +137,7 @@ public:
|
||||
// take a copy of each row used. This is a speedup provided memcpy() is vectorized.
|
||||
tmp_stripe_.resize(2 * info.stride);
|
||||
uint8_t const *Y_start = span.data();
|
||||
+ uint8_t const *UV_start = Y_start + info.height * info.stride;
|
||||
uint8_t *Y_row = &tmp_stripe_[0];
|
||||
uint8_t *U_row = Y_row + info.stride;
|
||||
uint8_t *V_row = U_row + (info.stride >> 1);
|
||||
@@ -146,8 +153,11 @@ public:
|
||||
unsigned x_pos = x_step >> 1;
|
||||
|
||||
memcpy(Y_row, Y_start + row * info.stride, info.stride);
|
||||
- memcpy(U_row, Y_start + ((4 * info.height + row) >> 1) * (info.stride >> 1), info.stride >> 1);
|
||||
- memcpy(V_row, Y_start + ((5 * info.height + row) >> 1) * (info.stride >> 1), info.stride >> 1);
|
||||
+ //memcpy(U_row, Y_start + ((4 * info.height + row) >> 1) * (info.stride >> 1), info.stride >> 1);
|
||||
+ //memcpy(V_row, Y_start + ((5 * info.height + row) >> 1) * (info.stride >> 1), info.stride >> 1);
|
||||
+ uint8_t const *cur_uv = UV_start + (row >> 1) * info.width;
|
||||
+ for(unsigned int uv_idx = 0; uv_idx < info.width >> 1; uv_idx++, cur_uv += 2)
|
||||
+ U_row[uv_idx] = cur_uv[0], V_row[uv_idx] = cur_uv[1];
|
||||
|
||||
for (unsigned int x = 0; x < window_width_; x += 2)
|
||||
{
|
||||
@@ -183,7 +193,7 @@ public:
|
||||
}
|
||||
// Reset the preview window, clearing the current buffers and being ready to
|
||||
// show new ones.
|
||||
- void Reset() override {}
|
||||
+ void Reset() override {frame_counter_ = 0;}
|
||||
// Check if preview window has been shut down.
|
||||
bool Quit() override { return main_window_->quit; }
|
||||
// There is no particular limit to image sizes, though large images will be very slow.
|
||||
@@ -218,6 +228,8 @@ private:
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cond_var_;
|
||||
std::vector<uint8_t> tmp_stripe_;
|
||||
+
|
||||
+ unsigned int frame_counter_;
|
||||
};
|
||||
|
||||
Preview *make_qt_preview(Options const *options)
|
||||
--
|
||||
2.34.1
|
||||
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
From de29362501b331f640a3d1d1f18722b229044873 Mon Sep 17 00:00:00 2001
|
||||
From: "zejian.su" <zejian.su@starfivetech.com>
|
||||
Date: Wed, 15 Nov 2023 12:00:25 +0800
|
||||
Subject: [PATCH] Fix the libcamera-still bug at low resolution (redmine
|
||||
#8306).
|
||||
|
||||
Set the raw stream's resolution too.
|
||||
|
||||
Signed-off-by: zejian.su <zejian.su@starfivetech.com>
|
||||
---
|
||||
core/libcamera_app.cpp | 8 ++++++--
|
||||
1 file changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/core/libcamera_app.cpp b/core/libcamera_app.cpp
|
||||
index a49e31d..27d5c44 100644
|
||||
--- a/core/libcamera_app.cpp
|
||||
+++ b/core/libcamera_app.cpp
|
||||
@@ -349,10 +349,14 @@ void LibcameraApp::ConfigureStill(unsigned int flags)
|
||||
configuration_->at(0).bufferCount = 3;
|
||||
else if (options_->buffer_count > 0)
|
||||
configuration_->at(0).bufferCount = options_->buffer_count;
|
||||
- if (options_->width)
|
||||
+ if (options_->width) {
|
||||
configuration_->at(0).size.width = options_->width;
|
||||
- if (options_->height)
|
||||
+ configuration_->at(1).size.width = options_->width;
|
||||
+ }
|
||||
+ if (options_->height) {
|
||||
configuration_->at(0).size.height = options_->height;
|
||||
+ configuration_->at(1).size.height = options_->height;
|
||||
+ }
|
||||
configuration_->at(0).colorSpace = libcamera::ColorSpace::Sycc;
|
||||
configuration_->transform = options_->transform;
|
||||
|
||||
--
|
||||
2.34.1
|
||||
|
||||
-300
@@ -1,300 +0,0 @@
|
||||
From 526cbca855ea6310dc846cc05158d403aea456e1 Mon Sep 17 00:00:00 2001
|
||||
From: "zejian.su" <zejian.su@starfivetech.com>
|
||||
Date: Mon, 27 Nov 2023 18:02:17 +0800
|
||||
Subject: [PATCH 1/2] In DRM preview, zoom the input image to fit the screen.
|
||||
|
||||
1. Use the atomic drm mode.
|
||||
2. Find a mode in the connector with most closed area with the input image.
|
||||
3. Set the plane property to scale the input image.
|
||||
|
||||
Signed-off-by: zejian.su <zejian.su@starfivetech.com>
|
||||
---
|
||||
preview/drm_preview.cpp | 184 ++++++++++++++++++++++++++++++++--------
|
||||
1 file changed, 147 insertions(+), 37 deletions(-)
|
||||
|
||||
diff --git a/preview/drm_preview.cpp b/preview/drm_preview.cpp
|
||||
index 38fc6a2..405bdca 100644
|
||||
--- a/preview/drm_preview.cpp
|
||||
+++ b/preview/drm_preview.cpp
|
||||
@@ -17,6 +17,92 @@
|
||||
|
||||
#include "preview.hpp"
|
||||
|
||||
+class DRMObject
|
||||
+{
|
||||
+public:
|
||||
+ DRMObject(int drmfd, uint32_t id, uint32_t type)
|
||||
+ : id_(id), type_(type){
|
||||
+ drmModeObjectProperties *properties = drmModeObjectGetProperties(drmfd, id, type);
|
||||
+ if (!properties)
|
||||
+ return;
|
||||
+
|
||||
+ drmModePropertyPtr property;
|
||||
+ for (uint32_t i = 0; i < properties->count_props; i++) {
|
||||
+ property = drmModeGetProperty(drmfd, properties->props[i]);
|
||||
+ property_[std::string(property->name)] = property->prop_id;
|
||||
+ drmModeFreeProperty(property);
|
||||
+ }
|
||||
+
|
||||
+ drmModeFreeObjectProperties(properties);
|
||||
+ }
|
||||
+
|
||||
+ uint32_t getID() const {return id_;};
|
||||
+
|
||||
+public:
|
||||
+ std::unordered_map<std::string, uint32_t> property_;
|
||||
+
|
||||
+private:
|
||||
+ uint32_t id_;
|
||||
+ uint32_t type_;
|
||||
+};
|
||||
+
|
||||
+class AtomicRequest
|
||||
+{
|
||||
+public:
|
||||
+ enum Flags {
|
||||
+ FlagAllowModeset = (1 << 0),
|
||||
+ FlagAsync = (1 << 1),
|
||||
+ FlagTestOnly = (1 << 2),
|
||||
+ };
|
||||
+
|
||||
+ AtomicRequest() : valid_(true) {
|
||||
+ request_ = drmModeAtomicAlloc();
|
||||
+ if (!request_)
|
||||
+ valid_ = false;
|
||||
+ }
|
||||
+
|
||||
+ ~AtomicRequest() {
|
||||
+ if (request_)
|
||||
+ drmModeAtomicFree(request_);
|
||||
+ }
|
||||
+
|
||||
+ bool isValid() const { return valid_; }
|
||||
+
|
||||
+ int addProperty(int drmfd, const DRMObject *object, const std::string &propertyName,
|
||||
+ uint64_t value) {
|
||||
+
|
||||
+ if (!valid_)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ auto it = object->property_.find(propertyName);
|
||||
+ if(it == object->property_.end())
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if(drmModeAtomicAddProperty(request_, object->getID(), it->second, value) < 0) {
|
||||
+ std::string errMsg = "drmModeAtomicAddProperty() failed -- object: " +
|
||||
+ std::to_string(object->getID()) + ", property: " + std::to_string(it->second);
|
||||
+ throw std::runtime_error(errMsg);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ int commit(int drmfd, unsigned int flags = 0) {
|
||||
+ if(drmModeAtomicCommit(drmfd, request_, flags, NULL) < 0)
|
||||
+ throw std::runtime_error("drmModeAtomicCommit() failed");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+private:
|
||||
+ AtomicRequest(const AtomicRequest &) = delete;
|
||||
+ AtomicRequest(const AtomicRequest &&) = delete;
|
||||
+ AtomicRequest &operator=(const AtomicRequest &) = delete;
|
||||
+ AtomicRequest &operator=(const AtomicRequest &&) = delete;
|
||||
+
|
||||
+ bool valid_;
|
||||
+ drmModeAtomicReq *request_;
|
||||
+};
|
||||
+
|
||||
class DrmPreview : public Preview
|
||||
{
|
||||
public:
|
||||
@@ -48,6 +134,7 @@ private:
|
||||
void makeBuffer(int fd, size_t size, StreamInfo const &info, Buffer &buffer);
|
||||
void findCrtc();
|
||||
void findPlane();
|
||||
+ void fitDisplaySize();
|
||||
int drmfd_;
|
||||
int conId_;
|
||||
drmModeConnector *con_;
|
||||
@@ -61,11 +148,18 @@ private:
|
||||
unsigned int height_;
|
||||
unsigned int screen_width_;
|
||||
unsigned int screen_height_;
|
||||
+ unsigned int display_x_;
|
||||
+ unsigned int display_y_;
|
||||
+ unsigned int display_w_;
|
||||
+ unsigned int display_h_;
|
||||
std::map<int, Buffer> buffers_; // map the DMABUF's fd to the Buffer
|
||||
int last_fd_;
|
||||
unsigned int max_image_width_;
|
||||
unsigned int max_image_height_;
|
||||
bool first_time_;
|
||||
+
|
||||
+ std::unique_ptr<DRMObject> connector_;
|
||||
+ std::unique_ptr<DRMObject> crtc_;
|
||||
};
|
||||
|
||||
#define ERRSTR strerror(errno)
|
||||
@@ -96,10 +190,6 @@ void DrmPreview::findCrtc()
|
||||
if (con->encoder_id)
|
||||
{
|
||||
enc = drmModeGetEncoder(drmfd_, con->encoder_id);
|
||||
- //if (enc->crtc_id)
|
||||
- //{
|
||||
- // crtc = drmModeGetCrtc(drmfd_, enc->crtc_id);
|
||||
- //}
|
||||
} else
|
||||
{
|
||||
enc = drmModeGetEncoder(drmfd_, con->encoders[0]);
|
||||
@@ -229,6 +319,7 @@ void DrmPreview::findPlane()
|
||||
drmModeFreePlane(plane);
|
||||
break;
|
||||
}
|
||||
+ planeId_ = planes->planes[0];
|
||||
}
|
||||
catch (std::exception const &e)
|
||||
{
|
||||
@@ -265,21 +356,16 @@ DrmPreview::DrmPreview(Options const *options) : Preview(options), last_fd_(-1),
|
||||
//out_fourcc_ = DRM_FORMAT_YUV420;
|
||||
out_fourcc_ = DRM_FORMAT_NV12;
|
||||
findPlane();
|
||||
+
|
||||
+ drmSetClientCap(drmfd_, DRM_CLIENT_CAP_ATOMIC, 1);
|
||||
+ connector_ = std::make_unique<DRMObject>(drmfd_, conId_, DRM_MODE_OBJECT_CONNECTOR);
|
||||
+ crtc_ = std::make_unique<DRMObject>(drmfd_, crtcId_, DRM_MODE_OBJECT_CRTC);
|
||||
}
|
||||
catch (std::exception const &e)
|
||||
{
|
||||
close(drmfd_);
|
||||
throw;
|
||||
}
|
||||
-
|
||||
- // Default behaviour here is to go fullscreen.
|
||||
- if (options_->fullscreen || width_ == 0 || height_ == 0 || x_ + width_ > screen_width_ ||
|
||||
- y_ + height_ > screen_height_)
|
||||
- {
|
||||
- x_ = y_ = 0;
|
||||
- width_ = screen_width_;
|
||||
- height_ = screen_height_;
|
||||
- }
|
||||
}
|
||||
|
||||
DrmPreview::~DrmPreview()
|
||||
@@ -365,9 +451,23 @@ static void setup_colour_space(int fd, int plane_id, std::optional<libcamera::Co
|
||||
drm_set_property(fd, plane_id, "COLOR_RANGE", range);
|
||||
}
|
||||
|
||||
+void DrmPreview::fitDisplaySize()
|
||||
+{
|
||||
+ if((int64_t)width_ * screen_height_ > (int64_t)screen_width_ * height_) {
|
||||
+ display_x_ = 0, display_w_ = screen_width_;
|
||||
+ display_h_ = ((int64_t)screen_width_ * height_) / (int64_t)width_;
|
||||
+ display_y_ = (screen_height_ - display_h_) >> 1;
|
||||
+ } else {
|
||||
+ display_y_ = 0, display_h_ = screen_height_;
|
||||
+ display_w_ = ((int64_t)width_ * screen_height_) / (int64_t)height_;
|
||||
+ display_x_ = (screen_width_ - display_w_) >> 1;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void DrmPreview::makeBuffer(int fd, size_t size, StreamInfo const &info, Buffer &buffer)
|
||||
{
|
||||
unsigned int width = info.width, height = info.height, stride = info.stride;
|
||||
+ int64_t targetArea = 0;
|
||||
if (first_time_)
|
||||
{
|
||||
first_time_ = false;
|
||||
@@ -379,6 +479,10 @@ void DrmPreview::makeBuffer(int fd, size_t size, StreamInfo const &info, Buffer
|
||||
buffer.size = size;
|
||||
buffer.info = info;
|
||||
|
||||
+ if(!width_ || !height)
|
||||
+ width_ = info.width, height_ = info.height;
|
||||
+ targetArea = (int64_t)width_ * height_;
|
||||
+
|
||||
if (drmPrimeFDToHandle(drmfd_, fd, &buffer.bo_handle))
|
||||
throw std::runtime_error("drmPrimeFDToHandle failed for fd " + std::to_string(fd));
|
||||
|
||||
@@ -401,33 +505,46 @@ void DrmPreview::makeBuffer(int fd, size_t size, StreamInfo const &info, Buffer
|
||||
|
||||
/* find preferred mode */
|
||||
drmModeModeInfo *modeptr = NULL, *preferred = NULL;
|
||||
+ int64_t minDiff = -1;
|
||||
for (int m = 0; m < con_->count_modes; m++) {
|
||||
+ int64_t area, areaDiff;
|
||||
modeptr = &con_->modes[m];
|
||||
- if (modeptr->hdisplay == width && modeptr->vdisplay == height) {
|
||||
+
|
||||
+ area = (int64_t)modeptr->hdisplay * modeptr->vdisplay;
|
||||
+ areaDiff = abs(targetArea - area);
|
||||
+ if(-1 == minDiff)
|
||||
+ minDiff = abs(targetArea - area), preferred = modeptr;
|
||||
+ else {
|
||||
+ if(areaDiff < minDiff)
|
||||
+ minDiff = areaDiff, preferred = modeptr;
|
||||
+ }
|
||||
+
|
||||
+ if (!minDiff) {
|
||||
preferred = modeptr;
|
||||
std::cout << "find the matched mode, modes index= "
|
||||
<< m << ", " << width << "x" << height << std::endl;
|
||||
break;
|
||||
}
|
||||
- if (modeptr->type & DRM_MODE_TYPE_PREFERRED) {
|
||||
- preferred = modeptr;
|
||||
- std::cout << "find perferred mode, modes index= " << m << std::endl;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (!preferred)
|
||||
- preferred = &con_->modes[0];
|
||||
-
|
||||
- // set default
|
||||
- if (drmModeSetCrtc(drmfd_, crtcId_, buffer.fb_handle, 0, 0,
|
||||
- (uint32_t *)&conId_, 1, preferred)) {
|
||||
- throw std::runtime_error("drmModeSetCrtc() failed");
|
||||
}
|
||||
|
||||
screen_width_ = preferred->hdisplay;
|
||||
screen_height_ = preferred->vdisplay;
|
||||
- width_ = width;
|
||||
- height_ = height;
|
||||
+ fitDisplaySize();
|
||||
+
|
||||
+ AtomicRequest ar;
|
||||
+ uint32_t blob_id;
|
||||
+
|
||||
+ drmModeCreatePropertyBlob(drmfd_, preferred, sizeof(con_->modes[0]), &blob_id);
|
||||
+ ar.addProperty(drmfd_, connector_.get(), "CRTC_ID", crtcId_);
|
||||
+ ar.addProperty(drmfd_, crtc_.get(), "ACTIVE", 1);
|
||||
+ ar.addProperty(drmfd_, crtc_.get(), "MODE_ID", blob_id);
|
||||
+ ar.commit(drmfd_, DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_ATOMIC_ALLOW_MODESET);
|
||||
+
|
||||
+ // set default
|
||||
+ //if (drmModeSetCrtc(drmfd_, crtcId_, buffer.fb_handle, 0, 0,
|
||||
+ // (uint32_t *)&conId_, 1, preferred)) {
|
||||
+ // throw std::runtime_error("drmModeSetCrtc() failed");
|
||||
+ //}
|
||||
}
|
||||
|
||||
void DrmPreview::Show(int fd, libcamera::Span<uint8_t> span, StreamInfo const &info)
|
||||
@@ -436,14 +553,7 @@ void DrmPreview::Show(int fd, libcamera::Span<uint8_t> span, StreamInfo const &i
|
||||
if (buffer.fd == -1)
|
||||
makeBuffer(fd, span.size(), info, buffer);
|
||||
|
||||
- unsigned int x_off = 0, y_off = 0;
|
||||
- unsigned int w = width_, h = height_;
|
||||
- if (info.width * height_ > width_ * info.height)
|
||||
- h = width_ * info.height / info.width, y_off = (height_ - h) / 2;
|
||||
- else
|
||||
- w = height_ * info.width / info.height, x_off = (width_ - w) / 2;
|
||||
-
|
||||
- if (drmModeSetPlane(drmfd_, planeId_, crtcId_, buffer.fb_handle, 0, x_off + x_, y_off + y_, w, h, 0, 0,
|
||||
+ if (drmModeSetPlane(drmfd_, planeId_, crtcId_, buffer.fb_handle, 0, display_x_, display_y_, display_w_, display_h_, 0, 0,
|
||||
buffer.info.width << 16, buffer.info.height << 16))
|
||||
throw std::runtime_error("drmModeSetPlane failed: " + std::string(ERRSTR));
|
||||
if (last_fd_ >= 0)
|
||||
--
|
||||
2.34.1
|
||||
|
||||
-291
@@ -1,291 +0,0 @@
|
||||
From e9e9555cac3c11c70277824d82d5b3fbd5e4afd2 Mon Sep 17 00:00:00 2001
|
||||
From: "zejian.su" <zejian.su@starfivetech.com>
|
||||
Date: Fri, 1 Dec 2023 16:30:27 +0800
|
||||
Subject: [PATCH 2/2] Fix the sync issue between the Preview.Show() and the
|
||||
QWidget.update() 1. Add a mutex between the Preview.Show() and the
|
||||
QWidget.update(). 2. Speed up the Preview.Show() -- change the floating point
|
||||
to integer, merge some plus and multiplying operation and remove some data
|
||||
copy.
|
||||
|
||||
Signed-off-by: zejian.su <zejian.su@starfivetech.com>
|
||||
---
|
||||
preview/qt_preview.cpp | 183 +++++++++++++++++++++++++----------------
|
||||
1 file changed, 113 insertions(+), 70 deletions(-)
|
||||
|
||||
diff --git a/preview/qt_preview.cpp b/preview/qt_preview.cpp
|
||||
index 8196a8e..ef3c8a4 100644
|
||||
--- a/preview/qt_preview.cpp
|
||||
+++ b/preview/qt_preview.cpp
|
||||
@@ -41,16 +41,47 @@ class MyWidget : public QWidget
|
||||
public:
|
||||
MyWidget(QWidget *parent, int w, int h) : QWidget(parent), size(w, h)
|
||||
{
|
||||
- image = QImage(size, QImage::Format_RGB888);
|
||||
- image.fill(0);
|
||||
+ for(int i = 0; i < 2; i++) {
|
||||
+ buffers_[i].image = QImage(size, QImage::Format_RGB888);
|
||||
+ buffers_[i].image.fill(0);
|
||||
+ availableBuffers_.push_back(&buffers_[i]);
|
||||
+ }
|
||||
}
|
||||
QSize size;
|
||||
- QImage image;
|
||||
+
|
||||
+ struct ImageBuffer {
|
||||
+ QImage image;
|
||||
+ uint8_t frameCounter;
|
||||
+
|
||||
+ ImageBuffer() : frameCounter(0) {};
|
||||
+ } buffers_[2];
|
||||
+
|
||||
+ std::list<ImageBuffer *> freeBuffers_;
|
||||
+ std::list<ImageBuffer *> availableBuffers_;
|
||||
+
|
||||
+ std::mutex buffers_available_mutex_;
|
||||
+ std::mutex buffers_free_mutex_;
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *) override
|
||||
{
|
||||
QPainter painter(this);
|
||||
- painter.drawImage(rect(), image, image.rect());
|
||||
+ {
|
||||
+ ImageBuffer *buffer = nullptr;
|
||||
+ {
|
||||
+ std::lock_guard<std::mutex> lock(buffers_available_mutex_);
|
||||
+ if(!availableBuffers_.size())
|
||||
+ return;
|
||||
+ buffer = availableBuffers_.back();
|
||||
+ availableBuffers_.pop_back();
|
||||
+ }
|
||||
+
|
||||
+ painter.drawImage(rect(), buffer->image, buffer->image.rect());
|
||||
+
|
||||
+ {
|
||||
+ std::lock_guard<std::mutex> lock(buffers_free_mutex_);
|
||||
+ freeBuffers_.push_back(buffer);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
QSize sizeHint() const override { return size; }
|
||||
};
|
||||
@@ -58,7 +89,7 @@ protected:
|
||||
class QtPreview : public Preview
|
||||
{
|
||||
public:
|
||||
- QtPreview(Options const *options) : Preview(options), frame_counter_(0)
|
||||
+ QtPreview(Options const *options) : Preview(options)
|
||||
{
|
||||
window_width_ = options->preview_width;
|
||||
window_height_ = options->preview_height;
|
||||
@@ -67,6 +98,8 @@ public:
|
||||
// This preview window is expensive, so make it small by default.
|
||||
if (window_width_ == 0 || window_height_ == 0)
|
||||
window_width_ = 512, window_height_ = 384;
|
||||
+
|
||||
+ frameCounter_ = 0;
|
||||
// As a hint, reserve twice the binned width for our widest current camera (V3)
|
||||
tmp_stripe_.reserve(4608);
|
||||
thread_ = std::thread(&QtPreview::threadFunc, this, options);
|
||||
@@ -83,100 +116,105 @@ public:
|
||||
void SetInfoText(const std::string &text) override { main_window_->setWindowTitle(QString::fromStdString(text)); }
|
||||
virtual void Show(int fd, libcamera::Span<uint8_t> span, StreamInfo const &info) override
|
||||
{
|
||||
- if((frame_counter_++) & 1) {
|
||||
- // Return the buffer to the camera system.
|
||||
- done_callback_(fd);
|
||||
- return;
|
||||
+ MyWidget::ImageBuffer *buffer = nullptr;
|
||||
+ {
|
||||
+ std::lock_guard<std::mutex> lock(pane_->buffers_free_mutex_);
|
||||
+ if(pane_->freeBuffers_.size() > 0) {
|
||||
+ buffer = pane_->freeBuffers_.front();
|
||||
+ pane_->freeBuffers_.pop_front();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if(!buffer) {
|
||||
+ std::lock_guard<std::mutex> lock(pane_->buffers_available_mutex_);
|
||||
+ if(!pane_->availableBuffers_.size()) {
|
||||
+ done_callback_(fd);
|
||||
+ return;
|
||||
+ }
|
||||
+ buffer = pane_->availableBuffers_.front();
|
||||
+ pane_->availableBuffers_.pop_front();
|
||||
}
|
||||
-
|
||||
// Quick and simple nearest-neighbour-ish resampling is used here.
|
||||
// We further share U,V samples between adjacent output pixel pairs
|
||||
// (even when downscaling) to speed up the conversion.
|
||||
unsigned x_step = (info.width << 16) / window_width_;
|
||||
unsigned y_step = (info.height << 16) / window_height_;
|
||||
|
||||
- // Choose the right matrix to convert YUV back to RGB.
|
||||
- static const float YUV2RGB[3][9] = {
|
||||
- { 1.0, 0.0, 1.402, 1.0, -0.344, -0.714, 1.0, 1.772, 0.0 }, // JPEG
|
||||
- { 1.164, 0.0, 1.596, 1.164, -0.392, -0.813, 1.164, 2.017, 0.0 }, // SMPTE170M
|
||||
- { 1.164, 0.0, 1.793, 1.164, -0.213, -0.533, 1.164, 2.112, 0.0 }, // Rec709
|
||||
+ static const uint32_t YUV2RGB[3][9] = {
|
||||
+ { 128, 0, 179, 128, 44, 91, 128, 227, 0 }, // JPEG
|
||||
+ { 149, 0, 204, 149, 50, 104, 149, 258, 0 }, // SMPTE170M
|
||||
+ { 149, 0, 230, 149, 27, 68, 149, 270, 0 }, // Rec709
|
||||
};
|
||||
- int offsetY;
|
||||
- float coeffY, coeffVR, coeffUG, coeffVG, coeffUB;
|
||||
- if (info.colour_space == libcamera::ColorSpace::Smpte170m)
|
||||
+ static const int RGBOFFSET[3][3] = {
|
||||
+ {24960, -15232, 31104}, {28496, -17328, 35408}, {31824, -9776, 36944}
|
||||
+ };
|
||||
+
|
||||
+ uint32_t coeffY, coeffVR, coeffUG, coeffVG, coeffUB;
|
||||
+ const int * rgbOffset = nullptr;
|
||||
+ if(info.colour_space == libcamera::ColorSpace::Smpte170m)
|
||||
{
|
||||
- offsetY = 16;
|
||||
coeffY = YUV2RGB[1][0];
|
||||
coeffVR = YUV2RGB[1][2];
|
||||
coeffUG = YUV2RGB[1][4];
|
||||
coeffVG = YUV2RGB[1][5];
|
||||
coeffUB = YUV2RGB[1][7];
|
||||
- }
|
||||
- else if (info.colour_space == libcamera::ColorSpace::Rec709)
|
||||
+ rgbOffset = RGBOFFSET[1];
|
||||
+ } else if(info.colour_space == libcamera::ColorSpace::Rec709)
|
||||
{
|
||||
- offsetY = 16;
|
||||
coeffY = YUV2RGB[2][0];
|
||||
coeffVR = YUV2RGB[2][2];
|
||||
coeffUG = YUV2RGB[2][4];
|
||||
coeffVG = YUV2RGB[2][5];
|
||||
coeffUB = YUV2RGB[2][7];
|
||||
- }
|
||||
- else
|
||||
+ rgbOffset = RGBOFFSET[2];
|
||||
+ } else
|
||||
{
|
||||
- offsetY = 0;
|
||||
coeffY = YUV2RGB[0][0];
|
||||
coeffVR = YUV2RGB[0][2];
|
||||
coeffUG = YUV2RGB[0][4];
|
||||
coeffVG = YUV2RGB[0][5];
|
||||
coeffUB = YUV2RGB[0][7];
|
||||
- if (info.colour_space != libcamera::ColorSpace::Sycc)
|
||||
- LOG(1, "QtPreview: unexpected colour space " << libcamera::ColorSpace::toString(info.colour_space));
|
||||
+ rgbOffset = RGBOFFSET[0];
|
||||
}
|
||||
|
||||
- // Because the source buffer is uncached, and we want to read it a byte at a time,
|
||||
- // take a copy of each row used. This is a speedup provided memcpy() is vectorized.
|
||||
- tmp_stripe_.resize(2 * info.stride);
|
||||
- uint8_t const *Y_start = span.data();
|
||||
- uint8_t const *UV_start = Y_start + info.height * info.stride;
|
||||
- uint8_t *Y_row = &tmp_stripe_[0];
|
||||
- uint8_t *U_row = Y_row + info.stride;
|
||||
- uint8_t *V_row = U_row + (info.stride >> 1);
|
||||
-
|
||||
- // Possibly this should be locked in case a repaint is happening? In practice the risk
|
||||
- // is only that there might be some tearing, so I don't think we worry. We could speed
|
||||
- // it up by getting the ISP to supply RGB, but I'm not sure I want to handle that extra
|
||||
- // possibility in our main application code, so we'll put up with the slow conversion.
|
||||
- for (unsigned int y = 0; y < window_height_; y++)
|
||||
+ uint8_t const * Y_start = span.data();
|
||||
+ uint8_t const * UV_start = Y_start + info.height * info.stride;
|
||||
+ int src_ypos = y_step >> 1;
|
||||
+ uint32_t Y2 = 0;
|
||||
+ uint32_t U2 = coeffUG | (coeffUB << 16);
|
||||
+ uint32_t V2 = coeffVR | (coeffVG << 16);
|
||||
+ uint16_t * y2 = (uint16_t *)&Y2;
|
||||
+ uint32_t U;
|
||||
+ uint32_t V;
|
||||
+ uint16_t * u2 = (uint16_t *)&U;
|
||||
+ uint16_t * v2 = (uint16_t *)&V;
|
||||
+
|
||||
+ for(unsigned int y = 0; y < window_height_; y++, src_ypos += y_step)
|
||||
{
|
||||
- unsigned row = (y * y_step) >> 16;
|
||||
- uint8_t *dest = pane_->image.scanLine(y);
|
||||
- unsigned x_pos = x_step >> 1;
|
||||
-
|
||||
- memcpy(Y_row, Y_start + row * info.stride, info.stride);
|
||||
- //memcpy(U_row, Y_start + ((4 * info.height + row) >> 1) * (info.stride >> 1), info.stride >> 1);
|
||||
- //memcpy(V_row, Y_start + ((5 * info.height + row) >> 1) * (info.stride >> 1), info.stride >> 1);
|
||||
- uint8_t const *cur_uv = UV_start + (row >> 1) * info.width;
|
||||
- for(unsigned int uv_idx = 0; uv_idx < info.width >> 1; uv_idx++, cur_uv += 2)
|
||||
- U_row[uv_idx] = cur_uv[0], V_row[uv_idx] = cur_uv[1];
|
||||
-
|
||||
- for (unsigned int x = 0; x < window_width_; x += 2)
|
||||
+ const uint8_t * src_y = Y_start + (src_ypos >> 16) * info.width;
|
||||
+ const uint8_t * src_uv = UV_start + (src_ypos >> 17) * info.width;
|
||||
+ uint8_t * dest = buffer->image.scanLine(y);
|
||||
+ uint32_t x_pos = x_step >> 1;
|
||||
+
|
||||
+ for(unsigned int x = 0; x < window_width_; x += 2)
|
||||
{
|
||||
- int Y0 = Y_row[x_pos >> 16];
|
||||
+ y2[0] = src_y[x_pos >> 16];
|
||||
x_pos += x_step;
|
||||
- int Y1 = Y_row[x_pos >> 16];
|
||||
- int U = U_row[x_pos >> 17];
|
||||
- int V = V_row[x_pos >> 17];
|
||||
+ y2[1] = src_y[x_pos >> 16];
|
||||
+ U = src_uv[(x_pos >> 16) & 0xfffffffe];
|
||||
+ V = src_uv[(x_pos >> 16) | 1];
|
||||
x_pos += x_step;
|
||||
- Y0 -= offsetY;
|
||||
- Y1 -= offsetY;
|
||||
- U -= 128;
|
||||
- V -= 128;
|
||||
- int R0 = coeffY * Y0 + coeffVR * V;
|
||||
- int G0 = coeffY * Y0 + coeffUG * U + coeffVG * V;
|
||||
- int B0 = coeffY * Y0 + coeffUB * U;
|
||||
- int R1 = coeffY * Y1 + coeffVR * V;
|
||||
- int G1 = coeffY * Y1 + coeffUG * U + coeffVG * V;
|
||||
- int B1 = coeffY * Y1 + coeffUB * U;
|
||||
+
|
||||
+ Y2 *= coeffY;
|
||||
+ U *= U2;
|
||||
+ V *= V2;
|
||||
+
|
||||
+ int R0 = ((int)y2[0] + (int)v2[0] - rgbOffset[0]) >> 7;
|
||||
+ int G0 = ((int)y2[0] - (int)u2[0] - (int)v2[1] - rgbOffset[1]) >> 7;
|
||||
+ int B0 = ((int)y2[0] + (int)u2[1] - rgbOffset[2]) >> 7;
|
||||
+ int R1 = ((int)y2[1] + (int)v2[0] - rgbOffset[0]) >> 7;
|
||||
+ int G1 = ((int)y2[1] - (int)u2[0] - (int)v2[1] - rgbOffset[1]) >> 7;
|
||||
+ int B1 = ((int)y2[1] + (int)u2[1] - rgbOffset[2]) >> 7;
|
||||
*(dest++) = std::clamp(R0, 0, 255);
|
||||
*(dest++) = std::clamp(G0, 0, 255);
|
||||
*(dest++) = std::clamp(B0, 0, 255);
|
||||
@@ -186,6 +224,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
+ {
|
||||
+ std::lock_guard<std::mutex> lock(pane_->buffers_available_mutex_);
|
||||
+ buffer->frameCounter = ++frameCounter_;
|
||||
+ pane_->availableBuffers_.push_back(buffer);
|
||||
+ }
|
||||
+
|
||||
pane_->update();
|
||||
|
||||
// Return the buffer to the camera system.
|
||||
@@ -193,7 +237,7 @@ public:
|
||||
}
|
||||
// Reset the preview window, clearing the current buffers and being ready to
|
||||
// show new ones.
|
||||
- void Reset() override {frame_counter_ = 0;}
|
||||
+ void Reset() override {}
|
||||
// Check if preview window has been shut down.
|
||||
bool Quit() override { return main_window_->quit; }
|
||||
// There is no particular limit to image sizes, though large images will be very slow.
|
||||
@@ -228,8 +272,7 @@ private:
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cond_var_;
|
||||
std::vector<uint8_t> tmp_stripe_;
|
||||
-
|
||||
- unsigned int frame_counter_;
|
||||
+ uint8_t frameCounter_;
|
||||
};
|
||||
|
||||
Preview *make_qt_preview(Options const *options)
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -1 +1 @@
|
||||
sha256 add2d80450f3b61de275c6505689b0984d29c9dde94f0cf381c4209620c96263 libcamera-apps-54a781dffdd101954dcfa6acd0bd80006f67da83-br1.tar.gz
|
||||
sha256 774e913f4b71ddf51a6f2adf00f4c48866018d32a0ba57569206e31ada339f59 libcamera-apps-31377be38defcfbd6bc70bd12895c6f145fc8171-br1.tar.gz
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#
|
||||
################################################################################
|
||||
|
||||
LIBCAMERA_APPS_SITE = https://github.com/raspberrypi/libcamera-apps.git
|
||||
LIBCAMERA_APPS_VERSION = 54a781dffdd101954dcfa6acd0bd80006f67da83
|
||||
LIBCAMERA_APPS_SITE = https://github.com/starfive-tech/libcamera-apps.git
|
||||
LIBCAMERA_APPS_VERSION = 31377be38defcfbd6bc70bd12895c6f145fc8171
|
||||
LIBCAMERA_APPS_SITE_METHOD = git
|
||||
LIBCAMERA_APPS_INSTALL_STAGING = YES
|
||||
|
||||
|
||||
Reference in New Issue
Block a user