Camera 實(shí)現(xiàn)預(yù)覽拍照

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

最后通知每個(gè) implements ModuleController 的模式,Camera 已經(jīng)處于可用狀態(tài)


以 PhotoModule 分析開啟預(yù)覽流程

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);
        }

        // 設(shè)置預(yù)覽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());
            }
        }

        ...

        // 設(shè)置預(yù)覽回調(diào)
        CameraAgent.CameraStartPreviewCallback startPreviewCallback
                = new CameraAgent.CameraStartPreviewCallback() {
            @Override
            public void onPreviewStarted() {
                ...
            }
        };

        // 開始預(yù)覽
        doStartPreview(startPreviewCallback, mCameraDevice);
        ...
    }
    protected void doStartPreview(CameraAgent.CameraStartPreviewCallback startPreviewCallback, 
                                  CameraAgent.CameraProxy cameraDevice) {
        // 開始預(yù)覽
        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);
            ...
            // 如果是三方調(diào)用拍照則 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) {
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饱岸,一起剝皮案震驚了整個(gè)濱河市被廓,隨后出現(xiàn)的幾起案子肮柜,更是在濱河造成了極大的恐慌脱柱,老刑警劉巖佣蓉,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兆解,死亡現(xiàn)場離奇詭異馆铁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)锅睛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門埠巨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人现拒,你說我怎么就攤上這事辣垒。” “怎么了印蔬?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵勋桶,是天一觀的道長。 經(jīng)常有香客問我,道長例驹,這世上最難降的妖魔是什么捐韩? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮鹃锈,結(jié)果婚禮上荤胁,老公的妹妹穿的比我還像新娘。我一直安慰自己屎债,他們只是感情好仅政,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著扔茅,像睡著了一般已旧。 火紅的嫁衣襯著肌膚如雪秸苗。 梳的紋絲不亂的頭發(fā)上召娜,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音惊楼,去河邊找鬼玖瘸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛檀咙,可吹牛的內(nèi)容都是我干的雅倒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼弧可,長吁一口氣:“原來是場噩夢啊……” “哼蔑匣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起棕诵,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤裁良,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后校套,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體价脾,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年笛匙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了侨把。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡妹孙,死狀恐怖秋柄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蠢正,我是刑警寧澤骇笔,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響蜘拉,放射性物質(zhì)發(fā)生泄漏萨西。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一旭旭、第九天 我趴在偏房一處隱蔽的房頂上張望谎脯。 院中可真熱鬧,春花似錦持寄、人聲如沸源梭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽废麻。三九已至,卻和暖如春模庐,著一層夾襖步出監(jiān)牢的瞬間烛愧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工掂碱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留怜姿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓疼燥,卻偏偏與公主長得像沧卢,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子醉者,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 分析Camera預(yù)覽的過程但狭,我是通過從底層向上層分析的,從jni->Native->HAL->v4l2->java...
    Lemon_Home閱讀 5,816評(píng)論 0 13
  • 諤然失魄撬即,玉隕香飛瓊?cè)~落立磁。地慟天傷,菊謝蘭凋松色蒼搞莺。 經(jīng)綸滿腹息罗,享譽(yù)同儕懷若谷。泣望蒼穹才沧,浩渺星空尋汝蹤迈喉。
    鑿冰而釣閱讀 459評(píng)論 9 32
  • 楊平廈門小微洗護(hù)產(chǎn)業(yè)2018年1月22日清 實(shí)際工作: 1.南坂活動(dòng)H5微信宣傳; 2.兩家市區(qū)店空氣洗物料布置温圆;...
    深笑567閱讀 123評(píng)論 0 0
  • 翠云廊生來就是個(gè)薄情的主挨摸。 聽人說,他用連綿數(shù)里的蒼翠和深郁岁歉,扼殺每一個(gè)想要走進(jìn)他...
    山谷明月光閱讀 299評(píng)論 0 1