e50c6c1b2b
Signed-off-by: zejian.su <zejian.su@starfivetech.com>
205 lines
7.7 KiB
Diff
205 lines
7.7 KiB
Diff
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
|
|
|