Android 應用程式開發:如何錄製影片

許多 Android 裝置的相機也有錄影功能,不過程式碼會稍微複雜一點。MediaRecorder API 針對聲音和影像提供了錄製控制功能,因此是你在 Android 上所有錄影功能的基礎。查看其 API 文件以了解其狀態機的完整示意圖。雖然 MediaRecorder 幫你做了許多工作,為了使其正常運作,有許多你得按照一定順序進行的步驟,此一教學稍後將加以解說。我們會使用預覽 XML 和來自先前教學的基本應用程式結構。

設定 MediaRecorder

首先,開啓 AndroidManifest.xml,在之前教學中設定的相機權限上,增加錄音權限:

<manifest .... >
  <uses-permission android:name="android.permission.CAMERA" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.RECORD_AUDIO" />
  <uses-feature android:name="android.hardware.camera" />

我們會在 MyCameraActivity.java 中撰寫獨立的方法來處理影片。第一步是為相機解鎖,接著建立新的 MediaRecorder。我們讓這個方法傳回真假布林值,好讓稍後我們要開始錄影前,可以檢查一切是否設定妥當,因此可避免不少可能的錯誤:

private MediaRecorder mr;
protected boolean prepareForVideoRecording() {
  camera.unlock();
  mr = new MediaRecorder();
  mr.setCamera(camera);
}

為相機解鎖這一步是必須的,可以讓 media 程序存取到相機。如果你只是拍照,Camera API 會自動幫你處理好,你只需要在錄影時做這件事。

接著,我們必須對 MediaRecorder 做各種設定:聲音與影像來源、配置 (profile)、輸出檔案、預覽顯示。

private static final int MEDIA_TYPE_VIDEO = 1;
protected boolean prepareForVideoRecording() {
  camera.unlock();
  mr = new MediaRecorder();
  mr.setCamera(camera);
  mr.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
  mr.setVideoSource(MediaRecorder.VideoSource.CAMERA);
  mr.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
  mr.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());
  mr.setPreviewDisplay(preview.getHolder().getSurface());
}

AudioSource 與 VideoSource 就如名稱所示。聲音部分有許多選項,包含 VOICE_CALL 與 MIC,在此我們用 CAMCORDER。在影像上你只有 CAMERA 與 DEFAULT 可以選擇。

setProfile() 是個快捷功能(從 API 8 開始提供),可以讓你一次設定好一連串的錄影與錄音編碼和格式資訊。如果你想手動進行,不管是使用了之前的 API,或是你想要更為細緻的控制,以下是設定範例程式:

mr.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
mr.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mr.setVideoEncoder(MediaRecorder.VideoEncoder.H264);

更多選項請查看 MediaRecorder API 文件。有關哪些選項會被自動設定請見 CamcorderProfile API 文件。

你可以看到呼叫 getOutputMediaFile() 指定了影片輸出檔案類型,目前我們的方法沒有加以處理,以下是額外的程式碼:

private File getOutputMediaFile(int type) {
// Get directory and timestamp as before
  if (type == MEDIA_TYPE_IMAGE) {
    return new File(dir.getPath() + File.separator + "IMG_"  
                    + timeStamp + ".jpg");
  } else if (type == MEDIA_TYPE_VIDEO) {
    return new File(dir.getPath() + File.separator + "VID_"  
                    + timeStamp + ".3gp");
  } else {
    return null;
  }
}

如果你使用了不同的編碼,你可能得更改結尾的檔案類型。最後,預覽就如之前我們所設定的一樣,我們只需呼叫適當方法以便取得所使用的 surface,好讓 MediaRecorder 與其溝通。

錄影

錄影前最後要做的事是準備好 MediaRecorder:

protected boolean prepareForVideoRecording() {
  // as above
  try {
	mr.prepare();
  } catch (IllegalStateException e) {
	Log.e(TAG, "IllegalStateException when preparing MediaRecorder "
          + e.getMessage());
	e.getStackTrace();
	releaseMediaRecorder();
	return false;
  } catch (IOException e) {
    Log.e(TAG, "IOException when preparing MediaRecorder "
          + e.getMessage());
    e.getStackTrace();
	releaseMediaRecorder();
	return false;
  }
  return true;
}
private void releaseMediaRecorder() {
  if (mr != null) {
    mr.reset();
    mr.release();
    mr = null;
    camera.lock();
  }
}

很簡單,我們只是在我們的 MediaRecorder 上呼叫 API 的 prepare() 方法,並處理例外狀況。重要的是記得在任何例外發生時,釋放 MediaRecorder 並回傳 false。在重置並釋放 MediaRecorder 後,我們必須重新鎖住相機,好讓應用程式保留其控制權。記得你必須在暫停時釋放相機,我們在之前教學中已經示範過。

在開始錄影前,我們要在預覽面板 (preview pane) 上加入按鈕,並設定該按鈕來停止或開始錄影:

private Button recordVideoButton;
private boolean isRecording = false;
private void setUpLayout() {
  // as in previous tutorials
  setUpVideoButton();
}
private void setUpVideoButton() {
  Button recordVideoButton = (Button) findViewById(R.id.button_video);
  setUpButton(recordVideoButton, "Start video");
  recordVideoButton.setOnClickListener(
    new View.OnClickListener() {
      public void onClick(View v) {
        if (isRecording) {
          mr.stop();
          releaseMediaRecorder();
          camera.lock();
          recordVideoButton.setText("Start video");
          isRecording = false;
        } else {
          if (prepareForVideoRecording()) {
             mr.start();
             recordVideoButton.setText("Stop video");
             isRecording = true;
          } else {
             // Something has gone wrong! Release the camera
             releaseMediaRecorder();
             Toast.makeText(MyCameraActivity.this,
                            "Sorry: couldn't start video",
                            Toast.LENGTH_LONG).show();
          }
        }
      }
    }
  );	
}

你也必須把按鈕加到 XML 中。上面的程式碼讓我們用同一個按鈕來開始與停止錄影。這表示不管是否正在錄影中,該按鈕都會顯示出來,這是個最大化用戶資訊,同時最小化螢幕空間使用的便利方式。如果應用程式已經在錄影,當按鈕被點選,表示用戶希望停止錄影。於是我們停止並釋放 MediaRecorder,重新鎖定相機,改變按鈕文字並重置 isRecording。

如果應用程式沒在錄影,我們希望開始錄影。假如設定方法傳回的是 true,也就是 MediaRecorder 已準備妥當,我們就開始錄影,改變按鈕文字並重設 isRecording。如果 MediaRecorder 沒設定好,我們再次將其釋放,顯示一個 Toast 訊息讓用戶得知問題所在。

和 Camera 相片儲存有所不同的是,對於 MediaRecorder,傳入儲存的檔案名稱就會自動處理好影片的儲存,你不需要自行處理儲存功能。不過,它所做的只是存入你所提供的檔名中。如果你希望對影片做其他處理,像是秀給用戶看或讓他們編輯,你必須進一步擴展應用程式以達成這些功能。


原文網址:https://www.linux.com/learn/tutorials/729988-android-app-development-how-to-capture-video



您也許有興趣閱讀以下文章:




自由軟體鑄造場電子報 : 第 225 期 Android 應用程式開發:如何錄製影片

分類: 技術專欄