Files
TAIXIN/sdk/app/ui/mp4_player_ui.c

439 lines
13 KiB
C
Raw Normal View History

/***************************************************************************************
***************************************************************************************/
#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;
}