热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

OpenCores框架

媒体播放引擎v在opencore中由PVPlayerEngine负责媒体播放功能的实现;v在PVPlayerEngine中负责创建各个节点来完成媒体文件格式解析&

媒体播放引擎

v      opencore 中由 PVPlayerEngine 负责媒体播放功能的实现;

v      PVPlayerEngine 中负责创建各个节点来完成媒体文件格式解析( SourceNode )、媒体数据编解码 (DecodeNode/EncNode) 以及媒体数据的输出 (MediaOutputNode) ;

v      PlayerDriver 负责 opencore android 媒体框架的适配;

v      AndroidAudioOutput 负责音频数据输出到 android-audioflinger 服务输出,由 AndroidSurfaceOutput 来负责将视频数据输出到 android-surfaceflinger 服务输出;



 

媒体播放引擎 - 驱动层

v      驱动层包括: PVPlayer PlayerDriver 组成;

v      PVPlayer 负责将上层应用的命令转换成 PlayerDriver 可以内部命令加入到其命令队列中,由 PlayerDriver 负责执行,并负责将命令执行的结果回送给上层媒体框架以及 JAVA 程序;

v      PlayerDriver 中有一个消息循环负责处理 PVPlayer 发送过来的命令,调用 PVPlayerEngine 相应的接口来完成媒体控制;

v      在创建 PlayerDriver 对象时会生成 opencore 主线程,并调用 OsclExecScheduler.StartScheduler 来开始 opencore 主线程循环;

v      源码文件:

v      android/playerdriver.cpp

v      android/playerdriver.h

媒体播放引擎 - 文件格式识别

v      opencore 中由 PVPlayerRecognizerRegistry 负责文件格式识别,并将结果返回给 PVPlayerEngine ;

v      PVPlayerEngine 根据类型来创建对应的文件解析节点 ParseNode ;

v      opencore 中对文件格式的识别时通过读取文件头的方式进行的,而不是根据文件扩展名;

v      opencore 中通过向系统中注册文件识别插件的方式来提供文件格式识别的功能,系统通过循环调用每个注册插件的 Recognize() 函数来进行格式识别;

v      在创建媒体播放引擎的时候会通过 PVPlayerRegistryPopulator::Populate() 函数来注册所有的文件识别插件到系统中



 

v      源码文件:

v      pvmi/recognizer/src/pvmf_recognizer_registry.cpp

v      pvmi/recognizer/src/pvmf_recognizer_registry_impl.cpp

v      pvmi/recognizer/plugins/ 目录下所有的子目录中存放着文件识别插件的代码;

媒体播放引擎 - 文件格式解析节点

v      opencore 中通过文件解析节点( ParseNode )来完成音视频文件格式的解析,并将文件中的音频、视频数据送到对应的解码节点进行解码;

v      PVPlayerEngine 通过 PVMFNodeInterface 接口来完成对 ParseNode 的操作; ParseNode 通过提供扩展接口来实现通用 Node 接口不能实现的功能;

v      常用的扩展接口如: PvmiCapabilityAndConfig ;

v      opencore 中通过注册的方式向系统中注册文件格式解析节点



 

媒体播放引擎 - 节点注册

v      1 、每个节点都有一个对应的 PVMFXXXXFactrory 来负责创建;

v      2 、系统中通过 PVPlayerRegistryPopulator. RegisterAllNodes() 来注册所有支持的节点;

v      3 opencore 首先调用 PVPlayerNodeRegistry-> QueryRegistry() 函数查询对于指定的输入 & 输出格式的 Node UUID ,然后通过 PVPlayerNodeRegistry-> CreateNode () 创建指定的 Node

v      4 PVPlayerEngine 就是通过文件格式识别插件返回的媒体类型来创建对应的文件解析节点的

void PVMFMP4FFParserNode::Run()

{

    //Process commands.

    if (!iInputCommands.empty())

    {

        ProcessCommand();

    }

 

    while (!iPortActivityQueue.empty() && (iInterfaceState == EPVMFNodeStarted ||                            FlushPending()))

    {

        ProcessPortActivity();

    }

 

    if (iInterfaceState == EPVMFNodeStarted && !FlushPending())

    {

        HandleTrackState();

    }

 

    //Check for completion of a flush command...

    if (FlushPending() && iPortActivityQueue.empty())

    {

        //Flush is complete.

         CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);

    }

}

 void PVMFMP4FFParserNode::HandleTrackState()

{

    for (uint32 i = 0; i

    {

        switch (iNodeTrackPortList[i].iState)

        {

             case PVMP4FFNodeTrackPortInfo::TRACKSTATE_UNINITIALIZED:

                ……

 

            case PVMP4FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_GETDATA:

                ……

                if (!RetrieveTrackData(iNodeTrackPortList[i]))

                {

                    ……

                }

                ……

 

            case PVMP4FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_SENDDATA:

                if (SendTrackData(iNodeTrackPortList[i]))

                {

                    ……

                 }

                break;

 

            ……

        }

    }

}

媒体播放引擎 - 解码节点

v      opencore 中由 DecNode 节点负责媒体数据的解码工作;

v      DecNode 通过调用底层的 opencoreMAX 通用接口实现媒体数据的解码;

v      对于一个普通的视频文件,存在 2 个解码节点:音频解码节点和视频解码节点;

 

 



bool PVMFOMXBaseDecNode::SendInputBufferToOMXComponent()

{

    ……

    OMX_EmptyThisBuffer(iOMXDecoder, input_buf->pBufHdr);

    ……

}

PVMFOMXBaseDecNode::SendOutputBufferToOMXComponent()

{

    ……

    OMX_FillThisBuffer(iOMXDecoder, output_buf->pBufHdr);

    ……

}

OMX_ERRORTYPE PVMFOMXBaseDecNode::EmptyBufferDoneProcessing(OMX_OUT OMX_HANDLETYPE aComponent,

        OMX_OUT OMX_PTR aAppData,

        OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer)

{

    ……

}

OMX_ERRORTYPE PVMFOMXBaseDecNode::FillBufferDoneProcessing(OMX_OUT OMX_HANDLETYPE aComponent,

        OMX_OUT OMX_PTR aAppData,

        OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer)

{

    ……

}

v      源码文件:

v      nodes/pvomxbasedecnode/

v      nodes/pvomxvideodecnode/

v      codecs_v2/omx/

媒体播放引擎 - 媒体输出节点

v      MediaOutputNode 负责接收 DecNode 的解码后数据,并将数据输出到 MIO ;同时在输出前作视频的同步;

v      MIO 负责将数据输出到 surfaceFlinger AudioFlinger ;

v      视频数据在输出前需要做颜色空间的转换( YUV->RGB )和缩放,这部分的工作也在 MIO 中完成;

v      节点源码:

v      nodes/pvmediaoutputnode/

v      MIO 源码:

v      android/android_surface_output.cpp

v      android/android_audio_output.cpp

v      android/android_audio_mio.cpp

v      http://zhaixishan.cublog.cn

 

附录:

具体的代码阅读:



目录结构


OpenCore的代码在以下目录中:external/opencore/。这个目录是OpenCore的根目录,其中包含的子目录如下所示:

    * android:这里面是一个上层的库,它基于PVPlayer和PVAuthor的SDK实现了一个为Android使用的Player和Author。
    * baselibs:包含数据结构和线程安全等内容的底层库
    * codecs_v2:这是一个内容较多的库,主要包含编解码的实现,以及一个OpenMAX的实现
    * engines:包含PVPlayer和PVAuthor引擎的实现
    * extern_libs_v2:包含了khronos的OpenMAX的头文件
    * fileformats:文件格式的据具体解析(parser)类
    * nodes:编解码和文件解析的各个node类。
    * oscl:操作系统兼容库
    * pvmi: 输入输出控制的抽象接口
    * protocols:主要是与网络相关的RTSP、RTP、HTTP等协议的相关内容
    * pvcommon:pvcommon库文件的Android.mk文件,没有源文件。
    * pvplayer:pvplayer库文件的Android.mk文件,没有源文件。
    * pvauthor:pvauthor库文件的Android.mk文件,没有源文件。
    * tools_v2:编译工具以及一些可注册的模块。

Splitter的定义与初始化
以wav的splitter为例,在fileformats目录下有解析wav文件格式的pvwavfileparser.cpp文件,在nodes目录 下有pvmf_wavffparser_factory.cpp,pvmf_wavffparser_node.h, pvmf_wavffparser_port.h等文件。
我们由底往上看,vwavfileparser.cpp中的PV_Wav_Parser 类有InitWavParser () ,GetPCMData () ,RetrieveFileInfo () 等解析wav格式的成员函数,此类应该就是最终的解析类。我们搜索PV_Wav_Parser 类被用到的地方可知,在PVMFWAVFFParserNode 类中有PV_Wav_Parser 的一个指针成员变量。再搜索可知,PVMFWAVFFParserNode 类是通过PVMFWAVFFParserNodeFactoryCreatePVMFWAVFFParserNode() 成员函数生成的。而CreatePVMFWAVFFParserNode() 函数是在PVPlayerNodeRegistry::PVPlayerNodeRegistry() 类构造函数中通过PVPlayerNodeInfo 类被注册到Oscl_Vector 的vector中,在这个构造函数中,AMR,mp3等node也是同样被注册的。
由上可知,Opencore中对splitter的管理也是与ffmpeg等类似,都是在框架的初始化时注册的,只不过Opencore注册的是每个splitter的factory函数。
综述一下splitter的定义与初始化过程:
  • 每个splitter都在fileformats目录下有个对应的子目录,其下有各自的解析类。
  • 每个splitter都在nodes目录下有关对应的子目录,其下有各自的统一接口的node类和node factory类。
  • 播放引擎PVPlayerEngine 类中有PVPlayerNodeRegistry iPlayerNodeRegistry 成员变量。
  • PVPlayerNodeRegistry 的构造函数中,将 AMR, AAC, MP3等splitter的输入与输出类型标示和node factory类中的create node与release delete接口通过PVPlayerNodeInfo类 push到Oscl_Vector iType 成员变量中。

当前Splitter的匹配 过程
PVMFStatus PVPlayerNodeRegistry::QueryRegistry(PVMFFormatType& aInputType, PVMFFormatType& aOutputType, Oscl_Vector& aUuids) 函数的功能是根据输入类型和输出类型,在已注册的node vector中寻找是否有匹配的node,有的话传回其唯一识别标识PVUuid。
QueryRegistry 这个函数至底向上搜索可得到,在android 中splitter的匹配过程如下:
  • android_media_MediaPlayer.cpp 之中定义了一个 JNINativeMethod ( JAVA 本地调用方法)类型的数组 gMethods ,供java代码中调用 MultiPlayer类的 setDataSource成员函数时找到对应的c++函数  
    {"setDataSource",       "(Ljava/lang/String;)V",            (void *)android_media_MediaPlayer_setDataSource},


  • static void android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path)

    此函数中先得到当前的MediaPlayer实例,然后调用其setDataSource函数,传入路径


  • status_t MediaPlayer::setDataSource(const char *url)

    此函数通过调getMediaPlayerService()先得到当前的MediaPlayerService,  const sp& service(getMediaPlayerService());
     然后新建一个IMediaPlayer变量,  sp player(service->create(getpid(), this, fd, offset, length));
     在sp MediaPlayerService::create(pid_t pid, const sp& client, const char* url)
     调status_t MediaPlayerService::Client::setDataSource(const char *url) 函数,ClientMediaPlayerService 的一个内部类。
     在MediaPlayerService::Client::setDataSource中,调sp MediaPlayerService::Client::createPlayer(player_type playerType)
    
生成一个继承自MediaPlayerBase的PVPlayer实例,
    PVPlayer的继承关系如下:
    PVPlayer -->MediaPlayerInterface -->MediaPlayerBase
    最后调PVPlayer的setDataSource ()函数


  • status_t PVPlayer::setDataSource(const char *url)
  • status_t PVPlayer::prepare()

    此函数开头执行ret = mPlayerDriver->enqueueCommand(new PlayerSetDataSource(mDataSourcePath,0,0));
     将PlayerSetDataSource 的command类加入到PlayerDriver的command处理队列中,
     在void PlayerDriver::Run()函数中处理此command,调用下面的handleSetDataSource函数。


  • void PlayerDriver::handleSetDataSource(PlayerSetDataSource* ec)
  • PVCommandId PVPlayerEngine::AddDataSource(PVPlayerDataSource& aDataSource, const OsclAny* aContextData)

        This function allows a player data source to be specified for playback. This function must be called


  • PVMFStatus PVPlayerEngine::DoAddDataSource(PVPlayerEngineCommand& aCmd)
  • PVMFStatus PVPlayerEngine::DoSetupSourceNode(PVCommandId aCmdId, OsclAny* aCmdContext)

 

http://www.cublog.cn/u3/112227/showart_2494787.html


推荐阅读
  • 在对WordPress Duplicator插件0.4.4版本的安全评估中,发现其存在跨站脚本(XSS)攻击漏洞。此漏洞可能被利用进行恶意操作,建议用户及时更新至最新版本以确保系统安全。测试方法仅限于安全研究和教学目的,使用时需自行承担风险。漏洞编号:HTB23162。 ... [详细]
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
  • Squaretest:自动生成功能测试代码的高效插件
    本文将介绍一款名为Squaretest的高效插件,该工具能够自动生成功能测试代码。使用这款插件的主要原因是公司近期加强了代码质量的管控,对各项目进行了严格的单元测试评估。Squaretest不仅提高了测试代码的生成效率,还显著提升了代码的质量和可靠性。 ... [详细]
  • 本文是对《敏捷软件开发:原则、模式与实践》一书的深度解析,书中不仅探讨了敏捷方法的核心理念及其应用,还详细介绍了面向对象设计的原则、设计模式的应用技巧及UML的有效使用。 ... [详细]
  • H5技术实现经典游戏《贪吃蛇》
    本文将分享一个使用HTML5技术实现的经典小游戏——《贪吃蛇》。通过H5技术,我们将探讨如何构建这款游戏的两种主要玩法:积分闯关和无尽模式。 ... [详细]
  • 本文详细介绍了 `org.apache.tinkerpop.gremlin.structure.VertexProperty` 类中的 `key()` 方法,并提供了多个实际应用的代码示例。通过这些示例,读者可以更好地理解该方法在图数据库操作中的具体用途。 ... [详细]
  • publicclassBindActionextendsActionSupport{privateStringproString;privateStringcitString; ... [详细]
  • 实践指南:使用Express、Create React App与MongoDB搭建React开发环境
    本文详细介绍了如何利用Express、Create React App和MongoDB构建一个高效的React应用开发环境,旨在为开发者提供一套完整的解决方案,包括环境搭建、数据模拟及前后端交互。 ... [详细]
  • 本文旨在探讨设计模式在Visual FoxPro (VFP) 中的应用可能性。虽然VFP作为一种支持面向对象编程(xbase语言)的工具,其OO特性相对简明,缺乏高级语言如Java、C++等提供的复杂特性,但设计模式作为一种通用的解决方案框架,是否能有效应用于VFP,值得深入研究。 ... [详细]
  • 电商高并发解决方案详解
    本文以京东为例,详细探讨了电商中常见的高并发解决方案,包括多级缓存和Nginx限流技术,旨在帮助读者更好地理解和应用这些技术。 ... [详细]
  • 在ElasticStack日志监控系统中,Logstash编码插件自5.0版本起进行了重大改进。插件被独立拆分为gem包,每个插件可以单独进行更新和维护,无需依赖Logstash的整体升级。这不仅提高了系统的灵活性和可维护性,还简化了插件的管理和部署过程。本文将详细介绍这些编码插件的功能、配置方法,并通过实际生产环境中的应用案例,展示其在日志处理和监控中的高效性和可靠性。 ... [详细]
  • iOS 设备唯一标识获取的高效解决方案与实践
    在iOS 7中,苹果公司再次禁止了对MAC地址的访问,使得开发者无法直接获取设备的物理地址。为了在开发过程中实现设备的唯一标识,苹果推荐使用Keychain服务来存储和管理唯一的标识符。此外,还可以结合其他技术手段,如UUID和广告标识符(IDFA),以确保设备的唯一性和安全性。这些方法不仅能够满足应用的需求,还能保护用户的隐私。 ... [详细]
  • 本文介绍了UUID(通用唯一标识符)的概念及其在JavaScript中生成Java兼容UUID的代码实现与优化技巧。UUID是一个128位的唯一标识符,广泛应用于分布式系统中以确保唯一性。文章详细探讨了如何利用JavaScript生成符合Java标准的UUID,并提供了多种优化方法,以提高生成效率和兼容性。 ... [详细]
  • 技术日志:Ansible的安装及模块管理详解 ... [详细]
  • Spring Boot 实战(一):基础的CRUD操作详解
    在《Spring Boot 实战(一)》中,详细介绍了基础的CRUD操作,涵盖创建、读取、更新和删除等核心功能,适合初学者快速掌握Spring Boot框架的应用开发技巧。 ... [详细]
author-avatar
韵公举_R
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有