android 攝像頭Camera調(diào)用的幾個(gè)小坑

Camera的使用教程很多了,就不寫完整的了。
這里就記一下遇到的幾個(gè)小坑。

1.在Surface建立后再調(diào)用攝像頭。

這是個(gè)簡單到傻的問題,然而一開始用的時(shí)候居然困擾了半天。明明有Camera對(duì)象卻黑屏。簡直要被自己蠢哭。
這里給SurfaceHolder設(shè)置回調(diào)就可以知道是否已創(chuàng)建了。

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

            //必須監(jiān)聽surfaceView的創(chuàng)建,創(chuàng)建完畢后才可以處理播放
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                Log.d("LOGCAT", "surfaceCreated");
                if(hasCamera) {
                    initCamera();//接收到Surface的回調(diào)后再啟用攝像頭。
                }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(); //開始預(yù)覽
3.攝像頭的釋放

切換攝像頭,或關(guān)閉應(yīng)用的時(shí)候一定要釋放。不然即使應(yīng)用關(guān)閉了,攝像頭還是可能處于使用狀態(tài)。

@Override
    public void onDestroy() {
        Log.d("LOGCAT", "player onDestroy");
        camera.release();
        camera=null;
        super.onDestroy();
    }
4.檢測(cè)攝像頭是否存在
    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);
// 設(shè)置從麥克風(fēng)采集聲音(或來自錄像機(jī)的聲音AudioSource.CAMCORDER)
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
// 設(shè)置從攝像頭采集圖像
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
//錄制角度
//mRecorder.setOrientationHint(90);
// 設(shè)置視頻文件的輸出格式
// 必須在設(shè)置聲音編碼格式、圖像編碼格式之前設(shè)置
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
// 設(shè)置聲音編碼的格式
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
// 設(shè)置圖像編碼的格式
mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
// 設(shè)置圖像的碼率
mRecorder.setVideoEncodingBitRate(5*screenW*screenH);
mRecorder.setVideoSize(screenW, screenH);
// 每秒24幀
mRecorder.setVideoFrameRate(24);
mRecorder.setOutputFile(videoFile.getAbsolutePath());
// 指定使用SurfaceView來預(yù)覽視頻
mRecorder.setPreviewDisplay(sfHolder.getSurface());
mRecorder.prepare();
// 開始錄制
mRecorder.start();

需要特別注意的是,錄制前必須

Camera.unlock();

以及

mRecorder.setCamera(camera);

不然會(huì)報(bào)錯(cuò)。

或者,錄制之前釋放掉Camere

camera.release();
camera=null;

那MediaRecorder.start()時(shí)會(huì)打開默認(rèn)攝像頭錄制。

6. MediaRecorder: start failed: -19錯(cuò)誤

這個(gè)問題通常是由setVideoFrameRate方法引起的。不支持就去掉吧。
還有setVideoSize方法,如果設(shè)置的分辨率是不支持的,也會(huì)報(bào)錯(cuò)。

7. camera setParameters failed錯(cuò)誤

這個(gè)是由于設(shè)置的分辨率不被當(dāng)前攝像頭支持造成的??梢允褂媚J(rèn),或者通過

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

獲取支持的分辨率進(jìn)行設(shè)置。

8. 6.0及以上系統(tǒng)權(quán)限問題

6.0開始有了運(yùn)行中請(qǐng)求權(quán)限的設(shè)置,所以要調(diào)用攝像頭的話除了需要在AndroidManifest中設(shè)置權(quán)限<uses-permission android:name="android.permission.CAMERA" />外,還要在調(diào)用的過程中請(qǐng)求權(quán)限:

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

這里的PHOTO_REQUEST_TAKEPHOTO是任意定的一個(gè)標(biāo)識(shí)符,回調(diào)的時(shí)候獲取以區(qū)分來源。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容