Home | History | Annotate | Download | only in com.example.android.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     @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    140     private boolean prepareVideoRecorder(){
    141 
    142         // BEGIN_INCLUDE (configure_preview)
    143         mCamera = CameraHelper.getDefaultCameraInstance();
    144 
    145         // We need to make sure that our preview and recording video size are supported by the
    146         // camera. Query camera to find all the sizes and choose the optimal size given the
    147         // dimensions of our preview surface.
    148         Camera.Parameters parameters = mCamera.getParameters();
    149         List<Camera.Size> mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
    150         List<Camera.Size> mSupportedVideoSizes = parameters.getSupportedVideoSizes();
    151         Camera.Size optimalSize = CameraHelper.getOptimalVideoSize(mSupportedVideoSizes,
    152                 mSupportedPreviewSizes, mPreview.getWidth(), mPreview.getHeight());
    153 
    154         // Use the same size for recording profile.
    155         CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
    156         profile.videoFrameWidth = optimalSize.width;
    157         profile.videoFrameHeight = optimalSize.height;
    158 
    159         // likewise for the camera object itself.
    160         parameters.setPreviewSize(profile.videoFrameWidth, profile.videoFrameHeight);
    161         mCamera.setParameters(parameters);
    162         try {
    163                 // Requires API level 11+, For backward compatibility use {@link setPreviewDisplay}
    164                 // with {@link SurfaceView}
    165                 mCamera.setPreviewTexture(mPreview.getSurfaceTexture());
    166         } catch (IOException e) {
    167             Log.e(TAG, "Surface texture is unavailable or unsuitable" + e.getMessage());
    168             return false;
    169         }
    170         // END_INCLUDE (configure_preview)
    171 
    172 
    173         // BEGIN_INCLUDE (configure_media_recorder)
    174         mMediaRecorder = new MediaRecorder();
    175 
    176         // Step 1: Unlock and set camera to MediaRecorder
    177         mCamera.unlock();
    178         mMediaRecorder.setCamera(mCamera);
    179 
    180         // Step 2: Set sources
    181         mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT );
    182         mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    183 
    184         // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
    185         mMediaRecorder.setProfile(profile);
    186 
    187         // Step 4: Set output file
    188         mOutputFile = CameraHelper.getOutputMediaFile(CameraHelper.MEDIA_TYPE_VIDEO);
    189         if (mOutputFile == null) {
    190             return false;
    191         }
    192         mMediaRecorder.setOutputFile(mOutputFile.getPath());
    193         // END_INCLUDE (configure_media_recorder)
    194 
    195         // Step 5: Prepare configured MediaRecorder
    196         try {
    197             mMediaRecorder.prepare();
    198         } catch (IllegalStateException e) {
    199             Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
    200             releaseMediaRecorder();
    201             return false;
    202         } catch (IOException e) {
    203             Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
    204             releaseMediaRecorder();
    205             return false;
    206         }
    207         return true;
    208     }
    209 
    210     /**
    211      * Asynchronous task for preparing the {@link android.media.MediaRecorder} since it's a long blocking
    212      * operation.
    213      */
    214     class MediaPrepareTask extends AsyncTask<Void, Void, Boolean> {
    215 
    216         @Override
    217         protected Boolean doInBackground(Void... voids) {
    218             // initialize video camera
    219             if (prepareVideoRecorder()) {
    220                 // Camera is available and unlocked, MediaRecorder is prepared,
    221                 // now you can start recording
    222                 mMediaRecorder.start();
    223 
    224                 isRecording = true;
    225             } else {
    226                 // prepare didn't work, release the camera
    227                 releaseMediaRecorder();
    228                 return false;
    229             }
    230             return true;
    231         }
    232 
    233         @Override
    234         protected void onPostExecute(Boolean result) {
    235             if (!result) {
    236                 MainActivity.this.finish();
    237             }
    238             // inform the user that recording has started
    239             setCaptureButtonText("Stop");
    240 
    241         }
    242     }
    243 
    244 }
    245