1、需求背景
有必要講一下需求的背景,防止被想歪。
背景:在一塊Android的開發板上,有HDMI的輸入接口,驅動層已經作了封裝,將HDMI輸入的視頻源轉成CameraApi提供給應用層調用;也就是說在Android應用中,只需調用攝像頭,就能夠獲取視頻源;
需求:要求在不展現界面的狀況下(Service中),對視頻源進行截屏,也就是拍照。session
2、探索過程
板子上Android的版本是6.0;攝像頭的Api是Camera2.0。
經過谷歌官方的例子,能夠看到一個正常拍照的流程以下
openCamera(開啓設備,啓動HandleThread)->
createCameraPreviewSession(建立預覽會話)->
setRepeatingRequest(開始預覽)->
capatrue(拍照請求)ide
考慮需求,着重看了createCameraPreviewSession這一步,其中部分代碼以下:工具
// This is the output Surface we need to start preview. Surface surface = new Surface(texture); // We set up a CaptureRequest.Builder with the output Surface. mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE\_PREVIEW); mPreviewRequestBuilder.addTarget(surface); // Here, we create a CameraCaptureSession for camera preview. mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback()
能夠看到,createCaptureSession方法中第一個參數爲surface列表,代碼中列表中爲,預覽界面及拍照存儲的Surface;
爲在Service中拍照,天然沒有預覽的界面,因此把列表中的第一個用於預覽的surface刪除,保留用於保存文件的surface:oop
camera.createCaptureSession(Arrays.asList(imageReaderSurface), new CameraCaptureSession.StateCallback()
第二點在於改按鈕觸發爲直接拍照,原有代碼中,是先進行預覽的請求TEMPLATE_PREVIEW,然後按鈕觸發再發出TEMPLATE_STILL_CAPTURE獲取靜態畫面,咱們改爲在建立會話的回調中,一旦狀態就緒,就發出保存圖片的請求:fetch
//獲取ImageReader的Surface Surface imageReaderSurface = mImageReader.getSurface(); mCaptureRequestBuilder = camera.createCaptureRequest(CameraDevice .TEMPLATE_STILL_CAPTURE); //CaptureRequest添加imageReaderSurface, // 不加的話就會致使ImageReader的onImageAvailable // ()方法不會回調 mCaptureRequestBuilder.addTarget(imageReaderSurface); camera.createCaptureSession(Arrays.asList(imageReaderSurface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { try { session.capture(mCaptureRequestBuilder.build(), null, null); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { } }, null);// 關閉相機時別忘了關閉ImageReader } catch (CameraAccessException e) { e.printStackTrace(); }
代碼中的mCaptureRequestBuilder設置爲TEMPLATE_STILL_CAPTURE捕獲靜態畫面捕捉。
全過程爲在Service中create中打開攝像頭,攝像頭開啓完畢後,創建捕獲對話,完成後發送請求保存文件,
至此需求就完成了。
3、延申
一、涉及以下的知識點
a:SurfaceView、TextureView、View的區別
官方的代碼中,使用了TextureView來進行預覽ui
b:HandlerThread
HandlerThread爲綁定了Handler的線程,本拍照程序中,應用在後臺啓動HandlerThread,主線程中在完成了相應的準備後,經過thread綁定的handler向其發送消息。
HandlerThread和Thread的不一樣在於內部有Looper和Handler,能夠接收消息。至關於把綁定handler和thread的操做封裝到內部。
spa
二、安利工具:DocFetch-文件內容搜索器
寫這篇博客的時候,離當時研究這個需求已通過去了一年多,項目文檔已經淹沒在大批的項目中找不到了,只能記得文件裏面關於createCaptureSession的內容,經過文件搜索沒法定位,只能去找查找文件內容的工具,最後找到了DocFetch;
在工程目錄創建索引花了10幾分鐘,以後順利得找到了須要的工程。
具體的操做能夠看參考連接中的文章。
4、參考連接
HandlerThread解析
Everything+Docfetcher 文檔查找兩把利器線程