在摄像头旧API的使用中,如果要保存全尺寸图像,只能通过takePicture()
分别是shutterCallback
,pictureCallback
,pictureCallback
第一个是快门键按下以后,第二个是RAW图像(如果支持的话)生成以后,第三个是jpeg图像生成以后
一般情况,在第三个Callback里面操作保存jpeg的动作,然后操作其他动作,比如startPreview()
,改变对焦方式,等等
现在发现一个问题,在我按照自己的想法设置好操作以后,如果启用闪光灯拍照,会在拍照以后没有重新开始预览,也就是说startPreview()没有效果,测试表明,所有的callback都没有调用.
表现就是,预览界面静止不动,不能autofocus,但是可以切换摄像头以后恢复预览
而且,如果出现上述现象以后,再次重新开启APP以后,不使用闪光灯的拍照也会出现问题
再而且,如果出现上述现象以后,使用其他(非原厂)APP拍照,也会出现这样的问题。比如CAMERA360,NUBIA CAMERA等等
但是,手机重启以后,在不使用自己的APP之前使用其他APP拍照,完全没问题,使用闪光灯也没问题。
总结来说就是,这个现象会影响到其他app,可以猜测是因为某些全局因素的影响。
测试手机是note3 with android 5.0
mCamera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Toast.makeText(thisActivity, "picture taken", Toast.LENGTH_SHORT).show();
camera.startPreview();
isPreviewing = true;
FileSystem.saveJpegFile(data);
//以下是问题代码
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mCameraParameters.setFocusAreas(null);
mCamera.setParameters(mCameraParameters);
}
});
上面的代码就是问题代码。经过测试,其他部分完全没有问题。
如果把上诉代码的问题部分删除,那么APP测试也完全没有问题,但是添加这一段以后,就会出现如上面描述的问题。
这一段代码的目的是,让每次拍照以后把对焦模式设置为continuous-picture
。如果手动点击屏幕对焦,那么需要把模式设置为auto
,会运行一次完全的对焦过程,就像大部分拍照app做的那样。但是对焦完成,拍照完成以后,对焦模式还是auto,不会像continuous-pictur
那样持续对焦,这样的体验不好。
需要在拍照以后把模式变成continuous-picture
,这样不需要点击屏幕也可以对当前画面对焦,大部分时候可以不需要点击屏幕对焦也可以直接拍照。
这一段代码的作用是很重要的,所以必须找到一个方法,能在闪光灯拍照以后切换对焦模式,又不会出现bug。
以下问题的探索都建立在这个基础上:使用闪光灯启用模式,点击屏幕自动对焦,然后拍照,在保存jpeg的callback里面设置改变对焦模式功能,将auto模式变成continuous模式,希望能在改变模式以后恢复正常,而不会将preview画面冻结住。(非闪光灯模式一直都是正常的,如前面描述)
1 将continuous-picture 变成continuous-video
无效
2, 设置一个handler,postdelay执行改变对焦模式,延迟设定在5000毫秒
无效
也就是说,在延迟一段时间以后再改变对焦模式无效,至少5000毫秒时间是不行的,更长的时间没有测试。
如果设置一个按键手动决定什么时候改变模式,基本上也跟这个postdelay一样,没有区别
3,把改变对焦模式的功能设置在callback外面,
mCamera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Toast.makeText(thisActivity, "picture taken", Toast.LENGTH_SHORT).show();
mCamera.startPreview();
isPreviewing = true;
FileSystem.saveJpegFile(data);
}
});
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mCameraParameters.setFocusAreas(null);
mCamera.setParameters(mCameraParameters);
Toast.makeText(thisActivity, "continuous", Toast.LENGTH_SHORT).show();
有效,但是实际测试效果不好,闪光灯打开以后,对焦过程中的预览看不见,有时候拍照会保存到没有闪光灯覆盖的画面。也就是说,上述问题没有了,但是不实用。舍弃。
4,设定一个异步runnable,然后执行异步动作
无效
5,干脆将改变对焦模式功能舍弃,直接重新打开摄像头。
有效
因为在之前测试的时候发现,如果转换摄像头到前摄像头,再转回到后摄像头以后,一切正常,所以想到这个方法
mCamera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Toast.makeText(thisActivity, "picture taken", Toast.LENGTH_SHORT).show();
//mCamera.startPreview();舍弃
//isPreviewing = true;舍弃
mCamera.release();
openCamera();
FileSystem.saveJpegFile(data);
}
});
这样设置以后,程序执行正常了。但是有一个问题,实际拍摄的时候,拍照保存照片以后的延迟边长,卡顿现象更加突出。本来takepicture以后就会卡顿,API文档里面说了会自动停止预览,需要手动开启预览。但是像这样设置以后,卡顿时间更长,使用体验非常不理想(至少我本人觉得非常不好)。舍弃。
6,我想到,是不是应该在callback里面首先设置一个cancelAutofocus()。API里面说,这个可以退出自动对焦,可以让continuous-picuture恢复正常持续对焦。
测试有效,效果很好,跟预想的一样,和其他app一样
mCamera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
mCamera.cancelAutoFocus(); //这一句很关键
//恢复对焦模式
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mCameraParameters.setFocusAreas(null);
mCamera.setParameters(mCameraParameters);
//
mCamera.startPreview();
isPreviewing = true;
FileSystem.saveJpegFile(data);
}
});
如上这样,终于达到了预期效果。
也就是说,在pictureCallback
里面,需要设置一个cancelAutofocus()
,然后再设置其他功能,就可以恢复正常操作。而如果没有这一句,会导致闪光灯模式下恢复continuous-picuture失败,预览画面被冻结住,而且会后续影响其他app,直到重启设备.
原因不得而知,可以猜想跟某个全局设置有关。为什么闪光灯模式会出现这样的问题,猜想是因为在闪光灯模式下,即便在continuous-picture模式下,程序也会像auto模式一样自动对焦一次,然后再拍照,这可能会影响到某个全局变量。
所以,设置了cancelAutofocus()
恢复正常。