說明
最近在學習音視頻相關知識,把一些需要注意的點記錄一下方便後續查閱,可能有些翻譯不準確,如有錯誤歡迎指正,後面不再說明。以下內容都是摘自官方API文檔。
正文
如果要訪問設備的相機,首先要添加Manifest.permission.CAMERA權限,如果是6.0以上不要忘記權限申請,還有就是要包含 清單元素聲明在你的應用中使用的相機功能。例如,你使用了相機及自動對焦功能,你的清單文件應該包含下面幾項:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
使用相機類拍照的步驟如下
- 使用open(int)方法獲取一個Camera實例
- 使用getParameters()方法獲取現有(默認)的設置
- 如有必要,修改返回的 Camera.Parameters 對象並調用 setParameters(Camera.Parameters)方法
- 調用 setDisplayOrientation(int) 方法保證正確的預覽方向
- 重要:給setPreviewDisplay(SurfaceHolder)方法傳一個完全初始化的SurfaceHolder。沒有surface,相機將不能開始預覽。
- 重要:調用 startPreview() 方法開始更新預覽顯示。在你能夠拍照之前必須要先開始預覽。
- 當你想要通過調用 takePicture(Camera.ShutterCallback, Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback) 方法來捕獲一張照片時。等待回調返回真實的圖像數據。
- 拍照後預覽顯示將停止,如果想拍更多的照片,請再次調用startPreview() 方法
- 調用 stopPreview() 停止更新預覽顯示
- 重要:調用 release() 方法釋放相機以供其他應用使用。應用應該在Activity.onPause()方法立即釋放相機( 並在 Activity.onResume()方法重新創建).
快速切換到錄像模式步驟如下
- 跟上面拍照步驟一樣獲取一個相機實例並開始預覽
- 調用 unlock() 方法來允許媒體進程訪問相機
- 將相機實例傳遞給MediaRecorder.setCamera(Camera)
- 錄製完成後,調用 reconnect() 方法重新獲取並鎖定相機
- 如果需要,請重新開始預覽拍攝更多的照片和視頻
- 跟拍照描述的那樣調用 stopPreview() 和 release()
Camera類非線程安全,適用於事件線程。大多數長時間運行的操作(如預覽、對焦、拍照等)都是異步發生的,並在需要時調用回調。回調會在調用 open(int) 的事件線程中調用。一定不要同時在多個線程中調用Camera類的方法。
檢查相機狀態的一些方法
1檢查相機固件
/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
2訪問相機
要訪問主攝像頭,請使用Camera.open()方法並確保捕獲任何異常,如下面的代碼所示:
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
} catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
警告:適用Camera.open()時請務必要檢查異常。如果相機正在使用或不存在導致檢查異常失敗,系統將會關閉你的應用。
如果一個設備上有多個相機,上面的代碼會訪問第一個後攝像頭。
3創建一個基本的相機預覽類
/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
4拍照
如果想要實現一個JPEG格式的圖片,你首先要實現Camera.PictureCallback接口用來接收圖像數據並寫入到文件,請看下面的示例:
private PictureCallback mPicture = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null){
Log.d(TAG, "Error creating media file, check storage permissions");
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
};
下面是調用拍照的方法
// get an image from the camera
mCamera.takePicture(null, null, mPicture);
5MediaRecorder錄製視頻
使用MediaRecorder類錄製視頻時,必須要按照特定的順序執行配置。下面的示例演示了怎麼正確的配置並準備MediaRecorder類來錄製視頻:
private boolean prepareVideoRecorder(){
mCamera = getCameraInstance();
mMediaRecorder = new MediaRecorder();
// Step 1: Unlock and set camera to MediaRecorder
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);
// Step 2: Set sources
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
// Step 4: Set output file
mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());
// Step 5: Set the preview output
mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());
// Step 6: Prepare configured MediaRecorder
try {
mMediaRecorder.prepare();
} catch (IllegalStateException e) {
Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
releaseMediaRecorder();
return false;
} catch (IOException e) {
Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
releaseMediaRecorder();
return false;
}
return true;
}
6使用相機功能
大部分相機功能可以通過 Camera.Parameters 對象激活並控制。你可以首先通過相機對象獲得 Camper.Parameters 對象的實例,然後調用 getParameters() 方法,修改返回的參數對象並重新設置給相機對象。示例代碼如下:
// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
// set the focus mode
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
mCamera.setParameters(params);