zoukankan      html  css  js  c++  java
  • android 多媒体框架中mediaplay与opencore的衔接调用过程

    本文从代码的角度来分析Android多媒体框架中mediaplay是如何调用opencore的。

    一 摘要
        对于Android 多媒体框架,Google 在 Android 2.2中就已经实现了stagefright,但还是保留了opencore;
    在新推出的2.3版本中,正式抛弃了opencore,而采用stagefright。网上关于Android opencore架构的文章有很多,例如下面的链接:http://www.360doc.com/content/10/0207/22/155970_15398760.shtml。但大都是基于框架的,而没有更加细致的给出代码的实现过程,本文从MediaPlayer::setDataSource开始,分析一下整个opcncore的初始化过程。

    二 引子
        在播放一个视频文件的时候,往往会这样做:
        第一步,创建一个MediaPlayer对象;
        第二步,依次调用MediaPlayer的setDataSource,prepare,start函数;
        本文仅仅分析setDataSource(opencore的初始化就是在这个函数中完成的)。

    三 代码分析
    1. MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)

        当我们在java层调用setDataSource函数时,最终,它会通过jni调用到C++层的MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)函数。它的实现如下:
    status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length) ;
      1) getMediaPlayerService()   
            1.1  getService(String16("media.player")
      2) service->create(getpid(), this, fd, offset, length)
            2.1  c = new Client, //这是一个MediaPlayerService::Client对象,参考MediaPlayerService类图
            2.2  c->setDataSource(fd, offset, length)
                   getPlayerType
                   sp<MediaPlayerBase> p = createPlayer(playerType);  // 真正的是实例PVPlayer, MidiFile or VorbisPlayer
                       android::createPlayer(playerType, this, notify)
                            sp<MediaPlayerBase> p;
                            case 1: p = new PVPlayer();  // defined media/PVPlayer.h
                            case 2: p = new MidiFile();   // defined libmediaplayerservice/PVPlayer.h
                            case 3: p = new VorbisPlayer();// same as MidiFile
                            case 4: p = new stagefright;   // 2.2开始加入的,2.3中就彻底用它了。


      3) setDataSource(player): 保存player的引用到MediaPlayer中.

    以上三步,简要分析如下:
    首先, 得到MediaPlayerService;
    其次, 通过MediaPlayerService这个service来创建Client,再通过Client去创建Player(即调用createPlayer函数),事实上,创建的真正的是实例PVPlayer, MidiFile or VorbisPlayer,这就是opencore于mediaplayer的真正的唯一的桥梁。
    最后, 通过调用setDataSource(这个是MediaPlayer类的函数)就创建的适配层的实例保存在MediaPlayer类的成员对象mPlayer中(详见setDataSource函数)。

    2. PVPlayer的初始化
      1) 相关文件分布: 
         既然createPlayer(playerType)函数中最创建PVPlayer(即调用new PVPlayer()),那么,就有必要看一下PVPlayer的构造的实现:
         PVPlayer的头文件是PVPlayer.h,路径为:base/include/media,而实现是在Playerdriver.cpp中,路径为:opencore/android.
         从这个小小的文件分布来看,也能得出PVPlayer是衔接C++层的mediaserver与opencore的桥梁。
      2) 然而,为什么头文件和实现不是相同的前缀名呢?
         答:看Playerdriver.cpp的代码就知道,原来,最终的与opencore打交道的任务都落在了Playerdriver这个类上,
         而它也是PVPlayer类的一个数据成员。所以,为了与上层的MediaPlayer(要注意,PVPlayer类是MediaPlayer类的数据成员->其实是sp<IMediaPlayer>       mPlayer,这里,因为PVPlayer继承了sp<IMediaPlayer>)衔接,头文件取名为PVPlayer; 另外,真正与opencore 打交道的是Playerdriver,所以,实现的Cpp文件就是Playerdriver.cpp了。笔者认为,为了更加代码更加清晰,完全可以写一个PVPlayer.cpp,将PVPlayer.cpp相关代码写在这个PVPlayer.cpp中,尽管代码不是特别多。
      3) 是该看一下PVPlayer的初始化过程了:

        看PVPlayer的构造函数,最主要的就就创建了Playerdriver对象( mPlayerDriver = new PlayerDriver(this);),所以,PlayerDriver的构造才是核心。

    3. PlayerDriver的构造

    在 PlayerDriver 的构造过程中,最主要做了 3 件事情:
    1) Semaphore(信号量)的创建:
    2) load libopencorehw.so:
    3) 开始 player thread
    4. PlayerDriver::playerThread的实现

    startPlayerThread会call playerThread,playerThread是真正创建PV thread的函数。

    简析:
    1) OMX_MasterInit 的调用,这正好是OMX协议定义中规定的要调用的第一个函数。
    2) OsclScheduler::Init("AndroidPVWrapper");
    3) OSCL_TRY(error, mPlayer = PVPlayerFactory::CreatePlayer(this, this, this)); 通过Factory模式来创建Player.
       在pv_player_factory.cpp中,有:
    4) AddToScheduler();
    5) PendForExec();
    6) OSCL_TRY(error, sched->StartScheduler(mSyncSem));
       StartScheduler的实现:
          (1) call BlockingLoopL
                A. call CallRunExec(pvactive);  // PVActiveBase *pvactive, 真正的对象是PlayerDriver实例。
                     a. call pvactive->Run() // 调用PlayerDriver的run.
       分析:在PlayerDriver的run函数中,根据command的命令来执行相应的handle函数。
    7) 可以看到,与OSCl层的调用,创建Engine的代码,具体,请读者自己看源码来理解吧。

    5 PVPlayerDriver中command的定义与理解
    对PVPlayerDriver的各种操作使用各种命令来完成,这些命令在playerdriver.h 中进行的定义。
        这些命令一般实现的是PVPlayerInterface 各个接口的简单封装,例如对于较为简单的暂停播放这个操作,整个系统执行的过程如下所示:
    (1) 在PVPlayer中的pause 函数(在playerdriver.cpp 文件中)
    这时调用其成员mPlayerDriver(PlayerDriver 类型)的函数,将一个PlayerPause 命令加入了命令序列,具体的各种命令功能在playerdriver.h 文件中。
    (2) PlayerDriver 类的enqueueCommand 将间接调用各个以handle 为开头的函数,对于PlayerPause 命令,调用的函数是handlePause
        这里的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 个成员:
        这里的mVideoSink 的类型为PVPlayerDataSink,这是Player Engine 中定义的类接口,mVideoNode 的类型为PVMFNodeInterface,在pvmi/pvmf/include的pvmf_node_interface.h 中定义,这是所有的PVMF 的NODE 都需要继承的统一接口,mVideoOutputMIO 的类型为PvmiMIOControl也在pvmi/pvmf/include 中定义,这是媒图输出控制的接口类。
    (1) 在PVPlayer 的setVideoSurface 用以设置一个Video 输出的界面,这里使用的参数的类型是ISurface指针:
    setVideoSurface 函数设置的是PVPlayer 中的一个成员mSurface ,真正设置Video 输出的界面的功能在run_set_video_surface() 函数中实现:
    这时使用的命令是PlayerSetVideoSurface ,最终将调用到PlayerDriver 中的handleSetVideoSurface 函数。
    (2) handleSetVideoSurface 函数的实现如下所示:
        在这里首先建立的创建成员mVideoOutputMIO(类型为PvmiMIOControl),这时建立的类是类AndroidSurfaceOutput ,这个类继承了PvmiMIOControl ,所以可以作为PvmiMIOControl 使用。然后调用PVMediaOutputNodeFactory::CreateMediaOutputNode 建立了PVMFNodeInterface 类型的mVideoNode 。随后创建PVPlayerDataSinkPVMFNode 类型的mVideoSink ,PVPlayerDataSinkPVMFNode 本身继承了PVPlayerDataSink ,因此可以作为PVPlayerDataSink 使用。调用SetDataSinkNode 函数将mVideoNode 设置为mVideoSink 的数据输出节点。

    结语:再次说一下,opencore将在2.3版本中彻底消失,但是OMX还会在stagefright中继续使用。不过对于上层应用来说,不用管这些,因为接口没有变化。

    在mk文件,没有看到具体的连接库的代码。如libmediaplayerservice的mk只看到链libopencore_player这个,
    而opencore/android目录下mk文件写这个模块编译生成的是libandroidpv。在opencore/Android.mk中,有:
    include $(PV_TOP)/build_config/opencore_dynamic/Android_opencore_common.mk
    include $(PV_TOP)/build_config/opencore_dynamic/Android_opencore_author.mk
    include $(PV_TOP)/build_config/opencore_dynamic/Android_opencore_player.mk
    在第三个mk文件,即文件opencore/build_config/opencore_dynamic/Android_opencore_player.mk中,有
    LOCAL_MODULE := libopencore_player。
    在libmediaplayerservice中用的,正是上面这个mk文件编译出来的libopencore_player.so。

    http://blog.csdn.net/liranke/article/details/6167043

  • 相关阅读:
    远程访问linux环境安装图形界面问题解决汇总
    如何通过SecureCRT FTP上传下载文件
    X-Frame-Options 响应头
    Openresty 学习笔记(四)lualocks包管理器安装使用
    PHP7 学习笔记(十六)Yaconf 一个高性能的配置管理扩展
    网络工具(一)frp 供内网穿透服务的工具
    博客园自定义样式参考
    Redis学习笔记(二)解析dump.rdb文件工具之redis-rdb-tools
    Docker 从入门到放弃(四)Docker+Jenkins_自动化持续集成
    PHP7 学习笔记(十五)Repository 模式实现业务逻辑和数据访问的分离
  • 原文地址:https://www.cnblogs.com/eustoma/p/2415827.html
Copyright © 2011-2022 走看看