- A+
Android 音视频的代码好多都属于native层,Nupalyer和AweSomePlayer控制流程复杂, 学习难度比较大,作为app人员来说接触的机会又比较少,导致想学习知识的人门槛比较高。所以这边通过上层的控制,让大家慢慢熟悉播放器的原理。
因此将非常简单的视频播放器,拿出来练习,源码提供大家参考。
本app采用上层的MediaCodec 、 MediaExtractor 将视频频播放,播放显示器采用常用的SurfaceView。
步骤大概如下:
1、在xml中创建SurfaceView 获取并添加监听。
2、开启线程
3、将输入源给分离器MediaExtractor,MediaExtractor差分数据和解析出相关信息
4、通过分离器MediaExtractor分里的信息创建解码器MediaCodec
5、启动解码器,先将输入数据送入,后将解码数据输出。
6、数据输出后 MediaExtractor 自动渲染SurfaceView。
package com.eebbk.sampleplayer; import android.media.MediaCodec; import android.media.MediaExtractor; import android.media.MediaFormat; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.WindowManager; import java.nio.ByteBuffer; public class MainActivity1 extends AppCompatActivity { private SurfaceView mSurfaceView ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.content_main); mSurfaceView = (SurfaceView)findViewById(R.id.surface); mSurfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); mSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { Thread thread = new Thread() { @Override public void run() { //创建分离器 MediaExtractor extractor = new MediaExtractor(); try { extractor.setDataSource("/sdcard/H264_1080.mp4"); } catch (Exception e) { e.printStackTrace(); } //选择视频流 创建解码器 MediaCodec mediaCodec = null; try { int tackNum = extractor.getTrackCount(); for (int i = 0; i < tackNum; i++) { MediaFormat format = extractor.getTrackFormat(i); String mime = format.getString(MediaFormat.KEY_MIME); if (mime.startsWith("video/")) { mediaCodec = MediaCodec.createDecoderByType(mime);//创建解码器 mediaCodec.configure(format, mSurfaceView.getHolder().getSurface(), null, 0);//设置输出环境 extractor.selectTrack(i); } } } catch (Exception e) { e.printStackTrace(); } //启动解码器 mediaCodec.start(); ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers(); boolean inputEnd = false; boolean outputEnd = false; final long kTimeOutUs = 10000; MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); while (!outputEnd) { try { if (!inputEnd) {//输入到解码器 进行解码 int inputBufIndex = mediaCodec.dequeueInputBuffer(kTimeOutUs); if (inputBufIndex >= 0) { ByteBuffer dstBuf = inputBuffers[inputBufIndex]; int sampleSize = extractor.readSampleData(dstBuf, 0);//从分离器获取数据 if (sampleSize < 0) { mediaCodec.queueInputBuffer(inputBufIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); inputEnd = true; } else { long mediatime = extractor.getSampleTime(); mediaCodec.queueInputBuffer(inputBufIndex, 0, sampleSize, mediatime, inputEnd ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0); extractor.advance();//将数据提交给解码器 } } } //从解码器输出 int res = mediaCodec.dequeueOutputBuffer(info, kTimeOutUs); if (res >= 0) { int outputBufIndex = res; try { sleep(60);//多长时间刷新下界面 } catch (InterruptedException e) { e.printStackTrace(); break; } //告诉显示器释放并显示这个内容 mediaCodec会根据上面设置的surface 自动渲染,之所以不让用户自己写surface数据 是为了保证效率 mediaCodec.releaseOutputBuffer(outputBufIndex, true); } } catch (RuntimeException e) { e.printStackTrace(); } } if (mediaCodec != null) { mediaCodec.stop(); mediaCodec.release(); mediaCodec = null; } if (extractor != null) { extractor.release(); extractor = null; } } }; thread.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } }); } }
Android 音视频学习基础--1.1 音视频基础知识
Android 音视频学习基础--1.2 需要认识的一些工具
Android 音视频学习基础--1.3 主流的开源项目
Android 音视频学习基础--1.4 ffmpeg pcm输出
Android 音视频学习基础--1.5 ffmpeg yuv输出
Android 音视频学习基础--1.6 ffmpeg 简单视频播放器
Android 音视频学习基础--1.7 Android最简单的音频播放器
Android 音视频学习基础--1.8 Android最简单的音频播放器
Android 音视频学习基础--1.9 Android最简单的视频播放器
Android 音视频学习基础--1.10 Android自制简单音视频播放器
您可以选择一种方式赞助本站
支付宝扫一扫赞助
微信钱包扫描赞助
赏