123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- From 6abadc7414f0fdfea160374326cea32bd2b40d7d Mon Sep 17 00:00:00 2001
- From: sw.multimedia <sw.multimedia@starfivetech.com>
- 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<unsigned int>(&height)->default_value(0),
- "Set the output image height (0 = use default value)")
- + ("pixelformat", value<std::string>(&pixelformat),
- + "Set the pixelformat name")
- ("timeout,t", value<uint64_t>(&timeout)->default_value(5000),
- "Time (in ms) for which program runs")
- ("output,o", value<std::string>(&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 <iostream>
- +#include <sys/mman.h>
- +#include <stdio.h>
- +#include <unistd.h>
- +#include <errno.h>
- +#include <malloc.h>
- +#include <sys/types.h>
- +#include <sys/stat.h>
- +#include <fcntl.h>
- +#include <sys/ioctl.h>
- +#include <linux/fb.h>
- +#include <string.h>
- +#include <malloc.h>
- +#include <linux/videodev2.h>
- +#include <libcamera/formats.h>
- +#include <chrono>
- +
- +#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<uint8_t> 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<unsigned char *>(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<uint8_t> 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<double,std::ratio<1,1000000>> duration_mcs =
- + std::chrono::duration_cast<std::chrono::duration<double,std::ratio<1,1000000>>>(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
|