android 摄像头Camera调用的几个小坑

Camera的使用教程很多了,就不写完整的了。
这里就记一下遇到的几个小坑。

1.在Surface建立后再调用摄像头。

这是个简单到傻的问题,然而一开始用的时候居然困扰了半天。明明有Camera对象却黑屏。简直要被自己蠢哭。
这里给SurfaceHolder设置回调就可以知道是否已创建了。

/**
     * 初始化surfaceView
     */
    private void initSurfaceView(){
        SurfaceView surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView);
        SurfaceHolder sfHolder=surfaceView.getHolder();
        // 设置分辨率
        sfHolder.setFixedSize(screenW, screenH);
        sfHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                Log.d("LOGCAT", "surfaceDestroyed");
            }

            //必须监听surfaceView的创建,创建完毕后才可以处理播放
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                Log.d("LOGCAT", "surfaceCreated");
                if(hasCamera) {
                    initCamera();//接收到Surface的回调后再启用摄像头。
                }else{
                    Toast.makeText(context, "没有摄像头,退散吧!", Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                Log.d("LOGCAT", "surfaceChanged");
            }
        });
    }
2.切换前后摄像头
camera.stopPreview();
camera.release();
if(camIdx==Camera.CameraInfo.CAMERA_FACING_FRONT){
    camIdx=Camera.CameraInfo.CAMERA_FACING_BACK;
}else{
    camIdx=Camera.CameraInfo.CAMERA_FACING_FRONT;
}
camera = Camera.open(camIdx);
camera.setPreviewDisplay(sfHolder);
camera.startPreview(); //开始预览
3.摄像头的释放

切换摄像头,或关闭应用的时候一定要释放。不然即使应用关闭了,摄像头还是可能处于使用状态。

@Override
    public void onDestroy() {
        Log.d("LOGCAT", "player onDestroy");
        camera.release();
        camera=null;
        super.onDestroy();
    }
4.检测摄像头是否存在
    private boolean checkCameraHardware(Context context) {
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
            return true;
        } else {
            return false;
        }
    }
5.录制视频
camera.unlock();
mRecorder = new MediaRecorder();
mRecorder.reset();
mRecorder.setCamera(camera);
// 设置从麦克风采集声音(或来自录像机的声音AudioSource.CAMCORDER)
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
// 设置从摄像头采集图像
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
//录制角度
//mRecorder.setOrientationHint(90);
// 设置视频文件的输出格式
// 必须在设置声音编码格式、图像编码格式之前设置
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
// 设置声音编码的格式
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
// 设置图像编码的格式
mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
// 设置图像的码率
mRecorder.setVideoEncodingBitRate(5*screenW*screenH);
mRecorder.setVideoSize(screenW, screenH);
// 每秒24帧
mRecorder.setVideoFrameRate(24);
mRecorder.setOutputFile(videoFile.getAbsolutePath());
// 指定使用SurfaceView来预览视频
mRecorder.setPreviewDisplay(sfHolder.getSurface());
mRecorder.prepare();
// 开始录制
mRecorder.start();

需要特别注意的是,录制前必须

Camera.unlock();

以及

mRecorder.setCamera(camera);

不然会报错。

或者,录制之前释放掉Camere

camera.release();
camera=null;

那MediaRecorder.start()时会打开默认摄像头录制。

6. MediaRecorder: start failed: -19错误

这个问题通常是由setVideoFrameRate方法引起的。不支持就去掉吧。
还有setVideoSize方法,如果设置的分辨率是不支持的,也会报错。

7. camera setParameters failed错误

这个是由于设置的分辨率不被当前摄像头支持造成的。可以使用默认,或者通过

Camera.Parameters parameters  = mCamera.getParameters();  
List<Camera.Size> prviewSizeList = parameter.getSupportedPreviewSizes();
List<Camera.Size> videoSizeList = parameter.getSupportedVideoSizes();

获取支持的分辨率进行设置。

8. 6.0及以上系统权限问题

6.0开始有了运行中请求权限的设置,所以要调用摄像头的话除了需要在AndroidManifest中设置权限<uses-permission android:name="android.permission.CAMERA" />外,还要在调用的过程中请求权限:

if (Build.VERSION.SDK_INT >= 24) {
                requestPermissions(new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, PHOTO_REQUEST_TAKEPHOTO);
            } 

这里的PHOTO_REQUEST_TAKEPHOTO是任意定的一个标识符,回调的时候获取以区分来源。

    原文作者:书柜里的松鼠
    原文地址: https://www.jianshu.com/p/7bebb228da47
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞