PVPlayer的实现方式
关于opencore下多媒体播放,在mediaserver进程里面仅仅有一行代码:
MediaPlayerService::instantiate();
这行代码的作用是初始化一个MediaPlayerService类的实例,并接把他增加到系统的serveceManager中。
MediaPlayerService的详细实如今目录frameworks/base/media/libmediaplayerservice中。
在涉及到要播放一个详细的媒体文件时,调用的函数是:
sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url)
{
int32_t connId = android_atomic_inc(&mNextConnId);
sp<Client> c = new Client(this, pid, connId, client);
LOGV("Create new client(%d) from pid %d, url=%s, connId=%d", connId, pid, url, connId);
if (NO_ERROR != c->setDataSource(url))
{
c.clear();
return c;
}
wp<Client> w = c;
Mutex::Autolock lock(mLock);
mClients.add(w);
return c;
}
这个new 了一个Client 而且函数将它返回为sp<IMediaPlayer>。
Client对象什么在文件MediaPlayerService.h中,而且是private类,说明它仅仅被MediaPlayerService对象使用。Client对象继承自BnMediaPlayer,而BnMediaPlaye又继承自BnInterface<IMediaPlayer>,看来是用来响应binder的IPC的函数。
而IMediaPlayer又是何许东东。
IMediaPlayer.cpp在目录frameworks/base/media/中,而IMediaPlayer.h 在目录frameworks/base/include/media中。IMediaPlayer.h中声明了一个IMediaPlayer的类,而它的函数又都是virtual,一看就是用来申明接口的。
MediaPlayerService::create函数调用以后,立即调用Client:setDataSource,事实上如今MediaPlayerService.cpp中,
status_t MediaPlayerService::Client::setDataSource(const char *url)
{
if (strncmp(url, "content://", 10) == 0) { //不太明确,留着以后在研究吧
// get a filedescriptor for the content Uri and
// pass it to the setDataSource(fd) method
String16 url16(url);
int fd = android::openContentProviderFile(url16);
if (fd < 0)
{
LOGE("Couldn't open fd for %s", url);
return UNKNOWN_ERROR;
}
setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
close(fd);
return mStatus;
} else {
player_type playerType = getPlayerType(url); //通过url来取得playertype,比如对于midi,就用SONIVOX_PLAYER,mp3,mp4等就用PVPLAYER
LOGV("player type = %d", playerType);
// create the right type of player
sp<MediaPlayerBase> p = createPlayer(playerType); //依据不同的playertype来创建不同的player实例
if (p == NULL) return NO_INIT;
if (!p->hardwareOutput()) {
mAudioOutput = new AudioOutput();
static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
}
// now set data source
LOGV(" setDataSource");
mStatus = p->setDataSource(url);
if (mStatus == NO_ERROR) {
mPlayer = p;
} else {
LOGE(" error: %d", mStatus);
}
return mStatus;
}
}
注意这行代码:sp<MediaPlayerBase> p = createPlayer(playerType);
他的作用是依据不同的playerType来创建player实例,我们这里主要关注PVPlayer。说了这么多,最终到达opencore那一层了。有时候会认为android这种设计实在太复杂了,调用起来太麻烦,直接实现一个IMediaPlayer的类不就完了吗。可是细致一样,androide的这种设计方式事实上有它在扩展性和可维护性上才这样做的。说究竟就是一句话,减少模块间的耦合性。
涉及到详细的操作,都是通过实现一个接口类来实现,这样详细的实例在创建的时候就能够通过工厂模式来简单的进行扩展。比如上面所提到的createPlayer(playerType)这个函数,当你须要加入自己的特殊格式的播放器的时候,就不用来改它本来的代码,而仅仅用在createPlayer(playerType)的实现以下几行代码:
case XXX_PLAYER:
LOGV(" create XXXFile");
p = new XXXPlayer();
break;
很方便,而这样的扩展性和是由接口和实现的分离带来的,createPlayer 返回的是sp<MediaPlayerBase>类,而去看这个类的代码,发现这个类都是由virtual函数组成的,当你要实现详细实现时候,你能够继承它,然后写好这些virtual函数的实现。
扯远了。设计模式的厉害,可能须要我花整个的职业生涯来体会。
废话不多说,让我们来看PVPlayer的实现,我刚才说过,PVPlayer才是opencore真正的内容。
PVPlayer的申明在frameworks/base/include/media/PVPlayer.h中,而实如今external/opencore/android/playerdriver.cpp。
为什么要这样做?我不懂,我推測还是为了实现和接口的分离,仅仅只是这次的分离就仅仅能简单的通过把头文件和实现文件放到不同目录下来实现。
OK,那么让我们来看看PVPlayer是干嘛的。
PVPlayer继承自MediaPlayerInterface,而MediaPlayerInterface是Opencore对媒体播放的抽象接口的声明类。
那么我们去看看PVPlayer的各个接口的实现吧。PVPlayer的非常多借口都是通过向它的成员mPlayerDriver发送命令来实现,而mPlayerDriver通过调用mPVPlayer的sendEvent函数来告诉PVPlayer,命令是否运行成功了。PlayerDriver是PVPlayer的一个内部成员,它是PVPlayer的命令运行者。
sendEvent的实现例如以下:
void sendEvent(int msg, int ext1=0, int ext2=0) { MediaPlayerBase::sendEvent(msg, ext1, ext2); }
MediaPlayerBase::sendEvent的实现例如以下:
virtual void sendEvent(int msg, int ext1=0, int ext2=0) { if (mNotify) mNotify(mCookie, msg, ext1, ext2); }
mNotify是MediaPlayerBase的一个成员变量,它是一个函数指针,原型例如以下:
typedef void (*notify_callback_f)(void* cookie, int msg, int ext1, int ext2);
这个成员变量在调用createPlayer的时候就调用setNotifyCallback来赋值的。
所以,能够看到,底层的事件会一层一层的往上调用,直至返回给用户层。
这里涉及到2个设计模式:
命令模式和观察者模式。
这两个模式都是设计模式中的基本模式之中的一个,功能强大,逻辑清晰。详细的内容不是本文的重点,在此略过。
PVPlayer的实现方式的更多相关文章
- 通过adb方式给安卓手机截图的cmd批处理文件
@echo off rem 通过adb方式截图rem 需要安装adb ,一般安装了android sdk 默认带了adb ,路径为sdk目录的android-sdk\platform-toolsr ...
- VisualVM通过jstatd方式远程监控远程主机
配置好权限文件 [root@test bin]# cd $JAVA_HOME/bin [root@test bin]# vim jstatd.all.policy grant codebase &qu ...
- 在WPF中使用依赖注入的方式创建视图
在WPF中使用依赖注入的方式创建视图 0x00 问题的产生 互联网时代桌面开发真是越来越少了,很多应用都转到了浏览器端和移动智能终端,相应的软件开发上的新技术应用到桌面开发的文章也很少.我之前主要做W ...
- UWP中新加的数据绑定方式x:Bind分析总结
UWP中新加的数据绑定方式x:Bind分析总结 0x00 UWP中的x:Bind 由之前有过WPF开发经验,所以在学习UWP的时候直接省略了XAML.数据绑定等几个看着十分眼熟的主题.学习过程中倒是也 ...
- MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息
MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二 ...
- C#高性能TCP服务的多种实现方式
哎~~ 想想大部分园友应该对 "高性能" 字样更感兴趣,为了吸引眼球所以标题中一定要突出,其实我更喜欢的标题是<猴赛雷,C#编写TCP服务的花样姿势!>. 本篇文章的主 ...
- C# 中参数验证方式的演变
一般在写方法的时候,第一步就是进行参数验证,这也体现了编码者的细心和缜密,但是在很多时候这个过程很枯燥和乏味,比如在拿到一个API设计文档的时候,通常会规定类型参数是否允许为空,如果是字符可能有长度限 ...
- nodejs之get/post请求的几种方式
最近一段时间在学习前端向服务器发送数据和请求数据,下面总结了一下向服务器发送请求用get和post的几种不同请求方式: 1.用form表单的方法:(1)get方法 前端代码: <form act ...
- CSS 选择器及各样式引用方式
Css :层叠样式表 (Cascading Style Sheets),定义了如何显示HTML元素. 目录 1. 选择器的分类:介绍ID.class.元素名称.符合.层次.伪类.属性选择器. 2. 样 ...
随机推荐
- 在WPF的DATAGRID中快速点击出现在ADDNEW或EDITITEM事务过程不允许DEFERREFRESH
原文 在WPF的DATAGRID中快速点击出现在ADDNEW或EDITITEM事务过程不允许DEFERREFRESH 在项目中关于DataGrid的遇到过一些问题,其中是关于迁入CheckBox的双向 ...
- spring mvc 与 jquery ajax
在 Spring mvc3中,响应.接受 JSON都十分方便. 使用注解@ResponseBody可以将结果(一个包含字符串和JavaBean的Map),转换成JSON. 使用 @RequestBod ...
- hdu 3998 (dp+最大流)
题意:求最长上升子序列的长度和数量. 分析:用dp求出最长上升子序列m,dp数组存的就是该元素为子序列结尾的长度,源点与长度为1的点建边,长度为m的与汇点连边,然后枚举任意两个元素,ai,aj(ai& ...
- PHP 的解压缩ZipArchive中的extractTo()方法 LINUX+nginx环境中解压zip时文件丢失的问题
在项目中要用ZipArchive解压ZIP文件,起初測试环境在WINDOWS平台中,測试通过,换到 LINUX+nginx 的环境中时 就出问题了(ZIP包中有文件和目录一共3百多个文件,大部分是带汉 ...
- tcp接收xml数据解析
避免tcp接收xml数据时加上xml数据长度,根据xml数据特点来解析recv到的xml数据 int nPos1 = 0; int nPos2 = 0; int nTempPos = 0; int n ...
- xhr的send方法以及node如何处理get和post数据
起因:看了阮一峰老师的关于上传文件的文章,进行测试,在使用xhr对象的send方法时遇到问题. 遇到的问题是使用send方法传送过去的数据,在node后台无法接收,经过很多次测试,怀疑是不是send与 ...
- 8天玩转并行开发——第三天 plinq的使用
原文 8天玩转并行开发——第三天 plinq的使用 相信在.net平台下,我们都玩过linq,是的,linq让我们的程序简洁优美,简直玩的是爱不释手,但是传统的linq只是串行代码,在并行的 年代如果 ...
- Poj 3771 hdu 3405
poj 3771 http://poj.org/problem?id=3771 wiki Prim http://zh.wikipedia.org/wiki/%E6%99%AE%E6%9E%97%E5 ...
- FreeLink开源呼叫中心设计思想
上一篇大概说了国内外优秀的呼叫中心系统: 国内外优秀呼叫中心系统简单介绍 借鉴上述呼叫中心系统,我们的设计新一代呼叫中心例如以下: watermark/2/text/aHR0cDovL2Jsb2cuY ...
- 【Demo 0009】Java基础-异常
本章学习要点: 1. 了解异常的基本概念: 2. 掌握异常捕获方法以及注意事项; 3. 掌握异常抛出方法: 4. 掌握自定义异常类和异常类继承注 ...