Android相機<第三篇>:Camera詳解

當我們自定義相機時萍膛,常常使用Camera對象完成拍照流程,本文的重點在于研究Camera 各個方法的作用仍源。

[方法一] 獲取Camera對象

Camera mCamera = Camera.open();

[方法二] 拍照

public final void takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback postview, PictureCallback jpeg)

使用方法如下:

    mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {

        }
    });

它有一個回調(diào)羹蚣,拍完照片之后會執(zhí)行onPictureTaken回調(diào)方法蜈七,data參數(shù)為圖片的字節(jié)數(shù)組柴底。

[方法三] 自動聚焦

自動聚焦的監(jiān)聽必須放在啟動預(yù)覽界面(mCamera.startPreview())之后婿脸,否則部分手機會崩潰。

實現(xiàn)代碼如下:

    //自動獲取焦點
    mCamera.autoFocus(autoFocusCallback );


private Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
    @Override
    public void onAutoFocus(boolean success, Camera camera) {

    }
};

此時發(fā)現(xiàn)柄驻,自動聚焦的回調(diào)方法始終只執(zhí)行一次狐树,那么怎么做才能無限聚焦呢?只要在自動聚焦的回調(diào)方法中添加兩句代碼即可凿歼。

private Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
    @Override
    public void onAutoFocus(boolean success, Camera camera) {
        mCamera.cancelAutoFocus();
        camera.autoFocus(autoFocusCallback);
    }
};

與設(shè)置自動聚焦相比褪迟,還有一個方法取消自動聚焦cancelAutoFocus

以上是實現(xiàn)自動聚焦的其中一個方法答憔,當然還有其它方法,文章下面會介紹掀抹。

[方法四] 鎖定虐拓、解鎖、重連

//鎖定攝像機硬件資源
mCamera.lock();
//解鎖攝像機硬件資源
mCamera.unlock();
//重連
mCamera.reconnect();

為了防止相機被其它資源利用傲武,相機默認是鎖定狀態(tài)蓉驹。當其它資源想要利用相機時,必須解鎖和重連后才能繼續(xù)使用相機服務(wù)揪利。

如果僅僅使用拍照态兴,您可能不需要使用這三個方法,當使用MediaRecorder錄制時會使用這三個方法獲取相機服務(wù)疟位。

[方法五] 設(shè)置預(yù)覽方向

mCamera.setDisplayOrientation(90);

預(yù)覽方向默認是橫屏的瞻润,所以這里要調(diào)整一下預(yù)覽方向。

[方法六] 設(shè)置預(yù)覽界面

目前拍照涉及到的預(yù)覽界面主要有兩種:TextureViewSurfaceView

        mCamera.setPreviewDisplay(SurfaceHolder);
        mCamera.setPreviewTexture(SurfaceTexture);

有關(guān)TextureViewSurfaceView會在第四篇第五篇介紹甜刻。

[方法七] 設(shè)置預(yù)覽監(jiān)聽

        mCamera.setPreviewCallback(new Camera.PreviewCallback() {
            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {
                
            }
        });

這個監(jiān)聽最強大的地方在于可以不停的返回一幀畫面的圖像數(shù)據(jù)绍撞,可以利用OpenGL對圖片進行處理。

設(shè)置監(jiān)聽的方法還有一個得院,如下:

        mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {
                
            }
        });

這個方法應(yīng)該是和mCamera.addCallbackBuffer(byte[] callbackBuffer)一起使用傻铣,mCamera.addCallbackBuffer(byte[] callbackBuffer)是向緩存隊列中添加一個預(yù)覽幀。

這兩種監(jiān)聽的工作方式差不多祥绞,他們都會不停的回調(diào)當前預(yù)覽幀非洲,那么如果獲取拍照或者觸發(fā)聚焦時的預(yù)覽幀的話,就會使用以下預(yù)覽監(jiān)聽方案:

        mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {

            }
        });

如果處于預(yù)覽狀態(tài)蜕径,那么會立即回調(diào)一個預(yù)覽幀两踏。

當觸發(fā)聚焦時,此時的畫面最為清晰丧荐,可以使用這個監(jiān)聽獲取當前預(yù)覽幀缆瓣,根據(jù)回調(diào)返回的字節(jié)數(shù)組來處理圖像。

[方法八] 開始預(yù)覽和停止預(yù)覽

當Camera綁定預(yù)覽界面后虹统,Camera就可以啟動預(yù)覽界面和停止預(yù)覽界面弓坞。

//啟動預(yù)覽界面
mCamera.startPreview();

//停止預(yù)覽界面
mCamera.stopPreview();

只有啟動預(yù)覽界面之后隧甚,預(yù)覽監(jiān)聽才會收到回調(diào)。

[方法九] 平滑縮放

有些手機的相機自帶縮放功能渡冻,當我們用雙指縮放預(yù)覽界面時會觸發(fā)平滑縮放監(jiān)聽戚扳。當然,一些手機不支持平滑縮放功能族吻。

監(jiān)聽代碼如下:

        mCamera.setZoomChangeListener(new Camera.OnZoomChangeListener() {
            @Override
            public void onZoomChange(int zoomValue, boolean stopped, Camera camera) {
                
            }
        });

zoomValue為當前縮放因子帽借,stopped表示當前縮放是否結(jié)束,如果為false則表示縮放正在進行超歌,如果為true表示縮放結(jié)束砍艾。

調(diào)用startSmoothZoom方法后開始啟動平滑縮放功能,代碼如下:

        Camera.Parameters parameters = mCamera.getParameters();
        if(parameters.isSmoothZoomSupported()){
            mCamera.startSmoothZoom(1);
        }

startSmoothZoom方法傳遞一個數(shù)值巍举,這個數(shù)值就是縮放因子脆荷,它的取值范圍是:[0,parameters.getMaxZoom()],取值不可超過這個范圍懊悯,否則報錯蜓谋,在設(shè)置縮放因子之前必須先判斷手機是否支持平滑縮放,否則設(shè)置無效或者異常炭分,設(shè)置縮放因子后桃焕,縮放監(jiān)聽開始執(zhí)行。假設(shè)當前縮放因子為0捧毛,那么執(zhí)行以下語句:

        if(parameters.isSmoothZoomSupported()){
            mCamera.startSmoothZoom(12);
        }

那么观堂,它不會直接從0變成12,設(shè)置縮放因子需要消耗一定的時間岖妄,它的變化過程如下:

  • 當從0變成1時型将,觸發(fā)一次監(jiān)聽回調(diào),zoomValue=1荐虐,stopped=false
  • 當從1變成2時七兜,觸發(fā)一次監(jiān)聽回調(diào),zoomValue=2福扬,stopped=false
  • 當從2變成3時腕铸,觸發(fā)一次監(jiān)聽回調(diào),zoomValue=3铛碑,stopped=false
  • 當從3變成4時狠裹,觸發(fā)一次監(jiān)聽回調(diào),zoomValue=4汽烦,stopped=false
  • 當從4變成5時涛菠,觸發(fā)一次監(jiān)聽回調(diào),zoomValue=5,stopped=false
  • 當從5變成6時俗冻,觸發(fā)一次監(jiān)聽回調(diào)礁叔,zoomValue=6,stopped=false
  • 當從6變成7時迄薄,觸發(fā)一次監(jiān)聽回調(diào)琅关,zoomValue=7,stopped=false
  • 當從7變成8時讥蔽,觸發(fā)一次監(jiān)聽回調(diào)涣易,zoomValue=8,stopped=false
  • 當從8變成9時冶伞,觸發(fā)一次監(jiān)聽回調(diào)新症,zoomValue=9,stopped=false
  • 當從9變成10時碰缔,觸發(fā)一次監(jiān)聽回調(diào)账劲,zoomValue=10,stopped=false
  • 當從10變成11時金抡,觸發(fā)一次監(jiān)聽回調(diào),zoomValue=11腌且,stopped=false
  • 當從11變成12時梗肝,觸發(fā)一次監(jiān)聽回調(diào),zoomValue=12铺董,stopped=true

也就是說巫击,平滑縮放的監(jiān)聽回調(diào)執(zhí)行了12次。

在這個過程中精续,可以提前停止縮放坝锰,只要執(zhí)行這個方法即可

    mCamera.stopSmoothZoom();

startSmoothZoomstopSmoothZoom這兩個方法必須在啟動預(yù)覽界面(mCamera.startPreview())之后執(zhí)行,否則會報錯重付。

[方法十] 相機異常監(jiān)聽

        mCamera.setErrorCallback(new Camera.ErrorCallback() {
            @Override
            public void onError(int error, Camera camera) {
                switch (error){
                    case Camera.CAMERA_ERROR_UNKNOWN:
                        System.out.println("相機未知錯誤");
                        break;
                    case Camera.CAMERA_ERROR_EVICTED:
                        System.out.println("相機已斷開連接");
                        break;
                    case Camera.CAMERA_ERROR_SERVER_DIED:
                        System.out.println("媒體服務(wù)器死機");
                        break;
                    default:
                        System.out.println("未知異常error:"+error);
                        break;

                }
            }
        });

可以監(jiān)聽相機使用過程之的錯誤顷级。

[方法十一] 設(shè)置拍照后,存入本地圖片的格式

        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPictureFormat(ImageFormat.JPEG);
        mCamera.setParameters(parameters);

setPictureFormat可以設(shè)置圖片格式确垫。

[方法十二] 解決輸出圖片旋轉(zhuǎn)90度問題

        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setRotation(90);
        mCamera.setParameters(parameters);

[方法十三] 設(shè)置預(yù)覽大小和圖片大小

設(shè)置預(yù)覽大小就是設(shè)置預(yù)覽界面的顯示圖像的分辨率

        Camera.Parameters parameters = mCamera.getParameters();
        Camera.Size previewSize = getCameraSize(parameters.getSupportedPreviewSizes(), width, height);
        parameters.setPreviewSize(previewSize.width, previewSize.height);
        mCamera.setParameters(parameters);

設(shè)置圖片大小就是設(shè)置保存到本地的圖片分辨率

        Camera.Parameters parameters = mCamera.getParameters();
        Camera.Size pictureSize = getCameraSize(parameters.getSupportedPictureSizes(), width, height);
        parameters.setPictureSize(pictureSize.width, pictureSize.height);
        mCamera.setParameters(parameters);

其中getCameraSize方法就是篩選出最適合的分辨率弓颈。

/**
 * 獲取最合適的Size
 * @param sizeList
 * @param width
 * @param height
 * @return
 */
private Camera.Size getCameraSize(List<Camera.Size> sizeList, int width, int height){

    Camera.Size tempSize = null;
    float aspectRatio = height * 1.0f / width;//求出預(yù)期橫寬比
    float offset = aspectRatio;//預(yù)期橫寬比和實際橫寬比誤差

    for(Camera.Size size : sizeList){

        if(size.width < height || size.height < width){
            continue;
        }

        //誤差最小值
        if(Math.abs(aspectRatio - size.width * 1.0f / size.height) < offset){
            offset = Math.abs(aspectRatio - size.width * 1.0f / size.height);
            tempSize = size;
        }
    }

    if(tempSize == null){
        tempSize = sizeList.get(0);
    }


    return tempSize;
}

[方法十四] 聚焦模式

Camera.Parameters parameters = mCamera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mCamera.setParameters(parameters);

調(diào)用setFocusMode方法可以設(shè)置聚焦模式,聚焦模式有很多:

FOCUS_MODE_AUTO删掀、FOCUS_MODE_INFINITY翔冀、FOCUS_MODE_MACROFOCUS_MODE_FIXED披泪、FOCUS_MODE_EDOF纤子、FOCUS_MODE_CONTINUOUS_VIDEOFOCUS_MODE_CONTINUOUS_PICTURE,這些模式用到的有兩種模式控硼,分別是:FOCUS_MODE_CONTINUOUS_PICTUREFOCUS_MODE_CONTINUOUS_VIDEO泽论。

這兩個參數(shù)最大的作用是可以不斷的觸發(fā)聚焦,并且可以接收到監(jiān)聽的回調(diào)象颖。

        mCamera.setAutoFocusMoveCallback(new Camera.AutoFocusMoveCallback() {
            @Override
            public void onAutoFocusMoving(boolean start, Camera camera) {
                
            }
        });

監(jiān)聽setAutoFocusMoveCallback與聚焦模式結(jié)合使用可以實現(xiàn)隨時聚焦功能佩厚,類似于[方法三]中說到的自動聚焦,但是autoFocus不可以和setAutoFocusMoveCallback混用说订,有些手機混用是沒有問題的抄瓦,但是有些手機一旦觸發(fā)了autoFocus監(jiān)聽,那么setAutoFocusMoveCallback監(jiān)聽就會中斷陶冷,所以這兩個觸發(fā)聚焦功能只能選擇一個钙姊。

代碼實現(xiàn)如下:

        mCamera.setAutoFocusMoveCallback(new Camera.AutoFocusMoveCallback() {
            @Override
            public void onAutoFocusMoving(boolean start, Camera camera) {

            }
        });


parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);     

//或者     
//parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);

[方法十五] 拍照聲音

enableShutterSound方法可以打開拍照聲音,如下:

        mCamera.enableShutterSound(true);

true為打開拍照聲音埂伦,false為關(guān)閉拍照聲音煞额。

不過,有一點需要注意

    //拍照
    mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {

        }
    });

如果takePicture的第一個參數(shù)為null沾谜,那么不管怎么設(shè)置enableShutterSound都不會有拍照聲音膊毁。

    //拍照
    mCamera.takePicture(new Camera.ShutterCallback() {
        @Override
        public void onShutter() {
            
        }
    }, null, null, new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {

        }
    });

如上代碼,保證第一個參數(shù)不為空基跑,這樣enableShutterSound才能保證有效婚温。

[方法十六] 人臉檢測

自從Android 6.0開始,Android就開始支持人臉識別功能媳否。

設(shè)置面部識別監(jiān)聽:

        mCamera.setFaceDetectionListener(new Camera.FaceDetectionListener() {
            @Override
            public void onFaceDetection(Camera.Face[] faces, Camera camera) {
                if(faces != null && faces.length > 0){

                }
            }
        });

開始面部識別:

        mCamera.startFaceDetection();

停止面部識別:

        mCamera.stopFaceDetection();

[方法十七] 釋放相機資源

mCamera.release();

請注意栅螟,一旦釋放了相機資源,想要重啟相機時必須重新執(zhí)行以下代碼:

Camera mCamera = Camera.open();
說明

另外篱竭,Camera.Parameters還有需要參數(shù)都沒有講到力图,因為感覺只要說明一下常用的即可。在Andorid5.0開始掺逼,Camera已被廢棄吃媒,改為Camera2Camera2將會在后面章節(jié)會講到坪圾。

[本章完...]

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末晓折,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子兽泄,更是在濱河造成了極大的恐慌漓概,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件病梢,死亡現(xiàn)場離奇詭異胃珍,居然都是意外死亡梁肿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門觅彰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吩蔑,“玉大人,你說我怎么就攤上這事填抬≈蚍遥” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵飒责,是天一觀的道長赘娄。 經(jīng)常有香客問我,道長宏蛉,這世上最難降的妖魔是什么遣臼? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮拾并,結(jié)果婚禮上揍堰,老公的妹妹穿的比我還像新娘。我一直安慰自己嗅义,他們只是感情好屏歹,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著之碗,像睡著了一般西采。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上继控,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機與錄音胖眷,去河邊找鬼武通。 笑死,一個胖子當著我的面吹牛珊搀,可吹牛的內(nèi)容都是我干的冶忱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼境析,長吁一口氣:“原來是場噩夢啊……” “哼囚枪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起劳淆,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤链沼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后沛鸵,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體括勺,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡缆八,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了疾捍。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奈辰。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖乱豆,靈堂內(nèi)的尸體忽然破棺而出奖恰,到底是詐尸還是另有隱情,我是刑警寧澤宛裕,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布瑟啃,位于F島的核電站,受9級特大地震影響续滋,放射性物質(zhì)發(fā)生泄漏翰守。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一疲酌、第九天 我趴在偏房一處隱蔽的房頂上張望蜡峰。 院中可真熱鬧,春花似錦朗恳、人聲如沸湿颅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽油航。三九已至,卻和暖如春怀浆,著一層夾襖步出監(jiān)牢的瞬間谊囚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工执赡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留镰踏,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓沙合,卻偏偏與公主長得像奠伪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子首懈,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

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