Initial commit: TXW82x FPV v2.7.0.7-42229 SDK + project sources

This commit is contained in:
2026-07-06 11:30:13 +08:00
commit e76462eeb7
3451 changed files with 1415300 additions and 0 deletions

View File

@@ -0,0 +1,104 @@
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
#include "stream_frame.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
#include "audio_media_ctrl/audio_media_ctrl.h"
//data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
//结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
extern lv_indev_t * indev_keypad;
extern lv_style_t g_style;
struct audio_dac_test_ui_s
{
lv_group_t *last_group;
lv_obj_t *base_ui;
lv_group_t *now_group;
lv_obj_t *now_label;
lv_obj_t *now_ui;
struct msi *audio_play_msi;
};
static void exit_audio_dac_test_ui(lv_event_t * e)
{
struct audio_dac_test_ui_s *ui_s = (struct audio_dac_test_ui_s *)lv_event_get_user_data(e);
lv_indev_set_group(indev_keypad, ui_s->last_group);
lv_obj_clear_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_del(ui_s->now_label);
lv_group_del(ui_s->now_group);
ui_s->now_group = NULL;
ui_s->now_label = NULL;
#if AUDIO_EN
if(ui_s->audio_play_msi) {
audio_file_play_stop(ui_s->audio_play_msi);
ui_s->audio_play_msi = NULL;
}
#endif
lv_obj_del(ui_s->now_ui);
}
static void enter_audio_dac_test_ui(lv_event_t * e)
{
struct audio_dac_test_ui_s *ui_s = (struct audio_dac_test_ui_s *)lv_event_get_user_data(e);
lv_obj_add_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_t *ui = lv_obj_create(lv_scr_act());
ui_s->now_ui = ui;
// lv_obj_add_style(ui, &g_style, 0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
lv_obj_t *label = lv_label_create(lv_scr_act());
lv_obj_set_size(label, LV_PCT(100), LV_PCT(100));
lv_label_set_text(label, "audio_dac_test");
lv_obj_align(label,LV_ALIGN_CENTER,0,0);
ui_s->now_label = label;
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_group_add_obj(group, ui);
ui_s->now_group = group;
#if AUDIO_EN
if(ui_s->audio_play_msi) {
audio_file_play_stop(ui_s->audio_play_msi);
ui_s->audio_play_msi = NULL;
}
msi_cmd("R_AUDAC", MSI_CMD_AUDAC, MSI_AUDAC_SET_MEDIA_VOLUME, 30);
AUDEC_INIT audec_init;
audec_init.track_type = MEDIA_TRACK;
audec_init.priority = play_interruptible;
audec_init.direct_to_dac = 1;
audec_init.use_tpc = 0;
audec_init.destroy_self = 0;
audec_init.src_msi = NULL;
ui_s->audio_play_msi = audio_file_play_init("0:count.wav", 1, &audec_init);
#endif
lv_obj_add_event_cb(ui, exit_audio_dac_test_ui, LV_EVENT_PRESSED, ui_s);
}
lv_obj_t *audio_dac_test_ui(lv_group_t *group,lv_obj_t *base_ui)
{
struct audio_dac_test_ui_s *ui_s = (struct audio_dac_test_ui_s*)STREAM_LIBC_ZALLOC(sizeof(struct audio_dac_test_ui_s));
ui_s->last_group = group;
ui_s->base_ui = base_ui;
lv_obj_t *btn = lv_list_add_btn(base_ui, NULL, "audio_dac_test");
lv_group_add_obj(group, btn);
lv_obj_add_event_cb(btn, enter_audio_dac_test_ui, LV_EVENT_PRESSED, ui_s);
return btn;
}

View File

@@ -0,0 +1,184 @@
/***************************************************************************************
这个主要是预览,通过scale3_msi将dvp/csi数据scale到对应的分辨率作为数据流发送出去
然后lcd_msi需要接收对应的数据去显示
这里只是产生对应数据流,数据用途实际需要终端流(比如lcd流)接收后去处理
S_PREVIEW_SCALE3 ----> R_VIDEO_P0(320x180)
(scale3) (lcd_video_p0)
***************************************************************************************/
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
#include "stream_frame.h"
#include "keyWork.h"
#include "keyScan.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
#include "avi_encode/avi_encode_msi.h"
#include "audio_msi/audio_adc.h"
struct msi *avi_encode_msi_init(const char *avi_msi_name, uint16_t filter_type, uint8_t rec_time);
//data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
//结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
#define LV_OBJ_AVI_RECORD_FLAG LV_OBJ_FLAG_USER_1
extern lv_indev_t * indev_keypad;
extern lv_style_t g_style;
struct avi_encode_ui_s
{
lv_group_t *last_group;
lv_obj_t *base_ui;
lv_group_t *now_group;
lv_obj_t *now_ui;
struct msi *s;
struct msi *avi_encode_s;
struct msi *jpg_s;
uint32_t record_time;
};
static uint32_t self_key(uint32_t val)
{
uint32_t key_ret = 0;
if(val > 0)
{
if((val&0xff) == KEY_EVENT_SUP)
{
switch(val>>8)
{
case AD_UP:
key_ret = LV_KEY_PREV;
break;
case AD_DOWN:
key_ret = LV_KEY_NEXT;
break;
case AD_LEFT:
key_ret = 'q';
break;
case AD_RIGHT:
key_ret = 'e';
break;
case AD_PRESS:
key_ret = LV_KEY_ENTER;
break;
default:
break;
}
}
}
return key_ret;
}
static void start_avi_record_ui(lv_event_t * e)
{
struct msi *ret = NULL;
int32_t c = *((int32_t *)lv_event_get_param(e));
struct avi_encode_ui_s *ui_s = (struct avi_encode_ui_s *)lv_event_get_user_data(e);
if(c == LV_KEY_ENTER)
{
if(!lv_obj_has_flag(ui_s->now_ui,LV_OBJ_AVI_RECORD_FLAG))
{
lv_obj_add_flag(ui_s->now_ui, LV_OBJ_AVI_RECORD_FLAG);
#if AUDIO_EN
auadc_msi_add_output(AUSYS_AUAD, R_AVI_ENCODE_MSI);
#endif
ret = avi_encode_msi_init(R_AVI_ENCODE_MSI, (uint16_t)~0, 60*1);
if (!ret) {
lv_obj_clear_flag(ui_s->now_ui, LV_OBJ_AVI_RECORD_FLAG);
}
ui_s->avi_encode_s = ret;
}
else
{
//已经在录像了
os_printf("%s already running\n",__FUNCTION__);
}
}
}
static void exit_avi_record_ui(lv_event_t * e)
{
int32_t c = *((int32_t *)lv_event_get_param(e));
if(c == 'q')
{
struct avi_encode_ui_s *ui_s = (struct avi_encode_ui_s *)lv_event_get_user_data(e);
lv_indev_set_group(indev_keypad, ui_s->last_group);
lv_obj_clear_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_group_del(ui_s->now_group);
ui_s->now_group = NULL;
#if AUDIO_EN
auadc_msi_del_output(AUSYS_AUAD, R_AVI_ENCODE_MSI);
#endif
msi_del_output(ui_s->jpg_s, NULL, R_AVI_ENCODE_MSI);
msi_put(ui_s->jpg_s);
msi_destroy(ui_s->avi_encode_s);
msi_destroy(ui_s->s);
//关闭VIDEO P0的使能释放占住的scale3的fb
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
lv_obj_del(ui_s->now_ui);
set_lvgl_get_key_func(NULL);
}
}
//进入预览的ui,那么就要创建新的ui去显示预览图了
static void enter_avi_encode_ui(lv_event_t * e)
{
set_lvgl_get_key_func(self_key);
struct avi_encode_ui_s *ui_s = (struct avi_encode_ui_s *)lv_event_get_user_data(e);
lv_obj_add_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_t *ui = lv_obj_create(lv_scr_act());
ui_s->now_ui = ui;
lv_obj_add_style(ui, &g_style, 0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
//绑定流到Video_P0显示
ui_s->s = scale3_msi(S_PREVIEW_SCALE3);
if (ui_s->s)
{
msi_add_output(ui_s->s, NULL, R_VIDEO_P0);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
ui_s->s->enable = 1;
}
ui_s->jpg_s = msi_find(AUTO_JPG, 1);
if (ui_s->jpg_s)
{
msi_add_output(ui_s->jpg_s, NULL, R_AVI_ENCODE_MSI);
}
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_group_add_obj(group, ui);
ui_s->now_group = group;
lv_obj_add_event_cb(ui, start_avi_record_ui, LV_EVENT_KEY, ui_s);
lv_obj_add_event_cb(ui, exit_avi_record_ui, LV_EVENT_KEY, ui_s);
}
lv_obj_t *avi_loop_record_ui(lv_group_t *group,lv_obj_t *base_ui)
{
struct avi_encode_ui_s *ui_s = (struct avi_encode_ui_s*)STREAM_LIBC_ZALLOC(sizeof(struct avi_encode_ui_s));
ui_s->last_group = group;
ui_s->base_ui = base_ui;
lv_obj_t *btn = lv_list_add_btn(base_ui, NULL, "avi_loop_record_ui");
lv_group_add_obj(group, btn);
lv_obj_add_event_cb(btn, enter_avi_encode_ui, LV_EVENT_PRESSED, ui_s);
return btn;
}

View File

@@ -0,0 +1,668 @@
/***************************************************************************************
***************************************************************************************/
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
#include "keyWork.h"
#include "keyScan.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
#include "avi_player_msi.h"
#define CHECK_DIR "AVI"
#define EXT_NAME "*avi"
#define PLAY_AVI_STREAM_NAME (64)
#define ROUTE_PLAYER_MSI_TX_NUM (16)
enum
{
PLAY_STATUS_STOP_PLAY = BIT(0),
PLAY_STATUS_PLAY_1FPS = BIT(1), //播放一帧,然后自动暂停
PLAY_STATUS_PLAY_END = BIT(2), //播放完毕,需要重新播放
};
//转发流的播放流结构体
struct player_forward_stream_s
{
struct os_work work;
struct msi *s;
struct framebuff *data_s;
uint32_t magic;
uint32_t start_time;
uint32_t last_fps_play_time; //上一帧播放的时间(非系统时间,是视频帧的时间)
uint8_t play_status; //自己的播放状态,第一bit代表播放或者暂停
};
//data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
//结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
extern lv_style_t g_style;
extern lv_indev_t * indev_keypad;
struct avi_player_ui_s
{
lv_group_t *last_group;
lv_obj_t *base_ui;
lv_group_t *now_group;
lv_obj_t *now_ui;
lv_timer_t *timer;
lv_obj_t * label_time;
struct msi *P0_jpg_msi;
struct msi *decode_msi;
struct msi *player_msi;
struct msi *avi_s;
uint8_t *play_name;
};
struct avi_list_param
{
lv_group_t *group;
lv_obj_t *ui;
struct avi_player_ui_s *ui_s;
};
typedef int (*creat_avi_list_ui)(const char *filename,void *data);
static uint32_t self_key(uint32_t val)
{
uint32_t key_ret = 0;
if(val > 0)
{
if((val&0xff) == KEY_EVENT_SUP)
{
switch(val>>8)
{
case AD_UP:
key_ret = 'q';
break;
case AD_DOWN:
key_ret = 'e';
break;
case AD_LEFT:
key_ret = 'a';
break;
case AD_RIGHT:
key_ret = 'd';
break;
case AD_PRESS:
key_ret = LV_KEY_ENTER;
break;
default:
break;
}
}
}
return key_ret;
}
static void exit_show_filelist(lv_event_t * e)
{
os_printf("%s:%d\n",__FUNCTION__,__LINE__);
set_lvgl_get_key_func(self_key);
struct avi_player_ui_s *ui_s = (struct avi_player_ui_s *)lv_event_get_user_data(e);
lv_obj_t *list_item = lv_event_get_current_target(e);
if(ui_s->now_group)
{
lv_indev_set_group(indev_keypad, ui_s->now_group);
}
if(list_item->user_data)
{
//由于是子控件回调函数需要删除父控件,所以需要用到异步删除,否则删除内部链表会有异常
lv_obj_del_async(list_item->user_data);
}
}
//进入回放
static void enter_playback(lv_event_t * e)
{
set_lvgl_get_key_func(self_key);
struct avi_player_ui_s *ui_s = (struct avi_player_ui_s *)lv_event_get_user_data(e);
lv_obj_t *list_item = lv_event_get_current_target(e);
lv_obj_t *list = list_item->user_data;
//将当前的流关闭,内部判断是否=NULL,这里就不判断了
if(ui_s->avi_s)
{
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
msi_destroy(ui_s->avi_s);
ui_s->avi_s = NULL;
}
if(ui_s->play_name)
{
STREAM_FREE(ui_s->play_name);
ui_s->play_name = NULL;
}
os_printf("ui_s->label_time:%X\n",ui_s->label_time);
lv_label_set_text(ui_s->label_time, "00:00");
//重新打开一个视频文件
char path[64];
const char *filename = lv_list_get_btn_text(list,list_item);
os_printf("play filename:%s\n",filename);
os_sprintf(path,"0:%s/%s",CHECK_DIR,filename);
ui_s->play_name = (uint8_t*)STREAM_MALLOC(PLAY_AVI_STREAM_NAME);
os_sprintf((char*)ui_s->play_name,"%s_%04d",filename,(uint32_t)os_jiffies());
os_printf("struct msi play_name:%s addr:0x%x\n",ui_s->play_name, ui_s->play_name);
ui_s->avi_s = avi_player_init((const char *)ui_s->play_name, (const char *)path);
if(ui_s->avi_s)
{
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
//设置播放一帧,先去停止播放器
struct player_forward_stream_s *player_msg = ui_s->player_msi->priv;
os_work_cancle2(&player_msg->work, 1);
msi_add_output(ui_s->avi_s, NULL, S_NEWPLAYER);
ui_s->avi_s->enable = 1;
//重新开始播放,修改启动时间
player_msg->last_fps_play_time = 0;
player_msg->start_time = os_jiffies();
player_msg->magic = os_jiffies() & 0xFF;
msi_do_cmd(ui_s->avi_s, MSI_CMD_PLAYER, MSI_PLAYER_MAGIC, player_msg->magic);
player_msg->play_status = (PLAY_STATUS_STOP_PLAY|PLAY_STATUS_PLAY_1FPS);
OS_WORK_REINIT(&player_msg->work);
os_run_work_delay(&player_msg->work, 1);
//文件开始解析
}
exit_show_filelist(e);
}
static int avi_list_show(const char *filename,void *data)
{
struct avi_list_param *param = (struct avi_list_param*)data;
lv_obj_t * btn = lv_list_add_btn(param->ui, NULL, (const char *)filename);
btn->user_data = (void*)param->ui;
if(param->group)
{
lv_group_add_obj(param->group, btn);
}
//回调函数,进入回放功能
lv_obj_add_event_cb(btn, enter_playback, LV_EVENT_CLICKED, param->ui_s);
return 0;
}
//遍历文件夹
static int each_read_file(creat_avi_list_ui fn,void *param)
{
DIR dir;
FILINFO finfo;
FRESULT fr;
if(!fn)
{
goto each_read_file_end;
}
fr = f_findfirst(&dir, &finfo, CHECK_DIR, EXT_NAME);
while(fr == FR_OK && finfo.fname[0] != 0)
{
fn(finfo.fname,param);
fr = f_findnext(&dir, &finfo);
}
f_closedir(&dir);
each_read_file_end:
os_printf("%s:%d\tret:%d\n",__FUNCTION__,__LINE__,fr);
return fr;
}
static void clear_list_group_ui(lv_event_t * e)
{
lv_group_t *group = (lv_group_t *)lv_event_get_user_data(e);
os_printf("group:%X\n",group);
if(group)
{
lv_group_del(group);
}
}
static void show_filelist(lv_event_t * e)
{
int32_t c = *((int32_t *)lv_event_get_param(e));
if(c == 'e')
{
set_lvgl_get_key_func(NULL);
struct avi_player_ui_s *ui_s = (struct avi_player_ui_s *)lv_event_get_user_data(e);
struct avi_list_param param;
lv_obj_t *list = lv_list_create(ui_s->now_ui);
lv_obj_set_size(list, LV_PCT(100), LV_PCT(100));
param.ui_s = ui_s;
param.ui = list;
param.group = lv_group_create();
lv_indev_set_group(indev_keypad, param.group);
//创建exit的控件
lv_obj_t *list_item = lv_list_add_btn(list, NULL, "exit");
list_item->user_data = (void*)list;
lv_group_add_obj(param.group, list_item);
lv_obj_add_event_cb(list_item, exit_show_filelist, LV_EVENT_SHORT_CLICKED, ui_s);
each_read_file(avi_list_show,(void*)&param);
lv_obj_add_event_cb(list, clear_list_group_ui, LV_EVENT_DELETE, param.group);
}
}
//这里要创建一个流,专门是控制avi播放流的,由jpg解码,发送到这里缓存起来,然后控制播放速度、暂停等
//这里使用lvgl的timer来代替workqueue
static int32_t player_work(struct os_work *work)
{
struct player_forward_stream_s *player_msg = (struct player_forward_stream_s *)work;
struct framebuff *data_s = NULL;
uint32_t time;
//static int count = 0;
if(!player_msg->s->enable)
{
goto player_work_get_data;
}
if(!(player_msg->play_status & PLAY_STATUS_STOP_PLAY))
{
goto player_work_get_data;
}
if(player_msg->data_s)
{
time = player_msg->data_s->time;
//先检查时间是否合适
if(player_msg->start_time + time > os_jiffies())
{
if(player_msg->magic != player_msg->data_s->datatag)
{
msi_delete_fb(NULL, player_msg->data_s);
player_msg->data_s = NULL;
}
goto player_work_end;
}
//再次检查是否符合需要播放(有可能是缓存或者快进导致进入这里)
if(player_msg->magic != player_msg->data_s->datatag)
{
msi_delete_fb(NULL, player_msg->data_s);
player_msg->data_s = NULL;
_os_printf("=");
goto player_work_end;
}
if(player_msg->play_status & PLAY_STATUS_PLAY_1FPS)
{
player_msg->play_status &= ~(PLAY_STATUS_STOP_PLAY|PLAY_STATUS_PLAY_1FPS);
}
//os_printf("time:%d\tstart_time:%d\tmagic:%d\n",time,player_msg->start_time,player_msg->data_s->datatag);
player_msg->last_fps_play_time = time;
//判断一下时间是否需要播放
data_s = fb_clone(player_msg->data_s, (player_msg->data_s->mtype << 8 | player_msg->data_s->stype), player_msg->s);
//准备填好显示、解码参数信息,然后发送到解码的模块去解码,主要如果没有成功要如何处理,这里没有考虑
if(data_s)
{
//os_printf("time:%d\ttype:%X\n",time,player_msg->data_s->mtype);
//如果不是音频,就是视频,就显示
if(data_s->mtype != F_AUDIO)
{
msi_output_fb(player_msg->s, data_s);
}
else
{
//如果是音频,看看是否需要暂停的,如果是,则不播放,因为可能是快进快退,这个时候是不需要去播音频
if(!(player_msg->play_status & PLAY_STATUS_STOP_PLAY))
{
msi_delete_fb(player_msg->s, data_s);
}
else
{
msi_output_fb(player_msg->s, data_s);
}
}
msi_delete_fb(player_msg->s, player_msg->data_s);
player_msg->data_s = NULL;
}
}
player_work_get_data:
if(!player_msg->data_s)
{
player_msg->data_s = msi_get_fb(player_msg->s, 0);
}
else
{
if(player_msg->magic != player_msg->data_s->datatag)
{
msi_delete_fb(NULL, player_msg->data_s);
player_msg->data_s = NULL;
goto player_work_end;
}
}
player_work_end:
os_run_work_delay(work, 1);
return 0;
}
static int32_t route_player_action(struct msi *msi, uint32_t cmd_id, uint32_t param1, uint32_t param2)
{
int32_t ret = RET_OK;
struct player_forward_stream_s *msg = (struct player_forward_stream_s *)msi->priv;
switch (cmd_id)
{
// 帮忙转发,但是永远不需要放在队列中
case MSI_CMD_TRANS_FB:
{
struct framebuff *data = (struct framebuff *)param1;
//过滤一下没有用的数据包,只是接收play_time_start之后的数据包
//os_printf("msg->magic:%d data->datatag:%d\n",msg->magic,data->datatag);
if(!(msg->magic == data->datatag))
{
ret = RET_OK + 1;
}
}
break;
case MSI_CMD_PRE_DESTROY:
{
if (msg) {
os_work_cancle2(&msg->work, 1);
if(msg->data_s)
{
os_printf("msg->data_s:%X\n",msg->data_s);
msi_delete_fb(NULL, msg->data_s);
msg->data_s = NULL;
}
}
}
break;
case MSI_CMD_POST_DESTROY:
{
if(msg)
{
STREAM_FREE(msg);
msi->priv = NULL;
}
}
break;
case MSI_CMD_FREE_FB:
{
//struct framebuff *fb = (struct framebuff *)param1;
//os_printf("ui free fb:0x%x\n",fb);
}
break;
default:
break;
}
return ret;
}
//创建播放器的流,这个流主要实现的是控制速度转发作用,暂时控制的是视频
//如果要控制音频,需要计算时间来控制速度
static struct msi *route_player_msi(const char *name)
{
struct msi *msi = msi_new(name, 16, NULL);
if (!msi) {
return NULL;
}
struct player_forward_stream_s *msg = (struct player_forward_stream_s*)msi->priv;
if (!msg) {
msg = (struct player_forward_stream_s *)STREAM_ZALLOC(sizeof(struct player_forward_stream_s));
msg->s = msi;
msi->priv = msg;
msg->start_time = os_jiffies();
msg->data_s = NULL;
msg->magic = 0;
msg->play_status = (PLAY_STATUS_STOP_PLAY|PLAY_STATUS_PLAY_1FPS);
msg->last_fps_play_time = 0;
//fbpool_init(&msg->tx_pool, ROUTE_PLAYER_MSI_TX_NUM);
msi->action = route_player_action;
msi->enable = 1;
OS_WORK_INIT(&msg->work, player_work, 0);
os_run_work_delay(&msg->work, 1);
}
else
{
msi_destroy(msi);
msi = NULL;
}
return msi;
}
static void player_locate_ctrl_ui(lv_event_t * e)
{
struct avi_player_ui_s *ui_s = (struct avi_player_ui_s *)lv_event_get_user_data(e);
struct player_forward_stream_s *player_msg = ui_s->player_msi->priv;
int32_t c = *((int32_t *)lv_event_get_param(e));
//printf("c:%d\n",c);
switch(c)
{
//后退
case 'a':
{
os_work_cancle2(&player_msg->work, 1);
uint32_t now_play_time = msi_do_cmd(ui_s->avi_s, MSI_CMD_PLAYER, MSI_REWIND_INDEX, player_msg->last_fps_play_time);
//重新开始播放,修改启动时间
player_msg->last_fps_play_time = now_play_time;
player_msg->start_time = os_jiffies() - now_play_time;
player_msg->magic = os_jiffies() & 0xFF;
msi_do_cmd(ui_s->avi_s, MSI_CMD_PLAYER, MSI_PLAYER_MAGIC, player_msg->magic);
player_msg->play_status = (PLAY_STATUS_STOP_PLAY|PLAY_STATUS_PLAY_1FPS);
OS_WORK_REINIT(&player_msg->work);
os_run_work_delay(&player_msg->work, 1);
}
break;
//前进
case 'd':
{
os_work_cancle2(&player_msg->work, 1);
uint32_t now_play_time = msi_do_cmd(ui_s->avi_s, MSI_CMD_PLAYER, MSI_FORWARD_INDEX, player_msg->last_fps_play_time);
//重新开始播放,修改启动时间
player_msg->last_fps_play_time = now_play_time;
player_msg->start_time = os_jiffies() - now_play_time;
player_msg->magic = os_jiffies() & 0xFF;
msi_do_cmd(ui_s->avi_s, MSI_CMD_PLAYER, MSI_PLAYER_MAGIC, player_msg->magic);
player_msg->play_status = (PLAY_STATUS_STOP_PLAY|PLAY_STATUS_PLAY_1FPS);
OS_WORK_REINIT(&player_msg->work);
os_run_work_delay(&player_msg->work, 1);
}
break;
default:
break;
}
}
static void player_ctrl_ui(lv_event_t * e)
{
struct avi_player_ui_s *ui_s = (struct avi_player_ui_s *)lv_event_get_user_data(e);
struct player_forward_stream_s *player_msg = ui_s->player_msi->priv;
os_printf("%s:%d\n",__FUNCTION__,__LINE__);
//根据播放状态设置
if(player_msg->play_status&PLAY_STATUS_STOP_PLAY)
{
player_msg->play_status &= (~PLAY_STATUS_STOP_PLAY);
}
else
{
//重新开始播放,修改启动时间
player_msg->start_time = os_jiffies() - player_msg->last_fps_play_time;
player_msg->play_status |= PLAY_STATUS_STOP_PLAY;
os_printf("################## stop time:%d\tlast_time:%d\n",player_msg->start_time,player_msg->last_fps_play_time);
}
}
static void exit_player_ui(lv_event_t * e)
{
struct avi_player_ui_s *ui_s = (struct avi_player_ui_s *)lv_event_get_user_data(e);
int32_t c = *((int32_t *)lv_event_get_param(e));
if(c == 'q')
{
lv_timer_del(ui_s->timer);
struct avi_player_ui_s *ui_s = (struct avi_player_ui_s *)lv_event_get_user_data(e);
lv_indev_set_group(indev_keypad, ui_s->last_group);
lv_obj_clear_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_group_del(ui_s->now_group);
ui_s->now_group = NULL;
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
msi_destroy(ui_s->P0_jpg_msi);
msi_destroy(ui_s->decode_msi);
msi_destroy(ui_s->player_msi);
msi_destroy(ui_s->avi_s);
ui_s->avi_s = NULL;
ui_s->player_msi = NULL;
ui_s->decode_msi = NULL;
ui_s->P0_jpg_msi = NULL;
lv_obj_del(ui_s->now_ui);
if(ui_s->play_name)
{
STREAM_FREE(ui_s->play_name);
ui_s->play_name = NULL;
}
set_lvgl_get_key_func(NULL);
}
}
static void player_ui_timer(lv_timer_t *t)
{
struct avi_player_ui_s *ui_s = (struct avi_player_ui_s *)t->user_data;
if(ui_s->avi_s)
{
//获取当前播放器的流结构体
struct player_forward_stream_s *player_msg = ui_s->player_msi->priv;
//os_printf("play time:%d\tstart_time:%d\n",player_msg->last_fps_play_time,player_msg->start_time);
char show_time[64];
sprintf(show_time,"%02d:%02d",(player_msg->last_fps_play_time/1000)/60,(player_msg->last_fps_play_time/1000)%60);
lv_label_set_text(ui_s->label_time, show_time);
//判断文件已经播放完毕,如果需要重新播放,则重新建立播放文件
int status = msi_do_cmd(ui_s->avi_s, MSI_CMD_PLAYER, MSI_PLAYER_STATUS, 0);
if(status)
{
os_printf("status:%d\n",status);
}
}
}
static void enter_player_ui(lv_event_t * e)
{
set_lvgl_get_key_func(self_key);
struct avi_player_ui_s *ui_s = (struct avi_player_ui_s *)lv_event_get_user_data(e);
lv_obj_t *base_ui = ui_s->base_ui;
lv_obj_add_flag(base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_t *ui = lv_obj_create(lv_scr_act());
ui_s->now_ui = ui;
lv_obj_add_style(ui, &g_style, 0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
//播放转发发送到P0,控制速度
ui_s->player_msi = route_player_msi(S_NEWPLAYER);
if (ui_s->player_msi) {
msi_add_output(ui_s->player_msi, NULL, "R_AUDAC");
msi_add_output(ui_s->player_msi, NULL, SR_OTHER_JPG);
ui_s->player_msi->enable = 1;
}
//SR_OTHER_JPG接收数据,然后发送到decode
ui_s->P0_jpg_msi = jpg_decode_msg_msi(SR_OTHER_JPG,640,360,640,360,FSTYPE_YUV_P0);
if (ui_s->P0_jpg_msi) {
msi_add_output(ui_s->P0_jpg_msi, NULL, S_JPG_DECODE);
ui_s->P0_jpg_msi->enable = 1;
}
//decode发送到S_NEWPLAYER控制速度后,转发到P0
ui_s->decode_msi = jpg_decode_msi(S_JPG_DECODE);
if (ui_s->decode_msi) {
msi_add_output(ui_s->decode_msi, NULL, R_VIDEO_P0);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
ui_s->decode_msi->enable = 1;
}
//创建lvgl的timer,用于获取播放的时间
ui_s->label_time = lv_label_create(ui);
lv_label_set_text(ui_s->label_time, "00:00");
lv_obj_align(ui_s->label_time,LV_ALIGN_TOP_MID,0,0);
ui_s->timer = lv_timer_create(player_ui_timer, 100, (void*)ui_s);
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_group_add_obj(group, ui);
ui_s->now_group = group;
lv_obj_add_event_cb(ui, exit_player_ui, LV_EVENT_KEY, ui_s);
//控制暂停、播放
lv_obj_add_event_cb(ui, player_ctrl_ui, LV_EVENT_SHORT_CLICKED, ui_s);
//快进快退,一次尝试快进5秒,一次尝试快退5秒
lv_obj_add_event_cb(ui, player_locate_ctrl_ui, LV_EVENT_KEY, ui_s);
//弹出菜单栏,用于切换分辨率
lv_obj_add_event_cb(ui, show_filelist, LV_EVENT_KEY, ui_s);
}
lv_obj_t *avi_playback_ui(lv_group_t *group,lv_obj_t *base_ui)
{
struct avi_player_ui_s *ui_s = (struct avi_player_ui_s*)STREAM_LIBC_ZALLOC(sizeof(struct avi_player_ui_s));
ui_s->last_group = group;
ui_s->base_ui = base_ui;
ui_s->play_name = NULL;
lv_obj_t *btn = lv_list_add_btn(base_ui, NULL, "avi_playback_ui");
lv_group_add_obj(group, btn);
lv_obj_add_event_cb(btn, enter_player_ui, LV_EVENT_SHORT_CLICKED, ui_s);
return btn;
}

174
sdk/app/ui/avi_record_ui.c Normal file
View File

@@ -0,0 +1,174 @@
/***************************************************************************************
这个主要是预览,通过scale3_msi将dvp/csi数据scale到对应的分辨率作为数据流发送出去
然后lcd_msi需要接收对应的数据去显示
这里只是产生对应数据流,数据用途实际需要终端流(比如lcd流)接收后去处理
S_PREVIEW_SCALE3 ----> R_VIDEO_P0(320x180)
(scale3) (lcd_video_p0)
***************************************************************************************/
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
#include "stream_frame.h"
#include "keyWork.h"
#include "keyScan.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
#include "record/avi_record_msi.h"
//data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
//结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
#define LV_OBJ_AVI_RECORD_FLAG LV_OBJ_FLAG_USER_1
extern lv_indev_t * indev_keypad;
extern lv_style_t g_style;
struct avi_record_ui_s
{
lv_group_t *last_group;
lv_obj_t *base_ui;
lv_group_t *now_group;
lv_obj_t *now_ui;
struct msi *s;
uint32_t record_time;
};
static uint32_t self_key(uint32_t val)
{
uint32_t key_ret = 0;
if(val > 0)
{
if((val&0xff) == KEY_EVENT_SUP)
{
switch(val>>8)
{
case AD_UP:
key_ret = LV_KEY_PREV;
break;
case AD_DOWN:
key_ret = LV_KEY_NEXT;
break;
case AD_LEFT:
key_ret = 'q';
break;
case AD_RIGHT:
key_ret = 'e';
break;
case AD_PRESS:
key_ret = LV_KEY_ENTER;
break;
default:
break;
}
}
}
return key_ret;
}
static void avi_record_end_callback(void *user_priv)
{
struct avi_record_ui_s *ui_s = (struct avi_record_ui_s *)user_priv;
lv_obj_clear_flag(ui_s->now_ui, LV_OBJ_AVI_RECORD_FLAG);
}
static void start_avi_record_ui(lv_event_t * e)
{
uint32_t *ret = NULL;
int32_t c = *((int32_t *)lv_event_get_param(e));
struct avi_record_ui_s *ui_s = (struct avi_record_ui_s *)lv_event_get_user_data(e);
if(c == LV_KEY_ENTER)
{
if(!lv_obj_has_flag(ui_s->now_ui,LV_OBJ_AVI_RECORD_FLAG))
{
lv_obj_add_flag(ui_s->now_ui, LV_OBJ_AVI_RECORD_FLAG);
#if AUDIO_EN
ret = avi_record_msi_init(1280, 720, 30, 8000, 60*1, avi_record_end_callback, ui_s);
#else
ret = avi_record_msi_init(1280, 720, 30, 0, 60*1, avi_record_end_callback, ui_s);
#endif
if (!ret) {
lv_obj_clear_flag(ui_s->now_ui, LV_OBJ_AVI_RECORD_FLAG);
}
}
else
{
//已经在录像了
os_printf("%s already running\n",__FUNCTION__);
}
}
}
static void exit_avi_record_ui(lv_event_t * e)
{
int32_t c = *((int32_t *)lv_event_get_param(e));
if(c == 'q')
{
struct avi_record_ui_s *ui_s = (struct avi_record_ui_s *)lv_event_get_user_data(e);
lv_indev_set_group(indev_keypad, ui_s->last_group);
lv_obj_clear_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_group_del(ui_s->now_group);
ui_s->now_group = NULL;
avi_record_msi_deinit();
msi_destroy(ui_s->s);
//关闭VIDEO P0的使能释放占住的scale3的fb
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
lv_obj_del(ui_s->now_ui);
set_lvgl_get_key_func(NULL);
}
}
//进入预览的ui,那么就要创建新的ui去显示预览图了
static void enter_avi_record_ui(lv_event_t * e)
{
set_lvgl_get_key_func(self_key);
struct avi_record_ui_s *ui_s = (struct avi_record_ui_s *)lv_event_get_user_data(e);
lv_obj_add_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_t *ui = lv_obj_create(lv_scr_act());
ui_s->now_ui = ui;
lv_obj_add_style(ui, &g_style, 0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
//绑定流到Video_P0显示
ui_s->s = scale3_msi(S_PREVIEW_SCALE3);
if (ui_s->s)
{
msi_add_output(ui_s->s, NULL, R_VIDEO_P0);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
ui_s->s->enable = 1;
}
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_group_add_obj(group, ui);
ui_s->now_group = group;
lv_obj_add_event_cb(ui, start_avi_record_ui, LV_EVENT_KEY, ui_s);
lv_obj_add_event_cb(ui, exit_avi_record_ui, LV_EVENT_KEY, ui_s);
}
lv_obj_t *avi_record_ui(lv_group_t *group,lv_obj_t *base_ui)
{
struct avi_record_ui_s *ui_s = (struct avi_record_ui_s*)STREAM_LIBC_ZALLOC(sizeof(struct avi_record_ui_s));
ui_s->last_group = group;
ui_s->base_ui = base_ui;
lv_obj_t *btn = lv_list_add_btn(base_ui, NULL, "avi_record_ui");
lv_group_add_obj(group, btn);
lv_obj_add_event_cb(btn, enter_avi_record_ui, LV_EVENT_PRESSED, ui_s);
return btn;
}

View File

@@ -0,0 +1,41 @@
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
extern lv_style_t g_style;
lv_obj_t *main_LLM_vision_ui(lv_obj_t *base_ui, lv_group_t *group)
{
lv_obj_t *ui = lv_obj_create(lv_scr_act());
lv_obj_add_style(ui, &g_style, 0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
//static const uint16_t filter[] = { FSTYPE_JPG_FILE, FSTYPE_JPG_CAMERA0, FSTYPE_NONE };
struct msi *decode_s = jpg_decode_msi(S_JPG_DECODE);
//将解码的数据推送到Video P0和Video P1显示
if (decode_s)
{
msi_add_output(decode_s, NULL, R_VIDEO_P0);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
}
else
{
os_printf("jpg decode new msi failed\n");
}
struct msi *jpg_decode_msg_s = jpg_decode_msg_msi(S_NET_JPEG, 320, 320, 320, 320, FSTYPE_JPG_FILE);
//将other_jpg的数据给到S_JPG_DECODE进行编码
if (jpg_decode_msg_s)
{
// 配置解码的坐标值
msi_do_cmd(jpg_decode_msg_s, MSI_CMD_DECODE_JPEG_MSG, MSI_JPEG_DECODE_FORCE_TYPE, FSTYPE_YUV_P0);
msi_do_cmd(jpg_decode_msg_s, MSI_CMD_DECODE_JPEG_MSG, MSI_JPEG_DECODE_X_Y, 0 << 16 | 0);
msi_add_output(jpg_decode_msg_s, NULL, S_JPG_DECODE);
}
else
{
os_printf("jpg decode msg 0 new msi failed\n");
}
return base_ui;
}

34
sdk/app/ui/lvgl_ui.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef __LVGL_UI_H
#define __LVGL_UI_H
#include "lvgl/lvgl.h"
lv_obj_t *preview_ui(lv_group_t *group, lv_obj_t *base_ui, uint16_t w, uint16_t h);
lv_obj_t *preview_usb_ui(lv_group_t *group, lv_obj_t *base_ui);
lv_obj_t *photo_ui(lv_group_t *group, lv_obj_t *base_ui);
lv_obj_t *preview_sim_video_ui(lv_group_t *group, lv_obj_t *base_ui);
lv_obj_t *preview_dvp_csi_usb_ui(lv_group_t *group, lv_obj_t *base_ui);
lv_obj_t *preview_qc_ui(lv_group_t *group, lv_obj_t *base_ui);
lv_obj_t *audio_dac_test_ui(lv_group_t *group, lv_obj_t *base_ui);
lv_obj_t *touch_pad_test_ui(lv_group_t *group, lv_obj_t *base_ui);
lv_obj_t *preview_encode_takephoto_ui(lv_group_t *group, lv_obj_t *base_ui);
lv_obj_t *avi_record_ui(lv_group_t *group, lv_obj_t *base_ui);
lv_obj_t *avi_loop_record_ui(lv_group_t *group, lv_obj_t *base_ui);
lv_obj_t *avi_playback_ui(lv_group_t *group, lv_obj_t *base_ui);
lv_obj_t *mp4_player_ui(lv_group_t *group, lv_obj_t *base_ui, uint16_t w, uint16_t h);
lv_obj_t *mp4_record_ui(lv_group_t *group, lv_obj_t *base_ui, uint16_t w, uint16_t h);
lv_obj_t *takephoto_ui(lv_group_t *group, lv_obj_t *base_ui, uint16_t w, uint16_t h);
lv_obj_t *main_LLM_vision_ui(lv_obj_t *base_ui, lv_group_t *group);
#include "basic_include.h"
#include "lib/multimedia/msi.h"
#include "scale_msi.h"
#include "jpg_concat_msi.h"
#include "scale3_normal_msi.h"
extern struct msi *jpg_decode_msg_msi(const char *name, uint16_t out_w, uint16_t out_h, uint16_t step_w, uint16_t step_h, uint32_t filter);
extern struct msi *sim_video_more_msi(const char *name, uint16_t w, uint16_t h, uint16_t *sim_filter);
extern struct msi *jpg_decode_msi(const char *name);
extern struct msi *route_msi(const char *name);
extern struct msi *sim_video_msi(const char *name, uint16_t w, uint16_t h, uint8_t top);
extern struct msi *gen420_msi_init(uint16_t w, uint16_t h, uint16_t *filter_type);
extern struct msi *jpg_thumb_msi_init(const char *msi_name, uint16_t filter);
void set_lvgl_get_key_func(void *func);
#endif

116
sdk/app/ui/main_ui.c Normal file
View File

@@ -0,0 +1,116 @@
#include "lvgl/lvgl.h"
#include "project_config.h"
#include "lvgl_ui.h"
enum UI_MODE
{
MINI_DV_UI,
IPC_UI,
BBM_UI,
CHILDREN_UI,
POCKET_CAMERA_UI, //拇指相机ui的demo
LLM_VISION_UI,
};
#ifndef DEFINE_UI
#define DEFINE_UI POCKET_CAMERA_UI
#endif
lv_indev_t * indev_keypad;
extern lv_style_t g_style;
lv_obj_t *main_Mini_DV_ui(lv_obj_t *base_ui,lv_group_t *group)
{
lv_obj_t *btn;
//可以打印系统一些信息
// btn = system_msg_ui(group,base_ui);
//预览dvp的镜头数据
btn = preview_ui(group,base_ui,320,240);
btn = preview_usb_ui(group,base_ui);
btn = photo_ui(group,base_ui);
btn = preview_sim_video_ui(group,base_ui);
btn = preview_dvp_csi_usb_ui(group,base_ui);
btn = preview_qc_ui(group,base_ui);
btn = audio_dac_test_ui(group,base_ui);
btn = touch_pad_test_ui(group,base_ui);
btn = preview_encode_takephoto_ui(group,base_ui);
btn = avi_record_ui(group,base_ui);
btn = avi_loop_record_ui(group,base_ui);
btn = avi_playback_ui(group,base_ui);
btn = mp4_player_ui(group,base_ui,320,240);
btn = mp4_record_ui(group,base_ui,320,240);
//可以进行录像拍照
// btn = preview_encode_selct_ui(group,base_ui);
//播放自己录制的视频文件
// btn = player2_ui(group,base_ui);
return base_ui;
}
lv_obj_t *main_pocket_camera_ui(lv_obj_t *base_ui,lv_group_t *group)
{
// lv_obj_t *btn;
// //可以打印系统一些信息
// // btn = system_msg_ui(group,base_ui);
// //预览dvp的镜头数据
// btn = preview_ui(group,base_ui,160,128);
// btn = takephoto_ui(group,base_ui,160,128);
// btn = mp4_player_ui(group,base_ui,160,128);
// btn = mp4_record_ui(group,base_ui,160,128);
// return base_ui;
// 白色大字 "Hello TXW82x!" 居中显示
lv_obj_t *label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Hello TXW82x!");
lv_obj_set_style_text_color(label, lv_color_white(), 0);
lv_obj_set_style_text_font(label, &lv_font_montserrat_24, 0);
lv_obj_align(label, LV_ALIGN_CENTER, 0, -20);
// 红色按钮
lv_obj_t *btn = lv_btn_create(lv_scr_act());
lv_obj_set_style_bg_color(btn, lv_color_make(0xFF, 0x00, 0x00), 0);
lv_obj_set_size(btn, 100, 50);
lv_obj_align(btn, LV_ALIGN_CENTER, 0, 30);
lv_obj_t *btn_text = lv_label_create(btn);
lv_label_set_text(btn_text, "TEST");
lv_group_add_obj(group, btn);
return base_ui;
}
extern void common_takephoto_normal_init(const char *thumb_msi_name);
extern void common_takephoto_over_dpi_init(uint8_t jpg_num);
extern struct msi *scale3_normal_msi2(const char *name, uint8_t force_stype, uint16_t ow, uint16_t oh);
lv_obj_t *main_ui(lv_obj_t *base_ui)
{
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_obj_t * ui = lv_list_create(lv_scr_act());
// lv_obj_add_style(ui,&g_style,0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
switch(DEFINE_UI)
{
case MINI_DV_UI:
main_Mini_DV_ui(ui,group);
break;
case IPC_UI:
break;
case BBM_UI:
lv_obj_add_style(ui,&g_style,0);
break;
case CHILDREN_UI:
break;
case POCKET_CAMERA_UI:
//支持大分辨拍照或者缩略图
scale3_normal_msi2(S_PREVIEW_SCALE3, FSTYPE_YUV_P0, 168, 128);
common_takephoto_normal_init(R_THUMB);
common_takephoto_over_dpi_init(JPGID0);
main_pocket_camera_ui(ui,group);
break;
case LLM_VISION_UI:
main_LLM_vision_ui(ui,group);
break;
}
return ui;
}

5
sdk/app/ui/main_ui.h Normal file
View File

@@ -0,0 +1,5 @@
#ifndef __MAIN_UI_H
#define __MAIN_UI_H
#include "lvgl/lvgl.h"
lv_obj_t *main_ui(lv_obj_t *base_ui);
#endif

439
sdk/app/ui/mp4_player_ui.c Normal file
View File

@@ -0,0 +1,439 @@
/***************************************************************************************
***************************************************************************************/
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
#include "keyWork.h"
#include "keyScan.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
#include "avi_player_msi.h"
#include "audio_media_ctrl/audio_code_ctrl.h"
#include "fs/fatfs/osal_file.h"
struct msi *h264_decode_msg_msi(const char *name, uint16_t out_w, uint16_t out_h, uint16_t step_w, uint16_t step_h, uint32_t filter);
struct msi *h264_decode_msi(const char *name, uint8_t only_I_H264);
struct msi *mp4_demux_msi_init(const char *msi_name, const char *filename);
void h264_drv_init();
#define CHECK_DIR "MP4"
#define EXT_NAME "*mp4"
#define PLAY_AVI_STREAM_NAME (64)
#define ROUTE_PLAYER_MSI_TX_NUM (16)
enum
{
PLAY_STATUS_STOP_PLAY = BIT(0),
PLAY_STATUS_PLAY_1FPS = BIT(1), // 播放一帧,然后自动暂停
PLAY_STATUS_PLAY_END = BIT(2), // 播放完毕,需要重新播放
};
// 转发流的播放流结构体
struct player_forward_stream_s
{
struct os_work work;
struct msi *s;
struct framebuff *data_s;
uint32_t magic;
uint32_t start_time;
uint32_t last_fps_play_time; // 上一帧播放的时间(非系统时间,是视频帧的时间)
uint8_t play_status; // 自己的播放状态,第一bit代表播放或者暂停
};
// data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
// 结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
extern lv_style_t g_style;
extern lv_indev_t *indev_keypad;
struct mp4_player_ui_s
{
lv_group_t *last_group;
lv_obj_t *base_ui;
uint16_t w, h;
lv_group_t *now_group;
lv_obj_t *now_ui;
lv_timer_t *timer;
lv_obj_t *label_time;
struct msi *P0_jpg_msi;
struct msi *decode_msi;
struct msi *mp4_s;
struct msi *aac_msi;
uint8_t *play_name;
uint8_t start : 1, rev : 7;
};
struct avi_list_param
{
lv_group_t *group;
lv_obj_t *ui;
struct mp4_player_ui_s *ui_s;
};
typedef int (*creat_avi_list_ui)(const char *filename, void *data);
static uint32_t self_key(uint32_t val)
{
uint32_t key_ret = 0;
if (val > 0)
{
if ((val & 0xff) == KEY_EVENT_SUP)
{
switch (val >> 8)
{
case AD_UP:
key_ret = 'q';
break;
case AD_DOWN:
key_ret = 'e';
break;
case AD_LEFT:
key_ret = 'a';
break;
case AD_RIGHT:
key_ret = 'd';
break;
case AD_PRESS:
key_ret = LV_KEY_ENTER;
break;
default:
break;
}
}
}
return key_ret;
}
static void exit_show_filelist(lv_event_t *e)
{
os_printf("%s:%d\n", __FUNCTION__, __LINE__);
set_lvgl_get_key_func(self_key);
struct mp4_player_ui_s *ui_s = (struct mp4_player_ui_s *) lv_event_get_user_data(e);
lv_obj_t *list_item = lv_event_get_current_target(e);
if (ui_s->now_group)
{
lv_indev_set_group(indev_keypad, ui_s->now_group);
}
if (list_item->user_data)
{
// 由于是子控件回调函数需要删除父控件,所以需要用到异步删除,否则删除内部链表会有异常
lv_obj_del_async(list_item->user_data);
}
}
// 进入回放
static void enter_playback(lv_event_t *e)
{
set_lvgl_get_key_func(self_key);
struct mp4_player_ui_s *ui_s = (struct mp4_player_ui_s *) lv_event_get_user_data(e);
lv_obj_t *list_item = lv_event_get_current_target(e);
lv_obj_t *list = list_item->user_data;
// 将当前的流关闭,内部判断是否=NULL,这里就不判断了
if (ui_s->mp4_s)
{
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
msi_destroy(ui_s->mp4_s);
ui_s->mp4_s = NULL;
}
#if AUDIO_EN
if (ui_s->aac_msi)
{
// msi_destroy(ui_s->aac_msi);
audio_decode_deinit(ui_s->aac_msi);
ui_s->aac_msi = NULL;
}
#endif
if (ui_s->play_name)
{
STREAM_FREE(ui_s->play_name);
ui_s->play_name = NULL;
}
os_printf("ui_s->label_time:%X\n", ui_s->label_time);
lv_label_set_text(ui_s->label_time, "00:00");
// 重新打开一个视频文件
char path[64];
const char *filename = lv_list_get_btn_text(list, list_item);
os_printf("play filename:%s\n", filename);
os_sprintf(path, "0:%s/%s", CHECK_DIR, filename);
ui_s->play_name = (uint8_t *) STREAM_MALLOC(PLAY_AVI_STREAM_NAME);
os_sprintf((char *) ui_s->play_name, "%s_%04d", filename, (uint32_t) os_jiffies());
os_printf("struct msi play_name:%s addr:0x%x\n", ui_s->play_name, ui_s->play_name);
ui_s->mp4_s = mp4_demux_msi_init((const char *) ui_s->play_name, (const char *) path);
if (ui_s->mp4_s)
{
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
#if AUDIO_EN
AUDEC_INIT audec_init;
audec_init.track_type = MEDIA_TRACK;
audec_init.priority = play_interruptible;
audec_init.direct_to_dac = 1;
audec_init.use_tpc = 0;
audec_init.destroy_self = 0;
audec_init.src_msi = ui_s->mp4_s;
ui_s->aac_msi = audio_decode_init(AAC_DEC, 0, &audec_init);
#endif
// 文件开始解析
msi_add_output(ui_s->mp4_s, NULL, ui_s->P0_jpg_msi->name);
msi_do_cmd(ui_s->mp4_s, MSI_CMD_VIDEO_DEMUX_CTRL, MSI_VIDEO_DEMUX_START, 0);
ui_s->start = 1;
}
exit_show_filelist(e);
}
static int mp4_list_show(const char *filename, void *data)
{
struct avi_list_param *param = (struct avi_list_param *) data;
lv_obj_t *btn = lv_list_add_btn(param->ui, NULL, (const char *) filename);
btn->user_data = (void *) param->ui;
if (param->group)
{
lv_group_add_obj(param->group, btn);
}
// 回调函数,进入回放功能
lv_obj_add_event_cb(btn, enter_playback, LV_EVENT_CLICKED, param->ui_s);
return 0;
}
// 遍历文件夹
static int each_read_file(creat_avi_list_ui fn, void *param)
{
DIR dir;
FILINFO finfo;
FRESULT fr;
if (!fn)
{
goto each_read_file_end;
}
fr = f_findfirst(&dir, &finfo, CHECK_DIR, EXT_NAME);
while (fr == FR_OK && finfo.fname[0] != 0)
{
fn(finfo.fname, param);
fr = f_findnext(&dir, &finfo);
}
f_closedir(&dir);
each_read_file_end:
os_printf("%s:%d\tret:%d\n", __FUNCTION__, __LINE__, fr);
return fr;
}
static void clear_list_group_ui(lv_event_t *e)
{
lv_group_t *group = (lv_group_t *) lv_event_get_user_data(e);
os_printf("group:%X\n", group);
if (group)
{
lv_group_del(group);
}
}
static void show_filelist(lv_event_t *e)
{
int32_t c = *((int32_t *) lv_event_get_param(e));
if (c == 'e')
{
set_lvgl_get_key_func(NULL);
struct mp4_player_ui_s *ui_s = (struct mp4_player_ui_s *) lv_event_get_user_data(e);
struct avi_list_param param;
lv_obj_t *list = lv_list_create(ui_s->now_ui);
lv_obj_set_size(list, LV_PCT(100), LV_PCT(100));
param.ui_s = ui_s;
param.ui = list;
param.group = lv_group_create();
lv_indev_set_group(indev_keypad, param.group);
// 创建exit的控件
lv_obj_t *list_item = lv_list_add_btn(list, NULL, "exit");
list_item->user_data = (void *) list;
lv_group_add_obj(param.group, list_item);
lv_obj_add_event_cb(list_item, exit_show_filelist, LV_EVENT_SHORT_CLICKED, ui_s);
each_read_file(mp4_list_show, (void *) &param);
lv_obj_add_event_cb(list, clear_list_group_ui, LV_EVENT_DELETE, param.group);
}
}
static void player_locate_ctrl_ui(lv_event_t *e)
{
// struct mp4_player_ui_s *ui_s = (struct mp4_player_ui_s *) lv_event_get_user_data(e);
int32_t c = *((int32_t *) lv_event_get_param(e));
// printf("c:%d\n",c);
switch (c)
{
// 后退
case 'a':
{
}
break;
// 前进
case 'd':
{
}
break;
default:
break;
}
}
static void player_ctrl_ui(lv_event_t *e)
{
struct mp4_player_ui_s *ui_s = (struct mp4_player_ui_s *) lv_event_get_user_data(e);
if (ui_s->mp4_s)
{
ui_s->start++;
if (ui_s->start)
{
msi_do_cmd(ui_s->mp4_s, MSI_CMD_VIDEO_DEMUX_CTRL, MSI_VIDEO_DEMUX_START, 0);
}
else
{
msi_do_cmd(ui_s->mp4_s, MSI_CMD_VIDEO_DEMUX_CTRL, MSI_VIDEO_DEMUX_PAUSE, 0);
}
}
}
static void exit_player_ui(lv_event_t *e)
{
struct mp4_player_ui_s *ui_s = (struct mp4_player_ui_s *) lv_event_get_user_data(e);
int32_t c = *((int32_t *) lv_event_get_param(e));
if (c == 'q')
{
lv_timer_del(ui_s->timer);
struct mp4_player_ui_s *ui_s = (struct mp4_player_ui_s *) lv_event_get_user_data(e);
lv_indev_set_group(indev_keypad, ui_s->last_group);
lv_obj_clear_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_group_del(ui_s->now_group);
ui_s->now_group = NULL;
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
msi_destroy(ui_s->P0_jpg_msi);
msi_destroy(ui_s->decode_msi);
if (ui_s->mp4_s)
{
msi_destroy(ui_s->mp4_s);
ui_s->mp4_s = NULL;
}
#if AUDIO_EN
if (ui_s->aac_msi)
{
// msi_destroy(ui_s->aac_msi);
audio_decode_deinit(ui_s->aac_msi);
ui_s->aac_msi = NULL;
}
#endif
ui_s->mp4_s = NULL;
ui_s->decode_msi = NULL;
ui_s->P0_jpg_msi = NULL;
lv_obj_del(ui_s->now_ui);
if (ui_s->play_name)
{
STREAM_FREE(ui_s->play_name);
ui_s->play_name = NULL;
}
set_lvgl_get_key_func(NULL);
}
}
static void player_ui_timer(lv_timer_t *t)
{
struct mp4_player_ui_s *ui_s = (struct mp4_player_ui_s *) t->user_data;
if (ui_s->mp4_s)
{
}
}
static void enter_player_ui(lv_event_t *e)
{
set_lvgl_get_key_func(self_key);
// demo主要是h264的解码,所以这里初始化一下
h264_drv_init();
struct mp4_player_ui_s *ui_s = (struct mp4_player_ui_s *) lv_event_get_user_data(e);
lv_obj_t *base_ui = ui_s->base_ui;
lv_obj_add_flag(base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_t *ui = lv_obj_create(lv_scr_act());
ui_s->now_ui = ui;
lv_obj_add_style(ui, &g_style, 0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
// SR_OTHER_JPG接收数据,然后发送到decode
ui_s->P0_jpg_msi = h264_decode_msg_msi(SR_OTHER_JPG, ui_s->w, ui_s->h, ui_s->w, ui_s->h, 0);
if (ui_s->P0_jpg_msi)
{
msi_do_cmd(ui_s->P0_jpg_msi, MSI_CMD_DECODE_JPEG_MSG, MSI_JPEG_DECODE_FORCE_TYPE, FSTYPE_YUV_P0);
ui_s->P0_jpg_msi->enable = 1;
}
// decode发送到S_NEWPLAYER控制速度后,转发到P0
ui_s->decode_msi = h264_decode_msi("h264_decode", 0);
if (ui_s->decode_msi)
{
msi_add_output(ui_s->P0_jpg_msi, NULL, ui_s->decode_msi->name);
msi_add_output(ui_s->decode_msi, NULL, R_VIDEO_P0);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
ui_s->decode_msi->enable = 1;
}
// 创建lvgl的timer,用于获取播放的时间
ui_s->label_time = lv_label_create(ui);
lv_label_set_text(ui_s->label_time, "00:00");
lv_obj_align(ui_s->label_time, LV_ALIGN_TOP_MID, 0, 0);
ui_s->timer = lv_timer_create(player_ui_timer, 100, (void *) ui_s);
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_group_add_obj(group, ui);
ui_s->now_group = group;
lv_obj_add_event_cb(ui, exit_player_ui, LV_EVENT_KEY, ui_s);
// 控制暂停、播放
lv_obj_add_event_cb(ui, player_ctrl_ui, LV_EVENT_SHORT_CLICKED, ui_s);
// 快进快退,一次尝试快进5秒,一次尝试快退5秒
lv_obj_add_event_cb(ui, player_locate_ctrl_ui, LV_EVENT_KEY, ui_s);
// 弹出菜单栏,用于切换分辨率
lv_obj_add_event_cb(ui, show_filelist, LV_EVENT_KEY, ui_s);
}
lv_obj_t *mp4_player_ui(lv_group_t *group, lv_obj_t *base_ui, uint16_t w, uint16_t h)
{
struct mp4_player_ui_s *ui_s = (struct mp4_player_ui_s *) STREAM_LIBC_ZALLOC(sizeof(struct mp4_player_ui_s));
ui_s->last_group = group;
ui_s->base_ui = base_ui;
ui_s->play_name = NULL;
ui_s->w = w;
ui_s->h = h;
lv_obj_t *btn = lv_list_add_btn(base_ui, NULL, "mp4_player");
lv_group_add_obj(group, btn);
lv_obj_add_event_cb(btn, enter_player_ui, LV_EVENT_SHORT_CLICKED, ui_s);
return btn;
}

View File

@@ -0,0 +1,259 @@
/***************************************************************************************
***************************************************************************************/
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
#include "keyWork.h"
#include "keyScan.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
#include "audio_msi/audio_adc.h"
#include "audio_media_ctrl/audio_code_ctrl.h"
#include "file_process.h"
#include "fs/fatfs/osal_file.h"
#include "file_process.h"
#define RECORDER_DIR "0:MP4"
struct msi *mp4_encode_msi2_init(const char *mp4_msi_name, uint8_t srcID, uint8_t filter_type, uint8_t rec_time, uint32_t audio_encode, struct file_process *file_process, uint8_t mode);
#define LVGL_MP4_MSI_NAME "lvgl_mp4"
#define LV_OBJ_MP4_RECORD_FLAG LV_OBJ_FLAG_USER_1
// data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
// 结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
extern lv_indev_t *indev_keypad;
extern lv_style_t g_style;
struct mp4_record_ui_s
{
lv_group_t *last_group;
lv_obj_t *base_ui;
uint16_t w, h;
lv_group_t *now_group;
lv_obj_t *now_ui;
lv_timer_t *timer;
lv_obj_t *label_time;
struct msi *s;
struct msi *h264_msi;
struct msi *mp4_msi;
struct msi *aac_msi;
uint8_t *play_name;
uint8_t start : 1, rev : 7;
};
static uint32_t self_key(uint32_t val)
{
uint32_t key_ret = 0;
if (val > 0)
{
if ((val & 0xff) == KEY_EVENT_SUP)
{
switch (val >> 8)
{
case AD_UP:
key_ret = 'q';
break;
case AD_DOWN:
key_ret = 'e';
break;
case AD_LEFT:
key_ret = 'a';
break;
case AD_RIGHT:
key_ret = 'd';
break;
case AD_PRESS:
key_ret = LV_KEY_ENTER;
break;
default:
break;
}
}
}
return key_ret;
}
static void *lvgl_mp4_file(struct file_process *file_process, char *filename, char *file_path, uint32_t file_size)
{
os_sprintf(filename, "%s/%016d.mp4", file_process->rec_path, (uint32_t) os_jiffies());
void *fp = osal_fopen_auto((const char *) filename, "w+", 0);
return fp;
}
static void start_mp4_record_ui(lv_event_t *e)
{
int32_t c = *((int32_t *) lv_event_get_param(e));
struct mp4_record_ui_s *ui_s = (struct mp4_record_ui_s *) lv_event_get_user_data(e);
if (c == LV_KEY_ENTER)
{
if (!lv_obj_has_flag(ui_s->now_ui, LV_OBJ_MP4_RECORD_FLAG))
{
os_printf("%s:%d\n", __FUNCTION__, __LINE__);
ui_s->h264_msi = msi_find(AUTO_H264, 1);
if (ui_s->h264_msi)
{
lv_obj_add_flag(ui_s->now_ui, LV_OBJ_MP4_RECORD_FLAG);
struct file_process mp4_file_process = {
.loop = NULL,
.rec_path = RECORDER_DIR,
.ext_name = ".MP4",
.create_file = lvgl_mp4_file,
.loop_free = NULL,
.lock_file = NULL,
};
uint8_t audio_flag = 0;
AUENC_INIT auenc_init;
auenc_init.destroy_self = 0;
auenc_init.src_msi = get_auadc_msi(AUSYS_AUAD);
ui_s->aac_msi = audio_encode_init(AAC_ENC, audio_adc_get_samplerate(AUSYS_AUAD), &auenc_init);
if (ui_s->aac_msi)
{
audio_code_add_output(ui_s->aac_msi, LVGL_MP4_MSI_NAME);
audio_flag = 1;
}
ui_s->mp4_msi = mp4_encode_msi2_init(LVGL_MP4_MSI_NAME, FRAMEBUFF_SOURCE_CAMERA0, FSTYPE_H264_VPP_DATA0, 1, audio_flag, &mp4_file_process, 0);
if (ui_s->mp4_msi)
{
msi_do_cmd(ui_s->mp4_msi, MSI_CMD_MEDIA_CTRL, MSI_MEDIA_CTRL_RECORD_START, 0);
msi_add_output(ui_s->h264_msi, NULL, LVGL_MP4_MSI_NAME);
}
else
{
if (ui_s->aac_msi)
{
audio_code_del_output(ui_s->aac_msi, LVGL_MP4_MSI_NAME);
audio_encode_deinit(ui_s->aac_msi);
ui_s->aac_msi = NULL;
}
if (ui_s->h264_msi)
{
msi_del_output(ui_s->h264_msi, NULL, LVGL_MP4_MSI_NAME);
msi_put(ui_s->h264_msi);
ui_s->h264_msi = NULL;
}
}
}
}
else
{
if (ui_s->mp4_msi)
{
msi_destroy(ui_s->mp4_msi);
ui_s->mp4_msi = NULL;
}
if (ui_s->aac_msi)
{
audio_code_del_output(ui_s->aac_msi, LVGL_MP4_MSI_NAME);
audio_encode_deinit(ui_s->aac_msi);
ui_s->aac_msi = NULL;
}
if (ui_s->h264_msi)
{
msi_del_output(ui_s->h264_msi, NULL, LVGL_MP4_MSI_NAME);
msi_put(ui_s->h264_msi);
ui_s->h264_msi = NULL;
}
lv_obj_clear_flag(ui_s->now_ui, LV_OBJ_MP4_RECORD_FLAG);
}
}
}
static void exit_mp4_record_ui(lv_event_t *e)
{
int32_t c = *((int32_t *) lv_event_get_param(e));
if (c == 'q')
{
struct mp4_record_ui_s *ui_s = (struct mp4_record_ui_s *) lv_event_get_user_data(e);
lv_indev_set_group(indev_keypad, ui_s->last_group);
lv_obj_clear_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_group_del(ui_s->now_group);
ui_s->now_group = NULL;
if(ui_s->s)
{
msi_do_cmd(ui_s->s, MSI_CMD_SCALE3_NORMAL, MSI_SCALE3_START, 0);
}
msi_destroy(ui_s->s);
// 关闭VIDEO P0的使能释放占住的scale3的fb
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
if (ui_s->mp4_msi)
{
msi_destroy(ui_s->mp4_msi);
ui_s->mp4_msi = NULL;
}
if (ui_s->aac_msi)
{
audio_code_del_output(ui_s->aac_msi, LVGL_MP4_MSI_NAME);
audio_encode_deinit(ui_s->aac_msi);
ui_s->aac_msi = NULL;
}
if (ui_s->h264_msi)
{
msi_del_output(ui_s->h264_msi, NULL, LVGL_MP4_MSI_NAME);
msi_put(ui_s->h264_msi);
ui_s->h264_msi = NULL;
}
lv_obj_del(ui_s->now_ui);
set_lvgl_get_key_func(NULL);
}
}
static void enter_mp4_record_ui(lv_event_t *e)
{
set_lvgl_get_key_func(self_key);
struct mp4_record_ui_s *ui_s = (struct mp4_record_ui_s *) lv_event_get_user_data(e);
lv_obj_add_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_t *ui = lv_obj_create(lv_scr_act());
ui_s->now_ui = ui;
lv_obj_add_style(ui, &g_style, 0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
// 绑定流到Video_P0显示
ui_s->s = scale3_normal_msi2(S_PREVIEW_SCALE3, FSTYPE_YUV_P0, ui_s->w, ui_s->h);
if (ui_s->s)
{
msi_do_cmd(ui_s->s, MSI_CMD_SCALE3_NORMAL, MSI_SCALE3_START, 0x01);
msi_add_output(ui_s->s, NULL, R_VIDEO_P0);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
ui_s->s->enable = 1;
}
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_group_add_obj(group, ui);
ui_s->now_group = group;
lv_obj_add_event_cb(ui, start_mp4_record_ui, LV_EVENT_KEY, ui_s);
lv_obj_add_event_cb(ui, exit_mp4_record_ui, LV_EVENT_KEY, ui_s);
}
lv_obj_t *mp4_record_ui(lv_group_t *group, lv_obj_t *base_ui, uint16_t w, uint16_t h)
{
struct mp4_record_ui_s *ui_s = (struct mp4_record_ui_s *) STREAM_LIBC_ZALLOC(sizeof(struct mp4_record_ui_s));
ui_s->last_group = group;
ui_s->base_ui = base_ui;
ui_s->w = w;
ui_s->h = h;
lv_obj_t *btn = lv_list_add_btn(base_ui, NULL, "mp4_record_ui");
lv_group_add_obj(group, btn);
lv_obj_add_event_cb(btn, enter_mp4_record_ui, LV_EVENT_SHORT_CLICKED, ui_s);
return btn;
}

435
sdk/app/ui/photo_ui.c Normal file
View File

@@ -0,0 +1,435 @@
/***************************************************************************************
***************************************************************************************/
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
#include "stream_frame.h"
#include "keyWork.h"
#include "keyScan.h"
#include "fatfs/osal_file.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
#define CHECK_DIR "photo"
#define EXT_NAME "*jpg"
//data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
//结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
extern lv_style_t g_style;
extern lv_indev_t * indev_keypad;
struct photo_ui_s
{
lv_group_t *last_group;
lv_obj_t *base_ui;
lv_group_t *now_group;
lv_obj_t *now_ui;
struct msi *photo_s;
struct fbpool tx_pool;
struct msi *other_s;
struct msi *decode_s;
lv_obj_t * label_path;
};
struct photo_list_param
{
lv_group_t *group;
lv_obj_t *ui;
struct photo_ui_s *ui_s;
};
typedef int (*list_ui)(const char *filename,void *data);
static void exit_show_filelist(lv_event_t * e)
{
os_printf("%s:%d\n",__FUNCTION__,__LINE__);
struct photo_ui_s *ui_s = (struct photo_ui_s *)lv_event_get_user_data(e);
lv_obj_t *list_item = lv_event_get_current_target(e);
if(ui_s->now_group)
{
lv_indev_set_group(indev_keypad, ui_s->now_group);
}
if(list_item->user_data)
{
//由于是子控件回调函数需要删除父控件,所以需要用到异步删除,否则删除内部链表会有异常
lv_obj_del_async(list_item->user_data);
}
}
//读取图片,发送出去显示
static void play_photo(lv_event_t * e)
{
void *fp = NULL;
void *photo_buf = NULL;
struct framebuff *data_s = NULL;
uint32_t len;
struct photo_ui_s *ui_s = (struct photo_ui_s *)lv_event_get_user_data(e);
lv_obj_t *list_item = lv_event_get_current_target(e);
lv_obj_t *list = list_item->user_data;
char path[64];
const char *filename = lv_list_get_btn_text(list,list_item);
os_sprintf(path,"0:%s/%s",CHECK_DIR,filename);
if(!ui_s->photo_s)
{
goto play_photo_fail;
}
//读取图片文件,通过流去发送
data_s = fbpool_get(&ui_s->tx_pool, 0, ui_s->photo_s);
if(data_s)
{
data_s->data = NULL;
lv_label_set_text(ui_s->label_path, path);
//开始显示图片
fp = osal_fopen(path,"rb");
if(fp)
{
uint32_t filesize = osal_fsize(fp);
photo_buf = (void*)STREAM_MALLOC(filesize);
if(!photo_buf)
{
msi_delete_fb(ui_s->photo_s, data_s);
data_s = NULL;
goto play_photo_fail;
}
else
{
len = osal_fread(photo_buf,1,filesize,fp);
if(len != filesize)
{
goto play_photo_fail;
}
data_s->data = (void*)photo_buf;
data_s->mtype = F_JPG;
data_s->stype = FSTYPE_YUV_P0;
data_s->len = filesize;
msi_output_fb(ui_s->photo_s, data_s);
photo_buf = NULL;
data_s = NULL;
goto play_photo_end;
}
}
goto play_photo_fail;
}
play_photo_fail:
//显示失败
os_sprintf(path,"0:%s/%s fail",CHECK_DIR,filename);
lv_label_set_text(ui_s->label_path, path);
if(photo_buf)
{
STREAM_FREE(photo_buf);
photo_buf = NULL;
}
if(data_s)
{
msi_delete_fb(NULL, data_s);
}
play_photo_end:
if(fp)
{
osal_fclose(fp);
fp = NULL;
}
exit_show_filelist(e);
}
static int photo_list_show(const char *filename,void *data)
{
struct photo_list_param *param = (struct photo_list_param*)data;
lv_obj_t * btn = lv_list_add_btn(param->ui, NULL, (const char *)filename);
btn->user_data = (void*)param->ui;
if(param->group)
{
lv_group_add_obj(param->group, btn);
}
//回调函数,进入回放功能
lv_obj_add_event_cb(btn, play_photo, LV_EVENT_CLICKED, param->ui_s);
return 0;
}
//遍历文件夹
//遍历文件夹
static int each_read_file(list_ui fn,void *param)
{
DIR dir;
FILINFO finfo;
FRESULT fr;
if(!fn)
{
goto each_read_file_end;
}
fr = f_findfirst(&dir, &finfo, CHECK_DIR, EXT_NAME);
while(fr == FR_OK && finfo.fname[0] != 0)
{
fn(finfo.fname,param);
fr = f_findnext(&dir, &finfo);
}
f_closedir(&dir);
each_read_file_end:
os_printf("%s:%d\tret:%d\n",__FUNCTION__,__LINE__,fr);
return fr;
}
static void clear_list_group_ui(lv_event_t * e)
{
lv_group_t *group = (lv_group_t *)lv_event_get_user_data(e);
os_printf("group:%X\n",group);
if(group)
{
lv_group_del(group);
}
}
static void show_filelist(lv_event_t * e)
{
int32_t c = *((int32_t *)lv_event_get_param(e));
if(c == 'e')
{
struct photo_ui_s *ui_s = (struct photo_ui_s *)lv_event_get_user_data(e);
struct photo_list_param param;
lv_obj_t *list = lv_list_create(ui_s->now_ui);
lv_obj_set_size(list, LV_PCT(100), LV_PCT(100));
param.ui_s = ui_s;
param.ui = list;
param.group = lv_group_create();
lv_indev_set_group(indev_keypad, param.group);
//创建exit的控件
lv_obj_t *list_item = lv_list_add_btn(list, NULL, "exit");
list_item->user_data = (void*)list;
lv_group_add_obj(param.group, list_item);
lv_obj_add_event_cb(list_item, exit_show_filelist, LV_EVENT_SHORT_CLICKED, ui_s);
each_read_file(photo_list_show,(void*)&param);
lv_obj_add_event_cb(list, clear_list_group_ui, LV_EVENT_DELETE, param.group);
}
}
static uint32_t self_key(uint32_t val)
{
uint32_t key_ret = 0;
if(val > 0)
{
if((val&0xff) == KEY_EVENT_SUP)
{
switch(val>>8)
{
case AD_UP:
key_ret = LV_KEY_PREV;
break;
case AD_DOWN:
key_ret = LV_KEY_NEXT;
break;
case AD_LEFT:
key_ret = 'q';
break;
case AD_RIGHT:
key_ret = 'e';
break;
case AD_PRESS:
key_ret = LV_KEY_ENTER;
break;
break;
default:
break;
}
}
}
return key_ret;
}
static int32 photo_msi_action(struct msi *msi, uint32 cmd_id, uint32 param1, uint32 param2)
{
int32_t ret = RET_OK;
struct photo_ui_s *ui_s = (struct photo_ui_s *)msi->priv;
switch (cmd_id)
{
case MSI_CMD_PRE_DESTROY:
{
}
break;
case MSI_CMD_POST_DESTROY:
{
fbpool_destroy(&ui_s->tx_pool);
os_printf("%s %d\n",__FUNCTION__,__LINE__);
}
break;
case MSI_CMD_FREE_FB:
{
struct framebuff *fb = (struct framebuff *)param1;
if (fb->data)
{
STREAM_FREE(fb->data);
fb->data = NULL;
}
fbpool_put(&ui_s->tx_pool, fb);
ret = RET_OK + 1;
}
break;
default:
break;
}
return ret;
}
//创建播放器的流,这个流主要实现的是控制速度转发作用,暂时控制的是视频
//如果要控制音频,需要计算时间来控制速度
static struct msi *photo_stream(const char *name)
{
struct msi *s = msi_new(name, 0, NULL);
return s;
}
static void exit_player_ui(lv_event_t * e)
{
int32_t c = *((int32_t *)lv_event_get_param(e));
if(c == 'q')
{
struct photo_ui_s *ui_s = (struct photo_ui_s *)lv_event_get_user_data(e);
lv_indev_set_group(indev_keypad, ui_s->last_group);
lv_obj_clear_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_group_del(ui_s->now_group);
ui_s->now_group = NULL;
msi_destroy(ui_s->photo_s);
msi_destroy(ui_s->other_s);
msi_destroy(ui_s->decode_s);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
ui_s->decode_s = NULL;
ui_s->other_s = NULL;
ui_s->photo_s = NULL;
lv_obj_del(ui_s->now_ui);
set_lvgl_get_key_func(NULL);
}
}
static void enter_player_ui(lv_event_t * e)
{
set_lvgl_get_key_func(self_key);
struct photo_ui_s *ui_s = (struct photo_ui_s *)lv_event_get_user_data(e);
lv_obj_t *base_ui = ui_s->base_ui;
lv_obj_add_flag(base_ui, LV_OBJ_FLAG_HIDDEN);
os_printf("%s ui_s:%x ui_s->decode_s:%x\n",__FUNCTION__,ui_s,&ui_s->decode_s);
lv_obj_t *ui = lv_obj_create(lv_scr_act());
ui_s->now_ui = ui;
lv_obj_add_style(ui, &g_style, 0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
ui_s->label_path = lv_label_create(ui);
lv_label_set_text(ui_s->label_path, "");
lv_obj_align(ui_s->label_path,LV_ALIGN_TOP_MID,0,0);
os_printf("%s %d\n",__FUNCTION__,__LINE__);
ui_s->photo_s = photo_stream(S_LVGL_PHOTO);
if (ui_s->photo_s)
{
ui_s->photo_s->priv = (void *)ui_s;
fbpool_init(&ui_s->tx_pool, 4);
ui_s->photo_s->action = photo_msi_action;
msi_add_output(ui_s->photo_s, NULL, SR_OTHER_JPG);
ui_s->photo_s->enable = 1;
}
else
{
os_printf("photo ui new msi failed\n");
}
os_printf("%s %d\n",__FUNCTION__,__LINE__);
//SR_OTHER_JPG接收数据,然后发送到decode
ui_s->other_s = jpg_decode_msg_msi(SR_OTHER_JPG,640,360,640,360,FSTYPE_YUV_P0);
if (ui_s->other_s)
{
msi_add_output(ui_s->other_s, NULL, S_JPG_DECODE);
}
os_printf("%s %d\n",__FUNCTION__,__LINE__);
//decode发送到S_NEWPLAYER控制速度后,转发到P0
ui_s->decode_s = jpg_decode_msi(S_JPG_DECODE);
if (ui_s->decode_s)
{
msi_add_output(ui_s->decode_s, NULL, R_VIDEO_P0);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
}
os_printf("%s %d\n",__FUNCTION__,__LINE__);
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_group_add_obj(group, ui);
ui_s->now_group = group;
//弹出菜单栏,用于切换分辨率
lv_obj_add_event_cb(ui, show_filelist, LV_EVENT_KEY, ui_s);
lv_obj_add_event_cb(ui, exit_player_ui, LV_EVENT_KEY, ui_s);
}
lv_obj_t *photo_ui(lv_group_t *group,lv_obj_t *base_ui)
{
struct photo_ui_s *ui_s = (struct photo_ui_s*)STREAM_LIBC_ZALLOC(sizeof(struct photo_ui_s));
os_printf("%s ui_s:%x ui_s->decode_s:%x\n",__FUNCTION__,ui_s,&ui_s->decode_s);
ui_s->last_group = group;
ui_s->base_ui = base_ui;
lv_obj_t *btn = lv_list_add_btn(base_ui, NULL, "photo");
lv_group_add_obj(group, btn);
lv_obj_add_event_cb(btn, enter_player_ui, LV_EVENT_SHORT_CLICKED, ui_s);
return btn;
}

View File

@@ -0,0 +1,152 @@
/***********************************************************************************************************
这个主要是 dvp + csi + uvc(mjpeg) 实现视频预览最多支持4个视频源输出预览
S_PREVIEW_SCALE3 ----> R_SIM_VIDEO(320x180) ----> R_VIDEO_P0
(scale3) (虚拟屏幕)
/dev/video0 ----> ROUTE_USB ----> SR_OTHER_JPG_USB1 ----> S_JPG_DECODE ----> R_SIM_VIDEO(320x180) ----> R_VIDEO_P0
(uvc) (uvc中转流) (uvc的jpg,配置解码size) (解码成yuv:320x180) (虚拟屏幕)
/dev/video1 ----> ROUTE_USB ----> SR_OTHER_JPG_USB2 ----> S_JPG_DECODE ----> R_SIM_VIDEO(320x180) ----> R_VIDEO_P0
(uvc) (uvc中转流) (uvc的jpg,配置解码size) (解码成yuv:320x180) (虚拟屏幕)
********************************************************************************************************** */
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
#include "stream_frame.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
//data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
//结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
extern lv_indev_t * indev_keypad;
extern lv_style_t g_style;
struct preview_usb_s
{
lv_group_t *last_group;
lv_obj_t *base_ui;
lv_group_t *now_group;
lv_obj_t *now_ui;
//这个是需要的流,但命名不一定对应,有可能通过中间流进行中转实现
struct msi *sim_video;
struct msi *scale3_s;
struct msi *decode_s;
struct msi *USB_P0_jpg_s;
struct msi *USB_P1_jpg_s;
struct msi *route_usb_msi;
};
static void exit_preview_dvp_csi_usb_ui(lv_event_t * e)
{
struct preview_usb_s *ui_s = (struct preview_usb_s *)lv_event_get_user_data(e);
lv_indev_set_group(indev_keypad, ui_s->last_group);
lv_obj_clear_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_group_del(ui_s->now_group);
ui_s->now_group = NULL;
msi_destroy(ui_s->route_usb_msi);
msi_destroy(ui_s->sim_video);
msi_destroy(ui_s->scale3_s);
msi_destroy(ui_s->decode_s);
msi_destroy(ui_s->USB_P0_jpg_s);
msi_destroy(ui_s->USB_P1_jpg_s);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
lv_obj_del(ui_s->now_ui);
}
//进入预览的ui,那么就要创建新的ui去显示预览图了
static void enter_preview_dvp_csi_usb_ui(lv_event_t * e)
{
struct preview_usb_s *ui_s = (struct preview_usb_s *)lv_event_get_user_data(e);
lv_obj_add_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_t *ui = lv_obj_create(lv_scr_act());
ui_s->now_ui = ui;
lv_obj_add_style(ui, &g_style, 0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
static const uint16_t filter[] = { FSTYPE_YUV_P0, FSTYPE_YUV_P1, FSTYPE_YUV_SIM_P0, FSTYPE_USB_CAM0, FSTYPE_USB_CAM1, FSTYPE_NONE };
ui_s->sim_video = sim_video_more_msi(R_SIM_VIDEO, 800, 480, (uint16_t*)filter);
if (ui_s->sim_video)
{
msi_add_output(ui_s->sim_video, NULL, R_VIDEO_P0);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
}
ui_s->scale3_s = scale3_msi(S_PREVIEW_SCALE3);
//绑定流到Video P1显示
if (ui_s->scale3_s)
{
msi_add_output(ui_s->scale3_s, NULL, R_SIM_VIDEO);
}
ui_s->decode_s = jpg_decode_msi(S_JPG_DECODE);
//将解码的数据推送到Video P0
if (ui_s->decode_s)
{
msi_add_output(ui_s->decode_s, NULL, R_SIM_VIDEO);
}
//接收UVC的jpg,配置解码需要的参数(320x180),最后给到解码模块
ui_s->USB_P0_jpg_s = jpg_decode_msg_msi(SR_OTHER_JPG_USB1,320,180,320,180,FSTYPE_USB_CAM0);
//将other_jpg的数据给到S_JPG_DECODE进行编码
if (ui_s->USB_P0_jpg_s)
{
// 配置解码的坐标值
msi_do_cmd(ui_s->USB_P0_jpg_s, MSI_CMD_DECODE_JPEG_MSG, MSI_JPEG_DECODE_X_Y, 0 << 16 | 220);
msi_add_output(ui_s->USB_P0_jpg_s, NULL, S_JPG_DECODE);
}
//接收usb的jpg数据,配置需要解码的参数(320x180),然后给到S_JPG_DECODE进行解码,最后给到P1去显示(设置时P1的类型)
ui_s->USB_P1_jpg_s = jpg_decode_msg_msi(SR_OTHER_JPG_USB2,320,180,320,180,FSTYPE_USB_CAM1);
//将other_jpg的数据给到S_JPG_DECODE进行编码
if (ui_s->USB_P1_jpg_s)
{
// 配置解码的坐标值
msi_do_cmd(ui_s->USB_P1_jpg_s, MSI_CMD_DECODE_JPEG_MSG, MSI_JPEG_DECODE_X_Y, 360 << 16 | 220);
msi_add_output(ui_s->USB_P1_jpg_s, NULL, S_JPG_DECODE);
}
ui_s->route_usb_msi = route_msi(ROUTE_USB);
if (ui_s->route_usb_msi)
{
msi_add_output(ui_s->route_usb_msi, NULL, SR_OTHER_JPG_USB1);
msi_add_output(ui_s->route_usb_msi, NULL, SR_OTHER_JPG_USB2);
}
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_group_add_obj(group, ui);
ui_s->now_group = group;
lv_obj_add_event_cb(ui, exit_preview_dvp_csi_usb_ui, LV_EVENT_PRESSED, ui_s);
}
lv_obj_t *preview_dvp_csi_usb_ui(lv_group_t *group,lv_obj_t *base_ui)
{
struct preview_usb_s *ui_s = (struct preview_usb_s*)STREAM_LIBC_ZALLOC(sizeof(struct preview_usb_s));
ui_s->last_group = group;
ui_s->base_ui = base_ui;
lv_obj_t *btn = lv_list_add_btn(base_ui, NULL, "preview_dvp_csi_usb");
lv_group_add_obj(group, btn);
lv_obj_add_event_cb(btn, enter_preview_dvp_csi_usb_ui, LV_EVENT_PRESSED, ui_s);
return btn;
}

View File

@@ -0,0 +1,288 @@
/***************************************************************************************
S_PREVIEW_SCALE3 ----> R_VIDEO_P0(320x180)
(scale3) (lcd_video_p0)
RS_JPG_CONCAT ----> R_LVGL_TAKEPHOTO(1280x720)
(mjpeg)
***************************************************************************************/
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
#include "stream_frame.h"
#include "keyWork.h"
#include "keyScan.h"
#include "fatfs/osal_file.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
//data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
//结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
#define LV_OBJ_TAKEPHOTO_FLAG LV_OBJ_FLAG_USER_1
extern lv_indev_t * indev_keypad;
extern lv_style_t g_style;
struct preview_encode_takephoto_ui_s
{
lv_group_t *last_group;
lv_obj_t *base_ui;
lv_group_t *now_group;
lv_obj_t *now_ui;
lv_timer_t *timer;
struct msi *s;
struct msi *jpg_s;
struct msi *takephoto_s;
};
static uint32_t self_key(uint32_t val)
{
uint32_t key_ret = 0;
if(val > 0)
{
if((val&0xff) == KEY_EVENT_SUP)
{
switch(val>>8)
{
case AD_UP:
key_ret = 'a';
break;
case AD_DOWN:
key_ret = 's';
break;
case AD_LEFT:
key_ret = 'q';
break;
case AD_RIGHT:
key_ret = 'd';
break;
case AD_PRESS:
key_ret = LV_KEY_ENTER;
break;
break;
default:
break;
}
}
else if((val&0xff) == KEY_EVENT_LUP)
{
switch(val>>8)
{
case AD_PRESS:
key_ret = 'e';
break;
default:
break;
}
}
}
return key_ret;
}
//生成一个流,专门接收图片,用于拍照的,拍照之前可以将缓冲区的删除,这样可以保证得到最新的图片
//要考虑一些问题,如果拍照放在workqueue,要考虑写卡时间是否影响workqueue
//这里尝试使用lvgl的timer事件去保存(影响lvgl,如果需要更加好,可能要创建任务去保存)
static int32 takephoto_msi_action(struct msi *msi, uint32 cmd_id, uint32 param1, uint32 param2)
{
int32_t ret = RET_OK;
//struct preview_encode_takephoto_ui_s *ui_s = (struct preview_encode_takephoto_ui_s *)msi->priv;
switch (cmd_id)
{
case MSI_CMD_PRE_DESTROY:
{
}
break;
case MSI_CMD_POST_DESTROY:
{
}
break;
case MSI_CMD_FREE_FB:
{
}
break;
default:
break;
}
return ret;
}
static struct msi *takephoto_stream(const char *name)
{
//设置接收1,是为了不要接收太多的图片,因为是拍照,需要保持实时性
//如果接收过多,如果不处理,会导致源头没有空间产生新的图片
//如果要结合录像,则需要在应用层去处理(实际录像时可以创建另一个独立的流)
struct msi *msi = msi_new(name, 1, NULL);
return msi;
}
static void takephoto_timer(lv_timer_t *t)
{
struct preview_encode_takephoto_ui_s *ui_s = (struct preview_encode_takephoto_ui_s *)t->user_data;
struct framebuff *fb = NULL;
//看看对应的流有没有图片,如果有,则保存
fb = msi_get_fb(ui_s->takephoto_s, 0);
if(fb)
{
ui_s->takephoto_s->enable = 0;
char filename[64];
sprintf(filename,"0:/photo/%08d.jpg",(uint32_t)os_jiffies());
void *fp = osal_fopen(filename,"wb");
if(fp)
{
osal_fwrite(fb->data,1,fb->len,fp);
osal_fclose(fp);
}
else
{
os_printf("takephoto fail,filename:%s\n",filename);
}
//保存图片
msi_delete_fb(NULL, fb);
while(fb)
{
fb = msi_get_fb(ui_s->takephoto_s, 0);
if(fb)
{
msi_delete_fb(NULL, fb);
}
}
os_printf("takephoto success\n");
lv_obj_clear_flag(ui_s->now_ui, LV_OBJ_TAKEPHOTO_FLAG);
ui_s->timer = NULL;
lv_timer_del(t);
}
}
//使能拍照
static void encode_takephoto_ui(lv_event_t * e)
{
struct preview_encode_takephoto_ui_s *ui_s = (struct preview_encode_takephoto_ui_s *)lv_event_get_user_data(e);
struct msi *s = ui_s->takephoto_s;
int32_t c = *((int32_t *)lv_event_get_param(e));
if(c == LV_KEY_ENTER)
{
if(!lv_obj_has_flag(ui_s->now_ui,LV_OBJ_TAKEPHOTO_FLAG))
{
lv_obj_add_flag(ui_s->now_ui, LV_OBJ_TAKEPHOTO_FLAG);
s->enable = 1;
//启动timer,10ms检查一次
ui_s->timer = lv_timer_create(takephoto_timer, 10, (void*)ui_s);
}
else
{
//已经在拍照了
os_printf("%s already running\n",__FUNCTION__);
}
}
}
static void exit_preview_encode_takephoto_ui(lv_event_t * e)
{
struct preview_encode_takephoto_ui_s *ui_s = (struct preview_encode_takephoto_ui_s *)lv_event_get_user_data(e);
int32_t c = *((int32_t *)lv_event_get_param(e));
if(c == 'q')
{
if(ui_s->timer)
{
lv_timer_del(ui_s->timer);
}
struct preview_encode_takephoto_ui_s *ui_s = (struct preview_encode_takephoto_ui_s *)lv_event_get_user_data(e);
lv_indev_set_group(indev_keypad, ui_s->last_group);
lv_obj_clear_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_group_del(ui_s->now_group);
ui_s->now_group = NULL;
msi_destroy(ui_s->s);
msi_del_output(ui_s->jpg_s, NULL, R_LVGL_TAKEPHOTO);
msi_put(ui_s->jpg_s);
msi_destroy(ui_s->takephoto_s);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
lv_obj_del(ui_s->now_ui);
set_lvgl_get_key_func(NULL);
}
}
//进入预览的ui,那么就要创建新的ui去显示预览图了
static void enter_preview_encode_takephoto_ui(lv_event_t * e)
{
set_lvgl_get_key_func(self_key);
struct preview_encode_takephoto_ui_s *ui_s = (struct preview_encode_takephoto_ui_s *)lv_event_get_user_data(e);
lv_obj_add_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_t *ui = lv_obj_create(lv_scr_act());
ui_s->now_ui = ui;
lv_obj_add_style(ui, &g_style, 0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
ui_s->s = scale3_msi(S_PREVIEW_SCALE3);
//绑定流到Video P0显示
if (ui_s->s)
{
msi_add_output(ui_s->s, NULL, R_VIDEO_P0);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
ui_s->s->enable = 1;
}
//创建jpg流,设置从vpp_buf0取数据
ui_s->jpg_s = msi_find(AUTO_JPG, 1);
if(ui_s->jpg_s)
{
msi_add_output(ui_s->jpg_s, NULL, R_LVGL_TAKEPHOTO);
ui_s->jpg_s->enable = 1;
}
ui_s->takephoto_s = takephoto_stream(R_LVGL_TAKEPHOTO);
if(ui_s->takephoto_s)
{
ui_s->takephoto_s->action = takephoto_msi_action;
ui_s->takephoto_s->priv = ui_s;
}
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_group_add_obj(group, ui);
ui_s->now_group = group;
lv_obj_add_event_cb(ui, exit_preview_encode_takephoto_ui, LV_EVENT_KEY, ui_s);
//拍照的按键事件
lv_obj_add_event_cb(ui, encode_takephoto_ui, LV_EVENT_KEY, ui_s);
}
lv_obj_t *preview_encode_takephoto_ui(lv_group_t *group,lv_obj_t *base_ui)
{
struct preview_encode_takephoto_ui_s *ui_s = (struct preview_encode_takephoto_ui_s*)STREAM_LIBC_ZALLOC(sizeof(struct preview_encode_takephoto_ui_s));
ui_s->last_group = group;
ui_s->base_ui = base_ui;
lv_obj_t *btn = lv_list_add_btn(base_ui, NULL, "preview_encode_takephoto");
lv_group_add_obj(group, btn);
lv_obj_add_event_cb(btn, enter_preview_encode_takephoto_ui, LV_EVENT_SHORT_CLICKED, ui_s);
return btn;
}

310
sdk/app/ui/preview_qc_ui.c Normal file
View File

@@ -0,0 +1,310 @@
/***********************************************************************************************************
这个主要是 dvp + csi + uvc(mjpeg) 实现视频预览最多支持4个视频源输出预览
S_PREVIEW_SCALE3 ----> R_SIM_VIDEO(320x180) ----> R_VIDEO_P0
(scale3) (虚拟屏幕)
/dev/video0 ----> ROUTE_USB ----> SR_OTHER_JPG_USB1 ----> S_JPG_DECODE ----> R_SIM_VIDEO(320x180) ----> R_VIDEO_P0
(uvc) (uvc中转流) (uvc的jpg,配置解码size) (解码成yuv:320x180) (虚拟屏幕)
S_LVGL_PHOTO ----> SR_OTHER_JPG_USB2 ----> S_JPG_DECODE ----> R_SIM_VIDEO(320x180) ----> R_VIDEO_P0
(sd) (sd的jpg,配置解码size) (解码成yuv:320x180) (虚拟屏幕)
********************************************************************************************************** */
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
#include "stream_frame.h"
#include "fatfs/osal_file.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
#define CHECK_DIR "photo"
#define EXT_NAME "*jpg"
//data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
//结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
extern lv_indev_t * indev_keypad;
extern lv_style_t g_style;
struct preview_qc_s
{
struct os_work work;
lv_group_t *last_group;
lv_obj_t *base_ui;
lv_group_t *now_group;
lv_obj_t *now_ui;
//这个是需要的流,但命名不一定对应,有可能通过中间流进行中转实现
struct msi *sim_video;
struct msi *scale3_s;
struct msi *decode_s;
struct msi *USB_P0_jpg_s;
struct msi *USB_P1_jpg_s;
struct msi *photo_s;
struct fbpool tx_pool;
struct msi *route_usb_msi;
};
static void play_photo(void *d)
{
void *fp = NULL;
void *photo_buf = NULL;
struct framebuff *data_s = NULL;
struct preview_qc_s *ui_s = (struct preview_qc_s *)d;
uint32_t len;
char path[64];
os_sprintf(path,"0:%s/%s",CHECK_DIR,"qc.jpg");
if(!ui_s->photo_s)
{
os_printf("%s %d\n",__FUNCTION__,__LINE__);
goto play_photo_fail;
}
//读取图片文件,通过流去发送
data_s = fbpool_get(&ui_s->tx_pool, 0, ui_s->photo_s);
if(data_s)
{
data_s->data = NULL;
//开始显示图片
fp = osal_fopen(path,"rb");
if(fp)
{
uint32_t filesize = osal_fsize(fp);
photo_buf = (void*)STREAM_MALLOC(filesize);
if(!photo_buf)
{
msi_delete_fb(ui_s->photo_s, data_s);
data_s = NULL;
os_printf("%s %d\n",__FUNCTION__,__LINE__);
goto play_photo_fail;
}
else
{
len = osal_fread(photo_buf,1,filesize,fp);
if(len != filesize)
{
os_printf("%s %d\n",__FUNCTION__,__LINE__);
goto play_photo_fail;
}
data_s->data = (void*)photo_buf;
data_s->mtype = F_JPG;
data_s->stype = FSTYPE_YUV_SIM_P0;
data_s->len = filesize;
msi_output_fb(ui_s->photo_s, data_s);
photo_buf = NULL;
data_s = NULL;
goto play_photo_end;
}
}
os_printf("%s %d\n",__FUNCTION__,__LINE__);
goto play_photo_fail;
}
play_photo_fail:
//显示失败
os_sprintf(path,"0:%s/%s fail",CHECK_DIR,"qc.jpg");
os_printf("----------------------------------------\n");
if(photo_buf)
{
STREAM_FREE(photo_buf);
}
if(data_s)
{
msi_delete_fb(NULL, data_s);
}
play_photo_end:
if(fp)
{
osal_fclose(fp);
fp = NULL;
}
}
static int32 photo_msi_work(struct os_work *work)
{
struct preview_qc_s *ui_s = (struct preview_qc_s *)work;
play_photo(ui_s);
os_run_work_delay(&ui_s->work, 200);
return 0;
}
static int32 photo_msi_action(struct msi *msi, uint32 cmd_id, uint32 param1, uint32 param2)
{
int32_t ret = RET_OK;
struct preview_qc_s *ui_s = (struct preview_qc_s *)msi->priv;
switch (cmd_id)
{
case MSI_CMD_PRE_DESTROY:
{
os_work_cancle2(&ui_s->work, 1);
}
break;
case MSI_CMD_POST_DESTROY:
{
fbpool_destroy(&ui_s->tx_pool);
os_printf("%s %d\n",__FUNCTION__,__LINE__);
}
break;
case MSI_CMD_FREE_FB:
{
struct framebuff *fb = (struct framebuff *)param1;
if (fb->data)
{
STREAM_FREE(fb->data);
fb->data = NULL;
}
fbpool_put(&ui_s->tx_pool, fb);
ret = RET_OK + 1;
}
break;
default:
break;
}
return ret;
}
//创建播放器的流,这个流主要实现的是控制速度转发作用,暂时控制的是视频
//如果要控制音频,需要计算时间来控制速度
static struct msi *photo_stream(const char *name)
{
struct msi *s = msi_new(name, 0, NULL);
return s;
}
static void exit_preview_qc_ui(lv_event_t * e)
{
struct preview_qc_s *ui_s = (struct preview_qc_s *)lv_event_get_user_data(e);
lv_indev_set_group(indev_keypad, ui_s->last_group);
lv_obj_clear_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_group_del(ui_s->now_group);
ui_s->now_group = NULL;
msi_destroy(ui_s->photo_s);
msi_destroy(ui_s->route_usb_msi);
msi_destroy(ui_s->sim_video);
msi_destroy(ui_s->scale3_s);
msi_destroy(ui_s->decode_s);
msi_destroy(ui_s->USB_P0_jpg_s);
msi_destroy(ui_s->USB_P1_jpg_s);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
msi_cmd(R_VIDEO_P1, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
lv_obj_del(ui_s->now_ui);
}
//进入预览的ui,那么就要创建新的ui去显示预览图了
static void enter_preview_qc_ui(lv_event_t * e)
{
struct preview_qc_s *ui_s = (struct preview_qc_s *)lv_event_get_user_data(e);
lv_obj_add_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_t *ui = lv_obj_create(lv_scr_act());
ui_s->now_ui = ui;
lv_obj_add_style(ui, &g_style, 0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
static const uint16_t filter[] = { FSTYPE_YUV_P0, FSTYPE_YUV_P1, FSTYPE_YUV_SIM_P0, FSTYPE_USB_CAM0, FSTYPE_USB_CAM1, FSTYPE_NONE };
ui_s->sim_video = sim_video_more_msi(R_SIM_VIDEO, 800, 480, (uint16_t*)filter);
if (ui_s->sim_video)
{
msi_add_output(ui_s->sim_video, NULL, R_VIDEO_P0);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
}
ui_s->scale3_s = scale3_msi(S_PREVIEW_SCALE3);
//绑定流到Video P1显示
if (ui_s->scale3_s)
{
msi_add_output(ui_s->scale3_s, NULL, R_SIM_VIDEO);
}
ui_s->decode_s = jpg_decode_msi(S_JPG_DECODE);
//将解码的数据推送到Video P0
if (ui_s->decode_s)
{
msi_add_output(ui_s->decode_s, NULL, R_SIM_VIDEO);
}
//接收UVC的jpg,配置解码需要的参数(320x180),最后给到解码模块
ui_s->USB_P0_jpg_s = jpg_decode_msg_msi(SR_OTHER_JPG_USB1,320,180,320,180,FSTYPE_USB_CAM0);
//将other_jpg的数据给到S_JPG_DECODE进行编码
if (ui_s->USB_P0_jpg_s)
{
// 配置解码的坐标值
msi_do_cmd(ui_s->USB_P0_jpg_s, MSI_CMD_DECODE_JPEG_MSG, MSI_JPEG_DECODE_X_Y, 0 << 16 | 220);
msi_add_output(ui_s->USB_P0_jpg_s, NULL, S_JPG_DECODE);
}
ui_s->photo_s = photo_stream(S_LVGL_PHOTO);
if (ui_s->photo_s)
{
ui_s->photo_s->priv = (void *)ui_s;
fbpool_init(&ui_s->tx_pool, 4);
ui_s->photo_s->action = photo_msi_action;
msi_add_output(ui_s->photo_s, NULL, SR_OTHER_JPG_USB2);
ui_s->photo_s->enable = 1;
}
//接收usb的jpg数据,配置需要解码的参数(320x180),然后给到S_JPG_DECODE进行解码,最后给到P1去显示(设置时P1的类型)
ui_s->USB_P1_jpg_s = jpg_decode_msg_msi(SR_OTHER_JPG_USB2,320,180,320,180,FSTYPE_YUV_SIM_P0);
//将other_jpg的数据给到S_JPG_DECODE进行编码
if (ui_s->USB_P1_jpg_s)
{
// 配置解码的坐标值
msi_do_cmd(ui_s->USB_P1_jpg_s, MSI_CMD_DECODE_JPEG_MSG, MSI_JPEG_DECODE_X_Y, 360 << 16 | 220);
msi_add_output(ui_s->USB_P1_jpg_s, NULL, S_JPG_DECODE);
}
ui_s->route_usb_msi = route_msi(ROUTE_USB);
if (ui_s->route_usb_msi)
{
msi_add_output(ui_s->route_usb_msi, NULL, SR_OTHER_JPG_USB1);
}
OS_WORK_INIT(&ui_s->work, photo_msi_work, 0);
os_run_work_delay(&ui_s->work, 1);
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_group_add_obj(group, ui);
ui_s->now_group = group;
lv_obj_add_event_cb(ui, exit_preview_qc_ui, LV_EVENT_PRESSED, ui_s);
}
lv_obj_t *preview_qc_ui(lv_group_t *group,lv_obj_t *base_ui)
{
struct preview_qc_s *ui_s = (struct preview_qc_s*)STREAM_LIBC_ZALLOC(sizeof(struct preview_qc_s));
ui_s->last_group = group;
ui_s->base_ui = base_ui;
lv_obj_t *btn = lv_list_add_btn(base_ui, NULL, "preview_qc");
lv_group_add_obj(group, btn);
lv_obj_add_event_cb(btn, enter_preview_qc_ui, LV_EVENT_PRESSED, ui_s);
return btn;
}

View File

@@ -0,0 +1,98 @@
/***************************************************************************************
这个主要是预览,通过scale3_msi将dvp/csi数据scale到对应的分辨率作为数据流发送出去
然后lcd_msi需要接收对应的数据去显示
这里只是产生对应数据流,数据用途实际需要终端流(比如lcd流)接收后去处理
S_PREVIEW_SCALE3 ----> R_SIM_VIDEO(320x180) ----> R_VIDEO_P0
(scale3) (虚拟屏幕)
***************************************************************************************/
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
#include "stream_frame.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
//data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
//结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
extern lv_indev_t * indev_keypad;
extern lv_style_t g_style;
struct preview_ui_s
{
lv_group_t *last_group;
lv_obj_t *base_ui;
lv_group_t *now_group;
lv_obj_t *now_ui;
struct msi *s;
struct msi *sim_video;
};
static void exit_preview_ui(lv_event_t * e)
{
struct preview_ui_s *ui_s = (struct preview_ui_s *)lv_event_get_user_data(e);
lv_indev_set_group(indev_keypad, ui_s->last_group);
lv_obj_clear_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_group_del(ui_s->now_group);
ui_s->now_group = NULL;
msi_destroy(ui_s->s);
msi_destroy(ui_s->sim_video);
//关闭VIDEO P0,VIDEO P1的使能释放占住的scale3的fb
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
lv_obj_del(ui_s->now_ui);
}
//进入预览的ui,那么就要创建新的ui去显示预览图了
static void enter_preview_ui(lv_event_t * e)
{
struct preview_ui_s *ui_s = (struct preview_ui_s *)lv_event_get_user_data(e);
lv_obj_add_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_t *ui = lv_obj_create(lv_scr_act());
ui_s->now_ui = ui;
lv_obj_add_style(ui, &g_style, 0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
ui_s->sim_video = sim_video_msi(R_SIM_VIDEO, 800, 480, 0);
if (ui_s->sim_video)
{
msi_add_output(ui_s->sim_video, NULL, R_VIDEO_P0);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
}
ui_s->s = scale3_msi(S_PREVIEW_SCALE3);
if (ui_s->s)
{
msi_add_output(ui_s->s, NULL, R_SIM_VIDEO);
ui_s->s->enable = 1;
}
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_group_add_obj(group, ui);
ui_s->now_group = group;
lv_obj_add_event_cb(ui, exit_preview_ui, LV_EVENT_PRESSED, ui_s);
}
lv_obj_t *preview_sim_video_ui(lv_group_t *group,lv_obj_t *base_ui)
{
struct preview_ui_s *ui_s = (struct preview_ui_s*)STREAM_LIBC_ZALLOC(sizeof(struct preview_ui_s));
ui_s->last_group = group;
ui_s->base_ui = base_ui;
lv_obj_t *btn = lv_list_add_btn(base_ui, NULL, "preview_sim_video");
lv_group_add_obj(group, btn);
lv_obj_add_event_cb(btn, enter_preview_ui, LV_EVENT_PRESSED, ui_s);
return btn;
}

104
sdk/app/ui/preview_ui.c Normal file
View File

@@ -0,0 +1,104 @@
/***************************************************************************************
这个主要是预览,通过scale3_msi将dvp/csi数据scale到对应的分辨率作为数据流发送出去
然后lcd_msi需要接收对应的数据去显示
这里只是产生对应数据流,数据用途实际需要终端流(比如lcd流)接收后去处理
----> R_VIDEO_P0(320x240)
| (lcd_video_p0)
S_PREVIEW_SCALE3 -----|
(scale3) |
----> R_VIDEO_P1(320x240)
(lcd_video_p1)
***************************************************************************************/
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
#include "stream_frame.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
// data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
// 结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
extern lv_indev_t *indev_keypad;
extern lv_style_t g_style;
struct preview_ui_s
{
lv_group_t *last_group;
lv_obj_t *base_ui;
uint16_t w, h;
lv_group_t *now_group;
lv_obj_t *now_ui;
struct msi *s;
};
static void exit_preview_ui(lv_event_t *e)
{
struct preview_ui_s *ui_s = (struct preview_ui_s *) lv_event_get_user_data(e);
lv_indev_set_group(indev_keypad, ui_s->last_group);
lv_obj_clear_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_group_del(ui_s->now_group);
ui_s->now_group = NULL;
msi_del_output(ui_s->s, NULL, R_VIDEO_P0);
msi_del_output(ui_s->s, NULL, R_VIDEO_P1);
ui_s->s->enable = 0;
if(ui_s->s)
{
msi_do_cmd(ui_s->s, MSI_CMD_SCALE3_NORMAL, MSI_SCALE3_START, 0);
}
// 关闭VIDEO P0,VIDEO P1的使能释放占住的scale3的fb
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
msi_cmd(R_VIDEO_P1, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
msi_destroy(ui_s->s);
lv_obj_del(ui_s->now_ui);
}
// 进入预览的ui,那么就要创建新的ui去显示预览图了
static void enter_preview_ui(lv_event_t *e)
{
struct preview_ui_s *ui_s = (struct preview_ui_s *) lv_event_get_user_data(e);
lv_obj_add_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_t *ui = lv_obj_create(lv_scr_act());
ui_s->now_ui = ui;
lv_obj_add_style(ui, &g_style, 0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
// 绑定流到Video_P0,Video_P1显示
ui_s->s = scale3_normal_msi2(S_PREVIEW_SCALE3, FSTYPE_YUV_P0, ui_s->w, ui_s->h);
if (ui_s->s)
{
msi_do_cmd(ui_s->s, MSI_CMD_SCALE3_NORMAL, MSI_SCALE3_START, 1);
msi_add_output(ui_s->s, NULL, R_VIDEO_P0);
msi_add_output(ui_s->s, NULL, R_VIDEO_P1);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
msi_cmd(R_VIDEO_P1, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
ui_s->s->enable = 1;
}
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_group_add_obj(group, ui);
ui_s->now_group = group;
lv_obj_add_event_cb(ui, exit_preview_ui, LV_EVENT_PRESSED, ui_s);
}
lv_obj_t *preview_ui(lv_group_t *group, lv_obj_t *base_ui, uint16_t w, uint16_t h)
{
struct preview_ui_s *ui_s = (struct preview_ui_s *) STREAM_LIBC_ZALLOC(sizeof(struct preview_ui_s));
ui_s->last_group = group;
ui_s->base_ui = base_ui;
ui_s->w = w;
ui_s->h = h;
lv_obj_t *btn = lv_list_add_btn(base_ui, NULL, "preview");
lv_group_add_obj(group, btn);
lv_obj_add_event_cb(btn, enter_preview_ui, LV_EVENT_PRESSED, ui_s);
return btn;
}

157
sdk/app/ui/preview_usb_ui.c Normal file
View File

@@ -0,0 +1,157 @@
/***********************************************************************************************************
支持双路 UVC mjpeg 镜头解码同时输出推屏,可以根据情况只显示一个
/dev/video0 ----> ROUTE_USB ----> SR_OTHER_JPG_USB1 ----> S_JPG_DECODE ----> R_SIM_VIDEO(320x180) ----> R_VIDEO_P0
(uvc) (uvc中转流) (uvc的jpg,配置解码size) (解码成yuv:320x180) (虚拟屏幕)
/dev/video1 ----> ROUTE_USB ----> SR_OTHER_JPG_USB2 ----> S_JPG_DECODE ----> R_SIM_VIDEO(320x180) ----> R_VIDEO_P0
(uvc) (uvc中转流) (uvc的jpg,配置解码size) (解码成yuv:320x180) (虚拟屏幕)
********************************************************************************************************** */
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
#include "stream_frame.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
//data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
//结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
extern lv_indev_t * indev_keypad;
extern lv_style_t g_style;
struct preview_usb_s
{
lv_group_t *last_group;
lv_obj_t *base_ui;
lv_group_t *now_group;
lv_obj_t *now_ui;
//这个是需要的流,但命名不一定对应,有可能通过中间流进行中转实现
struct msi *sim_video;
struct msi *sim_decode_jpg_msi;
struct msi *usb_P0_jpg_s;
struct msi *usb_P1_jpg_s;
struct msi *decode_s;
};
static void exit_preview_usb_ui(lv_event_t * e)
{
struct preview_usb_s *ui_s = (struct preview_usb_s *)lv_event_get_user_data(e);
lv_indev_set_group(indev_keypad, ui_s->last_group);
lv_obj_clear_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_group_del(ui_s->now_group);
ui_s->now_group = NULL;
msi_destroy(ui_s->sim_video);
msi_destroy(ui_s->sim_decode_jpg_msi);
msi_destroy(ui_s->usb_P0_jpg_s);
msi_destroy(ui_s->usb_P1_jpg_s);
msi_destroy(ui_s->decode_s);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
lv_obj_del(ui_s->now_ui);
}
//进入预览的ui,那么就要创建新的ui去显示预览图了
static void enter_preview_usb_ui(lv_event_t * e)
{
struct preview_usb_s *ui_s = (struct preview_usb_s *)lv_event_get_user_data(e);
lv_obj_add_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_t *ui = lv_obj_create(lv_scr_act());
ui_s->now_ui = ui;
lv_obj_add_style(ui, &g_style, 0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
ui_s->sim_decode_jpg_msi = route_msi(ROUTE_USB);
if (ui_s->sim_decode_jpg_msi)
{
msi_add_output(ui_s->sim_decode_jpg_msi, NULL, SR_OTHER_JPG_USB1);
msi_add_output(ui_s->sim_decode_jpg_msi, NULL, SR_OTHER_JPG_USB2);
}
else
{
os_printf("route new msi failed\n");
}
static const uint16_t filter[] = { FSTYPE_USB_CAM0, FSTYPE_USB_CAM1, FSTYPE_NONE };
ui_s->sim_video = sim_video_more_msi(R_SIM_VIDEO, 800, 480, (uint16_t *)filter);
if (ui_s->sim_video)
{
msi_add_output(ui_s->sim_video, NULL, R_VIDEO_P0);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
}
else
{
os_printf("sim video new msi failed\n");
}
ui_s->decode_s = jpg_decode_msi(S_JPG_DECODE);
//将解码的数据推送到Video P0和Video P1显示
if (ui_s->decode_s)
{
msi_add_output(ui_s->decode_s, NULL, R_SIM_VIDEO);
}
else
{
os_printf("jpg decode new msi failed\n");
}
//接收usb的jpg数据,配置需要解码的参数(320x180),然后给到S_JPG_DECODE进行解码,最后给到P0去显示(设置是P0的类型)
ui_s->usb_P0_jpg_s = jpg_decode_msg_msi(SR_OTHER_JPG_USB1,320,180,320,180,FSTYPE_USB_CAM0);
//将other_jpg的数据给到S_JPG_DECODE进行编码
if (ui_s->usb_P0_jpg_s)
{
// 配置解码的坐标值
msi_do_cmd(ui_s->usb_P0_jpg_s, MSI_CMD_DECODE_JPEG_MSG, MSI_JPEG_DECODE_X_Y, 0 << 16 | 0);
msi_add_output(ui_s->usb_P0_jpg_s, NULL, S_JPG_DECODE);
}
else
{
os_printf("jpg decode msg 0 new msi failed\n");
}
//接收usb的jpg数据,配置需要解码的参数(320x180),然后给到S_JPG_DECODE进行解码,最后给到P0去显示(设置是P0的类型)
ui_s->usb_P1_jpg_s = jpg_decode_msg_msi(SR_OTHER_JPG_USB2,320,180,320,180,FSTYPE_USB_CAM1);
//将other_jpg的数据给到S_JPG_DECODE进行编码
if (ui_s->usb_P1_jpg_s)
{
// 配置解码的坐标值
msi_do_cmd(ui_s->usb_P1_jpg_s, MSI_CMD_DECODE_JPEG_MSG, MSI_JPEG_DECODE_X_Y, 360 << 16 | 0);
msi_add_output(ui_s->usb_P1_jpg_s, NULL, S_JPG_DECODE);
}
else
{
os_printf("jpg decode msg 1 new msi failed\n");
}
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_group_add_obj(group, ui);
ui_s->now_group = group;
lv_obj_add_event_cb(ui, exit_preview_usb_ui, LV_EVENT_PRESSED, ui_s);
}
lv_obj_t *preview_usb_ui(lv_group_t *group,lv_obj_t *base_ui)
{
struct preview_usb_s *ui_s = (struct preview_usb_s*)STREAM_LIBC_ZALLOC(sizeof(struct preview_usb_s));
ui_s->last_group = group;
ui_s->base_ui = base_ui;
lv_obj_t *btn = lv_list_add_btn(base_ui, NULL, "preview_usb_pip");
lv_group_add_obj(group, btn);
lv_obj_add_event_cb(btn, enter_preview_usb_ui, LV_EVENT_PRESSED, ui_s);
return btn;
}

183
sdk/app/ui/takephoto_ui.c Normal file
View File

@@ -0,0 +1,183 @@
/***************************************************************************************
这个主要是预览,通过scale3_msi将dvp/csi数据scale到对应的分辨率作为数据流发送出去
然后lcd_msi需要接收对应的数据去显示
这里只是产生对应数据流,数据用途实际需要终端流(比如lcd流)接收后去处理
----> R_VIDEO_P0(320x240)
| (lcd_video_p0)
S_PREVIEW_SCALE3 -----|
(scale3) |
----> R_VIDEO_P1(320x240)
(lcd_video_p1)
***************************************************************************************/
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
#include "stream_frame.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
#include "scale_msi/scale3_normal_msi.h"
extern void common_takephoto_over_dpi_api(struct msi *scale3, uint16_t normal_w, uint16_t noraml_h, uint16_t thumb_w, uint16_t thumb_h);
extern void common_takephoto_noraml_api(struct msi *jpg_normal_msi);
// data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
// 结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
extern lv_indev_t *indev_keypad;
extern lv_style_t g_style;
struct takephoto_ui_s
{
lv_group_t *last_group;
lv_obj_t *base_ui;
uint16_t w, h;
lv_group_t *now_group;
lv_obj_t *now_ui;
struct msi *s;
struct msi *over_dpi_msi;
struct msi *thumb_msi;
struct msi *scale1_jpg_recode_msi;
struct msi *jpg_normal_msi;
};
static void exit_takephoto_ui(lv_event_t *e)
{
struct takephoto_ui_s *ui_s = (struct takephoto_ui_s *) lv_event_get_user_data(e);
lv_indev_set_group(indev_keypad, ui_s->last_group);
lv_obj_clear_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_group_del(ui_s->now_group);
ui_s->now_group = NULL;
msi_del_output(ui_s->s, NULL, R_VIDEO_P0);
msi_del_output(ui_s->s, NULL, R_VIDEO_P1);
ui_s->s->enable = 0;
// 关闭VIDEO P0,VIDEO P1的使能释放占住的scale3的fb
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
msi_cmd(R_VIDEO_P1, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 0);
if (ui_s->s)
{
msi_do_cmd(ui_s->s, MSI_CMD_SCALE3_NORMAL, MSI_SCALE3_START, 0);
if (ui_s->thumb_msi)
{
msi_del_output(ui_s->s, NULL, ui_s->thumb_msi->name);
msi_put(ui_s->thumb_msi);
}
if (ui_s->over_dpi_msi)
{
msi_del_output(ui_s->s, NULL, ui_s->over_dpi_msi->name);
msi_put(ui_s->over_dpi_msi);
}
}
if (ui_s->scale1_jpg_recode_msi)
{
msi_put(ui_s->scale1_jpg_recode_msi);
}
if(ui_s->jpg_normal_msi)
{
msi_put(ui_s->jpg_normal_msi);
}
msi_destroy(ui_s->s);
lv_obj_del(ui_s->now_ui);
}
static void takephoto_action(lv_event_t *e)
{
struct takephoto_ui_s *ui_s = (struct takephoto_ui_s *) lv_event_get_user_data(e);
// 没有找到重新编码的msi
if (!ui_s->scale1_jpg_recode_msi)
{
return;
}
//测试代码,如果是需要插值拍照
if (0)
{
// 设置需要拍照的分辨率,这里是demo,暂时固定,实际需要通过设置文件去配置
uint32_t w = 2560;
uint32_t h = 1440;
uint32_t dpi_w_h = w << 16 | h;
msi_do_cmd(ui_s->scale1_jpg_recode_msi, MSI_CMD_SCALE1, MSI_SCALE1_RESET_DPI, dpi_w_h);
os_printf("takephoto_action\n");
// 缩略图320x240
// 原图yuv
common_takephoto_over_dpi_api(ui_s->s, 0, 0, 320, 240);
}
//非插值拍照
else
{
if(ui_s->jpg_normal_msi)
{
common_takephoto_noraml_api(ui_s->jpg_normal_msi);
}
}
}
// 进入预览的ui,那么就要创建新的ui去显示预览图了
static void enter_takephoto_ui(lv_event_t *e)
{
struct takephoto_ui_s *ui_s = (struct takephoto_ui_s *) lv_event_get_user_data(e);
lv_obj_add_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_t *ui = lv_obj_create(lv_scr_act());
ui_s->now_ui = ui;
lv_obj_add_style(ui, &g_style, 0);
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
// 绑定流到Video_P0,Video_P1显示
ui_s->s = scale3_normal_msi2(S_PREVIEW_SCALE3, FSTYPE_YUV_P0, ui_s->w, ui_s->h);
if (ui_s->s)
{
msi_do_cmd(ui_s->s, MSI_CMD_SCALE3_NORMAL, MSI_SCALE3_START, 0x01);
msi_add_output(ui_s->s, NULL, R_VIDEO_P0);
msi_add_output(ui_s->s, NULL, R_VIDEO_P1);
msi_cmd(R_VIDEO_P0, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
msi_cmd(R_VIDEO_P1, MSI_CMD_LCD_VIDEO, MSI_VIDEO_ENABLE, 1);
ui_s->over_dpi_msi = msi_find(SR_OVER_DPI_JPG, 1);
if (ui_s->over_dpi_msi)
{
msi_add_output(ui_s->s, NULL, ui_s->over_dpi_msi->name);
}
ui_s->thumb_msi = msi_find(SR_OVER_DPI_THUMB_JPG, 1);
if (ui_s->thumb_msi)
{
msi_add_output(ui_s->s, NULL, ui_s->thumb_msi->name);
}
ui_s->jpg_normal_msi = msi_find(R_JPG_THUMB, 1);
ui_s->s->enable = 1;
}
ui_s->scale1_jpg_recode_msi = msi_find(R_SCALE1_JPG_RECODE, 1);
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_group_add_obj(group, ui);
ui_s->now_group = group;
lv_obj_add_event_cb(ui, exit_takephoto_ui, LV_EVENT_LONG_PRESSED, ui_s);
lv_obj_add_event_cb(ui, takephoto_action, LV_EVENT_SHORT_CLICKED, ui_s);
}
lv_obj_t *takephoto_ui(lv_group_t *group, lv_obj_t *base_ui, uint16_t w, uint16_t h)
{
struct takephoto_ui_s *ui_s = (struct takephoto_ui_s *) STREAM_LIBC_ZALLOC(sizeof(struct takephoto_ui_s));
ui_s->last_group = group;
ui_s->base_ui = base_ui;
ui_s->w = w;
ui_s->h = h;
lv_obj_t *btn = lv_list_add_btn(base_ui, NULL, "takephoto");
lv_group_add_obj(group, btn);
lv_obj_add_event_cb(btn, enter_takephoto_ui, LV_EVENT_SHORT_CLICKED, ui_s);
return btn;
}

View File

@@ -0,0 +1,111 @@
#include "lvgl/lvgl.h"
#include "lvgl_ui.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
//data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
//结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
extern lv_indev_t * indev_keypad;
extern lv_style_t g_style;
struct touch_pad_test_ui_s
{
lv_group_t *last_group;
lv_obj_t *base_ui;
lv_group_t *now_group;
lv_obj_t *now_label;
lv_obj_t *now_label2;
lv_obj_t *now_btn;
lv_obj_t *now_btn2;
lv_obj_t *now_ui;
};
static void btn_event_cb(lv_event_t* e) {
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t* btn = lv_event_get_target(e);
if (code == LV_EVENT_CLICKED) {
static uint8_t cnt = 0;
cnt++;
lv_obj_t* label = lv_obj_get_child(btn, 0);
lv_label_set_text_fmt(label, "Button: %d", cnt);
}
}
static void exit_touch_pad_test_ui(lv_event_t* e) {
struct touch_pad_test_ui_s *ui_s = (struct touch_pad_test_ui_s *)lv_event_get_user_data(e);
lv_indev_set_group(indev_keypad, ui_s->last_group);
lv_obj_clear_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_del(ui_s->now_label);
lv_obj_del(ui_s->now_btn);
lv_obj_del(ui_s->now_label2);
lv_obj_del(ui_s->now_btn2);
lv_group_del(ui_s->now_group);
ui_s->now_group = NULL;
ui_s->now_label = NULL;
ui_s->now_btn = NULL;
ui_s->now_label2 = NULL;
ui_s->now_btn2 = NULL;
lv_obj_del(ui_s->now_ui);
}
static void enter_touch_pad_test_ui(lv_event_t* e) {
struct touch_pad_test_ui_s *ui_s = (struct touch_pad_test_ui_s *)lv_event_get_user_data(e);
lv_obj_add_flag(ui_s->base_ui, LV_OBJ_FLAG_HIDDEN);
lv_obj_t *ui = lv_obj_create(lv_scr_act());
ui_s->now_ui = ui;
lv_obj_set_size(ui, LV_PCT(100), LV_PCT(100));
lv_obj_t* btn = lv_btn_create(ui);
lv_obj_set_size(btn, 150, 50);
lv_obj_center(btn);
lv_obj_align(btn, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL);
ui_s->now_btn = btn;
lv_obj_t* btn2 = lv_btn_create(ui);
lv_obj_set_size(btn2, 50, 50);
lv_obj_center(btn2);
lv_obj_align(btn2, LV_ALIGN_TOP_RIGHT, 0, 0);
lv_obj_add_event_cb(btn2, exit_touch_pad_test_ui, LV_EVENT_PRESSED, ui_s);
ui_s->now_btn2 = btn2;
lv_obj_t* label = lv_label_create(btn);
lv_label_set_text(label, "Button");
lv_obj_center(label);
ui_s->now_label = label;
lv_obj_t* label2 = lv_label_create(btn2);
lv_label_set_text(label2, LV_SYMBOL_CLOSE);
lv_obj_center(label2);
ui_s->now_label2 = label2;
lv_group_t *group;
group = lv_group_create();
lv_indev_set_group(indev_keypad, group);
lv_group_add_obj(group, ui);
ui_s->now_group = group;
// lv_obj_add_event_cb(ui, exit_touch_pad_test_ui, LV_EVENT_PRESSED, ui_s);
}
lv_obj_t *touch_pad_test_ui(lv_group_t *group,lv_obj_t *base_ui)
{
struct touch_pad_test_ui_s *ui_s = (struct touch_pad_test_ui_s*)STREAM_LIBC_ZALLOC(sizeof(struct touch_pad_test_ui_s));
ui_s->last_group = group;
ui_s->base_ui = base_ui;
lv_obj_t *btn = lv_list_add_btn(base_ui, NULL, "touch_pad_test");
lv_group_add_obj(group, btn);
lv_obj_add_event_cb(btn, enter_touch_pad_test_ui, LV_EVENT_PRESSED, ui_s);
return btn;
}