【Android 多媒体应用】使用MediaCodec解码使用SurfaceView显示视频
1.MainActivity.java
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.view.SurfaceHolder;
import android.view.SurfaceView; /**
* MediaCodec SurfaceHolder Example
* @author taehwan
*
*/
public class MainActivity extends Activity implements SurfaceHolder.Callback {
private VideoDecoderThread mVideoDecoder; private static final String FILE_PATH = Environment.getExternalStorageDirectory() + "/TopGirl.mp4"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); SurfaceView surfaceView = new SurfaceView(this);
surfaceView.getHolder().addCallback(this);
setContentView(surfaceView); mVideoDecoder = new VideoDecoderThread();
} @Override
public void surfaceCreated(SurfaceHolder holder) { } @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mVideoDecoder != null) {
if (mVideoDecoder.init(holder.getSurface(), FILE_PATH)) {
mVideoDecoder.start(); } else {
mVideoDecoder = null;
} }
} @Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mVideoDecoder != null) {
mVideoDecoder.close();
}
} }
2.VideoDecoderThread.java
import java.io.IOException;
import java.nio.ByteBuffer; import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.util.Log;
import android.view.Surface; public class VideoDecoderThread extends Thread {
private static final String VIDEO = "video/";
private static final String TAG = "VideoDecoder";
private MediaExtractor mExtractor;
private MediaCodec mDecoder; private boolean eosReceived; public boolean init(Surface surface, String filePath) {
eosReceived = false;
try {
mExtractor = new MediaExtractor();
mExtractor.setDataSource(filePath);
//分离出音轨和视轨
Log.d(TAG, "getTrackCount: " + mExtractor.getTrackCount() );
for (int i = 0; i < mExtractor.getTrackCount(); i++) {
MediaFormat format = mExtractor.getTrackFormat(i); String mime = format.getString(MediaFormat.KEY_MIME);
if (mime.startsWith(VIDEO)) {
mExtractor.selectTrack(i);
mDecoder = MediaCodec.createDecoderByType(mime);
try {
Log.d(TAG, "format : " + format);
mDecoder.configure(format, surface, null, 0 /* Decoder */); } catch (IllegalStateException e) {
Log.e(TAG, "codec '" + mime + "' failed configuration. " + e);
return false;
} mDecoder.start();
break;
}
} } catch (IOException e) {
e.printStackTrace();
} return true;
} @Override
public void run() {
BufferInfo info = new BufferInfo();
ByteBuffer[] inputBuffers = mDecoder.getInputBuffers();
mDecoder.getOutputBuffers(); boolean isInput = true;
boolean first = false;
long startWhen = 0; while (!eosReceived) {
if (isInput) {
int inputIndex = mDecoder.dequeueInputBuffer(10000);
if (inputIndex >= 0) {
// fill inputBuffers[inputBufferIndex] with valid data
ByteBuffer inputBuffer = inputBuffers[inputIndex]; int sampleSize = mExtractor.readSampleData(inputBuffer, 0); if (mExtractor.advance() && sampleSize > 0) {
mDecoder.queueInputBuffer(inputIndex, 0, sampleSize, mExtractor.getSampleTime(), 0); } else {
Log.d(TAG, "InputBuffer BUFFER_FLAG_END_OF_STREAM");
mDecoder.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
isInput = false;
}
}
} int outIndex = mDecoder.dequeueOutputBuffer(info, 10000);
switch (outIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
Log.d(TAG, "INFO_OUTPUT_BUFFERS_CHANGED");
mDecoder.getOutputBuffers();
break; case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
Log.d(TAG, "INFO_OUTPUT_FORMAT_CHANGED format : " + mDecoder.getOutputFormat());
break; case MediaCodec.INFO_TRY_AGAIN_LATER:
// Log.d(TAG, "INFO_TRY_AGAIN_LATER");
break; default:
if (!first) {
startWhen = System.currentTimeMillis();
first = true;
}
try {
long sleepTime = (info.presentationTimeUs / 1000) - (System.currentTimeMillis() - startWhen);
//Log.d(TAG, "info.presentationTimeUs : " + (info.presentationTimeUs / 1000) + " playTime: " + (System.currentTimeMillis() - startWhen) + " sleepTime : " + sleepTime); if (sleepTime > 0)
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} mDecoder.releaseOutputBuffer(outIndex, true /* Surface init */);
break;
} // All decoded frames have been rendered, we can stop playing now
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
Log.d(TAG, "OutputBuffer BUFFER_FLAG_END_OF_STREAM");
break;
}
} mDecoder.stop();
mDecoder.release();
mExtractor.release();
} public void close() {
eosReceived = true;
}
}
【Android 多媒体应用】使用MediaCodec解码使用SurfaceView显示视频的更多相关文章
- Android多媒体框架总结(1) - 利用MediaMuxer合成音视频数据流程分析
场景介绍: 设备端通过服务器传向客户端(Android手机)实时发送视频数据(H.264)和音频数据(g711a或g711u), 需要在客户端将音视频数据保存为MP4文件存放在本地,用户可以通过APP ...
- 基于 VLC 的 Android 多媒体解决方案
前段时间项目中需要在 Android 中播放视频.流媒体.查看监控,就研究了一下 Android 多媒体解决方案. 查找了一下,大致有如下几种: Android MediaPlayer FFmpeg ...
- Android 中使用MediaRecorder进行录像详解(视频录制)
在这里给出自己的一个测试DEMO,里面注释很详细.简单的视频录制功能. package com.video; import java.io.IOException; import android.ap ...
- Android 多媒体视频播放一( 多媒体理解与经验分享)
前言 说到android的多媒体,一把辛酸一把泪,当初听说会多媒体的比较牛掰,公司也有需求,于是乎我也积极的加入研究android多媒体的行列,记得以前刚接触的时候,最开始还是比较头大的,主要是但是很 ...
- android 原生 MediaPlayer 和 MediaCodec 的区别和联系(三)
目录: (4)Android 官方网站 对 MediaCodec的介绍 注:编解码器特定数据(Code-specific Data,简写为csd) 部分结合网上资料加入了补充和个人理解.请悉知 ...
- Android在MediaMuxer和MediaCodec用例 - audio+video
在Android多媒体类,MediaMuxer和MediaCodec这是一个相对年轻,他们是JB 4.1和JB 4.3据介绍. 前者被用来产生一个混合的音频和视频的多媒体文件.的缺点是,现在可以只支持 ...
- Android多媒体开发-stagefright及AwesomePlayer相关知识梳理
android的多媒体框架中, stagefright其实是AwesomePlayer的代理,就是个皮包公司. status_t StagefrightPlayer::setDataSource( c ...
- Android多媒体开发(3)————使用Android NKD编译havlenapetr-FFMpeg-7c27aa2
1. 使用NDK去编译官方的FFmpeg原版的话,还得自己实现JNI层与Java层,工程量比较大.所以移植FFmpeg到Android平台时,可以移植一些已经实现JNI与JAVA层的开源项目,毕竟软件 ...
- Android多媒体框架图
Android多媒体整体架构图 MediaPlayer框架图 Camera框架图 SoundRecorder框架图 VideoCamera框架图 OpenCore与Skia ALSA Audio框架图 ...
随机推荐
- javaScript中的DOM补充
一.DOM树 二.DOM节点 DOM 是这样规定的: 整个文档是一个文档节点 每个 HTML 标签是一个元素节点 包含在 HTML 元素中的文本是文本节点 每一个 HTM ...
- db2数据导出导入del与ixf格式区别
之前做数据迁移的时候遇到乱码的一些坑,总结一下. 一般导入导出: db2 export to /home/xxxx.del of del select * from tablename db2 im ...
- js模板方法
模板方法模式,定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤.模板方法模式把不变行为搬到超类中,从而去除了子类中的重复代码 ...
- 代码题(45)— 下一个排列、第k个排列
1.31. 下一个排列 实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列. 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列). 必须原地修改,只 ...
- iOS 检查指定日期是否在当前日期之前
iOS检查指定日期是否在当前日期之前, 直接上代码: - (BOOL)checkProductDate: (NSString *)tempDate { NSDateFormatter *dateFor ...
- vs 2005/2008/2010 ATL ActiveX控件显示XP风格
vs 2005/2008/2010 ATL ActiveX控件在IE浏览器中控件显示的是原始的风格,要显示XP风格只要进行以下操作 一.在Stdafx.h中增加下以内容 #if defined _M_ ...
- Codeforces Round #260(div2)C(递推)
有明显的递推关系: f[i]表示i为数列中最大值时所求结果.num[i]表示数i在数列中出现了几次. 对于数i,要么删i,要么删i-1,只有这两种情况,且子问题还是一样的思路.那么很显然递推一下就行了 ...
- AutoCAD2014的安装与激活
1.安装包与激活文件的下载 链接:https://pan.baidu.com/s/1I2-x9T__sQAgtvjkOyc_1Q 密码:5pd1 2.CAD的安装 此过程没什么特殊要求,安装时随便输入 ...
- MySql 创建函数 Error Code : 1418
查看日志信息:show variables like 'log_%';显示'log_bin'.'log_bin_trust_function_creators'等状态 解决方法: 关闭binary l ...
- HDU - 1402 A * B Problem Plus (FFT实现高精度乘法)
题意:计算A*B,A,B均为长度小于50000的整数. 这是FFT在大整数相乘中的一个应用,我本来想用NTT做的,但NTT由于取模很可能取炸,所以base必须设得很小,而且效率也比不上FFT. A和B ...