doubao_chat/apps/common/example/video/image/avi/main.c

424 lines
11 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"//YUV420p_Soft_Scaling
#include "storage_device.h"
//依赖文件 jpeg2yuv.c simple_avi_unpkg.c
#ifdef USE_SD_PLAY_AVI_DEMO //测试OK
#define AVI_ENTER_CRITICAL() \
spin_lock(&avi->lock)
#define AVI_EXIT_CRITICAL() \
spin_unlock(&avi->lock)
extern int jpeg2yuv_open(void);
extern void jpeg2yuv_yuv_callback_register(void (*cb)(u8 *data, u32 len, int width, int height));
extern int jpeg2yuv_jpeg_frame_write(u8 *buf, u32 len);
extern void jpeg2yuv_close(void);
struct avi_avi {
int jpg_num; //需要播放的JPG数量
int jpg_run_num;
int audio_num;
int audio_run_num;
int jpg_time_id;
int audio_time_id;
int play_time;
u8 avi_play_status;
char *jpg_buf;
char *audio_buf;
FILE *fd;
OS_SEM audio_run;
OS_SEM jpg_run;
struct server *dec_server; //解码服务
cbuffer_t cbuf; //音频数据cycle buffer
char *data_cbuf; //音频数据buffer
OS_SEM rd_sem; //写音频数据信号量
u8 dec_volume; //播放音量
u8 dec_status;
u8 audio_play_size;
char *yuv_buf;
spinlock_t lock; /*!< cbuffer硬件锁 */
u8 dec_ready_flag;
};
/*static struct avi_avi avi_play_handler;*/
#define AVI_PATH CONFIG_ROOT_PATH"bad.avi"
#define IDX_00DC ntohl(0x30306463)
#define IDX_01WB ntohl(0x30317762)
#define IDX_00WB ntohl(0x30307762)
#define DEC_JPG_LEN 50*1024
static void Calculation_frame(void)
{
static u32 tstart = 0, tdiff = 0;
static u8 fps_cnt = 0;
fps_cnt++ ;
if (!tstart) {
tstart = timer_get_ms();
} else {
tdiff = timer_get_ms() - tstart;
if (tdiff >= 1000) {
printf("\n [data_to_te]fps_count = %d\n", fps_cnt * 1000 / tdiff);
tstart = 0;
fps_cnt = 0;
}
}
}
/*************************音频播放部分*********************************/
#define CBUF_LEN 12 * 1024 //文件系统写数据比较快网络会被干扰所以这个buf可以小一点
#define DEC_AUDIO_LEN 1024
static int open_audio_dec(void *priv);
/****解码器会从CBUF里面取数取到数据就会有声音*****/
static int audio_vfs_fread(void *priv, void *data, u32 len)
{
int rlen = 0;
struct avi_avi *avi = (struct avi_avi *)priv;
if (cbuf_get_data_size(&avi->cbuf)) {
rlen = cbuf_read(&avi->cbuf, data, len);
} else {
rlen = 0;
}
return len;
}
static int audio_vfs_flen(void *priv)
{
struct avi_avi *avi = (struct avi_avi *)priv;
return avi->audio_play_size; //一定要告知解码器MP3格式的歌曲总长度 不然会报格式错误 导致播不出
}
static const struct audio_vfs_ops audio_vfs_ops = {
.fread = audio_vfs_fread,
.flen = audio_vfs_flen,
};
static int open_audio_dec(void *priv)
{
union audio_req req = {0};
struct avi_avi *avi = (struct avi_avi *)priv;
memset(&req, 0, sizeof(union audio_req));
avi->dec_volume = 40;
req.dec.output_buf = NULL;
req.dec.volume = avi->dec_volume;
req.dec.output_buf_len = CBUF_LEN;
req.dec.channel = 1;
req.dec.sample_rate = 16000;
req.dec.priority = 1;
req.dec.vfs_ops = &audio_vfs_ops;
req.dec.file = (FILE *)avi;
req.dec.dec_type = "pcm";
req.dec.sample_source = "dac";
//打开解码器
if (server_request(avi->dec_server, AUDIO_REQ_DEC, &req) != 0) {
return -1;
}
//开始解码
req.dec.cmd = AUDIO_DEC_START;
if (server_request(avi->dec_server, AUDIO_REQ_DEC, &req) != 0) {
return -1;
}
return 0;
}
static int close_audio_dec(void *priv)
{
union audio_req req = {0};
struct avi_avi *avi = (struct avi_avi *)priv;
req.dec.cmd = AUDIO_DEC_STOP;
if (avi->dec_server) {
//关闭解码器
printf("stop dec.\n");
server_request(avi->dec_server, AUDIO_REQ_DEC, &req);
//关闭解码服务
printf("close audio_server.\n");
server_close(avi->dec_server);
avi->dec_server = NULL;
}
return 0;
}
/*===========================endd=====================================*/
static void dec_jpg_to_yuv(void *priv, char *buf, int buf_len)
{
struct avi_avi *avi = (struct avi_avi *)priv;
struct jpeg_image_info info = {0};
struct jpeg_decode_req req = {0};
int pix;
int ytype;
int yuv_len;
char *cy, *cb, *cr;
info.input.data.buf = buf;
info.input.data.len = buf_len;
if (jpeg_decode_image_info(&info)) { //获取JPEG图片信息
printf("jpeg_decode_image_info err\n");
/*break;*/
} else {
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;
}
pix = info.width * info.height;
yuv_len = pix + pix / ytype * 2;
if (!avi->yuv_buf) {
avi->yuv_buf = malloc(yuv_len);
if (!avi->yuv_buf) {
printf("avi->yuv_buf malloc err len : %d , width : %d , height : %d \n", yuv_len, info.width, info.height);
/*break;*/
}
}
/*printf("width : %d , height : %d \n", info.width, info.height);*/
cy = avi->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;
int ret = jpeg_decode_one_image(&req);//JPEG转YUV解码
if (ret) {
printf("jpeg decode err !!\n");
/*break;*/
}
lcd_show_frame(avi->yuv_buf, info.width * info.height * 3 / 2, info.width, info.height);
Calculation_frame();
}
}
static void audio_play(void *priv)
{
struct avi_avi *avi = (struct avi_avi *)priv;
os_sem_post(&avi->audio_run);
}
static void avi_audio_task_inti(void *priv)
{
struct avi_avi *avi = (struct avi_avi *)priv;
int w_len;
int r_audio_len;
//初始化cycle buffer
avi->data_cbuf = (char *)calloc(1, CBUF_LEN);
if (avi->data_cbuf == NULL) {
printf("[error]>>>>>avi->data_cbuf= NULL");
}
cbuf_init(&avi->cbuf, avi->data_cbuf, CBUF_LEN);
os_sem_create(&avi->rd_sem, 0);
avi->audio_buf = (char *)calloc(1, DEC_AUDIO_LEN);//接收音频缓存
if (avi->audio_buf == NULL) {
printf("[error]>>>>>avi->audio_buf = NULL");
}
avi->audio_num = avi_get_audio_chunk_num(avi->fd, 1);
avi->dec_server = server_open("audio_server", "dec");
if (!avi->dec_server) {
puts("audio server open fail.\n");
} else {
puts("open success");
}
while (1) {
r_audio_len = avi_audio_get_frame(avi->fd, ++avi->audio_run_num, (u8 *)avi->audio_buf, DEC_AUDIO_LEN, 1); //全回放功能获取帧
if (r_audio_len) {
w_len = cbuf_write(&avi->cbuf, avi->audio_buf, r_audio_len);
os_sem_set(&avi->rd_sem, 0);
os_sem_post(&avi->rd_sem);
avi->audio_play_size = w_len;
if (!w_len) {
--avi->audio_run_num; //防止写太快填充满CbufHOY
os_time_dly(3);
}
if (!avi->dec_status) {
avi->dec_status = 1;
open_audio_dec(avi);
}
os_time_dly(1);
}
if (avi->audio_run_num >= avi->audio_num) {
printf(">>>>>>>close_audio_dec");
close_audio_dec(avi);
free(avi->data_cbuf);
free(avi->audio_buf);
avi->audio_buf = NULL;
os_sem_del(&avi->rd_sem, 0);
sys_timer_del(avi->audio_time_id);
break;
}
}
}
static void jpg_play(void *priv)
{
struct avi_avi *avi = (struct avi_avi *)priv;
os_sem_post(&avi->jpg_run);
}
static void avi_jpg_task_inti(void *priv)
{
struct avi_avi *avi = (struct avi_avi *)priv;
avi->jpg_buf = (char *)calloc(1, DEC_JPG_LEN); //接收JPG缓存
if (avi->jpg_buf == NULL) {
printf("[error]>>>>>avi->jpg_buf = NULL");
}
avi->jpg_num = avi_get_video_chunk_num(avi->fd, 1);
os_sem_create(&avi->jpg_run, 0);
avi->jpg_time_id = sys_timer_add(avi, jpg_play, (avi->play_time * 1000) / avi->jpg_num);
while (1) {
os_sem_pend(&avi->jpg_run, 0);
int r_jpg_len = avi_video_get_frame(avi->fd, ++avi->jpg_run_num, (u8 *)avi->jpg_buf, DEC_JPG_LEN, 1); //全回放功能获取帧
if (*(u32 *)avi->jpg_buf == IDX_00DC || *(u32 *)avi->jpg_buf == IDX_01WB || *(u32 *)avi->jpg_buf == IDX_00WB) {
r_jpg_len -= 8;
avi->jpg_buf += 8;
}
if (r_jpg_len > 0) {
dec_jpg_to_yuv(avi, avi->jpg_buf, r_jpg_len);
} else {
printf(">>>>>>>>>>jpg_play_close");
sys_timer_del(avi->jpg_time_id);
free(avi->jpg_buf);
avi->jpg_buf = NULL;
free(avi->yuv_buf);
os_sem_del(&avi->jpg_run, 0);
break;
}
}
}
static void avi_play_test(void *priv)
{
int ret;
//1.初始化屏
user_ui_lcd_init();
set_lcd_show_data_mode(CAMERA);
//8.获取播放帧数 音频包数
struct avi_avi *avi = (struct avi_avi *)calloc(1, sizeof(struct avi_avi));
if (avi == NULL) {
printf("[error]>>>>>avi= NULL");
}
while (!storage_device_ready()) { //等待sd文件系统挂载完成
os_time_dly(2);
printf(">>>>>>>>>>>>wait_sd_ok");
}
avi->fd = fopen(AVI_PATH, "r");
if (avi->fd == NULL) {
printf("[error]>>>>>avi_fd= NULL");
}
ret = avi_playback_unpkg_init(avi->fd, 1); //解码初始化,最多10分钟视频
if (ret) {
printf("avi_playback_unpkg_init err!!!\n");
}
avi->play_time = avi_get_file_time(avi->fd, 1);
thread_fork("avi_audio_task_inti", 10, 1024, 0, 0, avi_audio_task_inti, avi);
thread_fork("avi_jpg_task_inti", 11, 1024, 0, 0, avi_jpg_task_inti, avi);
//9.定时播放视频帧和音频帧
while (1) {
os_time_dly(100);
if (avi->jpg_buf == NULL && avi->audio_buf == NULL) {
avi_unpkg_exit(avi->fd, 1);
fclose(avi->fd);
free(avi);
printf(">>>>>>>>>>>>free_avi");
break;
}
}
}
static int avi_test_task_init(void)
{
puts("avi_test_task_init\n\n");
return thread_fork("avi_play_test", 11, 1024, 0, 0, avi_play_test, NULL);
}
late_initcall(avi_test_task_init);
#endif