骁龙camera预览拍照录像流程 api1和api2

19 篇文章 0 订阅

首先说api1的预览流程

CameraActivity的onCreate先区分是不是安全模式(锁屏进入就是安全模式),如果是安全模式会设置flag

indowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED这个flag会在锁屏的时候显示出来
        if (mSecureCamera) {
            // Change the window flags so that secure camera can show when locked
            Window win = getWindow();
            WindowManager.LayoutParams params = win.getAttributes();
            params.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
            if (intent.getComponent().getClassName().equals(GESTURE_CAMERA_NAME)) {
                params.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
                PowerManager pm = ((PowerManager) getSystemService(POWER_SERVICE));
                mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
                mWakeLock.acquire();
                Log.d(TAG, "acquire wake lock");
            }
            win.setAttributes(params);

        }

然后给moduleIndex赋值,第一次进入会赋值ModuleSwitcher.PHOTO_MODULE_INDEX

然后这里会有个api2的选择,如果你把开发者选项(设置里的红眼消除按五下)里的Camera2 Mode打开就会选择api2,也就是

moduleIndex 的值赋了 ModuleSwitcher.CAPTURE_MODULE_INDEX;
        boolean cam2on = mSettingsManager.isCamera2On();
        if (cam2on && moduleIndex == ModuleSwitcher.PHOTO_MODULE_INDEX)
            moduleIndex = ModuleSwitcher.CAPTURE_MODULE_INDEX;

然后进入SetModuleFromIndex,通过moduleIndex给实例赋值,这里以拍照的module为例,如果是第一次进入就会走

mPhotoModule.init(this, mCameraPhotoModuleRootView);这里的PhotoModule就是mvc里的m.
            case ModuleSwitcher.PHOTO_MODULE_INDEX:
                if (mPhotoModule == null) {
                    mPhotoModule = new PhotoModule();
                    mPhotoModule.init(this, mCameraPhotoModuleRootView);
                } else {
                    mPhotoModule.reinit();
                }
                mCurrentModule = mPhotoModule;
                mCameraPhotoModuleRootView.setVisibility(View.VISIBLE);
                break;
然后我们进入PhotoModule的init,在进入之前先看一下PhotoModule的定义,实现了10个接口,再看每一个类之前最好有看定义的习惯,能大体的知道这个类里面都干了什么
public class PhotoModule
        implements 
        CameraModule,//拍照,录像都要实现的接口,装饰者模式的
        PhotoController,// 按钮的点击事件处理接口ShutterButton.OnShutterButtonListener
        FocusOverlayManager.Listener,//处理所有焦点的类
        CameraPreference.OnPreferenceChangedListener,//处理
        ShutterButton.OnShutterButtonListener,//按钮的点击事件处理接口
        MediaSaveService.Listener,//
        OnCountDownFinishedListener,//
        LocationManager.Listener,//
        SensorEventListener,//
        MakeupLevelListener {//

现在看init,就是做了初始化ui和开启openCamera线程.

        mUI = new PhotoUI(activity, this, parent);
        if (mOpenCameraThread == null) {
            mOpenCameraThread = new OpenCameraThread();
            mOpenCameraThread.start();
        }

这里的ui就是mvc里的view,负责显示所有的控件,包括surfaceview和mSurfaceHolder的初始化

 mSurfaceView = (SurfaceView) mRootView.findViewById(R.id.mdp_preview_content);
 mSurfaceView.setVisibility(View.VISIBLE);
 mSurfaceHolder = mSurfaceView.getHolder();
 mSurfaceHolder.addCallback(this);

这里要说一下SurfaceView和SurfaceHolder,surface的关系,SurfaceView可以理解成比普通的view多个surface,然后SurfaceView通过SurfaceHolder控制surface,surface就是用来显示camera的图像的,SurfaceHolder有三个callback,分别是

surfaceChanged(),surface首次显示在屏幕上调用该方法

surfaceCreated(),surfaceview的视图层级结构被放到屏幕上时调用该方法

surfaceDestroyed(),surface销毁时调用

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        Log.v(TAG, "surfaceChanged: width =" + width + ", height = " + height);
        RectF r = new RectF(mSurfaceView.getLeft(), mSurfaceView.getTop(),
                mSurfaceView.getRight(), mSurfaceView.getBottom());
        mController.onPreviewRectChanged(CameraUtil.rectFToRect(r));
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Log.v(TAG, "surfaceCreated");
        mSurfaceHolder = holder;
        mController.onPreviewUIReady();
        mActivity.updateThumbnail(mThumbnail);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.v(TAG, "surfaceDestroyed");
        mSurfaceHolder = null;
        mController.onPreviewUIDestroyed();
    }

然后我们继续看mOpenCameraThread,这个thread调用了openCamera

    private class OpenCameraThread extends Thread {
        @Override
        public void run() {
            openCamera();
            startPreview();
        }
    }

openCamera里调用了

        mCameraDevice = CameraUtil.openCamera(
                mActivity, mCameraId, mHandler,
                mActivity.getCameraOpenErrorCallback());

然后CameraUtil里调用了CameraHolder.instance().open(handler, cameraId, cb);

    public static CameraManager.CameraProxy openCamera(
            Activity activity, final int cameraId,
            Handler handler, final CameraManager.CameraOpenErrorCallback cb) {
        try {
            throwIfCameraDisabled(activity);
            return CameraHolder.instance().open(handler, cameraId, cb);
        } catch (CameraDisabledException ex) {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    cb.onCameraDisabled(cameraId);
                }
            });
        }
        return null;
    }

CameraHolder的open又调用了

mCameraDevice = CameraManagerFactory .getAndroidCameraManager().cameraOpen(handler, cameraId, cb);

                mCameraDevice = CameraManagerFactory
                        .getAndroidCameraManager().cameraOpen(handler, cameraId, cb);
而这个CameraManagerFactory .getAndroidCameraManager()返回的是AndroidCameraManagerImpl的实例
public class CameraManagerFactory {

    private static AndroidCameraManagerImpl sAndroidCameraManager;

    /**
     * Returns the android camera implementation of {@link CameraManager}.
     *
     * @return The {@link CameraManager} to control the camera device.
     */
    public static synchronized CameraManager getAndroidCameraManager() {
        if (sAndroidCameraManager == null) {
            sAndroidCameraManager = new AndroidCameraManagerImpl();
        }
        return sAndroidCameraManager;
    }
}
所以openCamera其实最终调用的是AndroidCameraManagerImpl里的cameraOpen方法,也就是通过反射调用的camera的openLegacy,就是api1的标准接口,现在就和底层通信上了
                        try {
                            Method openMethod = Class.forName("android.hardware.Camera").getMethod(
                                    "openLegacy", int.class, int.class);
                            mCamera = (android.hardware.Camera) openMethod.invoke(
                                    null, msg.arg1, CAMERA_HAL_API_VERSION_1_0);
                        } catch (Exception e) {
                            /* Retry with open if openLegacy doesn't exist/fails */
                            Log.v(TAG, "openLegacy failed due to " + e.getMessage()
                                    + ", using open instead");
                            mCamera = android.hardware.Camera.open(msg.arg1);
                        }

然后子线程继续调用startPreview,主要做的就是1,把camera和SurfaceHolder绑定上,mCameraDevice.setPreviewDisplay(sh);2,设置camera的参数setCameraParameters. 3开始预览mCameraDevice.startPreview();

private void startPreview() {
        if (mPaused || mCameraDevice == null || mParameters == null) {
            return;
        }

        synchronized (mCameraDevice) {
            SurfaceHolder sh = null;
            Log.v(TAG, "startPreview: SurfaceHolder (MDP path)");
            if (mUI != null) {
                sh = mUI.getSurfaceHolder();
            }

            // Let UI set its expected aspect ratio
            mCameraDevice.setPreviewDisplay(sh);//camera和SurfaceHolder绑定上
        }

        if (!mCameraPreviewParamsReady) {
            Log.w(TAG, "startPreview: parameters for preview are not ready.");
            return;
        }
        mErrorCallback.setActivity(mActivity);
        mCameraDevice.setErrorCallback(mErrorCallback);
        // ICS camera frameworks has a bug. Face detection state is not cleared 1589
        // after taking a picture. Stop the preview to work around it. The bug
        // was fixed in JB.
        if (mCameraState != PREVIEW_STOPPED && mCameraState != INIT) {
            stopPreview();
        }

        if (!mSnapshotOnIdle) {
            mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
        }

        setCameraParameters(UPDATE_PARAM_ALL);
        mCameraDevice.setOneShotPreviewCallback(mHandler,
                new CameraManager.CameraPreviewDataCallback() {
                    @Override
                    public void onPreviewFrame(byte[] data, CameraProxy camera) {
                        mUI.hidePreviewCover();
                    }
                });
        Log.w("fy","startPreview--"+Log.getStackTraceString(new Throwable()));
        mCameraDevice.startPreview();

        mHandler.sendEmptyMessage(ON_PREVIEW_STARTED);

        setDisplayOrientation();

        if (!mSnapshotOnIdle && !mInstantCaptureSnapShot) {
            // If the focus mode is continuous autofocus, call cancelAutoFocus to
            // resume it because it may have been paused by autoFocus call.
            if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusManager.getFocusMode())) {
                mCameraDevice.cancelAutoFocus();
            }
        } else {
            Log.v(TAG, "Trigger snapshot from start preview.");
            mHandler.post(mDoSnapRunnable);
        }
    }

这里的setCameraParameters会调用了updateCameraParametersPreference,主要的功能就是将数据库中的数据

PictureSize,PreviewSize,flash,照片质量等数据设置给camera,mCameraDevice.setParameters(mParameters);

这个时候主线程也同时调用cameraActivity的onResume,会调用mCurrentModule.onResumeBeforeSuper();和

mCurrentModule.onResumeAfterSuper();

    @Override
    public void onResume() {
...
        mCurrentModule.onResumeBeforeSuper();
        super.onResume();
        mPaused = false;
        mCurrentModule.onResumeAfterSuper();

在PhotoModule的onResumeAfterSuper里调用了onResumeTasks();


    @Override
    public void onResumeAfterSuper() {
        mLastPhotoTakenWithRefocus = false;
        mUI.showSurfaceView();
        // Add delay on resume from lock screen only, in order to to speed up
        // the onResume --> onPause --> onResume cycle from lock screen.
        // Don't do always because letting go of thread can cause delay.
        String action = mActivity.getIntent().getAction();
        if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action)
                || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
            Log.v(TAG, "On resume, from lock screen.");

            // Check if there is a need to take a snapshot without
            // waiting for the shutter click
            if (isInstantCaptureEnabled()) {
                mInstantCaptureSnapShot = true;
            }

            // Note: onPauseAfterSuper() will delete this runnable, so we will
            // at most have 1 copy queued up.
            mHandler.postDelayed(new Runnable() {
                public void run() {
                    onResumeTasks();
                }
            }, ON_RESUME_TASKS_DELAY_MSEC);
        } else {
            Log.v(TAG, "On resume.");
            onResumeTasks();
        }

而onResumeTasks里主要是调用了initializeSecondTime,作用是初始化MediaSaveService和NameImage用来保存的

    private void initializeSecondTime() {
        // Start location update if needed.
        boolean recordLocation = RecordLocationPreference.get(mPreferences);
        mLocationManager.recordLocation(recordLocation);
        MediaSaveService s = mActivity.getMediaSaveService();
        if (s != null) {
            s.setListener(this);
        }
        mNamedImages = new NamedImages();
        if (!mIsImageCaptureIntent) {
            mUI.showSwitcher();
        }
        mUI.initializeSecondTime(mParameters);
    }

这样预览的整个流程就走下来了。

总结:
1在xml布局中定义一个SurfaceView,用于预览相机采集的数据
2给SurfaceHolder添加回调,在surfaceCreated(holder: SurfaceHolder?)回调中打开相机
3成功打开相机后,设置相机参数。比如:对焦模式,预览大小,照片保存大小等等
4设置相机预览时的旋转角度,然后调用startPreview()开始预览

拍照流程先看ShutterButton的performClick,调用了mListener.onShutterButtonClick();

    @Override
    public boolean performClick() {
        boolean result = super.performClick();
        if (mListener != null && getVisibility() == View.VISIBLE) {
            mListener.onShutterButtonClick();
        }
        return result;
    }

而PhotoModule实现了这个接口,最终调用了PhotoModule的onShutterButtonClick

先看是不是倒计时拍照,不是就调用initiateSnap();


    @Override
    public synchronized void onShutterButtonClick() {
...
        String timer = mPreferences.getString(
                CameraSettings.KEY_TIMER,
                mActivity.getString(R.string.pref_camera_timer_default));
        boolean playSound = mPreferences.getString(CameraSettings.KEY_TIMER_SOUND_EFFECTS,
                mActivity.getString(R.string.pref_camera_timer_sound_default))
                .equals(mActivity.getString(R.string.setting_on_value));

        int seconds = Integer.parseInt(timer);
        // When shutter button is pressed, check whether the previous countdown is
        // finished. If not, cancel the previous countdown and start a new one.
        if (mUI.isCountingDown()) {
            mUI.cancelCountDown();
        }
        if (seconds > 0) {
            String zsl = mPreferences.getString(CameraSettings.KEY_ZSL,
                    mActivity.getString(R.string.pref_camera_zsl_default));
            mUI.overrideSettings(CameraSettings.KEY_ZSL, zsl);
            mUI.startCountDown(seconds, isShutterSoundOn());
        } else {
            mSnapshotOnIdle = false;
            initiateSnap();
        }
    }
然后在initiateSnap中要看是不是自拍,是自拍要启线程调用mFocusManager.doSnap();不是自拍直接调用mFocusManager.doSnap()
    private void initiateSnap() {
        if (mPreferences.getString(CameraSettings.KEY_SELFIE_FLASH,
                mActivity.getString(R.string.pref_selfie_flash_default))
                .equalsIgnoreCase("on") &&
                mCameraId == CameraHolder.instance().getFrontCameraId()) {//自拍闪光灯
            mUI.startSelfieFlash();
            if (selfieThread == null) {
                selfieThread = new SelfieThread();
                selfieThread.start();
            }
        } else {
            mFocusManager.doSnap();
        }
    }

然后doSnap会调用capture,会最终调用mListener.capture().

    public void doSnap() {
        if (!mInitialized) return;

        // If the user has half-pressed the shutter and focus is completed, we
        // can take the photo right away. If the focus mode is infinity, we can
        // also take the photo.
        if (!needAutoFocusCall() || (mState == STATE_SUCCESS || mState == STATE_FAIL)) {
            capture();
        } else if (mState == STATE_FOCUSING) {
            // Half pressing the shutter (i.e. the focus button event) will
            // already have requested AF for us, so just request capture on
            // focus here.
            mState = STATE_FOCUSING_SNAP_ON_FINISH;
        } else if (mState == STATE_IDLE) {
            // We didn't do focus. This can happen if the user press focus key
            // while the snapshot is still in progress. The user probably wants
            // the next snapshot as soon as possible, so we just do a snapshot
            // without focusing again.
            capture();
        }
    }

这个mListener是PhotoModule,所以调用了PhotoModule的capture()

首先调用了mCaptureStartTime = System.currentTimeMillis();记录系统的当前时间

mReceivedSnapNum = 0;是当前的张数,最终调用了mCameraDevice.takePicture(mHandler,
        new ShutterCallback(!animateBefore),
        mRawPictureCallback, mPostViewPictureCallback,
        new JpegPictureCallback(loc));
@Override
    public boolean capture() {
        // If we are already in the middle of taking a snapshot or the image save request
        // is full then ignore.
        Log.w(TAG,"capture");
        if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
                || mCameraState == SWITCHING_CAMERA
                || mActivity.getMediaSaveService() == null
                || mActivity.getMediaSaveService().isQueueFull()) {
            return false;
        }
        mCaptureStartTime = System.currentTimeMillis();
        mPostViewPictureCallbackTime = 0;
        mJpegImageData = null;

        final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR);
        if(mHiston) {
            if (mSnapshotMode != CameraInfo.CAMERA_SUPPORT_MODE_ZSL) {
                mHiston = false;
                mCameraDevice.setHistogramMode(null);
            }
            mActivity.runOnUiThread(new Runnable() {
                public void run() {
                    if(mGraphView != null)
                        mGraphView.setVisibility(View.INVISIBLE);
                }
            });
        }

        if (animateBefore) {
            animateAfterShutter();
        }

        if (mCameraState == LONGSHOT) {
            mCameraDevice.setLongshot(true);
        }

        // Set rotation and gps data.
        int orientation = mOrientation;
        mJpegRotation = CameraUtil.getJpegRotation(mCameraId, orientation);
        String pictureFormat = mParameters.get(KEY_PICTURE_FORMAT);
        Location loc = getLocationAccordPictureFormat(pictureFormat);

        synchronized (mCameraDevice) {
            if (mCameraId == CAMERA_ID_MAIN) {
                mParameters.setFlashMode(Parameters.FLASH_MODE_OFF);
            }
            mParameters.setRotation(mJpegRotation);
            CameraUtil.setGpsParameters(mParameters, loc);

            if (mRefocus) {
                mParameters.set(CameraSettings.KEY_QC_LEGACY_BURST,
                        CameraSettings.KEY_QC_RE_FOCUS_COUNT);
            } else {
                mParameters.remove(CameraSettings.KEY_QC_LEGACY_BURST);
            }

            // Unlock AE&AWB, if they continue
            // to be locked during snapshot, then
            // side effects could be triggered w.r.t.
            // flash.
            mFocusManager.setAeAwbLock(false);
            setAutoExposureLockIfSupported();
            setAutoWhiteBalanceLockIfSupported();

            mCameraDevice.setParameters(mParameters);
            mParameters = mCameraDevice.getParameters();
        }

        mBurstSnapNum = mParameters.getInt("num-snaps-per-shutter");
        mReceivedSnapNum = 0;
        mPreviewRestartSupport = SystemProperties.getBoolean(
                PERSIST_PREVIEW_RESTART, false);
        mPreviewRestartSupport &= CameraSettings.isInternalPreviewSupported(
                mParameters);
        mPreviewRestartSupport &= (mBurstSnapNum == 1);
        // Restart is needed  if HDR is enabled
        mPreviewRestartSupport &= !CameraUtil.SCENE_MODE_HDR.equals(mSceneMode);
        mPreviewRestartSupport &= PIXEL_FORMAT_JPEG.equalsIgnoreCase(
                pictureFormat);

        // We don't want user to press the button again while taking a
        // multi-second HDR photo. For longshot, no need to disable.
        if (mCameraState != LONGSHOT) {
            mUI.enableShutter(false);
        }

        if (!isShutterSoundOn()) {
            mCameraDevice.enableShutterSound(false);
        } else {
            mCameraDevice.enableShutterSound(!mRefocus);
        }
        Log.w(TAG,"mCameraState="+mCameraState);
        if (mCameraState == LONGSHOT) {
            mLongShotCaptureCountLimit = SystemProperties.getInt(
                                    "persist.camera.longshot.shotnum", 0);
            mLongShotCaptureCount = 1;
            Log.w(TAG,"mLongshotSave1="+mLongshotSave);
            if(mLongshotSave) {
                mCameraDevice.takePicture(mHandler,
                        new LongshotShutterCallback(),
                        mRawPictureCallback, mPostViewPictureCallback,
                        new LongshotPictureCallback(loc));
            } else {
                mCameraDevice.takePicture(mHandler,
                        new LongshotShutterCallback(),
                        mRawPictureCallback, mPostViewPictureCallback,
                        new JpegPictureCallback(loc));
            }
        } else {
            mCameraDevice.takePicture(mHandler,
                    new ShutterCallback(!animateBefore),
                    mRawPictureCallback, mPostViewPictureCallback,
                    new JpegPictureCallback(loc));
            setCameraState(SNAPSHOT_IN_PROGRESS);
        }

        mNamedImages.nameNewImage(mCaptureStartTime, mRefocus);

        if (mSnapshotMode != CameraInfo.CAMERA_SUPPORT_MODE_ZSL) {
            mFaceDetectionStarted = false;
        }
        UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
                UsageStatistics.ACTION_CAPTURE_DONE, "Photo", 0,
                UsageStatistics.hashFileName(mNamedImages.mQueue.lastElement().title + ".jpg"));
        return true;
    }

这里的takePicture(shutter, raw, postView, jpeg)里面的参数分别是
shutter是在加工处理原始图像数据且没有存储之前,图像捕捉时刻的回调,或为空
raw原始(未压缩)图像数据的回调
postview包含postview图像数据的回调(一般需要硬件支持)
 jpeg jpeg图像数据的回调

骁龙camera里只实现了shutter和jpeg数据的回调,shutter主要做的事情

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值