Android(安卓)新API 之 MediaCodec使用笔记
16lz
2021-01-25
Android的视频编解码一直让人有点纠结,SDK竟然不提供硬件编解码的API,如果你想自己做,只能通过JNI借助第三方编解码器,其都是使用的软解码,效率很难保证,这对想做视频通话的是一个不小的打击。
好了,说到google 新提供的SDK中出现的类MediaCodec,这个api限制在API 16后,也就是Android 4.1.2后才可以使用,如果你的系统低于这个版本,是不可以使用这个类的。MediaCodec这家伙能提供给你硬件编解码功能,当然得厂商支持在下层已经,如果厂商没做好,系统会提供给你软件编解码器,反正不用你操心,可以直接就拿来用的。
使用网上有人提供的Demo,可以解码mp4文件,具体情况还没研究,先放出Github链接,直接自己抓出来就可以用,
如果懒得去抓,下面贴出代码,就一个简单的Activity,一切搞定,
“记得修改文件名,SAMPLE变量为你自己的文件名称”,
package io.vec.demo.mediacodec;import java.nio.ByteBuffer;import android.app.Activity;import android.media.MediaCodec;import android.media.MediaCodec.BufferInfo;import android.media.MediaExtractor;import android.media.MediaFormat;import android.os.Bundle;import android.os.Environment;import android.util.Log;import android.view.Surface;import android.view.SurfaceHolder;import android.view.SurfaceView;public class DecodeActivity extends Activity implements SurfaceHolder.Callback {private static final String SAMPLE = Environment.getExternalStorageDirectory() + "/video.mp4";private PlayerThread mPlayer = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);SurfaceView sv = new SurfaceView(this);sv.getHolder().addCallback(this);setContentView(sv);}protected void onDestroy() {super.onDestroy();}@Overridepublic void surfaceCreated(SurfaceHolder holder) {}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {if (mPlayer == null) {mPlayer = new PlayerThread(holder.getSurface());mPlayer.start();}}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {if (mPlayer != null) {mPlayer.interrupt();}}private class PlayerThread extends Thread {private MediaExtractor extractor;private MediaCodec decoder;private Surface surface;public PlayerThread(Surface surface) {this.surface = surface;}@Overridepublic void run() {extractor = new MediaExtractor();extractor.setDataSource(SAMPLE);for (int i = 0; i < extractor.getTrackCount(); i++) {MediaFormat format = extractor.getTrackFormat(i);String mime = format.getString(MediaFormat.KEY_MIME);if (mime.startsWith("video/")) {extractor.selectTrack(i);decoder = MediaCodec.createDecoderByType(mime);decoder.configure(format, surface, null, 0);break;}}if (decoder == null) {Log.e("DecodeActivity", "Can't find video info!");return;}decoder.start();ByteBuffer[] inputBuffers = decoder.getInputBuffers();ByteBuffer[] outputBuffers = decoder.getOutputBuffers();BufferInfo info = new BufferInfo();boolean isEOS = false;long startMs = System.currentTimeMillis();while (!Thread.interrupted()) {if (!isEOS) {int inIndex = decoder.dequeueInputBuffer(10000);if (inIndex >= 0) {ByteBuffer buffer = inputBuffers[inIndex];int sampleSize = extractor.readSampleData(buffer, 0);if (sampleSize < 0) {// We shouldn't stop the playback at this point, just pass the EOS// flag to decoder, we will get it again from the// dequeueOutputBufferLog.d("DecodeActivity", "InputBuffer BUFFER_FLAG_END_OF_STREAM");decoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);isEOS = true;} else {decoder.queueInputBuffer(inIndex, 0, sampleSize, extractor.getSampleTime(), 0);extractor.advance();}}}int outIndex = decoder.dequeueOutputBuffer(info, 10000);switch (outIndex) {case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:Log.d("DecodeActivity", "INFO_OUTPUT_BUFFERS_CHANGED");outputBuffers = decoder.getOutputBuffers();break;case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:Log.d("DecodeActivity", "New format " + decoder.getOutputFormat());break;case MediaCodec.INFO_TRY_AGAIN_LATER:Log.d("DecodeActivity", "dequeueOutputBuffer timed out!");break;default:ByteBuffer buffer = outputBuffers[outIndex];Log.v("DecodeActivity", "We can't use this buffer but render it due to the API limit, " + buffer);// We use a very simple clock to keep the video FPS, or the video// playback will be too fastwhile (info.presentationTimeUs / 1000 > System.currentTimeMillis() - startMs) {try {sleep(10);} catch (InterruptedException e) {e.printStackTrace();break;}}decoder.releaseOutputBuffer(outIndex, true);break;}// All decoded frames have been rendered, we can stop playing nowif ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {Log.d("DecodeActivity", "OutputBuffer BUFFER_FLAG_END_OF_STREAM");break;}}decoder.stop();decoder.release();extractor.release();}}}
最後再奉上我修改過的代碼,增加了選擇文件的功能.
http://download.csdn.net/detail/shawnkong/6555857
最近从事手机iOS/Android直播、视频实时美颜方面的工作。
欢迎加群交流:496010189
更多相关文章
- Android(安卓)Accessibility(辅助功能) 学习
- Android中音视频合成的几种方案详析
- 浅谈新一代Android操作系统Android(安卓)L
- Xamarin android 使用RecyclerView结合SwipeRefreshLayout下拉刷
- Android中实现一键分享功能
- android试手——通讯录(附源码)
- 【Android】第5章(8) 图片库(Galery)
- 【Android游戏开发十六】Android(安卓)Gesture之【触摸屏手势识
- android 万能视频播放器