Files
TAIXIN/sdk/lib/multimedia/msi_file/msi_file.c

319 lines
9.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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