android-使用Camera2+SurfaceView打开摄像头(二)

本文详细介绍了如何在Android应用中使用Camera2API配合SurfaceView创建一个可横竖屏自适应的CameraView控件,包括初始化、权限获取、生命周期管理和源码解析。同时提供了GitHubdemo链接供读者参考。
摘要由CSDN通过智能技术生成

android-使用Camera2+SurfaceView打开摄像头(二)


使用Camera2打开相机,所有逻辑封装在CameraView自定义控件,使用方式直接调用即可。
过时的Camera打开相机可以参考文章(android-使用Camera+SurfaceView打开摄像头(一))

1,效果图如下,支持横竖屏自适应

横屏
竖屏

2,使用步骤

2.1主布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:id="@+id/rl">
    <com.smart.camera2.CameraView
        android:layout_alignParentEnd="true"
        android:layout_width="108dp"
        android:id="@+id/camera_view"
        android:layout_alignParentBottom="true"
        android:layout_height="192dp"/>
</RelativeLayout>

2.2代码逻辑,初始化

camera_view = findViewById(R.id.camera_view);
        camera_view.initCamera();

2.3生命周期

   @Override
    protected void onPause() {
        super.onPause();
        camera_view.onPause();
    }

2.4权限的获取和处理

  // 处理权限请求的回调
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        camera_view.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

3,CamerView分析

CameraView继承SurfaceView,在SurfaceView的基础上进行的封装,源码如下:

/**
 * 本类的主要功能是 :   开启摄像头
 * <p>
 * 1,初始化,{@link CameraView#initCamera()}
 * 2,权限,{@link CameraView#onRequestPermissionsResult(int, String[], int[])}
 * 3,生命周期,{@link CameraView#onPause()}
 *
 * @author koko  2023/10/12 11:38
 */
public class CameraView extends SurfaceView {
    private static final String TAG = "CameraView";
    private static final int CAMERA_PERMISSION_REQUEST_CODE = 22;
    private CameraDevice mCameraDevice;
    private CameraCaptureSession mCaptureSession;
    private CaptureRequest.Builder mPreviewBuilder;
    public CameraView(Context context) {
        super(context);
        initView();
    }
    public CameraView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }
    public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }
    public CameraView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initView();
    }
    private void initView() {
        SurfaceHolder surfaceHolder = getHolder();
        surfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                Log.e(TAG, "surfaceCreated: ");
                // 初始化相机
                // 在需要使用相机的地方进行权限检查
                if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                    // 如果权限未被授予,则请求相机权限
                    ActivityCompat.requestPermissions((Activity) getContext(),
                            new String[]{Manifest.permission.CAMERA},
                            CAMERA_PERMISSION_REQUEST_CODE);
                } else {
                    // 如果权限已被授予,则直接打开相机
                    openCamera();
                }
            }
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                Log.e(TAG, "surfaceChanged: ");
                // 更新相机预览尺寸
                updatePreview();
            }
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                Log.e(TAG, "surfaceDestroyed: ");
                // 释放相机资源
                closeCamera();
            }
        });
    }
    /**
     * 初始化相机
     */
    public void initCamera() {
        changeCameraOri(getResources().getConfiguration().orientation);
    }
    // 处理权限请求的回调
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 相机权限已被授予,打开相机
                openCamera();
            } else {
                // 相机权限被拒绝,显示一个提示消息或执行其他操作
            }
        }
    }
    /**
     * 暂停
     */
    protected void onPause() {
        closeCamera();
    }
    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        changeCameraOri(newConfig.orientation);
    }
    /**
     * 横竖屏处理
     * @param orientation 横竖屏
     */
    private void changeCameraOri(int orientation) {
        float ratioScreen = 0.28f;
        float ratioCamera = 16 / 9f;
        //以窄边为标准
        //竖屏
        int screenWidthPortrait = (int) (com.smart.camera2.PhoneHelper.getScreenWidthReal(getContext()) * ratioScreen);
        int screenHeightPortrait = (int) (screenWidthPortrait * ratioCamera);
        //横屏
        int screenHeightLandScape = (int) (com.smart.camera2.PhoneHelper.getScreenHeightReal(getContext()) * ratioScreen);
        int screenWidthLandScape = (int) (screenHeightLandScape * ratioCamera);
        ViewGroup.LayoutParams layoutParams = getLayoutParams();
        if (layoutParams == null) {
            return;
        }
        switch (orientation) {
            case Configuration.ORIENTATION_PORTRAIT:
                Log.i(TAG, "onConfigurationChanged: " + "竖屏");
                // 竖屏1080-1920
                layoutParams.width = screenWidthPortrait;
                layoutParams.height = screenHeightPortrait;
                break;
            case Configuration.ORIENTATION_LANDSCAPE:
                Log.i(TAG, "onConfigurationChanged: " + "横屏");
                // 横屏1920-1080
                layoutParams.width = screenWidthLandScape;
                layoutParams.height = screenHeightLandScape;
                break;
        }
        setLayoutParams(layoutParams);
    }
    /**
     * 打开相机
     */
    private void openCamera() {
        CameraManager cameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
        getHolder().setFixedSize(9999, 9999);
        try {
            String cameraId = getFrontCameraId(cameraManager);
            if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {
                @Override
                public void onOpened(CameraDevice camera) {
                    mCameraDevice = camera;
                    Log.e(TAG, "onOpened: ");
                    createCaptureSession();
                }
                @Override
                public void onDisconnected(CameraDevice camera) {
                    Log.e(TAG, "onDisconnected: ");
                }
                @Override
                public void onError(CameraDevice camera, int error) {
                    Log.e(TAG, "onError: ");
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    /**
     * 关闭相机
     */
    private void closeCamera() {
        Log.e(TAG, "closeCamera: ");
        if (mCaptureSession != null) {
            mCaptureSession.close();
            mCaptureSession = null;
        }
        if (mCameraDevice != null) {
            mCameraDevice.close();
            mCameraDevice = null;
        }
    }
    /**
     * 刷新
     */
    private void updatePreview() {
        if (mCameraDevice == null) {
            return;
        }
        if (mCaptureSession == null) {
            return;
        }
        try {
            mCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), null, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    /**
     * 获取相机
     * @param cameraManager cameraManager
     * @return 相机id
     * @throws CameraAccessException 异常
     */
    private String getFrontCameraId(CameraManager cameraManager) throws CameraAccessException {
        String[] cameraIds = cameraManager.getCameraIdList();
        for (String cameraId : cameraIds) {
            CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
            Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
            if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
                return cameraId;
            }
        }
        return cameraIds[0];
    }
    /**
     * 创建CaptureSession
     */
    private void createCaptureSession() {
        try {
            SurfaceHolder surfaceHolder = getHolder();
            surfaceHolder.setFixedSize(getWidth(), getHeight());
            List<Surface> surfaces = new ArrayList<>();
            surfaces.add(surfaceHolder.getSurface());
            mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            mPreviewBuilder.addTarget(surfaceHolder.getSurface());
            mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(CameraCaptureSession session) {
                    mCaptureSession = session;
                    Log.e(TAG, "onConfigured: ");
                    updatePreview();
                }
                @Override
                public void onConfigureFailed(CameraCaptureSession session) {
                    // 配置会话失败
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
}

4,demo地址

附上github上demo地址,有需要的可以下载指正。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
如果在调用 android.hardware.Camera.open() 方法打开摄像头后,预览界面是灰色的,可能是因为相机预览的 SurfaceView 没有正确设置。以下是几个可能的解决方法: 1. 检查 SurfaceView 的大小是否正确,如果太小可能会导致预览出现问题。可以尝试在布局文件中设置 SurfaceView 的大小,或者在代码中设置: ```java surfaceView.getHolder().setFixedSize(width, height); ``` 2. 检查 SurfaceView 的类型是否正确。在 API level 11 以上的版本中,可以使用 SurfaceTexture 替代 SurfaceView,从而解决一些预览问题。 3. 检查权限是否正确获取。在 Android 6.0 及以上的版本中,需要在运行时动态申请相机权限。 ```java // 检查权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); } // 处理权限申请结果 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == REQUEST_CAMERA_PERMISSION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限已授予,可以打开相机 } else { // 权限被拒绝,无法打开相机 } } } ``` 4. 检查相机参数是否正确设置。可以尝试使用默认参数,或者根据需要设置相应的参数,例如预览尺寸、预览帧率等。 如果以上方法无法解决问题,可以尝试在论坛或社区中寻求帮助,或者查看 Android 官方文档和示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九千行代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值