From f79f0914c3f8e740cf653da0dd14e5664760188d Mon Sep 17 00:00:00 2001 From: "zejian.su" 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 &mem, std::vector> &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(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 &mem, std::vector> &yuv420, StreamInfo &info); +void NV12ToRGB888(const libcamera::Span &mem, std::vector> &rgb888, StreamInfo &info); +void NV12ToBGR888(const libcamera::Span &mem, std::vector> &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> 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> 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> 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> rgb888; + NV12ToBGR888(mem[0], rgb888, info); + png_save(rgb888, info, filename, options); + delete[] rgb888[0].data(); + } else if (options->encoding == "bmp") { + std::vector> rgb888; + NV12ToRGB888(mem[0], rgb888, info); + bmp_save(rgb888, info, filename, options); + delete[] rgb888[0].data(); + } else { + std::vector> 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> 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