Android 为什么带处理器的连续自动对焦相机不允许切换闪光灯?
到目前为止我所做的:Android 为什么带处理器的连续自动对焦相机不允许切换闪光灯?,android,android-camera,Android,Android Camera,到目前为止我所做的: public class CameraPreviewNew extends ViewGroup implements Callback { public static final int CAMERA_BACK = 0; public static final int CAMERA_FRONT = 1; public Camera mCamera = null; private Context context = null; Su
public class CameraPreviewNew extends ViewGroup implements Callback {
public static final int CAMERA_BACK = 0;
public static final int CAMERA_FRONT = 1;
public Camera mCamera = null;
private Context context = null;
SurfaceView mSurfaceView;
SurfaceHolder mSurfaceHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
PreviewCallback mPreviewCallback;
AutoFocusCallback mAutoFocusCallback;
public CameraPreviewNew(Context context,
PreviewCallback previewCallback, AutoFocusCallback autoFocusCb) {
super(context);
mPreviewCallback = previewCallback;
mAutoFocusCallback = autoFocusCb;
this.context = context;
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters()
.getSupportedPreviewSizes();
requestLayout();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(),
widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(),
heightMeasureSpec);
setMeasuredDimension(width, height);
}
public void hideSurfaceView() {
mSurfaceView.setVisibility(View.INVISIBLE);
}
public void showSurfaceView() {
mSurfaceView.setVisibility(View.VISIBLE);
}
public void surfaceCreated(SurfaceHolder holder) {
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e("logtag", "IOException caused by setPreviewDisplay()",
exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null) {
mCamera.cancelAutoFocus();
mCamera.stopPreview();
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (holder.getSurface() == null) {
return;
}
if (mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
mPreviewSize = getBestPreviewSize(mCamera.getParameters(), w, h);
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
mCamera.setPreviewCallback(mPreviewCallback);
mCamera.startPreview();
mCamera.autoFocus(mAutoFocusCallback);
setCameraDisplayOrientation(0);
}
}
private void setCameraDisplayOrientation(int cameraId) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
int rotation = ((WindowManager) context
.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
mCamera.setDisplayOrientation(result);
}
protected static Comparator<Size> newSizeComparator() {
return new Comparator<Size>() {
@Override
public int compare(Size lhs, Size rhs) {
return Integer.valueOf(rhs.height * rhs.width).compareTo(
lhs.height * lhs.width);
}
};
}
private Size getBestPreviewSize(Parameters parameters, int screenWidth,
int screenHeight) {
List<Size> supportedSizes = parameters.getSupportedPreviewSizes();
Collections.sort(supportedSizes, newSizeComparator());
int previewHeight = screenHeight;
int previewWidth = screenWidth;
if (previewHeight > previewWidth) {
int swap = previewWidth;
previewWidth = previewHeight;
previewHeight = swap;
}
Size bestSize = null;
float bestRatio = 999;
for (Size s : supportedSizes) {
if (s.height > s.width) {
int swap = s.width;
s.width = s.height;
s.height = swap;
}
float cameraRatio = ((float) s.height / (float) s.width);
float screenRatio = ((float) previewHeight)
/ ((float) previewWidth);
if ((s.height >= previewHeight) && (s.width >= previewWidth)) {
float ratioDiff = cameraRatio - screenRatio;
if ((ratioDiff < 0.19) && (ratioDiff > -0.19)
&& (Math.abs(bestRatio) > Math.abs(ratioDiff))) {
bestSize = s;
bestRatio = ratioDiff;
}
}
}
return bestSize;
}
public void setCameraFlashLight(Boolean setFlash) {
Parameters _parameters = mCamera.getParameters();
if (setFlash) {
_parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
} else {
_parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
}
mCamera.setParameters(_parameters);
mCamera.startPreview();
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height
/ previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width
/ previewWidth;
child.layout(0, (height - scaledChildHeight) / 2, width,
(height + scaledChildHeight) / 2);
}
}
}
}
我已经实现了用于读取二维码的定制摄像头,需要继续聚焦摄像头以更好地读取二维码
我的问题是当我使用处理器每秒钟对焦一次时,相机闪光灯的“开/关”按钮不起作用,或者打开和关闭相机闪光灯需要太多时间。当我删除每秒自动对焦相机的代码(runnable和handler)时,一切都很好
我想要的是在相机移动时自动快速对焦,并且能够根据需要快速打开和关闭闪光灯,而无需使用camera.Parameters.focus\u MODE\u CONTINUOUS\u PICTURE
,因为它不适用于API previewWidth){
int swap=previewWidth;
previewWidth=PreviewWight;
预览视图=交换;
}
大小bestSize=null;
浮动比率=999;
用于(尺寸s:支持的尺寸){
如果(s.高度>s.宽度){
int swap=s.width;
s、 宽度=s.高度;
s、 高度=交换;
}
浮动摄像机=((浮动)s.高度/(浮动)s.宽度);
浮动屏幕比率=((浮动)预览视图)
/((浮动)预览宽度);
如果((s.height>=预览宽度)和&(s.width>=预览宽度)){
浮动比率IdIff=摄像机-屏幕比率;
如果((ratioDiff<0.19)和&(ratioDiff>-0.19)
&&(数学绝对值(最佳比率)>数学绝对值(比率系数))){
最佳尺寸=s;
最佳比率=ratioDiff;
}
}
}
返回最佳大小;
}
公共无效设置照相机手电筒(布尔设置闪光灯){
参数_Parameters=mCamera.getParameters();
如果(设置闪存){
_参数设置闪光模式(参数闪光模式);
}否则{
_parameters.setFlashMode(parameters.FLASH_MODE_OFF);
}
mCamera.setParameters(_参数);
mCamera.startPreview();
}
@凌驾
仅受保护的void布局(布尔值已更改、int l、int t、int r、int b){
如果(已更改&&getChildCount()>0){
最终视图子对象=getChildAt(0);
最终整数宽度=r-l;
最终内部高度=b-t;
int previewWidth=宽度;
亮度=高度;
if(mPreviewSize!=null){
previewWidth=mPreviewSize.width;
PreviewView=mPreviewSize.height;
}
如果(宽度*预览宽度>高度*预览宽度){
最终整数scaledChildWidth=预览宽度*高度
/预演;
布局((宽度-scaledChildWidth)/2,0,
(宽度+缩放儿童宽度)/2,高度);
}否则{
最终int scaledChildHeight=预览视图*宽度
/预览宽度;
布局(0,(高度-缩放儿童高度)/2,宽度,
(身高+缩放儿童身高)/2);
}
}
}
}
您的应用程序似乎不需要使用AutoFocusCallBack
,因为您所做的只是延迟1秒
要始终对焦,您可以使用focus\u MODE\u CONTINUOUS\u PICTURE
(阅读更多内容)这样(setFocus
方法在CameraPreview
中,而不是在Activity
中):
并在SurfaceChanged
中调用它:
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
// You need to choose the most appropriate previewSize for your app
Camera.Size previewSize = previewSizes.get(0);
parameters.setPreviewSize(previewSize.width, previewSize.height);
parameters.setRotation(90);
mCamera.setParameters(parameters);
mCamera.startPreview();
setFlash(true);
setZoomLevel(5);
setFocus();
Log.w(TAG, "surfaceChanged()");
}
希望它能帮助你!如果您对我的答案有任何疑问,请随时发表评论。我发现您的自动对焦处理代码存在一些问题。
分析结果
自动对焦中有一个循环
解释
a) 相机预览类mautofocuscalback
通过相机活动的autoFocusCb
进行设置
b) surfaceChanged在加载活动时调用一次。要求相机自动对焦
c) 自动对焦完成后,调用mautofocuscalback
回调<代码>MautoFocuscalBack->autoFocusCb->onAutoFocus()
摄像机活动 d)
自动对焦
计划在1000毫秒1秒后再进行一次自动对焦。摄像机活动 e) 一秒钟后,消息被传递给调用runnable
doAutoFocus
请求相机自动对焦的处理程序,类似于上面的b)
f) 自动对焦完成后,再次调用autoFocusCB
,类似于上面的c)。循环继续。
解决方案
我不明白为什么要这样执行。该周期可能是不监听闪存启用/禁用呼叫的原因。您需要删除下面的代码,并执行一些有意义的操作,使onAutoFocus()保持为空
要在相机每次移动时自动对焦,您需要借助手机附带的运动传感器。你可以用谷歌搜索
希望有帮助。快乐编码 虽然此操作必须延迟,但如果要切换相机参数,最好按以下顺序操作
mCamera.stopPreview();
mCamera.setParameters(params); // set flash on in Camera parameters
mCamera.startPreview();
我不想在自动对焦回调中做任何其他事情,因为预览回调将继续查找二维码,我已经尝试过了,并且可以正常工作。我的问题是它不允许我正确地切换闪光灯。另一件事是,连续聚焦模式仅在api>=14中可用,因此您的目标设备的api低于14,我不知道这一点。我在API 15的应用程序中使用了这个。聚焦模式连续图片可以解决你的问题
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
// You need to choose the most appropriate previewSize for your app
Camera.Size previewSize = previewSizes.get(0);
parameters.setPreviewSize(previewSize.width, previewSize.height);
parameters.setRotation(90);
mCamera.setParameters(parameters);
mCamera.startPreview();
setFlash(true);
setZoomLevel(5);
setFocus();
Log.w(TAG, "surfaceChanged()");
}
public void setFlash(boolean isFlashOn) {
Camera.Parameters p = mCamera.getParameters();
if (isFlashOn) {
p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
mCamera.setParameters(p);
mCamera.startPreview();
} else {
p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
mCamera.setParameters(p);
mCamera.startPreview();
}
Log.w(TAG, "setFlash()");
}
public CameraPreviewNew(Context context,...,AutoFocusCallback autoFocusCb)
{
super(context);
mAutoFocusCallback = autoFocusCb;
...
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
{
if (mCamera != null)
{
...
mCamera.startPreview();
/*Auto focus camera and call <code>mAutoFocusCallback</code> after autofocus.*/
mCamera.autoFocus(mAutoFocusCallback);
...
}
}
Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
public void onAutoFocus(boolean success, Camera camera) {
mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
}
private Runnable doAutoFocus = new Runnable() {
public void run() {
if (mCamera != null && mPreviewing) {
mCamera.autoFocus(autoFocusCB);
}
}
};
Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
/*REMOVE LINE BELOW*/
mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
mCamera.stopPreview();
mCamera.setParameters(params); // set flash on in Camera parameters
mCamera.startPreview();