319 lines
9.1 KiB
C
319 lines
9.1 KiB
C
|
|
#include "basic_include.h"
|
|||
|
|
#include "lib/posix/stdio.h"
|
|||
|
|
#include "lib/multimedia/msi.h"
|
|||
|
|
#include "fatfs/osal_file.h"
|
|||
|
|
#include "fatfs/ff.h"
|
|||
|
|
|
|||
|
|
#define MSI_URLFILE (0)
|
|||
|
|
#if MSI_URLFILE
|
|||
|
|
#include "lib/net/urlfile/urlfile.h"
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
enum MSI_FILE_CMD {
|
|||
|
|
MSI_FILE_CMD_OPEN,
|
|||
|
|
MSI_FILE_CMD_CLOSE,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
enum MSI_FILE_STATE {
|
|||
|
|
MSI_FILE_STATE_IDLE,
|
|||
|
|
MSI_FILE_STATE_OPEN,
|
|||
|
|
MSI_FILE_STATE_READ,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
#define MSI_FILENAME_MAX (512)
|
|||
|
|
#define MSI_FILE_CMD_MAX (8)
|
|||
|
|
#define MSI_FILE_NUM_TRY (5)
|
|||
|
|
|
|||
|
|
#define MSIFILE_DBG(fmt, ...) os_printf("%s:%d::"fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
|||
|
|
#define MSIFILE_ERR(fmt, ...) os_printf(KERN_ERR"%s:%d::"fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
|||
|
|
|
|||
|
|
#define URLFILE(file) (os_strstr(file, "://") != NULL)
|
|||
|
|
|
|||
|
|
struct msi_file {
|
|||
|
|
struct os_task task;
|
|||
|
|
struct msi *msi;
|
|||
|
|
const char *name;
|
|||
|
|
uint8 running: 1, eof: 1, filelist: 1, rev: 5;
|
|||
|
|
uint8 state;
|
|||
|
|
uint16 file_idx;
|
|||
|
|
void *fp;
|
|||
|
|
char file_name[MSI_FILENAME_MAX];
|
|||
|
|
char *file_ext; //文件扩展名
|
|||
|
|
atomic8_t fb_cnt; //未被释放的framebuff个数
|
|||
|
|
uint8 fb_max; //允许使用的framebuff最大个数
|
|||
|
|
uint8 speed; //读取速度,用于倍速播放控制
|
|||
|
|
RBUFFER_DEF(cmd, uint8, MSI_FILE_CMD_MAX);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
extern void *fopen(const char *filename, const char *mode);
|
|||
|
|
extern size_t fread(void *ptr, size_t size, size_t nmemb, void *stream);
|
|||
|
|
extern int fclose(void *stream);
|
|||
|
|
|
|||
|
|
static void *msi_filestream_fopen(struct msi_file *msifile)
|
|||
|
|
{
|
|||
|
|
#if MSI_URLFILE
|
|||
|
|
if(URLFILE(msifile->file_name))
|
|||
|
|
return uf_open(msifile->file_name, 0);
|
|||
|
|
#endif
|
|||
|
|
return fopen(msifile->file_name, "r");
|
|||
|
|
}
|
|||
|
|
static int msi_filestream_fclose(struct msi_file *msifile)
|
|||
|
|
{
|
|||
|
|
if(msifile->fp){
|
|||
|
|
#if MSI_URLFILE
|
|||
|
|
if(URLFILE(msifile->file_name))
|
|||
|
|
return uf_close(msifile->fp);
|
|||
|
|
#endif
|
|||
|
|
return fclose(msifile->fp);
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
static size_t msi_filestream_fread(void *ptr, size_t size, size_t nmemb, struct msi_file *msifile)
|
|||
|
|
{
|
|||
|
|
#if MSI_URLFILE
|
|||
|
|
if(URLFILE(msifile->file_name))
|
|||
|
|
return uf_read(ptr, size, nmemb, msifile->fp);
|
|||
|
|
#endif
|
|||
|
|
return fread(ptr, size, nmemb, msifile->fp);
|
|||
|
|
}
|
|||
|
|
static int msi_filestream_fseek(struct msi_file *msifile, off_t offset, int whence)
|
|||
|
|
{
|
|||
|
|
#if MSI_URLFILE
|
|||
|
|
if(URLFILE(msifile->file_name))
|
|||
|
|
return uf_seek(msifile->fp, offset, whence);
|
|||
|
|
#endif
|
|||
|
|
return fseek(msifile->fp, offset, whence);//
|
|||
|
|
}
|
|||
|
|
static int msi_filestream_feof(struct msi_file *msifile)
|
|||
|
|
{
|
|||
|
|
#if MSI_URLFILE
|
|||
|
|
if(URLFILE(msifile->file_name))
|
|||
|
|
return uf_eof(msifile->fp);
|
|||
|
|
#endif
|
|||
|
|
return feof(msifile->fp);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int32 msi_filestream_action(struct msi *msi, uint32 cmd_id, uint32 param1, uint32 param2)
|
|||
|
|
{
|
|||
|
|
int32 ret = RET_OK;
|
|||
|
|
struct msi_file *msifile = (struct msi_file *)msi->priv;
|
|||
|
|
|
|||
|
|
switch (cmd_id) {
|
|||
|
|
case MSI_CMD_POST_DESTROY:
|
|||
|
|
while (msifile->running) {
|
|||
|
|
os_sleep_ms(10);
|
|||
|
|
}
|
|||
|
|
os_free(msifile);
|
|||
|
|
break;
|
|||
|
|
case MSI_CMD_FREE_FB:
|
|||
|
|
break;
|
|||
|
|
case MSI_CMD_SET_SPEED: //设置播放倍速,控制数据读取行为
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
return ret;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static void msi_filestream_check_filename(struct msi_file *msifile)
|
|||
|
|
{
|
|||
|
|
msifile->filelist = 0;
|
|||
|
|
msifile->file_idx = 0;
|
|||
|
|
|
|||
|
|
//检查是否存在文件列表,支持自动切换文件,格式要求:xxxx_001.avi
|
|||
|
|
if (msifile->file_ext) {
|
|||
|
|
char *ptr = msifile->file_ext - 4;
|
|||
|
|
if (ptr[0] == '_' && isdigit(ptr[1]) && isdigit(ptr[2]) && isdigit(ptr[3])) {
|
|||
|
|
msifile->filelist = 1;
|
|||
|
|
msifile->file_idx = os_atoi(ptr + 1);
|
|||
|
|
MSIFILE_DBG("start index %d\r\n", msifile->file_idx);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int32 msi_filestream_open_file(struct msi_file *msifile)
|
|||
|
|
{
|
|||
|
|
char *ptr;
|
|||
|
|
int32 i = 0;
|
|||
|
|
|
|||
|
|
msi_filestream_fclose(msifile);
|
|||
|
|
if (msifile->eof) {
|
|||
|
|
if (!msifile->filelist) {
|
|||
|
|
MSIFILE_ERR("read over!\r\n");
|
|||
|
|
msifile->state = MSI_FILE_STATE_IDLE;
|
|||
|
|
SYSEVT_NEW_MEDIA_EVT(SYSEVT_MEDIA_READ_EOF, (uint32)msifile);
|
|||
|
|
return RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ptr = msifile->file_ext - 4;
|
|||
|
|
for (i = 1; i <= MSI_FILE_NUM_TRY; i++) {
|
|||
|
|
os_sprintf(ptr + 1, "%03d", msifile->file_idx + i);
|
|||
|
|
msifile->fp = msi_filestream_fopen(msifile->file_name);
|
|||
|
|
if (msifile->fp) {
|
|||
|
|
MSIFILE_ERR("open %s success!\r\n", msifile->file_name);
|
|||
|
|
msifile->file_idx += i;
|
|||
|
|
msifile->state = MSI_FILE_STATE_READ;
|
|||
|
|
msifile->eof = 0;
|
|||
|
|
return RET_OK;
|
|||
|
|
} else {
|
|||
|
|
MSIFILE_ERR("open %s fail!\r\n", msifile->file_name);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
os_sprintf(ptr + 1, "%03d", msifile->file_idx);
|
|||
|
|
MSIFILE_ERR("read over! last file:%s\r\n", msifile->file_name);
|
|||
|
|
SYSEVT_NEW_MEDIA_EVT(SYSEVT_MEDIA_READ_EOF, (uint32)msifile);
|
|||
|
|
} else {
|
|||
|
|
msifile->file_ext = os_strrchr(msifile->file_name, '.'); //文件扩展名
|
|||
|
|
msifile->fp = msi_filestream_fopen(msifile->file_name);
|
|||
|
|
if (msifile->fp) {
|
|||
|
|
msi_filestream_check_filename(msifile);
|
|||
|
|
} else {
|
|||
|
|
SYSEVT_NEW_MEDIA_EVT(SYSEVT_MEDIA_OPEN_FAIL, (uint32)msifile);
|
|||
|
|
MSIFILE_ERR("open %s fail!\r\n", msifile->file_name);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//根据扩展名,加载对应的插件
|
|||
|
|
|
|||
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|||
|
|
msifile->state = msifile->fp ? MSI_FILE_STATE_READ : MSI_FILE_STATE_IDLE;
|
|||
|
|
return msifile->fp ? RET_OK : RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int32 msi_filestream_read_file(struct msi_file *msifile, struct framebuff **fb)
|
|||
|
|
{
|
|||
|
|
if (atomic_read(&msifile->fb_cnt) >= msifile->fb_max + 1) {
|
|||
|
|
return -ENOMEM;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//插件参与控制读取数据的行为: 比如 按帧读取数据,倍速跳帧
|
|||
|
|
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static void msi_filestream_proc_cmd(struct msi_file *msifile)
|
|||
|
|
{
|
|||
|
|
uint8 cmd;
|
|||
|
|
while (!RB_EMPTY(&msifile->cmd)) {
|
|||
|
|
RB_GET(&msifile->cmd, cmd);
|
|||
|
|
switch (cmd) {
|
|||
|
|
case MSI_FILE_CMD_OPEN:
|
|||
|
|
msifile->eof = 0;
|
|||
|
|
msifile->state = MSI_FILE_STATE_OPEN;
|
|||
|
|
break;
|
|||
|
|
case MSI_FILE_CMD_CLOSE:
|
|||
|
|
msifile->state = MSI_FILE_STATE_IDLE;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static void msi_filestream_task(void *arg)
|
|||
|
|
{
|
|||
|
|
int32 ret = 0;
|
|||
|
|
struct framebuff *fb = NULL;
|
|||
|
|
struct msi_file *msifile = (struct msi_file *)arg;
|
|||
|
|
|
|||
|
|
MSIFILE_DBG("msi_file running ...\r\n");
|
|||
|
|
msifile->running = 1;
|
|||
|
|
while (msifile->msi->enable) {
|
|||
|
|
msi_filestream_proc_cmd(msifile);
|
|||
|
|
switch (msifile->state) {
|
|||
|
|
case MSI_FILE_STATE_IDLE:
|
|||
|
|
os_sleep_ms(10);
|
|||
|
|
break;
|
|||
|
|
case MSI_FILE_STATE_OPEN:
|
|||
|
|
msi_filestream_open_file(msifile);
|
|||
|
|
break;
|
|||
|
|
case MSI_FILE_STATE_READ:
|
|||
|
|
fb = NULL;
|
|||
|
|
ret = msi_filestream_read_file(msifile, &fb);
|
|||
|
|
if (fb) {
|
|||
|
|
atomic_inc(&msifile->fb_cnt);
|
|||
|
|
msi_output_fb(msifile->msi, fb);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (msifile->eof) { //当前文件读取结束
|
|||
|
|
msifile->state = MSI_FILE_STATE_OPEN;
|
|||
|
|
} else if (ret < 0 && msifile->msi->enable) {
|
|||
|
|
os_sleep_ms(10);
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (msifile->fp) {
|
|||
|
|
msi_filestream_fclose(msifile);
|
|||
|
|
msifile->fp = NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
MSIFILE_DBG("msi_file stopped!\r\n");
|
|||
|
|
msifile->running = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void *msi_filestream_init(const char *name, uint8 fb_max)
|
|||
|
|
{
|
|||
|
|
struct msi_file *msifile = os_zalloc(sizeof(struct msi_file));
|
|||
|
|
if (msifile == NULL) {
|
|||
|
|
MSIFILE_ERR("no memory!\r\n");
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
RB_INIT(&msifile->cmd, MSI_FILE_CMD_MAX);
|
|||
|
|
msifile->fb_max = fb_max;
|
|||
|
|
msifile->name = name;
|
|||
|
|
msifile->msi = msi_new(name, 0, NULL);
|
|||
|
|
if (msifile->msi == NULL) {
|
|||
|
|
os_free(msifile);
|
|||
|
|
MSIFILE_ERR("no memory!\r\n");
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ASSERT(msifile->msi->priv == NULL);
|
|||
|
|
msifile->msi->priv = msifile;
|
|||
|
|
msifile->msi->action = msi_filestream_action;
|
|||
|
|
msifile->msi->enable = 1;
|
|||
|
|
OS_TASK_INIT(name, &msifile->task, msi_filestream_task, msifile, OS_TASK_PRIORITY_NORMAL, NULL,1024);
|
|||
|
|
MSIFILE_DBG("msi_file %s init!\r\n", name);
|
|||
|
|
return msifile;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int32 msi_filestream_destory(void *hdl)
|
|||
|
|
{
|
|||
|
|
if (hdl) {
|
|||
|
|
struct msi_file *msifile = (struct msi_file *)hdl;
|
|||
|
|
msi_destroy(msifile->msi); //msi被释放时会通过MSI_CMD_DESTORY通知msifile释放资源
|
|||
|
|
return RET_OK;
|
|||
|
|
} else {
|
|||
|
|
return -EINVAL;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int32 msi_filestream_close(void *hdl)
|
|||
|
|
{
|
|||
|
|
if (hdl) {
|
|||
|
|
struct msi_file *msifile = (struct msi_file *)hdl;
|
|||
|
|
RB_SET(&msifile->cmd, MSI_FILE_CMD_CLOSE);
|
|||
|
|
return RET_OK;
|
|||
|
|
} else {
|
|||
|
|
return -EINVAL;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int32 msi_filestream_open(void *hdl, char *file)
|
|||
|
|
{
|
|||
|
|
if (hdl) {
|
|||
|
|
struct msi_file *msifile = (struct msi_file *)hdl;
|
|||
|
|
if (os_strlen(file) >= MSI_FILENAME_MAX) {
|
|||
|
|
return -ENAMETOOLONG;
|
|||
|
|
}
|
|||
|
|
os_strcpy(msifile->file_name, file);
|
|||
|
|
RB_SET(&msifile->cmd, MSI_FILE_CMD_OPEN);
|
|||
|
|
return RET_OK;
|
|||
|
|
} else {
|
|||
|
|
return -EINVAL;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|