1. 程式人生 > >Android 攝像頭自動對焦的幾點注意

Android 攝像頭自動對焦的幾點注意

今天在做手機攝像頭自動對焦時出了一些問題,這裡做個筆記記錄一下。

注意事項: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<int[]> 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);
                    }
                }
            }
        });
    }
}

裡面引用的庫不必關心,參考裡面攝像頭部分的流程和邏輯即可。