431 lines
12 KiB
C
431 lines
12 KiB
C
#include "sys_config.h"
|
|
#include "typesdef.h"
|
|
#include "dev.h"
|
|
#include "devid.h"
|
|
#include "stream_frame.h"
|
|
#include "utlist.h"
|
|
#include "osal/work.h"
|
|
#include "custom_mem/custom_mem.h"
|
|
#include "osal/string.h"
|
|
#include "osal/task.h"
|
|
#include "osal/event.h"
|
|
#include "stream_define.h"
|
|
#include "avidemux.h"
|
|
#include "osal_file.h"
|
|
|
|
/*****************************************************************************
|
|
* AVI2.0
|
|
*****************************************************************************/
|
|
|
|
//data申请空间函数
|
|
#define STREAM_MALLOC custom_malloc_psram
|
|
#define STREAM_FREE custom_free_psram
|
|
#define STREAM_ZALLOC custom_zalloc_psram
|
|
|
|
//结构体申请空间函数
|
|
#define STREAM_LIBC_MALLOC custom_malloc
|
|
#define STREAM_LIBC_FREE custom_free
|
|
#define STREAM_LIBC_ZALLOC custom_zalloc
|
|
|
|
|
|
enum
|
|
{
|
|
PLAYER2_STOP = BIT(0),
|
|
PLAYER2_EXIT = BIT(1),
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct player2_msg_s
|
|
{
|
|
void *task;
|
|
struct os_event evt;
|
|
void *fp;
|
|
struct aviinfo *info;
|
|
stream *s;
|
|
uint32_t magic;
|
|
struct data_structure *video_data_tmp;
|
|
struct data_structure *audio_data_tmp;
|
|
int32_t locate_frame_number;
|
|
uint32_t fps;
|
|
uint32_t frq;
|
|
//用于音频视频同步计算的时间
|
|
uint32_t video_time;
|
|
uint32_t audio_time;
|
|
uint8_t thread_stop : 1, rev: 7;
|
|
};
|
|
|
|
|
|
//暂时不支持快进快退
|
|
static uint32_t newavi_player2_cmd(stream *s,int opcode,uint32_t arg)
|
|
{
|
|
uint32_t res = 0;
|
|
struct player2_msg_s *msg = (struct player2_msg_s *)s->priv;
|
|
switch(opcode)
|
|
{
|
|
//跳转位置,快进
|
|
case NEWAVI_PLAYER_LOCATE_FORWARD_INDEX:
|
|
{
|
|
res = msg->locate_frame_number*1000/msg->fps;
|
|
}
|
|
break;
|
|
|
|
//快退
|
|
case NEWAVI_PLAYER_LOCATE_REWIND_INDEX:
|
|
{
|
|
res = msg->locate_frame_number*1000/msg->fps;
|
|
}
|
|
break;
|
|
//修改data的magic,用于过滤某些数据情况
|
|
case NEWAVI_PLAYER_MAGIC:
|
|
msg->magic = arg;
|
|
break;
|
|
//返回是否正在播放的状态
|
|
case NEWAVI_PLAYER_STATUS:
|
|
res = msg->thread_stop;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
static void newplayer2_thread(void *d)
|
|
{
|
|
struct player2_msg_s *msg = (struct player2_msg_s *)d;
|
|
stream *s = msg->s;
|
|
uint32_t base = 0,size;
|
|
uint32_t audio_base;
|
|
uint32_t base_tmp = 0;
|
|
int res = 0;
|
|
int read_len;
|
|
uint8_t *data = NULL;
|
|
struct aviinfo *info = msg->info;
|
|
uint32_t audio_read_len = 0;
|
|
|
|
while(!msg->thread_stop)
|
|
{
|
|
if(!s->enable)
|
|
{
|
|
goto newplayer2_thread_wait;
|
|
}
|
|
|
|
if(!msg->video_data_tmp)
|
|
{
|
|
msg->video_data_tmp = get_src_data_f(msg->s);
|
|
}
|
|
|
|
if(msg->frq && !msg->audio_data_tmp)
|
|
{
|
|
msg->audio_data_tmp = get_src_data_f(msg->s);
|
|
}
|
|
|
|
if(!msg->video_data_tmp && !msg->audio_data_tmp)
|
|
{
|
|
goto newplayer2_thread_wait;
|
|
}
|
|
|
|
if(msg->video_data_tmp)
|
|
{
|
|
//这里应该要去计算一下音频视频是否同步,以音频为主(因为音频比较敏感)
|
|
//播放的时间小,就需要播放下一帧视频
|
|
//os_printf("video_time:%d\taudio_time:%d\n",msg->video_time,msg->audio_time);
|
|
if(msg->video_time > msg->audio_time)
|
|
{
|
|
goto newplayer2_thread_video_end;
|
|
}
|
|
//代表已经发送了,可以尝试读取下一帧
|
|
if(base == base_tmp)
|
|
{
|
|
res = read_avi_offset(&info->str[0],&base,&size);
|
|
}
|
|
|
|
if(base == 0 || res)
|
|
{
|
|
force_del_data(msg->video_data_tmp);
|
|
msg->video_data_tmp = NULL;
|
|
|
|
//需要退出
|
|
os_printf("@@@@@@@@@@@@@@@@@@@@@@%s:%d\n",__FUNCTION__,__LINE__);
|
|
goto newplayer2_thread_exit;
|
|
}
|
|
|
|
if(base_tmp != base)
|
|
{
|
|
|
|
//读取data数据发送出去
|
|
data = (uint8_t*)STREAM_MALLOC(size);
|
|
if(!data)
|
|
{
|
|
goto newplayer2_thread_wait;
|
|
}
|
|
read_len = read_avi_data(&info->str[0],(char*)data,size);
|
|
if(read_len <= 0)
|
|
{
|
|
//要退出,结束或者读取异常了
|
|
os_printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%s:%d\n",__FUNCTION__,__LINE__);
|
|
goto newplayer2_thread_exit;
|
|
}
|
|
|
|
msg->video_data_tmp->data = data;
|
|
msg->video_data_tmp->ref = 0;
|
|
msg->video_data_tmp->type = SET_DATA_TYPE(JPEG,JPEG_FULL);
|
|
//暂时使用msg->fps帧去播放
|
|
msg->video_data_tmp->magic = msg->magic;
|
|
set_stream_real_data_len(msg->video_data_tmp,read_len);
|
|
msg->locate_frame_number = get_avi_cur(&info->str[0])-1;
|
|
msg->video_time = get_avi_cur(&info->str[0])*1000/msg->fps;
|
|
set_stream_data_time(msg->video_data_tmp,(get_avi_cur(&info->str[0])-1)*1000/msg->fps);
|
|
//_os_printf("(V:%X\ttype:%X\tread_len:%d)\r\n",msg->video_data_tmp,msg->video_data_tmp->type,read_len);
|
|
send_data_to_stream(msg->video_data_tmp);
|
|
msg->video_data_tmp = NULL;
|
|
data = NULL;
|
|
|
|
base_tmp = base;
|
|
_os_printf("(V)");
|
|
}
|
|
else
|
|
{
|
|
msg->locate_frame_number = get_avi_cur(&info->str[0])-1;
|
|
msg->video_time = get_avi_cur(&info->str[0])*1000/msg->fps;
|
|
}
|
|
}
|
|
|
|
newplayer2_thread_video_end:
|
|
if(msg->frq && msg->audio_data_tmp)
|
|
{
|
|
if(msg->video_time < msg->audio_time)
|
|
{
|
|
goto newplayer2_thread_wait;
|
|
}
|
|
|
|
res = read_avi_offset(&info->str[1],&audio_base,&size);
|
|
if(audio_base == 0 || res)
|
|
{
|
|
force_del_data(msg->audio_data_tmp);
|
|
msg->audio_data_tmp = NULL;
|
|
goto newplayer2_thread_exit;
|
|
}
|
|
|
|
|
|
data = (uint8_t*)STREAM_MALLOC(size);
|
|
if(!data)
|
|
{
|
|
goto newplayer2_thread_wait;
|
|
}
|
|
read_len = read_avi_data(&info->str[1],(char*)data,size);
|
|
if(read_len <= 0)
|
|
{
|
|
//要退出,结束或者读取异常了
|
|
os_printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%s:%d\n",__FUNCTION__,__LINE__);
|
|
goto newplayer2_thread_exit;
|
|
}
|
|
msg->audio_data_tmp->data = data;
|
|
msg->audio_data_tmp->ref = 0;
|
|
msg->audio_data_tmp->type = SET_DATA_TYPE(SOUND,SOUND_FILE);
|
|
//暂时使用msg->fps帧去播放
|
|
msg->audio_data_tmp->magic = msg->magic;
|
|
set_stream_real_data_len(msg->audio_data_tmp,read_len);
|
|
audio_read_len += read_len;
|
|
set_stream_data_time(msg->audio_data_tmp,msg->audio_time);
|
|
msg->audio_time = audio_read_len*1000/msg->frq;
|
|
//_os_printf("(A:%X\ttype:%X\tread_len:%d)\r\n",msg->audio_data_tmp,msg->audio_data_tmp->type,read_len);
|
|
send_data_to_stream(msg->audio_data_tmp);
|
|
|
|
msg->audio_data_tmp = NULL;
|
|
data = NULL;
|
|
_os_printf("(A)");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newplayer2_thread_wait:
|
|
os_sleep_ms(1);
|
|
}
|
|
newplayer2_thread_exit:
|
|
os_printf("%s:%d exit\n",__FUNCTION__,__LINE__);
|
|
if(data)
|
|
{
|
|
STREAM_FREE(data);
|
|
data = NULL;
|
|
}
|
|
if(msg->video_data_tmp)
|
|
{
|
|
force_del_data(msg->video_data_tmp);
|
|
msg->video_data_tmp = NULL;
|
|
}
|
|
|
|
if(msg->audio_data_tmp)
|
|
{
|
|
force_del_data(msg->audio_data_tmp);
|
|
msg->audio_data_tmp = NULL;
|
|
}
|
|
|
|
msg->thread_stop = 1;
|
|
os_event_wait(&msg->evt,PLAYER2_STOP,NULL,OS_EVENT_WMODE_OR,-1);
|
|
os_event_set(&msg->evt,PLAYER2_EXIT,NULL);
|
|
}
|
|
|
|
|
|
static int opcode_func(stream *s,void *priv,int opcode)
|
|
{
|
|
int res = 0;
|
|
switch(opcode)
|
|
{
|
|
case STREAM_OPEN_ENTER:
|
|
break;
|
|
case STREAM_OPEN_EXIT:
|
|
{
|
|
|
|
struct player2_msg_s *msg = (struct player2_msg_s*)priv;
|
|
s->priv = (void*)priv;
|
|
msg->s = s;
|
|
msg->magic = 0;
|
|
msg->thread_stop = 0;
|
|
msg->fps = msg->info->str[0].dwRate;
|
|
if(msg->info->strmsk&BIT(1))
|
|
{
|
|
msg->frq = msg->info->str[1].dwRate;
|
|
}
|
|
else
|
|
{
|
|
msg->audio_time = ~0; //没有音频,不需要考虑音频同步
|
|
}
|
|
os_printf("fps:%d\tfrq:%d\n",msg->fps,msg->frq);
|
|
os_event_init(&msg->evt);
|
|
register_stream_self_cmd_func(s,newavi_player2_cmd);
|
|
msg->task = os_task_create(s->name,newplayer2_thread,(void*)msg,OS_TASK_PRIORITY_NORMAL,0,NULL,1024);
|
|
if(!msg->task)
|
|
{
|
|
os_event_set(&msg->evt,PLAYER2_EXIT,NULL);
|
|
}
|
|
}
|
|
break;
|
|
case STREAM_OPEN_FAIL:
|
|
break;
|
|
case STREAM_DATA_DIS:
|
|
{
|
|
}
|
|
break;
|
|
|
|
case STREAM_DATA_FREE:
|
|
{
|
|
struct data_structure *data = (struct data_structure *)priv;
|
|
if(data->data)
|
|
{
|
|
STREAM_FREE(data->data);
|
|
data->data = NULL;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case STREAM_FILTER_DATA:
|
|
{
|
|
}
|
|
break;
|
|
|
|
case STREAM_DATA_FREE_END:
|
|
break;
|
|
|
|
|
|
//数据发送完成,可以选择唤醒对应的任务
|
|
case STREAM_SEND_DATA_FINISH:
|
|
break;
|
|
|
|
|
|
case STREAM_SEND_DATA_START:
|
|
{
|
|
}
|
|
break;
|
|
|
|
case STREAM_DATA_DESTORY:
|
|
{
|
|
}
|
|
break;
|
|
|
|
case STREAM_CLOSE_ENTER:
|
|
{
|
|
struct player2_msg_s *msg = (struct player2_msg_s*)s->priv;
|
|
msg->thread_stop = 1;
|
|
os_event_set(&msg->evt,PLAYER2_STOP,NULL);
|
|
os_event_wait(&msg->evt,PLAYER2_EXIT,NULL,OS_EVENT_WMODE_OR,-1);
|
|
os_printf("newavi2_player close\n");
|
|
}
|
|
break;
|
|
|
|
case STREAM_CLOSE_EXIT:
|
|
{
|
|
struct player2_msg_s *msg = (struct player2_msg_s*)s->priv;
|
|
if(msg->info)
|
|
{
|
|
free_aviinfo_point(msg->info);
|
|
STREAM_LIBC_FREE(msg->info);
|
|
}
|
|
|
|
if(msg->fp)
|
|
{
|
|
osal_fclose(msg->fp);
|
|
}
|
|
STREAM_LIBC_FREE(msg);
|
|
os_printf("newavi2_player success\n");
|
|
}
|
|
break;
|
|
|
|
case STREAM_MARK_GC_END:
|
|
{
|
|
}
|
|
break;
|
|
|
|
default:
|
|
//默认都返回成功
|
|
break;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
static struct player2_msg_s *avi2_read_init(const char *filename)
|
|
{
|
|
struct player2_msg_s *msg = NULL;
|
|
struct aviinfo *info = NULL;
|
|
struct aviinfo *info_tmp = NULL;
|
|
void *fp = NULL;
|
|
|
|
fp = osal_fopen(filename,"rb");
|
|
info = (struct aviinfo *)STREAM_LIBC_ZALLOC(sizeof(struct aviinfo));
|
|
if(fp && info)
|
|
{
|
|
info_tmp = avidemux_parse(fp,info);
|
|
}
|
|
|
|
if(fp && info_tmp)
|
|
{
|
|
msg = (struct player2_msg_s *)STREAM_LIBC_ZALLOC(sizeof(struct player2_msg_s));
|
|
msg->fp = fp;
|
|
msg->info = info_tmp;
|
|
}
|
|
return msg;
|
|
}
|
|
|
|
stream *newavi_player2_init(const char *stream_name,const char *filename)
|
|
{
|
|
|
|
struct player2_msg_s *msg = NULL;
|
|
stream *s = NULL;
|
|
msg = avi2_read_init(filename);
|
|
//创建workqueue去不停读取视频数据,然后发送出去
|
|
if(msg)
|
|
{
|
|
s = open_stream_available(stream_name,8,0,opcode_func,(void*)msg);
|
|
}
|
|
|
|
|
|
return s;
|
|
} |