Camera 预览之SurfaceView、TextureView、GLSurfaceView(一)


最近在作一个VR项目,使用到Camera功能从项目的不一样需求从最开始使用SurfaceView、到TextureView一直到GLSurfaceView。android

SurfaceView 官网的解释是:api

Provides a dedicated drawing surface embedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screenapp

简单说就是“SurfaceView是视图(View)的继承类,这个视图里内嵌了一个专门用于绘制的Surface。你能够控制这个Surface的格式和尺寸。Surfaceview控制这个Surface的绘制位置。”ide

接下蓝看下camera预览如何使用这个view,废话少说,直接上代码:函数

public class CameraSurfacePreview extends SurfaceView implements SurfaceHolder.Callback  {
    
    public static final String TAG = "CameraSurfacePreview";
    SurfaceHolder mSurfaceHolder;
    Context mContext;
    CameraWrapper mCameraWrapper; //Camera api的包装类

    @SuppressWarnings("deprecation")
    public CameraSurfacePreview(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mSurfaceHolder = getHolder();
        this.mContext = getContext();
        this.mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
        this.mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
        this.mSurfaceHolder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Log.i(TAG, "surfaceCreated...");  
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        Log.i(TAG, "surfaceChanged...");
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.i(TAG, "surfaceDestroyed...");
        CameraWrapper.getInstance().doStopCamera();
    }
    
    public SurfaceHolder getSurfaceHolder(){  
        return this.mSurfaceHolder;  
    }
}
CameraSurfacePreview继承至SurfaceView,实现SurfaceHolder.Callback,重点看下这个3个接口:布局

一、public void surfaceCreated(SurfaceHolder holder),Suface建立的时候调用this

二、public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) Surface界面有变化的时候调用spa

三、public void surfaceDestroyed(SurfaceHolder holder) Surface界面销毁的时候调用。orm

看下CameraSurfacePreview是如何使用的:xml

public class CameraSurfacePreviewActivity extends Activity implements CamOpenOverCallback{
    private static final String TAG = "CameraPreviewActivity";
    private CameraSurfacePreview cameraSurfacePreview;
    private float mPreviewRate = -1f;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "onCreate");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera_preview);
        initUI();
        initViewParams();
    }
    
    @Override  
    protected void onStart() {  
        Log.i(TAG, "onStart");
        super.onStart();  
        
        Thread openThread = new Thread() {
            @Override
            public void run() {
                CameraWrapper.getInstance().doOpenCamera(CameraSurfacePreviewActivity.this);
            }
        };
        openThread.start();
    }
    
    private void initUI() {
        cameraSurfacePreview = (CameraSurfacePreview) findViewById(R.id.camera_surfaceview);
    }
    
    private void initViewParams() {
        LayoutParams params = cameraSurfacePreview.getLayoutParams();  
        DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();  
        int screenWidth = displayMetrics.widthPixels;  
        int screenHeight = displayMetrics.heightPixels;
        params.width = screenWidth;  
        params.height = screenHeight;   
        this.mPreviewRate = (float)screenHeight / (float)screenWidth;
        cameraSurfacePreview.setLayoutParams(params);  
    }

    @Override
    public void cameraHasOpened() {
        SurfaceHolder holder = this.cameraSurfacePreview.getSurfaceHolder();
        CameraWrapper.getInstance().doStartPreview(holder, mPreviewRate);
    }
}
下面是布局文件代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" >
        

<com.camera.preview.CameraSurfacePreview
            android:id="@+id/camera_surfaceview"
            android:layout_width="0dip"  
            android:layout_height="0dip" />  
    </FrameLayout>

</RelativeLayout>


initUI获取到CameraSurfacePreview对象而后经过initViewParams设置SurfaceView的size,这里设置的全屏预览,也能够自定义预览size。咱们的SurfaceView这时已经准备好了,接下来就是调用preview去显示预览画面。看下doStartPreview函数:

    public void doStartPreview(SurfaceHolder holder, float previewRate) {
        Log.i(TAG, "doStartPreview...");
        if (mIsPreviewing) {
            this.mCamera.stopPreview();
            return;
        }

        try {
            this.mCamera.setPreviewDisplay(holder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        initCamera();
    }

经过cameraSurfacePreview.getSurfaceHolder(),获取到holder,而后调用camera接口setPreviewDisplay,为摄像头设置SurfaceHolder对象,设置成功后初始化camera参数,开始startpreview。

    private void initCamera() {
        if (this.mCamera != null) {
            this.mCameraParamters = this.mCamera.getParameters();
            this.mCameraParamters.setPreviewFormat(ImageFormat.YV12);
            this.mCameraParamters.setFlashMode("off");
            this.mCameraParamters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
            this.mCameraParamters.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);
//            this.mCameraParamters.setPreviewSize(IMAGE_WIDTH, IMAGE_HEIGHT);
            this.mCamera.setDisplayOrientation(90);
            mCameraPreviewCallback = new CameraPreviewCallback();
            mCamera.addCallbackBuffer(mImageCallbackBuffer);
            mCamera.setPreviewCallbackWithBuffer(mCameraPreviewCallback);
            List<String> focusModes = this.mCameraParamters.getSupportedFocusModes();
            if (focusModes.contains("continuous-video")) {
                this.mCameraParamters
                        .setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
            }
            this.mCamera.setParameters(this.mCameraParamters);
            this.mCamera.startPreview();
            
            this.mIsPreviewing = true;
        }
    }

至此咱们就能够在手机屏幕上看见预览画面如图示:


原创不易,若是您以为好,能够分享此公众号给你更多的人。