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) {
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,841评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,415评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,904评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,051评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,055评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,255评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,729评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,377评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,517评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,420评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,467评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,144评论 3 317
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,735评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,812评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,029评论 1 256
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,528评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,126评论 2 341

推荐阅读更多精彩内容

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