Camera開發系列之一-顯示攝像頭實時畫面php
Camera開發系列之三-相機數據硬編碼爲h264android
Camera開發系列之四-使用MediaMuxer封裝編碼後的音視頻到mp4容器git
Camera開發系列之五-使用MediaExtractor製做一個簡易播放器github
Camera開發系列之七-使用GLSurfaceviw繪製Camera預覽畫面 最近一直在作安卓攝像頭方面的功能,不得不說這裏面的坑簡直多的一批,要注意的地方簡直不要太多,能夠說是從入門到入土系列。總之,這玩意兒差點要個人老命。api
本系列文章使用的都是使用android.hardware.Camera包下面的api,並無使用Camer2。主要是考慮到兼容性問題,另一個很重要的緣由是我還沒看camera2的文檔,啥都不會=_=。app
本片文章主要分爲如下幾個小點講解:框架
在開發設備相機以前,你須要在Mainfest中申明以下權限:ide
<uses-permission android:name="android.permission.CAMERA" />
複製代碼
固然,上面是最基本的權限,若是你的應用須要保持照片或者視頻到設備存儲中,你必須在Manifest指定文件的寫權限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
複製代碼
若是還須要錄像功能,則要添加錄音權限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
複製代碼
固然若是你須要拍攝的照片記錄地理位置,你一樣須要申請以下權限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
複製代碼
申明權限以後,就可使用camera相關的api了
在用相機以前,先要幹什麼呢?固然是要先檢測該設備是否有相機硬件,別說你的手機都有,你作的應用是否是你一我的使用你內心沒有一點13數麼?若是有相機硬件,才進一步去訪問相機,以下是檢測相機硬件是否存在是代碼示例:
private boolean checkCameraHardware(Context context) { if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
return true;
} else {
return false;
}
}
複製代碼
Android 設備能夠有多個相機硬件,如今通常手機都是先後兩個camera,後置攝像頭通常設備id爲0,前置攝像頭通常設備id爲1。爲了訪問相機基本功能,可使用Camera的open()方法來得到一個Camera的實例。
try {
Camera camera = Camera.open(mCamerId);
}catch (Exception e){
LogUtil.i("攝像頭被佔用");
e.printStackTrace();
}
複製代碼
這裏記得要捕獲一下異常,有可能其餘應用程序佔用了相機而crash。
一旦你能夠成功訪問相機設備,你可使用Camera#getParameters()方法來獲取相機參數信息,能夠根據 返回值 Camera.Parameters 類來查看當前camea支持哪些參數設置等。也可使用Camera#setParameters方法給相機設置相應的參數。
private void initCamera(int width,int height){
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewFormat(ImageFormat.NV21);
//根據設置的寬高 和手機支持的分辨率對比計算出合適的寬高算法
Camera.Size optionSize = CameraUtil
.getInstance(mCamera, mCamerId)
.getOptimalPreviewSize(width, height);
parameters.setPreviewSize(optionSize.width, optionSize.height);
//設置照片尺寸
parameters.setPictureSize(optionSize.width, optionSize.height);
//設置實時對焦 部分手機不支持會crash
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mCamera.setParameters(parameters);
//開啓預覽
mCamera.startPreview();
}
複製代碼
相機準備就緒,可是,還差最後一步,爲了有效的拍照或者錄像,咱們必須在屏幕上能看到相機的預覽。一個相機預覽類是由SurfaceView控件來實時顯示來自camera的預覽數據,如此咱們才能看到每一幀數據和捕獲圖片或者視頻。
mSurfaceView = findViewById(R.id.surfaceView);
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(new SurfaceCallback());
複製代碼
SurfaceCallback是個什麼呢?SurfaceCallback繼承SurfaceView.Callback接口類,而且須要實現裏面的接口方法以便監聽SurfaceView控件的建立以及銷燬事件的回調,在回調方法中關聯相機預覽顯示。
private class SurfaceCallback implements SurfaceHolder.Callback {
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera = Camera.open(mCamerId);
}catch (Exception e){
LogUtil.i("攝像頭被佔用");
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
try {
initCamera(mSurfaceView.getWidth(),mSurfaceView.getHeight());
mCamera.setPreviewDisplay(holder);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
複製代碼
佈局文件很簡單:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
<SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" />
</LinearLayout>
複製代碼
如今就能夠點擊運行了,運行以後你會看到以下效果:
咦,怎麼回事,畫面怎麼是旋轉的,是代碼有問題嗎?nonono,兄弟不要慌,camera 預覽默認的方向是橫屏的,故在該例子中佈局指定水平方向以及固定該應用爲橫屏顯示。爲了簡便渲染camera預覽,你能夠在manifest配置文件中指定Activity的方向爲橫屏。
<activity android:name=".MainActivity" android:screenOrientation="landscape">
複製代碼
也可使用以下方法,在startPreview()調用以前調用該方法:
/** * 獲得攝像頭默認旋轉角度後,旋轉回來 注意是逆時針旋轉 * * @param activity */
public void setCameraDisplayOrientation(Activity activity) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(mCameraId, info);
int rotation = activity.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;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
LogUtil.i("攝像頭被旋轉的角度;" + result);
mOrienta = result;//該值有其它用途
mCamera.setDisplayOrientation(result);
}
複製代碼
爲了美觀,弄個全屏主題~
<!--全屏-->
<style name="FullScreenTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowFullscreen">true</item> <item name="android:windowNoTitle">true</item> </style>
複製代碼
最後,使用完camera以後記得釋放camera資源。
if (null != camera) {
camera.stopPreview();
camera.release();
camera = null;
}
複製代碼
項目地址:github 歡迎start和fork