Android(安卓)摄像头自动对焦的几点注意
16lz
2021-01-25
今天在做手机摄像头自动对焦时出了一些问题,这里做个笔记记录一下。
注意事项:1、初始化Camera的代码中要加入下面两行代码
mCamera.autoFocus(myAutoFocusCallback);mCamera.cancelAutoFocus();
示例:
private void initCamera(SurfaceHolder holder) { Log.i(TAG, "initCamera.."); if (mPreviewRunning) { mCamera.stopPreview(); } Camera.Parameters parameters; try { parameters = mCamera.getParameters(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return; } parameters.setPreviewSize(videoWidth, videoHight); parameters.setPictureFormat(PixelFormat.JPEG); parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP); SetCameraFPS(parameters); setCameraDisplayOrientation(this, curCameraIndex, mCamera); mCamera.setParameters(parameters); int bufferSize = (((videoWidth | 0xf) + 1) * videoHight * ImageFormat.getBitsPerPixel(parameters.getPreviewFormat())) / 8; mCamera.addCallbackBuffer(new byte[bufferSize]); mCamera.setPreviewCallbackWithBuffer(this); try { mCamera.setPreviewDisplay(holder); } catch (Exception ex) { // TODO Auto-generated catch block if (null != mCamera) { mCamera.release(); mCamera = null; } ex.printStackTrace(); } mCamera.startPreview(); mCamera.autoFocus(myAutoFocusCallback); mCamera.cancelAutoFocus(); mPreviewRunning = true; }
myAutoFocusCallback相关代码:
private Camera.AutoFocusCallback myAutoFocusCallback = null;...//自动聚焦变量回调 myAutoFocusCallback = new Camera.AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { if (success)//success表示对焦成功 { Log.i(TAG, "onAutoFocus succeed..."); camera.cancelAutoFocus();//只有加上了这一句,才会自动对焦。 initCamera(mSurfaceHolder); doAutoFocus(); } else { Log.i(TAG, "onAutoFocus failed..."); } } };
注意事项2:也是上面代码中的一个聚焦的方法doAutoFocus
//设置聚焦 private void doAutoFocus() { parameters = mCamera.getParameters(); parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); mCamera.setParameters(parameters); mCamera.autoFocus(new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { if (success) { camera.cancelAutoFocus();// 只有加上了这一句,才会自动对焦。 if (!Build.MODEL.equals("KORIDY H30")) { parameters = camera.getParameters(); parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 连续自动对焦 camera.setParameters(parameters); } else { parameters = camera.getParameters(); parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); camera.setParameters(parameters); } } } }); }
这里面有个注释是 “连续自动对焦”,如果不选择这个模式 只能实现一开始自动对焦一次 然后在远近变化就不对焦了
最后完整代码贴一份,后面在找这个代码就方便了 不用打开工程去找:
package com.star.surveillance.live;import android.Manifest;import android.annotation.SuppressLint;import android.app.Activity;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.content.pm.PackageManager;import android.graphics.ImageFormat;import android.graphics.PixelFormat;import android.hardware.Camera;import android.media.AudioManager;import android.net.Uri;import android.os.Build;import android.os.Bundle;import android.os.Environment;import android.support.annotation.RequiresApi;import android.support.v4.app.ActivityCompat;import android.util.Log;import android.view.Surface;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.view.WindowManager;import android.widget.FrameLayout;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.RelativeLayout;import com.star.star_common.util.ActivityStyleUtil;import com.star.star_common.util.ToastUtil;import com.star.star_common.view.StarTextView;import java.io.File;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.List;import static com.star.star_common.constants.StarConstants.TAG;public class RecordActivity extends Activity implements SurfaceHolder.Callback, Camera.PreviewCallback { private LinearLayout rightBtnsLL; private FrameLayout playFL; private StarTextView backTV; private ImageView backIV; private ImageView switchCameraIV; private ImageView voiceIV; private StarTextView topBackTV; private RelativeLayout topTitleRL; private RelativeLayout backRL; private int previousVolume = 10; private View main; private MyVolumeReceiver mVolumeReceiver; private Uri fileUri; private Camera mCamera = null; private Camera.AutoFocusCallback myAutoFocusCallback = null; private SurfaceView mSurfaceView = null; private SurfaceHolder mSurfaceHolder = null; private static final int FRONT = 1; //前置摄像头标记 private static final int BACK = 2; //后置摄像头标记 private int currentCameraType = BACK; //当前打开的摄像头标记 private int curCameraIndex = -1; private boolean mPreviewRunning = false; private final int videoWidth = 1280; private final int videoHight = 720; private int frameCount = 0; private Camera.Parameters parameters;//相机参数 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityStyleUtil.setStatusTransparentStyle(this, false); main = getLayoutInflater().inflate(R.layout.activity_record, null); main.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); //屏幕常亮 setContentView(main);/* Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); try { fileUri = Uri.fromFile(createMediaFile()); // create a file to save the video } catch (Exception e) { e.printStackTrace(); } intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); // set the video image quality to high // start the Video Capture Intent startActivityForResult(intent, 1);*/ int permission = ActivityCompat.checkSelfPermission(this, android.Manifest.permission.READ_PHONE_STATE); if (permission != PackageManager.PERMISSION_GRANTED) { // We don't have permission so prompt the user ActivityCompat.requestPermissions(this, new String[]{ android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.CAMERA, android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, android.Manifest.permission.INTERNET, android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.WAKE_LOCK, android.Manifest.permission.VIBRATE, android.Manifest.permission.SYSTEM_ALERT_WINDOW, }, 1); } initView(); registerVolumeReceiver(); } @Override protected void onDestroy() { super.onDestroy(); try { if (mVolumeReceiver != null) { unregisterReceiver(mVolumeReceiver); mVolumeReceiver = null; } } catch (Exception e) { e.printStackTrace(); } } private void initView() { backIV = (ImageView) findViewById(R.id.surveillance_common_back_iv); topTitleRL = (RelativeLayout) findViewById(R.id.surveillance_common_top_rl); topTitleRL.setBackgroundResource(R.drawable.surveillance_record_back_bj); topBackTV = (StarTextView) findViewById(R.id.surveillance_common_back_tv); topBackTV.setText("手机录制"); playFL = (FrameLayout) findViewById(R.id.surveillance_record_fl); backTV = (StarTextView) findViewById(R.id.surveillance_common_back_tv); backRL = (RelativeLayout) findViewById(R.id.surveillance_common_back_rl); backRL.setOnClickListener(mClickListener); voiceIV = (ImageView) findViewById(R.id.surveillance_record_mute_iv); voiceIV.setOnClickListener(mClickListener); rightBtnsLL = (LinearLayout) findViewById(R.id.surveillance_record_right_btn_ll); if (getCurrentVolume() == 0) { voiceIV.setBackgroundResource(R.drawable.surveillance_record_mute); } mSurfaceView = (SurfaceView) findViewById(R.id.surface); mSurfaceView.setOnClickListener(mClickListener); mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.addCallback(this); mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); switchCameraIV = (ImageView) findViewById(R.id.surveillance_record_switch_camera_iv); switchCameraIV.setOnClickListener(mClickListener); //自动聚焦变量回调 myAutoFocusCallback = new Camera.AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { if (success)//success表示对焦成功 { Log.i(TAG, "onAutoFocus succeed..."); camera.cancelAutoFocus();//只有加上了这一句,才会自动对焦。 initCamera(mSurfaceHolder); doAutoFocus(); } else { Log.i(TAG, "onAutoFocus failed..."); } } }; } private View.OnClickListener mClickListener = new View.OnClickListener() { @Override public void onClick(View v) { if (v.getId() == R.id.surveillance_record_mute_iv) { if (getCurrentVolume() == 0) { voiceIV.setBackgroundResource(R.drawable.surveillance_record_voice); } else { voiceIV.setBackgroundResource(R.drawable.surveillance_record_mute); } setStreamVolume(); } else if (v.getId() == R.id.surveillance_common_back_rl) { onBackPressed(); } else if (v.getId() == R.id.surveillance_record_switch_camera_iv) { } else if (v.getId() == R.id.surface) { doAutoFocus(); } } }; public void setStreamVolume() { AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE); int volume = am.getStreamVolume(AudioManager.STREAM_MUSIC); if (volume == 0) { am.setStreamVolume(AudioManager.STREAM_MUSIC, previousVolume, AudioManager.FLAG_PLAY_SOUND); } else { previousVolume = volume; am.setStreamVolume(AudioManager.STREAM_MUSIC, 0, AudioManager.FLAG_PLAY_SOUND); } } public int getCurrentVolume() { AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE); int volume = am.getStreamVolume(AudioManager.STREAM_MUSIC); return volume; } //动态获取内存存储权限 public static void verifyStoragePermissions(Activity activity) { // Check if we have write permission int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE); if (permission != PackageManager.PERMISSION_GRANTED) { // We don't have permission so prompt the user ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case 1: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { } else { ToastUtil.showLongToast("需要SD卡权限才可以使用此功能"); } return; } } } @Override public void onBackPressed() { finish(); } /** * 注册当音量发生变化时接收的广播 */ private void registerVolumeReceiver() { mVolumeReceiver = new MyVolumeReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction("android.media.VOLUME_CHANGED_ACTION"); registerReceiver(mVolumeReceiver, filter); } @Override public void surfaceCreated(SurfaceHolder holder) { Log.i(TAG, "surfaceCreated.."); try { int CammeraIndex = findBackCamera(); Log.i(TAG, "BackCamera: " + CammeraIndex); if (CammeraIndex == -1) { CammeraIndex = findFrontCamera(); currentCameraType = FRONT; switchCameraIV.setEnabled(false); if (CammeraIndex == -1) { Log.i(TAG, "NO camera!!"); return; } } else { currentCameraType = BACK; } if (mCamera == null) { mCamera = openCamera(currentCameraType); } } catch (Exception e) { e.printStackTrace(); } } @SuppressLint("NewApi") private Camera openCamera(int type) { int frontIndex = -1; int backIndex = -1; int cameraCount = Camera.getNumberOfCameras(); Log.i(TAG, "cameraCount: " + cameraCount); Camera.CameraInfo info = new Camera.CameraInfo(); for (int cameraIndex = 0; cameraIndex < cameraCount; cameraIndex++) { Camera.getCameraInfo(cameraIndex, info); if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { frontIndex = cameraIndex; } else if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { backIndex = cameraIndex; } } currentCameraType = type; if (type == FRONT && frontIndex != -1) { curCameraIndex = frontIndex; return Camera.open(frontIndex); } else if (type == BACK && backIndex != -1) { curCameraIndex = backIndex; return Camera.open(backIndex); } return null; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.i(TAG, "surfaceChanged.."); initCamera(holder); mCamera.cancelAutoFocus();// 只有加上了这一句,才会自动对焦 doAutoFocus(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { } //Check if it has back camera private int findBackCamera() { int cameraCount = 0; Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); cameraCount = Camera.getNumberOfCameras(); for (int camIdx = 0; camIdx < cameraCount; camIdx++) { Camera.getCameraInfo(camIdx, cameraInfo); if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { return camIdx; } } return -1; } //监听 //Check if it has front camera private int findFrontCamera() { int cameraCount = 0; Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); cameraCount = Camera.getNumberOfCameras(); for (int camIdx = 0; camIdx < cameraCount; camIdx++) { Camera.getCameraInfo(camIdx, cameraInfo); if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { return camIdx; } } return -1; } /*it will call when surfaceChanged*/ private void initCamera(SurfaceHolder holder) { Log.i(TAG, "initCamera.."); if (mPreviewRunning) { mCamera.stopPreview(); } Camera.Parameters parameters; try { parameters = mCamera.getParameters(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return; } parameters.setPreviewSize(videoWidth, videoHight); parameters.setPictureFormat(PixelFormat.JPEG); parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP); SetCameraFPS(parameters); setCameraDisplayOrientation(this, curCameraIndex, mCamera); mCamera.setParameters(parameters); int bufferSize = (((videoWidth | 0xf) + 1) * videoHight * ImageFormat.getBitsPerPixel(parameters.getPreviewFormat())) / 8; mCamera.addCallbackBuffer(new byte[bufferSize]); mCamera.setPreviewCallbackWithBuffer(this); try { mCamera.setPreviewDisplay(holder); } catch (Exception ex) { // TODO Auto-generated catch block if (null != mCamera) { mCamera.release(); mCamera = null; } ex.printStackTrace(); } mCamera.startPreview(); mCamera.autoFocus(myAutoFocusCallback); mCamera.cancelAutoFocus(); mPreviewRunning = true; } //设置相机显示的方向 private void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) { Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(cameraId, info); int rotation = activity.getWindowManager().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; } else { // back-facing result = (info.orientation - degrees + 360) % 360; } Log.i(TAG, "curDegree: " + result); camera.setDisplayOrientation(result); } private void SetCameraFPS(Camera.Parameters parameters) { if (parameters == null) { return; } int[] findRange = null; int defFPS = 20 * 1000; List fpsList = parameters.getSupportedPreviewFpsRange(); if (fpsList != null && fpsList.size() > 0) { for (int i = 0; i < fpsList.size(); ++i) { int[] range = fpsList.get(i); if (range != null && Camera.Parameters.PREVIEW_FPS_MIN_INDEX < range.length && Camera.Parameters.PREVIEW_FPS_MAX_INDEX < range.length) { Log.i(TAG, "Camera index:" + i + " support min fps:" + range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX]); if (findRange == null) { if (defFPS <= range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]) { findRange = range; Log.i(TAG, "Camera found appropriate fps, min fps:" + range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] + " ,max fps:" + range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); } } } } } if (findRange != null) { parameters.setPreviewFpsRange(findRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], findRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); } } @Override public void onPreviewFrame(byte[] data, Camera camera) { frameCount++; if (frameCount % 3000 == 0) { Log.i("OnPre", "gc+"); System.gc(); Log.i("OnPre", "gc-"); } if (data == null) { Camera.Parameters params = camera.getParameters(); Camera.Size size = params.getPreviewSize(); int bufferSize = (((size.width | 0x1f) + 1) * size.height * ImageFormat.getBitsPerPixel(params.getPreviewFormat())) / 8; camera.addCallbackBuffer(new byte[bufferSize]); } else { camera.addCallbackBuffer(data); } } /** * 处理音量变化时的界面显示 * * @author long */ private class MyVolumeReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("android.media.VOLUME_CHANGED_ACTION")) { if (getCurrentVolume() == 0) { voiceIV.setBackgroundResource(R.drawable.surveillance_record_mute); } else { voiceIV.setBackgroundResource(R.drawable.surveillance_record_voice); } } } } @Override protected void onResume() { super.onResume(); } @Override protected void onStop() { super.onStop(); } /* 创建保存录制得到的视频文件 * * @return * @throws IOException */ private File createMediaFile() throws IOException { if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_MOVIES), "CameraDemo"); if (!mediaStorageDir.exists()) { if (!mediaStorageDir.mkdirs()) { Log.d(TAG, "failed to create directory"); return null; } } // Create an image file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "VID_" + timeStamp; String suffix = ".mp4"; File mediaFile = new File(mediaStorageDir + File.separator + imageFileName + suffix); return mediaFile; } else { // 当前不可用 } return null; } //设置聚焦 private void doAutoFocus() { parameters = mCamera.getParameters(); parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); mCamera.setParameters(parameters); mCamera.autoFocus(new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { if (success) { camera.cancelAutoFocus();// 只有加上了这一句,才会自动对焦。 if (!Build.MODEL.equals("KORIDY H30")) { parameters = camera.getParameters(); parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 连续自动对焦 camera.setParameters(parameters); } else { parameters = camera.getParameters(); parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); camera.setParameters(parameters); } } } }); }}
里面引用的库不必关心,参考里面摄像头部分的流程和逻辑即可。
更多相关文章
- 没有一行代码,「2020 新冠肺炎记忆」这个项目却登上了 GitHub 中
- PopupWindow位置
- Android(安卓)Studio 设置内存大小及原理
- AlertDialog使用自定义的布局
- java.io.IOException:Can't read [F:\..\android-support-v4.ja
- android之解析包时出现错误(二)
- android之点击回退键俩次退出程序
- Android之Handler的post注意事项
- Android仿硅谷商城实现购物车实例代码