426 lines
12 KiB
C
426 lines
12 KiB
C
#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, ¶m);
|
|
|
|
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)
|
|
{
|
|
char *filename = "storage/sd0/C/VID_0001.AVI";
|
|
avi_t *in_fd = AVI_open_input_file(filename, 1);
|
|
if (in_fd == NULL) {
|
|
printf("AVI_open_input_file err \n");
|
|
return -1;
|
|
}
|
|
|
|
u8 *file_buf = malloc(20 * 1024);
|
|
if (!file_buf) {
|
|
printf("file_buf malloc err\n");
|
|
return -1;
|
|
}
|
|
|
|
int total_frame = AVI_video_frames(in_fd);
|
|
printf("AVI total video frame:%d \n", total_frame);
|
|
int audio_chunks = AVI_audio_chunks(in_fd);
|
|
printf("AVI total audio frame:%d \n", audio_chunks);
|
|
|
|
char save_file_name[64];
|
|
int i = 0;
|
|
for (i = 0; i < total_frame; i++) {
|
|
AVI_set_video_position(in_fd, i);
|
|
|
|
int keyframe;
|
|
int file_len = AVI_read_frame(in_fd, (char *)file_buf, &keyframe);
|
|
if (file_len > 0) {
|
|
printf("write video frame:%d \n", i);
|
|
snprintf(save_file_name, sizeof(save_file_name), "storage/sd0/C/avi_test/jpg_%d.jpg", i);
|
|
FILE *fd = fopen(save_file_name, "w+");
|
|
fwrite(file_buf, 1, file_len, fd);
|
|
fclose(fd);
|
|
}
|
|
}
|
|
|
|
snprintf(save_file_name, sizeof(save_file_name), "storage/sd0/C/avi_test/test.pcm");
|
|
FILE *fd = fopen(save_file_name, "w+");
|
|
|
|
u32 offset = 0;
|
|
for (i = 0; i < audio_chunks; i++) {
|
|
int audio_chunk_size = AVI_audio_size(in_fd, i);
|
|
AVI_set_audio_position(in_fd, offset);
|
|
|
|
|
|
int file_len = AVI_read_audio_chunk(in_fd, (char *)file_buf);
|
|
if (file_len > 0) {
|
|
printf("write audio frame:%d size:%d chunk_size:%d \n", i, file_len, audio_chunk_size);
|
|
fwrite(file_buf, 1, file_len, fd);
|
|
}
|
|
|
|
offset += audio_chunk_size;
|
|
}
|
|
fclose(fd);
|
|
|
|
|
|
AVI_close(in_fd);
|
|
free(file_buf);
|
|
|
|
/* os_time_dly(-1); */
|
|
return 0;
|
|
}
|
|
|
|
#endif
|