1. 程式人生 > >Android自定義相機(三) —— 錄影

Android自定義相機(三) —— 錄影

前面我們已經大致完成了自定義相機的拍照功能,接下來,我們來實現一下錄影的功能。

1、錄影功能簡介

錄影功能的是相對比較簡單,因為步驟是很固定的,google給我們提供的api文件中說的也比較詳細,這裡我們主要用到 MediaRecorder 這個類。

MediaRecorder的狀態圖

這裡寫圖片描述

同時還給我們提供了示例用法

這裡寫圖片描述

2、程式碼實現

接下來我們就照著api中的示例做就可以了

(一)開始錄影

private MediaRecorder mMediaRecorder;
    private boolean isRecord = false;
    //開始錄影
    public
void startRecord(){ mCamera.unlock(); isRecord = true; mMediaRecorder = new MediaRecorder(); mMediaRecorder.reset(); mMediaRecorder.setCamera(mCamera); //錄製的視訊的角度,要自行旋轉,否則與預覽角度不同 mMediaRecorder.setOrientationHint(90); if(cameraId == CameraInfo.CAMERA_FACING_FRONT){ mMediaRecorder.setOrientationHint(270
); } mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // 設定錄影的質量(解析度,幀數) /** * 下面兩行程式碼的設定也可以具體寫: * mMediaRecorder.setVideoSize(320, 240);//解析度 * mMediaRecorder.setVideoFrameRate(5);//幀數 * 用別人的demo是沒有問題的,但是我自己寫的過程中總是出蜜汁BUG, * 而且各種方法都試了也無法解決,只能放棄了 */
CamcorderProfile mCamcorderProfile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_720P); mMediaRecorder.setProfile(mCamcorderProfile); // 設定視訊檔案輸出的路徑 mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()); // 設定捕獲視訊影象的預覽介面 mMediaRecorder.setPreviewDisplay(holder.getSurface()); try { mMediaRecorder.prepare(); } catch (Exception e) { isRecord = false; e.printStackTrace(); mCamera.lock(); } mMediaRecorder.start(); } //------------------------ 分割線 -------------------------- private static final int MEDIA_TYPE_IMAGE = 1;//圖片型別 private static final int MEDIA_TYPE_VIDEO = 2;//視訊型別 //獲取檔案儲存的位置,目錄不存在就建立 private File getOutputMediaFile(int type) { File mediaFile = null; if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ String filePath = "/sdcard/WaterCamera"; String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); if (type == MEDIA_TYPE_IMAGE){ mediaFile = new File(filePath + File.separator + "IMG_"+ timeStamp + ".jpg"); } else if(type == MEDIA_TYPE_VIDEO) { mediaFile = new File(filePath + File.separator + "VID_"+ timeStamp + ".mp4"); } if(!mediaFile.exists()){ if(!mediaFile.getParentFile().exists()){ mediaFile.getParentFile().mkdirs(); } try { mediaFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } } return mediaFile; }

(二)結束錄影

//停止錄影
public void stopRecord(){
    if(mMediaRecorder !=null){
           if(isRecord){
               mMediaRecorder.stop();
               mMediaRecorder.reset();
               mMediaRecorder.release();
               mMediaRecorder =null;
               isRecord = false;
           }
       }
    //重新設定預覽,否則會出現連續拍照崩潰的問題
    mCamera.stopPreview();//停掉原來攝像頭的預覽
       mCamera.release();//釋放資源
       mCamera = null;
    //重新預覽
    mCamera = Camera.open(cameraId);
    setCameraParams(this.getWidth(),this.getHeight());
    try {
        mCamera.setPreviewDisplay(holder);
    } catch (IOException e) {
        e.printStackTrace();
    }
    mCamera.startPreview();
}

3、遇到的問題

雖然步驟很簡單,但是也有一些坑,最常見的就是 start failed: -19 這個錯誤了:

這裡寫圖片描述

這個問題真是困擾了我一段時間,肯定是start之前設定有問題,主要問題還是出在這兩行程式碼:

mMediaRecorder.setVideoSize(320, 240);//解析度
mMediaRecorder.setVideoFrameRate(5);//幀數

用這種方式寫,無論是想根據攝像頭支援的解析度列表裡面找合適的尺寸我這裡都會出現bug,網上也有說註釋掉這兩句,或者新增camera.lock()和camera.unlock()之類的都不管用,不過在別人的demo裡面這麼寫是完全正常的,後來還是看別人的寫法,採用這種寫法,才沒報錯:

CamcorderProfile mCamcorderProfile = CamcorderProfile.get(cameraId,
CamcorderProfile.QUALITY_720P);
mMediaRecorder.setProfile(mCamcorderProfile);

在上面程式碼的引數CamcorderProfile.QUALITY_720P是可以自己調節的,一半是CamcorderProfile.QUALITY_HIGH,但是我設定成這個引數會導致預覽介面影象被壓縮,所以就找了個看著比較正常的填了進去。

小結

錄影功能基本算是完成了,雖然很粗糙,下面貼一下我的自定義的surfaceview吧,用法比較簡單,在layout中引用,Activity中用 CameraSurfaceView.getInstance() 獲取物件然後點出方法就可以。
連結:
CameraSurfaceView.java
MatrixUtils.java