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ū)分來源。