SurfaceView,VideoView,GlSurfaceView 中的Surface如何应用
JAVA层:
SurfaceView系列控件与其他View绘制存在很大的差别。有自己的Surface,其他View是共享一个Surface
1.最基本的SurfaceView
SurfaceView.java
public class SurfaceView extends View {
//绘图表面
final Surface mSurface = new Surface();
//wms中Session代表,跟ViewRootImpl中的一样
IWindowSession mSession;
MyWindow mWindow;
private void updateWindow(boolean force, boolean redrawNeeded) {
//创建一个surface
mSession.relayout(
mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
visible ? VISIBLE : GONE,
WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
mWinFrame, mOverscanInsets, mContentInsets,
mVisibleInsets, mConfiguration,
mNewSurface);
if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
//释放以前的,以前已经创建过,可见性改变了,隐藏
mSurfaceCreated = false;
SurfaceHolder.Callback.surfaceDestroyed(mSurfaceHolder);
}
//把mNewSurface的NativeObject拷贝到mSurface中
mSurface.transferFrom(mNewSurface);
if (!mSurfaceCreated ...) {//当新创建见surface时候回调,通知创建了新的surface了,可以在这个surface上干活了
SurfaceHolder.Callback.surfaceCreated(mSurfaceHolder);
}
if (sizeChanged ...) {//当大小,格式,等一些属性改变后,回调
SurfaceHolder.Callback.SurfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
}
}
SurfaceView的绘制的核心就是SurfaceHolder几个回调,
1.创建新的surface
2.surface属性改变
3.释放surface
private final SurfaceHolder mSurfaceHolder = new SurfaceHolder(){
//看名字就是跟ViewRootImpl中Surface用的一样了
public Canvas lockCanvas() {
return internalLockCanvas(null);
}
private final Canvas internalLockCanvas(Rect dirty) {
Canvas c = null;
c = mSurface.lockCanvas(dirty);
return null;
}
public void unlockCanvasAndPost(Canvas canvas) {
mSurface.unlockCanvasAndPost(canvas);
mSurfaceLock.unlock();
}
//这个就是SurfaceView创建的Surface,绘制都在这上面
public Surface getSurface() {
return mSurface;
}
}
SurfaceHolder的lock,unlock都是包转了一下Surface,都是在Surface基础上干活的。
封装的没有View其他类那么严实,获取到Surface后(通过回调SurfaceHolder.Callback),
可以在其他线程操作Surface了,不影响主线程的工作
SurfaceView的使用
SurfaceView.getHolder().addCallback(new Callback() {
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
通过holder可以获取到surface了,
可以启动一个线程直接直接用Surface或 Canvas
这个Canvas也是包装了Surface,需要lock,unlock
Canvas canvas = holder.lockCanvas();
holder.unlockCanvasAndPost(canvas);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
总结:SurfaceView就是吧Surface的创建,更改等封装好了,使用者只要操作SurfaceHolder就可以了,
通过注册回调
2. VideoView继承SurfaceView,看一下他的Surface怎么用的
class VideoView extends SurfaceView
private void initVideoView() {
getHolder().addCallback(mSHCallback); //注册一个自己处理的回调
getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback()
{
public void surfaceChanged(SurfaceHolder holder, int format,
int w, int h)
{ //播放
start();
}
public void surfaceCreated(SurfaceHolder holder)
{ //初始化video
openVideo();
}
}
//调用了mediaplyer的start
public void start() {
mMediaPlayer.start();
}
private void openVideo() {
mMediaPlayer = new MediaPlayer();
//把holder传给了mediaPlayer了
mMediaPlayer.setDisplay(mSurfaceHolder);
}
Mediaplayer.java
public class MediaPlayer{
static {
System.loadLibrary("media_jni");
native_init();
}
private native void _setVideoSurface(Surface surface);
public void setDisplay(SurfaceHolder sh) {
mSurfaceHolder = sh;
Surface surface= sh.getSurface();
//把surface取出来,设置给native层了
_setVideoSurface(surface);
}
这个很显然了Java层Surface包装了一个C++的Surface结构,底层直接用surface了,用ANativeWindow(GL)或者Producer
jni层,
android_media_MediaPlayer.cpp
{"
_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface},
static void android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface)
{
setVideoSurface(env, thiz, jsurface, true);
}
setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface, jboolean mediaPlayerMustBeAlive)
{
//获取c++层mediaplayer
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
//通过surface获取IGraphicBufferProducer
sp<IGraphicBufferProducer> new_st;
sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
new_st = surface->getIGraphicBufferProducer();
//把producer传给mediapalyer了,通过producer直接操作图像缓冲区了
mp->setVideoSurfaceTexture(new_st);
}
Mediaplayer不看了,日后再分析
3. GLSurfaceView 直接在app端使用openGl绘制的
GLSurfaceView.java
public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
直接都继承Holder.Callback了
构造函数中就init
private void init() {//很直接的注册回调
SurfaceHolder holder = getHolder();
holder.addCallback(this);
}
//看名字都直接转到gl绘制线程中了
public void surfaceCreated(SurfaceHolder holder) {
mGLThread.surfaceCreated();
}
public void surfaceDestroyed(SurfaceHolder holder) {
mGLThread.surfaceDestroyed();
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
mGLThread.onWindowResize(w, h);
}
static class GLThread extends Thread {
//都一样的逻辑,设置一个变量,马上通知notifyAll一下,肯定绘制线程等待则获取surface,然后再等待绘制线程干完活
public void surfaceCreated() {
//设置变量,通知更改
mHasSurface = true;
mFinishedCreatingEglSurface = false;
sGLThreadManager.notifyAll();
//等待响应完成
while (mWaitingForSurface&& !mFinishedCreatingEglSurface && !mExited) {
sGLThreadManager.wait();
}
}
}
//这个跟上个函数一样的
public void surfaceDestroyed() {
mHasSurface = false;
sGLThreadManager.notifyAll();
while((!mWaitingForSurface) && (!mExited)) {
sGLThreadManager.wait();
}
}
}
@Override
public void run() {
guardedRun();
}
private void guardedRun(){
while(true){
if (mEglHelper.createSurface()) {//创建完成eglsurface通知surfaceCreated等待的地方
synchronized(sGLThreadManager) {
mFinishedCreatingEglSurface = true;
sGLThreadManager.notifyAll();
}
}
{//调用外部设置的render开始绘制
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
view.mRenderer.onDrawFrame(gl);
}
}
//绘制完成提交后台缓冲区
int swapError = mEglHelper.swap();
}
}
mEglHelper怎么创建EGlSurface的
private static class EglHelper{
public void start() {//初始化egl环境
mEgl = (EGL10) EGLContext.getEGL(); //这个下面会用到
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
mEgl.eglInitialize(mEglDisplay, version)
mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig)
}
// view.getHolder()设置进去,创建EglSurface ,都是标准的用法
public boolean
createSurface() {
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
mEglSurface = view
.mEGLWindowSurfaceFactory.createWindowSurface(mEgl, mEglDisplay, mEglConfig, view.getHolder());
mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)
}
GlsurfaceView中
if (mEGLWindowSurfaceFactory == null) {
mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
}
//还是用的egl
private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {
public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
EGLConfig config, Object nativeWindow) {
EGLSurface result = null;
//又回到上面的egl了
result =
egl.eglCreateWindowSurface(display, config, nativeWindow, null);
}
//这是当前的egl
EGLContext.java
public abstract class EGLContext
{
private static final EGL EGL_INSTANCE =
new com.google.android.gles_jni.EGLImpl();
public static EGL getEGL() {
return EGL_INSTANCE;
}
}
EGLImpl.java
public class EGLImpl implements EGL10 {
private
native int _eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
//native_window支持好几个类型的
public EGLSurface eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list) {
Surface sur = null;
//如果是surfaceholder则获取出他的surface
} else if (native_window instanceof SurfaceHolder) {
SurfaceHolder holder = (SurfaceHolder)native_window;
sur = holder.getSurface();
}
//native创建 一个eglSurface(c++层)
int eglSurfaceId =
_eglCreateWindowSurface(display, config, sur, attrib_list);
//包装到java中
return new EGLSurfaceImpl( eglSurfaceId );
}
JNI层创建EglSurface
android_opengl_EGL14.cpp
static jobject
android_eglCreateWindowSurface
(JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject win, jintArray attrib_list_ref, jint offset) {
//通过java层Surface(win)获取c++层的ANativeWindow , 其实就是c++层的Surface
// class Surface: public ANativeWindow
android::sp<ANativeWindow> window=android::android_view_Surface_getNativeWindow(_env, win);
//调用c++层eglapi创建EglSurface
_returnValue = eglCreateWindowSurface( (EGLDisplay)dpy_native, (EGLConfig)config_native, (EGLNativeWindowType)window.get(), (EGLint *)attrib_list
);
总结:
为了提高绘制效率增加了SurfaceView系列,可以不在主线程中绘制。
基本的SurfaceView是把Surface包装成Canvas,提供了跟普通控件一样的绘制方式。
VideoView 把Surface(IGraphicBufferProducer)给了底层,底层直接进行绘制,上层就不需要关心绘制了
GlSurfaceView 把Surface(ANativeWindow) 通过Egl包装成EglSurface,上层通过OpenglEs进行3d绘制