Camera API

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
這個類別可用來透過相機錄影。
Intent
MediaStore.ACTION_IMAGE_CAPTUREMediaStore.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" />
    
  • 儲存空間權限 - 應用程式可將圖片或影片儲存到 裝置的外部儲存空間 (SD 卡),前提是裝置定位為 Android 10 (API 級別 29) 並在資訊清單中指定下列項目。
    <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 也能使用 Google Cloud CLI 或 Compute Engine API對於全新或進階的相機應用程式,新版 android.hardware.camera2 API 是 建議。

為應用程式建立自訂相機介面的一般步驟如下:

  • 偵測及存取相機 - 建立程式碼來檢查是否存在 攝影機和要求存取權
  • 建立預覽類別 - 建立可擴充 SurfaceView 的相機預覽類別,並實作 SurfaceHolder 介面。這個 類別預覽相機中的即時影像。
  • 「Build a Preview Layout」(建構預覽版面配置) - 取得相機預覽類別後,請建立 包含預覽和所需使用者介面控制項的版面配置。
  • 擷取設定監聽器 - 連線至介面的事件監聽器 用來回應使用者動作 (例如按下 按鈕。
  • 擷取及儲存檔案:設定拍照或 並儲存輸出內容
  • 釋出相機:使用相機後,您的應用程式必須 並妥善發布,以便供其他應用程式使用

相機硬體屬於共用資源,必須謹慎管理,應用程式才能確保 與可能使用它的其他應用程式衝突。下列各節將討論 如何偵測相機硬體、如何要求相機存取權、如何拍照或錄影 以及如何在應用程式使用後釋放相機

注意:請記得發布 Camera 方法是呼叫 Camera.release(), 應用程式、應用程式、應用程式如果您的應用程式無法正確釋放相機,則所有 之後嘗試存取攝影機 (包括您應用程式的裝置) 將會失敗, 導致您的或其他應用程式關閉。

偵測相機硬體

如果您的應用程式不需要使用資訊清單宣告, 應在執行階段檢查是否有相機可用。如要執行這項檢查,請使用 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 方法是呼叫 Camera.release(), 應用程式、應用程式、應用程式如需瞭解如何釋出相機,請參閱「釋放相機」一文。

拍攝影片

使用 Android 架構擷取影片時,必須謹慎管理 Camera 物件,並與 MediaRecorder 協調 類別使用 Camera 錄影時,你必須管理 Camera.lock()Camera.unlock() 通話,允許 MediaRecorder 存取相機硬體。 除了 Camera.open()Camera.release() 呼叫之外。

注意:自 Android 4.0 (API 級別 14) 起,系統會自動為您管理 Camera.lock()Camera.unlock() 呼叫。

不同於使用裝置相機拍照,擷取影片時需要進行特別呼叫 順序。您必須按照特定的執行順序,才能順利準備及拍攝影片 聯絡。

  1. 開啟相機 - 使用 Camera.open() 來取得相機物件的例項。
  2. 連線預覽:使用 Camera.setPreviewDisplay()SurfaceView 連線至相機,準備即時相機圖片預覽。
  3. 開始預覽:呼叫 Camera.startPreview() 即可開始顯示相機的即時影像。
  4. 開始錄影 - 請務必在 以下條件,才能順利錄製影片:
    1. 解鎖相機:呼叫 Camera.unlock() 將相機解鎖,供 MediaRecorder 使用。
    2. 設定 MediaRecorder:請依序使用下列 MediaRecorder 方法呼叫。如需更多資訊,請參閱 MediaRecorder 參考說明文件。
      1. setCamera():設定要用於錄影的攝影機,請使用應用程式目前的執行個體 (共 Camera 個)。
      2. setAudioSource() - 將 音訊來源,請使用 MediaRecorder.AudioSource.CAMCORDER
      3. setVideoSource() - 已設定 影片來源,請使用 MediaRecorder.VideoSource.CAMERA
      4. 設定影片輸出格式和編碼。針對 Android 2.2 (API 級別 8) 和 以上版本,請使用 MediaRecorder.setProfile 方法,並使用 CamcorderProfile.get() 取得設定檔例項。下列日期前的 Android 版本: 2.2,您必須設定影片輸出格式和編碼參數:
        1. setOutputFormat() - 已設定 輸出格式,請指定預設值或 MediaRecorder.OutputFormat.MPEG_4
        2. setAudioEncoder() - 已設定 音訊編碼類型,請指定預設值或 MediaRecorder.AudioEncoder.AMR_NB
        3. setVideoEncoder() - 已設定 影片編碼類型,並指定預設設定或 MediaRecorder.VideoEncoder.MPEG_4_SP
      5. setOutputFile(): 設定輸出檔案,使用範例中的 getOutputMediaFile(MEDIA_TYPE_VIDEO).toString() 方法,請參閱儲存媒體檔案一節中的方法。
      6. setPreviewDisplay() - 指定 SurfaceView 預覽版面配置元素 應用程式使用您為「Connect Preview」指定的相同物件。

      注意:您必須依序呼叫這些 MediaRecorder 設定方法,否則 應用程式就會發生錯誤,且錄製作業也會失敗。

    3. Prepare MediaRecorder - 準備 MediaRecorder 呼叫 MediaRecorder.prepare() 提供的組態設定。
    4. 啟動 MediaRecorder - 呼叫 MediaRecorder.start() 開始錄影。
  5. 停止錄影:請「依序」呼叫下列方法, 如何順利完成錄影:
    1. 停止 MediaRecorder:呼叫 MediaRecorder.stop() 即可停止錄影。
    2. 重設 MediaRecorder:視需要移除以下設定的組態設定: 呼叫 MediaRecorder.reset()
    3. Release MediaRecorder - 發布 MediaRecorder 呼叫 MediaRecorder.release()
    4. 鎖定攝影機:呼叫 Camera.lock() 鎖定攝影機,讓未來的 MediaRecorder 工作階段能使用攝影機。從 Android 4.0 (API 級別 14) 開始,除非 「MediaRecorder.prepare()」通話失敗。
  6. 停止預覽:活動用完相機後,請停止 請使用 Camera.stopPreview() 進行預覽。
  7. 釋出相機:釋出相機,讓其他應用程式使用 呼叫 Camera.release() 即可。

注意:您可以使用 MediaRecorder 不必先建立相機預覽畫面,也略過這項程序的前幾個步驟。不過 由於使用者通常偏好在開始錄影前先預覽內容,因此這項程序並非 討論的主題

提示:如果應用程式通常用於錄影,請設定 開始前setRecordingHint(boolean)true 預覽。這項設定有助於縮短開始錄影的時間。

設定 MediaRecorder

使用 MediaRecorder 類別錄製影片時,必須執行 設定步驟,然後呼叫 MediaRecorder.prepare() 方法,檢查並實作 此外還會從 0 自動調整資源配置 您完全不必調整資源調度設定以下程式碼範例示範如何正確設定及準備 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 提供下列錄影參數 不過,建議您針對應用程式調整這些設定:

啟動和停止 MediaRecorder

使用 MediaRecorder 類別開始和停止錄影時, 您必須遵循下列特定的順序。

  1. 使用「Camera.unlock()」解鎖相機
  2. 按照上述程式碼範例設定 MediaRecorder
  3. 開始使用「MediaRecorder.start()」錄製
  4. 錄製影片
  5. 停止使用「MediaRecorder.stop()」錄製
  6. 使用「MediaRecorder.release()」釋出媒體錄音工具
  7. 使用「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) - 這個方法會傳回標準、共用和建議值 相片和影片的儲存位置。此目錄是共用 (公開),因此其他應用程式 您可以輕鬆尋找、讀取、變更及刪除儲存在這個位置的檔案。如果您的應用程式是 使用者解除安裝的媒體檔案,並不會移除儲存在該位置的媒體檔案。為了避免 幹擾使用者現有的相片和影片,建議您為 如下方程式碼範例所示,此目錄內的應用程式媒體檔案。此方法 適用於舊版 API 中的同等呼叫,請參閱儲存共用檔案
  • Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) - 這個方法會傳回標準位置以供儲存 所有與應用程式相關的相片和影片如果您的應用程式已解除安裝 所有儲存在這個位置的檔案都會遭到移除。系統不會針對這個檔案中的檔案強制執行安全性措施 位置和其他應用程式可讀取、變更及刪除它們。

以下程式碼範例示範如何為媒體檔案建立 FileUri 位置,可用於叫用裝置相機 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 EXTRA_OUTPUT敬上 來自 Intent

想進一步瞭解如何在 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) 架構提供透過 臉部辨識技術

注意:在執行臉部偵測功能時, 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,請參閱拍攝影片

Camera2VideoHdrViewfinder 範例,進一步示範如何使用本頁提及的 API。

需要權限的相機欄位

如果是搭載 Android 10 (API 級別 29) 以上版本的應用程式,則必須採用 CAMERA 權限,才能 就能存取 getCameraCharacteristics() 方法會傳回:

  • LENS_POSE_ROTATION
  • LENS_POSE_TRANSLATION
  • LENS_INTRINSIC_CALIBRATION
  • LENS_RADIAL_DISTORTION
  • LENS_POSE_REFERENCE
  • LENS_DISTORTION
  • LENS_INFO_HYPERFOCAL_DISTANCE
  • LENS_INFO_MINIMUM_FOCUS_DISTANCE
  • SENSOR_REFERENCE_ILLUMINANT1
  • SENSOR_REFERENCE_ILLUMINANT2
  • SENSOR_CALIBRATION_TRANSFORM1
  • SENSOR_CALIBRATION_TRANSFORM2
  • SENSOR_COLOR_TRANSFORM1
  • SENSOR_COLOR_TRANSFORM2
  • SENSOR_FORWARD_MATRIX1
  • SENSOR_FORWARD_MATRIX2

其他程式碼範例

如要下載範例應用程式,請參閱 Camera2Basic 範例CameraX 官方範例應用程式