Initial commit: TXW82x FPV v2.7.0.7-42229 SDK + project sources

This commit is contained in:
2026-07-06 11:30:13 +08:00
commit e76462eeb7
3451 changed files with 1415300 additions and 0 deletions

View File

@@ -0,0 +1,402 @@
#include "file_common_api.h"
#include "lib/fs/fatfs/osal_file.h"
#include "app/video_app/file_thumb.h"
#include "osal/string.h"
#include "lwip/sockets.h"
static uint8_t get_rtc_time_str(char *timestr, uint8_t timestr_len, struct timeval *t)
{
struct tm *time_info;
struct timeval *time = t;
struct timeval ptimeval;
if(!time)
{
time = &ptimeval;
gettimeofday(time, NULL);
}
time_t time_val = (time_t)time->tv_sec;
int ms = time->tv_usec / 1000;
time_info = gmtime(&time_val);
if (time_info == NULL) {
_os_printf("gmtime error\r\n");
return 1;
}
os_snprintf(timestr, timestr_len, "%04d%02d%02d%02d%02d%02d%03d",
time_info->tm_year + 1900, time_info->tm_mon + 1, time_info->tm_mday,
time_info->tm_hour, time_info->tm_min, time_info->tm_sec, ms);
return 0;
}
/*
* 获取JPG文件路径不按天存储
* img_dir: 录像目录0:/IMG
* file_path: 文件名,格式: 0:/IMG/20250918010101000.JPG
* filepath_size: 文件名大小
*/
uint8_t takephoto_name(const char *img_dir, char *file_path, int filepath_size)
{
char timestr[FILE_NAME_LEN + 1];
if(get_rtc_time_str(timestr, FILE_NAME_LEN + 1, NULL))
return 1;
os_snprintf(file_path, filepath_size, "%s/%.*s.JPG", img_dir, FILE_NAME_LEN, timestr);
return 0;
}
/*
* 获取JPG文件路径按天存储
* img_dir: 录像目录0:/IMG
* file_path: 文件名,格式: 0:/IMG/20250918/20250918010101000.JPG
* filepath_size: 文件名大小
*/
uint8_t takephoto_name_day(const char *img_dir, char *file_path, int filepath_size)
{
char timestr[FILE_NAME_LEN + 1];
if(get_rtc_time_str(timestr, FILE_NAME_LEN + 1, NULL))
return 1;
os_snprintf(file_path, filepath_size, "%s/%.*s/%.*s.JPG", img_dir, FILE_SUB_PATH_LEN, timestr, FILE_NAME_LEN, timestr);
return 0;
}
/*
* 获取JPG文件名称
* filename: 文件名,格式: 20250918010101000.JPG
* filename_size: 文件名大小
*/
int32_t takephoto_name_no_dir(char *filename, int filename_size)
{
char timestr[FILE_NAME_LEN + 1];
if(get_rtc_time_str(timestr, FILE_NAME_LEN + 1, NULL))
return 1;
os_snprintf(filename, filename_size, "%.*s.JPG", FILE_NAME_LEN, timestr);
return 0;
}
/*
* 获取JPG文件名称
* filename: 文件名,格式: 20250918010101000.JPG
* filename_size: 文件名大小
* time: 时间
*/
int32_t takephoto_name_no_dir_time(char *filename, int filename_size, struct timeval *time)
{
char timestr[FILE_NAME_LEN + 1];
if(get_rtc_time_str(timestr, FILE_NAME_LEN + 1, time))
return 1;
os_snprintf(filename, filename_size, "%.*s.JPG", FILE_NAME_LEN, timestr);
return 0;
}
/*
* 为JPG文件添加目录
* path: 文件路径,格式: dir_name/filename
* path_size: 文件路径大小
*/
int32_t takephoto_name_add_dir(char *filename, int filename_size, char *path, const char *dir_name)
{
if(dir_name)
{
os_snprintf(filename, filename_size,"%s/%s", dir_name, path);
}
else
{
os_snprintf(filename, filename_size,"%s", path);
}
return 0;
}
/*
* 获取MP4文件名
* rec_dir: 录像目录0:/REC
* sub_path: 子目录,格式: 0:/REC/20250918
* file_name: 文件名,格式: 20250918010101000.MP4
*/
uint8_t get_mp4_file_name(const char *rec_dir, char *sub_path, char *file_name)
{
char timestr[FILE_NAME_LEN + 1];
if(get_rtc_time_str(timestr, FILE_NAME_LEN + 1, NULL))
return 1;
os_sprintf(sub_path, "%s/%.*s", rec_dir, FILE_SUB_PATH_LEN, timestr);
os_sprintf(file_name, "%.*s.MP4", FILE_NAME_LEN, timestr);
return 0;
}
/*
* 获取文件名
* rec_dir: 录像目录0:/RECA
* sub_path: 子目录,格式: 0:/RECA/20250918
* file_name: 文件名,格式: 20250918010101000.MP4
* extension_name: 文件扩展名,格式: .MP4/.AVI/...
*/
uint8_t get_extension_file_name(const char *rec_dir, char *sub_path, char *file_name, const char *extension_name)
{
char timestr[FILE_NAME_LEN + 1];
if(get_rtc_time_str(timestr, FILE_NAME_LEN + 1, NULL))
return 1;
os_sprintf(sub_path, "%s/%.*s", rec_dir, FILE_SUB_PATH_LEN, timestr);
os_sprintf(file_name, "%.*s%s", FILE_NAME_LEN, timestr, extension_name);
return 0;
}
/*
* 获取文件名
* rec_dir: 录像目录0:/RECA
* sub_path: 子目录,格式: 0:/RECA/20250918
* file_name: 文件名,格式: 20250918010101000.MP4
* extension_name: 文件扩展名,格式: .MP4/.AVI/...
* time: 时间
*/
uint8_t get_extension_file_name_time(const char *rec_dir, char *sub_path, char *file_name, const char *extension_name, struct timeval *time)
{
char timestr[FILE_NAME_LEN + 1];
if(get_rtc_time_str(timestr, FILE_NAME_LEN + 1, time))
return 1;
os_sprintf(sub_path, "%s/%.*s", rec_dir, FILE_SUB_PATH_LEN, timestr);
os_sprintf(file_name, "%.*s%s", FILE_NAME_LEN, timestr, extension_name);
return 0;
}
/*
* 根据文件类型获取照片文件路径
* filename: 文件名
* path: 文件路径
* pathsize: 文件路径大小
*/
void gen_photo_path(const char *filename, char *path, uint32_t pathsize)
{
const char *rec_path = NULL;
const char* file_dot = strrchr(filename, '.');
if(file_dot == NULL) {
os_printf("%s file_dot is NULL\n", __FUNCTION__);
return;
}
if(os_strstr(filename, FRONT_SUFFIX)) {
rec_path = IMGA_PATH;
} else if(os_strstr(filename, INTER_SUFFIX)) {
rec_path = IMGB_PATH;
} else if(os_strstr(filename, BACK_SUFFIX)) {
rec_path = IMGC_PATH;
} else {
rec_path = IMG_PATH;
}
os_snprintf(path, pathsize, "%s/%.*s%s", rec_path, FILE_NAME_LEN, filename, file_dot);
os_printf("%s path: %s\n", __FUNCTION__, path);
}
/*
* 根据文件类型获取视频文件路径
* filename: 文件名
* path: 文件路径
* pathsize: 文件路径大小
*/
void gen_video_path(const char *filename, char *path, uint32_t pathsize)
{
uint8_t prefix_len = 0;
const char *rec_path = NULL;
const char *file_name = os_strrchr(filename, '/');
if(file_name == NULL) {
file_name = filename;
}
const char* file_dot = strrchr(filename, '.');
if(file_dot == NULL) {
os_printf("%s file_dot is NULL\n", __FUNCTION__);
return;
}
if(os_strstr(file_name, SOS_PREFIX)) {
prefix_len = strlen(SOS_PREFIX);
} else if(os_strstr(file_name, PARKF_PREFIX)) {
prefix_len = strlen(PARKF_PREFIX);
}
if(os_strstr(file_name, FRONT_SUFFIX)) {
rec_path = RECA_PATH;
} else if(os_strstr(file_name, INTER_SUFFIX)) {
rec_path = RECB_PATH;
} else if(os_strstr(file_name, BACK_SUFFIX)) {
rec_path = RECC_PATH;
} else {
rec_path = REC_PATH;
}
os_snprintf(path, pathsize, "%s/%.*s/%.*s%s", rec_path, FILE_SUB_PATH_LEN, file_name + prefix_len, FILE_NAME_LEN + prefix_len, file_name, file_dot);
os_printf("%s path: %s\n", __FUNCTION__, path);
}
void gen_photo_video_path(const char *filename, char *path, uint32_t pathsize)
{
if(os_strstr(filename, JPG_EXTENSION_NAME))
{
gen_photo_path(filename, path, pathsize);
}
else if(os_strstr(filename, MP4_EXTENSION_NAME) || os_strstr(filename, AVI_EXTENSION_NAME))
{
gen_video_path(filename, path, pathsize);
}
else
{
_os_printf("filename %s format err!\n", filename);
}
}
/***************************************************************
* 获取文件列表接口 *
* *
****************************************************************/
typedef void (* conver_send_fn)(int fd, struct file_info *file_info);
void send_chunk(int fd, const char* data, uint16_t data_len)
{
char chunk_buffer[256]; // 或者使用动态分配
int chunk_len = os_snprintf(chunk_buffer, sizeof(chunk_buffer), "%x\r\n%s\r\n", data_len, data);
send(fd, chunk_buffer, chunk_len, 0);
}
void conver_send(int fd, struct file_info *file_info)
{
char send_buffer[256];
char timestr[15];
os_snprintf(timestr, sizeof(timestr), "%04d%02d%02d%02d%02d%02d",
((file_info->file_date & 0xFE00)>>9)+1980,
(file_info->file_date & 0x1E0)>>5,
(file_info->file_date & 0x1F),
(file_info->file_time & 0xF800)>>11,
(file_info->file_time & 0x7E0)>>5,
(file_info->file_time & 0x1F)*2);
os_snprintf(send_buffer, sizeof(send_buffer), "%s{\"name\":\"%s\",\"size\":%d,\"createtimestr\":\"%s\"}",
(file_info->file_count++ > 0) ? "," : "",
file_info->file_name,
file_info->file_size / 1024,
timestr);
// 发送数据
send_chunk(fd, send_buffer, strlen(send_buffer));
}
int get_fileinfo_send(int fd, const char *search_dir, const char *ext_name, conver_send_fn cs_fn)
{
struct file_info file_info;
FILINFO *fil = NULL;
void *dir = osal_opendir(search_dir);
if (dir)
{
do
{
fil = osal_readdir(dir);
if(!fil) break;
if(fil->fname[0] == 0) break;
if (fil->fname[0] == '.') continue;
if(!osal_dirent_isdir(fil))
{
char *filename = osal_dirent_name(fil);
uint32_t filesize = osal_dirent_size(fil);
uint32_t filedate = osal_dirent_date(fil);
uint32_t filetime = osal_dirent_time(fil);
uint8_t filename_len = os_strlen(filename);
// 检查后缀名是否匹配
if(ext_name)
{
uint8_t ext_filename[16];
uint8_t extname_len = os_strlen(ext_name);
// 进行全部转换成大写
if (filename_len - extname_len > 0)
{
for (uint8_t i = 0; i < os_strlen(ext_name); i++)
{
ext_filename[i] = toupper(filename[filename_len - extname_len + i]);
}
// 后缀名匹配
if (memcmp(ext_name, ext_filename, extname_len) != 0)
{
continue;
}
}
}
file_info.file_name = filename;
file_info.file_size = filesize;
file_info.file_date = filedate;
file_info.file_time = filetime;
file_info.file_count++;
cs_fn(fd, &file_info);
}
} while (fil);
osal_closedir(dir);
}
return file_info.file_count;
}
// 发送demo采用分块发送的方式
void send_stream_filelist(int fd)
{
int video_count = 0;
int photo_count = 0;
char send_buffer[256];
// 创建HTTP响应头
snprintf(send_buffer, sizeof(send_buffer),
"HTTP/1.0 200 OK\r\n"
"Connection: close\r\n"
"Content-Type: application/json\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n");
send(fd, send_buffer, strlen(send_buffer), 0);
// 获取视频
os_snprintf(send_buffer, sizeof(send_buffer), "{\"result\":0,\"info\":[{\"folder\":\"%s\",\"files\":[", LOOP_PREFIX);
send_chunk(fd, send_buffer, strlen(send_buffer));
void *dir = osal_opendir(REC_PATH);
FILINFO *fil = NULL;
char path[64];
if(dir)
{
do
{
fil = osal_readdir(dir);
if(!fil) break;
if(fil->fname[0] == 0) break;
if (fil->fname[0] == '.') continue;
if(osal_dirent_isdir(fil))
{
os_snprintf(path, sizeof(path), "%s/%s", REC_PATH, fil->fname);
video_count += get_fileinfo_send(fd, path, MP4_EXTENSION_NAME, conver_send);
send_chunk(fd, ",", strlen(","));
}
} while(fil);
}
// 获取照片
os_snprintf(send_buffer, sizeof(send_buffer), "],\"count\":%d},{\"folder\":\"%s\",\"files\":[", video_count, EVENT_PREFIX);
send_chunk(fd, send_buffer, strlen(send_buffer));
photo_count = get_fileinfo_send(fd, IMG_PATH, JPG_EXTENSION_NAME, conver_send);
os_snprintf(send_buffer, sizeof(send_buffer), "],\"count\":%d}]}", photo_count);
send_chunk(fd, send_buffer, strlen(send_buffer));
// 发送分块结束标记
send_chunk(fd, "", 0); // 0长度块表示结束
}