422 lines
14 KiB
C
422 lines
14 KiB
C
|
|
#include "avi_player_msi.h"
|
||
|
|
|
||
|
|
/*****************************************************************************
|
||
|
|
* AVI1.0
|
||
|
|
*****************************************************************************/
|
||
|
|
|
||
|
|
// data申请空间函数
|
||
|
|
#define STREAM_MALLOC av_psram_malloc
|
||
|
|
#define STREAM_FREE av_psram_free
|
||
|
|
#define STREAM_ZALLOC av_psram_zalloc
|
||
|
|
|
||
|
|
// 结构体申请空间函数
|
||
|
|
#define STREAM_LIBC_MALLOC av_malloc
|
||
|
|
#define STREAM_LIBC_FREE av_free
|
||
|
|
#define STREAM_LIBC_ZALLOC av_zalloc
|
||
|
|
|
||
|
|
#define AVI_PLAYER_MAX_TX_NUM 8
|
||
|
|
|
||
|
|
#define AVI_STREAM_NAME (64)
|
||
|
|
|
||
|
|
#define AUDIO_TMP_BUF_SIZE (1024)
|
||
|
|
|
||
|
|
struct player_msg_s
|
||
|
|
{
|
||
|
|
void *task;
|
||
|
|
struct msi *msi;
|
||
|
|
struct fbpool tx_pool;
|
||
|
|
uint32_t magic;
|
||
|
|
struct avi_msg_s *avi_msg;
|
||
|
|
struct fast_index_list *g_fast_index_list;
|
||
|
|
|
||
|
|
uint32_t audio_frame_number; //读取索引的长度
|
||
|
|
uint32_t audio_frame_number_send; //已经播放的长度
|
||
|
|
uint32_t frame_number; //当前读取的帧
|
||
|
|
uint32_t not_read_size; //剩余未读取的空间长度
|
||
|
|
uint32_t cache_addr; //读取下一次的偏移地址
|
||
|
|
|
||
|
|
struct framebuff *data_tmp;
|
||
|
|
struct framebuff *audio_data_tmp;
|
||
|
|
|
||
|
|
int32_t locate_frame_number; //跳转视频的偏移
|
||
|
|
uint8_t running: 1, thread_stop : 1, speed_flag:1, rev: 5;
|
||
|
|
};
|
||
|
|
|
||
|
|
static void avi_player_thread(void *d)
|
||
|
|
{
|
||
|
|
struct player_msg_s *msg = (struct player_msg_s *)d;
|
||
|
|
struct msi *msi = msg->msi;
|
||
|
|
struct avi_msg_s *avi_msg = msg->avi_msg;
|
||
|
|
uint32_t magic = 0;
|
||
|
|
uint8_t *audio_tmp_buf = (uint8_t *)STREAM_LIBC_MALLOC(AUDIO_TMP_BUF_SIZE);
|
||
|
|
uint32_t now_audio_offset = 0;
|
||
|
|
uint32_t video_time = 0;
|
||
|
|
uint32_t audio_time = 0;
|
||
|
|
if (!avi_msg->sample)
|
||
|
|
{
|
||
|
|
audio_time = ~0; //没有音频
|
||
|
|
}
|
||
|
|
while (!msg->thread_stop)
|
||
|
|
{
|
||
|
|
if (!msi->enable)
|
||
|
|
{
|
||
|
|
//这里是否可以考虑先去建立部分快速索引?
|
||
|
|
goto avi_player_thread_end;
|
||
|
|
}
|
||
|
|
//正常这里去建立快速索引
|
||
|
|
gen_fast_index_list(avi_msg);
|
||
|
|
|
||
|
|
//判断一下是否要快进或者快退?
|
||
|
|
//所以先设置locate_frame_number,再配置speed_flag
|
||
|
|
if (msg->speed_flag)
|
||
|
|
{
|
||
|
|
msg->speed_flag = 0;
|
||
|
|
locate_avi_index(avi_msg,msg->locate_frame_number);
|
||
|
|
msg->frame_number = msg->locate_frame_number;
|
||
|
|
magic = msg->magic;
|
||
|
|
video_time = msg->frame_number * 1000 / avi_msg->fps;
|
||
|
|
|
||
|
|
//os_printf("msg->frame_number:%d\n",msg->frame_number);
|
||
|
|
|
||
|
|
if (avi_msg->sample)
|
||
|
|
{
|
||
|
|
//重置音频,音频是跟着视频走的,表示音频和video同步
|
||
|
|
msg->audio_frame_number_send = video_time * avi_msg->sample * 2 / 1000;;
|
||
|
|
audio_time = msg->audio_frame_number_send * 500 / avi_msg->sample;
|
||
|
|
now_audio_offset = 0;
|
||
|
|
|
||
|
|
//实际音频索引的位置应该在前面,意思是快速索引在前面,实际播放时间可能在后面,后面需要慢慢去轮询读取到对应的音频
|
||
|
|
msg->audio_frame_number = avi_msg->audio_frame_num;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
//如果视频比音频播放前,就需要去读取音频了
|
||
|
|
if (video_time > audio_time)
|
||
|
|
{
|
||
|
|
//os_printf("goto avi_player_thread_audio_start:%d\n",__LINE__);
|
||
|
|
goto avi_player_thread_audio_start;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
if (!msg->data_tmp)
|
||
|
|
{
|
||
|
|
msg->data_tmp = fbpool_get(&msg->tx_pool, 0, msi);
|
||
|
|
if (!msg->data_tmp)
|
||
|
|
{
|
||
|
|
goto avi_player_thread_audio_start;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
//理论要判断当前播放的视频帧是否已经最大,最大就直接退出
|
||
|
|
uint32_t offset;
|
||
|
|
uint32_t size = 0;
|
||
|
|
avi_read_next_index(avi_msg, &offset, &size, &msg->frame_number);
|
||
|
|
if (!size)
|
||
|
|
{
|
||
|
|
// os_printf("goto avi_player_thread_audio_start:%d\n",__LINE__);
|
||
|
|
goto avi_player_thread_audio_start;
|
||
|
|
}
|
||
|
|
uint8_t *fb_video_data = (uint8_t *)STREAM_MALLOC(size);
|
||
|
|
if (fb_video_data)
|
||
|
|
{
|
||
|
|
osal_fseek(avi_msg->fp, offset);
|
||
|
|
osal_fread(fb_video_data, 1, size, avi_msg->fp);
|
||
|
|
sys_dcache_clean_range((uint32_t*)fb_video_data, size);
|
||
|
|
msg->data_tmp->data = (uint8_t *)fb_video_data;
|
||
|
|
msg->data_tmp->mtype = F_JPG;
|
||
|
|
msg->data_tmp->stype = FSTYPE_YUV_P0;
|
||
|
|
//转换成ms
|
||
|
|
//os_printf("msg->avi_msg->fps:%d\t%d\n",msg->avi_msg->fps,msg->frame_number*1000/msg->avi_msg->fps);
|
||
|
|
msg->data_tmp->time = msg->frame_number * 1000 / msg->avi_msg->fps;
|
||
|
|
msg->data_tmp->len = size;
|
||
|
|
|
||
|
|
video_time = msg->frame_number * 1000 / msg->avi_msg->fps;
|
||
|
|
|
||
|
|
msg->data_tmp->datatag = magic;
|
||
|
|
msi_output_fb(msi, msg->data_tmp);
|
||
|
|
msg->data_tmp = NULL;
|
||
|
|
_os_printf("(V:%d)",size);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
avi_player_thread_audio_start:
|
||
|
|
|
||
|
|
if (!avi_msg->sample)
|
||
|
|
{
|
||
|
|
goto avi_player_thread_end;
|
||
|
|
}
|
||
|
|
if (video_time < audio_time)
|
||
|
|
{
|
||
|
|
//os_printf("audio_time:%d\tvideo_time:%d\n",audio_time,video_time);
|
||
|
|
goto avi_player_thread_end;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
if (!msg->audio_data_tmp)
|
||
|
|
{
|
||
|
|
msg->audio_data_tmp = fbpool_get(&msg->tx_pool, 0, msi);
|
||
|
|
if (!msg->audio_data_tmp)
|
||
|
|
{
|
||
|
|
goto avi_player_thread_end;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//先去获取一个音频节点
|
||
|
|
if (msg->audio_data_tmp)
|
||
|
|
{
|
||
|
|
|
||
|
|
//os_printf("audio_time:%d\tvideo_time:%d\n",audio_time,video_time);
|
||
|
|
//为stream申请音频的空间,然后读取音频发送
|
||
|
|
uint8_t *fb_audio_data = (uint8_t *)STREAM_LIBC_MALLOC(AUDIO_TMP_BUF_SIZE);
|
||
|
|
//申请到空间,就将音频先读取到缓冲区,没有空间,则下次重新尝试
|
||
|
|
if (fb_audio_data)
|
||
|
|
{
|
||
|
|
uint32_t max_read_len;
|
||
|
|
uint32_t read_len = 0;
|
||
|
|
max_read_len = AUDIO_TMP_BUF_SIZE - now_audio_offset;
|
||
|
|
while (max_read_len)
|
||
|
|
{
|
||
|
|
|
||
|
|
//读取够音频数据长度,然后通过流发送,然后再将剩下的拷贝到缓冲区,由于
|
||
|
|
avi_read_next_audio_index(avi_msg, &offset, &size, &msg->audio_frame_number);
|
||
|
|
//音频已经读取完毕了
|
||
|
|
if (!size)
|
||
|
|
{
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
osal_fseek(avi_msg->fp, offset);
|
||
|
|
read_len = (max_read_len > size) ? size : max_read_len;
|
||
|
|
osal_fread(audio_tmp_buf + now_audio_offset, 1, read_len, avi_msg->fp);
|
||
|
|
now_audio_offset += read_len;
|
||
|
|
max_read_len -= read_len;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!now_audio_offset) {
|
||
|
|
avi_msg->sample = 0;
|
||
|
|
audio_time = ~0;
|
||
|
|
msi_delete_fb(NULL, msg->audio_data_tmp);
|
||
|
|
msg->audio_data_tmp = NULL;
|
||
|
|
goto avi_player_thread_end;
|
||
|
|
}
|
||
|
|
|
||
|
|
//流发送,先拷贝数据
|
||
|
|
hw_memcpy(fb_audio_data, audio_tmp_buf, now_audio_offset);
|
||
|
|
msg->audio_data_tmp->data = (uint8_t *)fb_audio_data;
|
||
|
|
msg->audio_data_tmp->mtype = F_AUDIO;
|
||
|
|
msg->audio_data_tmp->stype = FSTYPE_AUDIO_PCM;
|
||
|
|
//转换成ms
|
||
|
|
//os_printf("msg->avi_msg->fps:%d\t%d\n",msg->avi_msg->fps,msg->frame_number*1000/msg->avi_msg->fps);
|
||
|
|
//设置音频的时间
|
||
|
|
msg->audio_data_tmp->time = msg->audio_frame_number_send * 500 / avi_msg->sample;
|
||
|
|
msg->audio_data_tmp->len = now_audio_offset;
|
||
|
|
msg->audio_data_tmp->datatag = magic;
|
||
|
|
_os_printf("(A:%d\t%d)",now_audio_offset,avi_msg->sample);
|
||
|
|
|
||
|
|
msi_output_fb(msi, msg->audio_data_tmp);
|
||
|
|
|
||
|
|
msg->audio_data_tmp = NULL;
|
||
|
|
msg->audio_frame_number_send += now_audio_offset;
|
||
|
|
|
||
|
|
audio_time = msg->audio_frame_number_send * 500 / avi_msg->sample;
|
||
|
|
|
||
|
|
//将剩余的数据拷贝
|
||
|
|
now_audio_offset = size - read_len;
|
||
|
|
//os_printf("remain:%d\n",now_audio_offset);
|
||
|
|
//如果有剩余,紧接着读取数据就可以了
|
||
|
|
if (now_audio_offset)
|
||
|
|
{
|
||
|
|
osal_fread(audio_tmp_buf, 1, now_audio_offset, avi_msg->fp);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
avi_player_thread_end:
|
||
|
|
os_sleep_ms(1);
|
||
|
|
}
|
||
|
|
msg->running = 0;
|
||
|
|
|
||
|
|
if (audio_tmp_buf)
|
||
|
|
{
|
||
|
|
STREAM_LIBC_FREE(audio_tmp_buf);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
static int32_t avi_player_action(struct msi *msi, uint32_t cmd_id, uint32_t param1, uint32_t param2)
|
||
|
|
{
|
||
|
|
int32_t ret = RET_OK;
|
||
|
|
struct player_msg_s *msg = (struct player_msg_s *)msi->priv;
|
||
|
|
switch (cmd_id)
|
||
|
|
{
|
||
|
|
case MSI_CMD_PRE_DESTROY:
|
||
|
|
{
|
||
|
|
if(msg) {
|
||
|
|
msg->thread_stop = 1;
|
||
|
|
|
||
|
|
while(msg->running)
|
||
|
|
{
|
||
|
|
os_sleep_ms(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
if(msg->data_tmp)
|
||
|
|
{
|
||
|
|
msi_delete_fb(NULL, msg->data_tmp);
|
||
|
|
msg->data_tmp = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(msg->audio_data_tmp)
|
||
|
|
{
|
||
|
|
msi_delete_fb(NULL, msg->audio_data_tmp);
|
||
|
|
msg->audio_data_tmp = NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case MSI_CMD_POST_DESTROY:
|
||
|
|
{
|
||
|
|
if(msg) {
|
||
|
|
|
||
|
|
if(msg->avi_msg)
|
||
|
|
{
|
||
|
|
avi_deinit(msg->avi_msg);
|
||
|
|
msg->avi_msg = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
fbpool_destroy(&msg->tx_pool);
|
||
|
|
|
||
|
|
STREAM_LIBC_FREE(msg);
|
||
|
|
STREAM_LIBC_FREE((void*)msi->name);
|
||
|
|
msi->name = NULL;
|
||
|
|
msi->priv = NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case MSI_CMD_FREE_FB:
|
||
|
|
{
|
||
|
|
struct framebuff *fb = (struct framebuff *)param1;
|
||
|
|
//os_printf("player free fb:0x%x\n",fb);
|
||
|
|
if (fb->data)
|
||
|
|
{
|
||
|
|
if (fb->mtype == F_AUDIO) {
|
||
|
|
STREAM_LIBC_FREE(fb->data);
|
||
|
|
} else if (fb->mtype == F_JPG) {
|
||
|
|
STREAM_FREE(fb->data);
|
||
|
|
}
|
||
|
|
fb->data = NULL;
|
||
|
|
}
|
||
|
|
fbpool_put(&msg->tx_pool, fb);
|
||
|
|
// 不需要内核去释放fb
|
||
|
|
ret = RET_OK + 1;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case MSI_CMD_PLAYER:
|
||
|
|
{
|
||
|
|
uint32_t opcode = param1;
|
||
|
|
uint32_t arg = param2;
|
||
|
|
switch(opcode)
|
||
|
|
{
|
||
|
|
case MSI_FORWARD_INDEX:
|
||
|
|
{
|
||
|
|
//快进3s的时间
|
||
|
|
uint32_t play_time = arg + 3000;
|
||
|
|
msg->locate_frame_number = play_time * msg->avi_msg->fps / 1000;
|
||
|
|
//要判断是否已经到最后
|
||
|
|
if (msg->locate_frame_number > msg->avi_msg->avi.dwTotalFrame )
|
||
|
|
{
|
||
|
|
msg->locate_frame_number = msg->avi_msg->avi.dwTotalFrame;
|
||
|
|
}
|
||
|
|
//os_printf("msg->locate_frame_number:%d\targ:%d\n",msg->locate_frame_number,arg);
|
||
|
|
ret = msg->locate_frame_number * 1000 / msg->avi_msg->fps;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case MSI_REWIND_INDEX:
|
||
|
|
{
|
||
|
|
uint32_t play_time = 0;
|
||
|
|
if (arg > 3000)
|
||
|
|
{
|
||
|
|
play_time = arg - 3000;
|
||
|
|
}
|
||
|
|
msg->locate_frame_number = play_time * msg->avi_msg->fps / 1000;
|
||
|
|
//os_printf("msg->locate_frame_number:%d\targ:%d\n",msg->locate_frame_number,arg);
|
||
|
|
ret = msg->locate_frame_number * 1000 / msg->avi_msg->fps;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case MSI_PLAYER_MAGIC:
|
||
|
|
{
|
||
|
|
msg->magic = arg;
|
||
|
|
msg->speed_flag = 1;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
struct msi *avi_player_init(const char *stream_name, const char *filename)
|
||
|
|
{
|
||
|
|
struct avi_msg_s *avi_msg = NULL;
|
||
|
|
struct msi *msi = NULL;
|
||
|
|
|
||
|
|
uint8_t * stream_name_buf = (uint8_t *)STREAM_LIBC_ZALLOC(AVI_STREAM_NAME);
|
||
|
|
if (!stream_name_buf)
|
||
|
|
{
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
os_memcpy(stream_name_buf, stream_name, os_strlen(stream_name)+1);
|
||
|
|
|
||
|
|
avi_msg = avi_read_init(filename);
|
||
|
|
os_printf("avi_msg:%X\n",avi_msg);
|
||
|
|
//创建workqueue去不停读取视频数据,然后发送出去
|
||
|
|
|
||
|
|
msi = msi_new((char*)stream_name_buf, 0, NULL);
|
||
|
|
if (!msi)
|
||
|
|
{
|
||
|
|
avi_deinit(avi_msg);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
struct player_msg_s *msg = (struct player_msg_s *)msi->priv;
|
||
|
|
|
||
|
|
if (!msg)
|
||
|
|
{
|
||
|
|
msg = (struct player_msg_s*)STREAM_LIBC_ZALLOC(sizeof(struct player_msg_s));
|
||
|
|
msi->priv = (void*)msg;
|
||
|
|
msg->msi = msi;
|
||
|
|
msg->avi_msg = (struct avi_msg_s*)avi_msg;
|
||
|
|
msg->magic = 0;
|
||
|
|
msg->not_read_size = msg->avi_msg->idx1_size;
|
||
|
|
msg->cache_addr = msg->avi_msg->idx1_addr;
|
||
|
|
msg->running = 1;
|
||
|
|
|
||
|
|
fbpool_init(&msg->tx_pool, AVI_PLAYER_MAX_TX_NUM);
|
||
|
|
msi->action = (msi_action)avi_player_action;
|
||
|
|
msi->enable = 1;
|
||
|
|
|
||
|
|
msg->task = os_task_create(msi->name, avi_player_thread, (void*)msg, OS_TASK_PRIORITY_NORMAL, 0, NULL, 1024);
|
||
|
|
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
msi_destroy(msi);
|
||
|
|
msi = NULL;
|
||
|
|
avi_deinit(avi_msg);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
return msi;
|
||
|
|
}
|