diff --git a/components/vision/port/linux/maix_uvc_stream.cpp b/components/vision/port/linux/maix_uvc_stream.cpp new file mode 100644 index 00000000..8fff93a2 --- /dev/null +++ b/components/vision/port/linux/maix_uvc_stream.cpp @@ -0,0 +1,44 @@ +#include +#include + +#include +#include +#include +#include + +#include "maix_uvc_stream.hpp" + +extern "C" { + +extern int uvc_main_exist; +extern int uvc_main(int argc, char *argv[]); + +int uvc_video_fill_mjpg_buffer(void *buf, uint32_t *size) { + return -1; +} + +} + +namespace maix::uvc +{ +int helper_fill_mjpg_image(void* buf, uint32_t* size, image::Image *img) { + return -1; +} + +// 静态成员定义 +UvcServer *UvcServer::_instance = nullptr; + +void UvcServer::run() { } + +void UvcServer::stop() { } + +UvcStreamer::UvcStreamer(): _using_jpeg(0) { } + +UvcStreamer::~UvcStreamer() { } + + +err::Err UvcStreamer::show(image::Image *img) { + return err::ERR_NOT_IMPL; +} + +} \ No newline at end of file diff --git a/components/vision/port/maixcam/maix_uvc_stream.cpp b/components/vision/port/maixcam/maix_uvc_stream.cpp index 7aa45bfc..502e002d 100644 --- a/components/vision/port/maixcam/maix_uvc_stream.cpp +++ b/components/vision/port/maixcam/maix_uvc_stream.cpp @@ -77,13 +77,6 @@ void UvcServer::stop() { maix::log::info("server restart\r\n"); } -/** - * cannot include it, because it brokes maixpy_wrapper.cpp:1027:38: error: expected unqualified-id before numeric constant - * 1027 | .value("SEEK_SET", fs::SEEK::SEEK_SET) - */ -// #include -#define O_RDWR 2 - #define atomic_load(ptr) __atomic_load_n(ptr, __ATOMIC_SEQ_CST) #define atomic_store(ptr, value) __atomic_store_n(ptr, value, __ATOMIC_SEQ_CST) diff --git a/projects/app_uvc_camera/.gitignore b/projects/app_uvc_camera/.gitignore new file mode 100644 index 00000000..fab7cec0 --- /dev/null +++ b/projects/app_uvc_camera/.gitignore @@ -0,0 +1,9 @@ + +build +dist +.config.mk +.flash.conf.json +data + +/CMakeLists.txt + diff --git a/projects/app_uvc_camera/app.yaml b/projects/app_uvc_camera/app.yaml new file mode 100644 index 00000000..c1762965 --- /dev/null +++ b/projects/app_uvc_camera/app.yaml @@ -0,0 +1,12 @@ +id: uvc_camera +name: UVC Camera +name[zh]: UVC相机 +version: 1.0.0 +icon: assets/uvc_camera.json +author: Sipeed Ltd +desc: UVC Camera APP, show pictures on your PC +desc[zh]: UVC照相机应用,在你的电脑上显示画面 +files: + app.yaml: app.yaml + assets: assets + diff --git a/projects/app_uvc_camera/assets/ret.png b/projects/app_uvc_camera/assets/ret.png new file mode 100644 index 00000000..99aa76b2 Binary files /dev/null and b/projects/app_uvc_camera/assets/ret.png differ diff --git a/projects/app_uvc_camera/assets/uvc_camera.json b/projects/app_uvc_camera/assets/uvc_camera.json new file mode 100644 index 00000000..5b45c95d --- /dev/null +++ b/projects/app_uvc_camera/assets/uvc_camera.json @@ -0,0 +1 @@ +{"v":"5.5.7","fr":24,"ip":0,"op":113,"w":1920,"h":1080,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","td":1,"sr":1,"ks":{"o":{"a":0,"k":33,"ix":11},"r":{"a":0,"k":59,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0,"y":0},"t":75,"s":[1400.934,956.094,0],"to":[-108.884,-112.133,0],"ti":[108.884,112.133,0]},{"t":105,"s":[747.632,283.294,0]}],"ix":2},"a":{"a":0,"k":[528.07,304.922,0],"ix":1},"s":{"a":0,"k":[96.184,121.047,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[26.73,373.958],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[600.746,307.39],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 2","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[83.859,357.844],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[528.07,304.922],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 2","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1023.744,558.744,0],"ix":2},"a":{"a":0,"k":[63.744,18.744,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[307.488,307.488],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.463,-0.522],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[104.865,104.865],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"red dot","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.915],"y":[-0.033]},"t":60.177,"s":[0]},{"t":72,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[630.655,239.905,0],"ix":2},"a":{"a":0,"k":[-297.38,-258.381,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[83.238,83.238],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.958700980392,0.21661825741,0.41830405441,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-297.38,-258.381],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"lense","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.144],"y":[1]},"o":{"x":[0],"y":[0]},"t":45,"s":[0]},{"t":62,"s":[100]}],"ix":11},"r":{"a":0,"k":46,"ix":10},"p":{"a":0,"k":[960,540,0],"ix":2},"a":{"a":0,"k":[56.474,62.473,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":45,"s":[0,0,100]},{"t":62,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[262.946,262.946],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.057923238418,0.080224459779,0.351317401961,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[56.474,62.473],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[120.413,120.413],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"focal","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0],"y":[1]},"o":{"x":[1],"y":[0]},"t":23.764,"s":[0]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.703],"y":[0]},"t":24,"s":[0]},{"t":46.12109375,"s":[100]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":28,"s":[-103]},{"t":42,"s":[0]}],"ix":10},"p":{"a":0,"k":[960,540,0],"ix":2},"a":{"a":0,"k":[-13.47,25.53,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":0,"s":[-8.103,-8.103,100]},{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":28,"s":[36.897,36.897,100]},{"t":42,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[393.059,393.059],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-13.47,25.53],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"body","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[960,540,0],"ix":2},"a":{"a":0,"k":[115.847,26.596,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[1,1,0.333],"y":[0,0,0]},"t":0,"s":[20.607,20.764,100]},{"t":28,"s":[102.607,103.391,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[867.692,785.192],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":121,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.913725550034,0.898039275525,0.898039275525,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[115.847,26.596],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/projects/app_uvc_camera/compile/priority.conf b/projects/app_uvc_camera/compile/priority.conf new file mode 100644 index 00000000..b3e97013 --- /dev/null +++ b/projects/app_uvc_camera/compile/priority.conf @@ -0,0 +1,9 @@ +# component register priority +# The upper components have higher priority +# comments start with `#` + +basic +lvgl +main +uvc + diff --git a/projects/app_uvc_camera/main/CMakeLists.txt b/projects/app_uvc_camera/main/CMakeLists.txt new file mode 100644 index 00000000..452f67bd --- /dev/null +++ b/projects/app_uvc_camera/main/CMakeLists.txt @@ -0,0 +1,74 @@ +############### Add include ################### +list(APPEND ADD_INCLUDE "include" + ) +list(APPEND ADD_PRIVATE_INCLUDE "") +############################################### + +############ Add source files ################# +# list(APPEND ADD_SRCS "src/main.c" +# "src/test.c" +# ) +append_srcs_dir(ADD_SRCS "src") # append source file in src dir to var ADD_SRCS +# list(REMOVE_ITEM COMPONENT_SRCS "src/test2.c") +# FILE(GLOB_RECURSE EXTRA_SRC "src/*.c") +# FILE(GLOB EXTRA_SRC "src/*.c") +# list(APPEND ADD_SRCS ${EXTRA_SRC}) +# aux_source_directory(src ADD_SRCS) # collect all source file in src dir, will set var ADD_SRCS +# append_srcs_dir(ADD_SRCS "src") # append source file in src dir to var ADD_SRCS +# list(REMOVE_ITEM COMPONENT_SRCS "src/test.c") +# set(ADD_ASM_SRCS "src/asm.S") +# list(APPEND ADD_SRCS ${ADD_ASM_SRCS}) +# SET_PROPERTY(SOURCE ${ADD_ASM_SRCS} PROPERTY LANGUAGE C) # set .S ASM file as C language +# SET_SOURCE_FILES_PROPERTIES(${ADD_ASM_SRCS} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp -D BBBBB") +############################################### + +###### Add required/dependent components ###### +list(APPEND ADD_REQUIREMENTS basic nn vision) +############################################### + +###### Add link search path for requirements/libs ###### +# list(APPEND ADD_LINK_SEARCH_PATH "${CONFIG_TOOLCHAIN_PATH}/lib") +# list(APPEND ADD_REQUIREMENTS pthread m) # add system libs, pthread and math lib for example here +# set (OpenCV_DIR opencv/lib/cmake/opencv4) +# find_package(OpenCV REQUIRED) +############################################### + +############ Add static libs ################## +# list(APPEND ADD_STATIC_LIB "lib/libtest.a") +############################################### + +#### Add compile option for this component #### +#### Just for this component, won't affect other +#### modules, including component that depend +#### on this component +# list(APPEND ADD_DEFINITIONS_PRIVATE -DAAAAA=1) + +#### Add compile option for this component +#### and components depend on this component +# list(APPEND ADD_DEFINITIONS -DAAAAA222=1 +# -DAAAAA333=1) +############################################### + +############ Add static libs ################## +#### Update parent's variables like CMAKE_C_LINK_FLAGS +# set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--start-group libmaix/libtest.a -ltest2 -Wl,--end-group" PARENT_SCOPE) +############################################### + +######### Add files need to download ######### +# list(APPEND ADD_FILE_DOWNLOADS "{ +# 'url': 'https://*****/abcde.tar.xz', +# 'urls': [], # backup urls, if url failed, will try urls +# 'sites': [], # download site, user can manually download file and put it into dl_path +# 'sha256sum': '', +# 'filename': 'abcde.tar.xz', +# 'path': 'toolchains/xxxxx', +# 'check_files': [] +# }" +# ) +# +# then extracted file in ${DL_EXTRACTED_PATH}/toolchains/xxxxx, +# you can directly use then, for example use it in add_custom_command +############################################## + +# register component, DYNAMIC or SHARED flags will make component compiled to dynamic(shared) lib +register_component() diff --git a/projects/app_uvc_camera/main/Kconfig b/projects/app_uvc_camera/main/Kconfig new file mode 100644 index 00000000..e69de29b diff --git a/projects/app_uvc_camera/main/include/main.h b/projects/app_uvc_camera/main/include/main.h new file mode 100644 index 00000000..45dcbb04 --- /dev/null +++ b/projects/app_uvc_camera/main/include/main.h @@ -0,0 +1,3 @@ +#pragma once + + diff --git a/projects/app_uvc_camera/main/src/main.cpp b/projects/app_uvc_camera/main/src/main.cpp new file mode 100644 index 00000000..986677b9 --- /dev/null +++ b/projects/app_uvc_camera/main/src/main.cpp @@ -0,0 +1,105 @@ +#include +#include + +using namespace std; +using namespace chrono_literals; + +#include "maix_basic.hpp" +#include "maix_vision.hpp" +#include "maix_touchscreen.hpp" +#include "maix_uvc_stream.hpp" + +using namespace maix; + +#include "main.h" + +static std::unique_ptr pCam = nullptr; + +int my_uvc_video_fill_mjpg_buffer(void *buf, uint32_t *size) { + static uint64_t frame_count = 0; + static uint64_t last_ms; + if (!pCam) return 1; + + image::Image *img = pCam->read(); + if (!img) return 1; + uint64_t curr_ms_takeframe = time::ticks_ms(); + + std::ostringstream oss; + oss << "frame[" << img->width() << "x" << img->height() << "]: " << frame_count; + img->draw_string(4, 32, oss.str(), image::Color::from_rgb(255, 0, 0), 1.3); + + uvc::helper_fill_mjpg_image(buf, size, img); + uint64_t curr_ms_mjpgframe = time::ticks_ms(); + + delete img; +#if 0 + char result_bin_name[32]; + sprintf((char *)result_bin_name, "/root/res/res_%llu.jpg", frame_count); + ofstream((const char*)result_bin_name, std::ios::binary) + .write(reinterpret_cast(buf), *size); +#endif + + uint64_t curr_ms = time::ticks_ms(); + static uint32_t flip = 1; + if(flip^=1) log::info("[%llu]loop use %lld ms, %.2ffps, %d bytes\r\n" + "\ttake: %lld ms\r\n" + "\tto_mjpg: %lld ms\r\n", frame_count++, curr_ms - last_ms, 1000.f/(curr_ms - last_ms), *size, + curr_ms_takeframe - last_ms, curr_ms_mjpgframe - curr_ms_takeframe); + last_ms = curr_ms; + return 0; +} + +int _main(int argc, char *argv[]) +{ + int ret = 0; + log::info("Program start"); + + + image::Image *ret_img = image::load("./assets/ret.png", image::Format::FMT_RGB888); + if (!ret_img) + { + log::error("load ret image failed"); + return -12345; + } + display::Display disp = display::Display(); + image::Image img(disp.width(), disp.height()); + img.draw_image(0, 0, *ret_img); + disp.show(img); + + log::info("open camera now"); + camera::Camera cam = camera::Camera(1280, 720, image::Format::FMT_RGB888, "", 60, 3); + if(!pCam) pCam = make_unique(std::move(cam)); + log::info("open camera success"); + + touchscreen::TouchScreen ts; + int ts_x = 0, ts_y = 0; + bool ts_pressed = false; + + std::unique_ptr pUvc = std::make_unique(my_uvc_video_fill_mjpg_buffer); + pUvc->run(); + img.draw_string(100, disp.height()/2, std::string("UVC started."), image::Color::from_rgb(0, 255, 0), 1.3); + disp.show(img); + while (!app::need_exit()) + { + std::this_thread::sleep_for(300ms); + ts.read(ts_x, ts_y, ts_pressed); + if (ts_pressed && ts_x < 40 + 60 && ts_y < 40) + break; + } + pUvc->stop(); + + log::info("Program exit"); + + return ret; +} + +int main(int argc, char *argv[]) +{ + // Catch signal and process + sys::register_default_signal_handle(); + + // Use CATCH_EXCEPTION_RUN_RETURN to catch exception, + // if we don't catch exception, when program throw exception, the objects will not be destructed. + // So we catch exception here to let resources be released(call objects' destructor) before exit. + CATCH_EXCEPTION_RUN_RETURN(_main, -1, argc, argv); +}