Android 是时候使用Camera2的时候了(当Camera无界面不能预览)

Camera2的bug:

error1:
LegacyCameraDevice_nativeGetSurfaceId: Could not retrieve native Surface from surface.
error2:
getNativeWindow: Surface had no valid native window.
LegacyCameraDevice_nativeDetectSurfaceType: Could not retrieve native window from surface.

使用Camera一般都是用ImageReader来导出frame来进行处理,这两个错误都是由于Camera使用不当造成的。
反复测试发现,如果关闭Camera2之前没有stoprepeating,就会报上面的错误,果断,先stopReapting再关闭相机,示例代码如下(完整代码可以参考google官方示例代码的基础上,改进而来,下面有链接):

    public void stop() {

        try {
            mCameraCaptureSession.stopRepeating();
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        mBackgroundHandler.postDelayed(new Runnable() {//延迟关闭相机
            @Override
            public void run() {
                if (mCameraCaptureSession!=null){
                    mCameraCaptureSession.close();
                    mCameraCaptureSession = null;
                }
                if (mCameraDevice!=null)//注意关闭顺序,先
                    mCameraDevice.close();
                mCameraDevice = null;
                if (mImageReader!=null)//注意关闭顺序,后
                    mImageReader.close();
                mImageReader = null;

                isCameraOn = false;
                stopBackgroundThread();
            }

        },100);
    }

上面是开胃菜,下面继续
先听听我的故事:
最近做人脸识别,都是别人实现的库,直接调用就好了,结果被Camera坑。
Camera预览贞正常是前提,在android5.1上运行好好的,到Android6.0上就是预览不被回调(经过多方比较,就是少了一个设置setPreviewTexture(因为我应用不需要这个,没有界面),具体原因不详);使用Camera2正常所以才有了后面的事

通过Camera2,预览中把人脸框出来:opencv人脸框出来
先看看api文档:官方文档
最好的例子:官方sample地址
使用场景:
1、无界面预览(有surfaceview)
只取预览图片,对图片特征进行处理(如,人脸识别),不需要将图片显示出来
注意:a、图片的格式ImageFormat(如果用imagereader 请使用YUV_420_888)

2、有界面预览(无surfaceview)
需要预览图片,并将结果显示在surfaceview,textureview等控件上。

3、获取Camera支持的分辨率(我是遇到172*144,相机并不支持这个分辨率,我强行设置的结果是实际输出的分辨率是176*144,表现出来的bug就是图片显示出来“花了”)

       mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
        try {
            characteristics = mCameraManager.getCameraCharacteristics("0");
            listMap  = characteristics.get( SCALER_STREAM_CONFIGURATION_MAP);
            listSize = listMap.getOutputSizes(ImageFormat.JPEG);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

搜索“camera2”
出来很多
搜索结果

  • CaptureResult
  • CameraCaptureSession
  • CameraManager
  • CameraCharacteristics
  • CameraDevice
  • CaptureRequest
  • CameraCaptureSession.StateCallback

    Camera

import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;

import android.hardware.camera2.CaptureRequest;
import android.media.Image;
import android.media.ImageReader;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;

import java.nio.ByteBuffer;
import java.util.Arrays;

public class Camera2ActivityMine extends Activity implements TextureView.SurfaceTextureListener{
    private final static String TAG = Camera2ActivityMine.class.getSimpleName();
    TextureView mTexture;
    CameraManager cameraManager;
    CameraDevice mCameraDevice;
    Handler mainHandler;
    CaptureRequest.Builder captureRequestBuilder;
    ImageReader mImageReader;
    CameraCaptureSession mCameraCaptureSession;
    ImageView mImageView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_camera2_mine);
        mTexture = (TextureView) findViewById(R.id.mine_texture);
        mImageView = (ImageView)findViewById(R.id.mine_picture);
        mImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                takePicture();
            }
        });
        mTexture.setSurfaceTextureListener(this);
    }


    public void init(){
        cameraManager = (CameraManager)getSystemService(CAMERA_SERVICE);
        mainHandler = new Handler(getMainLooper());
        mImageReader = ImageReader.newInstance(mTexture.getWidth(),mTexture.getHeight(), ImageFormat.JPEG,2);
        mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader imageReader) {
                // 拿到拍照照片数据

                Image image = imageReader.acquireLatestImage();

                ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                byte[] bytes = new byte[buffer.remaining()];
                buffer.get(bytes);//由缓冲区存入字节数组
                final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                if (bitmap != null) {
                    mImageView.setImageBitmap(bitmap);
                }
                image.close();
            }
        }, mainHandler);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED){
            return;
        }
        try {
            cameraManager.openCamera(String.valueOf(CameraCharacteristics.LENS_FACING_FRONT), new CameraDevice.StateCallback() {
                @Override
                public void onOpened(@NonNull CameraDevice cameraDevice) {
                    mCameraDevice = cameraDevice;
                    afterOpenCamera();
                }

                @Override
                public void onDisconnected(@NonNull CameraDevice cameraDevice) {
                   mCameraDevice.close();
                }

                @Override
                public void onError(@NonNull CameraDevice cameraDevice, int i) {
                    Log.e(TAG,cameraDevice.toString()+i);
                }
            },mainHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
        init();
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {

    }
    //打开摄像头之后要做的事情
    public void afterOpenCamera(){
        SurfaceTexture surfaceTexture = mTexture.getSurfaceTexture();
        surfaceTexture.setDefaultBufferSize(mTexture.getWidth(),mTexture.getHeight());
        Surface surface = new Surface(surfaceTexture);
        try {
            captureRequestBuilder  = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

        captureRequestBuilder.addTarget(surface);
        try {
            mCameraDevice.createCaptureSession(Arrays.asList(surface,mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                    try {
                        mCameraCaptureSession = cameraCaptureSession;
                        cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), new CameraCaptureSession.CaptureCallback() {

                        },mainHandler);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {

                }
            }, mainHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }
    //拍照
    public void takePicture(){
        captureRequestBuilder.addTarget(mImageReader.getSurface());
        try {
            mCameraCaptureSession.capture(captureRequestBuilder.build(),null,mainHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }
}

layout

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

    <TextureView
        android:id="@+id/mine_texture"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent" />
    <ImageView
        android:layout_weight="1"
        android:id="@+id/mine_picture"
        android:layout_width="0dp"
        android:layout_height="match_parent" />
</LinearLayout>
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值