ExoPlayer架构详解与源码分析(5)——MediaSource
系列文章目录
ExoPlayer架构详解与源码分析(1)——前言
ExoPlayer架构详解与源码分析(2)——Player
ExoPlayer架构详解与源码分析(3)——Timeline
ExoPlayer架构详解与源码分析(4)——整体架构
ExoPlayer架构详解与源码分析(5)——MediaSource
文章目录
- 系列文章目录
- 前言
- MediaSource
- MediaSource的实现
- BaseMediaSource
- CompositeMediaSource
- WrappingMediaSource
- MaskingMediaSource
- ProgressiveMediaSource
- 总结
前言
上篇说完整体架构,这里开始分析其中的各个组件,先从MediaSource看起,继续拿运载火箭做对比,MediaSource在整个运载火箭中的角色就类似于燃料系统,确保火箭顺利升空,燃料系统是其中重要的一环,需要能在运行过程从持续稳定的提供燃料。ExoPlayer也一样,为了保证能够持续的渲染出媒体内容,就得保证MediaSource持续稳定提供需要的数据。
MediaSource
继续扩充下我们的版图

MediaSource定义了媒体信息以及提供媒体数据给播放器,主要有2个职责:
- 为播放器提供定义其媒体时序结构的Timeline,并在媒体时序结构发生变化时提供新的Timeline。初始化是提供一个PlaceholdTimeline,当prepareSource 完成时一般就能获取到真实的Timeline,然后调用传递给prepareSource 的MediaSourceCallers 上的onSourceInfoRefreshed 来更新这些新的Timeline。
- 为其Timeline中的Period提供 MediaPeriod 实例。 MediaPeriods是通过调用createPeriod获得的,并为播放器提供加载和读取媒体的方式。
应用代码不应该直接调用MediaSource 里的方法,而应该让ExoPlayer在合适的时间调用。
MediaSource实例可以重复使用,但只能同时用于一个 ExoPlayer 实例。
不同MediaSource 方法只能在应用程序线程或内部播放线程其中一个上调用。每个方法文档上都明确了可以调用的线程。
看下几个重要的方法定义
- getInitialTimeline主线程调用,当真实Timeline未知时立即返回初始PlaceholderTimeline,或者为返回null 让播放器创建初始Timeline。
- getMediaItem主线程调用,返回当前的MediaItem,可以看到MediaSource里也可能保存了MediaItem。
- prepareSource内部播放线程调用,注册 MediaSourceCaller,主要用来为播放器提供一个回调,获取最新的Timeline。另外,在播放某些播放资源需要先获取真实的媒体源时,这里会提前解析媒体资源(如播放HLS时这个时候会去获取解析M3U8文件),prepareSource完成后会立即刷新Timeline。
void prepareSource(MediaSourceCaller caller,@Nullable TransferListener mediaTransferListener,PlayerId playerId);interface MediaSourceCaller {void onSourceInfoRefreshed(MediaSource source, Timeline timeline);}
- createPeriod在内部播放线程调用,返回一个由periodId区分的新的MediaPerods对象,只能在真实的源已经准备好后再调用,也就是上面的prepareSource确保源已经准备完成,参数id就是MediaPerods唯一区分,startPositionUs想要播放的开始位置,allocator是一个缓存分配器这个后面讲MediaPerods会提到,MediaPerods创建完成后也会perpare,完成后一般就可以获取媒体的基本数据,如时长、轨道等,这个时候会反过来通知MediaSource刷新Timeline。
MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs);
MeidiaSource大致工作流程就是创建时初始化出一个Timeline,然后prepareSource准备数据源,之后createPeriod创建Period,然后讲工作交给Period,整个过程都在刷新Timeline。
MediaSource的实现

BaseMediaSource
MediaSource虚函数实现,主要用于多个MediaSourceEventListener的处理分发,触发多个MediaSourceCaller的onSourceInfoRefreshed,还保存上一次的Timeline。
CompositeMediaSource
由多个子MediaSource组成的复合MediaSource,将所有方法调用转发给各个子的MediaSource
WrappingMediaSource
继承自CompositeMediaSource,实现只包含了一个子MediaSource的MediaSource 。
MaskingMediaSource
一个MediaSource ,主要作用是当实际媒体结果未知时,用一个PlaceholderTimeline来表示Timeline ,当获取实际的媒体结构时采用实际的Timeline替换PlaceholderTimeline。
public MaskingMediaSource(MediaSource mediaSource, boolean useLazyPreparation) {super(mediaSource);this.useLazyPreparation = useLazyPreparation && mediaSource.isSingleWindow();window = new Timeline.Window();period = new Timeline.Period();@Nullable Timeline initialTimeline = mediaSource.getInitialTimeline();if (initialTimeline != null) {timeline =MaskingTimeline.createWithRealTimeline(initialTimeline, /* firstWindowUid= */ null, /* firstPeriodUid= */ null);hasRealTimeline = true;} else {timeline = MaskingTimeline.createWithPlaceholderTimeline(mediaSource.getMediaItem());}}
ProgressiveMediaSource
继承自BaseMediaSource,主要用于渐进式媒体文件的播放,如本地或远程的单个视频文件
@Override//prepareprotected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {transferListener = mediaTransferListener;drmSessionManager.setPlayer(/* playbackLooper= */ checkNotNull(Looper.myLooper()), getPlayerId());drmSessionManager.prepare();notifySourceInfoRefreshed();}@Override//ProgressiveMediaPeriod在获取到Timeline相关信息后会回调更新Timelinepublic void onSourceInfoRefreshed(long durationUs, boolean isSeekable, boolean isLive) {// 优先实现之前的durationUs durationUs = durationUs == C.TIME_UNSET ? timelineDurationUs : durationUs;if (!timelineIsPlaceholder&& timelineDurationUs == durationUs&& timelineIsSeekable == isSeekable&& timelineIsLive == isLive) {// 没有发生变更return;}timelineDurationUs = durationUs;timelineIsSeekable = isSeekable;timelineIsLive = isLive;timelineIsPlaceholder = false;notifySourceInfoRefreshed();}//刷新TimeLineprivate void notifySourceInfoRefreshed() {Timeline timeline =new SinglePeriodTimeline(timelineDurationUs,timelineIsSeekable,/* isDynamic= */ false,/* useLiveConfiguration= */ timelineIsLive,/* manifest= */ null,mediaItem);if (timelineIsPlaceholder) {timeline =new ForwardingTimeline(timeline) {@Overridepublic Window getWindow(int windowIndex, Window window, long defaultPositionProjectionUs) {super.getWindow(windowIndex, window, defaultPositionProjectionUs);window.isPlaceholder = true;return window;}@Overridepublic Period getPeriod(int periodIndex, Period period, boolean setIds) {super.getPeriod(periodIndex, period, setIds);period.isPlaceholder = true;return period;}};}//触发监听refreshSourceInfo(timeline);}
总结
没了就这么多,燃料系统这么简陋的吗?当然不会,因为它把除了Timeline的管理维护之外的几乎所有的工作都交给别人来完成了,它就是下面要重点讲的MediaPeriod,MediaSource只管创建出就好了,ExoPlayer也是主要通过MediaSource关联的MediaPeriod控制媒体的加载释放等。
版权声明 ©
本文为CSDN作者山雨楼原创文章
转载请注明出处
原创不易,觉得有用的话,收藏转发点赞支持
相关文章:
ExoPlayer架构详解与源码分析(5)——MediaSource
系列文章目录 ExoPlayer架构详解与源码分析(1)——前言 ExoPlayer架构详解与源码分析(2)——Player ExoPlayer架构详解与源码分析(3)——Timeline ExoPlayer架构详解与源码分析(4)—…...
控制一个游戏对象的旋转和相机的缩放
介绍 这段代码是一个Unity游戏开发脚本,它用于控制一个游戏对象的旋转和相机的缩放。以下是代码的主要功能: 控制游戏对象的旋转: 通过按下Q键和W键,用户可以选择以逆时针或顺时针方向绕游戏对象的Y轴进行旋转。旋转角度和速度可…...
【数据结构】线性表(二)单链表及其基本操作(创建、插入、删除、修改、遍历打印)
目录 前文、线性表的定义及其基本操作(顺序表插入、删除、查找、修改) 四、线性表的链接存储结构 1. 单链表(C语言) a. 链表节点结构 b. 创建新节点 c. 在链表末尾插入新节点 d. 删除指定节点 e. 修改指定节点的数据 f. …...
label的作用是什么?是怎么用的?(1)
Label(标签)在不同的上下文中有不同的作用和用途。以下是几种常见的用途和用法: 1. 数据标注:在机器学习和数据科学中,标签用于标识数据样本的类别或属性。标注数据是监督学习中的一项重要任务,它为算法提…...
C- 使用原子变量实现自旋锁
自旋锁 自旋锁(Spinlock)是一种常用于多线程编程中的低开销锁,其特点是当线程尝试获取锁而锁已被其他线程占用时,该线程会处于一个持续的忙等待(busy-wait)状态,直到它可以获取到锁为止。这种方…...
汇编的指令
减法类指令: 不带借位的减法: sub dest,src;dest(dest)-(src) 注意: 1、源操作数和目的操作数不能同时为段寄存器或存储单元 2、对标志位有影响,主要影响CF、ZF、OF、SF。 带借位的减法: sbb dest,src;dest(dest)-(…...
《数据结构、算法与应用C++语言描述》使用C++语言实现数组队列
《数据结构、算法与应用C语言描述》使用C语言实现数组队列 定义 队列的定义 队列(queue)是一个线性表,其插入和删除操作分别在表的不同端进行。插入元素的那一端称为队尾(back或rear),删除元素的那一端称…...
零基础如何学习自动化测试
现在很多测试人员有些急于求成,没有任何基础想当然的,要在一周内上手自动化测试。 在自动化的过程中时候总有人会犯很低级的问题,有语法问题,有定位问题,而且有人居然连__init__.py 文件名都弄错误,还有将…...
系统架构师备考倒计时16天(每日知识点)
1.信息化战略与实施 2.UML图(12个) 3.结构化设计(耦合) 4.SMP与AMP的区别(多核处理器的工作方式) 多核处理器一般有SMP和AMP两种不同的工作方式: SMP(对称多处理技术):将2颗完全一样的处理器封…...
【MySQL系列】- Select查询SQL执行过程详解
【MySQL系列】- Select查询SQL执行过程详解 文章目录 【MySQL系列】- Select查询SQL执行过程详解一、SQL查询语句的执行过程二、SQL执行过程详解2.1. 连接器2.2. 查询缓存2.3. 分析器2.4. 优化器2.5. 执行器 三、undo log 和 redo log作⽤3.1. redo log (重做日志&a…...
软考高级信息系统项目管理师系列之:信息系统项目管理师论文评分参考标准
软考高级信息系统项目管理师系列之:信息系统项目管理师论文评分参考标准 论文满分是 75 分,论文评分可分为优良、及格与不及格 3 个档次。评分的分数可分为: 60 分至 75 分优良(相当于百分制 80 分至 100 分)。45 分至 59 分及格(相当于百分制 60 分至 79 分)。0 分至 44 分…...
MyBatis--多案例让你熟练使用CRUD操作
目录 一、前期准备 二、两种实现CRUD方式 三、增加数据(INSERT) 四、删除数据(DELETE) 五、查询数据(SELECT) 六、更新数据(UPDATE) 一、前期准备 1.创建maven项目并在pom文件…...
用Python造轮子
目录 背景安装setuptools库准备要打包的代码创建setup.py文件打包生成whl文件把库装到电脑上使用这个库 背景 如何把自己写的代码,打包成库方便其他人使用 安装setuptools库 正所谓想要富先修路,先把造轮子要用的库装上 pip install wheel pip insta…...
ARM 堆栈寻址类型区分
文章目录 堆栈指向分类堆栈指向数据分类满递增与满递减空递增与空递减 堆栈指向分类 根据堆栈指针的指向的方向不同,可以划分为向上生成型和向下生成型。 向上生成型: 随着数据的入栈,堆栈的指针逐渐增大,称为:递增…...
每日一练 | 网络工程师软考真题Day43
1、在生成树协议〔STP〕IEEE 802.1d中,根据 来选择根交换机。 A.最小的MAC地址 B.最大的MAC地址 C.最小的交换机ID D.最大的交换机ID 2、在快速以太网物理层标准中,使用两对5类无屏蔽双绞线的是 。 A&…...
jsonXML格式化核心代码
json格式化: 依赖: <dependency><groupId>com.jayway.jsonpath</groupId><artifactId>json-path</artifactId><version>2.6.0</version><scope>compile</scope> </dependency> string t…...
PTQ量化和QAT量化
目录 1--PTQ量化 2--QAT量化 1--PTQ量化 PTQ量化表示训练后量化(Post Training Quantization)。使用一批校准数据对训练好的模型进行校准,将训练好的FP32网络直接转换为定点计算的网络,过程中无需对原始模型进行任何训练&#x…...
【Django 02】数据表构建、数据迁移与管理
1. Django 构建数据表创建与数据迁移 1.1 数据表创建 1.1.1 模块功能 如前所述,models.py文件主要用一个 Python 类来描述数据表。运用这个类,可以通过简单的 Python 代码来创建、检索、更新、删除 数据库中的记录而无需写一条又一条的SQL语句。今天的例子就是在…...
一天吃透Java集合面试八股文
内容摘自我的学习网站:topjavaer.cn 常见的集合有哪些? Java集合类主要由两个接口Collection和Map派生出来的,Collection有三个子接口:List、Set、Queue。 Java集合框架图如下: List代表了有序可重复集合,…...
高级深入--day36
Settings Scrapy设置(settings)提供了定制Scrapy组件的方法。可以控制包括核心(core),插件(extension),pipeline及spider组件。比如 设置Json Pipeliine、LOG_LEVEL等。 参考文档:Settings — Scrapy 1.0.5 文档 内置设置参考手册 BOT_NAME 默认: scrapybot 当您使用 sta…...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
API网关Kong的鉴权与限流:高并发场景下的核心实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中,API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关,Kong凭借其插件化架构…...
