1、同步BR28。add 文件传输crc校验心跳包,防止传输大文件校验超时;

2、修正科大讯飞、摄像头测试问题;
This commit is contained in:
huxi
2025-12-15 14:39:25 +08:00
parent 719f612ab5
commit 48416abdf1
67 changed files with 3512 additions and 2958 deletions
+186 -75
View File
@@ -84,24 +84,10 @@
#include "avi_video.h"
#include "avi_audio_player.h"
#if TCFG_VIDEO_DIAL_ENABLE
#define AVI_TASK_NAME "avi_task"
#define NEW_PARSE_RIFF_FILE 1 // 该宏打开使用新的文件解析流程,与旧流程主要区别在于兼容packres工具打包后的avi资源解析
#define DEFAULT_DWSUGGESTEDBUFFER_SIZE 20*1024
#define PCM_CBUF_SIZE (4*1024) /* 根据负载可调 320B*3帧约等于1KB */
enum avi_status {
AVI_PLAY_STATUS = 1,
AVI_STOP_STATUS,
};
enum {
MIC2DAC_STATUS_STOP = 0,
MIC2DAC_STATUS_START,
MIC2DAC_STATUS_PAUSE, // 暂时未添加这个状态
};
enum {
AVI_PLAY_ONCE = 0,
AVI_PLAY_LOOP,
AVI_PLAY_SEQUENCE,
};
#define PCM_CBUF_SIZE (20*1024) /* 根据负载可调 320B*3帧约等于1KB */
struct avi_fs_info {
FILE *fp;
u32 offset;
@@ -111,10 +97,9 @@ struct avi_fs_info {
};
cbuffer_t avi_pcm_cbuf;
OS_MUTEX avi_pcm_mutex;
u8 usr_test_flag = 0;
static u8 avi_play_mode = 0;
static u8 avi_play_mode = AVI_PLAY_LOOP;
static MV_DRAW *avi_player = NULL;
static PLAY_VIDEO_PATH_MANAGE *video_path_mange = NULL;
#define __this (avi_player)
/* static void *gpu_task_head; */
static void *avi_taskp;
@@ -124,6 +109,7 @@ static const char *avi_files[] = {
// 可以继续添加更多文件
};
static u16 task_switch_flag;
/* static u8 __this->param.is_audio_mute = 1; */
#define AVI_FILE_COUNT (sizeof(avi_files) / sizeof(avi_files[0]))
@@ -164,11 +150,13 @@ extern u32 ps_ram_size[];
extern int avi_get_width(void *avip);
extern int avi_get_height(void *avip);
extern int avi_fluh(void *priv);
extern void malloc_list_update_rets(void *buf, int rets);
void avi_stop(void *avip);
void avi_pause(void *avip);
void animig_close(void *ap);
/* void *animig_open(char *name, AVI_PARAM param, int arg); */
@@ -178,6 +166,10 @@ void animig_close(void *ap);
static void *avi_zalloc(size_t size)
{
u32 rets;
__asm__ volatile("%0 = rets":"=r"(rets));
void *p = NULL;
#if TCFG_PSRAM_DEV_ENABLE
p = malloc_psram(size);
@@ -185,16 +177,23 @@ static void *avi_zalloc(size_t size)
#else
p = zalloc(size);
#endif
malloc_list_update_rets(p, rets);
return p;
}
static void *avi_malloc(size_t size)
{
u32 rets;
__asm__ volatile("%0 = rets":"=r"(rets));
void *p = NULL;
#if TCFG_PSRAM_DEV_ENABLE
p = malloc_psram(size);
#else
p = malloc(size);
#endif
malloc_list_update_rets(p, rets);
return p;
}
static void avi_free(void *pv)
@@ -216,7 +215,6 @@ static void pcm_cbuf_init(void)
}
ASSERT(__this->avi_pcm_buf, "pcm cbuf avi_malloc fail\n");
cbuf_init(&avi_pcm_cbuf, __this->avi_pcm_buf, PCM_CBUF_SIZE);
os_mutex_create(&avi_pcm_mutex);
__this->avi_audio_start = 1;
log_info("\n[pcm_cbuf_init]mem_status:\n");
mem_stats();
@@ -229,7 +227,6 @@ static void pcm_cbuf_deinit(void)
cbuf_clear(&avi_pcm_cbuf);
avi_free(__this->avi_pcm_buf);
__this->avi_pcm_buf = NULL;
os_mutex_del(&avi_pcm_mutex, 0);
}
log_info("\n[pcm_cbuf_deinit]mem_status:\n");
mem_stats();
@@ -314,20 +311,72 @@ void avi_play_shutdown(void)
log_info("\n\n[avi_play_shutdown]mem_status:\n");
mem_stats();
}
void video_manage_init()
{
video_path_mange = avi_zalloc(sizeof(PLAY_VIDEO_PATH_MANAGE));
}
void set_avi_play_mode(u8 mode)
{
avi_play_mode = mode;
avi_play_shutdown();
}
// 播放下一个文件
void *animig_open(char *name, int window_id, int arg);
void avi_play_next(void)
{
AVI_PARAM param;
if (__this != NULL) {
memcpy(&param, &(__this->param), sizeof(AVI_PARAM));//拷贝当前配置
}
u8 is_dial = __this->param.is_dial;
u8 *video_path = NULL;
if (is_dial == 0) {
video_path = (u8 *)param.fname;
} else {
video_path = (u8 *)watch_avi_get_related_path(watch_get_style());
}
if (video_path == NULL) {
log_error("%s path is NULL");
return ;
}
if (!__this->avi_is_switching) {
avi_switch_timelock();
wdt_clear();
avi_play_shutdown();
avi_player = animig_open((char *)watch_avi_get_related_path(watch_get_style()), 0, 3); // 缓存3帧可以达到流畅播放30FPS
avi_player = animig_open((char *)video_path, param, 3); // 缓存3帧可以达到流畅播放30FPS
/* avi_player = (MV_DRAW *) animig_open((char *)set_avi_play_file(), 0, 3); // 缓存3帧可以达到流畅播放30FPS */
__this->avi_playtimer = 0;
// UI_HIDE_CURR_WINDOW();
// UI_SHOW_WINDOW(AVI_WINDOW);
// UI_SHOW_WINDOW(STYLE_DIAL_ID(WATCH));
}
}
void avi_play_loop(void)
{
AVI_PARAM param;
if (__this != NULL) {
memcpy(&param, &(__this->param), sizeof(AVI_PARAM));//拷贝当前配置
}
u8 is_dial = __this->param.is_dial;
u8 *video_path = NULL;
if (is_dial == 0) {
video_path = (u8 *)param.fname;
} else {
video_path = (u8 *)watch_avi_get_related_path(watch_get_style());
}
if (video_path == NULL) {
log_error("%s path is NULL");
return ;
}
if (!__this->avi_is_switching) {
avi_switch_timelock();
wdt_clear();
avi_play_shutdown();
avi_player = animig_open((char *)video_path, param, 3); // 缓存3帧可以达到流畅播放30FPS
/* avi_player = (MV_DRAW *) animig_open((char *)set_avi_play_file(), 0, 3); // 缓存3帧可以达到流畅播放30FPS */
__this->avi_playtimer = 0;
// UI_HIDE_CURR_WINDOW();
@@ -338,17 +387,35 @@ void avi_play_next(void)
// 播放上一个文件
void avi_play_prev(void)
{
AVI_PARAM param;
if (__this != NULL) {
memcpy(&param, &(__this->param), sizeof(AVI_PARAM));//拷贝当前配置
}
u8 is_dial = __this->param.is_dial;
u8 *video_path = NULL;
if (is_dial == 0) {
video_path = (u8 *)param.fname;
} else {
video_path = (u8 *)watch_avi_get_related_path(watch_get_style());
}
if (video_path == NULL) {
log_error("%s path is NULL");
return ;
}
if (!__this->avi_is_switching) {
avi_switch_timelock();
wdt_clear();
avi_play_shutdown();
__this->avi_index--;
if (__this->avi_index < 0) {
__this->avi_index = AVI_FILE_COUNT - 1;
}
avi_player = animig_open((char *)video_path, param, 3); // 缓存3帧可以达到流畅播放30FPS
/* avi_player = (MV_DRAW *) animig_open((char *)set_avi_play_file(), 0, 3); // 缓存3帧可以达到流畅播放30FPS */
__this->avi_playtimer = 0;
// UI_HIDE_CURR_WINDOW();
// UI_SHOW_WINDOW(AVI_WINDOW);
// UI_SHOW_WINDOW(STYLE_DIAL_ID(WATCH));
}
}
@@ -364,7 +431,7 @@ static size_t avi_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
#define rewind(fp) fseek(fp, 0, SEEK_SET)
void parse_riff_file(FILE *file, ChunkCallback callback, void *user_param, int curr_pos)
char parse_riff_file(FILE *file, ChunkCallback callback, void *user_param, int curr_pos)
{
char *head = "";
@@ -391,13 +458,13 @@ void parse_riff_file(FILE *file, ChunkCallback callback, void *user_param, int c
/* 读取RIFF头 */
if (avi_fread(chunk_id, 1, 4, file) != 4) {
log_error("Failed to read chunk ID");
return;
return -AVI_READ_CHUNK_ID_FAIL;
}
chunk_id[4] = '\0';
if (avi_fread(&chunk_size, 4, 1, file) != 1) {
log_error("Failed to read chunk size");
return;
return -AVI_READ_CHUNK_SIZE_FAIL;
}
log_info("\n\n\n\n\nRIFF chunk_size: %d\n\n\n\n\n", chunk_size);
/* 校验块大小合法性 */
@@ -406,7 +473,7 @@ void parse_riff_file(FILE *file, ChunkCallback callback, void *user_param, int c
if (current_pos + chunk_size > file_size) {
log_info("校验块大小合法性 %d %d %d", (int)current_pos, chunk_size, (int)file_size);
log_error("RIFF chunk size exceeds file size");
return;
return -AVI_FILE_LEN_ERR;
}
/* 处理子块 */
@@ -422,13 +489,13 @@ void parse_riff_file(FILE *file, ChunkCallback callback, void *user_param, int c
/* 读取子块头 */
if (avi_fread(sub_chunk_id, 1, 4, file) != 4) {
log_error("Failed to read sub chunk ID");
return;
return -AVI_READ_SUB_CHUNK_ID_FAIL;
}
sub_chunk_id[4] = '\0';
if (avi_fread(&sub_chunk_size, 4, 1, file) != 1) {
log_error("Failed to read sub chunk size");
return;
return -AVI_READ_SUB_CHUNK_ID_FAIL;
}
/* 校验子块大小 */
@@ -436,7 +503,7 @@ void parse_riff_file(FILE *file, ChunkCallback callback, void *user_param, int c
if (current_pos + sub_chunk_size > file_size) {
log_info("校验子块大小 %d %d %d", (int)current_pos, sub_chunk_size, (int)file_size);
log_error("Sub chunk exceeds file size");
return;
return -AVI_SUB_CHUNK_LEN_ERR;
}
off_t sub_start = ftell(file) - 8 - __this->file_offset; // 计算子块起始位置
@@ -447,7 +514,7 @@ void parse_riff_file(FILE *file, ChunkCallback callback, void *user_param, int c
char list_type[5] = {0};
if (avi_fread(list_type, 1, 4, file) != 4) {
log_error("Failed to read LIST type");
return;
return -AVI_LIST_TYPE_ERR;
}
list_type[4] = '\0';
@@ -487,6 +554,7 @@ void parse_riff_file(FILE *file, ChunkCallback callback, void *user_param, int c
fseek(file, 1, SEEK_CUR);
}
}
return 0;
}
/* LIST块解析实现 */
static void parse_list_chunk(FILE *file, long list_end, ChunkCallback callback,
@@ -804,15 +872,16 @@ void *avi_open(const char *path, int en_buf, int redrawid)
log_info("%s %d %s", __func__, __LINE__, path);
FILE *fp = fopen(path, "r");
AVIPlayer *player = avi_zalloc(sizeof(AVIPlayer));
wdt_clear();
log_info("%s %d fp %p", __func__, __LINE__, fp);
mem_stats();
if (!fp) {
return NULL;
log_error("%s open file fail ");
goto __err;
}
log_info("%s %d", __func__, __LINE__);
mem_stats();
AVIPlayer *player = avi_zalloc(sizeof(AVIPlayer));
player->file = fp;
player->redrawid = redrawid;
log_info("%s %d", __func__, __LINE__);
@@ -820,14 +889,19 @@ void *avi_open(const char *path, int en_buf, int redrawid)
// 解析文件结构
log_info("\n\n\nBefore parse_riff_file: file position: %u\n", ftell(fp));
parse_riff_file(fp, parse_callback, player, 0);
char parse_ret = parse_riff_file(fp, parse_callback, player, 0);
if (parse_ret != 0) {
log_error("%s check file fail =%d", __func__, parse_ret);
goto __err;
}
log_info("%s %d", __func__, __LINE__);
mem_stats();
rewind(fp);
if (player->avih_header.dwTotalFrames == 0) {
avi_free(player);
return NULL;
log_error("%s frames info no get ");
goto __err;
}
void *usr_mmu = strstr(path, "virfat_flash");
@@ -853,7 +927,7 @@ void *avi_open(const char *path, int en_buf, int redrawid)
player->cache.cnt = en_buf;
player->cache.block_len = len;
player->cache.data = malloc_psram(player->cache.cnt * player->cache.block_len);
player->cache.data = avi_zalloc(player->cache.cnt * player->cache.block_len);
ASSERT(player->cache.data);
player->cache.m = avi_zalloc(player->cache.cnt * sizeof(mjpegdata));
@@ -891,6 +965,12 @@ void *avi_open(const char *path, int en_buf, int redrawid)
os_mutex_create(&p->mutex);
return player;
__err:
printf("\n [ERROR] %s -[yuyu] %d\n", __FUNCTION__, __LINE__);
void avi_close(void *avip);
avi_close(player);
return NULL;
}
void avi_close(void *avip)
@@ -997,10 +1077,9 @@ void avi_pause()
/* AVIPlayer *p = (AVIPlayer *)avip; */
AVIPlayer *p = (AVIPlayer *)__this->st;
if (avi_player == NULL || avi_player->pause == 1) {
if (__this == NULL || __this->pause == 1 || p == NULL) {
return;
}
printf("\n [ERROR] %s -[yuyu] %d\n", __FUNCTION__, __LINE__);
p->ui_work = 2;
avi_player->pause = 1;
@@ -1020,7 +1099,9 @@ void avi_pcm_open(void *avip)
{
AVIPlayer *p = (AVIPlayer *)avip;
// 初始化循环缓冲区和互斥锁
if (p->audio_format.wFormatTag == 0) {
return ;
}
pcm_cbuf_init();
// 创建AI voice播放参数
@@ -1053,6 +1134,9 @@ void avi_pcm_open(void *avip)
void avi_pcm_close(void *avip)
{
AVIPlayer *p = (AVIPlayer *)avip;
if (p->audio_format.wFormatTag == 0) {
return ;
}
log_info("%s %d ", __func__, __LINE__);
pcm_cbuf_deinit();
@@ -1118,7 +1202,7 @@ int avi_exec(void *avip, DisplayMJpegFunc jpgcb, PlayPCMFunc pcmcb)
AVIPlayer *p = (AVIPlayer *)avip;
int argv[2] = {0};
int ret;
// log_info("%s %d is_playing %d", __func__, __LINE__, p->is_playing);
/* log_info("%s %d is_playing %d,", __func__, __LINE__, p->is_playing); */
if (!p) {
return -1;
@@ -1135,8 +1219,12 @@ int avi_exec(void *avip, DisplayMJpegFunc jpgcb, PlayPCMFunc pcmcb)
switch (avi_play_mode) {
case AVI_PLAY_LOOP:
// 默认模式,单视频循环
p->current_pos = 0;
avi_seek(avip, 0.0);
/* p->current_pos = 0; */
/* avi_seek(avip, 0.0); */
argv[0] = (int)avi_play_loop;
argv[1] = 0;
ret = os_taskq_post_type("ui", Q_CALLBACK, 2, argv);
log_info("\n\n[AVI_PLAY_LOOP]%s %d is_playing %d\n\n", __func__, __LINE__, p->is_playing);
return -1;
break;
@@ -1677,17 +1765,17 @@ static int _write_jlaudio(void *player, u8 *ptr, int len)
AVIPlayer *pp = (AVIPlayer *)player;
// log_info("[_write_aivoice] len:%d\n", len);
int cnt = 0;
while (len) {
/* os_mutex_pend(&avi_pcm_mutex, 0); */
u32 w = cbuf_write(&avi_pcm_cbuf, ptr, len); // 直接按len写,返回实际写入
// log_info("[cbuf_write] w:%d\n", w);
/* os_mutex_post(&avi_pcm_mutex); */
if (w == 0) {
os_time_dly(1);
continue;
if (__this->param.is_audio_mute != 1) {
while (len) {
u32 w = cbuf_write(&avi_pcm_cbuf, ptr, len); // 直接按len写,返回实际写入
/* log_info("[cbuf_write] w:%d len=%d\n", w, len); */
if (w == 0) {
os_time_dly(1);
continue;
}
ptr += w;
len -= w;
}
ptr += w;
len -= w;
}
pp->jump_mjpeg = jiffies_usec();
return len;
@@ -1890,6 +1978,7 @@ static void md_flush(MV_DRAW *md)
// log_info("11 %d", jiffies_msec());
AVIPlayer *p = (AVIPlayer *)md->st;
/* printf("[msg]%s-%d>>>>>>>>>>>md->pause=%d,p->avih_header.dwMicroSecPerFrame=%d p->audio_format.wFormatTag=%d", __FUNCTION__, __LINE__, md->pause, p->avih_header.dwMicroSecPerFrame, p->audio_format.wFormatTag); */
if (md->pause == 1) {
md->flushTimer = sys_timeout_add(md, (void(*)(void *))md_flush, p->avih_header.dwMicroSecPerFrame / 2000);
@@ -1898,7 +1987,7 @@ static void md_flush(MV_DRAW *md)
avi_fluh(md->st);
if (p->audio_format.wFormatTag == 0x0001) {
if (p->audio_format.wFormatTag == 0x0001 && __this->param.is_audio_mute != 1) {
md->flushTimer = sys_timeout_add(md, (void(*)(void *))md_flush, p->avih_header.dwMicroSecPerFrame / 2000);
} else {
md->flushTimer = sys_timeout_add(md, (void(*)(void *))md_flush, p->avih_header.dwMicroSecPerFrame / 1000);
@@ -1926,14 +2015,16 @@ void play_task(MV_DRAW *md)
// play
if (msg[1] == AVI_PLAY_STATUS) {
log_info("avi play");
avi_pcm_open(md->st);
md->flushTimer = sys_timeout_add(md, (void(*)(void *))md_flush, 1);
}
// stop
if (msg[1] == AVI_STOP_STATUS) {
log_info("avi stop");
avi_pcm_close(md->st);
if (__this->param.is_audio_mute != 1) {
avi_pcm_close(md->st);
}
if (md->flushTimer) {
sys_timeout_del(md->flushTimer);
md->flushTimer = 0;
@@ -1973,7 +2064,7 @@ static void app_video_mode_switch(void *priv)
}
#endif
void *animig_open(char *name, int window_id, int arg)
void *animig_open(char *name, AVI_PARAM param, int arg)
{
u8 type = 0;
@@ -1987,7 +2078,7 @@ void *animig_open(char *name, int window_id, int arg)
}
#endif
void *f = fopen(name, "r");
FILE *f = fopen(name, "r");
if (f == NULL) {
log_info("open file fail %s", name);
return NULL;
@@ -2014,42 +2105,62 @@ void *animig_open(char *name, int window_id, int arg)
MV_DRAW *md = avi_zalloc(sizeof(MV_DRAW));
__this = md;
ASSERT(__this);
memcpy(&(__this->param), &param, sizeof(AVI_PARAM));
os_sem_create(&md->mv_sem, 0);
md->type = type;
md->repeat = -1;
if (md->type == 2) {
md->st = avi_open(name, arg, 0);
AVIPlayer *p = (AVIPlayer *)(md->st);
if (md->st == NULL) {
goto __err;
}
if (p->width > LCD_WIDTH || p->height > LCD_HEIGHT) {
log_error("vidoe width %d or height%d over lcd width %d or height %d", p->width, p->height, LCD_WIDTH, LCD_HEIGHT);
goto __err;
}
if (__this->param.is_audio_mute != 1) {
avi_pcm_open(md->st);
}
wdt_clear();
ASSERT(md->st);
avi_fluh(md->st);
}
/* strcpy(__this->param.fname,name,) */
/* char *taskname = strrchr(name, '/'); */
/* taskname = taskname ? taskname + 1 : name; */
/* taskname = "avi_task"; */
u8 fname_len = (sizeof(__this->param.fname) / sizeof(__this->param.fname[0]));
strncpy(__this->param.fname, name, fname_len);
printf("[msg]%s-%d>>>>>>>>>>>__this->param.fname=%s", __FUNCTION__, __LINE__, __this->param.fname);
__this->param.fname[fname_len - 1] = '\0';
log_info("create %s", AVI_TASK_NAME);
task_create((void(*)(void *))play_task, md, AVI_TASK_NAME);
char *taskname = strrchr(name, '/');
taskname = taskname ? taskname + 1 : name;
taskname = "avi_task";
strcpy(md->fname, taskname);
log_info("create %s", taskname);
task_create((void(*)(void *))play_task, md, "avi_task");
os_taskq_post(md->fname, 1, AVI_PLAY_STATUS);
os_taskq_post(AVI_TASK_NAME, 1, AVI_PLAY_STATUS);
return md;
__err:
void avi_close(void *avip);
avi_close(md->st);
__this = NULL;
if (md) {
avi_free(md);
}
return NULL;
}
void animig_close(void *ap)
{
MV_DRAW *md = ap;
char *taskname = strrchr(md->fname, '/');
taskname = taskname ? taskname + 1 : md->fname;
// while (md->act != -1) {
// md->act = 0;
// os_time_dly(1);
// }\\
os_taskq_post(md->fname, 1, AVI_STOP_STATUS);
os_taskq_post(AVI_TASK_NAME, 1, AVI_STOP_STATUS);
os_sem_pend(&md->mv_sem, 0);
log_info("kill %s", taskname);
log_info("kill %s", AVI_TASK_NAME);
jlgpu_scheduler_wait_sync();
task_kill("avi_task");
+43 -3
View File
@@ -92,6 +92,21 @@ typedef void (*ChunkCallback)(FILE *file,
#pragma pack(push, 1)
enum avi_status {
AVI_PLAY_STATUS = 1,
AVI_STOP_STATUS,
};
enum {
MIC2DAC_STATUS_STOP = 0,
MIC2DAC_STATUS_START,
MIC2DAC_STATUS_PAUSE, // 暂时未添加这个状态
};
enum {
AVI_PLAY_ONCE = 0,
AVI_PLAY_LOOP,
AVI_PLAY_SEQUENCE,
};
typedef struct {
uint32_t dwMicroSecPerFrame; // 每帧时长(微秒)
@@ -175,6 +190,17 @@ typedef enum {
STREAM_AUDIO
} StreamType;
typedef enum {
AVI_READ_CHUNK_ID_FAIL = 1,
AVI_READ_CHUNK_SIZE_FAIL,
AVI_READ_SUB_CHUNK_ID_FAIL,
AVI_READ_SUB_CHUNK_SIZE_FAIL,
AVI_LIST_TYPE_ERR,
AVI_FILE_LEN_ERR,
AVI_SUB_CHUNK_LEN_ERR
} AVI_ERR_CODE;
typedef struct {
// 文件信息
FILE *file;
@@ -205,8 +231,8 @@ typedef struct {
int bits_per_sample;
u8 auds_vol;
u8 auds_drop;
int auds_idx;
u8 auds_exit;
int auds_idx;
u16 auds_inr;
int auds_rate;
int auds_total;
@@ -243,8 +269,14 @@ void *avi_open(const char *path, int en_buf, int redrawid);
void avi_close(void *avip);
int avi_fluh(void *priv);
typedef struct {
void *fp;
u8 is_dial;
u8 is_audio_mute;
u8 mode;
char fname[64];
} AVI_PARAM;
typedef struct {
void *fp;
OS_SEM mv_sem;
void *st; // 解码器
int drawid;
@@ -257,6 +289,7 @@ typedef struct {
u8 avi_is_switching;
u8 avi_index;
u16 avi_playtimer;
AVI_PARAM param;
int start;
int time;
int frameCount;
@@ -265,6 +298,12 @@ typedef struct {
u8 *avi_pcm_buf;
long file_offset;
} MV_DRAW;
typedef struct {
u8 **file_path;
u8 *cur_index;
} PLAY_VIDEO_PATH_MANAGE;
@@ -294,7 +333,8 @@ int avi_get_redrawid(void *avip);
float avi_get_total_sec(void *avip);
void *avi_get_view_file_info(void *priv);
void *animig_open(char *name, int window_id, int arg);
// void *animig_open(char *name, int window_id, int arg);
void *animig_open(char *name, AVI_PARAM param, int arg);
void avi_set_avi_playtimer_id(u16 timer_id);
u16 avi_get_avi_playtimer_id();
+3
View File
@@ -275,6 +275,7 @@ int mic_data_write(void *mic, void *data, int len)
struct voice_mic_data *fb = (struct voice_mic_data *)mic;
int wlen = 0;
wlen = cbuf_write(&fb->cbuf, data, len);
//如果有较多丢包,要开下读的putchar打印,评估是否需要加大cbuf
if (wlen < len) {
putchar('D');
}
@@ -285,9 +286,11 @@ int mic_data_read(void *mic, void *data, int len)
struct voice_mic_data *fb = (struct voice_mic_data *)mic;
/* printf("%s. %d, %d", __func__, len, cbuf_get_data_len(&fb->cbuf)); */
if (cbuf_get_data_len(&fb->cbuf) < len) {
/* putchar('B'); */
return 0;
} else {
int wlen = cbuf_read(&fb->cbuf, data, len);
/* putchar('G'); */
return wlen;
}
}
+196 -6
View File
@@ -4,6 +4,7 @@
#include "camera_manager.h"
#include "avilib.h"
#include "pcm_data.h"
#include "mic_data.h"
#include "clock_manager/clock_manager.h"
#define LOG_TAG_CONST VIDEO_REC
@@ -15,6 +16,16 @@
#define LOG_CLI_ENABLE
#include "debug.h"
#if TCFG_CAMERA_MANAGER_ENABLE
/*
是否使用独立pcm线程管理mic数据,
会消耗更多的ram(11*4k),直接获取mic数据仅需要(3*4k+512)
默认不开
*/
#define MIC_DATA_FORM_PCM_TASK_ENABLE 0
#define MIC_FREMA_SIZE (4*1024)
#define MIC_BUFFER_SIZE (MIC_FREMA_SIZE*2+512)
#define MIC_SIMPLE_RATE (8000)
enum {
Q_AVI_TASK_KILL = (Q_USER + 100),
@@ -22,8 +33,23 @@ enum {
Q_AVI_TASK_REC_STOP,
};
struct fill_frame {
u32 start_msecs;//开始录像时间
u32 msecs;//上一次补帧时间
u32 secs;//录像时间
u32 fnum;//需要补帧的数
u32 cnt_fnum;//总帧数
u16 fps;//目标帧率
u16 one_sec_fps;//1秒实际帧率
u8 fill_frame_en;
u8 droping_frame_en;
};
struct video_rec_handle {
void *pcm_hdl;
void *mic;
u8 *mic_frame;
char avi_task_name[32];
u8 write_error; //写文件异常
u8 busy;
@@ -32,10 +58,20 @@ struct video_rec_handle {
int sample_rate;
void (*ui_refresh_cb)(int status);
int bytes_per_sample;
struct fill_frame fill;
};
static struct video_rec_handle *video_rec;
#define __this (video_rec)
#if TCFG_PSRAM_DEV_ENABLE
#define malloc(size) malloc_psram(size)
#define free(ptr) free_psram(ptr)
#else
#define malloc(size) malloc(size)
#define free(ptr) free(ptr)
#endif
extern uint32_t timer_get_ms(void);
@@ -112,6 +148,101 @@ int jlcamera_video_rec_stop()
return os_taskq_post_type(__this->avi_task_name, Q_AVI_TASK_REC_STOP, 0, NULL);
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief 补帧模块初始化
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
static void jljpeg_frame_fill_init()
{
if (!__this) {
log_error("%s not init\n", __func__);
return;
}
memset(&__this->fill, 0, sizeof(struct fill_frame));
__this->fill.fps = __this->video_rate;
__this->fill.start_msecs = jiffies_msec();;
__this->fill.msecs = jiffies_msec();
__this->fill.droping_frame_en = 1;
__this->fill.fill_frame_en = 1;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief 补帧模块判断(需要运行在写帧后面)
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
static void jljpeg_frame_fill_judge(avi_t *out_fd, u32 frame_cnt)
{
if (!__this) {
log_error("%s not init\n", __func__);
return;
}
u32 cur_fcnt;
u32 need_fcnt;
__this->fill.cnt_fnum += frame_cnt;
__this->fill.one_sec_fps += frame_cnt;
if (jiffies_msec2offset(__this->fill.msecs, jiffies_msec()) >= 1000) {
__this->fill.secs = (jiffies_msec2offset(__this->fill.start_msecs, jiffies_msec())) / 1000;
if (!__this->fill.secs) {
__this->fill.secs = 1;
}
need_fcnt = __this->fill.secs * __this->fill.fps;
cur_fcnt = __this->fill.cnt_fnum + __this->fill.fnum;
if (cur_fcnt < need_fcnt) {
__this->fill.fnum += need_fcnt - cur_fcnt;
}
__this->fill.msecs = jiffies_msec();
/* printf("avi dup video fps :%d act fps:%d ,ext fps: %d %d\n", __this->fill.cnt_fnum / __this->fill.secs, __this->fill.one_sec_fps, __this->fill.fps,__this->fill.fnum); */
__this->fill.one_sec_fps = 0;
}
if (__this->fill.fnum && __this->fill.fill_frame_en) {
int ret = AVI_dup_frame(out_fd);
if (!ret) {
__this->fill.cnt_fnum++;
__this->fill.fnum--;
}
}
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief 动态丢帧补帧模块判断(需要运行在写帧前面)
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
static int jljpeg_frame_dropping_judge()
{
if (!__this || !__this->fill.droping_frame_en) {
return 0;
}
u32 msecs = jiffies_msec2offset(__this->fill.msecs, jiffies_msec());
/* printf("%d %d %d\n",(__this->fill.one_sec_fps+1) , (msecs*__this->fill.fps/1000),msecs); */
if ((__this->fill.one_sec_fps) > (msecs * __this->fill.fps / 1000) + 1) {
/* printf("fps > %d ,need droping\n",__this->fill.fps); */
if (__this->fill.fnum) {
__this->fill.fnum--;
return 0;
}
return 1;
}
return 0;
}
static void video_show_task(void *priv)
{
log_debug("%s enter>>>>>>>>>>>>>>>>>>>>\n ", __func__);
@@ -148,10 +279,21 @@ static void video_show_task(void *priv)
out_fd = NULL;
}
}
#if MIC_DATA_FORM_PCM_TASK_ENABLE
if (__this->pcm_hdl) {
pcm_data_exit(__this->pcm_hdl);
__this->pcm_hdl = NULL;
}
#else
if (__this->mic) {
mic_data_close(__this->mic);
__this->mic = NULL;
}
if (__this->mic_frame) {
free(__this->mic_frame);
__this->mic_frame = NULL;
}
#endif
log_debug("%s exit >>>>>>>>>>>>>>>>>>>>\n ", __func__);
//下面禁止加打印{
os_sem_post((OS_SEM *)msg[1]);
@@ -163,7 +305,7 @@ static void video_show_task(void *priv)
cyc_time = msg[2];
__this->write_error = 0;
log_debug("avi task rec start <%s> cyc_time:%d !\n", filename, cyc_time);
#if MIC_DATA_FORM_PCM_TASK_ENABLE
__this->pcm_hdl = pcm_data_init(__this->sample_rate, __this->aframe_size, __this->aframe_size * 10);
if (!__this->pcm_hdl) {
//TODO
@@ -172,6 +314,23 @@ static void video_show_task(void *priv)
__this->write_error = -1;
continue;
}
#else
__this->mic = mic_data_open(VOICE_MCU_MIC, MIC_BUFFER_SIZE, MIC_SIMPLE_RATE);
if (!__this->mic) {
//TODO
log_error("avi task rec start pcm err!!!\n");
/* break; */
__this->write_error = -1;
continue;
}
__this->mic_frame = malloc(MIC_FREMA_SIZE);
if (!__this->mic_frame) {
log_error("avi task rec start pcm err!!!\n");
/* break; */
__this->write_error = -1;
continue;
}
#endif
out_fd = AVI_open_output_file(filename);
if (out_fd == NULL) {
log_error("open file erro\n");
@@ -182,6 +341,7 @@ static void video_show_task(void *priv)
AVI_set_video_suggestbuffersize(out_fd, 20 * 1024); //建议缓存区20k,解码用
AVI_set_video(out_fd, frame_width, frame_height, __this->video_rate, "MJPG");
AVI_set_audio(out_fd, 1, __this->sample_rate, 16, WAVE_FORMAT_PCM, 0);//默认单声道s16格式
jljpeg_frame_fill_init();
frame_cnt = 0;
/* break; */
} else if (msg[0] == Q_AVI_TASK_REC_STOP) {
@@ -197,11 +357,21 @@ static void video_show_task(void *priv)
}
out_fd = NULL;
}
#if MIC_DATA_FORM_PCM_TASK_ENABLE
if (__this->pcm_hdl) {
pcm_data_exit(__this->pcm_hdl);
__this->pcm_hdl = NULL;
}
#else
if (__this->mic) {
mic_data_close(__this->mic);
__this->mic = NULL;
}
if (__this->mic_frame) {
free(__this->mic_frame);
__this->mic_frame = NULL;
}
#endif
__this->write_error = 0;
/* break; */
}
@@ -212,11 +382,20 @@ static void video_show_task(void *priv)
log_char('C');
//录像输出
if (out_fd) {
#if MIC_DATA_FORM_PCM_TASK_ENABLE
if (pcm_data_read(__this->pcm_hdl, &pcm_data, &pcm_data_len) == 0) {
read_data = 1;
__this->write_error = AVI_write_audio(out_fd, (char *)pcm_data, pcm_data_len);
pcm_data_read_done(__this->pcm_hdl, pcm_data);
}
#else
if (__this->mic && __this->mic_frame) {
if (mic_data_read(__this->mic, __this->mic_frame, MIC_FREMA_SIZE)) {
read_data = 1;
__this->write_error = AVI_write_audio(out_fd, (char *)__this->mic_frame, MIC_FREMA_SIZE);
}
}
#endif
}
if (camera_manager_data_read(&jpeg_data, &jpeg_data_len) == 0) {
log_char('M');
@@ -230,7 +409,14 @@ static void video_show_task(void *priv)
}
#endif
if (out_fd) { //录像输出
__this->write_error = AVI_write_frame(out_fd, (char *)jpeg_data, jpeg_data_len, 1);
if (!jljpeg_frame_dropping_judge()) {
__this->write_error = AVI_write_frame(out_fd, (char *)jpeg_data, jpeg_data_len, 1);
jljpeg_frame_fill_judge(out_fd, 1); //补帧计算
} else {
jljpeg_frame_fill_judge(out_fd, 0); //补帧计算
}
}
camera_manager_read_done(jpeg_data);
#if 0
@@ -302,7 +488,11 @@ int jlcamera_video_rec_init(void)
{
int ret = 0;
ASSERT(!__this);
__this = zalloc(sizeof(struct video_rec_handle));
__this = malloc(sizeof(struct video_rec_handle));
if (!__this) {
goto __err;
}
memset(__this, 0, sizeof(struct video_rec_handle));
__this->busy = 1;
clock_lock("camera_video", clk_get_max_frequency());
//初始化驱动
@@ -320,8 +510,8 @@ int jlcamera_video_rec_init(void)
//视频帧率
__this->video_rate = fps / 2;
//音频采样率
__this->sample_rate = 8000;
__this->aframe_size = 4096;
__this->sample_rate = MIC_SIMPLE_RATE;
__this->aframe_size = MIC_FREMA_SIZE;
snprintf(__this->avi_task_name, sizeof(__this->avi_task_name), "video_show_task");
if (os_task_create(video_show_task, __this, 8, 1024, 1024, __this->avi_task_name)) {