Files
TAIXIN/sdk/app/playback/avi_player_msi.c

422 lines
14 KiB
C
Raw Normal View History

#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;
}