Android Camera-Camera1使用

Android Camera API和Android版本一樣纯露,也是碎片化比較嚴重剿骨,所以Google官方推出了CameraView,提供給開發(fā)者參考和學(xué)習(xí)埠褪,現(xiàn)在最新的可以使用Jetpack CameraX來開發(fā)浓利,大大簡化了開發(fā)的復(fù)雜度。本系列從Camera1->Camera2->CameraView->CameraX钞速,一步步講解Camera的進化過程贷掖,本篇先介紹Camera1的使用。
相機開發(fā)的流程:

  1. 檢測設(shè)備攝像頭渴语,打開相機
  2. 創(chuàng)建預(yù)覽畫面苹威,顯示實時預(yù)覽畫面
  3. 設(shè)置相機參數(shù),進行拍照監(jiān)聽
  4. 監(jiān)聽中驾凶,保存圖片資源或者直接操作原始數(shù)據(jù)
  5. 釋放相機資源

上面的是基本的相機開發(fā)流程屠升,不同的Camera API在實現(xiàn)上會有不同,整體流程上還是統(tǒng)一的狭郑。

Camera1使用

權(quán)限聲明

<uses-feature
        android:name="android.hardware.camera"
        android:required="true" />

<uses-permission android:name="android.permission.CAMERA" />

相機必須聲明CAMERA權(quán)限腹暖,在Android6.0上,你還需要在代碼中動態(tài)申請權(quán)限

ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
                    REQUEST_CAMERA_PERMISSION);

開發(fā)流程

下圖是一個開發(fā)流程的導(dǎo)覽:

打開相機

Camera.open()

該方法的系統(tǒng)源碼實現(xiàn)

public static Camera open() {
    int numberOfCameras = getNumberOfCameras();
    CameraInfo cameraInfo = new CameraInfo();
    for (int i = 0; i < numberOfCameras; i++) {
        getCameraInfo(i, cameraInfo);
        if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
            return new Camera(i);
        }
    }
    return null;
}

這里會檢查可用的攝像頭翰萨,默認使用的CameraInfo.CAMERA_FACING_BACK后置攝像頭

創(chuàng)建預(yù)覽畫面

這里使用的是SurfaceView

private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
...
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        ...
        startPreview();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        releaseCamera();
    }
});
...
private void startPreview() {
    try {
        //設(shè)置實時預(yù)覽
        mCamera.setPreviewDisplay(mSurfaceHolder);
        //Orientation
        setCameraDisplayOrientation();
        //開始預(yù)覽
        mCamera.startPreview();

        startFaceDetect();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

設(shè)置預(yù)覽的時候脏答,可以設(shè)置setPreviewCallback監(jiān)聽預(yù)覽數(shù)據(jù)的回調(diào)

void onPreviewFrame(byte[] data, Camera camera);

設(shè)置相機參數(shù)

設(shè)置相機參數(shù)后,需要重新啟動預(yù)覽,這邊在初始化的時候殖告,已經(jīng)設(shè)置好了阿蝶。

private void initParameters(final Camera camera) {
    mParameters = camera.getParameters();
    mParameters.setPreviewFormat(ImageFormat.NV21); //default

    if (isSupportFocus(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
        mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
    } else if (isSupportFocus(Camera.Parameters.FOCUS_MODE_AUTO)) {
        mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
    }

    //設(shè)置預(yù)覽圖片大小
    setPreviewSize();
    //設(shè)置圖片大小
    setPictureSize();

    camera.setParameters(mParameters);
}

Camera.Parameters可以設(shè)置的參數(shù)非常多,這里就介紹幾個比較常用的


Camera.Parameters

1.setFocusMode

設(shè)置對焦模式

  • FOCUS_MODE_AUTO:自動對焦
  • FOCUS_MODE_INFINITY:無窮遠
  • FOCUS_MODE_MACRO:微距
  • FOCUS_MODE_FIXED:固定焦距
  • FOCUS_MODE_EDOF:景深擴展
  • FOCUS_MODE_CONTINUOUS_PICTURE:持續(xù)對焦(針對照片)
  • FOCUS_MODE_CONTINUOUS_VIDEO:(針對視頻)

2.setPreviewSize

設(shè)置預(yù)覽圖片大小

3.setPreviewFormat

支持的格式:

  • ImageFormat.NV16
  • ImageFormat.NV21
  • ImageFormat.YUY2
  • ImageFormat.YV12
  • ImgaeFormat.RGB_565
  • ImageFormat.JPEG
    如果不設(shè)置黄绩,默認返回NV21的數(shù)據(jù)

4.setPictureSize

設(shè)置保存圖片的大小

5.setPictureFormat

設(shè)置保存圖片的格式羡洁,格式和setPreviewFormat一樣

6.setDisplayOrientation

設(shè)置相機預(yù)覽畫面旋轉(zhuǎn)的角度,degress取值0爽丹,90筑煮,180,270

7.setPreviewDisplay

設(shè)置實時預(yù)覽SurfaceHolder

8.setPreviewCallback

監(jiān)聽相機預(yù)覽數(shù)據(jù)回調(diào)

9.setParameters

設(shè)置相機的Parameters
其他一些設(shè)置粤蝎,大家可以查看Android文檔進行相應(yīng)的設(shè)置

設(shè)置方向

設(shè)置相機的預(yù)覽方向真仲,orientation比較詳細的介紹

private void setCameraDisplayOrientation() {
    Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
    Camera.getCameraInfo(mCameraId, cameraInfo);
    int rotation = getWindowManager().getDefaultDisplay().getRotation();  //自然方向
    int degrees = 0;
    switch (rotation) {
        case Surface.ROTATION_0:
            degrees = 0;
            break;
        case Surface.ROTATION_90:
            degrees = 90;
            break;
        case Surface.ROTATION_180:
            degrees = 180;
            break;
        case Surface.ROTATION_270:
            degrees = 270;
            break;
    }

    int result;
    //cameraInfo.orientation 圖像傳感方向
    if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
        result = (cameraInfo.orientation + degrees) % 360;
        result = (360 - result) % 360;
    } else {
        result = (cameraInfo.orientation - degrees + 360) % 360;
    }

    mOrientation = result;
    //相機預(yù)覽方向
    mCamera.setDisplayOrientation(result);
}

拍照

private void takePicture() {
    if (null != mCamera) {
        mCamera.takePicture(new Camera.ShutterCallback() {
            @Override
            public void onShutter() {

            }
        }, new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
                //base data
            }
        }, new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(final byte[] data, Camera camera) {
                mCamera.startPreview();
                //save data
            }
        });
    }
}

takePicture的源碼實現(xiàn):

public final void takePicture(ShutterCallback shutter, PictureCallback raw,
            PictureCallback jpeg) {
        takePicture(shutter, raw, null, jpeg);
    }
  • shutter(ShutterCallback):快門按下后的回調(diào)
  • raw(PictureCallback):raw圖像數(shù)據(jù)
  • jpeg(PictureCallback):jpeg圖像生成以后的回調(diào)

釋放相機資源

在使用完成后,onPause或者onDestory中進行相機資源的釋放

private void releaseCamera() {
    if (null != mCamera) {
        mCamera.stopPreview();
        mCamera.stopFaceDetection();
        mCamera.setPreviewCallback(null);
        mCamera.release();
        mCamera = null;
    }
}
  • stopPreview:停止預(yù)覽
  • release:釋放資源

Camera1的開發(fā)上初澎,還是相對比較簡單的秸应,需要定制的功能項比較少,下面一篇開始介紹Camera2的使用碑宴。
文章中涉及到的代碼

參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末软啼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子延柠,更是在濱河造成了極大的恐慌祸挪,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捕仔,死亡現(xiàn)場離奇詭異匕积,居然都是意外死亡盈罐,警方通過查閱死者的電腦和手機榜跌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盅粪,“玉大人钓葫,你說我怎么就攤上這事∑惫耍” “怎么了础浮?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長奠骄。 經(jīng)常有香客問我豆同,道長,這世上最難降的妖魔是什么含鳞? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任影锈,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鸭廷。我一直安慰自己枣抱,他們只是感情好,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布辆床。 她就那樣靜靜地躺著佳晶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪讼载。 梳的紋絲不亂的頭發(fā)上轿秧,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音维雇,去河邊找鬼淤刃。 笑死,一個胖子當著我的面吹牛吱型,可吹牛的內(nèi)容都是我干的逸贾。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼津滞,長吁一口氣:“原來是場噩夢啊……” “哼铝侵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起触徐,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤咪鲜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后撞鹉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疟丙,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年鸟雏,在試婚紗的時候發(fā)現(xiàn)自己被綠了享郊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡孝鹊,死狀恐怖炊琉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情又活,我是刑警寧澤苔咪,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站柳骄,受9級特大地震影響团赏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜耐薯,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一舔清、第九天 我趴在偏房一處隱蔽的房頂上張望隘世。 院中可真熱鬧,春花似錦鸠踪、人聲如沸丙者。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽械媒。三九已至,卻和暖如春评汰,著一層夾襖步出監(jiān)牢的瞬間纷捞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工被去, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留主儡,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓惨缆,卻偏偏與公主長得像糜值,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子坯墨,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

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