Camera 实现预览拍照

openCamera 流程

CameraActivity.java

    @Override
    public void onCreateTasks(Bundle state) {
        ...
        // oncreate manager initialize
        CameraFilmstripDataAdapter.THREAD_POOL_EXECUTOR.execute(mOncreateManagerInitialize);
        // oncreate - onecameramanager
        CameraFilmstripDataAdapter.THREAD_POOL_EXECUTOR.execute(mOncreateOneCameraManager);
        // oncreate modules info and set current module
        CameraFilmstripDataAdapter.THREAD_POOL_EXECUTOR
                .execute(mOncreateModulesInfoAndCurrentModule);
        // oncreate - camera controller
        CameraFilmstripDataAdapter.THREAD_POOL_EXECUTOR.execute(mOncreateCameraController);
        // oncreate - module data setting
        CameraFilmstripDataAdapter.THREAD_POOL_EXECUTOR.execute(mOnCreateDataSeting);
        // oncreate - request open camera
        CameraFilmstripDataAdapter.THREAD_POOL_EXECUTOR.execute(mOncreateOpencamera);
        // other task
        CameraFilmstripDataAdapter.THREAD_POOL_EXECUTOR
                .execute(mOncreateOtherTaskInOncreateProcess);
        CameraFilmstripDataAdapter.THREAD_POOL_EXECUTOR.execute(mOncreateOtherTask);
        
        // init module ui
        postInit();
        ...
    }
    // oncreate - request open camera
    private Runnable mOncreateOpencamera = new Runnable() {

        @Override
        public void run() {
            ...
            mCameraController.requestCamera(
                    mDataModuleManager.getInstance(CameraActivity.this)
                            .getTempCameraModule().getInt(Keys.KEY_CAMERA_ID, 0),
                    mCurrentModule.useNewApi());
            ...
        }
    };


CameraController.java

    @Override
    public void requestCamera(int id, boolean useNewApi) {
        ...
        checkAndOpenCamera(cameraManager, id, mCallbackHandler, this);
        ...
    }

接下来分析 checkAndOpenCamera 流程

checkAndOpenCamera .png

最后通知每个 implements ModuleController 的模式,Camera 已经处于可用状态


以 PhotoModule 分析开启预览流程

PhotoModule.java

    @Override
    public void onCameraAvailable(CameraProxy cameraProxy) {
        ...
        startPreview(true);
        ...
    }
    protected void startPreview(boolean optimize) {
        ...

        // update Settings before start preview
        if(settingchange){
            settingchange = false;
        } else {
            updateSettingAfterOpencamera(optimize);
        }

        // 设置预览SurfaceHolder
        if (isUseSurfaceView()) {
            if (optimize) {
                mCameraDevice.setPreviewDisplay(mActivity.getCameraAppUI().getSurfaceHolder());
            } else {
                mCameraDevice.setPreviewDisplayWithoutOptimize(
                        mActivity.getCameraAppUI().getSurfaceHolder());
            }
        } else {
            if (optimize) {
                mCameraDevice.setPreviewTexture(mActivity.getCameraAppUI().getSurfaceTexture());
            } else {
                mCameraDevice.setPreviewTextureWithoutOptimize(mActivity.getCameraAppUI()
                        .getSurfaceTexture());
            }
        }

        ...

        // 设置预览回调
        CameraAgent.CameraStartPreviewCallback startPreviewCallback
                = new CameraAgent.CameraStartPreviewCallback() {
            @Override
            public void onPreviewStarted() {
                ...
            }
        };

        // 开始预览
        doStartPreview(startPreviewCallback, mCameraDevice);
        ...
    }
    protected void doStartPreview(CameraAgent.CameraStartPreviewCallback startPreviewCallback, 
                                  CameraAgent.CameraProxy cameraDevice) {
        // 开始预览
        if (useNewApi()) {
            mCameraDevice.startPreview();
            startPreviewCallback.onPreviewStarted();
        } else {
            mCameraDevice.startPreviewWithCallback(new Handler(Looper.getMainLooper()),
                    startPreviewCallback);
        }
        ...
    }


拍照流程

PhotoModule.java

    @Override
    public boolean capture() {
        ...
        // apply Settings
        mCameraDevice.applySettings(mCameraSettings);

        // Set JPEG orientation. Even if screen UI is locked in portrait, camera
        // orientation should
        // still match device orientation (e.g., users should always get
        // landscape photos while
        // capturing by putting device in landscape.)
        mCameraDevice.setJpegOrientation(mJpegRotation);
        
        // takePicture start!
        mCameraDevice.takePicture(mHandler,
                new ShutterCallback(false),
                mRawPictureCallback, mPostViewPictureCallback, new JpegPictureCallback(loc));
        ...
        return true;
    }
    private final class JpegPictureCallback implements CameraPictureCallback {
        Location mLocation;

        public JpegPictureCallback(Location loc) {
            ...
        }

        @Override
        public void onPictureTaken(final byte[] originalJpegData,
                                   final CameraProxy camera) {
            ...
            // 播放拍照音
            mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
            ...
            // 更新缩略图
            startPeekAnimation(originalJpegData);
            ...
            // 如果是三方调用拍照则 stopPreview
            if (mIsImageCaptureIntent) {
                stopPreview();
            }
            ...
            // 重新 startPreview
            if (!mIsImageCaptureIntent
                    && mContinuousCaptureCount <= 0 && isLastCallback()) {
                setupPreview();
            }
            ...
            // 保存图片
            saveFinalPhoto(originalJpegData, name, exif, camera, burstMode);
            ...
        }
    }

Q:为什么 takePicture 后需要重新 startPreview

A:

    /**
     * <p>This method is only valid when preview is active (after
     * {@link #startPreview()}).  Preview will be stopped after the image is
     * taken; callers must call {@link #startPreview()} again if they want to
     * re-start preview or take more pictures. This should not be called between
     * {@link android.media.MediaRecorder#start()} and
     * {@link android.media.MediaRecorder#stop()}.
     */
    public final void takePicture(ShutterCallback shutter, PictureCallback raw,
            PictureCallback postview, PictureCallback jpeg) {
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 分析Camera预览的过程,我是通过从底层向上层分析的,从jni->Native->HAL->v4l2->java...
    Lemon_Home阅读 5,909评论 0 13
  • 谔然失魄,玉陨香飞琼叶落。地恸天伤,菊谢兰凋松色苍。 经纶满腹,享誉同侪怀若谷。泣望苍穹,浩渺星空寻汝踪。
    凿冰而钓阅读 478评论 9 32
  • 杨平厦门小微洗护产业2018年1月22日清 实际工作: 1.南坂活动H5微信宣传; 2.两家市区店空气洗物料布置;...
    深笑567阅读 127评论 0 0
  • 翠云廊生来就是个薄情的主。 听人说,他用连绵数里的苍翠和深郁,扼杀每一个想要走进他...
    山谷明月光阅读 326评论 0 1