340 lines
9.1 KiB
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
|
|
|
|
|