系列文章目录
ExoPlayer架构详解与源码分析(1)——前言
ExoPlayer架构详解与源码分析(2)——Player
ExoPlayer架构详解与源码分析(3)——Timeline
ExoPlayer架构详解与源码分析(4)——整体架构
ExoPlayer架构详解与源码分析(5)——MediaSource
ExoPlayer架构详解与源码分析(6)——MediaPeriod
ExoPlayer架构详解与源码分析(7)——SampleQueue
ExoPlayer架构详解与源码分析(8)——Loader
ExoPlayer架构详解与源码分析(9)——TsExtractor
ExoPlayer架构详解与源码分析(10)——H264Reader
ExoPlayer架构详解与源码分析(11)——DataSource
ExoPlayer架构详解与源码分析(12)——Cache
ExoPlayer架构详解与源码分析(13)——TeeDataSource和CacheDataSource
文章目录
前言
好久不见各位,间隔了一段时间忙项目,终于有时间补上ProgressiveMediaPeriod最后一块拼图——DataSource。间隔太久先来个前情回顾。
本系列先介绍了ExoPlayer的整体架构还有些基本概念,然后围绕四大组件展开讲解,首先从MediaSource这个组件讲起,MediaSource主要由ProgressiveMediaPeriod来完整工作,先看下ProgressiveMediaPeriod整体结构:
之前的文章已经讲解完上图里用于解析数据的左半部分,而这些用于解析的数据就是从右半部分的DataSource里获取的。还是拿火箭来类比,MediaSource是火箭的燃料系统,那么左半边可以理解为燃油泵控制燃料的多少,右半部分就是油箱,为整个发动机提供源源不断的燃料。
DataSource
DataSource字面就是数据源的意思,用来读取URI定义的资源数据,扩展了DataReader提供了read方法供外部读取数据
看下主要方法:
- open 打开一个数据源,读取指定的数据,传入一个DataSpec用于告诉DataSource打开源的必要信息,如URI,数据的起始位置长度等,如果DataSpec打开数据段在数据范围内,那么通过read方法可以正常读取数据,如果DataSpec的position正好等于数据的长度,则会立即返回C.RESULT_END_OF_INPUT,如果超过数据的长度,则直接抛出IOException异常。
- read 从输入中读取最多length字节的数据,从buffer的offset位置开始填充length长度。如果readLength为0,则返回 0。如果由于已到达打开范围的末尾而没有可用数据,则返回C.RESULT_END_OF_INPUT 。否则,调用将阻塞,直到读取至少一个字节的数据并返回读取的字节数。
- close 关闭源。即使open调用抛出IOException 时,也必须调用此方法关闭源。
- getUri 数据源未open时返回null,当源打开时,返回从中读取数据的Uri 。返回的Uri将与open中的DataSpec的URI相同。如果发生了重定向,则返回重定向后的Uri 。
- getResponseHeaders 当源打开时,返回与上次open调用关联的响应标头。否则,返回一个空Map。返回Map中的键不区分大小写。
DataSource的实现
DataSource的定义很简单,主要就是和数据源的相关操作,打开、读取、关闭。
它的具体实现有很多这里列出常用的一部分
先过下简单几个DataSource:
-
BaseDataSource 主要实现了多个TransferListener的监听分发管理。
-
PlaceholderDataSource 顾名思义一个用于占位的DataSource,不可调用其中的open,read方法,会抛出异常。
-
StatsDataSource 一个DataSource的包装,会将所有的方法调用转发给子DataSource。
-
AesCipherDataSource 也是一个DataSource的包装,会将所以的方法调用转发给子DataSource,与StatsDataSource不同的是,可以AES解密加密子的DataSource,会将子DataSource返回的数据经过AES解密返回给上层。
-
PriorityDataSource 有优先级管理的DataSource,可以使用PriorityTaskManager管理包含的子DataSource ,只有优先级足够高才可以继续调用open和read否则抛出PriorityTooLowException异常通知上层更改执行顺序。
-
DataSchemeDataSource data作为Scheme的URI的DataSource,如将数据直接转成base64存储在字符串中的方式,这类读取也很简单,直接Base64转成字节数据就行了。
-
AssetDataSource 顾名思义,用来读取Android Asset文件,通过AssetManager获取到文件流。
-
ContentDataSource 通过ContentResolver获取到文件描述,然后打开文件流。
-
RawResourceDataSource 同Resources.openRawResourceFd获取文件描述打开文件流。
-
FileDataSource 打开文件路径的DataSource,这里看下实现。
@Override public long open(DataSpec dataSpec) throws FileDataSourceException { Uri uri = dataSpec.uri; this.uri = uri; transferInitializing(dataSpec);//触发监听 this.file = openLocalFile(uri);//创建随机访问的文件流,RandomAccessFile try { file.seek(dataSpec.position);//seek到DataSpec 指定的开始位置 bytesRemaining =//获取未读取长度 dataSpec.length == C.