当前位置: 首页 > news >正文

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接口定义了数据解析的大致过程:

  1. prepare准备数据源,完成后selectTracks向外提供出SampleStream
  2. continueLoading 继续加载数据填充SampleStream
  3. 将使用完的数据通过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里没有,需要自己…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

【2025年】解决Burpsuite抓不到https包的问题

环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...

华为OD机考-机房布局

import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

【深度学习新浪潮】什么是credit assignment problem?

Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...

快速排序算法改进:随机快排-荷兰国旗划分详解

随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...