Android 架構支援裝置上的各種相機和相機功能,可讓您在應用程式中拍攝相片和影片。本文將說明快速、簡單的圖片和影片拍攝方法,並概述為使用者建立自訂相機體驗的進階方法。
注意:本頁面說明已淘汰的 Camera 類別。建議使用 CameraX Jetpack 程式庫,或在特定用途使用 camera2 類別。CameraX 和 Camera2 均適用於 Android 5.0 (API 級別 21) 以上版本。
請參閱下列相關資源:
注意事項
在啟用應用程式以使用 Android 裝置上的相機之前,您應考慮幾個關於應用程式如何使用此硬體功能的問題。
- 相機需求:相機的使用對應用程式是否非常重要,以至於您不希望應用程式安裝在沒有相機的裝置上?如果是,請在資訊清單中宣告相機需求。
- 快速拍照或自訂相機:應用程式會如何使用相機?您只是想快速拍攝相片或短片,還是應用程式會提供新的相機使用方式?如要快速拍攝相片或短片,建議使用現有的相機應用程式。如要開發自訂相機功能,請參閱「建構相機應用程式」一節。
- 前景服務規定:應用程式何時會與相機互動?在 Android 9 (API 級別 28) 以上版本中,在背景執行的應用程式無法存取相機。因此,您應該在應用程式位於前景時,或在前景服務中使用相機。
- 儲存空間:應用程式產生的圖片或影片是否僅供應用程式本身查看,或可供其他應用程式 (例如相片庫或其他媒體和社交應用程式) 使用?即使應用程式已解除安裝,您是否仍希望保留相片和影片?請參閱「儲存媒體檔案」一節,瞭解如何實作這些選項。
基本概念
Android 架構支援透過 android.hardware.camera2 API 或相機 Intent 擷取圖片和影片。以下是相關類別:
android.hardware.camera2- 這個套件是用於控制裝置相機的主要 API。建構相機應用程式時,可用於拍攝相片或影片。
Camera- 這個類別是已淘汰的舊版 API,用於控制裝置相機。
SurfaceView- 這個類別用於向使用者顯示即時相機預覽畫面。
MediaRecorder- 這個類別用於錄製相機影片。
IntentMediaStore.ACTION_IMAGE_CAPTURE或MediaStore.ACTION_VIDEO_CAPTURE的意圖動作類型可用於擷取圖片或影片,而不直接使用Camera物件。
資訊清單宣告
使用 Camera API 開發應用程式前,請務必在資訊清單中加入適當宣告,允許使用相機硬體和其他相關功能。
- 相機權限:應用程式必須要求使用裝置相機的權限。
<uses-permission android:name="android.permission.CAMERA" />
注意:如果您是叫用現有的相機應用程式來使用相機,則應用程式不需要要求這項權限。
- 相機功能:應用程式也必須宣告使用相機功能,例如:
<uses-feature android:name="android.hardware.camera" />
如需相機功能清單,請參閱資訊清單功能參考資料。
在資訊清單中加入相機功能後,Google Play 會禁止將應用程式安裝到沒有相機,或不支援指定相機功能的裝置。如要進一步瞭解如何搭配 Google Play 使用依功能篩選,請參閱「Google Play 和依功能篩選」。
如果應用程式可以使用相機或相機功能正常運作,但並非必要,請在資訊清單中加入
android:required屬性,並將其設為false:<uses-feature android:name="android.hardware.camera" android:required="false" />
- 儲存空間權限:如果應用程式指定 Android 10 (API 級別 29) 以下版本,並在資訊清單中指定下列內容,則可將圖片或影片儲存至裝置的外部儲存空間 (SD 卡)。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- 錄音權限:如要錄製音訊和擷取影片,應用程式必須要求音訊擷取權限。
<uses-permission android:name="android.permission.RECORD_AUDIO" />
-
位置存取權:如果應用程式會為圖片加上 GPS 位置資訊標記,您必須要求
ACCESS_FINE_LOCATION權限。請注意,如果應用程式指定 Android 5.0 (API 級別 21) 以上版本,您也必須宣告應用程式使用裝置的 GPS:<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> ... <!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --> <uses-feature android:name="android.hardware.location.gps" />
如要進一步瞭解如何取得使用者位置,請參閱「位置策略」。
使用現有的相機應用程式
如要在應用程式中快速啟用拍照或錄影功能,而不需編寫大量額外程式碼,可以使用 Intent 叫用現有的 Android 相機應用程式。詳情請參閱「輕鬆拍照」和「輕鬆錄影」訓練課程。
建構相機應用程式
部分開發人員可能需要根據應用程式外觀自訂相機使用者介面,或提供特殊功能。自行編寫拍照程式碼,可為使用者提供更具吸引力的體驗。
注意:以下指南適用於已淘汰的舊版 Camera API。如果是新的或進階相機應用程式,建議使用較新的 android.hardware.camera2 API。
為應用程式建立自訂相機介面的一般步驟如下:
- 偵測及存取相機:建立程式碼,檢查相機是否存在並要求存取權。
- 建立預覽類別:建立可擴充
SurfaceView並實作SurfaceHolder介面的相機預覽類別。這個類別會預覽攝影機的即時影像。 - 建構預覽版面配置:取得相機預覽類別後,請建立檢視畫面版面配置,納入預覽畫面和所需的使用者介面控制項。
- 設定擷取事件監聽器:為介面控制項連結監聽器,以便在使用者執行動作 (例如按下按鈕) 時,開始擷取圖片或影片。
- 擷取及儲存檔案:設定用於擷取圖片或影片並儲存輸出的程式碼。
- 釋出相機:使用相機後,應用程式必須正確釋出相機,供其他應用程式使用。
相機硬體是共用資源,必須謹慎管理,以免應用程式與其他可能也想使用相機的應用程式發生衝突。以下各節將說明如何偵測相機硬體、如何要求相機存取權、如何拍攝相片或影片,以及如何在應用程式使用完畢後釋出相機。
注意:應用程式使用完畢後,請務必呼叫 Camera.release() 釋出 Camera 物件!如果應用程式未正確釋出相機,後續所有嘗試存取相機的行為 (包括您自己的應用程式) 都會失敗,並可能導致您或其他應用程式關閉。
偵測相機硬體
如果應用程式並未透過資訊清單宣告明確要求相機,則應在執行階段檢查相機是否可用。如要執行這項檢查,請使用 PackageManager.hasSystemFeature() 方法,如以下程式碼範例所示:
Kotlin
/** Check if this device has a camera */ private fun checkCameraHardware(context: Context): Boolean { if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) { // this device has a camera return true } else { // no camera on this device return false } }
Java
/** 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; } }
Android 裝置可以有多個相機,例如用於拍照的後置鏡頭,以及用於視訊通話的前置鏡頭。Android 2.3 (API 級別 9) 以上版本可讓您使用 Camera.getNumberOfCameras() 方法,檢查裝置上可用的相機數量。
存取攝影機
如果您已確定執行應用程式的裝置有相機,則必須取得 Camera 的執行個體,要求存取相機 (除非您使用意圖存取相機)。
如要存取主要相機,請使用 Camera.open() 方法,並務必擷取任何例外狀況,如以下程式碼所示:
Kotlin
/** A safe way to get an instance of the Camera object. */ fun getCameraInstance(): Camera? { return try { Camera.open() // attempt to get a Camera instance } catch (e: Exception) { // Camera is not available (in use or does not exist) null // returns null if camera is unavailable } }
Java
/** 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() 時,請務必檢查是否有例外狀況。如果攝影機正在使用中或不存在,未檢查例外狀況會導致系統關閉應用程式。
在搭載 Android 2.3 (API 級別 9) 以上版本的裝置上,您可以使用 Camera.open(int) 存取特定相機。上述範例程式碼會存取裝置上第一個後置鏡頭 (如果裝置有多個鏡頭)。
檢查相機功能
取得相機存取權後,您可以使用 Camera.getParameters() 方法進一步瞭解其功能,並檢查傳回的 Camera.Parameters 物件是否支援所需功能。使用 API 級別 9 以上版本時,請使用 Camera.getCameraInfo() 判斷相機位於裝置正面或背面,以及圖片的方向。
建立預覽類別
使用者必須能看到裝置相機拍攝的畫面,才能有效拍照或錄影。相機預覽類別是 SurfaceView,可顯示來自相機的即時圖片資料,方便使用者構圖及拍攝相片或影片。
以下程式碼範例說明如何建立可納入 View 版面配置的基本相機預覽類別。這個類別會實作 SurfaceHolder.Callback,以便擷取建立及刪除檢視畫面的回呼事件,這些事件是指定相機預覽輸入內容時所需。
Kotlin
/** A basic Camera preview class */ class CameraPreview( context: Context, private val mCamera: Camera ) : SurfaceView(context), SurfaceHolder.Callback { private val mHolder: SurfaceHolder = holder.apply { // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. addCallback(this@CameraPreview) // deprecated setting, but required on Android versions prior to 3.0 setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS) } override fun surfaceCreated(holder: SurfaceHolder) { // The Surface has been created, now tell the camera where to draw the preview. mCamera.apply { try { setPreviewDisplay(holder) startPreview() } catch (e: IOException) { Log.d(TAG, "Error setting camera preview: ${e.message}") } } } override fun surfaceDestroyed(holder: SurfaceHolder) { // empty. Take care of releasing the Camera preview in your activity. } override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { // 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.surface == null) { // preview surface does not exist return } // stop preview before making changes try { mCamera.stopPreview() } catch (e: Exception) { // 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 mCamera.apply { try { setPreviewDisplay(mHolder) startPreview() } catch (e: Exception) { Log.d(TAG, "Error starting camera preview: ${e.message}") } } } }
Java
/** 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()); } } }
如要為相機預覽設定特定大小,請在 surfaceChanged() 方法中設定,如上方註解所述。設定預覽大小時,必須使用 getSupportedPreviewSizes() 中的值。請勿在 setPreviewSize() 方法中設定任意值。
注意:
Android 7.0 (API 級別 24) 以上版本推出
多視窗模式功能後,即使呼叫 setDisplayOrientation(),也無法再假設預覽畫面的顯示比例與活動相同。
視視窗大小和顯示比例而定,您可能需要使用上下黑邊版面配置,將寬螢幕相機預覽畫面調整為直向版面配置,反之亦然。
在版面配置中加入預覽畫面
相機預覽類別 (例如上一節所示範例) 必須與其他用於拍照或錄影的使用者介面控制項,一起放在活動的版面配置中。本節說明如何為預覽畫面建構基本版面配置和活動。
下列版面配置程式碼提供非常基本的檢視畫面,可用於顯示相機預覽畫面。在這個範例中,FrameLayout 元素是相機預覽類別的容器。這種版面配置類型可讓您在即時相機預覽圖片上,疊加其他圖片資訊或控制項。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" > <FrameLayout android:id="@+id/camera_preview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" /> <Button android:id="@+id/button_capture" android:text="Capture" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> </LinearLayout>
在大多數裝置上,相機預覽畫面的預設方向為橫向。這個範例版面配置指定水平 (橫向) 版面配置,而下方程式碼會將應用程式的方向固定為橫向。為簡化相機預覽畫面的算繪作業,請在資訊清單中加入下列內容,將應用程式的預覽活動方向變更為橫向。
<activity android:name=".CameraActivity" android:label="@string/app_name" android:screenOrientation="landscape"> <!-- configure this activity to use landscape orientation --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
注意:相機預覽畫面不一定要採用橫向模式。從 Android 2.2 (API 級別 8) 開始,您可以使用 setDisplayOrientation() 方法設定預覽圖片的旋轉角度。如要在使用者重新調整手機方向時變更預覽方向,請在預覽類別的 surfaceChanged() 方法中,先使用 Camera.stopPreview() 停止預覽,變更方向,然後再使用 Camera.startPreview() 重新啟動預覽。
在相機檢視畫面的活動中,將預覽類別新增至上例所示的 FrameLayout 元素。此外,攝影機活動也必須確保在暫停或關閉時釋出攝影機。以下範例說明如何修改相機活動,以附加「建立預覽類別」一節中顯示的預覽類別。
Kotlin
class CameraActivity : Activity() { private var mCamera: Camera? = null private var mPreview: CameraPreview? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Create an instance of Camera mCamera = getCameraInstance() mPreview = mCamera?.let { // Create our Preview view CameraPreview(this, it) } // Set the Preview view as the content of our activity. mPreview?.also { val preview: FrameLayout = findViewById(R.id.camera_preview) preview.addView(it) } } }
Java
public class CameraActivity extends Activity { private Camera mCamera; private CameraPreview mPreview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Create an instance of Camera mCamera = getCameraInstance(); // Create our Preview view and set it as the content of our activity. mPreview = new CameraPreview(this, mCamera); FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview); preview.addView(mPreview); } }
注意:上述範例中的 getCameraInstance() 方法是指「存取相機」中顯示的範例方法。
拍攝相片
建構預覽類別和用於顯示預覽畫面的檢視區塊版面配置後,即可開始使用應用程式擷取圖片。在應用程式程式碼中,您必須為使用者介面控制項設定事件監聽器,以便透過拍照來回應使用者動作。
如要擷取相片,請使用 Camera.takePicture() 方法。這個方法會採用三個參數,從相機接收資料。如要接收 JPEG 格式的資料,您必須實作 Camera.PictureCallback 介面,才能接收圖片資料並寫入檔案。下列程式碼顯示 Camera.PictureCallback 介面的基本實作,用於儲存從相機接收的圖片。
Kotlin
private val mPicture = Camera.PictureCallback { data, _ -> val pictureFile: File = getOutputMediaFile(MEDIA_TYPE_IMAGE) ?: run { Log.d(TAG, ("Error creating media file, check storage permissions")) return@PictureCallback } try { val fos = FileOutputStream(pictureFile) fos.write(data) fos.close() } catch (e: FileNotFoundException) { Log.d(TAG, "File not found: ${e.message}") } catch (e: IOException) { Log.d(TAG, "Error accessing file: ${e.message}") } }
Java
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()); } } };
呼叫 Camera.takePicture() 方法,觸發圖片擷取。以下範例程式碼說明如何從按鈕 View.OnClickListener 呼叫這個方法。
Kotlin
val captureButton: Button = findViewById(R.id.button_capture) captureButton.setOnClickListener { // get an image from the camera mCamera?.takePicture(null, null, picture) }
Java
// Add a listener to the Capture button Button captureButton = (Button) findViewById(R.id.button_capture); captureButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { // get an image from the camera mCamera.takePicture(null, null, picture); } } );
注意:以下範例中的 mPicture 成員是指上述範例程式碼。
注意:應用程式使用完畢後,請務必呼叫 Camera.release() 釋出 Camera 物件!如要瞭解如何釋出相機,請參閱「釋出相機」。
錄製影片
使用 Android 架構錄製影片時,必須謹慎管理 Camera 物件,並與 MediaRecorder 類別協調。使用 Camera 錄製影片時,除了 Camera.open() 和 Camera.release() 呼叫外,您還必須管理 Camera.lock() 和 Camera.unlock() 呼叫,允許 MediaRecorder 存取相機硬體。
注意:自 Android 4.0 (API 級別 14) 起,系統會自動管理 Camera.lock() 和 Camera.unlock() 呼叫。
與使用裝置相機拍照不同,錄製影片需要非常特定的呼叫順序。您必須按照特定執行順序,才能成功準備並使用應用程式拍攝影片,詳情如下。
- 開啟相機:使用
Camera.open()取得相機物件的例項。 - 連線預覽:使用
Camera.setPreviewDisplay()將SurfaceView連接至攝影機,準備即時攝影機影像預覽。 - 開始預覽:呼叫
Camera.startPreview(),開始顯示即時攝影機影像。 - 開始錄影:請依序完成下列步驟,才能成功錄影:
- 解鎖相機:呼叫
Camera.unlock()將相機解鎖,供MediaRecorder使用。 - 設定 MediaRecorder:依序呼叫下列
MediaRecorder方法。詳情請參閱MediaRecorder參考文件。setCamera():設定用於擷取影片的相機,使用應用程式目前的Camera執行個體。setAudioSource():設定音訊來源,使用MediaRecorder.AudioSource.CAMCORDER。setVideoSource():設定影片來源,請使用MediaRecorder.VideoSource.CAMERA。- 設定影片輸出格式和編碼。如果是 Android 2.2 (API 級別 8) 以上版本,請使用
MediaRecorder.setProfile方法,並透過CamcorderProfile.get()取得設定檔例項。如果是 2.2 之前的 Android 版本,您必須設定影片輸出格式和編碼參數:setOutputFormat():設定輸出格式,指定預設設定或MediaRecorder.OutputFormat.MPEG_4。setAudioEncoder():設定音效編碼類型,指定預設設定或MediaRecorder.AudioEncoder.AMR_NB。setVideoEncoder():設定影片編碼類型,指定預設設定或MediaRecorder.VideoEncoder.MPEG_4_SP。
setOutputFile():設定輸出檔案,使用「儲存媒體檔案」一節中範例方法的getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()。setPreviewDisplay():指定應用程式的SurfaceView預覽版面配置元素。使用您為「Connect Preview」指定的相同物件。
注意:您必須依序呼叫這些
MediaRecorder設定方法,否則應用程式會發生錯誤,且錄製作業會失敗。 - 準備 MediaRecorder:呼叫
MediaRecorder.prepare(),使用提供的配置設定準備MediaRecorder。 - 啟動 MediaRecorder:呼叫
MediaRecorder.start()開始錄製影片。
- 解鎖相機:呼叫
- 停止錄製影片:請依序呼叫下列方法,成功完成影片錄製:
- 停止 MediaRecorder:呼叫
MediaRecorder.stop()停止錄製影片。 - 重設 MediaRecorder:您可以視需要呼叫
MediaRecorder.reset(),從錄製器中移除設定。 - 釋出 MediaRecorder:呼叫
MediaRecorder.release()釋出MediaRecorder。 - 鎖定相機:呼叫
Camera.lock()鎖定相機,供未來的MediaRecorder工作階段使用。自 Android 4.0 (API 級別 14) 起,除非MediaRecorder.prepare()呼叫失敗,否則不需要執行這項呼叫。
- 停止 MediaRecorder:呼叫
- 停止預覽:Activity 停止使用相機後,請使用
Camera.stopPreview()停止預覽。 - 釋出相機:呼叫
Camera.release()釋出相機,讓其他應用程式使用。
注意:您可以直接使用 MediaRecorder,不必先建立相機預覽畫面,並略過這項程序的前幾個步驟。不過,由於使用者通常偏好在開始錄製前查看預覽畫面,因此這裡不會討論該程序。
提示:如果應用程式通常用於錄製影片,請在開始預覽前將 setRecordingHint(boolean) 設為 true。這項設定可縮短開始錄製所需的時間。
設定 MediaRecorder
使用 MediaRecorder 類別錄製影片時,您必須按照特定順序執行設定步驟,然後呼叫 MediaRecorder.prepare() 方法來檢查及實作設定。下列程式碼範例示範如何正確設定及準備 MediaRecorder 類別,以便錄製影片。
Kotlin
private fun prepareVideoRecorder(): Boolean { mediaRecorder = MediaRecorder() mCamera?.let { camera -> // Step 1: Unlock and set camera to MediaRecorder camera?.unlock() mediaRecorder?.run { setCamera(camera) // Step 2: Set sources setAudioSource(MediaRecorder.AudioSource.CAMCORDER) setVideoSource(MediaRecorder.VideoSource.CAMERA) // Step 3: Set a CamcorderProfile (requires API Level 8 or higher) setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)) // Step 4: Set output file setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()) // Step 5: Set the preview output setPreviewDisplay(mPreview?.holder?.surface) setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT) setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT) // Step 6: Prepare configured MediaRecorder return try { prepare() true } catch (e: IllegalStateException) { Log.d(TAG, "IllegalStateException preparing MediaRecorder: ${e.message}") releaseMediaRecorder() false } catch (e: IOException) { Log.d(TAG, "IOException preparing MediaRecorder: ${e.message}") releaseMediaRecorder() false } } } return false }
Java
private boolean prepareVideoRecorder(){ mCamera = getCameraInstance(); mediaRecorder = new MediaRecorder(); // Step 1: Unlock and set camera to MediaRecorder mCamera.unlock(); mediaRecorder.setCamera(mCamera); // Step 2: Set sources mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // Step 3: Set a CamcorderProfile (requires API Level 8 or higher) mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); // Step 4: Set output file mediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()); // Step 5: Set the preview output mediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface()); // Step 6: Prepare configured MediaRecorder try { mediaRecorder.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; }
在 Android 2.2 (API 級別 8) 之前,您必須直接設定輸出格式和編碼格式參數,而不是使用 CamcorderProfile。下列程式碼示範了這種方法:
Kotlin
// Step 3: Set output format and encoding (for versions prior to API Level 8) mediaRecorder?.apply { setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT) setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT) }
Java
// Step 3: Set output format and encoding (for versions prior to API Level 8) mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
MediaRecorder 的下列錄影參數會採用預設設定,但您可能需要根據應用程式調整這些設定:
setVideoEncodingBitRate()setVideoSize()setVideoFrameRate()setAudioEncodingBitRate()setAudioChannels()setAudioSamplingRate()
啟動及停止 MediaRecorder
使用 MediaRecorder 類別開始及停止錄製影片時,必須按照下列特定順序操作。
- 使用
Camera.unlock()解鎖相機 - 按照上述程式碼範例設定
MediaRecorder - 開始使用「
MediaRecorder.start()」錄製 - 錄製影片
- 停止使用「
MediaRecorder.stop()」錄製 - 使用
MediaRecorder.release()釋出媒體錄製器 - 使用
Camera.lock()鎖定相機
以下程式碼範例示範如何連結按鈕,以便使用相機和 MediaRecorder 類別正確啟動及停止錄影。
注意:完成錄影時,請勿釋出相機,否則預覽畫面會停止。
Kotlin
var isRecording = false val captureButton: Button = findViewById(R.id.button_capture) captureButton.setOnClickListener { if (isRecording) { // stop recording and release camera mediaRecorder?.stop() // stop the recording releaseMediaRecorder() // release the MediaRecorder object mCamera?.lock() // take camera access back from MediaRecorder // inform the user that recording has stopped setCaptureButtonText("Capture") isRecording = false } else { // initialize video camera if (prepareVideoRecorder()) { // Camera is available and unlocked, MediaRecorder is prepared, // now you can start recording mediaRecorder?.start() // inform the user that recording has started setCaptureButtonText("Stop") isRecording = true } else { // prepare didn't work, release the camera releaseMediaRecorder() // inform user } } }
Java
private boolean isRecording = false; // Add a listener to the Capture button Button captureButton = (Button) findViewById(id.button_capture); captureButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { if (isRecording) { // stop recording and release camera mediaRecorder.stop(); // stop the recording releaseMediaRecorder(); // release the MediaRecorder object mCamera.lock(); // take camera access back from MediaRecorder // inform the user that recording has stopped setCaptureButtonText("Capture"); isRecording = false; } else { // initialize video camera if (prepareVideoRecorder()) { // Camera is available and unlocked, MediaRecorder is prepared, // now you can start recording mediaRecorder.start(); // inform the user that recording has started setCaptureButtonText("Stop"); isRecording = true; } else { // prepare didn't work, release the camera releaseMediaRecorder(); // inform user } } } } );
注意:在上述範例中,prepareVideoRecorder() 方法是指「設定 MediaRecorder」中顯示的範例程式碼。這個方法會鎖定相機、設定及準備 MediaRecorder 例項。
釋出相機
相機是裝置上應用程式共用的資源。應用程式取得 Camera 執行個體後,即可使用相機。請務必特別注意,當應用程式停止使用相機物件,以及應用程式暫停 (Activity.onPause()) 時,必須立即釋出相機物件。如果應用程式未正確釋出相機,後續所有存取相機的嘗試 (包括您自己的應用程式) 都會失敗,並可能導致您或其他應用程式關閉。
如要釋出 Camera 物件的例項,請使用 Camera.release() 方法,如以下程式碼範例所示。
Kotlin
class CameraActivity : Activity() { private var mCamera: Camera? private var preview: SurfaceView? private var mediaRecorder: MediaRecorder? override fun onPause() { super.onPause() releaseMediaRecorder() // if you are using MediaRecorder, release it first releaseCamera() // release the camera immediately on pause event } private fun releaseMediaRecorder() { mediaRecorder?.reset() // clear recorder configuration mediaRecorder?.release() // release the recorder object mediaRecorder = null mCamera?.lock() // lock camera for later use } private fun releaseCamera() { mCamera?.release() // release the camera for other applications mCamera = null } }
Java
public class CameraActivity extends Activity { private Camera mCamera; private SurfaceView preview; private MediaRecorder mediaRecorder; ... @Override protected void onPause() { super.onPause(); releaseMediaRecorder(); // if you are using MediaRecorder, release it first releaseCamera(); // release the camera immediately on pause event } private void releaseMediaRecorder(){ if (mediaRecorder != null) { mediaRecorder.reset(); // clear recorder configuration mediaRecorder.release(); // release the recorder object mediaRecorder = null; mCamera.lock(); // lock camera for later use } } private void releaseCamera(){ if (mCamera != null){ mCamera.release(); // release the camera for other applications mCamera = null; } } }
注意:如果應用程式未正確釋出相機,後續所有嘗試存取相機的行為 (包括您自己的應用程式) 都會失敗,並可能導致您或其他應用程式關閉。
儲存媒體檔案
使用者建立的媒體檔案 (例如圖片和影片) 應儲存至裝置的外部儲存空間目錄 (SD 卡),以節省系統空間,並允許使用者在不使用裝置的情況下存取這些檔案。裝置上有多個可能儲存媒體檔案的目錄位置,但身為開發人員,您只需要考慮兩個標準位置:
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES):這個方法會傳回儲存圖片和影片的標準、共用和建議位置。這個目錄是共用 (公開) 目錄,因此其他應用程式可以輕鬆探索、讀取、變更及刪除儲存在這個位置的檔案。如果使用者解除安裝您的應用程式,系統不會移除儲存在這個位置的媒體檔案。為避免干擾使用者現有的相片和影片,您應在這個目錄中為應用程式的媒體檔案建立子目錄,如以下程式碼範例所示。這個方法適用於 Android 2.2 (API 級別 8),如需舊版 API 的對等呼叫,請參閱「儲存共用檔案」。Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES):這個方法會傳回標準位置,用於儲存與應用程式相關聯的圖片和影片。如果解除安裝應用程式,系統會移除儲存在這個位置的所有檔案。系統不會對這個位置的檔案強制執行安全性措施,其他應用程式可能會讀取、變更及刪除這些檔案。
下列程式碼範例示範如何為媒體檔案建立 File 或 Uri 位置,以便在使用 Intent 叫用裝置相機時,或在建構相機應用程式時使用。
Kotlin
val MEDIA_TYPE_IMAGE = 1 val MEDIA_TYPE_VIDEO = 2 /** Create a file Uri for saving an image or video */ private fun getOutputMediaFileUri(type: Int): Uri { return Uri.fromFile(getOutputMediaFile(type)) } /** Create a File for saving an image or video */ private fun getOutputMediaFile(type: Int): File? { // To be safe, you should check that the SDCard is mounted // using Environment.getExternalStorageState() before doing this. val mediaStorageDir = File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyCameraApp" ) // This location works best if you want the created images to be shared // between applications and persist after your app has been uninstalled. // Create the storage directory if it does not exist mediaStorageDir.apply { if (!exists()) { if (!mkdirs()) { Log.d("MyCameraApp", "failed to create directory") return null } } } // Create a media file name val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date()) return when (type) { MEDIA_TYPE_IMAGE -> { File("${mediaStorageDir.path}${File.separator}IMG_$timeStamp.jpg") } MEDIA_TYPE_VIDEO -> { File("${mediaStorageDir.path}${File.separator}VID_$timeStamp.mp4") } else -> null } }
Java
public static final int MEDIA_TYPE_IMAGE = 1; public static final int MEDIA_TYPE_VIDEO = 2; /** Create a file Uri for saving an image or video */ private static Uri getOutputMediaFileUri(int type){ return Uri.fromFile(getOutputMediaFile(type)); } /** Create a File for saving an image or video */ private static File getOutputMediaFile(int type){ // To be safe, you should check that the SDCard is mounted // using Environment.getExternalStorageState() before doing this. File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES), "MyCameraApp"); // This location works best if you want the created images to be shared // between applications and persist after your app has been uninstalled. // Create the storage directory if it does not exist if (! mediaStorageDir.exists()){ if (! mediaStorageDir.mkdirs()){ Log.d("MyCameraApp", "failed to create directory"); return null; } } // Create a media file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); File mediaFile; if (type == MEDIA_TYPE_IMAGE){ mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_"+ timeStamp + ".jpg"); } else if(type == MEDIA_TYPE_VIDEO) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_"+ timeStamp + ".mp4"); } else { return null; } return mediaFile; }
注意: Environment.getExternalStoragePublicDirectory() 適用於 Android 2.2 (API 級別 8) 以上版本。如果指定搭載舊版 Android 的裝置,請改用 Environment.getExternalStorageDirectory()。詳情請參閱「儲存共用檔案」。
如要讓 URI 支援工作資料夾,請先
將檔案 URI 轉換為內容 URI。接著,將內容 URI 新增至 Intent 的 EXTRA_OUTPUT。
如要進一步瞭解如何在 Android 裝置上儲存檔案,請參閱「資料儲存空間」。
相機功能
Android 支援多種相機功能,可透過相機應用程式控制,例如相片格式、閃光燈模式、對焦設定等。本節列出常見的相機功能,並簡要說明使用方式。您可以使用 Camera.Parameters 物件存取及設定大部分的相機功能。不過,有幾項重要功能需要進行 Camera.Parameters 以外的設定。以下各節將介紹這些功能:
如要大致瞭解如何使用透過 Camera.Parameters 控制的功能,請參閱「使用相機功能」一節。如要進一步瞭解如何使用透過相機參數物件控制的功能,請點選下方功能清單中的連結,前往 API 參考文件。
表 1. 常見的相機功能,依導入的 Android API 級別排序。
| 功能 | API 層級 | 說明 |
|---|---|---|
| 臉部偵測 | 14 | 辨識相片中的人臉,並用於對焦、測光和白平衡 |
| 測光區域 | 14 | 指定圖片中的一或多個區域,用於計算白平衡 |
| 重點項目 | 14 | 設定圖片中的一或多個區域做為焦點 |
White Balance Lock |
14 | 停止或開始自動調整白平衡 |
Exposure Lock |
14 | 停止或開始自動調整曝光 |
Video Snapshot |
14 | 錄影時拍照 (擷取影格) |
| 縮時錄影 | 11 | 設定延遲時間,錄製縮時錄影 |
Multiple Cameras |
9 | 支援裝置上的多個相機,包括前置和後置相機 |
Focus Distance |
9 | 回報相機與對焦物體之間的距離 |
Zoom |
8 | 設定圖片放大倍率 |
Exposure
Compensation |
8 | 調高或調低曝光程度 |
GPS Data |
5 | 在圖片中加入或省略地理位置資料 |
White Balance |
5 | 設定白平衡模式,這會影響拍攝圖片中的顏色值 |
Focus Mode |
5 | 設定相機對焦主體的方式,例如自動、固定、微距或無限遠 |
Scene Mode |
5 | 套用預設模式,適用於特定類型的攝影情境,例如夜景、海灘、雪景或燭光場景 |
JPEG Quality |
5 | 設定 JPEG 圖片的壓縮等級,提高或降低圖片輸出檔案的品質和大小 |
Flash Mode |
5 | 開啟、關閉或自動設定閃光燈 |
Color Effects |
5 | 為拍攝的圖片套用色彩效果,例如黑白、棕褐色調或負片。 |
Anti-Banding |
5 | 減少 JPEG 壓縮造成的顏色漸層色帶效果 |
Picture Format |
1 | 指定圖片的檔案格式 |
Picture Size |
1 | 指定儲存相片的像素尺寸 |
注意:由於硬體差異和軟體實作,並非所有裝置都支援這些功能。如要瞭解如何檢查執行應用程式的裝置是否支援特定功能,請參閱「檢查功能可用性」。
確認功能支援情形
在 Android 裝置上使用相機功能時,首先要瞭解的是,並非所有裝置都支援所有相機功能。此外,支援特定功能的裝置可能支援不同等級或不同選項。因此,在開發相機應用程式時,您必須決定要支援哪些相機功能,以及支援到什麼程度。做出決定後,您應在相機應用程式中加入程式碼,檢查裝置硬體是否支援這些功能,並在功能無法使用時正常失敗。
如要確認相機功能是否可用,可以取得相機參數物件的例項,並檢查相關方法。以下程式碼範例說明如何取得 Camera.Parameters 物件,並檢查相機是否支援自動對焦功能:
Kotlin
val params: Camera.Parameters? = camera?.parameters val focusModes: List<String>? = params?.supportedFocusModes if (focusModes?.contains(Camera.Parameters.FOCUS_MODE_AUTO) == true) { // Autofocus mode is supported }
Java
// get Camera parameters Camera.Parameters params = camera.getParameters(); List<String> focusModes = params.getSupportedFocusModes(); if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { // Autofocus mode is supported }
上述技巧適用於大多數相機功能。Camera.Parameters 物件提供 getSupported...()、is...Supported() 或 getMax...() 方法,用於判斷是否支援某項功能 (以及支援程度)。
如果應用程式需要特定相機功能才能正常運作,您可以在應用程式資訊清單中加入這些功能。當您宣告使用特定相機功能 (例如閃光燈和自動對焦) 時,Google Play 會限制您的應用程式安裝在不支援這些功能的裝置上。如需可在應用程式資訊清單中宣告的相機功能清單,請參閱資訊清單 功能參考資料。
使用相機功能
大多數相機功能都是透過 Camera.Parameters 物件啟用及控制。如要取得這個物件,請先取得 Camera 物件的執行個體,呼叫 getParameters() 方法,變更傳回的參數物件,然後將其設回相機物件,如以下程式碼範例所示:
Kotlin
val params: Camera.Parameters? = camera?.parameters params?.focusMode = Camera.Parameters.FOCUS_MODE_AUTO camera?.parameters = params
Java
// get Camera parameters Camera.Parameters params = camera.getParameters(); // set the focus mode params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // set Camera parameters camera.setParameters(params);
這項技術適用於幾乎所有相機功能,且在取得 Camera 物件的例項後,您隨時可以變更大部分參數。使用者通常可以立即在應用程式的相機預覽畫面中,看到參數變更。在軟體方面,參數變更可能需要幾個影格才能實際生效,因為相機硬體會處理新指令,然後傳送更新的圖片資料。
重要事項:部分相機功能無法隨意變更。具體來說,如要變更相機預覽畫面的大小或方向,必須先停止預覽、變更預覽大小,然後重新啟動預覽。從 Android 4.0 (API 級別 14) 開始,您可以變更預覽方向,而不必重新啟動預覽。
其他相機功能需要更多程式碼才能實作,包括:
- 測光和對焦區域
- 臉部偵測
- 縮時錄影影片
以下各節將簡要說明如何實作這些功能。
測光和對焦區域
在某些攝影情境下,自動對焦和測光可能無法達到預期效果。從 Android 4.0 (API 級別 14) 開始,相機應用程式可以提供額外控制項,讓應用程式或使用者指定圖片中的區域,用於決定對焦或光線等級設定,並將這些值傳遞至相機硬體,用於擷取圖片或影片。
測光和對焦區域的運作方式與其他相機功能非常相似,因為您是透過 Camera.Parameters 物件中的方法控制這些區域。下列程式碼示範如何為 Camera 執行個體設定兩個測光區域:
Kotlin
// Create an instance of Camera camera = getCameraInstance() // set Camera parameters val params: Camera.Parameters? = camera?.parameters params?.apply { if (maxNumMeteringAreas > 0) { // check that metering areas are supported meteringAreas = ArrayList<Camera.Area>().apply { val areaRect1 = Rect(-100, -100, 100, 100) // specify an area in center of image add(Camera.Area(areaRect1, 600)) // set weight to 60% val areaRect2 = Rect(800, -1000, 1000, -800) // specify an area in upper right of image add(Camera.Area(areaRect2, 400)) // set weight to 40% } } camera?.parameters = this }
Java
// Create an instance of Camera camera = getCameraInstance(); // set Camera parameters Camera.Parameters params = camera.getParameters(); if (params.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>(); Rect areaRect1 = new Rect(-100, -100, 100, 100); // specify an area in center of image meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60% Rect areaRect2 = new Rect(800, -1000, 1000, -800); // specify an area in upper right of image meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40% params.setMeteringAreas(meteringAreas); } camera.setParameters(params);
Camera.Area 物件包含兩個資料參數:Rect 物件,用於指定相機視野內的區域;以及權重值,用於告知相機在測光或對焦計算中應給予該區域的重要性等級。
Camera.Area 物件中的 Rect 欄位描述了對應到 2000 x 2000 單位網格的矩形形狀。座標 -1000、-1000 代表相機圖片的左上角,座標 1000、1000 代表相機圖片的右下角,如下圖所示。
圖 1. 紅線代表在相機預覽畫面中指定 Camera.Area 的座標系統。藍色方塊顯示攝影機區域的位置和形狀,Rect 值為 333,333,667,667。
這個座標系統的邊界一律對應至相機預覽中可見圖片的外緣,且不會隨著縮放等級縮小或擴大。同樣地,使用 Camera.setDisplayOrientation() 旋轉圖片預覽畫面時,也不會重新對應座標系統。
臉部偵測
對於包含人物的相片,臉部通常是相片中最重要的部分,在拍攝圖片時,應使用臉部來決定焦點和白平衡。Android 4.0 (API 級別 14) 架構提供 API,可使用臉部辨識技術辨識臉部及計算相片設定。
注意:臉部偵測功能執行時,setWhiteBalance(String)、setFocusAreas(List<Camera.Area>) 和 setMeteringAreas(List<Camera.Area>) 不會生效。
如要在相機應用程式中使用臉部偵測功能,請按照下列一般步驟操作:
- 確認裝置支援臉部偵測功能
- 建立臉部偵測事件監聽器
- 將臉部偵測事件監聽器新增至相機物件
- 在預覽後 (以及每次重新啟動預覽後) 啟動臉部偵測
臉部偵測功能僅適用於部分裝置。您可以呼叫 getMaxNumDetectedFaces(),確認是否支援這項功能。以下 startFaceDetection() 範例方法顯示了這項檢查的範例。
為了接收通知並回應臉部偵測,相機應用程式必須設定臉部偵測事件的事件監聽器。如要執行這項操作,您必須建立實作 Camera.FaceDetectionListener 介面的事件監聽器類別,如下方程式碼範例所示。
Kotlin
internal class MyFaceDetectionListener : Camera.FaceDetectionListener { override fun onFaceDetection(faces: Array<Camera.Face>, camera: Camera) { if (faces.isNotEmpty()) { Log.d("FaceDetection", ("face detected: ${faces.size}" + " Face 1 Location X: ${faces[0].rect.centerX()}" + "Y: ${faces[0].rect.centerY()}")) } } }
Java
class MyFaceDetectionListener implements Camera.FaceDetectionListener { @Override public void onFaceDetection(Face[] faces, Camera camera) { if (faces.length > 0){ Log.d("FaceDetection", "face detected: "+ faces.length + " Face 1 Location X: " + faces[0].rect.centerX() + "Y: " + faces[0].rect.centerY() ); } } }
建立這個類別後,請將其設定到應用程式的 Camera 物件中,如以下程式碼範例所示:
Kotlin
camera?.setFaceDetectionListener(MyFaceDetectionListener())
Java
camera.setFaceDetectionListener(new MyFaceDetectionListener());
每次啟動 (或重新啟動) 攝影機預覽畫面時,應用程式都必須啟動臉部偵測功能。建立啟動臉部偵測的方法,以便視需要呼叫,如以下程式碼範例所示。
Kotlin
fun startFaceDetection() { // Try starting Face Detection val params = mCamera?.parameters // start face detection only *after* preview has started params?.apply { if (maxNumDetectedFaces > 0) { // camera supports face detection, so can start it: mCamera?.startFaceDetection() } } }
Java
public void startFaceDetection(){ // Try starting Face Detection Camera.Parameters params = mCamera.getParameters(); // start face detection only *after* preview has started if (params.getMaxNumDetectedFaces() > 0){ // camera supports face detection, so can start it: mCamera.startFaceDetection(); } }
每次啟動 (或重新啟動) 相機預覽畫面時,都必須啟動臉部偵測功能。如果您使用「建立預覽類別」一節中所示的預覽類別,請將 startFaceDetection() 方法新增至預覽類別中的 surfaceCreated() 和 surfaceChanged() 方法,如下方程式碼範例所示。
Kotlin
override fun surfaceCreated(holder: SurfaceHolder) { try { mCamera.setPreviewDisplay(holder) mCamera.startPreview() startFaceDetection() // start face detection feature } catch (e: IOException) { Log.d(TAG, "Error setting camera preview: ${e.message}") } } override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { if (holder.surface == null) { // preview surface does not exist Log.d(TAG, "holder.getSurface() == null") return } try { mCamera.stopPreview() } catch (e: Exception) { // ignore: tried to stop a non-existent preview Log.d(TAG, "Error stopping camera preview: ${e.message}") } try { mCamera.setPreviewDisplay(holder) mCamera.startPreview() startFaceDetection() // re-start face detection feature } catch (e: Exception) { // ignore: tried to stop a non-existent preview Log.d(TAG, "Error starting camera preview: ${e.message}") } }
Java
public void surfaceCreated(SurfaceHolder holder) { try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); startFaceDetection(); // start face detection feature } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { if (holder.getSurface() == null){ // preview surface does not exist Log.d(TAG, "holder.getSurface() == null"); return; } try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "Error stopping camera preview: " + e.getMessage()); } try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); startFaceDetection(); // re-start face detection feature } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } }
注意:請務必在呼叫 startPreview() 之後呼叫這個方法。請勿嘗試在相機應用程式主要活動的 onCreate() 方法中啟動臉部偵測,因為在應用程式執行到這個階段時,預覽畫面尚未就緒。
縮時錄影影片
縮時錄影功能可讓使用者建立短片,結合相隔幾秒或幾分鐘拍攝的相片。這項功能會使用 MediaRecorder 錄製縮時錄影序列的圖片。
如要使用 MediaRecorder 錄製縮時錄影,您必須設定錄製器物件,就像錄製一般影片一樣,將每秒影格數設為較低的數字,並使用其中一個縮時錄影品質設定,如下方程式碼範例所示。
Kotlin
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)) mediaRecorder.setCaptureRate(0.1) // capture a frame every 10 seconds
Java
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher) mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)); ... // Step 5.5: Set the video capture rate to a low number mediaRecorder.setCaptureRate(0.1); // capture a frame every 10 seconds
這些設定必須在 MediaRecorder 的大型設定程序中完成。如需完整的設定程式碼範例,請參閱「設定 MediaRecorder」。設定完成後,您就可以開始錄製影片,就像錄製一般短片一樣。如要進一步瞭解如何設定及執行 MediaRecorder,請參閱「擷取影片」。
Camera2Video 和 HdrViewfinder 範例進一步示範了本頁面提及的 API 使用方式。
需要權限的相機欄位
在搭載 Android 10 (API 級別 29) 以上版本的裝置上,應用程式必須具備 CAMERA 權限,才能存取 getCameraCharacteristics() 方法傳回的下列欄位值:
LENS_POSE_ROTATIONLENS_POSE_TRANSLATIONLENS_INTRINSIC_CALIBRATIONLENS_RADIAL_DISTORTIONLENS_POSE_REFERENCELENS_DISTORTIONLENS_INFO_HYPERFOCAL_DISTANCELENS_INFO_MINIMUM_FOCUS_DISTANCESENSOR_REFERENCE_ILLUMINANT1SENSOR_REFERENCE_ILLUMINANT2SENSOR_CALIBRATION_TRANSFORM1SENSOR_CALIBRATION_TRANSFORM2SENSOR_COLOR_TRANSFORM1SENSOR_COLOR_TRANSFORM2SENSOR_FORWARD_MATRIX1SENSOR_FORWARD_MATRIX2
其他程式碼範例
如要下載範例應用程式,請參閱 Camera2Basic 範例和官方 CameraX 範例應用程式。