當我們自定義相機時萍膛,常常使用
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ù)覽界面主要有兩種:TextureView
和SurfaceView
mCamera.setPreviewDisplay(SurfaceHolder);
mCamera.setPreviewTexture(SurfaceTexture);
有關(guān)TextureView
和SurfaceView
會在第四篇
和第五篇
介紹甜刻。
[方法七]
設(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();
startSmoothZoom
和stopSmoothZoom
這兩個方法必須在啟動預(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_MACRO
、FOCUS_MODE_FIXED
披泪、FOCUS_MODE_EDOF
纤子、FOCUS_MODE_CONTINUOUS_VIDEO
、FOCUS_MODE_CONTINUOUS_PICTURE
,這些模式用到的有兩種模式控硼,分別是:FOCUS_MODE_CONTINUOUS_PICTURE
和FOCUS_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
已被廢棄吃媒,改為Camera2
,Camera2
將會在后面章節(jié)會講到坪圾。
[本章完...]