Skip to content

Commit

Permalink
* camera application support add timestamp
Browse files Browse the repository at this point in the history
  • Loading branch information
lxowalle committed Dec 3, 2024
1 parent e74cab3 commit ddab5d6
Show file tree
Hide file tree
Showing 8 changed files with 349 additions and 2 deletions.
59 changes: 57 additions & 2 deletions projects/app_camera/main/app/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "maix_fs.hpp"
#include "maix_vision.hpp"
#include "maix_ffmpeg.hpp"
#include "region.hpp"
#include "sophgo_middleware.hpp"
#include <sys/ioctl.h>
#include <sys/types.h>
Expand Down Expand Up @@ -43,6 +44,7 @@ static struct {
std::string video_mp4_path;

uint64_t loop_last_ms;
uint64_t last_update_region_ms;
void *loop_last_frame;

bool camera_resolution_update_flag;
Expand All @@ -57,8 +59,11 @@ static struct {
gpio::GPIO *light;
ffmpeg::FFmpegPacker *ffmpeg_packer;
audio::Recorder *audio_recorder;
Region *region;
int encoder_bitrate;

bool show_timestamp_enable;

uint64_t last_read_pcm_ms;
uint64_t last_read_cam_ms;
uint64_t video_pts;
Expand Down Expand Up @@ -271,6 +276,15 @@ int app_base_init(void)
priv.camera = new camera::Camera(priv.camera_resolution_w, priv.camera_resolution_h, image::Format::FMT_YVU420SP, NULL, fps, 3, true, priv.capture_raw_enable);
err::check_bool_raise(priv.camera->is_opened(), "camera open failed");

// // init region
// auto string_size = image::string_size("2024/09/20 10:23:33");
// auto region_w = 200;
// auto region_h = string_size.height();
// auto region_x = 10;
// auto region_y = priv.camera->height() - region_h - 10;
// priv.region = new Region(region_x, region_y, region_w, region_h, image::FMT_BGRA8888, priv.camera);
// err::check_null_raise(priv.region, "region open failed");

// init display
priv.disp = new display::Display();
priv.other_disp = priv.disp->add_channel(); // This object(other_disp) is depend on disp, so we must keep disp.show() running.
Expand Down Expand Up @@ -359,6 +373,11 @@ int app_base_deinit(void)
priv.disp = NULL;
}

if (priv.region) {
delete priv.region;
priv.region = nullptr;
}

if (priv.camera) {
if (priv.loop_last_frame) {
_mmf_vi_frame_free(priv.camera->get_channel(), &priv.loop_last_frame);
Expand Down Expand Up @@ -491,7 +510,7 @@ int app_base_loop(void)
priv.video_pts += priv.ffmpeg_packer->video_us_to_pts((time::ticks_ms() - priv.last_read_cam_ms) * 1000);
priv.last_read_cam_ms = time::ticks_ms();
}
log::info("[VIDEO] pts:%d pts %f s", priv.video_pts, priv.ffmpeg_packer->video_pts_to_us(priv.video_pts) / 1000000);
// log::info("[VIDEO] pts:%d pts %f s", priv.video_pts, priv.ffmpeg_packer->video_pts_to_us(priv.video_pts) / 1000000);
if (err::ERR_NONE != priv.ffmpeg_packer->push(data, data_size, priv.video_pts)) {
log::error("ffmpeg push failed!");
}
Expand Down Expand Up @@ -520,7 +539,7 @@ int app_base_loop(void)
Bytes *pcm_data = priv.audio_recorder->record_bytes(read_pcm_size);
if (pcm_data) {
if (pcm_data->data_len > 0) {
log::info("[AUDIO] pts:%d pts %f s", priv.audio_pts, priv.ffmpeg_packer->audio_pts_to_us(priv.audio_pts) / 1000000);
// log::info("[AUDIO] pts:%d pts %f s", priv.audio_pts, priv.ffmpeg_packer->audio_pts_to_us(priv.audio_pts) / 1000000);
if (err::ERR_NONE != priv.ffmpeg_packer->push(pcm_data->data, pcm_data->data_len, priv.audio_pts, true)) {
log::error("ffmpeg push failed!");
}
Expand All @@ -546,6 +565,23 @@ int app_base_loop(void)
lv_timer_handler();

app_loop(*priv.camera, *priv.disp, priv.other_disp);

if (priv.show_timestamp_enable) {
uint64_t curr_ms = time::ticks_ms();
if (curr_ms - priv.last_update_region_ms > 1000) {
if (priv.region) {
auto img = priv.region->get_canvas();
auto datetime = time::now();
auto str1 = datetime->strftime("%Y/%m/%d %H:%M:%S");
delete datetime;
img->draw_string(0, 0, str1, image::COLOR_WHITE);
priv.region->update_canvas();
// log::info("use:%lld str:%s", time::ticks_ms() - curr_ms, str1.c_str());
}
priv.last_update_region_ms = curr_ms;
}
}

// printf("loop time: %ld ms\n", time::ticks_ms() - priv.loop_last_ms);
// priv.loop_last_ms = time::ticks_ms();
return 0;
Expand Down Expand Up @@ -772,6 +808,25 @@ static int app_config_param(void)
}
}

if (ui_get_timestamp_btn_update_flag()) {
priv.show_timestamp_enable = ui_get_timestamp_btn_touched();
if (priv.region) {
delete priv.region;
priv.region = nullptr;
}

if (priv.show_timestamp_enable) {
// init region
auto string_size = image::string_size("2024/09/20 10:23:33");
auto region_w = 200;
auto region_h = string_size.height();
auto region_x = 10;
auto region_y = priv.camera->height() - region_h - 10;
priv.region = new Region(region_x, region_y, region_w, region_h, image::FMT_BGRA8888, priv.camera);
err::check_null_raise(priv.region, "region open failed");
}
}

return 0;
}

Expand Down
126 changes: 126 additions & 0 deletions projects/app_camera/main/app/region.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#include "region.hpp"

Region::Region(int x, int y, int width, int height, image::Format format, camera::Camera *camera)
{
if (format != image::Format::FMT_BGRA8888) {
err::check_raise(err::ERR_RUNTIME, "region support FMT_BGRA8888 only!");
}

if (camera == NULL) {
err::check_raise(err::ERR_RUNTIME, "region bind a NULL camera!");
}

// int rgn_id = mmf_get_region_unused_channel();
int rgn_id = 1;
if (rgn_id < 0) {
err::check_raise(err::ERR_RUNTIME, "no more region id!");
}

int flip = true;
int mirror = true;
auto configs = sys::device_configs(true);
for (auto &item : configs) {
log::info("device:%s value:%s", item.first.c_str(), item.second.c_str());
}
auto mirror_string = configs.find("cam_flip");
auto flip_string = configs.find("cam_mirror");
if (mirror_string != configs.end()) {
mirror = !atoi(mirror_string->second.c_str());
}

if (flip_string != configs.end()) {
flip = !atoi(flip_string->second.c_str());
}

int x2 = flip ? camera->width() - width - x : x;
int y2 = mirror ? camera->height() - height - y : y;

int vi_vpss = 0;
int vi_vpss_chn = camera->get_channel();
if (0 != mmf_add_region_channel_v2(rgn_id, 0, 6, vi_vpss, vi_vpss_chn, x2, y2, width, height, mmf_invert_format_to_mmf(format))) {
err::check_raise(err::ERR_RUNTIME, "mmf_add_region_channel_v2 failed!");
}
this->_id = rgn_id;
this->_width = width;
this->_height = height;
this->_x = x;
this->_y = y;
this->_format = format;
this->_camera = camera;
this->_flip = flip;
this->_mirror = mirror;
}
Region::~Region()
{
if (mmf_del_region_channel(this->_id) < 0) {
err::check_raise(err::ERR_RUNTIME, "mmf_del_region_unused_channel failed!");
}
}

image::Image *Region::get_canvas()
{
void *data;
if (0 != mmf_region_get_canvas(this->_id, &data, NULL, NULL, NULL)) {
err::check_raise(err::ERR_RUNTIME, "mmf_region_get_canvas failed!");
}

image::Image *img = NULL;
switch (this->_format) {
case image::Format::FMT_BGRA8888:
img = new image::Image(this->_width, this->_height, this->_format, (uint8_t *)data, this->_width * this->_height * 4, false);
if (img == NULL) {
mmf_del_region_channel(this->_id);
err::check_raise(err::ERR_RUNTIME, "malloc failed!");
}
memset(img->data(), 0, img->data_size());
break;
default:err::check_raise(err::ERR_RUNTIME, "region format not support!");break;
}

this->_image = img;

return img;
}

err::Err Region::update_canvas()
{
image::Image *img = this->_image;
if (img->format() == image::Format::FMT_BGRA8888) {
uint32_t *data_u32 = (uint32_t *)img->data();
int width = img->width();
int height = img->height();

if (this->_flip) {
for (int h = 0; h < height; h ++) {
for (int w = 0; w < width / 2; w ++) {
int left_idx = h * width + w;
int right_idx = h * width + (width - 1 - w);
uint32_t tmp = data_u32[left_idx];
data_u32[left_idx] = data_u32[right_idx];
data_u32[right_idx] = tmp;
}
}
}

if (this->_mirror) {
for (int h = 0; h < height / 2; h ++) {
for (int w = 0; w < width; w ++) {
int left_idx = h * width + w;
int right_idx = (height - 1 - h) * width + w;
uint32_t tmp = data_u32[left_idx];
data_u32[left_idx] = data_u32[right_idx];
data_u32[right_idx] = tmp;
}
}
}
} else {
log::error("support FMT_BGRA888 only!\r\n");
return err::ERR_RUNTIME;
}

if (0 != mmf_region_update_canvas(this->_id)) {
log::error("mmf_region_update_canvas failed!\r\n");
return err::ERR_RUNTIME;
}
return err::ERR_NONE;
}
30 changes: 30 additions & 0 deletions projects/app_camera/main/app/region.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef __MMF_REGION_H
#define __MMF_REGION_H

#include "maix_image.hpp"
#include "maix_vision.hpp"
#include "sophgo_middleware.hpp"

using namespace maix;

class Region {
private:
int _id;
int _x;
int _y;
int _width;
int _height;
bool _flip;
bool _mirror;
image::Format _format;
image::Image *_image;
camera::Camera *_camera;
public:
Region(int x, int y, int width, int height, image::Format format, camera::Camera *camera);
~Region();

image::Image *get_canvas();
err::Err update_canvas();
};

#endif // __MMF_REGION_H
27 changes: 27 additions & 0 deletions projects/app_camera/main/app/ui_event_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ extern lv_obj_t *g_raw_button;
extern lv_obj_t *g_light_button;
extern lv_obj_t *g_bitrate_button;
extern lv_obj_t *g_drop_down_img;
extern lv_obj_t *g_timestamp_button;

static struct {
unsigned int camera_snap_start_flag : 1;
Expand All @@ -75,6 +76,8 @@ static struct {
unsigned int raw_btn_update_flag : 1;
unsigned int light_btn_touched : 1;
unsigned int light_btn_update_flag : 1;
unsigned int timestamp_btn_touched : 1;
unsigned int timestamp_btn_update_flag : 1;

unsigned int resolution_setting_idx;
unsigned int bitrate;
Expand Down Expand Up @@ -621,6 +624,20 @@ void event_touch_light_cb(lv_event_t * e)
}
}

void event_touch_timestamp_cb(lv_event_t * e)
{
lv_event_code_t code = lv_event_get_code(e);
if (code == LV_EVENT_CLICKED) {
if (lv_obj_get_state(g_timestamp_button) != LV_STATE_FOCUSED) {
priv.timestamp_btn_touched = 1;
priv.timestamp_btn_update_flag = 1;
} else {
priv.timestamp_btn_touched = 0;
priv.timestamp_btn_update_flag = 1;
}
}
}

static double bar_value_to_exp_us(lv_obj_t *obj, uint16_t shutter_bar_value)
{
DEBUG_EN(0);
Expand Down Expand Up @@ -1641,4 +1658,14 @@ void ui_set_bitrate(int bitrate, bool need_update)
priv.bitrate_update_flag = need_update;
}
}
}

bool ui_get_timestamp_btn_update_flag() {
bool flag = priv.timestamp_btn_update_flag ? true : false;
priv.timestamp_btn_update_flag = false;
return flag;
}

bool ui_get_timestamp_btn_touched() {
return priv.timestamp_btn_touched ? true : false;
}
4 changes: 4 additions & 0 deletions projects/app_camera/main/app/ui_event_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ void event_touch_iso_plus_cb(lv_event_t *e);
void event_touch_iso_minus_cb(lv_event_t *e);
void event_touch_raw_cb(lv_event_t * e);
void event_touch_light_cb(lv_event_t * e);
void event_touch_timestamp_cb(lv_event_t * e);

bool ui_get_cam_snap_flag(void);
bool ui_get_cam_video_start_flag(void);
Expand Down Expand Up @@ -91,6 +92,9 @@ bool ui_get_bitrate_update_flag();
void ui_set_bitrate(int bitrate, bool need_update);
int ui_get_bitrate();

bool ui_get_timestamp_btn_update_flag();
bool ui_get_timestamp_btn_touched();

typedef struct {
unsigned int exposure_time_max;
unsigned int exposure_time_min;
Expand Down
23 changes: 23 additions & 0 deletions projects/app_camera/main/app/ui_screen.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ lv_obj_t *g_light_button;
lv_obj_t *g_raw_button;
lv_obj_t *g_shutter_plus_minus_button;
lv_obj_t *g_iso_plus_minus_button;
lv_obj_t *g_timestamp_button;

lv_obj_t *g_drop_down_img;

Expand All @@ -75,6 +76,7 @@ LV_IMG_DECLARE(img_light_on);
LV_IMG_DECLARE(img_light_off);
LV_IMG_DECLARE(img_bitrate);
LV_IMG_DECLARE(img_drop_down);
LV_IMG_DECLARE(img_timestamp);

extern void event_touch_exit_cb(lv_event_t * e);
extern void event_touch_delay_cb(lv_event_t * e);
Expand Down Expand Up @@ -334,6 +336,27 @@ static void left_screen_init(void)
lv_obj_set_style_text_font(label, &lv_font_montserrat_16, 0);
lv_obj_center(label);
}

{
lv_obj_t *obj = lv_obj_create(scr);
lv_obj_set_size(obj, lv_pct(100), lv_pct(25));
lv_obj_set_pos(obj, 0, lv_pct(200));
lv_obj_set_style_bg_color(obj, lv_color_hex(0), 0);
lv_obj_set_style_bg_color(obj, lv_color_hex(0x2e2e2e), LV_STATE_CHECKED);
lv_obj_set_style_border_side(obj, LV_BORDER_SIDE_NONE, 0);
lv_obj_set_style_radius(obj, 0, 0);
lv_obj_remove_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_add_flag(obj, LV_OBJ_FLAG_CLICKABLE | LV_OBJ_FLAG_CHECKABLE);
lv_obj_add_event_cb(obj, event_touch_timestamp_cb, LV_EVENT_CLICKED, NULL);
g_timestamp_button = obj;
lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_style_pad_column(obj, 0, 0);

img = lv_image_create(obj);
lv_image_set_src(img, &img_timestamp);
lv_obj_center(img);
}
}

static void right_screen_init(void)
Expand Down
Loading

0 comments on commit ddab5d6

Please sign in to comment.