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