627 lines
13 KiB
C
627 lines
13 KiB
C
#include "sys_config.h"
|
|
#include "tx_platform.h"
|
|
#include "list.h"
|
|
#include "dev.h"
|
|
#include "typesdef.h"
|
|
#include "lib/video/dvp/cmos_sensor/csi.h"
|
|
#include "devid.h"
|
|
#include "osal/irq.h"
|
|
#include "osal/string.h"
|
|
#include "lib/video/dvp/jpeg/jpg.h"
|
|
#include "jpgdef.h"
|
|
#include "hal/jpeg.h"
|
|
#include "dev/scale/hgscale.h"
|
|
#include "osal/semaphore.h"
|
|
#include "openDML.h"
|
|
#include "osal/mutex.h"
|
|
#include "avidemux.h"
|
|
#include "avi/play_avi.h"
|
|
#include "custom_mem/custom_mem.h"
|
|
#include "osal/task.h"
|
|
|
|
#define WEBFILE_NODE_LEN 1400
|
|
|
|
extern uint8 psram_ybuf_src[IMAGE_H*IMAGE_W+IMAGE_H*IMAGE_W/2];
|
|
uint32_t photo_size[2];
|
|
extern FIL fp_jpg;
|
|
int global_avi_running = 0;
|
|
int global_avi_exit = 0;
|
|
void jpg_decode_to_lcd(uint32 photo,uint32 jpg_w,uint32 jpg_h,uint32 video_w,uint32 video_h);
|
|
uint32_t file_mode (const char *mode);
|
|
int32 jpg_decode_is_finish();
|
|
uint32_t stop_play_avi_stream(stream* s);
|
|
|
|
void jpg_analyze(uint8_t *buf,uint8_t *size){
|
|
uint32_t itk = 0;
|
|
uint8_t *p;
|
|
|
|
for(itk = 0; itk < 1024;itk++){
|
|
if(buf[itk] == 0xff){
|
|
if(buf[itk+1] == 0xc0){
|
|
p = size;
|
|
p[0] = buf[itk+6];
|
|
p[1] = buf[itk+5];
|
|
p = &size[4];
|
|
p[0] = buf[itk+8];
|
|
p[1] = buf[itk+7];
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#define MAX(a,b) ( (a)>(b)?a:b )
|
|
static uint32_t a2i(char *str)
|
|
{
|
|
uint32_t ret = 0;
|
|
uint32_t indx =0;
|
|
while(str[indx] != '\0'){
|
|
if(str[indx] >= '0' && str[indx] <='9'){
|
|
ret = ret*10+str[indx]-'0';
|
|
}
|
|
indx ++;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
uint8_t arrary_compare(uint8 *src,uint8 *dst,uint8 len){
|
|
uint8 itk;
|
|
for(itk = 0; itk < len;itk++){
|
|
if(src[itk] != dst[itk]){
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void jpeg_file_get(uint8* photo_name,uint32 reset,char* file)
|
|
{
|
|
static uint32 num_cal = 0;
|
|
char name[6];
|
|
FRESULT ret;
|
|
DIR avi_dir;
|
|
uint32 len;
|
|
FILINFO finfo;
|
|
|
|
uint32 cal = 0;
|
|
uint32 file_num = 0;
|
|
len = strlen(file);
|
|
|
|
if(reset == 1){
|
|
num_cal = 0;
|
|
}
|
|
|
|
ret = f_opendir(&avi_dir,"0:/DCIM");
|
|
|
|
if(ret!=FR_OK)
|
|
{
|
|
return;
|
|
}
|
|
strcpy(name,file);
|
|
while(1){
|
|
ret = f_readdir(&avi_dir,&finfo);
|
|
if(ret != FR_OK || finfo.fname[0] == 0) break;
|
|
if(arrary_compare((uint8 *)finfo.fname,(uint8 *)name,len)){
|
|
cal++; //先统计有多少个符合的文件
|
|
}
|
|
}
|
|
f_closedir(&avi_dir);
|
|
|
|
if(cal == 0){
|
|
strcpy((char *)photo_name,"");
|
|
return;
|
|
}
|
|
file_num = (num_cal % cal);
|
|
ret = f_opendir(&avi_dir,"0:/DCIM");
|
|
cal = 0;
|
|
while(1){
|
|
ret = f_readdir(&avi_dir,&finfo);
|
|
_os_printf("fname2--:%s %d %d\r\n",finfo.fname,file_num,cal);
|
|
if(ret != FR_OK || finfo.fname[0] == 0) break;
|
|
if(arrary_compare((uint8 *)finfo.fname,(uint8 *)name,len)){
|
|
if(file_num == cal){
|
|
break;
|
|
}
|
|
cal++;
|
|
}
|
|
}
|
|
f_closedir(&avi_dir);
|
|
|
|
_os_printf("==================fname:%s\r\n",finfo.fname);
|
|
strcpy((char *)photo_name,(char *)finfo.fname);
|
|
|
|
num_cal++;
|
|
|
|
}
|
|
|
|
void jpeg_photo_explain(uint8* photo_name, uint32 scale_w, uint32 scale_h){
|
|
|
|
uint32_t data_count;
|
|
uint32_t read_count = 0;
|
|
uint8_t *data_buf = NULL;
|
|
uint32_t readLen;
|
|
uint32_t count = 0;
|
|
uint32_t data_len;
|
|
void *fp;
|
|
uint8_t *photo_sd_cache = NULL;
|
|
uint32_t photo_sd_cache_size = 8*1024;
|
|
fp = osal_fopen((const char*)photo_name,"rb");
|
|
if(!fp){
|
|
_os_printf("f_open %s error\r\n",photo_name);
|
|
goto jpeg_photo_explain_end;
|
|
}
|
|
data_len = osal_fsize(fp);
|
|
_os_printf("data_len:%d\r\n",data_len);
|
|
|
|
//从psram中申请一个空间
|
|
data_buf = (uint8_t*)custom_malloc_psram(data_len);
|
|
if(!data_buf)
|
|
{
|
|
goto jpeg_photo_explain_end;
|
|
}
|
|
|
|
while(!photo_sd_cache)
|
|
{
|
|
photo_sd_cache = (uint8_t*)custom_malloc(photo_sd_cache_size);
|
|
if(!photo_sd_cache)
|
|
{
|
|
photo_sd_cache_size >>= 1;
|
|
if(photo_sd_cache_size < 512)
|
|
{
|
|
goto jpeg_photo_explain_end;
|
|
}
|
|
}
|
|
}
|
|
os_printf("photo_sd_cache_size:%d\n",photo_sd_cache_size);
|
|
data_count = 512;
|
|
while(data_len){
|
|
|
|
if(data_len > data_count)
|
|
{
|
|
data_count = photo_sd_cache_size;
|
|
}
|
|
else
|
|
{
|
|
data_count = data_len;
|
|
}
|
|
readLen = osal_fread(photo_sd_cache,1,data_count,fp);
|
|
if(readLen == 0)
|
|
{
|
|
goto jpeg_photo_explain_end;
|
|
}
|
|
memcpy(data_buf+read_count,photo_sd_cache,readLen);
|
|
read_count += readLen;
|
|
data_len -= readLen;
|
|
}
|
|
osal_fclose(fp);
|
|
fp = NULL;
|
|
jpg_analyze(data_buf,(uint8_t *)photo_size);
|
|
_os_printf("width:%d high:%d\r\n",photo_size[0],photo_size[1]);
|
|
jpg_decode_to_lcd((uint32)data_buf,photo_size[1],photo_size[0],scale_w,scale_h);
|
|
while(!jpg_decode_is_finish() && count < 1000)
|
|
{
|
|
os_sleep_ms(1);
|
|
count++;
|
|
}
|
|
os_printf("%s count:%d\n",__FUNCTION__,count);
|
|
|
|
jpeg_photo_explain_end:
|
|
if(fp)
|
|
{
|
|
osal_fclose(fp);
|
|
fp = NULL;
|
|
}
|
|
|
|
if(data_buf)
|
|
{
|
|
custom_free_psram(data_buf);
|
|
data_buf = NULL;
|
|
}
|
|
|
|
if(photo_sd_cache)
|
|
{
|
|
custom_free(photo_sd_cache);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t rec_arg[2];
|
|
void rec_playback_thread_init(uint8* rec_name){
|
|
//rec_arg[0] = (w&0xffff) | ((h<<16)&0xffff0000);
|
|
//rec_arg[1] = continuous_spot;
|
|
extern void lvgl_recv_avi_thread(void *d);
|
|
os_task_create("rec_playback_thread", lvgl_recv_avi_thread, (void*)rec_name, OS_TASK_PRIORITY_NORMAL, 0, NULL, 1024);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//使用新框架去实现sd卡回放功能
|
|
#include "stream_frame.h"
|
|
#include "utlist.h"
|
|
static int opcode_func(stream *s,void *priv,int opcode)
|
|
{
|
|
int res = 0;
|
|
switch(opcode)
|
|
{
|
|
case STREAM_OPEN_ENTER:
|
|
break;
|
|
case STREAM_OPEN_EXIT:
|
|
{
|
|
s->priv = NULL;
|
|
enable_stream(s,1);
|
|
}
|
|
break;
|
|
case STREAM_OPEN_FAIL:
|
|
break;
|
|
//过滤数据,文件发送过来的数据可能是jpeg也可能是sound
|
|
case STREAM_FILTER_DATA:
|
|
{
|
|
struct data_structure *data = (struct data_structure *)priv;
|
|
//os_printf("type:%d\tdata:%X\n",GET_DATA_TYPE1(data->type),data);
|
|
if(GET_DATA_TYPE1(data->type) == JPEG && GET_DATA_TYPE2(data->type) == JPEG_FILE)
|
|
{
|
|
//正确的图片包
|
|
}
|
|
else
|
|
{
|
|
res = 1;
|
|
}
|
|
|
|
}
|
|
break;
|
|
case STREAM_RECV_DATA_FINISH:
|
|
break;
|
|
|
|
case STREAM_CLOSE_EXIT:
|
|
|
|
break;
|
|
|
|
//响应命令,可以进行停止线程(要考虑线程内部的内存被释放)
|
|
case STREAM_SEND_CMD:
|
|
{
|
|
uint32_t cmd = (uint32_t)priv;
|
|
//只是接受支持的命令
|
|
if(GET_CMD_TYPE1(cmd) == CMD_JPEG_FILE)
|
|
{
|
|
s->priv = (void*)GET_CMD_TYPE2(cmd);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
//默认都返回成功
|
|
break;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
extern volatile uint8 scale2_finish ;
|
|
|
|
#ifdef PSRAM_HEAP
|
|
void lvgl_recv_avi_thread(void *d)
|
|
{
|
|
stream *s = NULL;
|
|
stream *play_avi_s = NULL;
|
|
uint32_t photo_size_msg[2] = {0};
|
|
struct data_structure *get_f = NULL;
|
|
uint32_t node_len ;
|
|
uint32_t count = 0;
|
|
uint32_t *cmd;
|
|
uint8_t pause_flag = 1;
|
|
|
|
|
|
struct stream_jpeg_data_s *el,*tmp;
|
|
uint8_t *jpeg_buf_addr = NULL;
|
|
|
|
|
|
char *filepath = (char*)d;
|
|
os_printf("filepath:%s\n",filepath);
|
|
global_avi_exit = 0;
|
|
global_avi_running = 0;
|
|
//创建接收视频的流
|
|
s = open_stream_available(R_LVGL_JPEG,0,2,opcode_func,NULL);
|
|
if(!s)
|
|
{
|
|
goto lvgl_recv_avi_end;
|
|
}
|
|
cmd = (uint32_t *)&s->priv;
|
|
play_avi_s = creat_play_avi_stream(S_PLAYBACK,filepath,R_LVGL_JPEG,R_SPEAKER);
|
|
if(!play_avi_s)
|
|
{
|
|
goto lvgl_recv_avi_end;
|
|
}
|
|
open_stream_again(play_avi_s);
|
|
pause_1FPS_avi_stream(play_avi_s);
|
|
extern uint32_t start_play_avi_thread(stream *s);
|
|
//启动回放视频的线程
|
|
start_play_avi_thread(play_avi_s);
|
|
|
|
uint32_t start_time = os_jiffies();
|
|
uint32_t last_play_time = 0;
|
|
//循环接收数据
|
|
while(1)
|
|
{
|
|
if(!get_f)
|
|
{
|
|
get_f = recv_real_data(s);
|
|
}
|
|
//视频播放已经停止
|
|
count++;
|
|
if(count%1000 == 0)
|
|
{
|
|
os_printf("@@@@@@@@s->priv:%X\tcmd:%X\n",s->priv,*cmd);
|
|
}
|
|
if((*cmd == PLAY_AVI_CMD_STOP)&&(!get_f))
|
|
{
|
|
goto lvgl_recv_avi_end;
|
|
}
|
|
if(!get_f)
|
|
{
|
|
os_sleep_ms(1);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
//可以播放
|
|
if(os_jiffies()-start_time >= get_stream_data_timestamp(get_f))
|
|
{
|
|
|
|
}
|
|
//检查状态,不播放,去检查是否要暂停
|
|
else
|
|
{
|
|
os_sleep_ms(1);
|
|
goto check_playback_status;
|
|
}
|
|
}
|
|
|
|
struct stream_jpeg_data_s *dest_list = (struct stream_jpeg_data_s *)get_stream_real_data(get_f);
|
|
struct stream_jpeg_data_s *dest_list_tmp = dest_list;
|
|
LL_COUNT(dest_list_tmp,el,node_len);
|
|
|
|
//在psram的情况下,node_len一定是2
|
|
if(node_len == 2)
|
|
{
|
|
LL_FOREACH_SAFE(dest_list,el,tmp)
|
|
{
|
|
if(dest_list_tmp == el)
|
|
{
|
|
continue;
|
|
}
|
|
jpeg_buf_addr = (uint8_t *)GET_JPG_SELF_BUF(get_f,el->data);
|
|
//os_printf("jpeg_buf_addr:%X\n",jpeg_buf_addr);
|
|
|
|
|
|
jpg_analyze(jpeg_buf_addr,(uint8_t *)photo_size_msg);
|
|
//os_printf("D");
|
|
last_play_time = get_stream_data_timestamp(get_f);
|
|
jpg_decode_to_lcd((uint32)jpeg_buf_addr,photo_size_msg[1],photo_size_msg[0],320,240);
|
|
count = 0;
|
|
while(!jpg_decode_is_finish() && count < 1000)
|
|
{
|
|
os_sleep_ms(1);
|
|
count++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
free_data(get_f);
|
|
get_f = NULL;
|
|
check_playback_status:
|
|
while(!global_avi_running)
|
|
{
|
|
if(!pause_flag)
|
|
{
|
|
pause_avi_stream(play_avi_s);
|
|
}
|
|
pause_flag = 1;
|
|
os_sleep_ms(1);
|
|
if(global_avi_exit)
|
|
break;
|
|
}
|
|
if(pause_flag)
|
|
{
|
|
pause_flag = 0;
|
|
start_time = os_jiffies() - last_play_time;
|
|
play_avi_stream(play_avi_s);
|
|
}
|
|
|
|
if(global_avi_exit)
|
|
break;
|
|
}
|
|
|
|
|
|
lvgl_recv_avi_end:
|
|
global_avi_exit = 1;
|
|
|
|
if(get_f)
|
|
{
|
|
free_data(get_f);
|
|
}
|
|
if(s)
|
|
{
|
|
close_stream(s);
|
|
}
|
|
|
|
if(play_avi_s)
|
|
{
|
|
//自带流删除功能,所以如果调用这个,不需要主动调用close_stream
|
|
os_printf("%s:%d!!!!!!!!!!!!!!!!!!\n",__FUNCTION__,__LINE__);
|
|
stop_avi_stream(play_avi_s);
|
|
}
|
|
|
|
os_printf("%s:%d end\n",__FUNCTION__,__LINE__);
|
|
|
|
return;
|
|
}
|
|
#else
|
|
void lvgl_recv_avi_thread(void *d)
|
|
{
|
|
stream *s = NULL;
|
|
stream *play_avi_s = NULL;
|
|
uint32_t photo_size_msg[2] = {0};
|
|
struct data_structure *get_f = NULL;
|
|
uint32_t node_len ;
|
|
uint32_t count = 0;
|
|
uint32_t *cmd;
|
|
uint8_t pause_flag = 1;
|
|
|
|
struct stream_jpeg_data_s *el,*tmp;
|
|
uint8_t *jpeg_buf_addr = NULL;
|
|
|
|
|
|
char *filepath = (char*)d;
|
|
os_printf("filepath:%s\n",filepath);
|
|
global_avi_exit = 0;
|
|
global_avi_running = 0;
|
|
//创建接收视频的流
|
|
s = open_stream_available(R_LVGL_JPEG,0,2,opcode_func,NULL);
|
|
if(!s)
|
|
{
|
|
goto lvgl_recv_avi_end;
|
|
}
|
|
cmd = (uint32_t *)&s->priv;
|
|
play_avi_s = creat_play_avi_stream(S_PLAYBACK,filepath,R_LVGL_JPEG,R_SPEAKER);
|
|
if(!play_avi_s)
|
|
{
|
|
goto lvgl_recv_avi_end;
|
|
}
|
|
open_stream_again(play_avi_s);
|
|
pause_1FPS_avi_stream(play_avi_s);
|
|
extern uint32_t start_play_avi_thread(stream *s);
|
|
//启动回放视频的线程
|
|
start_play_avi_thread(play_avi_s);
|
|
|
|
uint32_t start_time = os_jiffies();
|
|
uint32_t last_play_time = 0;
|
|
//循环接收数据
|
|
while(1)
|
|
{
|
|
if(!get_f)
|
|
{
|
|
get_f = recv_real_data(s);
|
|
}
|
|
//视频播放已经停止
|
|
count++;
|
|
if(count%1000 == 0)
|
|
{
|
|
os_printf("@@@@@@@@s->priv:%X\tcmd:%X\n",s->priv,*cmd);
|
|
}
|
|
if((*cmd == PLAY_AVI_CMD_STOP)&&(!get_f))
|
|
{
|
|
goto lvgl_recv_avi_end;
|
|
}
|
|
if(!get_f)
|
|
{
|
|
os_sleep_ms(1);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
//可以播放
|
|
if(os_jiffies()-start_time >= get_stream_data_timestamp(get_f))
|
|
{
|
|
|
|
}
|
|
//检查状态,不播放,去检查是否要暂停
|
|
else
|
|
{
|
|
os_sleep_ms(1);
|
|
goto check_playback_status;
|
|
}
|
|
}
|
|
struct stream_jpeg_data_s *dest_list = (struct stream_jpeg_data_s *)get_stream_real_data(get_f);
|
|
struct stream_jpeg_data_s *dest_list_tmp = dest_list;
|
|
LL_COUNT(dest_list_tmp,el,node_len);
|
|
|
|
uint8_t node_num = 0;
|
|
int jpg_buf_len = get_stream_real_data_len(get_f);
|
|
jpeg_buf_addr = (uint8_t *)custom_malloc(jpg_buf_len);
|
|
if(!jpeg_buf_addr) {
|
|
os_printf("%s:%d malloc jpg buf err!\n",__FUNCTION__,__LINE__);
|
|
}
|
|
LL_FOREACH_SAFE(dest_list,el,tmp)
|
|
{
|
|
if(dest_list_tmp == el)
|
|
{
|
|
continue;
|
|
}
|
|
node_num++;
|
|
if(jpg_buf_len >= WEBFILE_NODE_LEN) {
|
|
hw_memcpy(jpeg_buf_addr+(node_num-1)*WEBFILE_NODE_LEN, (uint8_t *)el->data,WEBFILE_NODE_LEN);
|
|
jpg_buf_len -= WEBFILE_NODE_LEN;
|
|
}
|
|
else {
|
|
hw_memcpy(jpeg_buf_addr+(node_num-1)*WEBFILE_NODE_LEN, (uint8_t *)el->data,jpg_buf_len);
|
|
jpg_buf_len = 0;
|
|
}
|
|
|
|
if(node_num >= (node_len-1))
|
|
break;
|
|
}
|
|
|
|
jpg_analyze(jpeg_buf_addr,(uint8_t *)photo_size_msg);
|
|
jpg_decode_to_lcd((uint32)jpeg_buf_addr,photo_size_msg[1],photo_size_msg[0],320,240);
|
|
while(!jpg_decode_is_finish() && count < 1000)
|
|
{
|
|
os_sleep_ms(1);
|
|
count++;
|
|
}
|
|
custom_free(jpeg_buf_addr);
|
|
jpeg_buf_addr = NULL;
|
|
free_data(get_f);
|
|
get_f = NULL;
|
|
check_playback_status:
|
|
while(!global_avi_running)
|
|
{
|
|
if(!pause_flag)
|
|
{
|
|
pause_avi_stream(play_avi_s);
|
|
}
|
|
pause_flag = 1;
|
|
os_sleep_ms(1);
|
|
if(global_avi_exit)
|
|
break;
|
|
}
|
|
if(pause_flag)
|
|
{
|
|
pause_flag = 0;
|
|
start_time = os_jiffies() - last_play_time;
|
|
play_avi_stream(play_avi_s);
|
|
}
|
|
|
|
if(global_avi_exit)
|
|
break;
|
|
}
|
|
lvgl_recv_avi_end:
|
|
global_avi_exit = 1;
|
|
if(get_f)
|
|
{
|
|
free_data(get_f);
|
|
}
|
|
if(s)
|
|
{
|
|
close_stream(s);
|
|
}
|
|
if(play_avi_s)
|
|
{
|
|
//自带流删除功能,所以如果调用这个,不需要主动调用close_stream
|
|
os_printf("%s:%d!!!!!!!!!!!!!!!!!!\n",__FUNCTION__,__LINE__);
|
|
stop_avi_stream(play_avi_s);
|
|
}
|
|
os_printf("%s:%d end\n",__FUNCTION__,__LINE__);
|
|
|
|
return;
|
|
}
|
|
|
|
#endif
|