当我们自定义相机时,常常使用
Camera
对象完成拍照流程,本文的重点在于研究Camera
各个方法的作用。
[方法一]
获取Camera对象
Camera mCamera = Camera.open();
[方法二]
拍照
public final void takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback postview, PictureCallback jpeg)
使用方法如下:
mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
}
});
它有一个回调,拍完照片之后会执行onPictureTaken
回调方法,data
参数为图片的字节数组。
[方法三]
自动聚焦
自动聚焦的监听必须放在启动预览界面(mCamera.startPreview())
之后,否则部分手机会崩溃。
实现代码如下:
//自动获取焦点
mCamera.autoFocus(autoFocusCallback );
private Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
}
};
此时发现,自动聚焦的回调方法始终只执行一次,那么怎么做才能无限聚焦呢?只要在自动聚焦的回调方法中添加两句代码即可。
private Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
mCamera.cancelAutoFocus();
camera.autoFocus(autoFocusCallback);
}
};
与设置自动聚焦相比,还有一个方法取消自动聚焦cancelAutoFocus
。
以上是实现自动聚焦的其中一个方法,当然还有其它方法,文章下面会介绍。
[方法四]
锁定、解锁、重连
//锁定摄像机硬件资源
mCamera.lock();
//解锁摄像机硬件资源
mCamera.unlock();
//重连
mCamera.reconnect();
为了防止相机被其它资源利用,相机默认是锁定状态。当其它资源想要利用相机时,必须解锁和重连后才能继续使用相机服务。
如果仅仅使用拍照,您可能不需要使用这三个方法,当使用MediaRecorder
录制时会使用这三个方法获取相机服务。
[方法五]
设置预览方向
mCamera.setDisplayOrientation(90);
预览方向默认是横屏的,所以这里要调整一下预览方向。
[方法六]
设置预览界面
目前拍照涉及到的预览界面主要有两种:TextureView
和SurfaceView
mCamera.setPreviewDisplay(SurfaceHolder);
mCamera.setPreviewTexture(SurfaceTexture);
有关TextureView
和SurfaceView
会在第四篇
和第五篇
介绍。
[方法七]
设置预览监听
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
}
});
这个监听最强大的地方在于可以不停的返回一帧画面的图像数据
,可以利用OpenGL对图片进行处理。
设置监听的方法还有一个,如下:
mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
}
});
这个方法应该是和mCamera.addCallbackBuffer(byte[] callbackBuffer)
一起使用,mCamera.addCallbackBuffer(byte[] callbackBuffer)
是向缓存队列中添加一个预览帧。
这两种监听的工作方式差不多,他们都会不停的回调当前预览帧,那么如果获取拍照或者触发聚焦时的预览帧的话,就会使用以下预览监听方案:
mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
}
});
如果处于预览状态,那么会立即回调一个预览帧。
当触发聚焦时,此时的画面最为清晰,可以使用这个监听获取当前预览帧,根据回调返回的字节数组来处理图像。
[方法八]
开始预览和停止预览
当Camera绑定预览界面后,Camera就可以启动预览界面和停止预览界面。
//启动预览界面
mCamera.startPreview();
//停止预览界面
mCamera.stopPreview();
只有启动预览界面之后,预览监听才会收到回调。
[方法九]
平滑缩放
有些手机的相机自带缩放功能,当我们用双指缩放预览界面时会触发平滑缩放监听。当然,一些手机不支持平滑缩放功能。
监听代码如下:
mCamera.setZoomChangeListener(new Camera.OnZoomChangeListener() {
@Override
public void onZoomChange(int zoomValue, boolean stopped, Camera camera) {
}
});
zoomValue
为当前缩放因子,stopped
表示当前缩放是否结束,如果为false则表示缩放正在进行,如果为true表示缩放结束。
调用startSmoothZoom
方法后开始启动平滑缩放功能,代码如下:
Camera.Parameters parameters = mCamera.getParameters();
if(parameters.isSmoothZoomSupported()){
mCamera.startSmoothZoom(1);
}
startSmoothZoom
方法传递一个数值,这个数值就是缩放因子,它的取值范围是:[0,parameters.getMaxZoom()]
,取值不可超过这个范围,否则报错,在设置缩放因子之前必须先判断手机是否支持平滑缩放,否则设置无效或者异常,设置缩放因子后,缩放监听开始执行。假设当前缩放因子为0,那么执行以下语句:
if(parameters.isSmoothZoomSupported()){
mCamera.startSmoothZoom(12);
}
那么,它不会直接从0变成12,设置缩放因子需要消耗一定的时间,它的变化过程如下:
- 当从0变成1时,触发一次监听回调,zoomValue=1,stopped=false
- 当从1变成2时,触发一次监听回调,zoomValue=2,stopped=false
- 当从2变成3时,触发一次监听回调,zoomValue=3,stopped=false
- 当从3变成4时,触发一次监听回调,zoomValue=4,stopped=false
- 当从4变成5时,触发一次监听回调,zoomValue=5,stopped=false
- 当从5变成6时,触发一次监听回调,zoomValue=6,stopped=false
- 当从6变成7时,触发一次监听回调,zoomValue=7,stopped=false
- 当从7变成8时,触发一次监听回调,zoomValue=8,stopped=false
- 当从8变成9时,触发一次监听回调,zoomValue=9,stopped=false
- 当从9变成10时,触发一次监听回调,zoomValue=10,stopped=false
- 当从10变成11时,触发一次监听回调,zoomValue=11,stopped=false
- 当从11变成12时,触发一次监听回调,zoomValue=12,stopped=true
也就是说,平滑缩放的监听回调执行了12次。
在这个过程中,可以提前停止缩放,只要执行这个方法即可
mCamera.stopSmoothZoom();
startSmoothZoom
和stopSmoothZoom
这两个方法必须在启动预览界面(mCamera.startPreview())
之后执行,否则会报错。
[方法十]
相机异常监听
mCamera.setErrorCallback(new Camera.ErrorCallback() {
@Override
public void onError(int error, Camera camera) {
switch (error){
case Camera.CAMERA_ERROR_UNKNOWN:
System.out.println("相机未知错误");
break;
case Camera.CAMERA_ERROR_EVICTED:
System.out.println("相机已断开连接");
break;
case Camera.CAMERA_ERROR_SERVER_DIED:
System.out.println("媒体服务器死机");
break;
default:
System.out.println("未知异常error:"+error);
break;
}
}
});
可以监听相机使用过程之的错误。
[方法十一]
设置拍照后,存入本地图片的格式
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPictureFormat(ImageFormat.JPEG);
mCamera.setParameters(parameters);
setPictureFormat
可以设置图片格式。
[方法十二]
解决输出图片旋转90度问题
Camera.Parameters parameters = mCamera.getParameters();
parameters.setRotation(90);
mCamera.setParameters(parameters);
[方法十三]
设置预览大小和图片大小
设置预览大小就是设置预览界面的显示图像的分辨率
Camera.Parameters parameters = mCamera.getParameters();
Camera.Size previewSize = getCameraSize(parameters.getSupportedPreviewSizes(), width, height);
parameters.setPreviewSize(previewSize.width, previewSize.height);
mCamera.setParameters(parameters);
设置图片大小就是设置保存到本地的图片分辨率
Camera.Parameters parameters = mCamera.getParameters();
Camera.Size pictureSize = getCameraSize(parameters.getSupportedPictureSizes(), width, height);
parameters.setPictureSize(pictureSize.width, pictureSize.height);
mCamera.setParameters(parameters);
其中getCameraSize
方法就是筛选出最适合的分辨率。
/**
* 获取最合适的Size
* @param sizeList
* @param width
* @param height
* @return
*/
private Camera.Size getCameraSize(List sizeList, int width, int height){
Camera.Size tempSize = null;
float aspectRatio = height * 1.0f / width;//求出预期横宽比
float offset = aspectRatio;//预期横宽比和实际横宽比误差
for(Camera.Size size : sizeList){
if(size.width < height || size.height < width){
continue;
}
//误差最小值
if(Math.abs(aspectRatio - size.width * 1.0f / size.height) < offset){
offset = Math.abs(aspectRatio - size.width * 1.0f / size.height);
tempSize = size;
}
}
if(tempSize == null){
tempSize = sizeList.get(0);
}
return tempSize;
}
[方法十四]
聚焦模式
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mCamera.setParameters(parameters);
调用setFocusMode
方法可以设置聚焦模式,聚焦模式有很多:
FOCUS_MODE_AUTO
、FOCUS_MODE_INFINITY
、FOCUS_MODE_MACRO
、FOCUS_MODE_FIXED
、FOCUS_MODE_EDOF
、FOCUS_MODE_CONTINUOUS_VIDEO
、FOCUS_MODE_CONTINUOUS_PICTURE
,这些模式用到的有两种模式,分别是:FOCUS_MODE_CONTINUOUS_PICTURE
和FOCUS_MODE_CONTINUOUS_VIDEO
。
这两个参数最大的作用是可以不断的触发聚焦,并且可以接收到监听的回调。
mCamera.setAutoFocusMoveCallback(new Camera.AutoFocusMoveCallback() {
@Override
public void onAutoFocusMoving(boolean start, Camera camera) {
}
});
监听setAutoFocusMoveCallback
与聚焦模式结合使用可以实现随时聚焦功能,类似于[方法三]
中说到的自动聚焦,但是autoFocus
不可以和setAutoFocusMoveCallback
混用,有些手机混用是没有问题的,但是有些手机一旦触发了autoFocus
监听,那么setAutoFocusMoveCallback
监听就会中断,所以这两个触发聚焦功能只能选择一个。
代码实现如下:
mCamera.setAutoFocusMoveCallback(new Camera.AutoFocusMoveCallback() {
@Override
public void onAutoFocusMoving(boolean start, Camera camera) {
}
});
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
//或者
//parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
[方法十五]
拍照声音
enableShutterSound
方法可以打开拍照声音,如下:
mCamera.enableShutterSound(true);
true为打开拍照声音,false为关闭拍照声音。
不过,有一点需要注意
//拍照
mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
}
});
如果takePicture
的第一个参数为null,那么不管怎么设置enableShutterSound
都不会有拍照声音。
//拍照
mCamera.takePicture(new Camera.ShutterCallback() {
@Override
public void onShutter() {
}
}, null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
}
});
如上代码,保证第一个参数不为空,这样enableShutterSound
才能保证有效。
[方法十六]
人脸检测
自从Android 6.0开始,Android就开始支持人脸识别功能。
设置面部识别监听:
mCamera.setFaceDetectionListener(new Camera.FaceDetectionListener() {
@Override
public void onFaceDetection(Camera.Face[] faces, Camera camera) {
if(faces != null && faces.length > 0){
}
}
});
开始面部识别:
mCamera.startFaceDetection();
停止面部识别:
mCamera.stopFaceDetection();
[方法十七]
释放相机资源
mCamera.release();
请注意,一旦释放了相机资源,想要重启相机时必须重新执行以下代码:
Camera mCamera = Camera.open();
说明
另外,Camera.Parameters
还有需要参数都没有讲到,因为感觉只要说明一下常用的即可。在Andorid5.0开始,Camera
已被废弃,改为Camera2
,Camera2
将会在后面章节会讲到。
[本章完...]