欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android Camera 预览镜像(使用 surfaceView 实现)

程序员文章站 2022-03-29 18:40:49
...

该方法是从opencv的java接口中学得
不知道为什么,最后显示出来的效果基本不能用(卡顿)
效果如下:
Android Camera 预览镜像(使用 surfaceView 实现)
Android Camera 预览镜像(使用 surfaceView 实现)

主要思想:
将Camera.PreviewCallback获得的 实时数据byte[] 数组,显示到Surfaceview上(双缓冲,子线程画图),这样就可以在即将预览的数据做镜像处理;

问题描述:
一般情况下 我们会直接使用

camera.setPreviewDisplay(this.getHolder());

将surfaceHolder 和 Camera的数据关联起来;但并没有提供这个接口直接实现镜像

Camera权限;activity注册等细节就不多说了,下面是

完整代码(1、CameraView ;2、Activity中使用 CameraView)

1、 重写 SurfaceView ,实现相关逻辑:

package com.yongyida.fastversion;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.io.IOException;

/**
 * @author Brandon on 2018/5/2
 **/
public class CameraView extends SurfaceView implements Camera.PreviewCallback, SurfaceHolder.Callback {

    private static final String TAG = CameraView.class.getSimpleName();

    public static final int SURFACE_WIDTH = 640;
    public static final int SURFACE_HIGH = 480;
    SurfaceHolder mSurfaceHolder;


    byte [] mData;
    byte[] buffer;

    Camera camera;

    public CameraView(Context context) {
        super(context);
        mSurfaceHolder = this.getHolder();
        mSurfaceHolder.addCallback(this);
        cacheBitmap = Bitmap.createBitmap(SURFACE_WIDTH, SURFACE_HIGH, Bitmap.Config.ARGB_8888);
        camera = Camera.open();
        Camera.Parameters params = camera.getParameters();
        int size = SURFACE_HIGH * SURFACE_WIDTH;
        size = size * ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8;
        buffer = new byte[size];
        camera.addCallbackBuffer(buffer);
        camera.setPreviewCallbackWithBuffer(this);
//        try {
//
//            camera.setPreviewDisplay(this.getHolder());
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
        camera.startPreview();
    }


    Bitmap cacheBitmap;
    int mScale = 1;
    //在子线程中绘制
    private void drawFrame(byte[] data) {

        cacheBitmap = TrackUtil.byte2Bitmap(data, SURFACE_WIDTH, SURFACE_HIGH);
        Canvas canvas = mSurfaceHolder.lockCanvas();
        canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
        Matrix m = new Matrix();
        m.postScale(-1, 1);
        cacheBitmap =  Bitmap.createBitmap(cacheBitmap, 0, 0, SURFACE_WIDTH, SURFACE_HIGH, m, true);
        canvas.drawBitmap(cacheBitmap, new Rect(0,0,cacheBitmap.getWidth(), cacheBitmap.getHeight()),
                new Rect((canvas.getWidth() - cacheBitmap.getWidth()) / 2,
                        (canvas.getHeight() - cacheBitmap.getHeight()) / 2,
                        (canvas.getWidth() - cacheBitmap.getWidth()) / 2 + cacheBitmap.getWidth(),
                        (canvas.getHeight() - cacheBitmap.getHeight()) / 2 + cacheBitmap.getHeight()), null);
        mSurfaceHolder.unlockCanvasAndPost(canvas);
    }


    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {

        synchronized (this) {

            if (data!=null)
            {
                mData = data;
                mCameraFrameReady = true;
                Log.e(TAG, "preview ");
            }

            this.notify();

        }
        camera.addCallbackBuffer(buffer);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Log.e(TAG, "onCreate");
        Thread thread = new Thread(new SurfaceRunnable());
        thread.start();
    }

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

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.e(TAG, "onDestory");
    }

    boolean mCameraFrameReady = false;
    boolean mStopThread = false;
    int mChainIdx = 0;

    private class SurfaceRunnable implements Runnable {

        @Override
        public void run() {
            do {
                Log.e(TAG,"cameraReady "   + mCameraFrameReady + " mStopThread " + mStopThread );
                boolean hasFrame = false;
                synchronized (CameraView.this) {
                    try {
                        while (!mCameraFrameReady && !mStopThread) {
                            CameraView.this.wait();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (mCameraFrameReady) {
                        mChainIdx = 1 - mChainIdx;
                        mCameraFrameReady = false;
                        hasFrame = true;
                    }
                }

                if (!mStopThread && hasFrame) {
                    if (mData!=null){

                        drawFrame(mData);
                        Log.e(TAG,"frame been draw " + mData.length);
                    }
                }
            } while (!mStopThread);
        }
    }

}

2、Activity中显示

package com.yongyida.fastversion;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import com.yongyida.yydrobotcv.R;

/**
 *   create by Brandon 2018/5/2
 *   make it can mirror frame
 */

public class CanMirrorCameraActivity extends AppCompatActivity {
    private static final String TAG = CanMirrorCameraActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e(TAG,"onCreate ");
        setContentView(new CameraView(this));
    }
}