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是任意定的一个标识符,回调的时候获取以区分来源。