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. 样 ...
随机推荐
- 如何捕获winform程序全局异常?
1.在C#中我们如何处理异常? 上面的问题学过C#的问题大家可能都能回答处理,用try-catch-finally具体如下: try { //可能出错的语句 } catch (Exception) { ...
- 基于visual Studio2013解决面试题之1006判断升序
题目
- boost 循环缓冲区
boost 循环缓冲区 #include <boost/circular_buffer.hpp> int _tmain(int argc, _TCHAR* argv[]) { boost: ...
- Linux下可执行程序调试信息的分离及release程序的调试
前两天在群里看到在讨论如何把debug版中的符号表加到release版本中,觉得这个非常有用,所以学习一下. 使用的工具是objcopy. 如果要生成单独的调试信息文件,命令如下: objcopy ...
- EDStarRating(IOS星级评定)
链接地址:https://github.com/erndev/EDStarRating EDStarRating
- 施用 maven shade plugin 解决 jar 或类的多版本冲突
施用 maven shade plugin 解决 jar 或类的多版本冲突 使用 maven shade plugin 解决 jar 或类的多版本冲突java 应用经常会碰到的依赖的三方库出现版本 ...
- C# LDAP认证登录
LDAP是轻量目录访问协议,英文全称是Lightweight Directory Access Protocol,一般都简称为LDAP.它是基于X.500标准的,但是简单多了并且可以根据需要定制.与X ...
- 怎样使用 App Studio 高速定制你自己的 Universal Windows App
今天之所以在写一篇关于 App Studio 的文章是由于,App Studio 经过了几次升级功能得到了明显提升还能够调用系统功能了.而且能够更方便的和应用商店关联公布 Universal Wind ...
- 简易的sniffer程序
真的非常简易,这个程序不过抓一些发送到本机的数据包,然后显示出来它们的一些信息罢了. 程序很easy! #include <WinSock2.h> #include ...
- SRM 627 D1L2GraphInversionsDFS查找指定长度的所有路径 Binary indexed tree (BIT)
题目:http://community.topcoder.com/stat?c=problem_statement&pm=13275&rd=16008 由于图中边数不多,选择DFS遍历 ...