Android相机不使用SurfaceView预览,使用ImageView预览

刚接触Android三个月,以下内容可能存在错误,欢迎指正。

以下在Android5. 1 ,API22机器下调试的。

之前参考网上的资源,很多使用的surfaceView控件预览相机,所以就用的是surfaceview。但是我的需求不仅是预览,还需要经常性的拍照,然后在代码里处理图片,而takePicture期间有一段的卡顿时间(拍照的过程)。

后来,硬件工程师让做一个关于双摄的app。要求是能同时在四个地方预览同一个摄像头,并能切换两个摄像头像这样(1代表第一个摄像头,2代表第二个摄像头,画面填充了ImageView控件,有拉伸现象)


发现提到了一个Camera的接口: Camera.PreviewCallback。说明是这样的: Camera.PreviewCallback Called as preview frames are displayed. This callback is invoked on the event thread open(int) was called from.

接口里面有一个回调方法:onPreviewFrame(byte[] data, Camera camera),在预览帧显示的时候调用。

然后在这个方法里实现对拍到的内容data转换成bitmap就行了。然后把这个bitmap显示在需要的ImageView上就行了。目测来看效果还阔以。具体源码角度我没有分析(还没有那个水平),待后期分析。

注意:不能把data简单的转换成btmap,否则得到的bitmap为null。这是因为data格式是YUV的,需要进行数据转换。

下面的代码是另起一个类,实现PreviewCallback接口:只需要看这部分代码就行

public class CameraPreviewCallback implements Camera.PreviewCallback {
    private ImageView imageView;

    public CameraPreviewCallback(ImageView imageView) {
        this.imageView = imageView;
    }

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        //格式的转换
        Camera.Size previewSize = camera.getParameters().getPreviewSize();
        YuvImage image = new YuvImage(data, ImageFormat.NV21, previewSize.width, previewSize.height, null);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        image.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 80, stream);
        Constant.FACE_BITMAP = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());

        //在指定的imageView上显示预览的图片
        imageView.setImageBitmap(Constant.FACE_BITMAP);
     
    }
}

MainActivity代码:主要是不需要写surfaceHolder等,只设置了下预览回调。

(相机预览只是实现了。但相机的正确处理还没有完全弄明白,可能写的有很多不足的地方)

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ImageView center = null;

    private ImageView right;
    private ImageView left;
    private ImageView up;
    private ImageView down;

    // byte[] buffer=new byte[];

    private Boolean isPause = false;
    private Boolean isSwitch = false;


    private Camera mCamera1;
    private Camera mCamera2;

    private TextView tip_left; //切换摄像头
    private TextView tip_right; //暂停/开始预览

    private long firstTime = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        findViews();
        setListener();
        init();
        //initSurface();
        Log.e("*************", "onCreate调用了");
    }


    @Override
    protected void onStart() {
        Log.e("*************", "onStart调用了");
        super.onStart();
    }


    private void setListener() {
        tip_left.setOnClickListener(this);
        tip_right.setOnClickListener(this);
    }

    private void findViews() {
        center = findViewById(R.id.center);


        left = findViewById(R.id.left);
        up = findViewById(R.id.up);
        down = findViewById(R.id.down);
        right = findViewById(R.id.right);

        tip_left = findViewById(R.id.tip_left);
        tip_right = findViewById(R.id.tip_right);
    }

    //拍照出错的回调
    Camera.ErrorCallback callback = new Camera.ErrorCallback() {
        @Override
        public void onError(int i, Camera camera) {
            switch (i) {
                case Camera.CAMERA_ERROR_SERVER_DIED:
                    Log.d("SERVER_DIED", "CAMERA_ERROR_SERVER_DIED");
                    break;
                case Camera.CAMERA_ERROR_UNKNOWN:
                    Log.d("UNKNOWN", "CAMERA_ERROR_UNKNOWN");
                    break;
            }
        }
    };

    private void init() {
        initCamera();  //开启摄像头
        mCamera1.setPreviewCallback(new MyPreviewCallback(new ImageView[]{right, left, up, down}));  
        mCamera2.setPreviewCallback(new MyPreviewCallback(new ImageView[]{center}));
        mCamera1.setErrorCallback(callback);
        mCamera2.setErrorCallback(callback);
    //设置第一次打开app时,中间的ImageView预览摄像头1的内容

    }



    //初始化摄像头
    private void initCamera() {
        //如果存在摄像头
        if (checkCameraHardware(getApplicationContext())) {
            //获取摄像头(首选前置,无前置选后置)
            try {
                if (openFacingFrontCamera()) {
                    Log.e("Demo", "openCameraSuccess");
                } else {
                    Log.e("Demo", "openCameraFailed");
                }
            } catch (Exception e) {
                Log.e("Demo", "autoFocus/openFacingFrontCamera函数异常:");
            }
        }
    }
//也有用open(id)打开摄像头的,这里只是参考下。
    //得到后置摄像头
    private boolean openFacingFrontCamera() {
        //尝试开启前置摄像头,因为我用的是两个后摄。下面这个for其实没有执行
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        for (int camIdx = 0, cameraCount = Camera.getNumberOfCameras(); camIdx < cameraCount; camIdx++) {
            Camera.getCameraInfo(camIdx, cameraInfo);
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                try {
                    if (camIdx == 0)
                        mCamera1 = Camera.open(camIdx);
                    //这两个摄像头是后置摄像头
                    if (camIdx == 1)
                        mCamera2 = Camera.open(camIdx);
                } catch (RuntimeException e) {
                    return false;
                }
            }
        }

        //如果开启前置失败(无前置)则开启后置
        if (mCamera1 == null) {
            for (int camIdx = 0, cameraCount = Camera.getNumberOfCameras(); camIdx < cameraCount; camIdx++) {
                Camera.getCameraInfo(camIdx, cameraInfo);
                if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                    try {
                        if (camIdx == 0)
                            mCamera1 = Camera.open(camIdx);
                        //这两个摄像头是后置摄像头
                        if (camIdx == 1)
                            mCamera2 = Camera.open(camIdx);
                    } catch (RuntimeException e) {
                        return false;
                    }
                }
            }
        }
        try {
            mCamera1.startPreview();
            mCamera2.startPreview();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    //判断是否存在摄像头
    private boolean checkCameraHardware(Context context) {
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
            // 设备存在摄像头
            return true;
        } else {
            // 设备不存在摄像头
            Toast.makeText(context, "未检测到摄像头", Toast.LENGTH_SHORT).show();
            return false;
        }
    }

    //对焦并拍照
    private void autoFocus() {
        mCamera1.startPreview();
        //自动对焦
        mCamera1.autoFocus(myAutoFocus);
        mCamera2.startPreview();
        //自动对焦
        mCamera2.autoFocus(myAutoFocus);
    }

    //自动对焦回调函数(空)
    private Camera.AutoFocusCallback myAutoFocus = new Camera.AutoFocusCallback() {
        @Override
        public void onAutoFocus(boolean success, Camera camera) {
        }
    };

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.tip_left:  //控制预览画面展示到不同的控件上
                mCamera1.startPreview();
                mCamera2.startPreview();
                if (!isSwitch) { //isSwitch==false   camera1->中间
                    mCamera1.setPreviewCallback(new MyPreviewCallback(new ImageView[]{center}));
                    mCamera2.setPreviewCallback(new MyPreviewCallback(new ImageView[]{right, left, up, down}));
                } else {  //isSwitch==true    camera1->四周
                    mCamera1.setPreviewCallback(new MyPreviewCallback(new ImageView[]{right, left, up, down}));
                    mCamera2.setPreviewCallback(new MyPreviewCallback(new ImageView[]{center}));
                }


                isSwitch = !isSwitch;

                //以下if作用是解决:当处于暂停状态时,点击切换画面时,
                if (isPause) {  //本身画面当处于暂停状态时
                    tip_right.setText("点击暂停预览");
                }
                isPause = !isPause;
                break;

            case R.id.tip_right:  //控制预览暂停/开始
                if (!isPause) {
                    tip_right.setText("点击开始预览");
                    mCamera1.stopPreview();
                    mCamera2.stopPreview();
                } else {
                    if (isSwitch) {
                        mCamera1.setPreviewCallback(new MyPreviewCallback(new ImageView[]{center}));
                        mCamera2.setPreviewCallback(new MyPreviewCallback(new ImageView[]{right, left, up, down}));
                    } else {
                        mCamera1.setPreviewCallback(new MyPreviewCallback(new ImageView[]{right, left, up, down}));
                        mCamera2.setPreviewCallback(new MyPreviewCallback(new ImageView[]{center}));
                    }
                    tip_right.setText("点击暂停预览");
                    mCamera1.startPreview();
                    mCamera2.startPreview();
                }
                isPause = !isPause;
                break;
        }
    }


    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
            if (System.currentTimeMillis() - firstTime > 2000) {
                Toast.makeText(this, "再按一次退出程序", Toast.LENGTH_SHORT).show();
                firstTime = System.currentTimeMillis();
                return true;
            } else {
                if (mCamera1 != null) {
                    mCamera1.stopPreview();
                    mCamera1.unlock();
                    mCamera1.release();
                    mCamera1 = null;
                }
                if (mCamera2 != null) {
                    mCamera2.stopPreview();
                    mCamera2.unlock();
                    mCamera2.release();
                    mCamera2 = null;
                }
                //finish();
                System.exit(0);
            }
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mCamera1 != null) {
            mCamera1.stopPreview();
            mCamera1.unlock();
            mCamera1.release();
            mCamera1 = null;
        }
        if (mCamera2 != null) {
            mCamera2.stopPreview();
            mCamera2.unlock();
            mCamera2.release();
            mCamera2 = null;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_31371757/article/details/83108726