dtplayer如何添加stream
2014-03-25 20:09
471 查看
目录
1 dtstream介绍
2 dtstream接口说明
3 dtstream添加步骤
stream模块和demuxer模块是播放器的数据入口,本篇主要介绍如何添加一个新的stream类型,下篇会介绍如何添加一个新的demuxer。
1 dtstream 介绍
dtstream的主要作用是依据传入的参数. 建立与源的连接,并为dtdemuxer模块提供服务,主要接口有read seek等,
在设计之初由于ffmpeg中demuxer和stream结合的比较紧密,本来是没有这个模块的,后来考虑到整个播放器的模块化以及后续的扩展性
添加了dtstream的模块,用户可以直接在dtstream框架下添加新的stream,如添加一些ffmpeg本身不支持的stream类型: rtsp 等
但由于还未提供dtdemuxer中的demuxer_ffmpeg直接使用dtsteam的接口,后面会添加此功能。
与dtstream模块相关的源代码主要在dtstream目录下,主要有
dtstream_api.c 对外接口
dtstream.c 对下层stream实现的封装,包括选择stream、调用对应stream的方法等
stream/*.c 实际stream的实现,如file rtsp http等
下面介绍下dtstream的代码执行过程。
1.1 register
在播放器开头的初始化阶段,会register所有的stream demuxer decoder render等,具体代码在dtplayer/dtplayer.c中
具体实现在dtstream/dtstream.c中
由于现在只添加了一个file类型,因此只注册了一个
注册过程也很简单,类似ffmpeg中的av_register_all,就是将所有的stream挂载到一个全局的链表g_stream中
1.2 dtstream_open
dtstream是依托dtdemux而存在的,为dtdemux提供服务,因此后续的控制等都由dtdemux来发起,代码在dtdemux/dtdemuxer.c:
int demuxer_open (dtdemuxer_context_t * dem_ctx){ int ret = 0; /* open stream */ dtstream_para_t para; para.stream_name = dem_ctx->file_name; ret = dtstream_open(&dem_ctx->stream_priv,¶,dem_ctx); if(ret != DTERROR_NONE) { dt_error (TAG, "stream open failed \n"); //return -1; } else { //open stream failed, then we use ffmpeg only int64_t old_pos = dtstream_tell(dem_ctx->stream_priv); ret = buf_init(&dem_ctx->probe_buf,PROBE_BUF_SIZE); if(ret < 0) return -1; ret = dtstream_read(dem_ctx->stream_priv,dem_ctx->probe_buf.data,PROBE_BUF_SIZE); if(ret <= 0) return -1; dem_ctx->probe_buf.level = ret; dtstream_seek(dem_ctx->stream_priv,old_pos,SEEK_SET); }......
return 0;}
可以看到在demuxer_open的实现中会构造并初始化dtstream_para_t结构体变量,并调用dtstream_open来初始化dtstream模块
【dtstream/dtstream_api.c】
简单说下,初始化首先构造一个context,之后是选择stream,并调用stream_open
stream_open就是实际stream的封装,这里就不展开了,比较简单。
初始化成功后,基本上就可以为dtdemux提供服务了,剩下的接口大部分播放器都是一致的,read seek skip close等
这里后面介绍实际的stream的时候再说
2 dtstream api介绍
dtstream_api.c dtstream.c可以认为是一个对外,一个对内,对外提供dtstream接口
对内管理内部的各个stream,并在初始化的时候选择合适的stream提供实际的服务。
而这里只介绍 一个典型的stream应该实现哪些接口
在dtstream模块中,主要是实现一个stream_wrapper_t的结构体,定义:
【dtstream/dtstream.h】
主要是函数指针,各个函数的含义为
open 初始化
tell 返回当前读取位置
read 在当前位置读取len大小的数据到buf中,返回实际读取的数据量
seek 在流中seek,whence和pos的定义与read的系统调用定义一致
close 关闭stream,释放内存等
各个成员含义为:
name: stream名称
id: stream id
stream_priv 实际stream可定义自己独有的结构保存在此成员中
parent:上一级管理员,这里为dtstream_context_t
info:一些控制信息,如eof等,这样判断eof就不必到实际的stream中,提高了效率
next: 所有的stream都挂载在一条链表中,这里next指的当前stream的下一个,在register的时候会用到
[b]3 dtstream
添加步骤[/b]
这里以刚添加的stream_file为例,介绍如何在dtstream框架下添加一个新的stream
具体源文件在dtstream/stream/stream_file.c
注意这里不讲细节,只讲如何添加一个stream并在dtplayer中跑起来
3.1 定义结构体
首先是定义一个stream_wrapper_t的结构体,并将其链接到dtstream的全局链表中
这里可以看下示例建立的结构提变量需要按照一定的明明规则,后面会讲回身么,必须是stream_** 格式
这里每添加一个新的stream,需要定义一个ID,统一定义的位置在dtstream/dtstream.h
现在只实现了file ,下一步会添加ffmpe封装
3.2 在注册方法中加入file
代码在dtstream/dtstream.c中
看下宏实现
之前说stream命名需按照规则,作用就在此处,在注册的时候是按照统一的模式进行注册的,
参数FILE 主要是构造成ENABLE_STREAM_FILE来判断在编译的时候是否配置成可用,如果不可用,则不注册
参数file主要是引用实际的变量,即stream_file调用registere_stream进行注册
static stream_wrapper_t *g_stream = NULL;
static void register_stream (stream_wrapper_t * wrapper){ stream_wrapper_t **p; p = &g_stream; while (*p != NULL) p = &((*p)->next); *p = wrapper; wrapper->next = NULL;}
static int stream_select (dtstream_context_t * stm_ctx)
{
if (!g_stream)
return -1;
stm_ctx->stream = g_stream; // select the only one
return 0;
}
实现也比较简单,就是挂载在g_stream的链表中,挂载好后,就可以通过stream_select选择对应的stream了
选择好了之后后面调用dtstream_api的接口时,就会路由到实际注册的stream的实现或者通过封装相应的实现来完成。
3.3 实现stream_wrapper_t的各个部分的功能
这部分就不展开了,但凡自己添加stream的同仁都知道要实现什么样的接口。
实在不清楚的可以邮件我:)
3.4 配置
最后一步是配置编译系统
首先是将源文件加到编译系统中,这里是makefile中添加一行
#dtstreamSRCS_COMMON-$(DT_STREAM) +=dtstream/dtstream_api.cSRCS_COMMON-$(DT_STREAM) +=dtstream/dtstream.c+ SRCS_COMMON-$(DT_STREAM_FILE) +=dtstream/stream/stream_file.c
这样在编译整个项目的时候才能编译到你添加的源文件
再有就是配置config.mk,这里主要就是两部分
其中第一个是用于注册的时候用,第二个是上面Makfile中配置将代码加入编译
至此一个stream就添加成功了。
最后介绍下stream选取的思路, 后面会添加比较多的stream,选择的依据是,最先匹配优先,当都不匹配的时候会选择ffmpeg。
源代码地址:https://github.com/peterfuture/dtplayer
联系开发者:peter_future@outlook.com
blog: http://blog.csdn.net/u011350110
开源中国地址:http://www.oschina.net/p/dtplayer
由于后面随着开发的进行文章会进行细节的更新,因此为了保证读者随时读到最新的内容,文章禁止转载,多谢大家支持。
1 dtstream介绍
2 dtstream接口说明
3 dtstream添加步骤
stream模块和demuxer模块是播放器的数据入口,本篇主要介绍如何添加一个新的stream类型,下篇会介绍如何添加一个新的demuxer。
1 dtstream 介绍
dtstream的主要作用是依据传入的参数. 建立与源的连接,并为dtdemuxer模块提供服务,主要接口有read seek等,
在设计之初由于ffmpeg中demuxer和stream结合的比较紧密,本来是没有这个模块的,后来考虑到整个播放器的模块化以及后续的扩展性
添加了dtstream的模块,用户可以直接在dtstream框架下添加新的stream,如添加一些ffmpeg本身不支持的stream类型: rtsp 等
但由于还未提供dtdemuxer中的demuxer_ffmpeg直接使用dtsteam的接口,后面会添加此功能。
与dtstream模块相关的源代码主要在dtstream目录下,主要有
dtstream_api.c 对外接口
dtstream.c 对下层stream实现的封装,包括选择stream、调用对应stream的方法等
stream/*.c 实际stream的实现,如file rtsp http等
下面介绍下dtstream的代码执行过程。
1.1 register
在播放器开头的初始化阶段,会register所有的stream demuxer decoder render等,具体代码在dtplayer/dtplayer.c中
void player_register_all() {
stream_register_all(); demuxer_register_all(); audio_register_all(); video_register_all(); }
具体实现在dtstream/dtstream.c中
static void stream_register_all () { REGISTER_STREAM (FILE, file); }
由于现在只添加了一个file类型,因此只注册了一个
注册过程也很简单,类似ffmpeg中的av_register_all,就是将所有的stream挂载到一个全局的链表g_stream中
1.2 dtstream_open
dtstream是依托dtdemux而存在的,为dtdemux提供服务,因此后续的控制等都由dtdemux来发起,代码在dtdemux/dtdemuxer.c:
int demuxer_open (dtdemuxer_context_t * dem_ctx){ int ret = 0; /* open stream */ dtstream_para_t para; para.stream_name = dem_ctx->file_name; ret = dtstream_open(&dem_ctx->stream_priv,¶,dem_ctx); if(ret != DTERROR_NONE) { dt_error (TAG, "stream open failed \n"); //return -1; } else { //open stream failed, then we use ffmpeg only int64_t old_pos = dtstream_tell(dem_ctx->stream_priv); ret = buf_init(&dem_ctx->probe_buf,PROBE_BUF_SIZE); if(ret < 0) return -1; ret = dtstream_read(dem_ctx->stream_priv,dem_ctx->probe_buf.data,PROBE_BUF_SIZE); if(ret <= 0) return -1; dem_ctx->probe_buf.level = ret; dtstream_seek(dem_ctx->stream_priv,old_pos,SEEK_SET); }......
return 0;}
可以看到在demuxer_open的实现中会构造并初始化dtstream_para_t结构体变量,并调用dtstream_open来初始化dtstream模块
【dtstream/dtstream_api.c】
int dtstream_open (void **priv, dtstream_para_t * para, void *parent) { dtstream_context_t *ctx = (dtstream_context_t *)malloc(sizeof(dtstream_context_t)); if(!ctx) { dt_error(TAG,"STREAM CTX MALLOC FAILED \n"); return -1; } memset (ctx, 0, sizeof (dtstream_context_t)); ctx->stream_name = para->stream_name; if(stream_open(ctx) == -1) { dt_error(TAG,"STREAM CONTEXT OPEN FAILED \n"); free(ctx); *priv = NULL; return -1; } *priv = (void *)ctx; ctx->parent = parent; dt_info(TAG,"STREAM CTX OPEN SUCCESS\n"); return 0; }
简单说下,初始化首先构造一个context,之后是选择stream,并调用stream_open
stream_open就是实际stream的封装,这里就不展开了,比较简单。
初始化成功后,基本上就可以为dtdemux提供服务了,剩下的接口大部分播放器都是一致的,read seek skip close等
这里后面介绍实际的stream的时候再说
2 dtstream api介绍
dtstream_api.c dtstream.c可以认为是一个对外,一个对内,对外提供dtstream接口
对内管理内部的各个stream,并在初始化的时候选择合适的stream提供实际的服务。
而这里只介绍 一个典型的stream应该实现哪些接口
在dtstream模块中,主要是实现一个stream_wrapper_t的结构体,定义:
【dtstream/dtstream.h】
typedef struct stream_wrapper { char *name; int id; int (*open) (struct stream_wrapper * wrapper,char *stream_name); int64_t (*tell) (struct stream_wrapper * wrapper); int (*read) (struct stream_wrapper * wrapper, uint8_t *buf,int len); int (*seek) (struct stream_wrapper * wrapper, int64_t pos, int whence); int (*close) (struct stream_wrapper * wrapper); void *stream_priv; // point to priv context void *parent; // point to parent, dtstream_context_t stream_ctrl_t info; struct stream_wrapper *next; } stream_wrapper_t;
主要是函数指针,各个函数的含义为
open 初始化
tell 返回当前读取位置
read 在当前位置读取len大小的数据到buf中,返回实际读取的数据量
seek 在流中seek,whence和pos的定义与read的系统调用定义一致
close 关闭stream,释放内存等
各个成员含义为:
name: stream名称
id: stream id
stream_priv 实际stream可定义自己独有的结构保存在此成员中
parent:上一级管理员,这里为dtstream_context_t
info:一些控制信息,如eof等,这样判断eof就不必到实际的stream中,提高了效率
next: 所有的stream都挂载在一条链表中,这里next指的当前stream的下一个,在register的时候会用到
[b]3 dtstream
添加步骤[/b]
这里以刚添加的stream_file为例,介绍如何在dtstream框架下添加一个新的stream
具体源文件在dtstream/stream/stream_file.c
注意这里不讲细节,只讲如何添加一个stream并在dtplayer中跑起来
3.1 定义结构体
首先是定义一个stream_wrapper_t的结构体,并将其链接到dtstream的全局链表中
stream_wrapper_t stream_file = { .name = "File", .id = STREAM_FILE, .open = stream_file_open, .read = stream_file_read, .seek = stream_file_seek, .close = stream_file_close, };
这里可以看下示例建立的结构提变量需要按照一定的明明规则,后面会讲回身么,必须是stream_** 格式
这里每添加一个新的stream,需要定义一个ID,统一定义的位置在dtstream/dtstream.h
typedef enum{ STREAM_INVALID = -1, STREAM_FILE, STREAM_FFMPEG, STREAM_UNSUPPORT }stream_format_t;
现在只实现了file ,下一步会添加ffmpe封装
3.2 在注册方法中加入file
代码在dtstream/dtstream.c中
static void stream_register_all (){ REGISTER_STREAM (FILE, file);}
看下宏实现
#define REGISTER_STREAM(X,x) \ if(ENABLE_STREAM_##X) \ { \ extern stream_wrapper_t stream_##x; \ register_stream(&stream_##x); \ }
之前说stream命名需按照规则,作用就在此处,在注册的时候是按照统一的模式进行注册的,
参数FILE 主要是构造成ENABLE_STREAM_FILE来判断在编译的时候是否配置成可用,如果不可用,则不注册
参数file主要是引用实际的变量,即stream_file调用registere_stream进行注册
static stream_wrapper_t *g_stream = NULL;
static void register_stream (stream_wrapper_t * wrapper){ stream_wrapper_t **p; p = &g_stream; while (*p != NULL) p = &((*p)->next); *p = wrapper; wrapper->next = NULL;}
static int stream_select (dtstream_context_t * stm_ctx)
{
if (!g_stream)
return -1;
stm_ctx->stream = g_stream; // select the only one
return 0;
}
实现也比较简单,就是挂载在g_stream的链表中,挂载好后,就可以通过stream_select选择对应的stream了
选择好了之后后面调用dtstream_api的接口时,就会路由到实际注册的stream的实现或者通过封装相应的实现来完成。
3.3 实现stream_wrapper_t的各个部分的功能
这部分就不展开了,但凡自己添加stream的同仁都知道要实现什么样的接口。
实在不清楚的可以邮件我:)
3.4 配置
最后一步是配置编译系统
首先是将源文件加到编译系统中,这里是makefile中添加一行
#dtstreamSRCS_COMMON-$(DT_STREAM) +=dtstream/dtstream_api.cSRCS_COMMON-$(DT_STREAM) +=dtstream/dtstream.c+ SRCS_COMMON-$(DT_STREAM_FILE) +=dtstream/stream/stream_file.c
这样在编译整个项目的时候才能编译到你添加的源文件
再有就是配置config.mk,这里主要就是两部分
+DT_CFLAGS += -DENABLE_STREAM_FILE=1 +DT_STREAM_FILE=yes
其中第一个是用于注册的时候用,第二个是上面Makfile中配置将代码加入编译
至此一个stream就添加成功了。
最后介绍下stream选取的思路, 后面会添加比较多的stream,选择的依据是,最先匹配优先,当都不匹配的时候会选择ffmpeg。
源代码地址:https://github.com/peterfuture/dtplayer
联系开发者:peter_future@outlook.com
blog: http://blog.csdn.net/u011350110
开源中国地址:http://www.oschina.net/p/dtplayer
由于后面随着开发的进行文章会进行细节的更新,因此为了保证读者随时读到最新的内容,文章禁止转载,多谢大家支持。
相关文章推荐
- rstp设备之间的对接
- php正则表达式攻略
- discuz x3.1 去除后面的portal.php
- php中如何实现网上商城用户历史浏览记录的代码
- PHP header
- StagefrightPlayer&&AwesomePlayer 初步分析
- PHP集成支付宝快速实现充值功能
- PHP集成支付宝快速实现充值功能
- PHP整理CMS无限层级目录(毗邻目录模式)
- SWT EditPart组合快捷键
- 搭建vsftp
- PHP简单登录退出代码
- PHP 局域网其他机器无法访问的问题
- php常用函数
- php延迟加载的示例
- php排序测试
- php处理字符串格式的计算公式
- 用php实现对AJAX引擎和RSS内容的桥接
- YII中actionadmin对应的gridview数据的排序
- 如何利用PHP函数实现桥接AJAX引擎和RSS内容