Android音视频开发之MediaExtactor使用教程
作者:JulyYu 发布时间:2023-03-20 19:25:11
前言
在之前学习如何使用MediaPlayer后,了解到Android系统提供开发者播放多媒体全家桶能力,但对于开发者希望DIY自由度更高的播放器能力也是可以利用Android内部提供组件包自行实现一个播放器的。举例实现一个视频播放这个流程,它大致流程是【多媒体文件解析提取视频文件】-> 【视频流解码】-> 【解码数据播放渲染到Render】。首要需要实现的是多媒体中需要文件提取工作,这就需要使用到Android提供MediaExtactor
类来实现提取媒体信息能力。
MediaExtactor
MediaExtactor
在Android
音视频开发中负责提取音视频信息和数据流的功能,可以通过该类实现从多媒体文件中剥离得到音频和视频的能力。
使用MediaExtactor
在一个音视频文件多可能会包含多个数据流(音频数据、视频数据等一般情况是一个视频组合多个音频)
因此需要
MediaExtactor
加载音视频文件获取到所有数据轨道通过遍历获取到想要操作的轨道
然后指定该轨道是
MediaExtactor
所有解析的数据流通过
MediaExtactor
获取到该轨道MediaFormat
加载音视频文件代码
加载音视频文件过程可传递Uri
、path
、URL
等。在确认希望需要解析的数据轨道后调用selectTrack
就能锁定当前MediaExtactor
要使用的轨道在之后数据解码中去使用。
// 加载资源
MediaExtractor extractor = new MediaExtractor();
extractor.setDataSource(path);
// 遍历获取视频轨道
int trackIndex = getTrackIndex(extractor, "audio/");
// 选定轨道
extractor.selectTrack(trackIndex);
获取轨道代码
加载文件之后可以通过MediaExtactor
的getTrackCount
方法获取到所有数据轨道。然后可以通过getTrackFormat
获取到轨道信息,通过MediaFormat.KEY_MIME
得到轨道格式比对期望所有获取到的轨道,比如比对"audio/"
就是希望获取到音频轨道数据。
// 获取指定轨道的方法
private static int getTrackIndex(MediaExtractor extractor, String mediaType) {
int trackIndex = -1;
for (int i = 0; i < extractor.getTrackCount(); i++) {
MediaFormat mediaFormat = extractor.getTrackFormat(i);
String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
if (mime.startsWith(mediaType)) {
trackIndex = i;
break;
}
}
return trackIndex;
}
提取轨道数据信息
在选定希望获取到的轨道后就可以获取到当前选择轨道的基本信息,例如视频尺寸大小、格式、时长、码率等一些音视频相关基础信息方便只有做解码时选用合适的解码器以及其他必要信息确认。
音频轨道基础信息获取
MediaFormatInfo mediaFormatInfo = new MediaFormatInfo();
mediaFormatInfo.mediaFormat = mediaFormat;
mediaFormatInfo.audioChannels = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
mediaFormatInfo.audioSampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
mediaFormatInfo.maxInputSize = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
mediaFormatInfo.mime = mediaFormat.getString(MediaFormat.KEY_MIME);
视频轨道基础信息获取
MediaFormatInfo mediaFormatInfo = new MediaFormatInfo();
mediaFormatInfo.mediaFormat = mediaFormat;
mediaFormatInfo.videoHeight = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
mediaFormatInfo.videoWidth = mediaFormat.getInteger(MediaFormat.KEY_WIDTH);
mediaFormatInfo.timeDuration = mediaFormat.getLong(MediaFormat.KEY_DURATION);
mediaFormatInfo.mime = mediaFormat.getString(MediaFormat.KEY_MIME);
但如果你选取的轨道是视频轨道但操作错误提取了音频相关信息可能会出现错误崩溃的情况(例如KEY_IS_ADTS
只有音频轨道才能提取),因此尽量保证提取参数是否正确做好代码保护机制。
一些源码细节分析
MediaExtactor
作为提取器,其底层代码逻辑也是调用JNI来实现的,它只是上层API提供出能力而已。 在源码细节中可以看到MediaExtactor
同样是加载media_jni
so库,这和MediaPlayer
是一样的逻辑。
public MediaExtractor() {
native_setup();
}
private native final void native_setup();
static {
System.loadLibrary("media_jni");
native_init();
}
同时setDataSoure
方法调用底层native
接口和MediaPlayer
也是同样的方法名和入参。
private native final void nativeSetDataSource(
@NonNull IBinder httpServiceBinder,
@NonNull String path,
@Nullable String[] keys,
@Nullable String[] values) throws IOException;
这基本也能够了解MediaExtactor
和MediaPlayer
在底层实现上应该属于同一套逻辑和功能。只不过MediaExtactor
可以理解为MediaPlayer
其中一小部分功能提供提取能力而MediaPlayer
是封装成型的工具类只需要加载音视频资源文件播放即可,中间提取轨道和解析过程直接就在底层帮开发者实现了。
来源:https://juejin.cn/post/7090477876813758471


猜你喜欢
- 1、继承Threadpublic class T4 {public static void main(String[] args) {Sys
- Main方法如下:static void Main(string[] args){ dynamic st
- public final class Integer extends Number implements Comparable<Int
- properties配置文件如下:human.name=Mr.Yuhuman.age=21human.gender=male如何把prope
- 一、Error:All flavors must now belong to a named flavor dimension问题描述:Er
- 一、什么是桥接模式桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又
- 1、线程的控制很常见,如文件传送到一半时,需要暂停文件传送,或终止文件传送,这实际上就是控制线程的运行。2、线程有创建、可运行、运行中、阻塞
- Android 6.0版本对于程序员兄弟来说最不友好的就是权限的问题,动态权限的设置曾经让我很苦恼,目前大部分关于6.0权限设置的框架基本都
- 前言在我的申请下,公司终于购买了一台基于Android12.0的手机,然后我就开心的拿去安装测试了,发现程序崩溃了,于是我这里就写下来,An
- // 举个例子:一个网站有用户系统、商家系统、网站后台3个系统//可以分3个userType, user ,shop , system//网
- 这篇文章主要介绍了Mybatis 缓存原理及失效情况解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- 网上找了几个,写的都不太适合,有的写出来了,也没有给出参考的算法链接。这样就导致了如果产生错误我们无法排查(不懂原理怎么排查对吧)。如果在使
- 前端采用layui框架,讲解多文件上传的完整实现功能。前端html重点代码如下:<div class="layui-form
- 素数就是质数,就是只能被1整除,不能被其他数整除的数java程序为:public static void main(String[] arg
- 目录什么是抽象类和接口? 区别在哪里?抽象类接口抽象类和接口解决了什么问题?如何模拟抽象类和接口如何决定该用抽象还是接口?什么是抽象类和接口
- 本文实例讲述了Android编程实现震动与振铃的方法。分享给大家供大家参考,具体如下:1、Android的震动实现——Vibrator类(1
- 什么是进程?电脑中时会有很多单独运行的程序,每个程序有一个独立的进程,而进程之间是相互独立存在的。比如下图中的QQ、酷狗播放器、电脑管家等等
- 本文实例为大家分享了C#实现银行家算法的具体代码,供大家参考,具体内容如下1.死锁死锁,顾名思义,是一种锁住不可自行解开的死局。在操作系统中
- 路由做Android/iOS原生开发的时候,要打开一个新的页面,你得知道你的目标页面对象,然后初始化一个Intent或者ViewContro
- 先看下这个问题的背景:假设有一个spring应用,开发人员希望自定义一个注解@Log,可以加到指定的方法上,实现自动记录日志(入参、出参、响