修复摄像头、科大讯飞、rcsp、彩屏仓等相关测试问题;

This commit is contained in:
huxi
2025-12-10 09:40:24 +08:00
parent bc195654bf
commit 719f612ab5
84 changed files with 3520 additions and 178 deletions
+154 -35
View File
@@ -28,6 +28,9 @@
#include "avilib.h"
#include "app_config.h"
//创建另外的文件存储AVI索引, 节约ram内存。在结束录像时合并索引到AVI文件中
#define AVI_INDXE_FILE_ENABLE 1
//#include <time.h>
#if TCFG_PSRAM_DEV_ENABLE
#define malloc(size) malloc_psram(size)
@@ -80,7 +83,7 @@ static size_t avi_write(void *fd, char *buf, size_t len)
while (r < len) {
n = fwrite(buf + r, 1, len - r, (FILE *)fd);
if ((ssize_t)n < 0) {
if ((ssize_t)n <= 0) {
return n;
}
@@ -174,53 +177,108 @@ static int avi_add_chunk(avi_t *AVI, unsigned char *tag, unsigned char *data, in
return 0;
}
static int avi_add_idx_chunk(avi_t *AVI, u32 length)
{
unsigned char c[8] = { 'i', 'd', 'x', '1', 0, 0, 0, 0 };
long2str(c + 4, length);
if (avi_write(AVI->fdes, (char *)c, 8) != 8) {
fseek(AVI->fdes, AVI->pos, SEEK_SET);
AVI_errno = AVI_ERR_WRITE;
return -1;
}
/* Update file position */
AVI->pos += 8;
return 0;
}
static int avi_add_idx_data(avi_t *AVI, unsigned char *data, int length)
{
/* Output tag, length and data, restore previous position
if the write fails */
length = PAD_EVEN(length);
if (avi_write(AVI->fdes, (char *)data, length) != length) {
fseek(AVI->fdes, AVI->pos, SEEK_SET);
AVI_errno = AVI_ERR_WRITE;
return -1;
}
/* Update file position */
AVI->pos += length;
//fprintf(stderr, "pos=%lu %s\n", AVI->pos, tag);
return 0;
}
static int avi_add_index_entry(avi_t *AVI, unsigned char *tag, long flags, unsigned long pos, unsigned long len)
{
void *ptr;
if (AVI->n_idx >= AVI->max_idx) {
if (AVI->index_fdes) {
unsigned char c[16];
size_t old_count = AVI->max_idx; // 原有元素个数
size_t elem_size = 16; // 每个元素大小
size_t new_count = old_count + 4096; // 扩容后的元素个数
size_t new_size = new_count * elem_size; // 扩容后的字节数
memcpy(c, tag, 4);
long2str(c + 4, flags);
//pos - movi_addr
long2str(c + 8, pos - (HEADERBYTES - 4));
long2str(c + 12, len);
// 1. 分配新的内存块
void *new_idx = malloc(new_size);
if (!new_idx) {
// 申请失败,保持原状或做错误处理
AVI_errno = AVI_ERR_NO_MEM;
//写入索引文件
if (avi_write(AVI->index_fdes, (char *)c, 16) != 16) {
printf("wirte index fail \n");
AVI_errno = AVI_ERR_WRITE;
return -1;
}
} else {
if (AVI->n_idx >= AVI->max_idx) {
memcpy(new_idx, AVI->idx, old_count * elem_size);
size_t old_count = AVI->max_idx; // 原有元素个数
size_t elem_size = 16; // 每个元素大小
size_t new_count = old_count + 4096; // 扩容后的元素个数
size_t new_size = new_count * elem_size; // 扩容后的字节数
free((void *)AVI->idx);
// 1. 分配新的内存块
void *new_idx = malloc(new_size);
if (!new_idx) {
// 申请失败,保持原状或做错误处理
AVI_errno = AVI_ERR_NO_MEM;
return -1;
}
AVI->idx = new_idx;
AVI->max_idx = new_count;
memcpy(new_idx, AVI->idx, old_count * elem_size);
/* ptr = realloc((void *)AVI->idx, (AVI->max_idx + 4096) * 16); */
free((void *)AVI->idx);
/* if (ptr == 0) { */
/* AVI_errno = AVI_ERR_NO_MEM; */
/* return -1; */
/* } */
/* AVI->max_idx += 4096; */
/* AVI->idx = (unsigned char((*)[16])) ptr; */
AVI->idx = new_idx;
AVI->max_idx = new_count;
/* ptr = realloc((void *)AVI->idx, (AVI->max_idx + 4096) * 16); */
/* if (ptr == 0) { */
/* AVI_errno = AVI_ERR_NO_MEM; */
/* return -1; */
/* } */
/* AVI->max_idx += 4096; */
/* AVI->idx = (unsigned char((*)[16])) ptr; */
}
/* Add index entry */
// fprintf(stderr, "INDEX %s %ld %lu %lu\n", tag, flags, pos, len);
memcpy(AVI->idx[AVI->n_idx], tag, 4);
long2str(AVI->idx[AVI->n_idx] + 4, flags);
//TODO
//pos - movi_addr
long2str(AVI->idx[AVI->n_idx] + 8, pos - (HEADERBYTES - 4));
long2str(AVI->idx[AVI->n_idx] + 12, len);
}
/* Add index entry */
// fprintf(stderr, "INDEX %s %ld %lu %lu\n", tag, flags, pos, len);
memcpy(AVI->idx[AVI->n_idx], tag, 4);
long2str(AVI->idx[AVI->n_idx] + 4, flags);
//TODO
//pos - movi_addr
long2str(AVI->idx[AVI->n_idx] + 8, pos - (HEADERBYTES - 4));
long2str(AVI->idx[AVI->n_idx] + 12, len);
/* Update counter */
AVI->n_idx++;
@@ -288,6 +346,28 @@ avi_t *AVI_open_output_file(char *filename)
return 0;
}
#if AVI_INDXE_FILE_ENABLE
//创建索引文件
char index_filename[128];
char *dir_path = strrchr(filename, '/');
strcpy(index_filename, filename);
if (dir_path) {
dir_path++;
sprintf(index_filename + (dir_path - filename), "IDX_****.idx");
} else {
sprintf(index_filename, "%s.idx", filename);
}
/* printf("index :%s \n", index_filename); */
AVI->index_fdes = fopen(index_filename, "w+");
if (AVI->index_fdes == NULL) {
printf("fopen index file err \n");
fclose(AVI->fdes);
AVI_errno = AVI_ERR_OPEN;
free(AVI);
return 0;
}
#endif
/* Write out HEADERBYTES bytes, the header will go here
when we are finished with writing */
@@ -298,6 +378,9 @@ avi_t *AVI_open_output_file(char *filename)
if (i != HEADERBYTES) {
fclose(AVI->fdes);
AVI->fdes = NULL;
#if AVI_INDXE_FILE_ENABLE
fdelete(AVI->index_fdes);
#endif
AVI_errno = AVI_ERR_WRITE;
free(AVI);
return 0;
@@ -642,7 +725,7 @@ int avi_update_header(avi_t *AVI)
static int avi_close_output_file(avi_t *AVI)
{
int ret, njunk, sampsize, hasIndex, ms_per_frame, frate, idxerror, flag;
int ret = 0, njunk, sampsize, hasIndex, ms_per_frame, frate, idxerror, flag;
unsigned long movi_len;
int hdrl_start, strl_start, j;
unsigned char AVI_header[HEADERBYTES];
@@ -664,7 +747,43 @@ static int avi_close_output_file(avi_t *AVI)
idxerror = 0;
// fprintf(stderr, "pos=%lu, index_len=%ld \n", AVI->pos, AVI->n_idx*16);
ret = avi_add_chunk(AVI, (unsigned char *)"idx1", (unsigned char *)AVI->idx, AVI->n_idx * 16);
if (AVI->index_fdes) {
//合并索引文件到AVI文件中
int buffer_size = 1024;
unsigned char *index_data = (unsigned char *)malloc(buffer_size);
if (!index_data) {
idxerror = 1;
AVI_errno = AVI_ERR_NO_MEM;
} else {
//读取索引文件内容
/* fflush(AVI->index_fdes); */
u32 index_file_size = flen(AVI->index_fdes);
fseek(AVI->index_fdes, 0, SEEK_SET);
size_t read_bytes = avi_read(AVI->index_fdes, (char *)index_data, buffer_size);
avi_add_idx_chunk(AVI, index_file_size);
while (read_bytes > 0) {
//写入AVI文件中
ret = avi_add_idx_data(AVI, index_data, read_bytes);
hasIndex = (ret == 0);
if (ret) {
idxerror = 1;
AVI_errno = AVI_ERR_WRITE_INDEX;
break;
}
read_bytes = avi_read(AVI->index_fdes, (char *)index_data, buffer_size);
}
free(index_data);
}
//删除索引文件
fdelete(AVI->index_fdes);
//(AVI->index_fdes);
AVI->index_fdes = NULL;
} else {
//内存索引写入AVI文件中
ret = avi_add_chunk(AVI, (unsigned char *)"idx1", (unsigned char *)AVI->idx, AVI->n_idx * 16);
}
hasIndex = (ret == 0);
//fprintf(stderr, "pos=%lu, index_len=%d\n", AVI->pos, hasIndex);
+1
View File
@@ -123,6 +123,7 @@ typedef struct {
typedef struct {
void *fdes; /* File descriptor of AVI file */
void *index_fdes; /* File descriptor of AVI file */
long mode; /* 0 for reading, 1 for writing */
long width; /* Width of a video frame */
+42 -1
View File
@@ -71,6 +71,7 @@
#include "media/includes.h"
#include "audio_config.h"
#include "gpio.h"
#include "app_task.h"
#define LOG_TAG_CONST AVI_VIDEO
#define LOG_TAG "[AVI_VIDEO]"
@@ -122,6 +123,8 @@ static const char *avi_files[] = {
"storage/UI_FAT/C/Btest.avi",
// 可以继续添加更多文件
};
static u16 task_switch_flag;
#define AVI_FILE_COUNT (sizeof(avi_files) / sizeof(avi_files[0]))
static void parse_list_chunk(FILE *file, long list_end, ChunkCallback callback,
@@ -231,7 +234,7 @@ static void pcm_cbuf_deinit(void)
log_info("\n[pcm_cbuf_deinit]mem_status:\n");
mem_stats();
}
__attribute__((weak))
u8 get_avi_audio_status()
{
if (__this == NULL) {
@@ -289,6 +292,13 @@ void avi_play_shutdown(void)
u32 rets;
__asm__ volatile("%0 = rets":"=r"(rets));
log_info("\n\n avi_play_shutdown rets=%x\n\n", rets);
#if TCFG_APP_VIDEO_EN
if (app_get_current_mode_name() == APP_MODE_VIDEO) {
app_mode_stack_clr(APP_MODE_VIDEO);
app_task_switch_back();
}
#endif
if (__this == NULL) {
return ;
}
@@ -1941,11 +1951,42 @@ void *get_avi_player_st_handle()
{
return __this->st;
}
#if TCFG_APP_VIDEO_EN
static void app_video_mode_switch(void *priv)
{
u16 flag = (u16)priv;
if (flag != task_switch_flag) {
log_info("\n\n %s, %d \n\n", __func__, __LINE__);
log_info("flag:%d, %d \n", flag, task_switch_flag);
return;
}
++task_switch_flag;
if (app_get_current_mode_name() == APP_MODE_VIDEO) {
return;
}
int ret = app_task_switch_to(APP_MODE_VIDEO, NULL_VALUE);
if (ret == FALSE) {
sys_timeout_add((void *)(long)task_switch_flag, app_video_mode_switch, 500);
}
}
#endif
void *animig_open(char *name, int window_id, int arg)
{
u8 type = 0;
#if TCFG_APP_VIDEO_EN
if (app_get_current_mode_name() != APP_MODE_VIDEO) {
int ret = app_task_switch_to(APP_MODE_VIDEO, NULL_VALUE);
if (ret == FALSE) {
sys_timeout_add((void *)(long)task_switch_flag, app_video_mode_switch, 500);
}
}
#endif
void *f = fopen(name, "r");
if (f == NULL) {
log_info("open file fail %s", name);
+85 -12
View File
@@ -60,6 +60,7 @@ struct camera_handle {
// JPEG 编码线程
char task_name[32];
u8 task_runing;
u8 task_stoping;
OS_SEM task_kill_sem;
// SPI接收行数统计
@@ -164,6 +165,16 @@ static void camera_jpeg_dec_task(void *priv)
u32 enc_time;
while (hdl->task_runing) {
if (hdl->task_stoping) {
log_char('L');
os_time_dly(1);
if (lbuf_data) {
lbuf_free(lbuf_data);
lbuf_data = NULL;
}
line_cnt = 0;
continue;
}
u8 *chunk = NULL;
/* dma_memcpy_wait_idle(); */
chunk = queue_buf_pop(__this->qbuf);
@@ -222,6 +233,31 @@ static void camera_jpeg_dec_task(void *priv)
if (software_jpegenc_line(jpegenc_hdl, cur_bits, remain_size,
in_buf, DMA_CAMERA_SIZE, line_cnt, &out_bits_size)) {
log_error("software jpgenc line err \n");
printf("jpeg enc err,reset !!!\n");
//pass当前帧
queue_buf_reset(__this->qbuf);
line_cnt = 0;
if (lbuf_data) {
lbuf_free(lbuf_data);
lbuf_data = NULL;
/* os_time_dly(1); */
/* continue; */
}
//reset jpg_hd
software_jpegenc_exit(jpegenc_hdl);
jpegenc_hdl = software_jpegenc_init(
__this->dev->width,
__this->dev->height,
__this->dev->width + SPI_FHEAD_SIZE,
jpeg_qval);
if (!jpegenc_hdl) {
log_error("software jpegenc init err \n");
//下面禁止加打印{
os_sem_post(&__this->task_kill_sem);
os_time_dly(-1);
//}
}
continue;
}
@@ -308,6 +344,9 @@ int camera_spi_deinit()
int camera_manager_start(void)
{
if (!__this) {
return -1;
}
int ret = 0;
mem_stats();
@@ -384,12 +423,12 @@ __err:
int camera_manager_stop(void)
{
printf("%s %d", __func__, __LINE__);
if (!__this) {
return -1;
}
camera_manager_suspend();
camera_spi_deinit();
if (__this->task_runing) {
__this->task_runing = 0;
os_sem_pend(&__this->task_kill_sem, 0);
@@ -397,7 +436,6 @@ int camera_manager_stop(void)
task_kill(__this->task_name);
}
if (__this->qbuf) {
queue_buf_destroy(__this->qbuf);
__this->qbuf = NULL;
@@ -406,14 +444,12 @@ int camera_manager_stop(void)
free_psram(__this->lbuf_ptr);
__this->lbuf_ptr = NULL;
}
for (int i = 0; i < ARRAY_SIZE(__this->dma_recv_buf); i++) {
if (__this->dma_recv_buf[i]) {
free(__this->dma_recv_buf[i]);
__this->dma_recv_buf[i] = NULL;
}
}
return 0;
}
@@ -444,7 +480,39 @@ void camera_manager_suspend(void)
}
__this->dev->supend();
}
void camera_manager_deep_resume(void)
{
if (!__this) {
return ;
}
if (!__this->dev) {
return ;
}
queue_buf_reset(__this->qbuf);
__this->dma_recv_buf_index = 0;
__this->spi_recv_line_cnt = 0;
if (__this->dev->init) {
__this->dev->init();
}
camera_spi_init();
camera_manager_resume();
__this->task_stoping = 0;
}
void camera_manager_deep_suspend(void)
{
if (!__this) {
return ;
}
if (!__this->dev) {
return ;
}
__this->task_stoping = 1;
camera_spi_deinit();
if (__this->dev->deinit) {
__this->dev->deinit();
}
}
static int camera_manager_dev_check(void)
{
struct camera_device *dev = NULL;
@@ -464,8 +532,8 @@ int camera_manager_init(void)
{
ASSERT(!__this);
__this = malloc(sizeof(struct camera_handle));
memset(__this, 0, sizeof(struct camera_handle));
camera_manager_dev_check();
if (!__this->dev) {
return -1;
}
@@ -478,18 +546,22 @@ int camera_manager_init(void)
int camera_manager_deinit(void)
{
int ret = -1;
if (!__this) {
return -1;
}
if (!__this->dev) {
return -1;
goto __err;
}
if (!__this->dev->deinit) {
return -1;
goto __err;
}
ret = __this->dev->deinit();
__err:
if (__this) {
free(__this);
__this = NULL;
}
int ret = __this->dev->deinit();
free(__this);
__this = NULL;
return ret;
}
@@ -545,3 +617,4 @@ int camera_manager_get_dev_fps(int *fps)
}
return -1;
}
@@ -29,6 +29,9 @@ int camera_manager_stop(void);
void camera_manager_resume(void);
void camera_manager_suspend(void);
void camera_manager_deep_resume(void);
void camera_manager_deep_suspend(void);
int camera_manager_init(void);
int camera_manager_deinit(void);
+360
View File
@@ -1,5 +1,363 @@
#include "avilib.h"
#include "media/includes.h"
#include "audio_config.h"
#include "avi_audio_player.h"
//===========================================================================
// 使用avilib解码参考
//===========================================================================
#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 cbuffer_t avi_pcm_cbuf;
extern int jljpeg_stream_src_data_copy(u8 *buf, int size);
#define VIDEO_DEC_TASK_NAME "VIDEO_DEC"
#define PATH_LEN 64
#define PCM_CBUF_SIZE (12*1024)
struct video_player {
s8(*path)[64];
u8 path_number;
u8 path_index;
u8 play_mode;
u8 play_status;
int frame_index;
int frame_rate;
int video_chunks;
int audio_chunks;
u32 start_msec;
u32 pause_msec;
u32 curr_msec;
u32 audio_offset;
u16 tick_id;
void *dec_hd;
void (*ui_refresh_cb)(int status);
u8 *audio_buf;
OS_SEM task_kill_sem;
} *__player;
#define __this (__player)
enum {
VIDEO_DEC_MSG_INIT,
VIDEO_DEC_MSG_EXIT,
VIDEO_DEC_MSG_START,
VIDEO_DEC_MSG_STOP,
VIDEO_DEC_MSG_UPDATE_FILE,
VIDEO_DEC_MSG_TICK,
VIDEO_DEC_MSG_SUSPEND,
VIDEO_DEC_MSG_RESUME,
};
enum {
VIDEO_DEC_PLAY_MODE_SINGLE,//单次播放
VIDEO_DEC_PLAY_MODE_SINGLE_LOOP,//单次循环
VIDEO_DEC_PLAY_MODE_LIST,//列表播放,不循环
VIDEO_DEC_PLAY_MODE_LIST_LOOP,//列表播放,循环
};
#if 0//使用video_dec解码时打开
u8 get_avi_audio_status()
{
if (__this == NULL) {
return 0;
}
return 1;
}
#endif
static int video_msg_post(int msg, void *priv, int priv_len)
{
int err = os_taskq_post_type(VIDEO_DEC_TASK_NAME, msg, priv_len, priv);
if (err) {
printf("%s err::%d\n", __func__, err);
}
return err;
}
static int video_dec_player_update_dec_hd()
{
if (__this->dec_hd) {
AVI_close(__this->dec_hd);
__this->dec_hd = NULL;
}
printf("%s path:%s\n", __func__, (char *)__this->path[__this->path_index]);
__this->dec_hd = AVI_open_input_file((char *)__this->path[__this->path_index], 1);
__this->frame_rate = AVI_frame_rate(__this->dec_hd);
__this->audio_chunks = AVI_audio_chunks(__this->dec_hd);
__this->video_chunks = AVI_video_frames(__this->dec_hd);
__this->frame_index = 0;
return 0;
}
static void video_dec_tick_cb(void *p)
{
video_msg_post(VIDEO_DEC_MSG_TICK, NULL, 0);
}
int video_dec_tick_update()
{
video_msg_post(VIDEO_DEC_MSG_TICK, NULL, 0);
return 0;
}
static int video_dec_player_tick()
{
if (!__this->frame_index) {
__this->start_msec = jiffies_msec();
}
__this->curr_msec = jiffies_msec2offset(__this->start_msec, jiffies_msec());
int real_frame_index = __this->curr_msec * __this->frame_rate / 1000;
/* printf("%s rf:%d total:%d",__func__,real_frame_index,__this->video_chunks); */
if (real_frame_index >= __this->video_chunks) {
//stop
if (__this->tick_id) {
usr_timer_del(__this->tick_id);
__this->tick_id = 0;
}
return -1;
}
AVI_set_video_position(__this->dec_hd, real_frame_index);
int keyframe;
u32 offset = 0;
int frame_len = AVI_frame_size(__this->dec_hd, real_frame_index);
u8 *file_buf = malloc(20 * 1024);
if (frame_len <= 20 * 1024) {
int file_len = AVI_read_frame(__this->dec_hd, (char *)file_buf, &keyframe);
//copy_to_ui
if (!jljpeg_stream_src_data_copy(file_buf, file_len)) {
if (__this->ui_refresh_cb) {
__this->ui_refresh_cb(0);
}
}
}
int exit = 0;
if (__this->video_chunks) {
real_frame_index = real_frame_index * __this->audio_chunks / __this->video_chunks;
}
/* printf("%s %d->%d(%d)",__func__,__this->frame_index,real_frame_index,__this->audio_chunks); */
for (int i = __this->frame_index ; i < real_frame_index; i++) {
int audio_chunk_size = AVI_audio_size(__this->dec_hd, i);
AVI_set_audio_position(__this->dec_hd, __this->audio_offset);
int file_len = AVI_read_audio_chunk(__this->dec_hd, (char *)file_buf);
//copy_to_pcm_player
int len = file_len;
u8 *ptr = file_buf;
while (len) {
int w = cbuf_write(&avi_pcm_cbuf, ptr, len);
/* printf("[w] len:%d wl:%d",len,w); */
if (w == 0) {
/* os_time_dly(1); */
exit = 1;
break;
}
ptr += w;
len -= w;
}
if (exit) {
__this->frame_index = i;
break;
}
/* printf("[cw] i:%d chunks:%d filelen:%d",i,audio_chunk_size,file_len); */
//todo
__this->audio_offset += audio_chunk_size;
}
if (!exit) {
__this->frame_index = real_frame_index;
}
if (!__this->frame_index) {
__this->frame_index ++;
}
free(file_buf);
return 0;
}
static int video_dec_player_start()
{
int msec = (int)1000 / __this->frame_rate; // /2?
if (__this->tick_id) {
usr_timer_del(__this->tick_id);
}
__this->tick_id = usr_timer_add(NULL, video_dec_tick_cb, msec, 1);
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, app_audio_volume_max_query(AppVol_MUSIC), NULL); // 音量状态设置
audio_dac_set_volume(&dac_hdl, app_audio_volume_max_query(AppVol_MUSIC) / 100); // dac 音量设置
struct avi_audio_player_param param = {0};
param.coding_type = AUDIO_CODING_PCM;
param.channel_mode = (AVI_audio_channels(__this->dec_hd) == 1) ? AUDIO_CH_L : AUDIO_CH_MIX;
param.sample_rate = AVI_audio_rate(__this->dec_hd);
param.bit_rate = AVI_audio_channels(__this->dec_hd) * AVI_audio_rate(__this->dec_hd) * AVI_audio_bits(__this->dec_hd);
param.type = AVI_SERVICE_VOICE;
printf("simple_rate:%d channel:%d bitrate:%d", param.sample_rate, param.channel_mode, param.bit_rate);
// 打开AI voice播放
int ret = avi_audio_player_open(NULL, 0, &param);
return 0;
}
static int video_dec_player_stop()
{
avi_audio_player_close(0);
if (__this->tick_id) {
usr_timer_del(__this->tick_id);
__this->tick_id = 0;
}
if (__this->audio_buf) {
free(__this->audio_buf);
__this->audio_buf = NULL;
}
if (__this->dec_hd) {
AVI_close(__this->dec_hd);
__this->dec_hd = NULL;
}
return 0;
}
static int video_dec_player_suspend()
{
/* if(__this->tick_id){ */
/* usr_timer_del(__this->tick_id); */
/* } */
return 0;
}
static int video_dec_player_resume()
{
/* int msec = (int)1000/__this->frame_rate;// /2? */
/* if(__this->tick_id){ */
/* usr_timer_del(__this->tick_id); */
/* } */
/* __this->tick_id = usr_timer_add(NULL, video_dec_tick_cb,msec,1); */
return 0;
}
static void video_dec_task(void *p)
{
int msg[32];
int ret;
while (1) {
ret = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
printf("%s msg:%d \n", __func__, msg[0]);
if (!__this) {
break;
}
switch (msg[0]) {
case VIDEO_DEC_MSG_TICK:
video_dec_player_tick();
break;
case VIDEO_DEC_MSG_UPDATE_FILE:
video_dec_player_update_dec_hd();
break;
case VIDEO_DEC_MSG_START:
video_dec_player_start();
break;
case VIDEO_DEC_MSG_STOP:
video_dec_player_stop();
break;
case VIDEO_DEC_MSG_SUSPEND:
video_dec_player_suspend();
break;
case VIDEO_DEC_MSG_RESUME:
video_dec_player_resume();
break;
case VIDEO_DEC_MSG_EXIT:
os_sem_post(&__this->task_kill_sem);
os_time_dly(-1);
break;
default:
break;
}
}
}
int video_dec_init()
{
if (!__this) {
__this = malloc(sizeof(struct video_player));
memset(__this, 0, sizeof(struct video_player));
}
if (!__this->audio_buf) {
__this->audio_buf = malloc(PCM_CBUF_SIZE);
}
cbuf_init(&avi_pcm_cbuf, __this->audio_buf, PCM_CBUF_SIZE);
os_sem_create(&__this->task_kill_sem, 0);
//create_task
int ret = os_task_create(video_dec_task, NULL, 8, 1024, 1024, VIDEO_DEC_TASK_NAME);
if (ret) {
printf("%s err\n", __func__);
free(__this);
__this = NULL;
}
return ret;
}
int video_dec_deinit()
{
//kill
if (__this->tick_id) {
usr_timer_del(__this->tick_id);
__this->tick_id = 0;
}
int ret = video_msg_post(VIDEO_DEC_MSG_EXIT, NULL, 0);
os_sem_pend(&__this->task_kill_sem, 0);
os_sem_del(&__this->task_kill_sem, OS_DEL_ALWAYS);
task_kill(VIDEO_DEC_TASK_NAME);
//free
if (__this->audio_buf) {
free(__this->audio_buf);
__this->audio_buf = NULL;
}
if (__this->dec_hd) {
AVI_close(__this->dec_hd);
__this->dec_hd = NULL;
}
if (__this) {
free(__this);
__this = NULL;
}
return 0;
}
int video_dec_set_path(s8(*path)[64], u8 path_number)
{
__this->path = path;
__this->path_number = path_number;
return 0;
}
int video_dec_start(u8 index, u8 mode)
{
if ((index < __this->path_number) && (index >= 0)) {
__this->frame_index = index;
} else {
__this->frame_index = 0;
}
int ret = 0;
ret += video_msg_post(VIDEO_DEC_MSG_UPDATE_FILE, NULL, 0);
ret += video_msg_post(VIDEO_DEC_MSG_START, NULL, 0);
return 0;
}
int video_dec_stop()
{
int ret = video_msg_post(VIDEO_DEC_MSG_STOP, NULL, 0);
return ret;
}
int video_dec_refresh_cb_register(void (*cb)(int status))
{
if (!__this) {
printf("%s not find\n", __func__);
return -1;
}
__this->ui_refresh_cb = cb;
return 0;
}
#if 0
//读取AVI文件视频帧和音频帧行写卡在PC上验证
int video_dec_demo(void)
{
@@ -63,3 +421,5 @@ int video_dec_demo(void)
/* os_time_dly(-1); */
return 0;
}
#endif
+267 -24
View File
@@ -31,11 +31,15 @@ struct video_rec_handle {
int video_rate;
int sample_rate;
void (*ui_refresh_cb)(int status);
int bytes_per_sample;
};
static struct video_rec_handle *video_rec;
#define __this (video_rec)
//摄像头流程 camera_manager_init->start->read->read_done->read...->stop->exit.
extern uint32_t timer_get_ms(void);
//摄像头流程 bf30a2_camera_init->start->read->read_done->read...->stop->exit.
//麦克风流程 pcm_data_init->read->read_done->read...->exit.
extern int jljpeg_stream_src_data_copy(u8 *buf, int size);
@@ -181,17 +185,17 @@ static void video_show_task(void *priv)
frame_cnt = 0;
/* break; */
} else if (msg[0] == Q_AVI_TASK_REC_STOP) {
log_debug("avi task rec stop!\n");
if (out_fd) {
ret = AVI_close(out_fd);
if (ret) {
log_error("camera devide avi close err :%d \n", ret);
ASSERT(0);
__this->write_error = 1;
/* ASSERT(0); */
} else {
log_debug("avi write success \n");
out_fd = NULL;
}
out_fd = NULL;
}
if (__this->pcm_hdl) {
pcm_data_exit(__this->pcm_hdl);
@@ -229,6 +233,23 @@ static void video_show_task(void *priv)
__this->write_error = AVI_write_frame(out_fd, (char *)jpeg_data, jpeg_data_len, 1);
}
camera_manager_read_done(jpeg_data);
#if 0
static int cam_last_msec = 0;
static int cam_frame_sum = 0;
static int cam_frame_cnt = 0;
if (cam_last_msec) {
u32 cur_msec = jiffies_msec();
u32 offset = jiffies_msec2offset(cam_last_msec, cur_msec);
cam_frame_sum += offset;
cam_frame_cnt ++;
if (cam_frame_cnt && cam_frame_sum) {
u32 avg = cam_frame_sum / cam_frame_cnt;
u32 fps = 1000 / avg;
printf("CAM avg:%d fps:%d \n", avg, fps);
}
}
cam_last_msec = jiffies_msec();
#endif
}
if (out_fd && (cyc_time != -1)) {
@@ -287,14 +308,12 @@ int jlcamera_video_rec_init(void)
//初始化驱动
ret = camera_manager_init();
if (ret) {
//TODO
return -1;
goto __err;
}
//启动摄像头
ret = camera_manager_start();
if (ret) {
//TODO
return -1;
goto __err;
}
int fps;
camera_manager_get_dev_fps(&fps);
@@ -307,11 +326,19 @@ int jlcamera_video_rec_init(void)
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)) {
log_error("avi task create fail \n");
//TODO
return -1;
goto __err;
}
return 0;
__err:
log_error("%s err\n", __func__);
camera_manager_stop();
camera_manager_deinit();
if (__this) {
free(__this);
__this = NULL;
}
return -1;
}
/* ------------------------------------------------------------------------------------*/
/**
@@ -322,22 +349,21 @@ int jlcamera_video_rec_init(void)
/* ------------------------------------------------------------------------------------*/
int jlcamera_video_rec_deinit(void)
{
printf("%s %d", __func__, __LINE__);
/* printf("%s %d", __func__, __LINE__); */
/* void dma_memcpy_wait_idle(void); */
/* dma_memcpy_wait_idle(); */
camera_manager_stop();
OS_SEM task_kill_sem;
os_sem_create(&task_kill_sem, 0);
int msg = (int)&task_kill_sem;
os_taskq_del_type(__this->avi_task_name, Q_AVI_TASK_REC_START);
os_taskq_del_type(__this->avi_task_name, Q_AVI_TASK_REC_STOP);
os_taskq_post_type(__this->avi_task_name, Q_AVI_TASK_KILL, 1, &msg);
os_sem_pend(&task_kill_sem, 0);
os_sem_del(&task_kill_sem, OS_DEL_ALWAYS);
task_kill(__this->avi_task_name);
if (__this) {
OS_SEM task_kill_sem;
os_sem_create(&task_kill_sem, 0);
int msg = (int)&task_kill_sem;
os_taskq_del_type(__this->avi_task_name, Q_AVI_TASK_REC_START);
os_taskq_del_type(__this->avi_task_name, Q_AVI_TASK_REC_STOP);
os_taskq_post_type(__this->avi_task_name, Q_AVI_TASK_KILL, 1, &msg);
os_sem_pend(&task_kill_sem, 0);
os_sem_del(&task_kill_sem, OS_DEL_ALWAYS);
task_kill(__this->avi_task_name);
}
camera_manager_deinit();
clock_unlock("camera_video");
@@ -442,6 +468,214 @@ static void avi_task(void *priv)
}
}
//基于音频时间进行补帧(音频包太大有误差)
static void avi_task_dup1(void *priv)
{
int ret = 0;
int msg[8];
int frame_cnt = 0;
int cyc_time = 30; //循环录影时间,单位秒
u8 *pcm_data, *jpeg_data;
int pcm_data_len, jpeg_data_len;
char *filename = "storage/sd0/C/VID_****.AVI";
avi_t *out_fd = AVI_open_output_file(filename);
if (out_fd == NULL) {
printf("open file erro\n");
os_time_dly(-1);
}
AVI_set_video(out_fd, BF30A2_INPUT_W, BF30A2_INPUT_H, __this->video_rate, "MJPG");
AVI_set_audio(out_fd, 1, __this->sample_rate, 16, WAVE_FORMAT_PCM, 0);//默认单声道s16格式
// --- 用于补帧的统计变量 ---
u32 total_audio_bytes = 0; // 累加收到并写入的音频字节数
const int bytes_per_sample = __this->bytes_per_sample;
const int video_rate = __this->video_rate;
const int sample_rate = __this->sample_rate;
int dup_frame_cnt = 0; //调试使用
while (1) {
u8 read_data = 0;
if (os_taskq_accept(ARRAY_SIZE(msg), msg) == OS_TASKQ) {
if (msg[0] == Q_AVI_TASK_KILL) {
if (out_fd) {
AVI_close(out_fd);
}
printf("avi task exit !\n");
os_sem_post((OS_SEM *)msg[1]);
os_time_dly(-1);
break;
}
}
if (pcm_data_read(__this->pcm_hdl, &pcm_data, &pcm_data_len) == 0) {
read_data = 1;
AVI_write_audio(out_fd, (char *)pcm_data, pcm_data_len);
// 累加已写入的音频字节(用于推算应该产生的视频帧数)
total_audio_bytes += pcm_data_len;
pcm_data_read_done(__this->pcm_hdl, pcm_data);
}
if (bf30a2_camera_data_read(&jpeg_data, &jpeg_data_len) == 0) {
read_data = 1;
frame_cnt ++;
AVI_write_frame(out_fd, (char *)jpeg_data, jpeg_data_len, 1);
bf30a2_camera_read_done(jpeg_data);
// 基于音频进度推算并补帧
if (total_audio_bytes >= sample_rate * bytes_per_sample) {
u32 total_audio_samples = total_audio_bytes / bytes_per_sample; // 整数
u32 expected_frames = (total_audio_samples * video_rate) / sample_rate;
if (expected_frames > frame_cnt) {
ret = AVI_dup_frame(out_fd);
if (!ret) {
dup_frame_cnt++;
frame_cnt++;
printf("avi dup video frame :%d cur frame:%d \n", dup_frame_cnt, frame_cnt);
}
}
}
}
if (frame_cnt >= __this->video_rate * cyc_time) {
ret = AVI_close(out_fd);
if (ret) {
printf("bf30a2 avi close err :%d \n", ret);
} else {
printf("avi write success \n");
}
out_fd = AVI_open_output_file(filename);
if (out_fd == NULL) {
printf("open file erro\n");
break;
}
AVI_set_video(out_fd, BF30A2_INPUT_W, BF30A2_INPUT_H, __this->video_rate, "MJPG");
AVI_set_audio(out_fd, 1, __this->sample_rate, 16, WAVE_FORMAT_PCM, 0);//默认单声道s16格式
frame_cnt = 0;
dup_frame_cnt = 0;
total_audio_bytes = 0;
}
//没有读到数据
if (!read_data) {
//根据音频包计算延时
u32 delay_ms = ((float)__this->aframe_size / (__this->sample_rate * 2)) * 1000;
u32 tick = delay_ms / 10;
os_time_dly(tick + 1);
}
}
}
//基于系统时间进行补帧
static void avi_task_dup2(void *priv)
{
int ret = 0;
int msg[8];
int frame_cnt = 0;
int cyc_time = 30; //循环录影时间,单位秒
u8 *pcm_data, *jpeg_data;
int pcm_data_len, jpeg_data_len;
char *filename = "storage/sd0/C/VID_****.AVI";
avi_t *out_fd = AVI_open_output_file(filename);
if (out_fd == NULL) {
printf("open file erro\n");
os_time_dly(-1);
}
AVI_set_video(out_fd, BF30A2_INPUT_W, BF30A2_INPUT_H, __this->video_rate, "MJPG");
AVI_set_audio(out_fd, 1, __this->sample_rate, 16, WAVE_FORMAT_PCM, 0);//默认单声道s16格式
// --- 用于补帧的统计变量 ---
const int video_rate = __this->video_rate;
u32 start_ms = timer_get_ms(); // 每次 open file 时重置
int dup_frame_cnt = 0; // 调试使用
while (1) {
u8 read_data = 0;
if (os_taskq_accept(ARRAY_SIZE(msg), msg) == OS_TASKQ) {
if (msg[0] == Q_AVI_TASK_KILL) {
if (out_fd) {
AVI_close(out_fd);
}
printf("avi task exit !\n");
os_sem_post((OS_SEM *)msg[1]);
os_time_dly(-1);
break;
}
}
if (pcm_data_read(__this->pcm_hdl, &pcm_data, &pcm_data_len) == 0) {
read_data = 1;
AVI_write_audio(out_fd, (char *)pcm_data, pcm_data_len);
pcm_data_read_done(__this->pcm_hdl, pcm_data);
}
if (bf30a2_camera_data_read(&jpeg_data, &jpeg_data_len) == 0) {
read_data = 1;
frame_cnt ++;
AVI_write_frame(out_fd, (char *)jpeg_data, jpeg_data_len, 1);
bf30a2_camera_read_done(jpeg_data);
// --------- 基于系统时钟检查是否需要补帧 ---------
u32 now = timer_get_ms();
u32 elapsed_ms = now - start_ms;
u32 expected_frames = (elapsed_ms * video_rate) / 1000;
if (expected_frames > frame_cnt) {
ret = AVI_dup_frame(out_fd);
if (!ret) {
dup_frame_cnt++;
frame_cnt++;
printf("avi dup video frame :%d cur frame:%d \n", dup_frame_cnt, frame_cnt);
}
}
}
if (frame_cnt >= __this->video_rate * cyc_time) {
ret = AVI_close(out_fd);
if (ret) {
printf("bf30a2 avi close err :%d \n", ret);
} else {
printf("avi write success \n");
}
out_fd = AVI_open_output_file(filename);
if (out_fd == NULL) {
printf("open file erro\n");
break;
}
AVI_set_video(out_fd, BF30A2_INPUT_W, BF30A2_INPUT_H, __this->video_rate, "MJPG");
AVI_set_audio(out_fd, 1, __this->sample_rate, 16, WAVE_FORMAT_PCM, 0);//默认单声道s16格式
frame_cnt = 0;
dup_frame_cnt = 0;
start_ms = timer_get_ms();
}
//没有读到数据
if (!read_data) {
//根据音频包计算延时
u32 delay_ms = ((float)__this->aframe_size / (__this->sample_rate * 2)) * 1000;
u32 tick = delay_ms / 10;
os_time_dly(tick + 1);
}
}
}
int video_rec_start_demo(void)
{
int ret = 0;
@@ -458,7 +692,8 @@ int video_rec_start_demo(void)
}
__this->video_rate = BF30A2_INPUT_FPS / 2; //视频帧率
__this->sample_rate = 8000; //音频采样率
__this->sample_rate = 8000; //音频采样率
__this->bytes_per_sample = 2; // 单声道 s16 -> 每采样 2 字节
__this->aframe_size = 4096;
__this->pcm_hdl = pcm_data_init(__this->sample_rate, __this->aframe_size, __this->aframe_size * 10);
if (!__this->pcm_hdl) {
@@ -473,6 +708,14 @@ int video_rec_start_demo(void)
return -1;
}
/* __this->video_rate = 20; //可配置一个摄像头达不到的帧率,模拟需要补帧的情况 */
/* //根据系统时间进行补帧 */
/* if (os_task_create(avi_task_dup2, __this, 8, 1024, 1024, __this->avi_task_name)) { */
/* printf("avi task create fail \n"); */
/* //TODO */
/* return -1; */
/* } */
return 0;
}