From d02d3b3a6c0abdfd8a89ee92447df7d8d48639d5 Mon Sep 17 00:00:00 2001 From: "zejian.su" 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 &mem, std::vector> &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(msg.payload); + const std::vector> mem = app.Mmap(payload->buffers[stream]); + std::vector> 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(msg.payload); - const std::vector> 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 +#include +#include +#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 &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 &mem, std::vector> &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(yuv420Buf, imgBufSize)); + + NV12ToYUV420(mem, yuv420Buf, info); + info.pixel_format = libcamera::formats::YUV420; +} + +template +void NV12ToRGB888(const libcamera::Span &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 +void RGB888FromNV12(const libcamera::Span &mem, std::vector> &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(rgb888Buf, imgBufSize)); + + NV12ToRGB888(mem, rgb888Buf, info); + info.stride = 3 * info.width; +} + +void NV12ToRGB888(const libcamera::Span &mem, std::vector> &rgb888, StreamInfo &info) +{ + RGB888FromNV12<0>(mem, rgb888, info); + info.pixel_format = libcamera::formats::RGB888; +} + +void NV12ToBGR888(const libcamera::Span &mem, std::vector> &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> 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