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