StagefrightPlayer也叫做AwesomePlayer,虽然只是一个已经不再使用的组件

AwesomePlayer构造过程

StagefrightPlayerFactory创建了一个StagefrightPlayer后,就开始进入StagefrightPlayer的构造函数

StagefrightPlayer.h中有如下声明

可看出StagefrightPlayer中封装了AwesomePlayer,进而进行播放行为相关操作,接着分析下里面的StagefrightPlayer

可以看出它继承了MediaPlayerInterface抽象基类,这个抽象基类有很多虚函数

同样以setDataSource为例,通常当我们负责的模块和别人的模块进行交互时,在模块之间相当于一个黑盒,通过返回对应的状态或者数据可以判断已经发生的事件,进而进行下一个环节。StagefrightPlayer只是一层外壳,真正干活的是AwesomePlayer

在调用MediaPlayerService中的setDataSource函数后会到达StagefrightPlayer中的setDataSource函数

所有执行步骤都会调用mPlayer->setDataSource(xxxx),而通过前面的分析我们知道,这个mPlayer被定义成AwesomePlayer,虽然AwesomePlayer中也有一些网络流处理的代码,但通常执行不到这段逻辑,而是使用NuPlayer,接下来到达AwesomePlayer的setDataSource函数

总结:AwesomePlayer主要用于本地播放,匹配不同的文件类型,并用数据解析器处理mime表示该资源的媒体类型,当出现常见音视频封装格式的时候,Android播放器如果在Manifest.xml中设置了mime对应的类型,就能被播放器识别

常用的mime类型资源

AwesomePlayer使用MediaExtractor进行数据解析的过程

MediaExtractor即为数据解析器,查看其源码

总结:针对文件解析的不同格式创建Extractor解析器并解析,创建好解析器后回到AwesomePlayer::setDataSource_l中,继续执行setDataSource_l(extractor)函数,对新建的解析器做处理,实质是做视频的A(音频)/V(视频)分离,解析器的类型在AwesomePlayer::setDataSource_l中创建的时候就定下来了


mVideoTrackmAudioTrack作为创建AwesomePlayer的成员函数,其类型为MPEG4Source,继承自MediaSource

以上过程完成了音视频数据的分离,也就是demux(解复用),对音频和视频资源分开处理,顺序:MediaPlayerService->StagefrighterPlayer->AwesomePlayer->MPEG4Extractor->MPEG4Source,音频同理

AudioPlayer为AwesomePlayer的成员,AudioPlayer通过callback来驱动数据的获取,AwesomePlayer则通过videoevent来驱动。数据的获取都抽象成mSource->read来完成,且read内部把parse和decode绑在一起。StageFright A/V同步部分,Audio完全由callback驱动数据流,注意视频部分在onViewEvent里会获取Audio的时间戳,然后、进行音视频时间的比较,计算下一帧间隔多久显示,使时间戳同步

AwesomePlayer的Video主要成员

1.mVideoSource(解码视频)
2.mVideoTrack(从多媒体文件中读取视频数据)
3.mVideoRenderer(对解码好的视频进行格式转换,Android使用的格式为RGB565)
4.mISurface(重绘图层)
5.mQueue(event事件队列)

StageFright运行时的Audio流程

1.设置mUri的路径
2.启动mQueue,创建一个线程来运行threadEntry(命名为TimedEventQueue),这个线程就是event调度器
3.打开mUri所指定文件的头部,根据类型选择不同的分离器,如MPEG4Extractor
4.使用MPEG4Extractor对MP4进行音视频轨道的分离,并返回MPEG4Source类型的视频轨道给mVideoTrack
5.根据mVideoTrack中的编码类型来选择解码器,AVC的编码类型会选择AVCDecoder,返回给mVideoSource,并设置mVideoSource中的mSource为mVideoTrack
6.插入onVideoEvent到Queue中,开始解码播放
7.通过mVideoSource对象读取解析好的视频Buffer

如果解析好的视频Buffer还没到A/V时间戳同步的时刻,则推迟到下一轮操作
1.mVideoRenderer为空,则进行初始化(如果不使用OMX,会将mVideoRenderer设置为AwesomeLocalRenderer)
2.通过mVideoRenderer对象将解析好的视频Buffer转换成RGB565格式,并发给display模块进行图像绘制
3.将onVideoEvent重新插入event调度器来循环

AwesomePlayer解码过程

AwesomePlayer中的prepare过程

总结:prepare过程调用了prepareAsync_l函数,在其中执行AwesomeEvent构造函数,并将AwesomePlayer调用onPrepareAsyncEvent的引用结果返回AwesomeEvent的构造函数作为参数

然后分析AwesomeEvent的过程。首先启动mQueue,作为EventHandler

上面的new AwesomeEvent会执行onPrepareAsyncEvent函数

总结:会将音视频分别处理,于是有了AwesomePlayer::initVideoDecoderAwesomePlayer::initAudioDecoder

先看initVideoDecoder

AwesomPlayer.h中几个变量的声明

然后看看初始化音频解码器

总结:在StageFright调用AwesomePlayer的prepare函数后,AwesomePlayer调用自身的prepareAsync初始化音视频解码器,无论是prepare还是prepareAsync都会触发OMXCode::Create函数,然后使用OMXCodec处理对应的业务逻辑

prepareAsync主要完成3件事
1.Streaming:启动下载数据并缓存
2.初始化并创建音视频解码器
3.通知上层已经处于Prepared状态

使用OMXCodec的解码过程

经过数据流封装得到的是两个MediaSource其实是两个OMXCodec。AwesomePlayer和mAudioPlayer都是从MediaSource中得到数据并进行播放的。AwesomePlayer得到的是最终要渲染的原始视频数据,而AudioPlayer得到的是最终要播放的原始音频数据,也就是说从OMXCOdec中读到的数据已经是原始数据

先看构造函数Create

总结
1.IOMX &omx指的是一个OMXNodeInstance对象的实例
2.MetaData &meta这个参数由MediaSource.getFormat获取得到,这个对象的主要成员是一个KeyedVector(uint32_t,typed_data)mItems,里面存放了一些代表MediaSource格式信息的键值对
3.bool createEncoder指明这个OMXCodec是编码还是解码
4.MediaSource &source是一个MeidaExtractor(数据解析器)
5.char* matchComponentName指定一种Codec用于生成这个OMXCodec

先使用findMatchingCodecs寻找对应的Codec,找到以后为当前IOMX分配节点并注册事件监听器

最后把IOMX封装进一个OMXCodec

这样就得到了OMXCodec

在AwesomePlayer中得到了这个OMXCodec后,我们返回初始化解码器的函数中

使mAudioSource=mOmxSource,然后调用start进行初始化

OMXCodec主要做以下两件事
1.向OpenMAX发送开始指令,如mOMX->sendCommand(mNode,OMX_CommandStateSet,OMX_StateIdle),表示状态就绪了,可以进入预解码阶段
2.调用allocateBufers函数分配两个缓冲去,存放在变量mPortBuffers[2]中,分别用于输入输出

然后再initxxxDecoder函数中调用start函数

触发MediaSource的子类VideoSource及AudioSource调用start函数后,它的内部就会开始从数据源获取数据并解析,等到缓冲区满后便停止。在AwesomePlayer里就可以调用MediaSource的read函数读取解码后的数据

对于mVideoSource来说,将读取的数据(mVideoSource->read(&mVideoBuffer,&options))交给显示模块进行渲染(mVideoRenderer->render(mVideoBuffer))

对于mAudioSource来说,用mAudioPlayer对mAudioSource进行封装,然后由mAudioPlayer负责读取数据控制播放

AwesomePlayer调用OMXCodec读取ES(基本码流,包含音视频或数据的连续码流),并进行解码处理

OMXCodec调用MediaSource的read函数获取音视频数据,调用Android的IOMX接口来实现音视频解码操作

这个过程就是prepare过程,主要用于分离音视频数据,给音视频申请好Buffer空间,做预解码操作

然后当Java层调用start函数时,通过MediaPlayerService进行IPC通信后,再调用StagefrightPlayer中的start函数,引用AwesomePlayer,这样就调用了AwesomePlayer的play函数

在AwesomePlayer调用play后,通过mVideoSource->read(&mVideoBuffer,&options)读取数据。mVideoSource->read(&mVideoBuffer,&options)具体是通过调用OMXCdodec.read来读取数据的。

而OMXCodec.read通过1.调用drainInputBuffers函数对mPortBuffers[kPortIndexInput]进行填充,这一步完成parse。由OpenMAX从数据源把demux(解复用)后的数据读取到输入缓冲区,作为OpenMAX的输入。2.通过fillOutputBuffers[kPortIndexInput]进行填充,这一步完成解码数据的填充。由OpenMAX对输入缓冲区中的数据进行解码,然后把解码后可以显示的视频数据输出到输出缓冲区

AwesomePlayer通过mVideoRenderer->render(mVideoBuffer)对经过parse和decode处理的数据进行渲染。一个mVideoRenderer其实就是一个包装了IOMXRenderer的AwesomeRemoteRenderer(在很早的版本才有,仅作了解)

【学习】从零开始的Android音视频开发(7)——AwesomePlayer的构造、解码过程相关推荐

  1. 【学习】从零开发的Android音视频开发(13)——MediaCodec到OMX框架过程及其硬解码

    MediaCodec到OMX框架过程 在讲NuPlayer时,NuPlayer解码部分会创建MediaCodec,并且最终到达OMX框架,先看MediaCodec的init函数 从init函数中可以看 ...

  2. Android 音视频开发学习思路

    Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...

  3. 企业级Android音视频开发笔记分享,快来get正确的学习姿势

    随着传统的图文媒体向以音视频为主的新媒体转变,音视频开发逐渐成为Android领域内的小热门.但音视频开发涉及的层面较广,相关的技术繁多且复杂,想要深入确有一定难度.且目前网络上关于Android 音 ...

  4. Android音视频开发基础(六):学习MediaCodec API,完成视频H.264的解码

    前言 在Android音视频开发中,网上知识点过于零碎,自学起来难度非常大,不过音视频大牛Jhuster提出了<Android 音视频从入门到提高 - 任务列表>.本文是Android音视 ...

  5. Android 音视频开发(二):使用 AudioRecord 采集音频PCM并保存到文件(学习笔记)

    关于 AudioRecord Android SDK 提供了两套音频采集的API,分别是:MediaRecorder 和 AudioRecord,前者是一个更加上层一点的API,它可以直接把手机麦克风 ...

  6. android音频开发6,Android 音视频开发(一) : 通过三种方式绘制图片

    想要逐步入门音视频开发,就需要一步步的去学习整理,并积累.本文是音视频开发积累的第一篇. 对应的要学习的内容是:在 Android 平台绘制一张图片,使用至少 3 种不同的 API,ImageView ...

  7. 直播平台源码搭建教程之Android音视频开发

    直播平台源码搭建教程之Android音视频开发 音频 将声音保存成音频的过程,其实就是将模拟音频数字化的过程,为了实现这个过程,就需要对模拟音频进行采样.量化和编码.接下来我们详细讲解这一过程. 采样 ...

  8. Android 音视频开发之基础篇 使用 imageview绘制一张图片

    Android 音视频开发 任务一 ImageView 绘制图片 文章目录 Android 音视频开发 任务一 ImageView 绘制图片 前言 一.配置activity_main.xml 二.添加 ...

  9. Android 音视频开发(三) -- Camera2 实现预览、拍照功能

    音视频 系列文章 Android 音视频开发(一) – 使用AudioRecord 录制PCM(录音):AudioTrack播放音频 Android 音视频开发(二) – Camera1 实现预览.拍 ...

最新文章

  1. 关于Qomo于ajax的异同~
  2. Spark机器学习9· 实时机器学习(scala with sbt)
  3. 用delphi操作mapinfo
  4. 详解 | 引起电源模块发热的4个主要原因
  5. zookeeper zoo.cfg配置文件
  6. python中最难的是什么_Python 最难的问题你猜是什么?
  7. linux 登入用户记录,linux记录所有用户登陆及执行过的命令脚本
  8. linux设备树sysfs,迅为-iMX6开发板-设备树内核-sys方式控制GPIO
  9. 倍福plc的型号_常用PLC型号大全及简介,选型必备技能!
  10. 安装3dmax出现:error 1311 找不到源文件
  11. 拖放 Drag and drop
  12. SLAM综述阅读笔记一:Past, Present, and Future of Simultaneous Localization And Mapping(2016)
  13. 使用Seaborn和Pandas进行相关性分析和可视化
  14. 普洱市企业登记“区块链云签名”试点工作启动, 用户操作仅需5分钟!
  15. preceding-sibling::*[1]
  16. 【搬运】黑苹果台式机机型选择指导 By 黑果小兵
  17. 51单片机实现的双机通信设计仿真
  18. java excel 边框颜色_poi生成excel整理(设置边框/字体/颜色/加粗/居中/)
  19. 使用python为Excel插入附件
  20. radius认证服务

热门文章

  1. polar靶场通关笔记
  2. windows动态链接库dll生成和使用
  3. 关于undefined reference to `WinMain@16`是发生了什么呢
  4. python前端开发和后端开发工程师_一文看懂前端和后端开发
  5. arduino编程语言_Arduino编程语言
  6. Kyuubi入门简介
  7. 七、svn带历史信息迁移到Gitlib
  8. Osmosis 0.46详细使用说明
  9. 快速开发框架源码 JNPF 旗舰版 单体版 java+netcore 炎黄盈动
  10. 这!就是数据安全-尚文网络xUP楠哥