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

596 lines
17 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/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;
}