809 lines
21 KiB
C
809 lines
21 KiB
C
#include "app_config.h"
|
|
#include "system/includes.h"
|
|
#include "device/device.h"
|
|
#include "lcd_drive.h"
|
|
#include "os/os_api.h"
|
|
#include "asm/includes.h"
|
|
#include "system/timer.h"
|
|
#include "sys_common.h"
|
|
#include "system/includes.h"
|
|
#include "simple_avi_unpkg.h"
|
|
#include "server/server_core.h"
|
|
#include "server/audio_server.h"
|
|
#include "server/video_dec_server.h"
|
|
#include "lcd_config.h"
|
|
#include "yuv_soft_scalling.h"
|
|
#include "storage_device.h"
|
|
|
|
|
|
#if 1
|
|
#define log_info(x, ...) printf("[AVI_PLAY][INFO] " x " ", ## __VA_ARGS__)
|
|
#define log_err(x, ...) printf("[AVI_PLAY][ERR] " x " ", ## __VA_ARGS__)
|
|
#else
|
|
#define log_info(...)
|
|
#define log_err(...)
|
|
#endif
|
|
|
|
#define TIMER_BASE (2)
|
|
#define AVI_OFFSET_THR (50)
|
|
|
|
enum {
|
|
MSG_VIDS_UPDATE,
|
|
MSG_VIDS_EXIT,
|
|
};
|
|
|
|
|
|
enum replay_speed_type {
|
|
REPLAY_SPEED_1X = 1,
|
|
REPLAY_SPEED_2X,
|
|
REPLAY_SPEED_3X,
|
|
REPLAY_SPEED_4X,
|
|
REPLAY_SPEED_0_5X,
|
|
REPLAY_SPEED_0_25X,
|
|
};
|
|
|
|
|
|
enum replay_status_type {
|
|
RE_ST_NULL = 0,
|
|
RE_ST_START,
|
|
RE_ST_EXIT,
|
|
RE_ST_PAUSE,
|
|
};
|
|
|
|
struct avi_hdl {
|
|
FILE *fd;
|
|
int play_time;
|
|
char *jpg_buf;
|
|
char *yuv_buf;
|
|
char *scale_buf;
|
|
char *rgb_buf;
|
|
u8 vids_drop;
|
|
u8 vids_exit;
|
|
u8 vids_busy;
|
|
u16 vids_inr;
|
|
int vids_idx;
|
|
int vids_total;
|
|
u8 auds_vol;
|
|
u8 auds_drop;
|
|
int auds_idx;
|
|
u8 auds_exit;
|
|
u16 auds_inr;
|
|
int auds_rate;
|
|
int auds_total;
|
|
char *auds_data;
|
|
char *auds_frame;
|
|
cbuffer_t auds_cbuf;
|
|
u8 dec_status;
|
|
struct server *dec_server;
|
|
int sync_timer;
|
|
OS_MUTEX mutex;
|
|
OS_SEM auds_rsem;
|
|
enum replay_speed_type speed;
|
|
enum replay_status_type status;
|
|
};
|
|
|
|
|
|
static struct avi_hdl hdl = {0};
|
|
#define __this (&hdl)
|
|
|
|
#define AUDS_CBUF_LEN (10 * 1024)
|
|
#define AUDS_FRAME_LEN (1 * 1024)
|
|
|
|
#define DEC_JPG_LEN 100*1024
|
|
#define IDX_00DC ntohl(0x30306463)
|
|
#define IDX_01WB ntohl(0x30317762)
|
|
#define IDX_00WB ntohl(0x30307762)
|
|
|
|
|
|
static void video_decode(char *buf, int buf_len)
|
|
{
|
|
int pix;
|
|
int ytype;
|
|
int yuv_len;
|
|
char *cy, *cb, *cr;
|
|
struct jpeg_decode_req req = {0};
|
|
struct jpeg_image_info info = {0};
|
|
|
|
info.input.data.buf = buf;
|
|
info.input.data.len = buf_len;
|
|
|
|
if (jpeg_decode_image_info(&info)) {
|
|
log_err("jpeg_decode_image_info err\n");
|
|
return;
|
|
}
|
|
|
|
switch (info.sample_fmt) {
|
|
case JPG_SAMP_FMT_YUV444:
|
|
ytype = 1;
|
|
break;//444
|
|
|
|
case JPG_SAMP_FMT_YUV420:
|
|
ytype = 4;
|
|
break;//420
|
|
|
|
default:
|
|
ytype = 2;
|
|
break;
|
|
}
|
|
|
|
pix = info.width * info.height;
|
|
yuv_len = pix + pix / ytype * 2;
|
|
//log_info("ytype = %d, width = %d , height = %d\n", ytype, info.width, info.height);
|
|
|
|
if (!__this->yuv_buf) {
|
|
if (!(__this->yuv_buf = malloc(yuv_len))) {
|
|
log_err("yuv_buf malloc error, size = %d\n", yuv_len);
|
|
return;
|
|
}
|
|
}
|
|
|
|
cy = __this->yuv_buf;
|
|
cb = cy + pix;
|
|
cr = cb + pix / ytype;
|
|
|
|
req.input_type = JPEG_INPUT_TYPE_DATA;
|
|
req.input.data.buf = info.input.data.buf;
|
|
req.input.data.len = info.input.data.len;
|
|
req.buf_y = cy;
|
|
req.buf_u = cb;
|
|
req.buf_v = cr;
|
|
req.buf_width = info.width;
|
|
req.buf_height = info.height;
|
|
req.out_width = info.width;
|
|
req.out_height = info.height;
|
|
req.output_type = JPEG_DECODE_TYPE_DEFAULT;
|
|
req.bits_mode = BITS_MODE_UNCACHE;
|
|
req.dec_query_mode = TRUE;
|
|
|
|
if (jpeg_decode_one_image(&req)) {
|
|
log_err("jpeg decode error\n");
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
if (!__this->scale_buf) {
|
|
if (!(__this->scale_buf = malloc(LCD_H * LCD_W * (1 + 1 / ytype * 2)))) {
|
|
log_err("scale_buf malloc error, size = %d\n", LCD_H * LCD_W * (1 + 1 / ytype * 2));
|
|
return;
|
|
}
|
|
}
|
|
|
|
YUV420p_Soft_Scaling(__this->yuv_buf, __this->scale_buf, info.width, info.height, LCD_W, LCD_H);
|
|
lcd_show_frame(__this->scale_buf, info.width * info.height * 3 / 2, info.width, info.height);
|
|
#else
|
|
lcd_show_frame(__this->yuv_buf, info.width * info.height * 3 / 2, info.width, info.height);
|
|
#endif
|
|
}
|
|
|
|
|
|
static int audio_vfs_fread(void *priv, void *data, u32 len)
|
|
{
|
|
int rlen = 0, ret;
|
|
int read_len, recv_len, remain_len;
|
|
|
|
if (__this->status == RE_ST_EXIT) {
|
|
return 0;
|
|
}
|
|
|
|
os_sem_pend(&__this->auds_rsem, 0);
|
|
//putchar(')');
|
|
if (cbuf_get_data_size(&__this->auds_cbuf)) {
|
|
rlen = cbuf_read(&__this->auds_cbuf, data, len);
|
|
}
|
|
return len;
|
|
}
|
|
|
|
|
|
static const struct audio_vfs_ops audio_vfs_ops = {
|
|
.fread = audio_vfs_fread,
|
|
};
|
|
|
|
|
|
static int open_audio_dec(void)
|
|
{
|
|
union audio_req req = {0};
|
|
|
|
req.dec.output_buf = NULL;
|
|
req.dec.volume = __this->auds_vol;
|
|
req.dec.output_buf_len = AUDS_CBUF_LEN;
|
|
req.dec.channel = 1;
|
|
req.dec.sample_rate = __this->auds_rate;
|
|
req.dec.priority = 1;
|
|
req.dec.vfs_ops = &audio_vfs_ops;
|
|
req.dec.file = (FILE *)__this;
|
|
req.dec.dec_type = "pcm";
|
|
req.dec.sample_source = "dac";
|
|
if (server_request(__this->dec_server, AUDIO_REQ_DEC, &req) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
req.dec.cmd = AUDIO_DEC_START;
|
|
if (server_request(__this->dec_server, AUDIO_REQ_DEC, &req) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int close_audio_dec(void)
|
|
{
|
|
union audio_req req = {0};
|
|
|
|
if (__this->dec_server) {
|
|
req.dec.cmd = AUDIO_DEC_STOP;
|
|
server_request(__this->dec_server, AUDIO_REQ_DEC, &req);
|
|
server_close(__this->dec_server);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void audio_replay_task(void *priv)
|
|
{
|
|
u8 empty = 0;
|
|
int frame_len, msg[2];
|
|
|
|
for (;;) {
|
|
if (os_taskq_pend(NULL, msg, ARRAY_SIZE(msg)) != OS_TASKQ) {
|
|
continue;
|
|
}
|
|
|
|
switch (msg[0]) {
|
|
case MSG_VIDS_UPDATE:
|
|
//putchar('}');
|
|
break;
|
|
|
|
case MSG_VIDS_EXIT:
|
|
__this->auds_exit = 1;
|
|
return;
|
|
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
os_mutex_pend(&__this->mutex, 0);
|
|
if ((frame_len = avi_audio_get_frame(__this->fd, msg[1], (u8 *)__this->auds_frame, AUDS_FRAME_LEN, 1)) <= 0) {
|
|
log_err("get audio frame error\n");
|
|
__this->vids_exit = 1;
|
|
os_mutex_post(&__this->mutex);
|
|
return;
|
|
}
|
|
os_mutex_post(&__this->mutex);
|
|
|
|
_audio_retry_:
|
|
if (cbuf_write(&__this->auds_cbuf, __this->auds_frame, frame_len) > 0) {
|
|
os_sem_set(&__this->auds_rsem, 0);
|
|
os_sem_post(&__this->auds_rsem);
|
|
//putchar('(');
|
|
|
|
if (!__this->dec_status) {
|
|
__this->dec_status = 1;
|
|
open_audio_dec();
|
|
}
|
|
} else {
|
|
os_time_dly(2);
|
|
//putchar('R');
|
|
goto _audio_retry_;
|
|
}
|
|
|
|
if (msg[1] == __this->auds_total) {
|
|
__this->auds_exit = 1;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void video_replay_task(void *priv)
|
|
{
|
|
int frame_len, msg[2];
|
|
|
|
for (;;) {
|
|
if (os_taskq_pend(NULL, msg, ARRAY_SIZE(msg)) != OS_TASKQ) {
|
|
continue;
|
|
}
|
|
|
|
switch (msg[0]) {
|
|
case MSG_VIDS_UPDATE:
|
|
//putchar('>');
|
|
break;
|
|
|
|
case MSG_VIDS_EXIT:
|
|
__this->vids_exit = 1;
|
|
return;
|
|
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
os_mutex_pend(&__this->mutex, 0);
|
|
if ((frame_len = avi_video_get_frame(__this->fd, msg[1], (u8 *)__this->jpg_buf, DEC_JPG_LEN, 1)) <= 0) {
|
|
log_err("get video frame error\n");
|
|
__this->vids_exit = 1;
|
|
os_mutex_post(&__this->mutex);
|
|
return;
|
|
}
|
|
os_mutex_post(&__this->mutex);
|
|
|
|
if (*(u32 *)__this->jpg_buf == IDX_00DC || *(u32 *)__this->jpg_buf == IDX_01WB || *(u32 *)__this->jpg_buf == IDX_00WB) {
|
|
frame_len -= 8;
|
|
__this->jpg_buf += 8;
|
|
}
|
|
|
|
video_decode(__this->jpg_buf, frame_len);
|
|
|
|
__this->vids_busy = 0;
|
|
|
|
if (msg[1] == __this->vids_total) {
|
|
__this->vids_exit = 1;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void sync_timer_hdl(void *priv)
|
|
{
|
|
int offset;
|
|
static u32 time = 0, vids_time = 0, auds_time = 0, time_last = 0;
|
|
|
|
if (__this->auds_exit && __this->vids_exit) {
|
|
__this->status = RE_ST_EXIT;
|
|
os_sem_set(&__this->auds_rsem, 0);
|
|
os_sem_post(&__this->auds_rsem);
|
|
|
|
close_audio_dec();
|
|
free(__this->auds_data);
|
|
free(__this->auds_frame);
|
|
os_sem_del(&__this->auds_rsem, 0);
|
|
|
|
free(__this->jpg_buf);
|
|
free(__this->yuv_buf);
|
|
if (__this->scale_buf) {
|
|
free(__this->scale_buf);
|
|
}
|
|
|
|
avi_unpkg_exit(__this->fd, 1);
|
|
fclose(__this->fd);
|
|
|
|
sys_timer_del(__this->sync_timer);
|
|
|
|
memset(__this, 0, sizeof(struct avi_hdl));
|
|
log_info("STEP -> VIDEO COMPLETE\n");
|
|
return;
|
|
}
|
|
|
|
switch (__this->status) {
|
|
case RE_ST_NULL:
|
|
return;
|
|
case RE_ST_START:
|
|
break;
|
|
case RE_ST_EXIT:
|
|
break;
|
|
case RE_ST_PAUSE:
|
|
return;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
offset = (__this->auds_idx * __this->auds_inr) - (__this->vids_idx * __this->vids_inr);
|
|
//if (offset >= AVI_OFFSET_THR) {
|
|
// log_info("vids_drop = %d, offset = %d\n", offset / __this->vids_inr, offset);
|
|
//}
|
|
|
|
if ((time - vids_time >= __this->vids_inr && !__this->vids_busy) || !time) {
|
|
vids_time = time;
|
|
if (__this->speed == REPLAY_SPEED_0_5X || __this->speed == REPLAY_SPEED_0_25X) {
|
|
__this->vids_idx += __this->vids_drop;
|
|
__this->vids_idx = (__this->vids_idx > __this->vids_total) ? __this->vids_total : __this->vids_idx;
|
|
__this->vids_busy = 1;
|
|
//putchar('<');
|
|
if (os_taskq_post_type("video_replay_task", MSG_VIDS_UPDATE, 1, &__this->vids_idx) != OS_NO_ERR) {
|
|
log_err("update vids error\n");
|
|
}
|
|
} else {
|
|
if (offset) {
|
|
__this->vids_idx += offset >= AVI_OFFSET_THR ? (offset / __this->vids_inr) : __this->vids_drop;
|
|
__this->vids_idx = (__this->vids_idx > __this->vids_total) ? __this->vids_total : __this->vids_idx;
|
|
__this->vids_busy = 1;
|
|
//putchar('<');
|
|
if (os_taskq_post_type("video_replay_task", MSG_VIDS_UPDATE, 1, &__this->vids_idx) != OS_NO_ERR) {
|
|
//log_err("update vids error\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((time - auds_time >= __this->auds_inr) || !time) {
|
|
auds_time = time;
|
|
if (__this->speed == REPLAY_SPEED_0_5X || __this->speed == REPLAY_SPEED_0_25X) {
|
|
if (offset < 0) {
|
|
__this->auds_idx += fabs(offset) >= AVI_OFFSET_THR ? (fabs(offset) / __this->auds_inr) : __this->auds_drop;
|
|
__this->auds_idx = (__this->auds_idx > __this->auds_total) ? __this->auds_total : __this->auds_idx;
|
|
//putchar('{');
|
|
if (os_taskq_post_type("audio_replay_task", MSG_VIDS_UPDATE, 1, &__this->auds_idx) != OS_NO_ERR) {
|
|
//log_err("update auds error\n");
|
|
__this->auds_idx -= __this->auds_drop;
|
|
}
|
|
} else {
|
|
|
|
}
|
|
} else {
|
|
__this->auds_idx += __this->auds_drop;
|
|
__this->auds_idx = (__this->auds_idx > __this->auds_total) ? __this->auds_total : __this->auds_idx;
|
|
//putchar('{');
|
|
if (os_taskq_post_type("audio_replay_task", MSG_VIDS_UPDATE, 1, &__this->auds_idx) != OS_NO_ERR) {
|
|
//log_err("update auds error\n");
|
|
__this->auds_idx -= __this->auds_drop;
|
|
}
|
|
}
|
|
}
|
|
|
|
time += TIMER_BASE;
|
|
|
|
if (time - time_last >= 1000) {
|
|
time_last = time;
|
|
log_info("time = %d, vids = %d / %d, auds = %d / %d\n", time, __this->vids_idx, __this->vids_idx * __this->vids_inr, __this->auds_idx, __this->auds_idx * __this->auds_inr);
|
|
}
|
|
}
|
|
|
|
|
|
char avi_replay_start(char *path)
|
|
{
|
|
if (!path) {
|
|
log_err("%s path error\n");
|
|
return -1;
|
|
}
|
|
|
|
if (__this->status != RE_ST_NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (!(__this->fd = fopen(path, "r"))) {
|
|
log_err("%s open error\n", path);
|
|
return -1;
|
|
}
|
|
|
|
if (avi_playback_unpkg_init(__this->fd, 1)) {
|
|
log_err("avi_playback_unpkg_init error\n");
|
|
return -1;
|
|
}
|
|
|
|
__this->jpg_buf = (char *)calloc(1, DEC_JPG_LEN);
|
|
__this->auds_data = (char *)calloc(1, AUDS_CBUF_LEN);
|
|
__this->auds_frame = (char *)calloc(1, AUDS_FRAME_LEN);
|
|
ASSERT(__this->auds_data || __this->auds_frame || __this->jpg_buf);
|
|
|
|
cbuf_init(&__this->auds_cbuf, __this->auds_data, AUDS_CBUF_LEN);
|
|
|
|
__this->auds_drop = 1;
|
|
__this->vids_drop = 1;
|
|
__this->auds_vol = 50;
|
|
__this->play_time = avi_get_file_time(__this->fd, 1);
|
|
__this->auds_total = avi_get_audio_chunk_num(__this->fd, 1);
|
|
__this->vids_total = avi_get_video_chunk_num(__this->fd, 1);
|
|
__this->auds_rate = avi_get_audio_sample_rate(__this->fd, 1);
|
|
__this->vids_inr = (__this->play_time * 1000) / __this->vids_total;
|
|
__this->auds_inr = (__this->play_time * 1000) / __this->auds_total;
|
|
|
|
__this->dec_server = server_open("audio_server", "dec");
|
|
if (!__this->dec_server) {
|
|
return -1;
|
|
}
|
|
|
|
log_info("total_time = %d, vids_num = %d, auds_num = %d, vids_inr = %d, auds_inr = %d, auds_rate = %d\n", __this->play_time, __this->vids_total, __this->auds_total, __this->vids_inr, __this->auds_inr, __this->auds_rate);
|
|
|
|
os_mutex_create(&__this->mutex);
|
|
os_sem_create(&__this->auds_rsem, 0);
|
|
thread_fork("audio_replay_task", 11, 1024, 1024, 0, audio_replay_task, NULL);
|
|
thread_fork("video_replay_task", 11, 1024, 256, 0, video_replay_task, NULL);
|
|
|
|
__this->status = RE_ST_START;
|
|
__this->sync_timer = sys_timer_add(NULL, sync_timer_hdl, TIMER_BASE);
|
|
|
|
log_info("STEP -> START\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
char avi_replay_exit(void)
|
|
{
|
|
if (__this->status == RE_ST_NULL || __this->status == RE_ST_EXIT) {
|
|
return -1;
|
|
}
|
|
if (os_taskq_post_type("audio_replay_task", MSG_VIDS_EXIT, 0, NULL) != OS_NO_ERR) {
|
|
log_err("exit auds error\n");
|
|
return -1;
|
|
}
|
|
|
|
if (os_taskq_post_type("video_replay_task", MSG_VIDS_EXIT, 0, NULL) != OS_NO_ERR) {
|
|
log_err("exit vids error\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
char avi_replay_pause(u8 pause)
|
|
{
|
|
if (__this->status == RE_ST_START || __this->status == RE_ST_PAUSE) {
|
|
__this->status = pause ? RE_ST_PAUSE : RE_ST_START;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
char avi_replay_change_speed(enum replay_speed_type speed)
|
|
{
|
|
char *speed_str[] = {
|
|
"",
|
|
"REPLAY_SPEED_1X",
|
|
"REPLAY_SPEED_2X",
|
|
"REPLAY_SPEED_3X",
|
|
"REPLAY_SPEED_4X",
|
|
"REPLAY_SPEED_0_5X",
|
|
"REPLAY_SPEED_0_25X",
|
|
};
|
|
|
|
if (!(__this->status == RE_ST_START || __this->status == RE_ST_PAUSE)) {
|
|
return -1;
|
|
}
|
|
|
|
switch (speed) {
|
|
case REPLAY_SPEED_1X:
|
|
case REPLAY_SPEED_2X:
|
|
case REPLAY_SPEED_3X:
|
|
case REPLAY_SPEED_4X:
|
|
__this->auds_drop = speed;
|
|
__this->auds_inr = (__this->play_time * 1000 * 1) / __this->auds_total;
|
|
__this->vids_drop = 1;
|
|
__this->vids_inr = (__this->play_time * 1000 * 1) / __this->vids_total;
|
|
break;
|
|
|
|
case REPLAY_SPEED_0_5X:
|
|
__this->auds_drop = 1;
|
|
__this->auds_inr = (__this->play_time * 1000 * 2) / __this->auds_total;
|
|
__this->vids_drop = 1;
|
|
__this->vids_inr = (__this->play_time * 1000 * 2) / __this->vids_total;
|
|
break;
|
|
|
|
case REPLAY_SPEED_0_25X:
|
|
__this->auds_drop = 1;
|
|
__this->auds_inr = (__this->play_time * 1000 * 4) / __this->auds_total;
|
|
__this->vids_drop = 1;
|
|
__this->vids_inr = (__this->play_time * 1000 * 4) / __this->vids_total;
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
__this->speed = speed;
|
|
|
|
log_info("CHANTE_SPEED : %s, auds_inr = %d, auds_drop = %d\n", speed_str[speed], __this->auds_inr, __this->auds_drop);
|
|
return 0;
|
|
}
|
|
|
|
|
|
char avi_get_litimg(char *path, int idx, u8 *data, int *len, int width, int height)
|
|
{
|
|
FILE *fd;
|
|
int pix;
|
|
int ytype;
|
|
int jpg_len, yuv_len;
|
|
char *cy, *cb, *cr;
|
|
struct jpeg_decode_req req = {0};
|
|
struct jpeg_image_info info = {0};
|
|
u8 *jpg_data, *yuv_data;
|
|
|
|
if (!path || !data) {
|
|
log_err("params error\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!(fd = fopen(path, "r"))) {
|
|
log_err("%s open error\n", path);
|
|
return -1;
|
|
}
|
|
|
|
if (avi_playback_unpkg_init(fd, 1)) {
|
|
log_err("avi_playback_unpkg_init error\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!(jpg_data = malloc(DEC_JPG_LEN))) {
|
|
log_err("jpg_data malloc error, size = %d\n", DEC_JPG_LEN);
|
|
return -1;
|
|
}
|
|
|
|
jpg_len = avi_video_get_frame(fd, idx, jpg_data, DEC_JPG_LEN, 1);
|
|
avi_unpkg_exit(fd, 1);
|
|
fclose(fd);
|
|
|
|
info.input.data.buf = jpg_data;
|
|
info.input.data.len = jpg_len;
|
|
if (jpeg_decode_image_info(&info)) {
|
|
log_err("jpeg_decode_image_info err\n");
|
|
return -1;
|
|
}
|
|
|
|
switch (info.sample_fmt) {
|
|
case JPG_SAMP_FMT_YUV444:
|
|
ytype = 1;
|
|
break;//444
|
|
|
|
case JPG_SAMP_FMT_YUV420:
|
|
ytype = 4;
|
|
break;//420
|
|
|
|
default:
|
|
ytype = 2;
|
|
break;
|
|
}
|
|
|
|
pix = info.width * info.height;
|
|
yuv_len = pix + pix / ytype * 2;
|
|
|
|
if (!(yuv_data = malloc(yuv_len))) {
|
|
log_err("yuv_data malloc error, size = %d\n", yuv_len);
|
|
return -1;
|
|
}
|
|
|
|
cy = yuv_data;
|
|
cb = cy + pix;
|
|
cr = cb + pix / ytype;
|
|
|
|
req.input_type = JPEG_INPUT_TYPE_DATA;
|
|
req.input.data.buf = info.input.data.buf;
|
|
req.input.data.len = info.input.data.len;
|
|
req.buf_y = cy;
|
|
req.buf_u = cb;
|
|
req.buf_v = cr;
|
|
req.buf_width = info.width;
|
|
req.buf_height = info.height;
|
|
req.out_width = info.width;
|
|
req.out_height = info.height;
|
|
req.output_type = JPEG_DECODE_TYPE_DEFAULT;
|
|
req.bits_mode = BITS_MODE_UNCACHE;
|
|
req.dec_query_mode = TRUE;
|
|
|
|
if (jpeg_decode_one_image(&req)) {
|
|
log_err("jpeg decode error\n");
|
|
return -1;
|
|
}
|
|
|
|
YUV420p_Soft_Scaling(yuv_data, data, info.width, info.height, width, height);
|
|
|
|
pix = width * height;
|
|
*len = pix + pix / ytype * 2;
|
|
printf("len = %d\n", *len);
|
|
|
|
free(jpg_data);
|
|
free(yuv_data);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "demo_config.h"
|
|
#ifdef AVI_REPLAY_DEMO
|
|
|
|
#include "event/device_event.h"
|
|
#include "event/key_event.h"
|
|
|
|
static void avi_litimg_show_task(void *priv)
|
|
{
|
|
int len;
|
|
FILE *fd;
|
|
u8 *data = malloc(LCD_W * LCD_H * 2);
|
|
|
|
avi_get_litimg("storage/sd0/C/SJ.avi", 1, data, &len, LCD_W, LCD_H);
|
|
if (fd = fopen("storage/sd0/C/litimg.yuv", "w+")) {
|
|
fwrite(data, len, 1, fd);
|
|
}
|
|
fclose(fd);
|
|
lcd_show_frame(data, len, LCD_W, LCD_H);
|
|
free(data);
|
|
}
|
|
|
|
|
|
static int key_event_handler(struct sys_event *event)
|
|
{
|
|
enum replay_speed_type speed;
|
|
static u32 k2_cnt = 0, k4_cnt = 0, k5_cnt = 0;
|
|
struct key_event *key = (struct key_event *)event->payload;
|
|
|
|
if (event->type == SYS_KEY_EVENT) {
|
|
printf("key : value = %d, action = %d", key->value, key->action);
|
|
if (key->action == KEY_EVENT_CLICK) {
|
|
switch (key->value) {
|
|
case 13://K1
|
|
avi_replay_start("storage/sd0/C/SJ.avi");
|
|
break;
|
|
|
|
case 6://K2
|
|
k2_cnt++;
|
|
avi_replay_pause(k2_cnt % 2);
|
|
break;
|
|
|
|
case 4://K3
|
|
avi_replay_exit();
|
|
break;
|
|
|
|
case 5://K4
|
|
k4_cnt++;
|
|
log_info("k4_cnt = %d, k4_cnt/4 = %d\n", k4_cnt, k4_cnt % 4);
|
|
switch (k4_cnt % 4) {
|
|
case 0:
|
|
speed = REPLAY_SPEED_1X;
|
|
break;
|
|
case 1:
|
|
speed = REPLAY_SPEED_2X;
|
|
break;
|
|
case 2:
|
|
speed = REPLAY_SPEED_3X;
|
|
break;
|
|
case 3:
|
|
speed = REPLAY_SPEED_4X;
|
|
break;
|
|
default:
|
|
speed = REPLAY_SPEED_1X;
|
|
break;
|
|
}
|
|
avi_replay_change_speed(speed);
|
|
break;
|
|
|
|
case 12://K5
|
|
k5_cnt++;
|
|
log_info("k5_cnt = %d, k5_cnt/3 = %d\n", k5_cnt, k5_cnt % 3);
|
|
switch (k5_cnt % 3) {
|
|
case 0:
|
|
speed = REPLAY_SPEED_1X;
|
|
break;
|
|
case 1:
|
|
speed = REPLAY_SPEED_0_5X;
|
|
break;
|
|
case 2:
|
|
speed = REPLAY_SPEED_0_25X;
|
|
break;
|
|
default:
|
|
speed = REPLAY_SPEED_1X;
|
|
break;
|
|
}
|
|
avi_replay_change_speed(speed);
|
|
break;
|
|
|
|
case 10://K6
|
|
thread_fork("avi_litimg_show_task", 6, 1024, 0, NULL, avi_litimg_show_task, NULL);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void avi_replay_test(void)
|
|
{
|
|
user_ui_lcd_init();
|
|
set_lcd_show_data_mode(CAMERA);
|
|
register_sys_event_handler(SYS_KEY_EVENT, 0, 1, key_event_handler);
|
|
|
|
while (!storage_device_ready()) {
|
|
os_time_dly(10);
|
|
putchar('S');
|
|
}
|
|
}
|
|
late_initcall(avi_replay_test);
|
|
#endif
|
|
|
|
|