热门标签 | 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


推荐阅读
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • MATLAB函数重名问题解决方法及数据导入导出操作详解
    本文介绍了解决MATLAB函数重名的方法,并详细讲解了数据导入和导出的操作。包括使用菜单导入数据、在工作区直接新建变量、粘贴数据到.m文件或.txt文件并用load命令调用、使用save命令导出数据等方法。同时还介绍了使用dlmread函数调用数据的方法。通过本文的内容,读者可以更好地处理MATLAB中的函数重名问题,并掌握数据导入导出的各种操作。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 【Windows】实现微信双开或多开的方法及步骤详解
    本文介绍了在Windows系统下实现微信双开或多开的方法,通过安装微信电脑版、复制微信程序启动路径、修改文本文件为bat文件等步骤,实现同时登录两个或多个微信的效果。相比于使用虚拟机的方法,本方法更简单易行,适用于任何电脑,并且不会消耗过多系统资源。详细步骤和原理解释请参考本文内容。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • Week04面向对象设计与继承学习总结及作业要求
    本文总结了Week04面向对象设计与继承的重要知识点,包括对象、类、封装性、静态属性、静态方法、重载、继承和多态等。同时,还介绍了私有构造函数在类外部无法被调用、static不能访问非静态属性以及该类实例可以共享类里的static属性等内容。此外,还提到了作业要求,包括讲述一个在网上商城购物或在班级博客进行学习的故事,并使用Markdown的加粗标记和语句块标记标注关键名词和动词。最后,还提到了参考资料中关于UML类图如何绘制的范例。 ... [详细]
  • 本文介绍了Python语言程序设计中文件和数据格式化的操作,包括使用np.savetext保存文本文件,对文本文件和二进制文件进行统一的操作步骤,以及使用Numpy模块进行数据可视化编程的指南。同时还提供了一些关于Python的测试题。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
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社区 版权所有