Files
OpenTXW81X/sdk/app/avi/newavi2_player.c
T
2025-08-27 09:51:58 +01:00

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