注:本文翻譯自Google官方的Android Developers Training文檔,譯者技術一般,由于喜愛安卓而產生了翻譯的念頭,純屬個人興趣愛好。
原文鏈接: http://developer.android.com/training/camera/cameradirect.html
在這節課中,我們討論如何直接通過框架內的API來控制相機硬件。
直接控制一個相機硬件需要的代碼,比通過已存在的相機應用拍攝照片和視頻所需要的代碼要多。然而,如果你希望構建一個特制的相機應用,或者需要將一些東西整合入你的應用界面,那么這節課將會教授你如何去做。
一). 打開一個相機對象
要直接控制相機,首先應當獲得一個相機( Camera )對象的實例。就像Android自己的相機應用所做的,推薦的訪問相機的方法是在 onCreate() 方法中,通過一個獨立的線程來啟動。這個方法的優點在于訪問相機需要一定的時間,這就導致如果在UI線程例訪問相機,可能會造成UI停滯。在一個更加基本的實現中,打開一個相機可以推遲到 onResume() 方法中,使得代碼重用更加方便,同時還能讓控制流更加簡潔。
調用 Camera.open() 后,如果相機已經再被另一個應用使用,那么會拋出一個異常,我們可以在try塊中捕獲它。
private
boolean
safeCameraOpen(
int
id) {
boolean
qOpened =
false
;
try
{
releaseCameraAndPreview();
mCamera
=
Camera.open(id);
qOpened
= (mCamera !=
null
);
}
catch
(Exception e) {
Log.e(getString(R.string.app_name),
"failed to open Camera"
);
e.printStackTrace();
}
return
qOpened;
}
private
void
releaseCameraAndPreview() {
mPreview.setCamera(
null
);
if
(mCamera !=
null
) {
mCamera.release();
mCamera
=
null
;
}
}
從API Level 9之后,相機框架能夠支持多個相機。如果你使用過去的API,并且調用了無傳遞參數的 open() 方法,你會得到第一個后置攝像頭。
二). 創建相機預覽
拍攝照片通常需要讓你的用戶可以在按下快門鍵之前看見一個實時預覽界面。要這樣做,一可以使用 SurfaceView 來繪制相機預覽,顯示傳感器元件捕捉到的實時畫面。
Preview類
要開始顯示一個相機預覽,你需要Preview類。它需要實現
“
android.view.SurfaceHolder.Callback
”
接口,用來將圖像數據從相機硬件傳遞給應用。
class
Preview
extends
ViewGroup
implements
SurfaceHolder.Callback {
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Preview(Context context) {
super
(context);
mSurfaceView
=
new
SurfaceView(context);
addView(mSurfaceView);
//
Install a SurfaceHolder.Callback so we get notified when the
//
underlying surface is created and destroyed.
mHolder =
mSurfaceView.getHolder();
mHolder.addCallback(
this
);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
...
}
Preview類必須在激活的相機預覽啟動之前傳遞給 Camera 對象,這方面知識將在下一節展開。
設置并啟動預覽
一個相機實例和與它相關聯的相機預覽必須以一個特定的順序創建,相機對象在先。在下面的代碼片段中,初始化相機的操作已經封裝好了,所以我們可以看到 Camera.startPreview() 在 setCamera() 方法中被調用,不管何時用戶做了什么事情來改變當前激活的攝像頭。預覽界面必須在preview類中的 surfaceChanged()回調函數中重新啟動。
public
void
setCamera(Camera camera) {
if
(mCamera == camera) {
return
; }
stopPreviewAndFreeCamera();
mCamera
=
camera;
if
(mCamera !=
null
) {
List
<Size> localSizes =
mCamera.getParameters().getSupportedPreviewSizes();
mSupportedPreviewSizes
=
localSizes;
requestLayout();
try
{
mCamera.setPreviewDisplay(mHolder);
}
catch
(IOException e) {
e.printStackTrace();
}
//
Important: Call startPreview() to start updating the preview
//
surface. Preview must be started before you can take a picture.
mCamera.startPreview();
}
}
三). 修改相機設置
相機設置改變相機拍攝照片的方式,相機設置從變焦到曝光補償等等。下面的例子值修改了預覽的尺寸,可以通過閱讀相機源碼來學習更多其他的設置。
public
void
surfaceChanged(SurfaceHolder holder,
int
format,
int
w,
int
h) {
//
Now that the size is known, set up the camera parameters and begin
//
the preview.
Camera.Parameters parameters =
mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
//
Important: Call startPreview() to start updating the preview surface.
//
Preview must be started before you can take a picture.
mCamera.startPreview();
}
四). 設置預覽方向
大多數相機應用會將顯示鎖定在橫屏模式,因為那是攝像頭的自然方向。但這不會令你無法拍攝豎屏模式的照片,因為設備的方向會被記錄在EXIF頭中。 setCameraDisplayOrientation() 方法可以讓你再不影響照片是如何拍攝的情況下改變預覽的方向。然而,在Android API Level 14之前,你必須在改變方向之前停止你的相機預覽,然后重新啟動它。
五). 拍攝照片
一旦相機預覽啟動了,就可以通過 Camera.takePicture() 方法來拍攝照片。你可以創建 Camera.PictureCallback 和 Camera.ShutterCallback 對象,并將它們傳遞給 Camera.takePicture() 。
如果你希望連續抓拍圖像,你可以創建一個實現了 onPreviewFrame() 的 Camera.PreviewCallback 。在這兩件事情之間,你可以值捕獲選中的預覽框,或者設置一個調用 takePicture() 的延遲。
六). 重啟相機預覽
當一個照片拍好后,你必須在用戶拍攝另一張照片之前重啟相機預覽。在下面的例子中,通過重載快門按鈕,實現了重啟的操作:
@Override
public
void
onClick(View v) {
switch
(mPreviewState) {
case
K_STATE_FROZEN:
mCamera.startPreview();
mPreviewState
=
K_STATE_PREVIEW;
break
;
default
:
mCamera.takePicture(
null
, rawCallback,
null
);
mPreviewState
=
K_STATE_BUSY;
}
//
switch
shutterBtnConfig();
}
七). 停止相機預覽并且釋放相機
一旦你的應用完成了相機的拍攝,那么久到了釋放資源的時間了。尤其要注意的是你要釋放相機對象,不然的話你可能會導致其它應用的崩潰,這也包括你自己的應用。
那么什么時候應該停止預覽并釋放相機呢?當你的預覽Surface被銷毀時,那么這是一個信號,你需要停止預覽并釋放相機,見下面的例子,這些方法都來自Preview類:
public
void
surfaceDestroyed(SurfaceHolder holder) {
//
Surface will be destroyed when we return, so stop the preview.
if
(mCamera !=
null
) {
//
Call stopPreview() to stop updating the preview surface.
mCamera.stopPreview();
}
}
/**
* When this function returns, mCamera will be null.
*/
private
void
stopPreviewAndFreeCamera() {
if
(mCamera !=
null
) {
//
Call stopPreview() to stop updating the preview surface.
mCamera.stopPreview();
//
Important: Call release() to release the camera for use by other
//
applications. Applications should release the camera immediately
//
during onPause() and re-open() it during onResume()).
mCamera.release();
mCamera
=
null
;
}
}
中這堂課的前半部分,上述步驟也是“ setCamera() ”方法的一部分,所以初始化一個相機一般都始于停止相機預覽。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

