Android媒体解码MediaCodec,MediaExtractor
Android提供了MediaPlayer播放器播放媒体文件,其实MediaPlyer只是对Android Media包下的MediaCodec和MediaExtractor进行了包装,方便使用。但是最好理解下Android媒体文件的解码,编码和渲染流程。
Shape Of My Heart.mp4
<source src="http://7xoquj.com1.z0.glb.clouddn.com/shape_of_my_heart.mp4" type="video/mp4">
使用android.media
包下的MediaCodec和MediaExtractor实现一个简单的视频解码渲染。
使用到了:
- MediaCodec:负责媒体文件的编码和解码工作,内部方法均为native
- MediaExtractor:负责将指定类型的媒体文件从文件中找到轨道,并填充到MediaCodec的缓冲区中
- AudioTrack:负责将解码之后的音频播放
- SurfaceView:展示解码之后的视频
视频被播放主要分为以下步骤:
- 将资源加载到extractor
- 获取视频所在轨道
- 设置extractor选中视频所在轨道
- 创将解码视频的MediaCodec,decoder
- 开始循环,直到视频资源的末尾
- 将extractor中资源以一个单位填充进decoder的输入缓冲区
- decoder将解码之后的视频填充到输出缓冲区
- decoder释放输出缓冲区的同时,将缓冲区中数据渲染到surface
音频的播放类似,只多了AudioTrack部分,少了渲染到surface部分。
MediaCodec.releaseOutputBuffer(int outputBufferIndex, boolean render);
- render为
true
就会渲染到surface
播放的控制,视频和音频各自拥有一个Thread。
public void play() {isPlaying = true;if (videoThread == null) {videoThread = new VideoThread();videoThread.start();}if (audioThread == null) {audioThread = new AudioThread();audioThread.start();}}public void stop() {isPlaying = false;}
VideoThread
private class VideoThread extends Thread {@Overridepublic void run() {MediaExtractor videoExtractor = new MediaExtractor();MediaCodec videoCodec = null;try {videoExtractor.setDataSource(filePath);} catch (IOException e) {e.printStackTrace();}int videoTrackIndex;//获取视频所在轨道videoTrackIndex = getMediaTrackIndex(videoExtractor, "video/");if (videoTrackIndex >= 0) {MediaFormat mediaFormat = videoExtractor.getTrackFormat(videoTrackIndex);int width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH);int height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);//视频长度:秒float time = mediaFormat.getLong(MediaFormat.KEY_DURATION) / 1000000;callBack.videoAspect(width, height, time);videoExtractor.selectTrack(videoTrackIndex);try {videoCodec = MediaCodec.createDecoderByType(mediaFormat.getString(MediaFormat.KEY_MIME));videoCodec.configure(mediaFormat, surface, null, 0);} catch (IOException e) {e.printStackTrace();}}if (videoCodec == null) {Log.v(TAG, "MediaCodec null");return;}videoCodec.start();MediaCodec.BufferInfo videoBufferInfo = new MediaCodec.BufferInfo();ByteBuffer[] inputBuffers = videoCodec.getInputBuffers();
// ByteBuffer[] outputBuffers = videoCodec.getOutputBuffers();boolean isVideoEOS = false;long startMs = System.currentTimeMillis();while (!Thread.interrupted()) {if (!isPlaying) {continue;}//将资源传递到解码器if (!isVideoEOS) {isVideoEOS = putBufferToCoder(videoExtractor, videoCodec, inputBuffers);}int outputBufferIndex = videoCodec.dequeueOutputBuffer(videoBufferInfo, TIMEOUT_US);switch (outputBufferIndex) {case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:Log.v(TAG, "format changed");break;case MediaCodec.INFO_TRY_AGAIN_LATER:Log.v(TAG, "解码当前帧超时");break;case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED://outputBuffers = videoCodec.getOutputBuffers();Log.v(TAG, "output buffers changed");break;default://直接渲染到Surface时使用不到outputBuffer//ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];//延时操作//如果缓冲区里的可展示时间>当前视频播放的进度,就休眠一下sleepRender(videoBufferInfo, startMs);//渲染videoCodec.releaseOutputBuffer(outputBufferIndex, true);break;}if ((videoBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {Log.v(TAG, "buffer stream end");break;}}//end whilevideoCodec.stop();videoCodec.release();videoExtractor.release();}}
获取指定类型媒体文件所在轨道
//获取指定类型媒体文件所在轨道private int getMediaTrackIndex(MediaExtractor videoExtractor, String MEDIA_TYPE) {int trackIndex = -1;for (int i = 0; i < videoExtractor.getTrackCount(); i++) {//获取视频所在轨道MediaFormat mediaFormat = videoExtractor.getTrackFormat(i);String mime = mediaFormat.getString(MediaFormat.KEY_MIME);if (mime.startsWith(MEDIA_TYPE)) {trackIndex = i;break;}}return trackIndex;}
将缓冲区传递至解码器
//将缓冲区传递至解码器private boolean putBufferToCoder(MediaExtractor extractor, MediaCodec decoder, ByteBuffer[] inputBuffers) {boolean isMediaEOS = false;int inputBufferIndex = decoder.dequeueInputBuffer(TIMEOUT_US);if (inputBufferIndex >= 0) {ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];int sampleSize = extractor.readSampleData(inputBuffer, 0);if (sampleSize < 0) {decoder.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);isMediaEOS = true;Log.v(TAG, "media eos");} else {decoder.queueInputBuffer(inputBufferIndex, 0, sampleSize, extractor.getSampleTime(), 0);extractor.advance();}}return isMediaEOS;}
音频的部分类似,完整源码请移步jiyangg/MediaPlaySimpleDemo
转载于:https://www.cnblogs.com/jiy-for-you/p/7282033.html
Android媒体解码MediaCodec,MediaExtractor相关推荐
- android jni 硬解码,Android 硬解码 MediaCodec 遇到的(部分手机绿屏)API21
MediaCodec 是android用来做音视频编解码 下面是遇到其它的问题(解码几分钟后一直dequeueInputBuffer-1) http://blog.csdn.net/qq3773663 ...
- Android 音视频编解码 MediaCodec
MediaCodec 简介 Android中的MediaCodec是一个用于音视频编解码功能的API,使用它可以实现对音视频数据进行压缩.解压缩.编辑和转换.以下是MediaCodec的主要功能: 支 ...
- 【AVD】FFmpeg + MediaCodec 实现 Android 硬件解码,中间有个大坑
最近在做移动端音视频编解码,首先要实现的是移动端视频的解码功能.纯的 FFmpeg 方法在移动端也能实现,但是效率上的确要慢一些,1080p 的视频还好,但是上到 2k.4k,那个解码速度(以肉眼可见 ...
- Android中使用MediaCodec视频编码异步实现
Android中使用MediaCodec进行视频编解码异步实现 简单的介绍一下MediaCodec:本文主要讲述的是博主自己在用MediaCodec进行编解码过程中分别用同步和异步两种方式实现了硬编解 ...
- Android音视频-MediaCodec
原文:https://mp.weixin.qq.com/s?__biz=MzU3NTA3MDU1OQ==&mid=2247484865&idx=1&sn=174b8ca7024 ...
- android m4a播放器,如何在android上解码m4a音频
我试图在android上解码音频并获取原始数据以应用过滤器. 所以我首先用 extractor.getTrackFormat(0); MediaExtractor extractor = new Me ...
- Android 媒体 IV-支持的媒体格式
概述: 该文档介绍了Android平台可以支持的媒体编解码, 容器和网络协议. 作为一个APP开发者, 我们可以自由的使用任何Android设备上的媒体编解码器, 包括那些Android提供的和设备指 ...
- android 播放器 wav 无法播放,对于Android媒体播放器mp3与wav(For android media player mp3 vs. wav)...
对于Android媒体播放器mp3与wav(For android media player mp3 vs. wav) 我想知道在Android媒体播放器上加载和播放小wav是否比较快的小文件更快. ...
- 全新的基于 Windows NT (2000/XP/2003) 的媒体解码包.
Zoom Player Platinum Stream Codec ( 绚彩魅影) 2.1 Build 104 全新的基于 Windows NT (2000/XP/2003) 的媒体解码包.它包含了支 ...
最新文章
- 简单介绍Lua中三种循环语句的使用
- server sql 分组 去重 字符串拼接_SQL | 数据分析面试必备SQL语句+语法
- python怎么限制输出精度_谈谈关于Python里面小数点精度控制的问题
- keyshot手机渲染教程_keyshot灯光渲染基础入门教程【英】
- (转)百度文库浏览器分析及实现(续)
- 五款常用邮件管理系统评测
- sklearn中常用的数据预处理方法
- 软件测试之python面试题_常见Python面试题整理带答案
- L323 英语有必要学语法吗
- 基于Java生鲜蔬菜食品商城系统详细设计和实现
- 52个比付费软件更好的免费软件
- pymol怎么做底物口袋表面_高质量PyMOL作图教程
- fabs () 函数
- NTP客户端配置-Windows时间同步设置
- 数学建模竞赛常用软件培训2
- Java自学之异常处理——自学笔记
- 2014智联卓聘积分获取新攻略
- python下载油管、B站视频的方法
- Android 机型适配之百分比适配 ConstraintLayout
- 医疗供应链-药品SPD管理
热门文章
- c语言gcc汇编文件,[汇编]gcc生成汇编.s文件 $ gcc -Og -S sum.c /$ gcc -Og -S -masm=intel sum.c 与 反汇编 objdump...
- Promise学习笔记
- LeetCode 1973. Count Nodes Equal to Sum of Descendants(DFS)
- LeetCode 1819. 序列中不同最大公约数的数目
- ACwing 2. 01背包问题(DP)
- LeetCode 319. 灯泡开关(找规律)
- LeetCode 26. 删除排序数组中的重复项
- Android8.1怎么装谷歌,谷歌PixelXL安卓9.0/8.1/8.0/7.X安装面具ROOT方案
- .net pdf转图片_pdf2image类库实现批量pdf转图片
- python求超级素数代码_C语言求超级素数