ExoPlayer架构详解与源码分析(6)——MediaPeriod
系列文章目录
ExoPlayer架构详解与源码分析(1)——前言
ExoPlayer架构详解与源码分析(2)——Player
ExoPlayer架构详解与源码分析(3)——Timeline
ExoPlayer架构详解与源码分析(4)——整体架构
ExoPlayer架构详解与源码分析(5)——MediaSource
ExoPlayer架构详解与源码分析(6)——MediaPeriod
ExoPlayer架构详解与源码分析(7)——SampleQueue
文章目录
- 系列文章目录
- 前言
- MediaPeriod
- MediaPeriod的实现
- ProgressiveMediaPeriod
- 总结
前言
上篇看完了MediaSource,发现其中正在发挥作用的是其中的MediaPeriod,如果MediaSource是燃料系统的外壳,那么MediaPeriod就是其外壳下的核心,媒体数据的的加载获取甚至是解析主要就靠它了。
MediaPeriod
先看下整体结构

MediaPeriod主要用于加载于Timeline中的一个Period对于的媒体数据。换句话说Timeline中有多少个Period就会对于多少个MediaPeriod。
MediaPeriod的所有方法都在播放器内部线程调用。MediaPeriod是在MediaSource.createPeriod创建的,MediaSource中媒体数据的加载读取解复用最终提供数据给Renderer等都通过它来实现。MediaPeriod 中每个轨道对应一个SampleStream,MediaPeriod 在同一时间可能只能为一个SampleStream提供数据,但是当前的SampleStream 可以切换(因为MediaPeriod在读取数据时是单线程的,获取到数据后会同步解析数据,通过TrackId 将其关联到不同的轨道的SampleStream 中,这个后面具体会讲到)。
看下几个重要的方法定义
-
prepare异步准备当前的MediaPeriod,因为是异步的方法入参提供了一个Callback在prepared后通知调用者,在通知调用者前搜先会调用MediaSource的onSourceInfoRefreshed通知MediaSource更新Timeline,然后完成解轨道数据的解析提供给getTrackGroups方法,目的是提前准备好Timeline,如果prepare失败就会调用MediaPeriod的maybeThrowPrepareError方法
-
maybeThrowPrepareError功能如上,这个方法只会在prepare完成前调用
-
getTrackGroups获取解析出的轨道数据,因为解析轨道是prepare时完成的,所以这个方法只能在prepared之后调用。
-
selectTracks执行轨道选择,这是一个重要的方法,就是在这个方法中将轨道数据提供给上层使用者的确切的说是Renderer,同时Renderer也通过mayRetainStreamFlags 告诉MediaPeriod使用保留当前的SampleStream。MediaPeriod如果创建了新的流或者更新了SampleStream也会通过streamResetFlags=true来告诉Renderer需要重置当前的Renderer了。另外每次调用都应该更新TrackSelections。同样这个方法肯定也只能在prepared之后调用。
long selectTracks(@NullableType ExoTrackSelection[] selections,//TrackSelector提供的轨道选择boolean[] mayRetainStreamFlags,//需要保留的流@NullableType SampleStream[] streams,//提供的数据流boolean[] streamResetFlags,//需要替换的流long positionUs);//当前的播放位置,如果当前的period还没有播放,这个值就是起始播放位置 -
seekToUs Seek到指定位置。仅当至少选择一个轨道时才会调用此方法。
-
continueLoading 当需要继续加载数据时调用,MediaPeriod在prepareing或者prepared后都可以调用这个方法。
-
reevaluateBuffer 释放SampleStream的相关缓存,同样这个方法肯定也只能在prepared之后调用。
-
getStreamKeys 当MediaPeriod由多个播放源时,如HLS,这个方法返回一个多个源关于选中轨道的KeyList
MediaPeriod接口定义了数据解析的大致过程:
- prepare准备数据源,完成后selectTracks向外提供出SampleStream
- continueLoading 继续加载数据填充SampleStream
- 将使用完的数据通过reevaluateBuffer释放
MediaPeriod的实现

可以看到基本每一种ExoPlayer支持的媒体都实现了一个MediaPeriod,ProgressiveMediaPeriod相对比较基础和典型,后面也将重点解析它,剩余其他几种类型的可以先做了解,后面有时间再扩充。
ProgressiveMediaPeriod
ProgressiveMediaSource的MediaPeriod实现,主要用于渐进式媒体文件的加载,如本地或远程的单个视频文件,
先看下ProgressiveMediaPeriod整体结构

ProgressiveMediaPeriod主要分2部分:
- 数据存取 管理缓存获取的数据,主要交由SampleQueue来负责,需要提供高效的缓存读写能力保证数据的持续性。
- 数据加载解析 加载主要由DataSource负责,主要工作是获取媒体数据供解析器读取,解析器主要指的是Extractor,主要负责将获取的数据解析到不同的SampleQueue中。
上图中并没有MediaPeriod提到的SampleStream,其实ProgressiveMediaPeriod内部类中实现了SampleStream ,通过内部类将
对SampleStream 操作通过trackid关联转发给SampleQueue来实现,所以上图中的SampleQueue其实就是相当于SampleStream。
private final class SampleStreamImpl implements SampleStream {private final int track;public SampleStreamImpl(int track) {this.track = track;}@Overridepublic boolean isReady() {return ProgressiveMediaPeriod.this.isReady(track);}@Overridepublic void maybeThrowError() throws IOException {ProgressiveMediaPeriod.this.maybeThrowError(track);}@Overridepublic int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, @ReadFlags int readFlags) {return ProgressiveMediaPeriod.this.readData(track, formatHolder, buffer, readFlags);}@Overridepublic int skipData(long positionUs) {return ProgressiveMediaPeriod.this.skipData(track, positionUs);}}/* package */ int readData(int sampleQueueIndex,FormatHolder formatHolder,DecoderInputBuffer buffer,@ReadFlags int readFlags) {if (suppressRead()) {return C.RESULT_NOTHING_READ;}maybeNotifyDownstreamFormat(sampleQueueIndex);int result =//sampleQueueIndex查询对应的sampleQueues读取数据sampleQueues[sampleQueueIndex].read(formatHolder, buffer, readFlags, loadingFinished);if (result == C.RESULT_NOTHING_READ) {maybeStartDeferredRetry(sampleQueueIndex);}return result;}
Extractor和DataSource那一块还没扩展开,目前就已经很复杂了,DrmSessionManager和LoadErrorHandlingPolicy不是主线任务就跳过了,重点关注Loder、SampleQueue、DataSource、Extractor。
总结
MediaPeriod接口只是定义了标准的执行逻辑,具体如何实现其中定义的每个方法其实每种MediaPeriod实现都会有很大的差异,因为媒体结构本身就千变万化。ProgressiveMediaPeriod实现了其中一种相对基础的媒体类型,但是结构也很复杂,预计下面分多篇将ProgressiveMediaPeriod的SampleQueue、Loder、DataSource、Extractor分析一遍,下篇先从SampleQueue说起。
版权声明 ©
本文为CSDN作者山雨楼原创文章
转载请注明出处
原创不易,觉得有用的话,收藏转发点赞支持
相关文章:
ExoPlayer架构详解与源码分析(6)——MediaPeriod
系列文章目录 ExoPlayer架构详解与源码分析(1)——前言 ExoPlayer架构详解与源码分析(2)——Player ExoPlayer架构详解与源码分析(3)——Timeline ExoPlayer架构详解与源码分析(4)—…...
【开题报告】基于Spring Boot的课程在线预约系统的设计与实现
1.引言 随着互联网的发展,线上教育和课程培训变得越来越普遍。然而,很多学生在选择课程时面临一些困扰,例如如何找到适合自己的课程,如何与老师进行预约等。因此,设计一个基于Spring Boot的课程在线预约系统具有重要的…...
React Hooks还有哪些常用的用法?
除了之前提到的 useState、useEffect、useContext、useRef、useMemo 和 useCallback,还有一些其他常用的 React Hooks,它们提供了额外的功能和灵活性。以下是其中一些常见的 React Hooks: 1:useReducer:用于在函数组件中管理复杂的状态逻辑,类似于 Redux 的 reducer。 …...
基于Java的学生学籍管理系统设计与实现(源码+lw+部署文档+讲解等)
文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding) 代码参考数据库参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…...
Java内部类、匿名内部类、嵌套类详解
CONTENTS 1. 创建内部类2. 内部类到外部类的连接3. 在内部类中生成外部类对象的引用4. 匿名内部类5. 嵌套类6. 接口中的类 1. 创建内部类 创建内部类的方式就是把类定义放在一个包围它的类之中: package com.yyj;public class Parcel1 {class Contests {private i…...
【兔子王赠书第3期】《案例学Python(进阶篇)》
文章目录 前言推荐图书本书特色本书目录本书样章本书读者对象粉丝福利丨评论免费赠书尾声 前言 随着人工智能和大数据的蓬勃发展,Python将会得到越来越多开发者的喜爱和应用。因为Python语法简单,学习速度快,大家可以用更短的时间掌握这门语…...
【C刷题】day6
一、选择题 1、以下叙述中正确的是( ) A: 只能在循环体内和switch语句体内使用break语句 B: 当break出现在循环体中的switch语句体内时,其作用是跳出该switch语句体,并中止循环体的执行 C: continue语句的作用是:在…...
MySQL精髓:如何使用ALL一次找到最大值
题目来自LeetCode 题目 表:Project -------------------- | Column Name | Type | -------------------- | project_id | int | | employee_id | int | -------------------- (project_id, employee_id) 是该表的主键(具有唯一值的列的组合)。 employee_id 是该表…...
安全设备
一.防火墙 5层应用层 防火墙 4层 udp tcp 协议 华为 厂商 华为 h3 1.区域划分 Dmz 停火区 Untrust 不安全区域 Trust 安全区域 防火墙 默认禁止所有 二.Waf Web 应用防火墙 放到web前面 产品 雷池 绿盟 软件 安…...
基于Java的足球赛会管理系统设计与实现(源码+lw+部署文档+讲解等)
文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding) 代码参考数据库参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…...
如何确定Apache Kafka的大小和规模
调整或扩展Kafka以获得最佳成本和性能的第一步是了解数据流平台如何使用资源。这里给一些实用的建议。 实现Apache Kafka的团队,或者扩展他们对强大的开源分布式事件流平台的使用,通常需要帮助理解如何根据他们的需求正确地调整和扩展Kafka资源。这可能…...
项目总结-新增商品-Pagehelper插件分页查询
(1)新增商品 工具类: /** * Title: FileUtils.java * Package com.qfedu.common.utils * Description: TODO(用一句话描述该文件做什么) * author Feri * date 2018年5月29日 * version V1.0 */ package com.gdsdxy.common.u…...
java基础篇-环境变量
java基础 编程学习的关键点、重点1.环境变量设置待续 编程学习的关键点、重点 输入输出 Java语言、C语言、Python语言、甚至SQL语言,都需要实战、做大量输入输出等 1.环境变量设置 1.下载jdk安装 jdk官网下载直达链接:https://www.oracle.com/java/te…...
API自动化测试:如何构建高效的测试流程!
一、引言 在当前的软件开发环境中,API(Application Programming Interface)扮演了极为重要的角色,连接着应用的各个部分。对API进行自动化测试能够提高测试效率,降低错误,确保软件产品的质量。本文将通过实…...
MySQL8锁的问题
关键字 mysql 8、lock 问题描述 项目上反馈,一个简单的提交操作需要 40 秒。 抓取 SQL 发现 update gl_credit_bill set verifystate2 where id2761279790403840 执行耗时近40秒解决问题思路 手动执行 SQL,发现非常快,基本排除数据库本身…...
进阶JAVA篇-深入了解 Stream 流对象的创建与中间方法、终结方法
目录 1.0 Stream 流的说明 2.0 Stream 流对象的创建 2.1 对于 Collection 系列集合创建 Stream 流对象的方式 2.2 对于 Map 系列集合创建 Stream 流对象的方式 2.3 对于数组创建 Stream 流对象的方式 3.0 Stream 流的中间方法 3.1 Stream 流的 filter() 中间方法 3.2 Stream 流…...
原型制作的软件 Experience Design mac( XD ) 中文版软件特色
XD是一个直观、功能强大的UI/UX开发工具,旨在设计、原型、用户之间共享材料以及通过数字技术进行设计交互。Adobe XD提供了开发网站、应用程序、语音界面、游戏界面、电子邮件模板等所需的一切。xd mac软件特色 体验设计的未来。 使用 Adobe XD 中快速直观、即取即…...
Kotlin中使用ViewBinding绑定控件并添加点击事件
文章目录 效果1、加入依赖2、与控件进行绑定在 Activity 中使用视图绑定 3、监听控件 效果 实现源码 class MainActivity : AppCompatActivity() {lateinit var binding:ActivityMainBindingoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstan…...
Node学习笔记之MongoDB
一、简介 1.1 Mongodb 是什么 MongoDB 是一个基于分布式文件存储的数据库,官方地址 MongoDB: The Developer Data Platform | MongoDB 1.2 为什么选择 Mongodb 操作语法与 JavaScript 类似,容易上手,学习成本低 二、核心概念 Mongodb 中…...
awtk用C语言开发串口通信示例
awtk开发工具封装了串口,可以方便的异步调用,就做个程序试一下吧 在deepinlinux20.9版本调试通过,开始第一步先给系统增加usb串口线驱动 https://download.csdn.net/download/qiaozhangchi/87463972 串口控件ide里没有,需要自己…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...
