doubao_chat/apps/common/ui/ui_action_video.c

340 lines
9.1 KiB
C

#include "ui/ui.h"
#include "ui_api.h"
#include "ui_action_video.h"
#include "server/server_core.h"
#include "os/os_api.h"
#include "system/includes.h"
#include "app_config.h"
#include "storage_device.h"
#include "server/video_dec_server.h"
#include "video/video.h"
#include "yuv_to_rgb.h"
#ifdef CONFIG_UI_ENABLE
#if 1
#define log_info(x, ...) printf("\r\n[UI]" x " ", ## __VA_ARGS__)
#else
#define log_info(...)
#endif
struct video_data_type {
cbuffer_t cbuf;
u8 *cycle_buf;
u32 frame_size;
u8 *rgb_buf;
u8 *yoffset;
u8 *uoffset;
u8 *voffset;
u8 *wbuf;
u32 width;
u32 height;
OS_SEM sem;
};
struct video_dec_hdl {
#if 0
u8 status;
char curr_dir;
u8 file_type;
u8 ff_fr_times;
u8 need_move;
char *cur_path;
int wait;
int timer;
int timeout;
#endif
struct server *video_dec;
FILE *file;
u8 *audio_buf;
u8 *video_buf;
u32 lcd_size;
struct lcd_interface *lcd_hdl;
struct video_data_type video_data;
u8 dec_end_flag;
};
#define AUDIO_DEC_BUF_SIZE (50 * 1024)
#define VIDEO_DEC_BUF_SIZE (200 * 1024)
/* #define UI_VIDEO_TEST */
static struct video_dec_hdl dec_hdl;
static void vdec_server_event_handler(void *priv, int argc, int *argv)
{
struct video_dec_hdl *dec_handler = (struct video_dec_hdl *)priv;
switch (argv[0]) {
case VIDEO_DEC_EVENT_CURR_TIME:
/* 发送当前播放时间给UI */
log_info("play time = %ds.\n", argv[1]);
break;
case VIDEO_DEC_EVENT_END:
log_info("video dec end\n");
dec_handler->dec_end_flag = 1;
os_sem_post(&dec_handler->video_data.sem);
break;
case VIDEO_DEC_EVENT_ERR:
/* 解码出错,如果存储设备没有被拔出则播放前一个文件 */
log_info("video dec err\n");
break;
}
}
static int get_yuv_data(void *hdl, void *frame)
{
struct video_data_type *video_data = &dec_hdl.video_data;
struct YUV_frame_data *_frame = (struct YUV_frame_data *)frame;
u32 wlen;
u8 *wbuf;
u32 ysize = 0;
video_data->width = _frame->width;
video_data->height = _frame->height;
if (_frame->line_num == 0) {
video_data->yoffset = NULL;
video_data->uoffset = NULL;
video_data->voffset = NULL;
video_data->wbuf = NULL;
video_data->frame_size = _frame->width * _frame->height * 3 / 2;
wbuf = cbuf_write_alloc(&video_data->cbuf, &wlen);
if ((wlen >= video_data->frame_size) && wbuf) {
video_data->wbuf = wbuf;
video_data->yoffset = wbuf;
video_data->uoffset = wbuf + _frame->width * _frame->height;
video_data->voffset = wbuf + _frame->width * _frame->height + _frame->width * _frame->height / 4;
}
}
if (video_data->wbuf) {
ysize = _frame->width * _frame->data_height;
memcpy(video_data->yoffset, _frame->y, ysize);
memcpy(video_data->uoffset, _frame->u, ysize / 4);
memcpy(video_data->voffset, _frame->v, ysize / 4);
video_data->yoffset += ysize;
video_data->uoffset += ysize / 4;
video_data->voffset += ysize / 4;
if ((_frame->line_num + _frame->data_height) >= _frame->height) {
/* static int i = 0; */
/* log_info("frame = %d.\n", i++); */
cbuf_write_updata(&video_data->cbuf, video_data->frame_size);
os_sem_post(&video_data->sem);
video_data->wbuf = NULL;
}
}
return 0;
}
static void display_task(void *priv)
{
u8 *rbuf;
u32 rlen;
struct video_dec_hdl *dec_handler = (struct video_dec_hdl *)priv;
struct video_data_type *video_data = &dec_handler->video_data;
#ifdef UI_VIDEO_TEST
void *y_file;
void *r_file;
const char *y_file_path = "storage/sd0/C/test1.yuv";
const char *r_file_path = "storage/sd0/C/test2.rgb";
y_file = fopen(y_file_path, "w+");
if (!y_file) {
log_info("open y_file err\n");
return;
}
r_file = fopen(r_file_path, "w+");
if (!r_file) {
log_info("open r_file err\n");
return;
}
#endif
for (;;) {
os_sem_pend(&video_data->sem, 50);
if (dec_handler->dec_end_flag == 1) {
dec_handler->dec_end_flag = 0;
#ifdef UI_VIDEO_TEST
fclose(y_file);
fclose(r_file);
#endif
stop_play_video();
fclose(dec_handler->file);
dec_handler->file = NULL;
return;
}
rbuf = cbuf_read_alloc(&video_data->cbuf, &rlen);
if (rbuf && rlen) {
yuv420p_quto_rgb565(rbuf, video_data->rgb_buf, video_data->width, video_data->height, 1);
#ifdef UI_VIDEO_TEST
fwrite(y_file, rbuf, rlen);
fwrite(r_file, video_data->rgb_buf, dec_handler->lcd_size * 2);
#endif
/* log_info("start show_frame = %d.\n", i); */
dec_handler->lcd_hdl->draw(video_data->rgb_buf, dec_handler->lcd_size * 2, 1);
/* static int i = 0; */
/* log_info("end show_frame = %d.\n", i); */
/* i++; */
cbuf_read_updata(&video_data->cbuf, rlen);
}
}
}
static void free_video_memory(struct video_dec_hdl *dec_handler)
{
log_info("free_video_memory.\n");
free(dec_handler->video_data.rgb_buf);
free(dec_handler->video_data.cycle_buf);
free(dec_handler->audio_buf);
free(dec_handler->video_buf);
dec_handler->video_data.rgb_buf = NULL;
dec_handler->video_data.cycle_buf = NULL;
dec_handler->audio_buf = NULL;
dec_handler->video_buf = NULL;
}
static int malloc_video_memory(struct video_dec_hdl *dec_handler)
{
dec_handler->video_data.rgb_buf = malloc(dec_handler->lcd_size * 2);
dec_handler->video_data.cycle_buf = malloc(dec_handler->lcd_size * 3 / 2);
if ((!dec_handler->video_data.rgb_buf) || (!dec_handler->video_data.cycle_buf)) {
free_video_memory(dec_handler);
return -ENOMEM;
}
dec_handler->audio_buf = malloc(AUDIO_DEC_BUF_SIZE);
dec_handler->video_buf = malloc(VIDEO_DEC_BUF_SIZE);
if ((!dec_handler->audio_buf) || (!dec_handler->video_buf)) {
free_video_memory(dec_handler);
return -ENOMEM;
}
return 0;
}
int start_play_video(const char *path)
{
int err;
struct video_dec_arg arg = {0};
union video_dec_req req = {0};
struct lcd_info lcd_info = {0};
struct video_dec_hdl *dec_handler = &dec_hdl;
#ifdef UI_VIDEO_TEST
log_info("waiting sd to mount......\n");
while (!storage_device_ready());
#endif
log_info("avi decode start.\n");
memset(dec_handler, 0, sizeof(struct video_dec_hdl));
dec_handler->file = fopen(path, "r");
if (dec_handler->file == NULL) {
log_info("open avi file err\n");
return -EFAULT;
}
dec_handler->lcd_hdl = lcd_get_hdl();
ASSERT(dec_handler->lcd_hdl != NULL);
log_info("lcd_hdl get success.\n");
dec_handler->lcd_hdl->get_screen_info(&lcd_info);
dec_handler->lcd_hdl->set_draw_area(0, lcd_info.width - 1, 0, lcd_info.height - 1);
log_info("lcd size w = %d. h = %d.\n", lcd_info.width, lcd_info.height);
dec_handler->lcd_size = lcd_info.width * lcd_info.height;
if (malloc_video_memory(dec_handler) != 0) {
return -ENOMEM;
}
os_sem_create(&dec_handler->video_data.sem, 0);
cbuf_init(&dec_handler->video_data.cbuf, dec_handler->video_data.cycle_buf, dec_handler->lcd_size * 3 / 2);
arg.dev_name = "video_dec";
arg.audio_buf_size = AUDIO_DEC_BUF_SIZE;
arg.video_buf_size = VIDEO_DEC_BUF_SIZE;
arg.audio_buf = dec_handler->audio_buf;
arg.video_buf = dec_handler->video_buf;
dec_handler->video_dec = server_open("video_dec_server", &arg);
if (!dec_handler->video_dec) {
log_info("video_dec_server open fail\n");
free_video_memory(dec_handler);
return -EFAULT;
}
server_register_event_handler(dec_handler->video_dec, dec_handler, vdec_server_event_handler);
req.dec.preview = 0;
req.dec.volume = 100;
req.dec.get_yuv = get_yuv_data;
req.dec.file = dec_handler->file;
err = server_request(dec_handler->video_dec, VIDEO_REQ_DEC_START, &req);
if (err) {
log_info("start dec err = %d.\n", err);
server_close(dec_handler->video_dec);
dec_handler->video_dec = NULL;
free_video_memory(dec_handler);
return -EFAULT;
}
log_info("start dec succ\n");
return thread_fork("display_task", 20, 1024, 0, NULL, display_task, dec_handler);
}
int stop_play_video(void)
{
struct video_dec_hdl *dec_handler = &dec_hdl;
int err = -1;
if (dec_handler->video_dec) {
err = server_request(dec_handler->video_dec, VIDEO_REQ_DEC_STOP, NULL);
log_info("server close.\n");
server_close(dec_handler->video_dec);
dec_handler->video_dec = NULL;
free_video_memory(dec_handler);
}
return err;
}
int pause_play_video(void)
{
struct video_dec_hdl *dec_handler = &dec_hdl;
int err = -1;
if (dec_handler->video_dec) {
err = server_request(dec_handler->video_dec, VIDEO_REQ_DEC_PLAY_PAUSE, NULL);
}
return err;
}
void ui_server_init(void)
{
/* ui_init(&ui_cfg_data); */
extern const struct ui_devices_cfg ui_cfg_data;
lcd_ui_init(&ui_cfg_data);
}
#endif