diff --git a/package/starfive/Config.in b/package/starfive/Config.in index 37cbedbf..8bfcc218 100755 --- a/package/starfive/Config.in +++ b/package/starfive/Config.in @@ -6,6 +6,7 @@ source "package/starfive/codaj12/Config.in" source "package/starfive/sf-omx-il/Config.in" source "package/starfive/sf-omx-il-test/Config.in" source "package/starfive/v4l2_test/Config.in" +source "package/starfive/libcamera-apps/Config.in" source "package/starfive/ispsdk/Config.in" source "package/starfive/mailbox-test/Config.in" source "package/starfive/e24-test/Config.in" diff --git a/package/starfive/libcamera-apps/0001-add-starfive-support.patch b/package/starfive/libcamera-apps/0001-add-starfive-support.patch new file mode 100644 index 00000000..91a7a613 --- /dev/null +++ b/package/starfive/libcamera-apps/0001-add-starfive-support.patch @@ -0,0 +1,489 @@ +From 6abadc7414f0fdfea160374326cea32bd2b40d7d Mon Sep 17 00:00:00 2001 +From: sw.multimedia +Date: Fri, 15 Oct 2021 10:55:01 +0800 +Subject: [PATCH] add starfive support + +--- + CMakeLists.txt | 2 +- + core/CMakeLists.txt | 2 +- + core/libcamera_app.cpp | 38 ++++-- + core/options.hpp | 3 + + preview/CMakeLists.txt | 9 ++ + preview/fb_preview.cpp | 289 +++++++++++++++++++++++++++++++++++++++++ + preview/preview.cpp | 7 +- + 7 files changed, 338 insertions(+), 12 deletions(-) + create mode 100644 preview/fb_preview.cpp + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 2293211..253ec8d 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -12,7 +12,7 @@ endif() + set (CMAKE_EXPORT_COMPILE_COMMANDS ON) + set (CMAKE_CXX_STANDARD 17) + set (CMAKE_CXX_FLAGS "-Wall -Wextra -pedantic -Wno-unused-parameter -faligned-new") +-add_definitions(-Werror) ++# add_definitions(-Werror) + add_definitions(-Wfatal-errors) + add_definitions(-D_FILE_OFFSET_BITS=64) + +diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt +index 1618541..84316b2 100644 +--- a/core/CMakeLists.txt ++++ b/core/CMakeLists.txt +@@ -11,6 +11,6 @@ add_library(libcamera_app libcamera_app.cpp post_processor.cpp version.cpp) + add_dependencies(libcamera_app VersionCpp) + + set_target_properties(libcamera_app PROPERTIES PREFIX "" IMPORT_PREFIX "") +-target_link_libraries(libcamera_app pthread preview ${LIBCAMERA_LINK_LIBRARIES} ${Boost_LIBRARIES} post_processing_stages) ++target_link_libraries(libcamera_app pthread preview ${LIBCAMERA_LIBRARIES} ${Boost_LIBRARIES} post_processing_stages) + + install(TARGETS libcamera_app LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +diff --git a/core/libcamera_app.cpp b/core/libcamera_app.cpp +index 7d4e28f..3c4d862 100644 +--- a/core/libcamera_app.cpp ++++ b/core/libcamera_app.cpp +@@ -134,7 +134,12 @@ void LibcameraApp::ConfigureViewfinder() + } + + // Now we get to override any of the default settings from the options_-> +- configuration_->at(0).pixelFormat = libcamera::formats::YUV420; ++ std::cout << "viewfinder pixelformat: " << options_->pixelformat << std::endl; ++ if (options_->pixelformat.length()) ++ configuration_->at(0).pixelFormat = ++ libcamera::PixelFormat::fromString(options_->pixelformat); ++ else ++ configuration_->at(0).pixelFormat = libcamera::formats::YUV420; + configuration_->at(0).size = size; + + if (have_lores_stream) +@@ -143,7 +148,11 @@ 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(1).pixelFormat = libcamera::formats::YUV420; ++ if (options_->pixelformat.length()) ++ configuration_->at(0).pixelFormat = ++ libcamera::PixelFormat::fromString(options_->pixelformat); ++ else ++ configuration_->at(1).pixelFormat = libcamera::formats::YUV420; + configuration_->at(1).size = lores_size; + configuration_->at(1).bufferCount = configuration_->at(0).bufferCount; + } +@@ -186,8 +195,13 @@ 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 { ++ if (options_->pixelformat.length()) ++ configuration_->at(0).pixelFormat = ++ libcamera::PixelFormat::fromString(options_->pixelformat); ++ 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) +@@ -241,7 +255,11 @@ void LibcameraApp::ConfigureVideo(unsigned int flags) + throw std::runtime_error("failed to generate video configuration"); + + // Now we get to override any of the default settings from the options_-> +- configuration_->at(0).pixelFormat = libcamera::formats::YUV420; ++ if (options_->pixelformat.length()) ++ configuration_->at(0).pixelFormat = ++ libcamera::PixelFormat::fromString(options_->pixelformat); ++ else ++ configuration_->at(0).pixelFormat = libcamera::formats::YUV420; + configuration_->at(0).bufferCount = 6; // 6 buffers is better than 4 + if (options_->width) + configuration_->at(0).size.width = options_->width; +@@ -267,7 +285,11 @@ 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; ++ if (options_->pixelformat.length()) ++ configuration_->at(0).pixelFormat = ++ libcamera::PixelFormat::fromString(options_->pixelformat); ++ else ++ configuration_->at(lores_index).pixelFormat = libcamera::formats::YUV420; + configuration_->at(lores_index).size = lores_size; + configuration_->at(lores_index).bufferCount = configuration_->at(0).bufferCount; + } +@@ -713,8 +735,8 @@ 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) ++ // throw std::runtime_error("Preview windows only support YUV420"); + + unsigned int w, h, stride; + StreamDimensions(item.stream, &w, &h, &stride); +diff --git a/core/options.hpp b/core/options.hpp +index 447983f..5c68088 100644 +--- a/core/options.hpp ++++ b/core/options.hpp +@@ -43,6 +43,8 @@ struct Options + "Set the output image width (0 = use default value)") + ("height", value(&height)->default_value(0), + "Set the output image height (0 = use default value)") ++ ("pixelformat", value(&pixelformat), ++ "Set the pixelformat name") + ("timeout,t", value(&timeout)->default_value(5000), + "Time (in ms) for which program runs") + ("output,o", value(&output), +@@ -119,6 +121,7 @@ struct Options + std::string post_process_file; + unsigned int width; + unsigned int height; ++ std::string pixelformat; + bool rawfull; + bool nopreview; + std::string preview; +diff --git a/preview/CMakeLists.txt b/preview/CMakeLists.txt +index 1a7481f..a772e14 100644 +--- a/preview/CMakeLists.txt ++++ b/preview/CMakeLists.txt +@@ -63,6 +63,15 @@ else() + message(STATUS "QT display mode will be unavailable!") + endif() + ++set(ENABLE_FB 1) ++if (ENABLE_FB) ++ set(SRC ${SRC} fb_preview.cpp) ++ set(FB_FOUND 1) ++ message(STATUS "FB display mode enabled") ++else() ++ message(STATUS "FB display mode will be unavailable!") ++endif() ++ + add_library(preview null_preview.cpp ${SRC}) + target_link_libraries(preview ${TARGET_LIBS}) + +diff --git a/preview/fb_preview.cpp b/preview/fb_preview.cpp +new file mode 100644 +index 0000000..1a88b79 +--- /dev/null ++++ b/preview/fb_preview.cpp +@@ -0,0 +1,289 @@ ++/* SPDX-License-Identifier: BSD-2-Clause */ ++/* ++ * Copyright (C) 2021, Raspberry Pi (Trading) Ltd. ++ * ++ * null_preview.cpp - dummy "show nothing" preview window. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "core/options.hpp" ++ ++#include "preview.hpp" ++ ++#define FBIOPAN_GET_PP_MODE 0x4609 ++#define FBIOPAN_SET_PP_MODE 0x460a ++ ++enum COLOR_FORMAT { ++ COLOR_YUV422_UYVY = 0, // 00={Y1,V0,Y0,U0} ++ COLOR_YUV422_VYUY = 1, // 01={Y1,U0,Y0,V0} ++ COLOR_YUV422_YUYV = 2, // 10={V0,Y1,U0,Y0} ++ COLOR_YUV422_YVYU = 3, // 11={U0,Y1,V0,Y0} ++ ++ COLOR_YUV420P, // 4 ++ COLOR_YUV420_NV21, // 5 ++ COLOR_YUV420_NV12, // 6 ++ ++ COLOR_RGB888_ARGB, // 7 ++ COLOR_RGB888_ABGR, // 8 ++ COLOR_RGB888_RGBA, // 9 ++ COLOR_RGB888_BGRA, // 10 ++ COLOR_RGB565, // 11 ++}; ++ ++struct pp_video_mode { ++ enum COLOR_FORMAT format; ++ unsigned int height; ++ unsigned int width; ++ unsigned int addr; ++}; ++ ++struct pp_mode { ++ char pp_id; ++ bool bus_out; /*out to ddr*/ ++ bool fifo_out; /*out to lcdc*/ ++ bool inited; ++ struct pp_video_mode src; ++ struct pp_video_mode dst; ++}; ++ ++class FbPreview : public Preview ++{ ++public: ++ FbPreview(Options const *options); ++ ~FbPreview(); ++ void SetInfoText(const std::string &text) override ++ { ++ std::cout << "Camera fps: " << text << std::endl; ++ } ++ // Display the buffer. You get given the fd back in the BufferDoneCallback ++ // once its available for re-use. ++ virtual void Show(int fd, libcamera::Span span, int width, int height, int stride) override; ++ // Reset the preview window, clearing the current buffers and being ready to ++ // show new ones. ++ void Reset() override {} ++ // Return the maximum image size allowed. Zeroes mean "no limit". ++ virtual void MaxImageSize(unsigned int &w, unsigned int &h) const override { w = h = 0; } ++ ++private: ++ int NVResize(unsigned char *inBuf, ++ unsigned char *outBuf, int imgWidth, int imgHeight); ++ int g_fb_fd; ++ int g_stfbc_fd; ++ struct fb_var_screeninfo g_vinfo; ++ struct fb_fix_screeninfo g_finfo; ++ unsigned char *g_fb_buf; ++ unsigned char *tmpBuf; ++ unsigned int g_screensize; ++ enum COLOR_FORMAT pixformat; ++}; ++ ++static enum COLOR_FORMAT v4l2fmt_to_fbfmt(unsigned int format) ++{ ++ enum COLOR_FORMAT pixformat = COLOR_RGB565; ++ ++ switch (format) { ++ case V4L2_PIX_FMT_RGB565: ++ pixformat = COLOR_RGB565; ++ break; ++ case V4L2_PIX_FMT_RGB24: ++ pixformat = COLOR_RGB888_ARGB; ++ break; ++ case V4L2_PIX_FMT_YUV420: ++ pixformat = COLOR_YUV420P; ++ break; ++ case V4L2_PIX_FMT_YUYV: ++ pixformat = COLOR_YUV422_YUYV; ++ break; ++ case V4L2_PIX_FMT_NV21: ++ pixformat = COLOR_YUV420_NV21; ++ break; ++ case V4L2_PIX_FMT_NV12: ++ pixformat = COLOR_YUV420_NV12; ++ break; ++ case V4L2_PIX_FMT_YVYU: ++ pixformat = COLOR_YUV422_YVYU; ++ break; ++ default: ++ pixformat = COLOR_RGB565; ++ break; ++ } ++ ++ return pixformat; ++} ++ ++FbPreview::FbPreview(Options const *options) : Preview(options) ++{ ++ g_fb_fd = open("/dev/fb0", O_RDWR); ++ if (g_fb_fd == -1) ++ throw std::runtime_error("Couldn't open fb display"); ++ g_stfbc_fd = open("/dev/stfbcdev", O_RDWR); ++ if (g_stfbc_fd == -1) ++ throw std::runtime_error("Couldn't open stfbcdev display"); ++ ++ struct pp_mode pp_info[3]; ++ libcamera::PixelFormat pixelFormat = ++ libcamera::PixelFormat::fromString(options_->pixelformat); ++ ++ if (pixelFormat.fourcc() != V4L2_PIX_FMT_NV12) ++ throw std::runtime_error("FB onlu support NV12 display"); ++ ++ pixformat = v4l2fmt_to_fbfmt(pixelFormat.fourcc()); ++ if (-1 == ioctl(g_stfbc_fd, FBIOPAN_GET_PP_MODE, &pp_info[0])) ++ throw std::runtime_error("Error reading variable information."); ++ ++ std::cout << "get pp format : " ++ << pp_info[1].src.format ++ << std::endl; ++ ++ pp_info[1].src.format = pixformat; ++ ++ if (-1 == ioctl(g_stfbc_fd, FBIOPAN_SET_PP_MODE, &pp_info[0])) ++ throw std::runtime_error("Error reading variable information."); ++ ++ if (-1 == ioctl(g_stfbc_fd, FBIOPAN_GET_PP_MODE, &pp_info[0])) ++ throw std::runtime_error("Error reading variable information."); ++ ++ std::cout << "get pp format : " ++ << pp_info[1].src.format ++ << std::endl; ++ ++ pixformat = pp_info[1].src.format; ++ ++ // Get fixed screen information ++ if (-1 == ioctl(g_fb_fd, FBIOGET_FSCREENINFO, &g_finfo)) ++ throw std::runtime_error("Error reading fixed information."); ++ ++ // Get variable screen information ++ if (-1 == ioctl(g_fb_fd, FBIOGET_VSCREENINFO, &g_vinfo)) ++ throw std::runtime_error("Error reading variable information."); ++ ++ std::cout << "g_vinfo.xres = " << g_vinfo.xres ++ << ", g_vinfo.yres = " << g_vinfo.yres ++ << ", grayscale = " << g_vinfo.grayscale ++ << std::endl; ++ std::cout << "g_vinfo.xoffset = " << g_vinfo.xoffset ++ << ", g_vinfo.yoffset = " << g_vinfo.yoffset ++ << std::endl; ++ std::cout << "g_vinfo.bits_per_pixel = " << g_vinfo.bits_per_pixel ++ << ", g_finfo.line_length = " << g_finfo.line_length ++ << std::endl; ++ ++ g_screensize = g_vinfo.xres * g_vinfo.yres * g_vinfo.bits_per_pixel / 8; ++ g_fb_buf = (unsigned char *)mmap(NULL, g_screensize, PROT_READ | PROT_WRITE, MAP_SHARED, g_fb_fd, 0); ++ if (g_fb_buf == (void *)(-1)) ++ throw std::runtime_error("Error: failed to map framebuffer device to memory."); ++ ++ memset(g_fb_buf, 0x00, g_screensize); ++ tmpBuf = static_cast(malloc(g_screensize)); ++ if (!tmpBuf) ++ throw std::runtime_error("Error: failed to malloc memory."); ++ memset(tmpBuf, 0x00, g_screensize); ++ ++ if (options->verbose) ++ std::cout << "Running fb preview window" << std::endl; ++} ++ ++FbPreview::~FbPreview() ++{ ++ free(tmpBuf); ++ munmap((void *)g_fb_buf, g_screensize); ++ close(g_fb_fd); ++ close(g_stfbc_fd); ++ std::cout << "fb preview window ~FbPreview" << std::endl; ++} ++ ++int FbPreview::NVResize(unsigned char *inBuf, ++ unsigned char *outBuf, int imgWidth, int imgHeight) ++{ ++ int rows, cols; ++ unsigned char *OutNVdata, *InNVdata; ++ int Ypos, Upos, Vpos; ++ int fb_Ypos, fb_Upos, fb_Vpos; ++ int width, height; ++ int x_offset, y_offset; ++ unsigned int start_timems; ++ unsigned int end_timems; ++ struct timeval ts_start, ts_end; ++ ++ width = imgWidth > g_vinfo.xres ? g_vinfo.xres : imgWidth; ++ height = imgHeight > g_vinfo.yres ? g_vinfo.yres : imgHeight; ++ x_offset = (g_vinfo.xres - width) / 2; ++ y_offset = (g_vinfo.yres - height) / 2; ++ ++ InNVdata = inBuf; ++ OutNVdata = tmpBuf; ++ ++ if (imgWidth == g_vinfo.xres) { ++ fb_Ypos = y_offset * g_vinfo.xres + x_offset; ++ fb_Upos = (y_offset / 2 * g_vinfo.xres / 2 + x_offset / 2) * 2; ++ fb_Upos = g_vinfo.xres * g_vinfo.yres + fb_Upos; ++ Upos = imgWidth * imgHeight; ++ memcpy(&tmpBuf[fb_Ypos], inBuf, imgWidth * height); ++ memcpy(&tmpBuf[fb_Upos], &inBuf[Upos], imgWidth * height / 2); ++ memcpy(&outBuf[fb_Ypos], &tmpBuf[fb_Ypos], imgWidth * height * 2); ++ memcpy(&outBuf[fb_Upos], &tmpBuf[fb_Upos], imgWidth * height / 2); ++ return 0; ++ } ++ ++ /* two bytes for every pixels */ ++ for(rows = 0; rows < height; rows+=2) ++ { ++ // g_vinfo.xres, g_vinfo.yres g_vinfo.bits_per_pixel ++ fb_Ypos = ((rows + y_offset) * g_vinfo.xres + x_offset); ++ fb_Upos = ((rows + y_offset) / 2 * g_vinfo.xres / 2 + x_offset / 2) * 2; ++ fb_Upos = g_vinfo.xres * g_vinfo.yres + fb_Upos; ++ fb_Vpos = fb_Upos + 1; ++ ++ Ypos = rows * imgWidth; ++ Upos = imgWidth * imgHeight + Ypos / 2; ++ Vpos = Upos + 1; ++ memcpy(&OutNVdata[fb_Ypos], &InNVdata[Ypos], width); ++ memcpy(&OutNVdata[fb_Ypos+g_vinfo.xres], &InNVdata[Ypos+imgWidth], width); ++ ++ memcpy(&OutNVdata[fb_Upos], &InNVdata[Upos], width); ++ } ++ ++ memcpy(outBuf, tmpBuf, g_screensize); ++ ++ return 0; ++} ++ ++void FbPreview::Show(int fd, libcamera::Span span, int width, int height, int stride) ++{ ++ int imgsize = stride * height + stride * height / 2; ++ auto startTime = std::chrono::high_resolution_clock::now(); ++ ++ if (pixformat == COLOR_YUV420_NV21 || pixformat == COLOR_YUV420_NV12) ++ NVResize(span.data(), g_fb_buf, width, height); ++ else ++ std::cout << "FbPreview unsupport pixformat: " << pixformat << std::endl; ++ ++ auto endTime = std::chrono::high_resolution_clock::now(); ++ ++ std::chrono::duration> duration_mcs = ++ std::chrono::duration_cast>>(endTime-startTime); ++ std::cout << "FbPreview copy fps " << 1000000 / duration_mcs.count() << "." << std::endl; ++ ++ done_callback_(fd); ++} ++ ++Preview *make_fb_preview(Options const *options) ++{ ++ return new FbPreview(options); ++} +diff --git a/preview/preview.cpp b/preview/preview.cpp +index 68d193a..0086d83 100644 +--- a/preview/preview.cpp ++++ b/preview/preview.cpp +@@ -13,6 +13,7 @@ Preview *make_null_preview(Options const *options); + Preview *make_egl_preview(Options const *options); + Preview *make_drm_preview(Options const *options); + Preview *make_qt_preview(Options const *options); ++Preview *make_fb_preview(Options const *options); + + Preview *make_preview(Options const *options) + { +@@ -48,8 +49,10 @@ Preview *make_preview(Options const *options) + } + catch (std::exception const &e) + { +- std::cout << "Preview window unavailable" << std::endl; +- return make_null_preview(options); ++ std::cout << "FB Preview window." << std::endl; ++ return make_fb_preview(options); ++ // std::cout << "Preview window unavailable" << std::endl; ++ // return make_null_preview(options); + } + } + } +-- +2.17.1 + diff --git a/package/starfive/libcamera-apps/0002-add-select-camera-options.patch b/package/starfive/libcamera-apps/0002-add-select-camera-options.patch new file mode 100644 index 00000000..b3a00c9b --- /dev/null +++ b/package/starfive/libcamera-apps/0002-add-select-camera-options.patch @@ -0,0 +1,92 @@ +From aec56c70bdc7f037a88deaa4cc84854ec2c961e9 Mon Sep 17 00:00:00 2001 +From: sw.multimedia +Date: Mon, 22 Nov 2021 10:16:15 +0800 +Subject: [PATCH] add select camera options + +--- + core/libcamera_app.cpp | 29 +++++++++++++++++++++-------- + core/options.hpp | 5 +++++ + 2 files changed, 26 insertions(+), 8 deletions(-) + +diff --git a/core/libcamera_app.cpp b/core/libcamera_app.cpp +index 3c4d862..22896a7 100644 +--- a/core/libcamera_app.cpp ++++ b/core/libcamera_app.cpp +@@ -58,17 +58,30 @@ void LibcameraApp::OpenCamera() + if (camera_manager_->cameras().size() == 0) + throw std::runtime_error("no cameras available"); + +- std::string const &cam_id = camera_manager_->cameras()[0]->id(); +- camera_ = camera_manager_->get(cam_id); +- if (!camera_) +- throw std::runtime_error("failed to find camera " + cam_id); +- +- if (camera_->acquire()) +- throw std::runtime_error("failed to acquire camera " + cam_id); ++ if (options_->camera_name.length()) { ++ char *endptr; ++ unsigned long index = strtoul(options_->camera_name.c_str(), &endptr, 10); ++ std::cout << "Acquired camera name: " << options_->camera_name << std::endl; ++ if (*endptr == '\0' && index > 0 && index <= camera_manager_->cameras().size()) ++ camera_ = camera_manager_->cameras()[index - 1]; ++ else ++ camera_ = camera_manager_->get(options_->camera_name); ++ if (!camera_) ++ throw std::runtime_error("failed to find camera " + options_->camera_name); ++ if (camera_->acquire()) ++ throw std::runtime_error("failed to acquire camera " + options_->camera_name); ++ } else { ++ std::string const &cam_id = camera_manager_->cameras()[0]->id(); ++ camera_ = camera_manager_->get(cam_id); ++ if (!camera_) ++ throw std::runtime_error("failed to find camera " + cam_id); ++ if (camera_->acquire()) ++ throw std::runtime_error("failed to acquire camera " + cam_id); ++ } + camera_acquired_ = true; + + if (options_->verbose) +- std::cout << "Acquired camera " << cam_id << std::endl; ++ std::cout << "Acquired camera " << camera_->id() << std::endl; + + if (!options_->post_process_file.empty()) + post_processor_.Read(options_->post_process_file); +diff --git a/core/options.hpp b/core/options.hpp +index 5c68088..de49beb 100644 +--- a/core/options.hpp ++++ b/core/options.hpp +@@ -30,6 +30,8 @@ struct Options + "Displays the build version number") + ("verbose,v", value(&verbose)->default_value(false)->implicit_value(true), + "Output extra debug and diagnostics") ++ ("camera", value(&camera_name), ++ "Specify which camera to operate on, by id or by index") + ("config,c", value(&config_file)->implicit_value("config.txt"), + "Read the options from a file. If no filename is specified, default to config.txt. " + "In case of duplicate options, the ones provided on the command line will be used. " +@@ -115,6 +117,7 @@ struct Options + bool help; + bool version; + bool verbose; ++ std::string camera_name; + uint64_t timeout; // in ms + std::string config_file; + std::string output; +@@ -259,12 +262,14 @@ struct Options + { + std::cout << "Options:" << std::endl; + std::cout << " verbose: " << verbose << std::endl; ++ std::cout << " camera_name: " << camera_name << std::endl; + if (!config_file.empty()) + std::cout << " config file: " << config_file << std::endl; + std::cout << " info_text:" << info_text << std::endl; + std::cout << " timeout: " << timeout << std::endl; + std::cout << " width: " << width << std::endl; + std::cout << " height: " << height << std::endl; ++ std::cout << " pixelformat: " << pixelformat << std::endl; + std::cout << " output: " << output << std::endl; + std::cout << " post_process_file: " << post_process_file << std::endl; + std::cout << " rawfull: " << rawfull << std::endl; +-- +2.17.1 + diff --git a/package/starfive/libcamera-apps/0003-add-FbPreview-support-YUYV-YVYU-display.patch b/package/starfive/libcamera-apps/0003-add-FbPreview-support-YUYV-YVYU-display.patch new file mode 100644 index 00000000..d0832ccd --- /dev/null +++ b/package/starfive/libcamera-apps/0003-add-FbPreview-support-YUYV-YVYU-display.patch @@ -0,0 +1,224 @@ +From 4fd0d73ae92f4e0f49c9d0f9f7e559e55e4fe2a8 Mon Sep 17 00:00:00 2001 +From: sw.multimedia +Date: Mon, 22 Nov 2021 15:28:17 +0800 +Subject: [PATCH] add FbPreview support YUYV/YVYU display + +--- + preview/fb_preview.cpp | 123 +++++++++++++++++++++++++++++++++++------ + preview/preview.cpp | 15 +++-- + 2 files changed, 118 insertions(+), 20 deletions(-) + +diff --git a/preview/fb_preview.cpp b/preview/fb_preview.cpp +index 1a88b79..0b42ad1 100644 +--- a/preview/fb_preview.cpp ++++ b/preview/fb_preview.cpp +@@ -44,6 +44,7 @@ enum COLOR_FORMAT { + COLOR_RGB888_RGBA, // 9 + COLOR_RGB888_BGRA, // 10 + COLOR_RGB565, // 11 ++ COLOR_UNKOWN, // unkown + }; + + struct pp_video_mode { +@@ -83,6 +84,10 @@ public: + private: + int NVResize(unsigned char *inBuf, + unsigned char *outBuf, int imgWidth, int imgHeight); ++ int YUYVResize(unsigned char *inBuf, ++ unsigned char *outBuf, int imgWidth, int imgHeight); ++ void setPixformat(unsigned int format); ++ unsigned int getPixformat(void); + int g_fb_fd; + int g_stfbc_fd; + struct fb_var_screeninfo g_vinfo; +@@ -93,10 +98,8 @@ private: + enum COLOR_FORMAT pixformat; + }; + +-static enum COLOR_FORMAT v4l2fmt_to_fbfmt(unsigned int format) ++void FbPreview::setPixformat(unsigned int format) + { +- enum COLOR_FORMAT pixformat = COLOR_RGB565; +- + switch (format) { + case V4L2_PIX_FMT_RGB565: + pixformat = COLOR_RGB565; +@@ -120,11 +123,43 @@ static enum COLOR_FORMAT v4l2fmt_to_fbfmt(unsigned int format) + pixformat = COLOR_YUV422_YVYU; + break; + default: +- pixformat = COLOR_RGB565; ++ pixformat = COLOR_UNKOWN; + break; + } ++} + +- return pixformat; ++unsigned int FbPreview::getPixformat(void) ++{ ++ unsigned int format; ++ ++ switch (pixformat) { ++ case COLOR_RGB565: ++ format = V4L2_PIX_FMT_RGB565; ++ break; ++ case COLOR_RGB888_ARGB: ++ format = V4L2_PIX_FMT_RGB24; ++ break; ++ case COLOR_YUV420P: ++ format = V4L2_PIX_FMT_YUV420; ++ break; ++ case COLOR_YUV422_YUYV: ++ format = V4L2_PIX_FMT_YUYV; ++ break; ++ case COLOR_YUV420_NV21: ++ format = V4L2_PIX_FMT_NV21; ++ break; ++ case COLOR_YUV420_NV12: ++ format = V4L2_PIX_FMT_NV12; ++ break; ++ case COLOR_YUV422_YVYU: ++ format = V4L2_PIX_FMT_YVYU; ++ break; ++ default: ++ format = 0; ++ break; ++ } ++ ++ return format; + } + + FbPreview::FbPreview(Options const *options) : Preview(options) +@@ -140,10 +175,10 @@ FbPreview::FbPreview(Options const *options) : Preview(options) + libcamera::PixelFormat pixelFormat = + libcamera::PixelFormat::fromString(options_->pixelformat); + +- if (pixelFormat.fourcc() != V4L2_PIX_FMT_NV12) +- throw std::runtime_error("FB onlu support NV12 display"); ++ setPixformat(pixelFormat.fourcc()); ++ if (pixformat == COLOR_UNKOWN) ++ throw std::runtime_error("FB unsupport format display."); + +- pixformat = v4l2fmt_to_fbfmt(pixelFormat.fourcc()); + if (-1 == ioctl(g_stfbc_fd, FBIOPAN_GET_PP_MODE, &pp_info[0])) + throw std::runtime_error("Error reading variable information."); + +@@ -217,9 +252,6 @@ int FbPreview::NVResize(unsigned char *inBuf, + int fb_Ypos, fb_Upos, fb_Vpos; + int width, height; + int x_offset, y_offset; +- unsigned int start_timems; +- unsigned int end_timems; +- struct timeval ts_start, ts_end; + + width = imgWidth > g_vinfo.xres ? g_vinfo.xres : imgWidth; + height = imgHeight > g_vinfo.yres ? g_vinfo.yres : imgHeight; +@@ -264,15 +296,74 @@ int FbPreview::NVResize(unsigned char *inBuf, + return 0; + } + ++int FbPreview::YUYVResize(unsigned char *inBuf, ++ unsigned char *outBuf, int imgWidth, int imgHeight) ++{ ++ int rows, cols; ++ unsigned char *OutNVdata, *InNVdata; ++ int Ypos, fb_Ypos; ++ int width, height; ++ int x_offset, y_offset; ++ ++ width = imgWidth > g_vinfo.xres ? g_vinfo.xres : imgWidth; ++ height = imgHeight > g_vinfo.yres ? g_vinfo.yres : imgHeight; ++ x_offset = (g_vinfo.xres - width) / 2; ++ y_offset = (g_vinfo.yres - height) / 2; ++ x_offset &= ~0x1; ++ ++ InNVdata = inBuf; ++ OutNVdata = tmpBuf; ++ ++ if (imgWidth == g_vinfo.xres) { ++ fb_Ypos = y_offset * g_vinfo.xres + x_offset; ++ memcpy(&tmpBuf[fb_Ypos], inBuf, imgWidth * height * 2); ++ memcpy(&outBuf[fb_Ypos], &tmpBuf[fb_Ypos], imgWidth * height * 2); ++ return 0; ++ } ++ ++ /* two bytes for every pixels */ ++ for(rows = 0; rows < height; rows++) ++ { ++ // g_vinfo.xres, g_vinfo.yres g_vinfo.bits_per_pixel ++ fb_Ypos = ((rows + y_offset) * g_vinfo.xres + x_offset) * 2; ++ Ypos = rows * imgWidth * 2; ++ memcpy(&OutNVdata[fb_Ypos], &InNVdata[Ypos], width * 2); ++ } ++ ++ memcpy(outBuf, tmpBuf, g_screensize); ++ ++ return 0; ++} ++ + void FbPreview::Show(int fd, libcamera::Span span, int width, int height, int stride) + { +- int imgsize = stride * height + stride * height / 2; + auto startTime = std::chrono::high_resolution_clock::now(); ++ int size_valid = 0; ++ int imgsize; ++ ++ if (pixformat == COLOR_YUV420_NV21 || pixformat == COLOR_YUV420_NV12) { ++ imgsize = stride * height + stride * height / 2; ++ if (imgsize == span.size()) { ++ size_valid = 1; ++ NVResize(span.data(), g_fb_buf, width, height); ++ } ++ } else if (pixformat == COLOR_YUV422_YVYU || pixformat == COLOR_YUV422_YUYV) { ++ imgsize = stride * height; ++ if (imgsize == span.size()) { ++ size_valid = 1; ++ YUYVResize(span.data(), g_fb_buf, width, height); ++ } ++ } + +- if (pixformat == COLOR_YUV420_NV21 || pixformat == COLOR_YUV420_NV12) +- NVResize(span.data(), g_fb_buf, width, height); +- else +- std::cout << "FbPreview unsupport pixformat: " << pixformat << std::endl; ++ if (!size_valid) { ++ std::cout << "FbPreview unsupport pixformat: " << pixformat ++ << " fb need size: " << imgsize ++ << " width: " << width ++ << " height: " << height ++ << " stride: " << stride ++ << " size: " << span.size() << std::endl; ++ throw std::runtime_error("Error FbPreview unsupport pixformat."); ++ } + + auto endTime = std::chrono::high_resolution_clock::now(); + +diff --git a/preview/preview.cpp b/preview/preview.cpp +index 0086d83..17118d4 100644 +--- a/preview/preview.cpp ++++ b/preview/preview.cpp +@@ -49,10 +49,17 @@ Preview *make_preview(Options const *options) + } + catch (std::exception const &e) + { +- std::cout << "FB Preview window." << std::endl; +- return make_fb_preview(options); +- // std::cout << "Preview window unavailable" << std::endl; +- // return make_null_preview(options); ++ try { ++ std::cout << "FB Preview window." << std::endl; ++ return make_fb_preview(options); ++ if (options->verbose) ++ std::cout << "Made FB Preview window." << std::endl; ++ } ++ catch (std::exception const &e) ++ { ++ std::cout << "Preview window unavailable" << std::endl; ++ return make_null_preview(options); ++ } + } + } + } +-- +2.17.1 + diff --git a/package/starfive/libcamera-apps/0004-add-DrmPreview-support-NV12-display.patch b/package/starfive/libcamera-apps/0004-add-DrmPreview-support-NV12-display.patch new file mode 100644 index 00000000..2e86d487 --- /dev/null +++ b/package/starfive/libcamera-apps/0004-add-DrmPreview-support-NV12-display.patch @@ -0,0 +1,153 @@ +From 30ce74f6cc34ddb310cee72280d9e1e00aa4e459 Mon Sep 17 00:00:00 2001 +From: sw.multimedia +Date: Thu, 25 Nov 2021 14:57:09 +0800 +Subject: [PATCH] add DrmPreview support NV12 display + +--- + preview/drm_preview.cpp | 84 +++++++++++++++++++++++++++++++++++------ + 1 file changed, 73 insertions(+), 11 deletions(-) + +diff --git a/preview/drm_preview.cpp b/preview/drm_preview.cpp +index c444918..a969358 100644 +--- a/preview/drm_preview.cpp ++++ b/preview/drm_preview.cpp +@@ -10,6 +10,8 @@ + #include + #include + #include ++#include ++#include + + #include "core/options.hpp" + +@@ -50,6 +52,7 @@ private: + void findPlane(); + int drmfd_; + int conId_; ++ drmModeConnector *con_; + uint32_t crtcId_; + int crtcIdx_; + uint32_t planeId_; +@@ -95,10 +98,19 @@ 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]); ++ } ++ ++ if (enc->crtc_id) ++ { ++ crtc = drmModeGetCrtc(drmfd_, enc->crtc_id); ++ } ++ else ++ { ++ crtc = drmModeGetCrtc(drmfd_, res->crtcs[0]); + } + + if (!conId_ && crtc) +@@ -161,6 +173,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_); +@@ -227,10 +241,13 @@ void DrmPreview::findPlane() + + DrmPreview::DrmPreview(Options const *options) : Preview(options), last_fd_(-1) + { +- drmfd_ = drmOpen("vc4", NULL); ++ // drmfd_ = drmOpen("vc4", NULL); ++ drmfd_ = open("/dev/dri/card0", O_RDWR | O_CLOEXEC); + 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; +@@ -245,7 +262,12 @@ DrmPreview::DrmPreview(Options const *options) : Preview(options), last_fd_(-1) + + conId_ = 0; + findCrtc(); +- out_fourcc_ = DRM_FORMAT_YUV420; ++ if (options_->pixelformat.length()) { ++ libcamera::PixelFormat pixelFormat = ++ libcamera::PixelFormat::fromString(options_->pixelformat); ++ out_fourcc_ = pixelFormat.fourcc(); ++ } else ++ out_fourcc_ = DRM_FORMAT_YUV420; + findPlane(); + } + catch (std::exception const &e) +@@ -281,12 +303,52 @@ void DrmPreview::makeBuffer(int fd, size_t size, unsigned int width, unsigned in + if (drmPrimeFDToHandle(drmfd_, fd, &buffer.bo_handle)) + throw std::runtime_error("drmPrimeFDToHandle failed for fd " + std::to_string(fd)); + +- 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)) ++ 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 span, int width, int height, int stride) +-- +2.17.1 + diff --git a/package/starfive/libcamera-apps/Config.in b/package/starfive/libcamera-apps/Config.in new file mode 100644 index 00000000..16cb7ad0 --- /dev/null +++ b/package/starfive/libcamera-apps/Config.in @@ -0,0 +1,19 @@ +config BR2_PACKAGE_LIBCAMERA_APPS + bool "libcamera-apps" + depends on BR2_PACKAGE_LIBCAMERA + select BR2_PACKAGE_GNUTLS + select BR2_PACKAGE_BOOST + select BR2_PACKAGE_BOOST_PROGRAM_OPTIONS + select BR2_PACKAGE_BOOST_SYSTEM + select BR2_PACKAGE_TIFF + select BR2_PACKAGE_LIBEXIF + select BR2_PACKAGE_LIBYUV + select BR2_PACKAGE_LIBPNG + help + libcamera-apps provides a software stack to support + complex devices that need heavy hardware image + processing operations. + +comment "libcamera-apps needs a toolchain w/ C++, threads, wchar, dynamic library, gcc >= 7" + depends on !BR2_INSTALL_LIBSTDCPP || !BR2_TOOLCHAIN_HAS_THREADS || \ + !BR2_TOOLCHAIN_GCC_AT_LEAST_7 || BR2_STATIC_LIBS || !BR2_USE_WCHAR diff --git a/package/starfive/libcamera-apps/libcamera-apps.hash b/package/starfive/libcamera-apps/libcamera-apps.hash new file mode 100644 index 00000000..ef2e40d3 --- /dev/null +++ b/package/starfive/libcamera-apps/libcamera-apps.hash @@ -0,0 +1,3 @@ +sha256 5600c4289457c03a5062001f5942c77fabe4fcef8877b67cfaeed5bae5672756 libcamera-apps-main.tar.gz +sha256 3fe6e9e343f268c518652a00260791c55f18cd5902fd5de578005b9c6ec9785b libcamera-apps-87f807f4eacf7d62021e3b4061348e64b2ecadc3.tar.gz +sha256 09a169037dfba889bc9f449aaefc18c210fdf4eb7ea02cffd4a36c383b71583c libcamera-apps-87f807f4eacf7d62021e3b4061348e64b2ecadc3-br1.tar.gz diff --git a/package/starfive/libcamera-apps/libcamera-apps.mk b/package/starfive/libcamera-apps/libcamera-apps.mk new file mode 100644 index 00000000..bea861bc --- /dev/null +++ b/package/starfive/libcamera-apps/libcamera-apps.mk @@ -0,0 +1,14 @@ +################################################################################ +# +# libcamera-apps +# +################################################################################ + +LIBCAMERA_APPS_SITE = git@github.com:raspberrypi/libcamera-apps.git +LIBCAMERA_APPS_VERSION = 87f807f4eacf7d62021e3b4061348e64b2ecadc3 +LIBCAMERA_APPS_SITE_METHOD = git +LIBCAMERA_APPS_INSTALL_STAGING = YES + +LIBCAMERA_APPS_DEPENDENCIES = libcamera libexif tiff boost host-pkgconf + +$(eval $(cmake-package))