简介
MediaExtractor,用于提取指定媒体文件的媒体信息的一个工具类。说白一点,就是可以利用它提取视频或者音频中的信息和数据流,例如轨道,时长,格式等等。
MediaExtractor通常和MediaCodec一起使用,用于视频解码播放。
说明
一个视频里,可以包含多个数据流(一般是视频与音频各一个,但是音频可以多个)。我们需要先获取需要的数据轨道编号,才能后续的各种操作。
通常我们播放一个视频会使用以下类:
- MediaCodec:负责媒体文件的编码和解码工作,内部方法均为native
- MediaExtractor:负责将指定类型的媒体文件从文件中找到轨道,并填充到MediaCodec的缓冲区中
- AudioTrack:负责将解码之后的音频播放
- SurfaceView:展示解码之后的视频
视频被播放主要分为以下步骤:
- 将资源加载到MediaExtractor
- 获取视频所在轨道
- MediaExtractor选中视频所在轨道
- 创将解码视频的MediaCodec,decoder
- 开始循环,直到视频资源的末尾
- 将extractor中资源以一个单位填充进decoder的输入缓冲区
- decoder将解码之后的视频填充到输出缓冲区
- decoder释放输出缓冲区的同时,将缓冲区中数据渲染到surface
当然,这上面只是播放了视频,并没有播放音频,音频播放可参考我之前写的AudioTrack使用。
大家注意,千万别把视频和音频混为一谈,虽然我们口头上一直在说视频,但实际播放中他们是分开的,音频对应声音,视频对应影像图画。
由上可以看出MediaExtractor在这其中的作用
主要方法
- setDataSource(String path):设置数据源,可以是本地文件或者网络文件
- getTrackCount():得到源文件的轨道数
- getTrackFormat(int index):获取指定(index)的轨道格式
- getSampleTime():返回当前的时间戳
- readSampleData(ByteBuffer byteBuf, int offset):把指定轨道中的数据按偏移量读取到ByteBuffer中;
- advance():读取下一帧数据
- release(): 读取结束后释放资源
使用示例
private fun init() {
try {
//构造
mExtractor = MediaExtractor()
//设置视频数据源,可以是本地文件也可以是网络文件,这里我使用了手机本机拍摄的示例文件
mExtractor?.setDataSource("${
externalCacheDir!!.absolutePath}/test.mp4")
for (i in 0 until mExtractor!!.getTrackCount()) {
//获取轨道信息
val mediaFormat: MediaFormat = mExtractor!!.getTrackFormat(i)
val mime = mediaFormat.getString(MediaFormat.KEY_MIME)
Log.i("Test", "第${
i}个轨道格式:$mime\n")
}
} catch (e: Exception) {
Log.e("Test", "出错了", e)
}
}
打印数据如下:
I/Test: 第0个轨道格式:video/avc
I/Test: 第1个轨道格式:audio/mp4a-latm
从上面可以看出,MediaExtractor会帮我们提取视频文件的信息,其中video/avc
代表视频所在轨道信息,audio/mp4a-latm
代表音频所在轨道信息
主要是获取对应的MediaFormat.。MeidaFormat包含了视频的所有信息,下面列一些获取常用的视频信息:
val videoIndex = getTrackIndex("video/")//找到视频所在轨道
val mediaFormat: MediaFormat = mExtractor!!.getTrackFormat(videoIndex)
//获取视频高度
val width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH)
//获取视频高度
val height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT)
//总时长
val duration = mediaFormat.getLong(MediaFormat.KEY_DURATION)
//获取视频缓存输出的最大大小
val maxInputSize = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)
//以下是不一定能获取到的数据
//获取采样率
val sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE)
//获取码率
val bitRate = mediaFormat.getInteger(MediaFormat.KEY_BIT_RATE)
//获取声道数量
val channelCount = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT)
//获取帧率
val frameRate = mediaFormat.getInteger(MediaFormat.KEY_FRAME_RATE)
//PCM编码 模拟信号编码
val pcmEncoding = mediaFormat.getInteger(MediaFormat.KEY_PCM_ENCODING)
更多的信息可以自己去探索,官方文档:MediaExtractor
项目示例源码:Github/VideoDemo
关于涉及到与MediaCodec配合使用的内容我将会在后续博客中更新。
扫描二维码关注公众号,回复:
15907522 查看本文章