Android Camera(三)

把預覽類放到佈局中

Camera的預覽類,如上文所示的示例,必須要跟用戶界面控件一起放到一個Activity的佈局中,以便拍照或錄像。本段向你顯示如果構建一個基本的用於預覽的Activity佈局。

下面的佈局代碼提供瞭一個很基本的View,它能夠用於顯示Camera的預覽圖像。在這個示例中,FrameLayout元素被用於Camera預覽類的容器。使用這個佈局類型可以讓額外的圖像信息或控件能夠覆蓋在實時的Camera預覽圖像之上。

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="https://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>

在大多數設備上,Camera預覽的默認方向是橫向。這個示例佈局指定瞭一個水平(橫向)佈局,並且下面的代碼把應用程序固定為橫向。為瞭簡化Camera預覽中的展現,你應該通過在你的清單文件中添加以下設置,把應用程序的預覽Activity的方向改變為橫向的:

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

註意:Camera的預覽不一定就是橫屏模式。從Android2.2(API Level8)開始,你能夠使用setDisplayOrientation()方法來設置預覽圖像的旋轉。為瞭重新定位用戶手的預覽方向,在你的預覽類的surfaceChanged()方法中,首先要用Camera.stopPreview()方法停止預覽,然後改變方向,再用Camera.startPreview()方法啟動預覽。

在Camera View的Activity中,把你的預覽類添加到上例所示的FrameLayout元素中。你的Camera Activity還必須確保在它被掛起或關閉時,要釋放Camera對象。以下示例顯示如何把上文中創建的預覽類添加到Camera的Activity中:

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”中的示例方法。

采集圖片

一旦你構建瞭一個預覽類,並把它放到瞭一個View中,你就可以開始用你的應用程序來采集應用程序瞭。在你的應用程序代碼中,必須建立用於響應用戶拍照操作的用戶界面控件的監聽器。

要使用Camera.takePicture()方法來獲取一張圖片。這個方法需要3個參數來接收來自Camera的數據。為瞭接收JPEG格式的數據,你必須實現接收圖片數據的Camera.PictureCallback接口,並把接收到數據寫到一個文件中。下面的代碼顯示瞭一個Camera.PictureCallback接口的基本實現,它把從Camera接收到的數據保存到一個圖片文件中:

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());

        }

    }

};

通過調用Camera.takePicture()方法來觸發采集圖片的操作。下面的示例代碼顯示瞭如何從一個按鈕的View.OnClickListener中調用這個方法:

// 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);

        }

    }

);

註意:代碼中的mPicture成員變量會在下面的示例代碼中引用。

警告:記住,在應用程序使用完Camera對象後,一定要調用Camera.release()方法來釋放Camera對象。

采集視頻

使用Android框架采集視頻需要認真的管理Camera對象,以及跟MediaRecorder類的協調。當使用Camera對象記錄視頻時,除瞭Camera.open()和Camera.release()方法的調用以外,還必須管理Camera.lock()和Camera.unlock()方法的調用,從而允許MediaRecorder對象訪問Camera硬件。

註意:從Android4.0(API Level 14)開始,Camera.lock()和Camera.unlock()方法調用系統會為你自動管理。

跟拍照不一樣,采集視頻需要非常特殊的調用順序,必須按照一個特定執行順序來準備和采集視頻,詳細如下:

1. 打開Camera:使用Camera.open()方法來獲得一個Camera對象的實例。

2. 連接預覽:使用Camera.setPreviewDisplay()方法把SurfaceView跟Camera連接起來,準備一個實時的Camera圖像預覽界面。

3. 啟動預覽:調用Camera.starPreview()方法開始顯示實時的Camera圖像。

4. 啟動視頻錄像:為瞭成功的記錄視頻,必須完成以下步驟。

    a. 給Camera對象解鎖:通過調用Camera.unlock()方法給由MediaRecorder對象使用的Camera對象解鎖。

    b. 配置MediaRecorder對象:在這一步中要調用以下MediaRecorder方法。更多信息,請看MediaRecorder參考文檔。

       1. setCamera():使用應用程序當前的Camera實例,把它設置成用於視頻采集;

       2. setAudiioSource():使用MediaRecorder.AudioSource.CAMCORDER,設置音頻源;

       3. setVideoSource():使用MediaRecorder.VideoSource.CAMERA來設置視頻源;

       4. 設置視頻的輸出格式和編碼。對於Android2.2以上的版本,要使用MediaRecorder.setProfile方法,並且要私用CamcorderProfile.get()方法來獲得一個Profile的示例。對於Android2.2以前的版本,必須要設置視頻輸出的格式和編碼參數:

              I. setOutputFormat():設置輸出格式,指定默認設置,或者是MediaRecorder.OutputFormat.MPEG_4;

             II. setAudioEncoder():設置聲音的編碼類型,指定默認設置,或者是MediaRecorder.AudioEncoder.AMR_NB;

             III.setVideoEncoder():設置視頻的編碼類型,指定默認設置,或者是MediaRecorder.VideoEncoder.MPEG_4_SP;

        5. setOutputFile():設置輸出文件,可以使用下文“保存媒體文件”中的示例代碼中的getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()方法來獲取輸出文件路徑。

        6. setPreviewDisplay():給應用程序指定SurfaceView的預覽佈局。要使用與連接預覽相同的對象。

        警告:這步中必須要調用MediaRecorder的配置方法,否則你的應用程序將會發生錯誤,並且錄像也會失敗。

    c. 準備MediaRecorder對象:通過調用MediaRecorder.prepare()方法,準備給MediaRecorder對象提供的配置設置。

    d. 啟動MediaRecorder對象:通過調用MediaRecorder.star()方法來記錄視頻。

5. 停止視頻錄像:在這步中要調用以下方法來成功完成視頻記錄:

    a. 停止MediaRecorder對象:通過調用MediaRecorder.stop()方法來停止視頻采集

    b. 重置MediaRecorder對象:可選操作,通過調用MediaRecorder.reset()方法來刪除記錄器的配置設置。

    c. 釋放MediaRecorder對象:調用MediaRecorder.release()方法來釋放MediaRecorder對象。

    d. 鎖定Camera對象:調用Camera.lock()方法來鎖定Camera對象,以便MediaRecorder會話能夠繼續使用它。從Android4.0(API Level 14)開始,這個調用不再需要瞭,除非MediaRecorder.prepare()方法調用失敗。

6. 停止預覽:當Activity使用完Camera對象時,要使用Camera.stopPreview()方法來停止預覽。

7. 釋放Camera對象:調用Camera.release()方法來釋放Camera對象,以便其他應用程序能夠使用它。

註意:使用MediaRecorder對象,不首先創建Camera預覽,並跳過這個過程開始的幾步是可能的。但是,因為典型的在開始視頻采集之前,要給用戶看到圖像預覽,所以跳過的步驟It is possible to use MediaRecorder without creating a camera preview first and skip the first few steps of this process.在此就不討論瞭。

提示:如果你的應用程序被用於典型的視頻記錄,那麼在啟動預覽期間,把setRecordingHint(boolean)方法設置為true,這樣有助於減少啟動采集所需要的時間。

 

配置MediaRecorder對象

在使用MediaRecorder類來采集視頻時,必須按照指定的順利來執行配置處理,並且要調用MediaRecorder.prepare()方法來檢查和實現配置。下面的示例代碼演示瞭如何為采集視頻配置和準備MediaRecorder類:

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;

}

在Android2.2(API Level8)之前,必須要直接設置輸出格式和編碼格式參數,而不是使用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對象設置的默認的視頻采集參數,但是你可以在你的應用程序中來調整這些設置:

1.  setVideoEncodingBitRate()

2.  setVideoSize()

3.  setVideoFrameRate()

4.  setAudioEncodingBitRate()

5.  setAudioChannels()

6.  setAudioSamplingRate()

啟動和停止MediaRecorder對象

在使用MediaRecorder類來啟動和停止視頻采集時,必須按照以下順序來執行:

1.  用Camera.unlock()方法來解鎖Camera對象;

2.  向上面代碼中顯示的那樣來配置MediaRecorder;

3.  使用MediaRecorder.start()方法來啟動采集;

4.  記錄視頻;

5.  使用MediaRecorder.stop()方法來停止采集;

6.  使用MediaRecorder.release()方法來釋放媒體記錄器;

7.  使用Camera.lock()方法來鎖定Camera對象。

以下示例代碼演示瞭如何觸發一個按鈕正確的使用Camera和MediaRecorder類來啟動和停止視頻采集。

註意:當完成視頻采集時,不要釋放Camera,否則你的預覽將會被停止。

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”一節中的示例代碼。這個方法要鎖定Camera,然後配置和準備MediaRecorder示例。

釋放Camera

Camera是一種由應用程序共享的設備資源。在獲得一個Camera實例之後,你的應用程序才能夠使用Camera,並且要特別小心,在應用程序停止使用它的時候,即使是是應用程序被掛起(Activity.onPause()),一定要釋放Camera對象。如果應用程序沒有正確的釋放Camera,所有後續的訪問Camera的嘗試,包括你自己的應用程序,都會因訪問失敗而導致應用程序被關閉。

像下面的示例代碼那樣,使用Camera.release()方法來釋放Camera對象:

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;

        }

    }

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。