Home | History | Annotate | Download | only in mediarecorder
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.mediarecorder;
     18 
     19 import android.annotation.TargetApi;
     20 import android.app.Activity;
     21 import android.hardware.Camera;
     22 import android.media.CamcorderProfile;
     23 import android.media.MediaRecorder;
     24 import android.os.AsyncTask;
     25 import android.os.Build;
     26 import android.os.Bundle;
     27 import android.util.Log;
     28 import android.view.Menu;
     29 import android.view.TextureView;
     30 import android.view.View;
     31 import android.widget.Button;
     32 
     33 import com.example.android.common.media.CameraHelper;
     34 
     35 import java.io.File;
     36 import java.io.IOException;
     37 import java.util.List;
     38 
     39 /**
     40  *  This activity uses the camera/camcorder as the A/V source for the {@link android.media.MediaRecorder} API.
     41  *  A {@link android.view.TextureView} is used as the camera preview which limits the code to API 14+. This
     42  *  can be easily replaced with a {@link android.view.SurfaceView} to run on older devices.
     43  */
     44 public class MainActivity extends Activity {
     45 
     46     private Camera mCamera;
     47     private TextureView mPreview;
     48     private MediaRecorder mMediaRecorder;
     49     private File mOutputFile;
     50 
     51     private boolean isRecording = false;
     52     private static final String TAG = "Recorder";
     53     private Button captureButton;
     54 
     55     @Override
     56     protected void onCreate(Bundle savedInstanceState) {
     57         super.onCreate(savedInstanceState);
     58         setContentView(R.layout.sample_main);
     59 
     60         mPreview = (TextureView) findViewById(R.id.surface_view);
     61         captureButton = (Button) findViewById(R.id.button_capture);
     62     }
     63 
     64     /**
     65      * The capture button controls all user interaction. When recording, the button click
     66      * stops recording, releases {@link android.media.MediaRecorder} and {@link android.hardware.Camera}. When not recording,
     67      * it prepares the {@link android.media.MediaRecorder} and starts recording.
     68      *
     69      * @param view the view generating the event.
     70      */
     71     public void onCaptureClick(View view) {
     72         if (isRecording) {
     73             // BEGIN_INCLUDE(stop_release_media_recorder)
     74 
     75             // stop recording and release camera
     76             try {
     77                 mMediaRecorder.stop();  // stop the recording
     78             } catch (RuntimeException e) {
     79                 // RuntimeException is thrown when stop() is called immediately after start().
     80                 // In this case the output file is not properly constructed ans should be deleted.
     81                 Log.d(TAG, "RuntimeException: stop() is called immediately after start()");
     82                 //noinspection ResultOfMethodCallIgnored
     83                 mOutputFile.delete();
     84             }
     85             releaseMediaRecorder(); // release the MediaRecorder object
     86             mCamera.lock();         // take camera access back from MediaRecorder
     87 
     88             // inform the user that recording has stopped
     89             setCaptureButtonText("Capture");
     90             isRecording = false;
     91             releaseCamera();
     92             // END_INCLUDE(stop_release_media_recorder)
     93 
     94         } else {
     95 
     96             // BEGIN_INCLUDE(prepare_start_media_recorder)
     97 
     98             new MediaPrepareTask().execute(null, null, null);
     99 
    100             // END_INCLUDE(prepare_start_media_recorder)
    101 
    102         }
    103     }
    104 
    105     private void setCaptureButtonText(String title) {
    106         captureButton.setText(title);
    107     }
    108 
    109     @Override
    110     protected void onPause() {
    111         super.onPause();
    112         // if we are using MediaRecorder, release it first
    113         releaseMediaRecorder();
    114         // release the camera immediately on pause event
    115         releaseCamera();
    116     }
    117 
    118     private void releaseMediaRecorder(){
    119         if (mMediaRecorder != null) {
    120             // clear recorder configuration
    121             mMediaRecorder.reset();
    122             // release the recorder object
    123             mMediaRecorder.release();
    124             mMediaRecorder = null;
    125             // Lock camera for later use i.e taking it back from MediaRecorder.
    126             // MediaRecorder doesn't need it anymore and we will release it if the activity pauses.
    127             mCamera.lock();
    128         }
    129     }
    130 
    131     private void releaseCamera(){
    132         if (mCamera != null){
    133             // release the camera for other applications
    134             mCamera.release();
    135             mCamera = null;
    136         }
    137     }
    138 
    139     private boolean prepareVideoRecorder(){
    140 
    141         // BEGIN_INCLUDE (configure_preview)
    142         mCamera = CameraHelper.getDefaultCameraInstance();
    143 
    144         // We need to make sure that our preview and recording video size are supported by the
    145         // camera. Query camera to find all the sizes and choose the optimal size given the
    146         // dimensions of our preview surface.
    147         Camera.Parameters parameters = mCamera.getParameters();
    148         List<Camera.Size> mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
    149         List<Camera.Size> mSupportedVideoSizes = parameters.getSupportedVideoSizes();
    150         Camera.Size optimalSize = CameraHelper.getOptimalVideoSize(mSupportedVideoSizes,
    151                 mSupportedPreviewSizes, mPreview.getWidth(), mPreview.getHeight());
    152 
    153         // Use the same size for recording profile.
    154         CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
    155         profile.videoFrameWidth = optimalSize.width;
    156         profile.videoFrameHeight = optimalSize.height;
    157 
    158         // likewise for the camera object itself.
    159         parameters.setPreviewSize(profile.videoFrameWidth, profile.videoFrameHeight);
    160         mCamera.setParameters(parameters);
    161         try {
    162                 // Requires API level 11+, For backward compatibility use {@link setPreviewDisplay}
    163                 // with {@link SurfaceView}
    164                 mCamera.setPreviewTexture(mPreview.getSurfaceTexture());
    165         } catch (IOException e) {
    166             Log.e(TAG, "Surface texture is unavailable or unsuitable" + e.getMessage());
    167             return false;
    168         }
    169         // END_INCLUDE (configure_preview)
    170 
    171 
    172         // BEGIN_INCLUDE (configure_media_recorder)
    173         mMediaRecorder = new MediaRecorder();
    174 
    175         // Step 1: Unlock and set camera to MediaRecorder
    176         mCamera.unlock();
    177         mMediaRecorder.setCamera(mCamera);
    178 
    179         // Step 2: Set sources
    180         mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT );
    181         mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    182 
    183         // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
    184         mMediaRecorder.setProfile(profile);
    185 
    186         // Step 4: Set output file
    187         mOutputFile = CameraHelper.getOutputMediaFile(CameraHelper.MEDIA_TYPE_VIDEO);
    188         if (mOutputFile == null) {
    189             return false;
    190         }
    191         mMediaRecorder.setOutputFile(mOutputFile.getPath());
    192         // END_INCLUDE (configure_media_recorder)
    193 
    194         // Step 5: Prepare configured MediaRecorder
    195         try {
    196             mMediaRecorder.prepare();
    197         } catch (IllegalStateException e) {
    198             Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
    199             releaseMediaRecorder();
    200             return false;
    201         } catch (IOException e) {
    202             Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
    203             releaseMediaRecorder();
    204             return false;
    205         }
    206         return true;
    207     }
    208 
    209     /**
    210      * Asynchronous task for preparing the {@link android.media.MediaRecorder} since it's a long blocking
    211      * operation.
    212      */
    213     class MediaPrepareTask extends AsyncTask<Void, Void, Boolean> {
    214 
    215         @Override
    216         protected Boolean doInBackground(Void... voids) {
    217             // initialize video camera
    218             if (prepareVideoRecorder()) {
    219                 // Camera is available and unlocked, MediaRecorder is prepared,
    220                 // now you can start recording
    221                 mMediaRecorder.start();
    222 
    223                 isRecording = true;
    224             } else {
    225                 // prepare didn't work, release the camera
    226                 releaseMediaRecorder();
    227                 return false;
    228             }
    229             return true;
    230         }
    231 
    232         @Override
    233         protected void onPostExecute(Boolean result) {
    234             if (!result) {
    235                 MainActivity.this.finish();
    236             }
    237             // inform the user that recording has started
    238             setCaptureButtonText("Stop");
    239 
    240         }
    241     }
    242 
    243 }
    244