#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