• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
onCreate(Bundle savedInstanceState)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      */
onCaptureClick(View view)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 
setCaptureButtonText(String title)105     private void setCaptureButtonText(String title) {
106         captureButton.setText(title);
107     }
108 
109     @Override
onPause()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 
releaseMediaRecorder()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 
releaseCamera()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)
prepareVideoRecorder()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
doInBackground(Void... voids)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
onPostExecute(Boolean result)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