Android Camera詳解(譯)

以下內(nèi)容翻譯來源,Google官方開發(fā)文檔:https://developer.android.google.cn/guide/topics/media/camera.html

相關(guān)的類

  1. android.hardware.camera2
  2. Camera
  3. SurfaceView---這個(gè)類用于向用戶呈現(xiàn)實(shí)時(shí)相機(jī)預(yù)覽。
  4. MediaRecorder---這個(gè)類用于從攝像機(jī)錄制視頻。
  5. Intent---MediaStore.ACTION_IMAGE_CAPTURE或MediaStore.ACTION_VIDEO_CAPTURE可用于捕獲圖像或視頻,而無需直接使用Camera對(duì)象。

清單聲明

在使用Camera API開始開發(fā)應(yīng)用程序之前,應(yīng)確保您的清單具有適當(dāng)?shù)穆暶?,以允許使用相機(jī)硬件和其他相關(guān)功能。

  • 相機(jī)權(quán)限 - 您的應(yīng)用程序必須請(qǐng)求使用設(shè)備相機(jī)的權(quán)限。

    <uses-permission android:name="android.permission.CAMERA" />

    注意:如果您通過調(diào)用現(xiàn)有的攝像頭應(yīng)用程序來使用攝像頭,則應(yīng)用程序不需要請(qǐng)求此權(quán)限。

  • 相機(jī)功能 - 您的應(yīng)用程序還必須聲明使用相機(jī)功能,例如:

    <uses-feature android:name="android.hardware.camera" />

  • 存儲(chǔ)權(quán)限 - 如果應(yīng)用程序?qū)D像或視頻保存到設(shè)備的外部存儲(chǔ)設(shè)備(SD卡),則還必須在清單中指定此選項(xiàng)。

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

  • 音頻錄制權(quán)限 - 對(duì)于使用視頻捕獲錄制音頻,應(yīng)用程序必須請(qǐng)求獲取音頻捕獲權(quán)限。

    <uses-permission android:name="android.permission.RECORD_AUDIO" />

創(chuàng)建自定義攝像頭

為應(yīng)用程序創(chuàng)建自定義攝像頭界面的一般步驟如下:

  1. 檢測(cè)和訪問攝像機(jī) - 創(chuàng)建代碼以檢查攝像機(jī)是否存在并請(qǐng)求訪問。
  2. 創(chuàng)建預(yù)覽類 - 創(chuàng)建擴(kuò)展SurfaceView并實(shí)現(xiàn)SurfaceHolder界面的相機(jī)預(yù)覽類。這個(gè)類預(yù)覽來自相機(jī)的實(shí)時(shí)圖像。
  3. 構(gòu)建預(yù)覽布局 - 一旦你擁有相機(jī)預(yù)覽類,創(chuàng)建一個(gè)包含預(yù)覽和你想要的用戶界面控件的視圖布局。
  4. Capture的監(jiān)聽器 - 為您的接口控件連接偵聽器,以響應(yīng)用戶操作(例如按下按鈕)開始捕獲圖像或視頻。
  5. 捕獲和保存文件 - 設(shè)置用于捕獲圖片或視頻和保存輸出的代碼。
  6. 釋放相機(jī) - 使用相機(jī)后,應(yīng)用程序必須正確釋放它以供其他應(yīng)用程序使用。

相機(jī)硬件是一個(gè)共享資源,必須仔細(xì)管理,以便您的應(yīng)用程序不會(huì)與其他可能也想使用它的應(yīng)用程序沖突。以下部分討論如何檢測(cè)相機(jī)硬件,如何請(qǐng)求訪問相機(jī),如何捕獲圖片或視頻以及如何在應(yīng)用程序使用完成后釋放相機(jī)。

檢測(cè)相機(jī)硬件

如果您的應(yīng)用程序沒有特別要求使用清單聲明的攝像機(jī),則應(yīng)檢查相機(jī)在運(yùn)行時(shí)是否可用。要執(zhí)行此檢查,請(qǐng)使用PackageManager.hasSystemFeature()方法,如下面的示例代碼所示:

/** 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設(shè)備可以具有多個(gè)攝像機(jī),例如用于攝影的背面攝像機(jī)和用于視頻通話的前置攝像機(jī)。Android 2.3(API Level 9)及更高版本允許您使用Camera.getNumberOfCameras()方法檢查設(shè)備上可用的攝像機(jī)數(shù)量。

訪問相機(jī)

如果您確定運(yùn)行應(yīng)用程序的設(shè)備具有攝像頭,則必須通過獲取攝像頭實(shí)例來請(qǐng)求訪問它(除非您正在使用意圖來訪問一個(gè)攝像頭)。
要訪問主要攝像機(jī),請(qǐng)使用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()時(shí)始終檢查異常。如果相機(jī)正在使用或不存在,則無法檢查異常,將導(dǎo)致您的應(yīng)用程序被系統(tǒng)關(guān)閉。

在運(yùn)行Android 2.3(API Level 9)或更高版本的設(shè)備上,您可以使用Camera.open(int)訪問特定的攝像機(jī)。上面的示例代碼將訪問具有多個(gè)攝像頭的設(shè)備上的第一個(gè)后置攝像頭

檢查相機(jī)功能

獲取對(duì)攝像機(jī)的訪問權(quán)限后,您可以使用Camera.getParameters()方法獲取有關(guān)其功能的更多信息,并檢查返回的Camera.Parameters對(duì)象以獲取支持的功能。使用API?? Level 9或更高版本時(shí),請(qǐng)使用Camera.getCameraInfo()確定相機(jī)是位于設(shè)備的正面還是背面,以及圖像的方向。

創(chuàng)建預(yù)覽類

為了讓用戶有效地拍攝照片或視頻,他們必須能夠看到設(shè)備相機(jī)看到的內(nèi)容。相機(jī)預(yù)覽類是SurfaceView,可以顯示來自相機(jī)的實(shí)時(shí)圖像數(shù)據(jù),因此用戶可以框架并捕獲圖片或視頻。
以下示例代碼演示了如何創(chuàng)建可包含在視圖布局中的基本攝像機(jī)預(yù)覽類。這個(gè)類實(shí)現(xiàn)了SurfaceHolder.Callback,以便捕獲用于創(chuàng)建和銷毀視圖的回調(diào)事件,這是分配攝像機(jī)預(yù)覽輸入所需要的。

/** 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());
        }
    }
}

如果要為相機(jī)預(yù)覽設(shè)置特定大小,請(qǐng)?jiān)谏鲜鲎⑨屩兴龅膕urfaceChanged()方法中設(shè)置此大小。設(shè)置預(yù)覽大小時(shí),必須使用getSupportedPreviewSizes()的值。不要在setPreviewSize()方法中設(shè)置任意值。

注意:隨著Android 7.0(API級(jí)別24)及更高版本中多窗口功能的引入,即使在調(diào)用setDisplayOrientation()之后,也不能再假設(shè)預(yù)覽的縱橫比與您的活動(dòng)相同。根據(jù)窗口大小和寬高比,您可能必須使用信箱布局將寬相機(jī)預(yù)覽適配為縱向布局,反之亦然。

在布局中放置預(yù)覽

相機(jī)預(yù)覽類(例如上一部分中所示的示例)必須與用于拍攝圖片或視頻的其他用戶界面控件一起放置在活動(dòng)的布局中。

<?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>

在大多數(shù)設(shè)備上,相機(jī)預(yù)覽的默認(rèn)方向?yàn)闄M向。此示例布局指定水平(橫向)布局,以下代碼將應(yīng)用程序的方向固定為橫向。為了簡(jiǎn)化渲染相機(jī)預(yù)覽,您應(yīng)該將以下內(nèi)容添加到清單中,以將應(yīng)用程序的預(yù)覽活動(dòng)方向更改為橫向。

<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>

注意:相機(jī)預(yù)覽不必處于橫向模式。從Android 2.2(API級(jí)別8)開始,您可以使用setDisplayOrientation()方法設(shè)置預(yù)覽圖像的旋轉(zhuǎn)。為了在用戶重新定位手機(jī)時(shí)更改預(yù)覽方向,請(qǐng)?jiān)陬A(yù)覽類的surfaceChanged()方法中,首先使用Camera.stopPreview()停止預(yù)覽,更改方向,然后再次使用Camera.startPreview()啟動(dòng)預(yù)覽。

在相機(jī)視圖的活動(dòng)中,將預(yù)覽類添加到上面示例中所示的FrameLayout元素。您的相機(jī)活動(dòng)還必須確保在暫?;蜿P(guān)閉時(shí)釋放相機(jī)。以下示例顯示如何修改相機(jī)活動(dòng)以附加創(chuàng)建預(yù)覽類中顯示的預(yù)覽類。

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()方法指的是訪問攝像機(jī)中顯示的示例方法。

捕獲圖片

一旦構(gòu)建了預(yù)覽類和顯示它的視圖布局,就可以開始使用應(yīng)用程序捕獲圖像。在應(yīng)用程序代碼中,您必須為用戶界面控件設(shè)置偵聽器,以通過拍攝圖片來響應(yīng)用戶操作。在應(yīng)用程序代碼中,您必須為用戶界面控件設(shè)置偵聽器,以通過拍攝圖片來響應(yīng)用戶操作。

為了檢索圖片,請(qǐng)使用Camera.takePicture()方法。此方法需要三個(gè)參數(shù),從相機(jī)接收數(shù)據(jù)。為了接收J(rèn)PEG格式的數(shù)據(jù),您必須實(shí)現(xiàn)一個(gè)Camera.PictureCallback接口來接收?qǐng)D像數(shù)據(jù)并將其寫入文件。以下代碼顯示了Camera.PictureCallback接口的基本實(shí)現(xiàn),用于保存從相機(jī)接收的圖像。

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: " +
                e.getMessage());
            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());
        }
    }
};

通過調(diào)用Camera.takePicture()方法觸發(fā)捕獲圖像。以下示例代碼顯示了如何從按鈕View.OnClickListener調(diào)用此方法。

// 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) {
            // get an image from the camera
            mCamera.takePicture(null, null, mPicture);
        }
    }
);

警告:記住,當(dāng)您的應(yīng)用程序使用它時(shí),通過調(diào)用Camera.release()來釋放Camera對(duì)象!有關(guān)如何釋放相機(jī)的信息,請(qǐng)參閱釋放相機(jī)。

捕獲視頻

使用Android框架的視頻捕獲需要仔細(xì)管理Camera對(duì)象和與MediaRecorder類的協(xié)調(diào)。使用Camera錄制視頻時(shí),除了Camera.open()和Camera.release()調(diào)用外,還必須管理Camera.lock()和Camera.unlock()調(diào)用,以允許MediaRecorder訪問攝像機(jī)硬件。

注意:從Android 4.0(API級(jí)別14)開始,Camera.lock()和Camera.unlock()調(diào)用會(huì)自動(dòng)管理。

與使用設(shè)備相機(jī)拍攝照片不同,捕獲視頻需要非常特殊的通話順序。您必須遵循特定的執(zhí)行順序,才能使用您的應(yīng)用程序成功準(zhǔn)備和捕獲視頻,如下所述。

  1. 打開相機(jī) - 使用Camera.open()獲取相機(jī)對(duì)象的實(shí)例。
  2. 連接預(yù)覽 - 通過使用Camera.setPreviewDisplay()將SurfaceView連接到攝像機(jī),準(zhǔn)備實(shí)時(shí)的攝像機(jī)圖像預(yù)覽
  3. 開始預(yù)覽 - 調(diào)用Camera.startPreview()開始顯示實(shí)時(shí)攝像機(jī)圖像。
  4. 開始錄制視頻 - 必須完成以下步驟才能成功錄制視頻:
    1. 解鎖相機(jī) - 通過調(diào)用Camera.unlock()解鎖相機(jī)以供MediaRecorder使用。
    2. 配置MediaRecorder - 按以下順序調(diào)用以下MediaRecorder方法。有關(guān)更多信息,請(qǐng)參閱MediaRecorder參考文檔。
      1. setCamera() - 設(shè)置要用于視頻捕獲的攝像機(jī),使用應(yīng)用程序的當(dāng)前攝像機(jī)實(shí)例。
      2. setAudioSource() - 設(shè)置音頻源,使用MediaRecorder.AudioSource.CAMCORDER。
      3. setVideoSource() - 設(shè)置視頻源,使用MediaRecorder.VideoSource.CAMERA。
      4. 設(shè)置視頻輸出格式和編碼。對(duì)于Android 2.2(API Level 8)及更高版本,請(qǐng)使用MediaRecorder.setProfile方法,并使用CamcorderProfile.get()獲取配置文件實(shí)例。對(duì)于2.2之前的Android版本,必須設(shè)置視頻輸出格式和編碼參數(shù):
        1. setOutputFormat() - 設(shè)置輸出格式,指定默認(rèn)設(shè)置或MediaRecorder.OutputFormat.MPEG_4
        2. setAudioEncoder() - 設(shè)置聲音編碼類型,指定默認(rèn)設(shè)置或MediaRecorder.AudioEncoder.AMR_NB。
        3. setVideoEncoder() - 設(shè)置視頻編碼類型,指定默認(rèn)設(shè)置或MediaRecorder.VideoEncoder.MPEG_4_SP。
    3. 準(zhǔn)備MediaRecorder - 通過調(diào)用MediaRecorder.prepare()為提供的配置設(shè)置準(zhǔn)備MediaRecorder。
    4. 啟動(dòng)MediaRecorder - 通過調(diào)用MediaRecorder.start()開始錄制視頻
  5. 停止錄制視頻 - 按順序調(diào)用以下方法,以成功完成視頻錄制:
    1. 停止MediaRecorder - 停止通過調(diào)用MediaRecorder.stop()錄制視頻。
    2. 重置MediaRecorder - (可選)通過調(diào)用MediaRecorder.reset()從記錄器中刪除配置設(shè)置。
    3. 釋放MediaRecorder - 通過調(diào)用MediaRecorder.release()釋放MediaRecorder。
    4. 鎖定相機(jī) - 鎖定相機(jī),以便將來的MediaRecorder會(huì)話可以通過調(diào)用Camera.lock()來使用它。從Android 4.0(API級(jí)別14)開始,不需要此調(diào)用,除非MediaRecorder.prepare()調(diào)用失敗。
  6. 停止預(yù)覽 - 當(dāng)您的活動(dòng)使用相機(jī)完成后,使用Camera.stopPreview()停止預(yù)覽。
  7. 釋放相機(jī) - 釋放相機(jī),以便其他應(yīng)用程序可以通過調(diào)用Camera.release()來使用它。

注意:可以先使用MediaRecorder而不創(chuàng)建相機(jī)預(yù)覽,并跳過此過程的前幾個(gè)步驟。然而,由于用戶通常喜歡在開始記錄之前看到預(yù)覽,所以這里不討論該處理。

提示:如果您的應(yīng)用程序通常用于錄制視頻,請(qǐng)?jiān)陂_始預(yù)覽之前將setRecordingHint(boolean)設(shè)置為true。此設(shè)置可以幫助減少開始錄制所需的時(shí)間。

配置MediaRecorder

當(dāng)使用MediaRecorder類記錄視頻時(shí),必須按特定順序執(zhí)行配置步驟,然后調(diào)用MediaRecorder.prepare()方法來檢查和實(shí)現(xiàn)配置。以下示例代碼演示如何正確配置和準(zhǔn)備MediaRecorder類進(jìn)行視頻錄制。

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;
}

在Android 2.2(API級(jí)別8)之前,您必須直接設(shè)置輸出格式和編碼格式參數(shù),而不是使用CamcorderProfile。這種方法在下面的代碼中演示:

 // Step 3: Set output format and encoding (for versions prior to API Level 8)
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);

MediaRecorder的以下視頻錄制參數(shù)被賦予默認(rèn)設(shè)置,但是,您可能想要為應(yīng)用程序調(diào)整這些設(shè)置:

setVideoEncodingBitRate()
setVideoSize()
setVideoFrameRate()
setAudioEncodingBitRate()
setAudioChannels()
setAudioSamplingRate()

啟動(dòng)和停止MediaRecorder

當(dāng)使用MediaRecorder類啟動(dòng)和停止視頻錄制時(shí),必須遵循以下列出的特定順序。

  1. 使用Camera.unlock()解鎖相機(jī)
  2. 配置MediaRecorder,如上面的代碼示例所示
  3. 使用MediaRecorder.start()開始錄制
  4. 錄制視頻
  5. 使用MediaRecorder.stop()停止錄制
  6. 使用MediaRecorder.release()釋放媒體記錄器
  7. 使用Camera.lock()鎖定相機(jī)

以下示例代碼演示了如何連接一個(gè)按鈕,以使用相機(jī)和MediaRecorder類正確啟動(dòng)和停止視頻錄制。

注意:完成視頻錄制時(shí),請(qǐng)勿釋放相機(jī),否則將停止預(yù)覽。

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
                mMediaRecorder.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
                    mMediaRecorder.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中顯示的示例代碼。此方法負(fù)責(zé)鎖定相機(jī),配置和準(zhǔn)備MediaRecorder實(shí)例。(詳見例子)

釋放相機(jī)

攝像機(jī)是由設(shè)備上的應(yīng)用程序共享的資源。您的應(yīng)用程序可以在獲取相機(jī)實(shí)例后使用相機(jī),并且您的應(yīng)用程序停止使用時(shí),以及應(yīng)用程序暫停后(Activity.onPause()),您必須特別小心釋放相機(jī)對(duì)象。如果應(yīng)用程序未正確釋放相機(jī),則隨后嘗試訪問相機(jī)(包括您自己的應(yīng)用程序)將會(huì)失敗,并可能導(dǎo)致您的或其他應(yīng)用程序關(guān)閉。

要釋放Camera對(duì)象的實(shí)例,請(qǐng)使用Camera.release()方法,如下面的示例代碼所示。

public class CameraActivity extends Activity {
    private Camera mCamera;
    private SurfaceView mPreview;
    private MediaRecorder mMediaRecorder;

    ...

    @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 (mMediaRecorder != null) {
            mMediaRecorder.reset();   // clear recorder configuration
            mMediaRecorder.release(); // release the recorder object
            mMediaRecorder = null;
            mCamera.lock();           // lock camera for later use
        }
    }

    private void releaseCamera(){
        if (mCamera != null){
            mCamera.release();        // release the camera for other applications
            mCamera = null;
        }
    }
}

警告:如果您的應(yīng)用程序未正確釋放相機(jī),則隨后嘗試訪問相機(jī)(包括您自己的應(yīng)用程序)將會(huì)失敗,并可能導(dǎo)致您的或其他應(yīng)用程序關(guān)閉。

保存媒體文件

用戶創(chuàng)建的媒體文件(如圖片和視頻)應(yīng)保存到設(shè)備的外部存儲(chǔ)目錄(SD卡),以節(jié)省系統(tǒng)空間,并允許用戶在沒有設(shè)備的情況下訪問這些文件。在設(shè)備上保存媒體文件有許多可能的目錄位置,但是您應(yīng)該考慮作為開發(fā)人員只有兩個(gè)標(biāo)準(zhǔn)位置:

  1. Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) --此方法返回用于保存圖片和視頻的標(biāo)準(zhǔn),共享和推薦的位置。此目錄是共享(公共),因此其他應(yīng)用程序可以輕松地發(fā)現(xiàn),讀取,更改和刪除保存在此位置的文件。如果用戶卸載了您的應(yīng)用程序,則不會(huì)刪除保存到此位置的媒體文件。了避免干擾用戶現(xiàn)有的圖片和視頻,您應(yīng)該為此目錄中的應(yīng)用程序的媒體文件創(chuàng)建一個(gè)子目錄,如下面的代碼示例所示。此方法在Android 2.2(API級(jí)別8)中可用,適用于早期API版本中的等效調(diào)用,請(qǐng)參閱保存共享文件。
  2. Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) ---此方法返回用于保存與您的應(yīng)用程序相關(guān)聯(lián)的圖片和視頻的標(biāo)準(zhǔn)位置。如果您的應(yīng)用程序已卸載,則會(huì)刪除保存在此位置的所有文件。不對(duì)此位置中的文件強(qiáng)制執(zhí)行安全性,其他應(yīng)用程序可能會(huì)讀取,更改和刪除它們。

以下示例代碼演示了如何為媒體文件創(chuàng)建文件或Uri位置,當(dāng)使用Intent或作為構(gòu)建相機(jī)應(yīng)用程序的一部分調(diào)用設(shè)備的攝像機(jī)時(shí),可以使用該位置。

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級(jí)別8)或更高版本中可用。如果您要使用早期版本的Android定位設(shè)備,請(qǐng)改用Environment.getExternalStorageDirectory()。有關(guān)詳細(xì)信息,請(qǐng)參閱保存共享文件。

有關(guān)在Android設(shè)備上保存文件的詳細(xì)信息,請(qǐng)參閱數(shù)據(jù)存儲(chǔ)。

相機(jī)功能(用來設(shè)置更加詳細(xì)的視屏,例如各種比例和白平衡等。后期再補(bǔ)充詳細(xì))

Android支持您可以使用相機(jī)應(yīng)用程序控制的各種相機(jī)功能,例如圖片格式,閃光模式,對(duì)焦設(shè)置等。本節(jié)列出常見的攝像機(jī)功能,并簡(jiǎn)要討論如何使用它們。大多數(shù)攝像機(jī)功能可以使用通過Camera.Parameters對(duì)象訪問和設(shè)置。然而,有幾個(gè)重要的功能,需要的不僅是Camera.Parameters中的簡(jiǎn)單設(shè)置。這些功能將在以下部分中介紹:

  1. 測(cè)光和對(duì)焦區(qū)域
  2. 面部檢測(cè)
  3. 時(shí)間流逝視頻
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容