技术的学习关键点
是什么?思路。
而我这里分享一个学习的经典路线,先厘清总框架,找到思路,然后再逐步击破。
这里关于音视频的就是:
总体分为几部分:
1 绘制
2 编解码格式
3 Android 平台的 FFmpeg 开源移植
4 应用场景
概括成一句话就是,视频如果解析出来,视频如何显示画面,声音怎么播放。
然后这里面的
市场机会
在哪里?
1 支持格式扩展
2 特效画面 gpuimage 框架
3 倍速播放
4 格式转化,自动制作工具
5 移植到嵌入式板子
那么我们第二版就来完成这个任务,首先我们先说一个,就是绘制。
绘制流程(图)
市面上讲解绘制,直接上来一堆内容,我这里先忽略掉细节,我们来说下简单的绘制代表什
么。
我们自己画东西的时候,需要画笔,画板(画布),然后有各种涂料。
在安卓里面,这里画板就是 Canvas ,而画笔就是对应的各种 API。
那么接下来我们说下,这 Canvas 的简单逻辑,让你一目了然。
我们画的东西,叫做一个内存,叫做 FrameBuffer,这个有时候是双缓存。
然后我们每个 Activity 创建的时候,都会申请一个 Surface ,这个被叫做 平面,然后这个对
应到一个 Buffer,这一组由 Activity 或者是系统对话框,系统中使用 WMS.addView 添加进来
的 Buffer 组合。
依据层叠关系放置,而 SurfaceFlinger 这边会完成所谓的合并,绘制,推送到真正的屏幕
FrameBuffer,完成显示。
我来给大家发画一张图,大家大致看一下,形成印象。
我们这里记住的点就是:我们 View 绘制是在一个 canvas 里面,而这个里面是一个 surface,
这个说白了就是一个内存区域,用 surface 包裹方便操作。
于是我们来进行调试,看下流程,以及记住几个文件,方便我们学习。
我们调试一个 TextView 的 OnDraw 方法,然后可以看到一个信息,ViewRootImpl.java
这里分享的调试技巧,通过堆栈,能够非常高效的定位到代码,找到流程,参考这个很快就
能把绘制流程分析完。
这个绘制流程,是普通的 surface ,对应上层为 canvas 的绘制。一般我们不会在游戏使用,
原因很简单,这个主线程(UI)线程,在游戏引擎中,游戏频繁更新,绘制很容易耗时,所
以需要单独的线程。
而安卓这里提供了 surfaceView 以及 textureView,这里我们看下 surfaceView 的使用:
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surface);
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
if (surfaceHolder == null) {
return;} Paint paint = new Paint(); paint.setAntiAlias(true); paint.setStyle(Paint.Style.STROKE); Canvas canvas = surfaceHolder.lockCanvas(); // 获取 canvas //canvas.drawBitmap(bitmap, 0, 0, paint); //执行绘制操作 surfaceHolder.unlockCanvasAndPost(canvas); // 释放并显示 } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { } 我们看个常用的使用方式: //内部类 class MyView extends SurfaceView implements SurfaceHolder.Callback{ SurfaceHolder holder; public MyView(Context context) { super(context); holder = this.getHolder();//获取 holder holder.addCallback(this); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { new Thread(new MyThread()).start(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { } //内部类的内部类 class MyThread implements Runnable{
@Override
public void run() {
Canvas canvas = holder.lockCanvas(null);//获取画布
Paint mPaint = new Paint();
mPaint.setColor(Color.BLUE);
canvas.drawRect(new RectF(40,60,80,80), mPaint);
holder.unlockCanvasAndPost(canvas);//解锁画布,提交画好的图像
}
}
}
从这里流程可以看到,关键点在于这个 holder 。这里整体的流程就是:
使用
holder = this.getHolder();//获取 holder
holder.addCallback(this);
完成获取 holder ,以及注册回调。
然后在 surfaceCreated 里面,完成创建线程,随后在线程里面,获取 canvas,绘制,然后释
放。
在游戏引擎里面,这里就是自己的一个线程,调入游戏引擎中去,完成游戏引擎的核心入口。
我们在学习的时候,一定要找这里的关键方法,也就是所谓的线索。在 surfaceView 的开发
中,这个 holder 就是引子。
下来我们说下,用 surfaceView+OpenGL 如何操作。