Camera2開發(fā)(2)之CameraDevice類

轉(zhuǎn)載請注明出處:http://www.reibang.com/p/cad777db008e
本文出自:m2u的簡書

0x00 說明

該文章為本人個(gè)人學(xué)習(xí)的總結(jié)桅滋,如果遺漏或錯(cuò)誤歡迎在評論區(qū)批評指出or補(bǔ)充儿普。如對您有幫助可以細(xì)看之,如希望直接查看本人的學(xué)習(xí)資料來源式廷,可直接跳到0x05 相關(guān)資料一節(jié)查看舶胀。

0x01 概覽

CameraDevice是連接在安卓設(shè)備上的單個(gè)相機(jī)的抽象表示,CameraDevice支持在高幀率下對捕獲的圖像進(jìn)行細(xì)粒度控制和后期處理.
<p>在Camera2 API中,一個(gè)相機(jī)設(shè)備可能支持的硬件等級有以下幾種(按每個(gè)等級所支持的功能來排序):

LEVEL_3>FULL>LIMIT>LEGACY

按照Google文檔的說法,一般手機(jī)的相機(jī)可能會支持FULLLIMIT,當(dāng)一個(gè)設(shè)備支持到LIMIT,此時(shí)盡管Camera2 API具有更整潔和高效的接口,然而其只暴露出和舊的Camera API功能相當(dāng)?shù)腁PI,與使用舊的API無異赊堪。
而支持到FULL等級的設(shè)備,則提供了比舊的Camera API大大改進(jìn)的功能履澳,比如支持30fps全高清連拍嘶窄,支持幀之間的手動(dòng)設(shè)置,支持RAW格式的圖片拍攝距贷,快門零延遲以及視頻速拍等特性柄冲。只有在支持FULL級別的設(shè)備上才能完全發(fā)揮Camera2的特性。然而經(jīng)過實(shí)測中發(fā)現(xiàn)忠蝗,目前市面上大多安卓手機(jī)都只支持到最低級別LEGACY(估計(jì)是為了兼容android L 以下的系統(tǒng)现横?)......也就是說在這樣的手機(jī)上使用Camera API和Camera2 API并沒有太大區(qū)別,甚至Camera API的發(fā)揮可能還要好一些阁最。不過戒祠,盡管如此,還是推薦使用Camera2 API速种,畢竟舊的Camera API已經(jīng)被打上deprecated標(biāo)簽姜盈,指不定在未來哪個(gè)android的版本中Camera API就被移除了。相機(jī)設(shè)備所支持的硬件等級是由硬件廠商決定的配阵,可以通過以下CameraCharacteristics類獲取機(jī)子上的相機(jī)所支持的硬件等級參數(shù):

CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
int hardwareLevel=characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);

其中managerCameraManager實(shí)例馏颂,關(guān)于CameraManager在上篇文章Camera2開發(fā)(1) --CameraManager類中有介紹。hardwareLevel==1FULL棋傍,hardwareLevel==2LEGACY救拉,hardwareLevel==0LIMIThardwareLevel==3LEVEL_3瘫拣。

0x02 內(nèi)部類

StateCallback

該類用于接收相機(jī)的連接狀態(tài)的更新亿絮。這些狀態(tài)包括一系列的通知如相機(jī)啟動(dòng)結(jié)束(此時(shí)允許調(diào)用CameraDevice.createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)創(chuàng)建一個(gè)捕獲會話),相機(jī)斷開連接或關(guān)閉以及相機(jī)出現(xiàn)異常錯(cuò)誤等麸拄。
在調(diào)用CameraDevice.openCamera(String,CameraDevice.StateCallback,Handler)方法打開相機(jī)時(shí)必須傳入一個(gè)CameraDevice.StateCallback實(shí)例,以用于接收相機(jī)狀態(tài)的更新和后續(xù)的處理派昧。
典型的CameraDevice.StateCallback的聲明和使用如下:

private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback()
{
    @Override
    public void onOpened(@NonNull CameraDevice camera)
    {
        //當(dāng)相機(jī)打開成功之后會回調(diào)此方法
        //一般在此進(jìn)行獲取一個(gè)全局的CameraDevice實(shí)例,開啟相機(jī)預(yù)覽等操作
        mCameraDevice = camera;//獲取CameraDevice實(shí)例
        createCameraPreviewSession();//創(chuàng)建相機(jī)預(yù)覽會話
    } 
    @Override
    public void onDisconnected(@NonNull CameraDevice camera)
    {
        //相機(jī)設(shè)備失去連接(不能繼續(xù)使用)時(shí)回調(diào)此方法感帅,同時(shí)當(dāng)打開相機(jī)失敗時(shí)也會調(diào)用此方法而不會調(diào)用onOpened()
        //可在此關(guān)閉相機(jī)斗锭,清除CameraDevice引用
        camera.close();
        mCameraDevice = null;
    }
    @Override
    public void onError(@NonNull CameraDevice camera, int error)
    {
        //相機(jī)發(fā)生錯(cuò)誤時(shí)調(diào)用此方法
        camera.close();
        mCameraDevice = null;
    }
    @Override
    public void onClosed(CameraDevice camera)
    {
        //相機(jī)完全關(guān)閉時(shí)回調(diào)此方法
        super.onClosed(camera);
    }
};

其中onError(@NonNull CameraDevice camera, int error)中的error參數(shù)代表出錯(cuò)的代碼地淀,可參考Google文檔上的錯(cuò)誤代碼說明失球。

0x03 常量

**int TEMPLATE_MANUAL **
Constant Value: 6 (0x00000006)

用于創(chuàng)建一個(gè)直接控制相機(jī)拍照參數(shù)CaptureRequest請求。使用該模板創(chuàng)建的請求,相機(jī)的所有自動(dòng)控制都會被禁用(例如自動(dòng)曝光实苞,自動(dòng)白平衡豺撑,自動(dòng)對焦等),并將后期處理參數(shù)設(shè)置成預(yù)覽質(zhì)量黔牵。手動(dòng)控制的參數(shù)(曝光聪轿,感光度等)將被設(shè)置成合理的默認(rèn)值,用戶需要根據(jù)自己想要的預(yù)期效果來調(diào)整這些參數(shù)猾浦。
兼容性:TEMPLATE_MANUAL在支持MANUAL_SENSOR功能的設(shè)備上可用陆错。

int TEMPLATE_PREVIEW
Constant Value: 1 (0x00000001)

用于創(chuàng)建一個(gè)相機(jī)預(yù)覽請求。通常情況下金赦,設(shè)置了該模板的預(yù)覽畫面音瓷,相機(jī)會優(yōu)先保證預(yù)覽的幀率。該模板適用于相機(jī)畫面預(yù)覽夹抗,通常將該模板結(jié)合setRepeatingRequest(CaptureRequest, CameraCaptureSession.CaptureCallback, Handler)創(chuàng)建一個(gè)預(yù)覽請求绳慎。
兼容性:TEMPLATE_PREVIEW在所有相機(jī)設(shè)備上均適用。

int TEMPLATE_RECORD
Constant Value: 3 (0x00000003)

用于創(chuàng)建錄制視頻的請求漠烧。使用該模板創(chuàng)建的請求將使用標(biāo)準(zhǔn)幀率杏愤,并且后期處理效果的質(zhì)量將被設(shè)置成錄像級別。
兼容性:TEMPLATE_RECORD可在所有的相機(jī)設(shè)備上使用.已脓。

int TEMPLATE_STILL_CAPTURE
Constant Value: 2 (0x00000002)

用于創(chuàng)建一個(gè)拍照請求珊楼。使用該模板創(chuàng)建的請求會優(yōu)先保證圖像的質(zhì)量,以獲得最好的拍照效果摆舟。
兼容性:可在所有的相機(jī)設(shè)備上使用亥曹。

int TEMPLATE_VIDEO_SNAPSHOT
Constant Value: 4 (0x00000004)

用于創(chuàng)建錄像時(shí)拍照請求。使用該模板創(chuàng)建的請求可以最大化地保證照片的質(zhì)量同時(shí)不會破壞正在錄制的視頻質(zhì)量恨诱。該模板創(chuàng)建的請求通常與CameraCaptureSession.capture(CaptureRequest request, CameraCaptureSession.CaptureCallback callback, Handler handler)結(jié)合使用媳瞪,其中這里的request必須是基于TEMPLATE_RECORD模板創(chuàng)建。
兼容性:硬件支持級別高于LEGACY的所有相機(jī)設(shè)備可用照宝。

int TEMPLATE_ZERO_SHUTTER_LAG
Constant Value: 5 (0x00000005)

用于創(chuàng)建零延遲拍照請求蛇受。使用該模板創(chuàng)建的請求將最大化地保證圖片質(zhì)量并且不會損失預(yù)覽圖像的幀率。此時(shí)自動(dòng)對焦/自動(dòng)白平衡和自動(dòng)曝光都應(yīng)處于auto模式厕鹃。
兼容性:該模板僅在支持PRIVATE_PEPROCESSINGYUV_PEPROCESSING特性的相機(jī)設(shè)備上適用兢仰。

0x04 常用的方法

close()
盡可能快地關(guān)閉當(dāng)前相機(jī)設(shè)備的連接。

調(diào)用該方法之后剂碴,所有調(diào)用處于激活狀態(tài)的sessionCameraDevice其方法的操作都將拋出一個(gè)IllegalStateException異常把将。當(dāng)相機(jī)完全關(guān)閉后,CameraDevice.StateCallback.onClosed(CameraDevice)方法會被調(diào)用忆矛,此時(shí)相機(jī)就緒以等待下一次被打開察蹲。

createCaptureRequest(int templateType)
創(chuàng)建一個(gè)用于構(gòu)建capture request的CaptureRequest.Builder實(shí)例,并用templateType模板初始化該實(shí)例请垛。

該設(shè)置會為當(dāng)前指定的CameraDevice適配最佳的選項(xiàng),因此創(chuàng)建的CaptureRequest不建議重用到其他的CameraDevice以免出錯(cuò)洽议。

參數(shù)說明:

  • templateType:參考0x03 常量一節(jié)宗收。

** createCaptureSession(List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler)**
通過提供給相機(jī)設(shè)備的目標(biāo)輸出surface集合創(chuàng)建一個(gè)新的相機(jī)捕獲會話(CameraCaptureSession)實(shí)例。

當(dāng)前活動(dòng)的capture session決定了相機(jī)的每一個(gè)capture request的輸出surface(每個(gè)capture request的輸出surface都是outputs的一個(gè)子集)亚兄。比如當(dāng)我需要將捕獲數(shù)據(jù)輸出到預(yù)覽surface混稽,則需要將預(yù)覽surface添加到outputs作為createCaptureSession的參數(shù)。
在實(shí)際使用中可根據(jù)不同的用例和輸出目標(biāo)來構(gòu)建surface用于接收相機(jī)輸出的圖像數(shù)據(jù),這里只列出拍照功能可能用到的幾個(gè)审胚,有關(guān)錄像的以后再補(bǔ)充:

  • 繪制到一個(gè)SurfaceView:
    使用SurfaceView來顯示預(yù)覽畫面時(shí)匈勋,應(yīng)在SurfaceViewSurface創(chuàng)建成功后先通過SurfaceHolder設(shè)置其大小,再獲取Surface實(shí)例,如果不設(shè)置膳叨,則相機(jī)會自動(dòng)為其設(shè)置一個(gè)小于且最接近1080p的可用預(yù)覽尺寸:
SurfaceView mSurfaceView = (SurfaceView)findViewById(R.id.surfaceview);
SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder();
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
//獲取所有可用的預(yù)覽尺寸
Size[] sizes=map.getOutputSizes(SurfaceHolder.class);
Size mPreviewSize=sizes[bestSizeIndex];
//設(shè)置surface尺寸
mSurfaceHolder.setFixedSize(mPreviewSize.getWidth(),mPreviewSize.getHeight());
//獲取預(yù)覽的surface
Surface surface=mSurfaceHolder.getSurface();
  • 通過SurfaceTexture來訪問OpenGL texture:
    使用TextureView來顯示預(yù)覽颓影,要確保手機(jī)的硬件加速開啟才能進(jìn)行。
    在創(chuàng)建Surface之前懒鉴,需要先設(shè)置SurfaceTexture的大小诡挂,如果不設(shè)置,則相機(jī)會自動(dòng)為其設(shè)置一個(gè)小于且最接近1080p的可用預(yù)覽尺寸:
//獲取SurfaceTexture
SurfaceTexture texture = mTextureView.getSurfaceTexture();
//獲取所有可用預(yù)覽尺寸
Size[] sizes=map.getOutputSizes(SurfactTexture.class);
Size mPreviewSize=sizes[bestSizeIndex];
//設(shè)置SurfaceTexture大小
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
//獲取預(yù)覽的surface
Surface surface = new Surface(texture);
  • 結(jié)合MediaCodec進(jìn)行錄像:待補(bǔ)充
  • 結(jié)合MediaRecorder進(jìn)行錄像:待補(bǔ)充
  • 結(jié)合android.renderscript進(jìn)行高效的YUV處理:待補(bǔ)充
  • 在程序中訪問RAW格式或未壓縮的YUV或者壓縮的JPEG格式的圖像數(shù)據(jù):
    可創(chuàng)建一個(gè)ImageReader對象临谱,通過ImageReaderSurface來接收相機(jī)圖像并保存圖像數(shù)據(jù):
//************************
//**1.創(chuàng)建ImageReader對象**
//************************
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
//獲取指定格式的所有支持尺寸
Size[] sizes=map.getOutputSizes(ImageFormat.JPEG);
//計(jì)算期望的最佳尺寸璃俗,至于怎么計(jì)算則看具體需求。如果該ImageReader的大小沒有在程序中設(shè)置,
//則當(dāng)前相機(jī)設(shè)備將自動(dòng)為該ImageReader設(shè)置一個(gè)支持的小于1080p的尺寸悉默。
Size largestSize = Collections.max(Arrays.asList(sizes), new CompareSizesByArea());
//創(chuàng)建ImageReader
ImageReader mImageReader = ImageReader.newInstance(largestSize.getWidth(), largestSize.getHeight(), ImageFormat.JPEG,/*maxImages*/2);

//...其他操作

/** 
* 摘自Google Sample:Camera2Basic
* Compares two {@code Size}s based on their areas. 
*/
static class CompareSizesByArea implements Comparator<Size>{
    @Override
    public int compare(Size lhs, Size rhs)
    {
        //We cast here to ensure the multiplications won't overflow
        return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
    }
}

//...其他操作

//************************
//**2.設(shè)置ImageReader.OnImageAvailableListener監(jiān)聽**
//************************
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener()
{
    @Override
    public void onImageAvailable(ImageReader reader)
    {
        //在這里調(diào)用(reader.acquireNextImage()獲取圖像數(shù)據(jù)
        mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));
    }
};

//...其他操作

mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);

//************************
//**3.隨后可通過ImageReader.getSurface()方法獲取Surface**
//************************
Surface surface=mImageReader.getSurface();

參數(shù)說明:

  • outputs
    所有可用于捕獲相機(jī)輸出數(shù)據(jù)的surface集合城豁。
  • callback
    CameraCaptureSession.StateCallback實(shí)例,調(diào)用CameraDevice.createCaptureSession后會回調(diào)callback中相應(yīng)的方法抄课,可在該回調(diào)中處理創(chuàng)建session成功或失敗之后的進(jìn)一步操作唱星。
  • handler
    指定處理該操作的handler

getId()

獲取當(dāng)前相機(jī)設(shè)備的id

0x05 相關(guān)資料

有關(guān)CameraDevice的使用實(shí)例可參考googlesamples/android-Camera2Basic


轉(zhuǎn)載請注明出處:http://www.reibang.com/p/cad777db008e
本文出自:m2u的簡書

20170115 15:45 by m2u

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市跟磨,隨后出現(xiàn)的幾起案子间聊,更是在濱河造成了極大的恐慌,老刑警劉巖抵拘,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哎榴,死亡現(xiàn)場離奇詭異,居然都是意外死亡僵蛛,警方通過查閱死者的電腦和手機(jī)尚蝌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來充尉,“玉大人飘言,你說我怎么就攤上這事⊥障溃” “怎么了姿鸿?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵泵喘,是天一觀的道長。 經(jīng)常有香客問我般妙,道長,這世上最難降的妖魔是什么相速? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任碟渺,我火速辦了婚禮,結(jié)果婚禮上突诬,老公的妹妹穿的比我還像新娘苫拍。我一直安慰自己,他們只是感情好旺隙,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布绒极。 她就那樣靜靜地躺著,像睡著了一般蔬捷。 火紅的嫁衣襯著肌膚如雪垄提。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天周拐,我揣著相機(jī)與錄音铡俐,去河邊找鬼。 笑死妥粟,一個(gè)胖子當(dāng)著我的面吹牛审丘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播勾给,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼滩报,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了播急?” 一聲冷哼從身側(cè)響起脓钾,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎桩警,沒想到半個(gè)月后惭笑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡生真,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年沉噩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柱蟀。...
    茶點(diǎn)故事閱讀 38,646評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡川蒙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出长已,到底是詐尸還是另有隱情畜眨,我是刑警寧澤昼牛,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站康聂,受9級特大地震影響贰健,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜恬汁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一伶椿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧氓侧,春花似錦脊另、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至独郎,卻和暖如春踩麦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背氓癌。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工靖榕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人顽铸。 一個(gè)月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓茁计,卻偏偏與公主長得像,于是被迫代替她去往敵國和親谓松。 傳聞我的和親對象是個(gè)殘疾皇子星压,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評論 2 348

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