Android的PVPlayer介绍
1 Player的组成
OpenCore的Player的编译文件是pvplayer/Android.mk,将生成动态库文件
libopencoreplayer.so。这个库包括了双方面的内容:一方是Player的engine(引擎),一方面是为
Android构件的Player,这实际上是一个适配器(adapter)。engine的路径是engine/player;adapter的路径是
android。
2 Player Engine部分
OpenCore
的
Player Engine
具有清晰明白的接口。在这个接口之上,不同的系统能够依据自己的情况实现不同
Player
。文件夹
engines
中的文件结构例如以下所看到的:
engines/player/
|-- Android.mk
|-- build
| |-- linux_nj
| |-- make
| `-- makefile.conf
|-- config
| `-- linux_nj
|-- include
| |-- pv_player_datasink.h
| |-- pv_player_datasinkfilename.h
| |-- pv_player_datasinkpvmfnode.h
| |-- pv_player_datasource.h
| |-- pv_player_datasourcepvmfnode.h
| |-- pv_player_datasourceurl.h
| |-- pv_player_events.h
| |-- pv_player_factory.h
| |-- pv_player_interface.h
| |-- pv_player_license_acquisition_interface.h
| |-- pv_player_registry_interface.h
| |-- pv_player_track_selection_interface.h
| `-- pv_player_types.h
|-- sample_app
| |-- Android.mk
| |-- build
| |-- sample_player_app_release.txt
| `-- src
|-- src
| |-- pv_player_datapath.cpp
| |-- pv_player_datapath.h
| |-- pv_player_engine.cpp
| |-- pv_player_engine.h
| |-- pv_player_factory.cpp
| |-- pv_player_node_registry.h
| `-- pv_player_sdkinfo.h
`-- test
|-- Android.mk
|-- build
|-- config
`-- src
当中,engines/player/include文件夹中是接口头文件,engines/player/src文件夹源文件和私有头文件,主要头文件的功能例如以下所看到的:
pv_player_types.h
:定义一些数据结构和枚举值
pv_player_events.h
:定义UUID和一些错误值。
pv_player_datasink.h
:datasink
是媒体数据的输出
,
定义类
PVPlayerDataSink
,
这是媒体数据输出的基类
,
作为接口使用
pv_player_datasinkfilename.h
:
定义类
PVPlayerDataSinkFilename
继承
PVPlayerDataSink
。
pv_player_datasinkpvmfnode.h
:
定义类
PVPlayerDataSinkPVMFNode
继承
PVPlayerDataSink
。
pv_player_datasource.h
:datasource
是媒体数据的输入
,
定义类
PVPlayerDataSource
,这是媒体数据输入的基类,作为接口使用。
pv_player_datasourcepvmfnode.h
:定义类PVPlayerDataSourcePVMFNode继承PVPlayerDataSource。
pv_player_datasourceurl.h
:定义类PVPlayerDataSourceURL继承PVPlayerDataSource。
pv_player_interface.h
:
定义
Player
的接口
PVPlayerInterface
,
这是一个接口类。
pv_player_factory.h
:
主要定义工厂类
PVPlayerFactory
,用于创建和销毁PVPlayerInterface。
其实,在engines/player/src
文件夹中
,
主要实现类为
pv_player_engine.cpp
,
当中定义了类
PVPlayerEngine
,PVPlayerEngine继承了PVPlayerInterface,这是一个实现类,在PVPlayerFactory创建PVPlayerInterface接口的时候,实际创建的是PVPlayerEngine。
在
Player Engine
的实现中,包括了编解码和流控制等功能,而输出的介质须要从外部设置进来。
PVPlayerInterface
定义的接口基本是依照操作顺序的,基本的接口例如以下所看到的:
在Player Engine的实现中,包括了编解码和流控制等功能,而输出的介质须要从外部设置进来。PVPlayerInterface定义的接口基本是依照操作顺序的,基本的接口例如以下所看到的:
PVCommandId AddDataSource(PVPlayerDataSource& aDataSource, const OsclAny* aContextData = NULL);
PVCommandId Init(const OsclAny* aContextData = NULL);
PVCommandId AddDataSink(PVPlayerDataSink& aDataSink, const OsclAny* aContextData = NULL);
PVCommandId Prepare(const OsclAny* aContextData = NULL);
PVCommandId Start(const OsclAny* aContextData = NULL);
PVCommandId Pause(const OsclAny* aContextData = NULL);
PVCommandId Resume(const OsclAny* aContextData = NULL);
PVCommandId Stop(const OsclAny* aContextData = NULL);
PVCommandId RemoveDataSink(PVPlayerDataSink& aDataSink, const OsclAny* aContextData = NULL);
PVCommandId Reset(const OsclAny* aContextData = NULL);
PVCommandId RemoveDataSource(PVPlayerDataSource& aDataSource, const OsclAny* aContextData = NULL);
这里面的DataSink可能包括Video的输出和Audio的输出两者部分。在pv_player_types.h文件里,定义了Player的状态机,以PVP_STATE_为开头,例如以下所看到的:
typedef enum
{
PVP_STATE_IDLE = 1,
PVP_STATE_INITIALIZED = 2,
PVP_STATE_PREPARED = 3,
PVP_STATE_STARTED = 4,
PVP_STATE_PAUSED = 5,
PVP_STATE_ERROR = 6
} PVPlayerState;
PVPlayerInterface
中的各个操作假设成功,能够更改Player的状态机:初始化的时候Player是PVP_STATE_IDLE状态,调用Init后,进入
PVP_STATE_INITIALIZED状态;调用AddDataSink,进入PVP_STATE_PREPARED状态;调用Prepare后,
进入PVP_STATE_PREPARED状态;调用start后进入PVP_STATE_STARTED状态,之后能够调用
pause进入PVP_STATE_PAUSED状态。
PVP_STATE_STARTED和PVP_STATE_PAUSED状态是播放情况下的状态,能够使用start和pause函数在这两个状态中切换。
在播放过程中,调用stop能够返回PVP_STATE_INITIALIZED状态,在调用RemoveDataSource返回PVP_STATE_IDLE状态。
3 Android Player Adapter
在android文件夹中定义为Player的适配器,这个文件夹主要包括的文件例如以下所看到的:
android
|-- Android.mk
|-- android_audio_mio.cpp
|-- android_audio_mio.h
|-- android_audio_output.cpp
|-- android_audio_output.h
|-- android_audio_output_threadsafe_callbacks.cpp
|-- android_audio_output_threadsafe_callbacks.h
|-- android_audio_stream.cpp
|-- android_audio_stream.h
|-- android_log_appender.h
|-- android_surface_output.cpp
|-- android_surface_output.h
|-- mediascanner.cpp
|-- metadatadriver.cpp
|-- metadatadriver.h
|-- playerdriver.cpp
|-- playerdriver.h
`-- thread_init.cpp
这个Android的Player的“适配器”须要调用OpenCore的Player Engine的接口,实现Android的媒体播放器的服务所须要接口,即终于实现一个PVPlayer,而PVPlayer实际上是继承了 MediaPlayerInterface。
在实现过程中,首先实现了一个PlayerDriver,然后再使用PVPlayer,PVPlayer通过调用PlayerDriver来完毕详细的功能。整个实现的结构图如图所看到的:
对PVPlayerDriver的各种操作使用各种命令来完毕,这些命令在playerdriver.h中进行的定义。
enum player_command_type {
PLAYER_QUIT = 1,
PLAYER_SETUP = 2,
PLAYER_SET_DATA_SOURCE = 3,
PLAYER_SET_VIDEO_SURFACE = 4,
PLAYER_SET_AUDIO_SINK = 5,
PLAYER_INIT = 6,
PLAYER_PREPARE = 7,
PLAYER_START = 8,
PLAYER_STOP = 9,
PLAYER_PAUSE = 10,
PLAYER_RESET = 11,
PLAYER_SET_LOOP = 12,
PLAYER_SEEK = 13,
PLAYER_GET_POSITION = 14,
PLAYER_GET_DURATION = 15,
PLAYER_GET_STATUS = 16,
PLAYER_REMOVE_DATA_SOURCE = 17,
PLAYER_CANCEL_ALL_COMMANDS = 18,
};
这些命令一般实现的是PVPlayerInterface各个接口的简单封装,比如对于较为简单的暂停播放这个操作,整个系统运行的步骤例如以下所看到的:
1.在PVPlayer中的pause函数(在playerdriver.cpp文件里)
status_t PVPlayer::pause()
{
LOGV("pause");
return mPlayerDriver->enqueueCommand(new PlayerPause(0,0));
}
这时调用其成员mPlayerDriver(PlayerDriver类型)的函数,将一个PlayerPause命令增加了命令序列,详细的各种命令功能在playerdriver.h文件里。
2.PlayerDriver类的enqueueCommand将间接调用各个以handle为开头的函数,对于PlayerPause命令,调用的函数是handlePause
void PlayerDriver::handlePause(PlayerPause* ec)
{
LOGV("call pause");
mPlayer->Pause(0);
FinishSyncCommand(ec);
}
这里的mPlayer是一个PVPlayerInterface类型的指针,使用这个指针调用到了OpenCore的 Player Engine中的PVPlayerEngine类。
在这个播放器适配器的实现中,一个主要工作是
将Android框架中定义的媒体的输出(包含Audio的输出和Video的输出)转换成,OpenCore的 Player
Engine须要的形式。在这里两个重要的类是android_surface_output.cpp实现的
AndroidSurfaceOutput,android_audio_output.cpp实现的AndroidAudioOutput。
对于Video输出的设置过程,在类PlayerDriver中定义了3个成员:
PVPlayerDataSink *mVideoSink;
PVMFNodeInterface *mVideoNode;
PvmiMIOControl *mVideoOutputMIO;
这里的mVideoSink 的类型为PVPlayerDataSink,这是Player
Engine中定义的类接口,mVideoNode的类型为VMFNodeInterface,在pvmi/pvmf/include的
pvmf_node_interface.h中定义,这是全部的PVMF的NODE都须要继承的统一接口,mVideoOutputMIO的类型为
PvmiMIOControl也在pvmi/pvmf/include中定义,这是媒体图形输出控制的接口类。
1.在PVPlayer的setVideoSurface用以设置一个Video输出的界面,这里使用的參数的类型是ISurface指针:
status_t PVPlayer::setVideoSurface(const sp<ISurface>& surface)
{
LOGV("setVideoSurface(%p)", surface.get());
mSurface = surface;
return OK;
}
setVideoSurface函数设置的是PVPlayer中的一个成员mSurface,真正设置Video输出的界面的功能在run_set_video_surface()函数中实现:
void PVPlayer::run_set_video_surface(status_t s, void *cookie)
{
LOGV("run_set_video_surface s=%d", s);
if (s == NO_ERROR) {
PVPlayer *p = (PVPlayer*)cookie;
if (p->mSurface == NULL) {
run_set_audio_output(s, cookie);
} else {
p->mPlayerDriver->enqueueCommand(new PlayerSetVideoSurface(p->mSurface, run_set_audio_output, cookie));
}
}
}
这时使用的命令是PlayerSetVideoSurface,终于将调用到PlayerDriver中的handleSetVideoSurface函数。
2.handleSetVideoSurface函数的实现例如以下所看到的:
void PlayerDriver::handleSetVideoSurface(PlayerSetVideoSurface* ec)
{
int error = 0;
mVideoOutputMIO = new AndroidSurfaceOutput(ec->surface());
mVideoNode = PVMediaOutputNodeFactory::CreateMediaOutputNode(mVideoOutputMIO);
mVideoSink = new PVPlayerDataSinkPVMFNode;
((PVPlayerDataSinkPVMFNode *)mVideoSink)->SetDataSinkNode(mVideoNode);
((PVPlayerDataSinkPVMFNode *)mVideoSink)->SetDataSinkFormatType(PVMF_YUV420);
OSCL_TRY(error, mPlayer->AddDataSink(*mVideoSink, ec));
OSCL_FIRST_CATCH_ANY(error, commandFailed(ec));
}
在这里首先建立的创建成员mVideoOutputMIO(类型为PvmiMIOControl),这时建立的类是类
AndroidSurfaceOutput,这个类继承了PvmiMIOControl,所以能够作为PvmiMIOControl使用。然后调用
PVMediaOutputNodeFactory::CreateMediaOutputNode建立了PVMFNodeInterface
类型的mVideoNode。随后创建PVPlayerDataSinkPVMFNode类型的
mVideoSink,PVPlayerDataSinkPVMFNode本身继承了PVPlayerDataSink,因此能够作为
PVPlayerDataSink使用。调用SetDataSinkNode函数将mVideoNode设置为mVideoSink的数据输出节点。
其实,对于Video的输出,基本的功能都是在类AndroidSurfaceOutput中完毕的,在这个类其中,基本的工作是将Android的
ISurface输出作为Player
Engine的输出。最后调用了AddDataSink将mVideoSink添加为了PVPlayerInterface的输出。
在android_surface_output.cpp文件里实现了类AndroidSurfaceOutput,这个类相当于一个OpenCore
Player Engine的Video输出和Android输出的“适配器”。AndroidSurfaceOutput类本身继承了类
PvmiMIOControl,而其构造函数又以ISurface类型为參数。这个类的实现是使用ISurface实现PvmiMIOControl的各
个接口。
Android的PVPlayer介绍的更多相关文章
- Android sdk目录介绍
android sdk目录介绍 build-tools 各版本SDK编译工具 docs 离线开发者文档Android SDK API参考文档 extras 扩展开发包,如兼容架包. platforms ...
- 我的Android第三章:Android的组件介绍
小编摘录了Android文档介绍Android四大组件的基本内容,感觉文档的内容写的很详细所以小编将它写入了博客 Android 使用Java语言开发.Android SDK 工具编译代码-以及任意数 ...
- GitHub上排名前100的Android开源库介绍(来自github)
本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍,至于排名完全是根据 GitHub 搜索 Java 语言选择 (Best Match) 得到的结果,然后过滤了 ...
- android MVP模式介绍与实战
android MVP模式介绍与实战 描述 MVP模式是什么?MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数 ...
- Android 不同文件名介绍
Android 不同文件名介绍
- Android发展简单介绍
Android一词的本义指“机器人”,同一时候也是Google于2007年11月5日宣布的基于Linux平台的开源手机操作系统的名称,该平台由操作系统.中间件.用户界面和应用软件组成,号称是首个为移动 ...
- Android IntentService使用介绍以及源码解析
版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.IntentService概述及使用举例 IntentService内部实现机制用到了HandlerThread,如果对HandlerThrea ...
- Android Jetpack 组建介绍(一)——Lifecycler
转自带你领略Android Jetpack组件的魅力 Android Jetpack 对于任何一个产品来说,我们开发中都会面对哪些问题?如:产品交互.用户体验.代码结构.数据获取.数据存储.网络优化. ...
- [原创]AndroBugs_Framework Android漏洞扫描器介绍
[原创]AndroBugs_Framework Android漏洞扫描器介绍 1 AndroBugs_Framework Android 漏洞扫描器简介 一款高效的Android漏洞扫描器,可以帮助开 ...
随机推荐
- [Angular2 Router] Redirects and Path Matching - Avoid Common Routing Pitfall
In this tutorial we are going to learn how we can can configure redirects in the angular 2 router co ...
- 基于mpvue的小程序项目搭建的步骤一
未标题-1.png mpvue 是美团开源的一套语法与vue.js一致的.快速开发小程序的前端框架,按官网说可以达到小程序与H5界面使用一套代码.使用此框架,开发者将得到完整的 Vue.js 开发体验 ...
- [Angular] Angular Advanced Features - ng-template , ng-container, ngTemplateOutlet
Previously we have tab-panel template defined like this: <ul class="tab-panel-buttons" ...
- 26、驱动调试之根据oops信息和堆栈确定出错的代码
a.驱动作为模块:1. 根据pc值确定该指令属于内核还是外加的模块pc=0xbf000018 它属于什么的地址?是内核还是通过insmod加载的驱动程序?先判断是否属于内核的地址: 看System.m ...
- CAP理论/AP架构/CP架构
原文地址:https://blog.csdn.net/u013058742/article/details/83541905 简书里的文章:Spring Cloud Eureka简介及与Zook ...
- 从Lua调用C
从Lua调用C: 方式:C函数从栈中获取函数參数(第一个參数总是局部栈的索引1),将结果压入栈中,C函数须要返回结果数量. 每一个函数都有自己的局部私有栈 样例: static int l_sin(l ...
- [SCSS] Loop Over Data with the SCSS @each Control Directive
The SCSS @for directive is great when we know how many iterations are required and we only need 1 va ...
- 在Eclipse中运行hadoop程序 分类: A1_HADOOP 2014-12-14 11:11 624人阅读 评论(0) 收藏
1.下载hadoop-eclipse-plugin-1.2.1.jar,并将之复制到eclipse/plugins下. 2.打开map-reduce视图 在eclipse中,打开window--> ...
- Java NIO详细介绍
不错的文章,推荐一下. http://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html JavaNIO非堵塞技术实际是采取Re ...
- 第一次使用docker for windows 遇到的坑
原文:第一次使用docker for windows 遇到的坑 1. 目前win10安装docker, 不需要安装其他工具,可直接到官网下载 2. 此版本的docker可同时运行Windows con ...