Files
TAIXIN/sdk/lib/multimedia/mplayer/txmplayer.c

596 lines
17 KiB
C
Raw Normal View History

#include "basic_include.h"
#include "lib/multimedia/msi.h"
#include "txmplayer.h"
#define TXMPLAYER_STREAM_MAX (4)
#define URLFILE(file) (os_strstr(file, "://") != NULL)
extern void *fopen(const char *filename, const char *mode);
extern void fclose(void *stream);
extern size_t fread(void *ptr, size_t size, size_t nmemb, void *stream);
extern int fseek(void *stream, long int offset, int whence);
extern long ftell(void *stream);
extern int feof(void *stream);
extern void *uf_open(char *url, char *mode, uint32 flags);
extern void uf_close(void *file);
extern size_t uf_read(void *ptr, size_t size, size_t nmemb, void *file);
extern int uf_seek(void *file, long int offset, int whence);
extern int uf_eof(void *file);
extern ulong uf_filesize(void *fp, uint32 size);
extern int32 uf_seektype(void *fp);
struct txmplayer_codec {
uint8 type;
struct msi *codec;
};
#define TXMPLAYER_HDRDATA_SIZE (2048)
struct txmplayer_stream {
ulong total_size;
void *file;
uint8 pause; //暂停读取数据
void *container_ctx; //container私有数据
const txmplayer_container *container; //关联的container
const struct txmplayer_input_ops *ops;
struct txmplayer_codec codecs[MEDIA_DATA_MAX]; //各路编码流的decoder
struct txmplayer_audio_info audio_info;
struct txmplayer_video_info video_info;
struct txmplayer_picture_info pic_info;
uint32 last_input_time; //最后一次输入数据的时间
};
struct txmplayer {
struct msi *msi;
os_mutex_t lock;
uint8 pause: 1, mute: 1, init: 1, rev: 4;
uint8 volume;
uint8 stream_max;
int8 msi_stream;
void *task_hdl;
uint32 containers_cnt;
const txmplayer_container *containers;
struct txmplayer_stream streams[TXMPLAYER_STREAM_MAX];
struct framebuff *fb;
uint32 fb_off;
} g_txmplayer;
size_t msi_read(void *ptr, size_t size, size_t nmemb, void *stream)
{
uint32 len = 0;
if (g_txmplayer.fb == NULL) {
g_txmplayer.fb = msi_get_fb(g_txmplayer.msi, 0);
g_txmplayer.fb_off = 0;
}
if (g_txmplayer.fb) {
len = size * nmemb;
if (len == 0) {
return 0;
}
len = min(len, (g_txmplayer.fb->len - g_txmplayer.fb_off));
hw_memcpy(ptr, g_txmplayer.fb->data + g_txmplayer.fb_off, len);
g_txmplayer.fb_off += len;
if (g_txmplayer.fb_off >= g_txmplayer.fb->len) {
fb_put(g_txmplayer.fb);
g_txmplayer.fb = NULL;
}
}
return len;
}
void msi_close(void *stream)
{
}
int msi_seek(void *hdl, long int offset, int whence)
{
return -ENOTSUP;
}
int msi_eof(void *stream)
{
return 0;
}
const struct txmplayer_input_ops msi_ops = {
.close = msi_close,
.read = msi_read,
.seek = msi_seek,
.eof = msi_eof,
};
const struct txmplayer_input_ops file_ops = {
.close = fclose,
.read = fread,
.seek = fseek,
.eof = feof,
};
const struct txmplayer_input_ops uf_ops = {
.close = uf_close,
.read = uf_read,
.seek = uf_seek,
.eof = uf_eof,
};
static struct msi *txmplayer_find_decoder(uint16 type)
{
struct msi *pmsi = NULL;
const char *name = NULL;
switch (type) {
case F_H264:
name = "h264_dec";
break;
default:
break;
}
pmsi = msi_find(name, 0);
if (pmsi == NULL) {
SYSEVT_NEW_MEDIA_EVT(SYSEVT_MEDIA_UNKNOWN_DECODER, type);
}
return pmsi;
}
static const txmplayer_container *txmplayer_find_container(uint32 type)
{
uint32 i = 0;
for (i = 0; i < g_txmplayer.containers_cnt; i++) {
if (g_txmplayer.containers[i].type == type) {
return &g_txmplayer.containers[i];
}
}
SYSEVT_NEW_MEDIA_EVT(SYSEVT_MEDIA_UNKNOWN_CONTAINER, type);
return NULL;
}
static int32 txmplayer_match_container(struct txmplayer_stream *stream, uint8 *data, uint32 len)
{
uint32 mtype;
if (stream->container_ctx == NULL) {
mtype = txmplayer_detect_mtype(data, len); //检测媒体数据类型
stream->container = txmplayer_find_container(mtype); //根据类型查找container
if (stream->container == NULL) {
return RET_ERR;
}
stream->container_ctx = stream->container->open(stream->total_size, data, len);
if (stream->container_ctx == NULL) {
SYSEVT_NEW_MEDIA_EVT(SYSEVT_MEDIA_CONTAINER_OPEN_ERROR, mtype);
return RET_ERR;
}
SYSEVT_NEW_MEDIA_EVT(SYSEVT_MEDIA_CONTAINER_MATCH, mtype);
}
return RET_OK;
}
static int32 txmplayer_release_stream(uint8 id)
{
int8 i = 0;
struct txmplayer_stream *stream = &g_txmplayer.streams[id];
for (i = 0; i < MEDIA_DATA_MAX; i++) {
msi_put(stream->codecs[i].codec);
stream->codecs[i].codec = NULL;
stream->codecs[i].type = MEDIA_DATA_MAX;
}
if (stream->container_ctx) {
stream->container->close(stream->container_ctx);
}
if (stream->ops) {
stream->ops->close(stream->file);
}
if (stream->file == g_txmplayer.msi) {
g_txmplayer.msi_stream = -1;
}
stream->pause = 0;
stream->last_input_time = 0;
stream->container_ctx = NULL;
stream->container = NULL;
stream->file = NULL;
stream->ops = NULL;
return RET_OK;
}
static int32 txmplayer_request_stream(const struct txmplayer_input_ops *ops, void *file)
{
uint8 i = 0;
int8 last = -1;
for (i = 0; i < g_txmplayer.stream_max; i++) {
if (g_txmplayer.streams[i].file == NULL) {
g_txmplayer.streams[i].ops = ops;
g_txmplayer.streams[i].file = file;
return i;
}
if ((last == -1) || (g_txmplayer.streams[i].last_input_time < g_txmplayer.streams[last].last_input_time)) {
last = i;
}
}
txmplayer_release_stream(last);
g_txmplayer.streams[last].ops = ops;
g_txmplayer.streams[last].file = file;
return last;
}
static int32 txmplayer_check_filesize(uint8 id)
{
struct txmplayer_stream *stream = &g_txmplayer.streams[id];
if (stream->total_size == 0) {
if (stream->ops == &file_ops) {
stream->ops->seek(stream->file, 0, SEEK_END);
stream->total_size = ftell(stream->file);
stream->ops->seek(stream->file, 0, SEEK_SET);
} else if ((stream->ops == &uf_ops)) {
stream->total_size = uf_filesize(stream->file, TXMPLAYER_HDRDATA_SIZE);
if (stream->total_size == 0) { //等待网络数据
txm_dbg("waitting for connectting ...\r\n");
return -EAGAIN;
}
} else {
stream->total_size = -1;
}
SYSEVT_NEW_MEDIA_EVT(SYSEVT_MEDIA_OPEN_SUCCESS, id);
}
return RET_OK;
}
static int32 txmplayer_proc_read_data(void)
{
int8 i = 0;
int8 more = 0;
uint32 len;
struct txmplayer_stream *stream;
uint8 *buff = NULL;
for (i = 0; i < g_txmplayer.stream_max; i++) {
stream = &g_txmplayer.streams[i];
if (stream->ops && stream->file != g_txmplayer.msi && !stream->pause) {
if (txmplayer_check_filesize(i) == -EAGAIN) {
return 0; //等待网络连接成功
}
if (stream->container_ctx == NULL) { //匹配container
buff = os_malloc(TXMPLAYER_HDRDATA_SIZE); //预读header数据,用于检测媒体类型
if (buff) {
len = stream->ops->read(buff, 1, TXMPLAYER_HDRDATA_SIZE, stream->file);
if (len > 0) {
if (txmplayer_match_container(stream, buff, len)) {
txmplayer_release_stream(i);
txm_err("unknown media format!\r\n");
}
}
os_free(buff);
} else {
txm_err("no memory!\r\n");
}
}
//执行demux解析一笔数据
if (stream->container_ctx && stream->container->demux(stream->container_ctx, stream->ops, stream->file, stream)) {
stream->last_input_time = os_seconds();
more = 1;
}
}
}
return more;
}
//处理通过MSI组件流程输入的fb
static int32 txmplayer_proc_msi_data()
{
struct framebuff *fb;
struct txmplayer_stream *stream;
if (g_txmplayer.msi_stream != -1 && g_txmplayer.streams[g_txmplayer.msi_stream].container_ctx) {
stream = &g_txmplayer.streams[g_txmplayer.msi_stream];
if (!stream->pause) {
return stream->container->demux(stream->container_ctx, stream->ops, stream->file, stream);
}
return 0;
}
fb = msi_get_fb(g_txmplayer.msi, 0);
if (fb) {
if (!g_txmplayer.msi->enable) {
fb_put(fb);
txm_err("TXMplayer stopped!\r\n");
return 1;
}
if (g_txmplayer.msi_stream == -1) {
g_txmplayer.msi_stream = txmplayer_request_stream(&msi_ops, g_txmplayer.msi);
}
stream = &g_txmplayer.streams[g_txmplayer.msi_stream];
stream->last_input_time = os_seconds();
stream->total_size = -1;
MEDIA_DATA_CATEGORY dtype = fb_category(fb);
if (dtype == MEDIA_DATA_MAX) { //未知类型识别container进行解封装
if (txmplayer_match_container(stream, fb->data, fb->len)) {
txmplayer_release_stream(g_txmplayer.msi_stream);
txm_err("unknown media format!\r\n");
}
fb_put(fb);
} else { //已知类型直接传递给decoder解码
txmplayer_stream_output(stream, fb);
}
return 1;
}
return 0;
}
static void txmplayer_thread(void *arg)
{
uint8 more_data = 0;
while (1) {
if (!g_txmplayer.pause) {
os_mutex_lock(&g_txmplayer.lock, osWaitForever);
more_data |= txmplayer_proc_msi_data();
more_data |= txmplayer_proc_read_data();
os_mutex_unlock(&g_txmplayer.lock);
}
if (!more_data) {
os_sleep_ms(10);
}
more_data = 0;
}
}
//container解封装构建fb之后执行此函数输出fb。
//该函数根据编码类型:fb->mtype查找对应的解码模块输出fb
int32 txmplayer_stream_output(void *priv, struct framebuff *fb)
{
struct msi *decoder = NULL;
struct txmplayer_stream *stream = priv;
MEDIA_DATA_CATEGORY dtype = fb_category(fb);
if (fb->msi == NULL) {
msi_get(g_txmplayer.msi);
fb->msi = g_txmplayer.msi;
}
if (dtype == MEDIA_DATA_MAX) {
fb_put(fb);
return -ENOTSUP;
}
if (fb->mtype != stream->codecs[dtype].type) { //编码类型发生变化,需要重新选择解码模块
msi_put(stream->codecs[dtype].codec);
stream->codecs[dtype].codec = NULL;
stream->codecs[dtype].type = fb->mtype;
}
if (stream->codecs[dtype].codec == NULL) {
stream->codecs[dtype].codec = txmplayer_find_decoder(fb->mtype);
}
decoder = stream->codecs[dtype].codec;
if (decoder && decoder->enable) {
if (msi_do_cmd(decoder, MSI_CMD_TRANS_FB, (uint32)fb, 0) == RET_OK) {
if (decoder->fbQ.init) {
fbq_enqueue(&decoder->fbQ, fb);
}
}
fb_put(fb);
return RET_OK;
} else {
fb_put(fb);
return -ENOTSUP;
}
}
static int32 txmplayer_msi_action(struct msi *msi, uint32 cmd_id, uint32 param1, uint32 param2)
{
int32_t ret = RET_OK;
switch (cmd_id) {
case MSI_CMD_TRANS_FB:
break;
case MSI_CMD_FREE_FB:
break;
case MSI_CMD_POST_DESTROY:
break;
default:
break;
}
return ret;
}
int32 txmplayer_init(uint8 stream_max, const txmplayer_container *containers, uint32 container_cnt, uint32 stack_size)
{
ASSERT(containers && container_cnt);
if (stream_max == 0) stream_max = 1;
if (stack_size == 0) stack_size = 1024;
os_mutex_init(&g_txmplayer.lock);
g_txmplayer.stream_max = min(stream_max, TXMPLAYER_STREAM_MAX);
g_txmplayer.containers = containers;
g_txmplayer.containers_cnt = container_cnt;
g_txmplayer.msi = msi_new("txmplayer", 256, NULL);
g_txmplayer.task_hdl = os_task_create("txmplayer", txmplayer_thread, NULL, OS_TASK_PRIORITY_HIGH, 5, NULL, stack_size);
ASSERT(g_txmplayer.msi && g_txmplayer.task_hdl);
g_txmplayer.msi->action = (msi_action)txmplayer_msi_action;
g_txmplayer.msi->enable = 1;
g_txmplayer.init = 1;
return RET_OK;
}
int32 txmplayer_deinit()
{
int8 i = 0;
struct framebuff *fb;
ASSERT(g_txmplayer.init);
g_txmplayer.init = 0;
g_txmplayer.msi->enable = 0;
os_mutex_lock(&g_txmplayer.lock, osWaitForever);
os_task_destroy(g_txmplayer.task_hdl);
for (i = 0; i < g_txmplayer.stream_max; i++) {
txmplayer_release_stream(i);
}
if (g_txmplayer.fb) {
fb_put(g_txmplayer.fb);
g_txmplayer.fb = NULL;
}
fb = msi_get_fb(g_txmplayer.msi, 0);
while (fb) {
fb_put(fb);
fb = msi_get_fb(g_txmplayer.msi, 0);
}
os_mutex_unlock(&g_txmplayer.lock);
msi_destroy(g_txmplayer.msi);
g_txmplayer.pause = 0;
g_txmplayer.mute = 0;
g_txmplayer.volume = 0;
g_txmplayer.msi_stream = -1;
g_txmplayer.task_hdl = NULL;
g_txmplayer.msi = NULL;
SYSEVT_NEW_MEDIA_EVT(SYSEVT_MEDIA_PLAY_CLOSE, 0);
return RET_OK;
}
int32 txmplayer_open(char *file)
{
int32 ret = -EIO;
void *file_hdl;
const struct txmplayer_input_ops *ops;
ASSERT(g_txmplayer.init);
if (URLFILE(file)) {
ops = &uf_ops;
file_hdl = uf_open(file, "rav", 0);
} else {
ops = &file_ops;
file_hdl = fopen(file, "r");
}
if (file_hdl == NULL) {
txm_err("open %s fail\r\n", file);
SYSEVT_NEW_MEDIA_EVT(SYSEVT_MEDIA_OPEN_FAIL, 0);
return RET_ERR;
}
os_mutex_lock(&g_txmplayer.lock, osWaitForever);
if (g_txmplayer.init) {
ret = txmplayer_request_stream(ops, file_hdl);
}
os_mutex_unlock(&g_txmplayer.lock);
if (ret < 0) {
ops->close(file_hdl);
} else {
SYSEVT_NEW_MEDIA_EVT(SYSEVT_MEDIA_PLAY_START, ret);
}
return ret;
}
int32 txmplayer_stop(uint8 stream_id)
{
ASSERT(g_txmplayer.init);
if (stream_id < g_txmplayer.stream_max) {
os_mutex_lock(&g_txmplayer.lock, osWaitForever);
if (g_txmplayer.init) {
txmplayer_release_stream(stream_id);
SYSEVT_NEW_MEDIA_EVT(SYSEVT_MEDIA_PLAY_STOP, stream_id);
}
os_mutex_unlock(&g_txmplayer.lock);
return RET_OK;
}
return -EINVAL;
}
int32 txmplayer_pause(uint8 stream_id, uint8 pause)
{
ASSERT(g_txmplayer.init);
if (stream_id < g_txmplayer.stream_max) {
os_mutex_lock(&g_txmplayer.lock, osWaitForever);
if (g_txmplayer.init) {
g_txmplayer.streams[stream_id].pause = pause;
//TBD ..........
if(pause){
SYSEVT_NEW_MEDIA_EVT(SYSEVT_MEDIA_PLAY_PAUSE, stream_id);
}else{
SYSEVT_NEW_MEDIA_EVT(SYSEVT_MEDIA_PLAYING, stream_id);
}
}
os_mutex_unlock(&g_txmplayer.lock);
return RET_OK;
}
return -EINVAL;
}
int32 txmplayer_seek(uint8 stream_id, uint32 new_time)
{
struct txmplayer_stream *stream;
ASSERT(g_txmplayer.init);
if (stream_id < g_txmplayer.stream_max) {
os_mutex_lock(&g_txmplayer.lock, osWaitForever);
if (g_txmplayer.init) {
stream = &g_txmplayer.streams[stream_id];
if (stream->file) {
if (stream->total_size == (ulong)(-1)) {
os_mutex_unlock(&g_txmplayer.lock);
SYSEVT_NEW_MEDIA_EVT(SYSEVT_MEDIA_PLAY_SEEK_ERR, stream_id);
txm_err("Livestream, Can not seek!\r\n");
return -ENOTSUP;
} else {
if (stream->ops == &uf_ops && uf_seektype(stream->file) == 1) { //time seek: 直接执行seek操作
stream->ops->seek(stream->file, new_time, SEEK_SET);
} else if (stream->container) { //由container执行seek
stream->container->seek(stream->container_ctx, new_time);
}
}
}
}
os_mutex_unlock(&g_txmplayer.lock);
return RET_OK;
}
return -EINVAL;
}
int32 txmplayer_set_speed(uint8 stream_id, MEDIA_PLAY_SPEED speed)
{
ASSERT(g_txmplayer.init);
os_mutex_lock(&g_txmplayer.lock, osWaitForever);
//TBD ..........
os_mutex_unlock(&g_txmplayer.lock);
return RET_OK;
}
int32 txmplayer_set_volume(uint8 stream_id, uint8 volume)
{
ASSERT(g_txmplayer.init);
os_mutex_lock(&g_txmplayer.lock, osWaitForever);
//TBD ..........
os_mutex_unlock(&g_txmplayer.lock);
return RET_OK;
}