blob: 23f4042525d85a0761ddcacf8d32f4a857043335 [file] [log] [blame]
Michael Kolb8872c232013-01-29 10:33:22 -08001/*
2 * Copyright (C) 2012 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
17package com.android.camera;
18
19import android.annotation.TargetApi;
20import android.app.Activity;
21import android.content.ActivityNotFoundException;
22import android.content.BroadcastReceiver;
23import android.content.ContentResolver;
24import android.content.ContentValues;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.SharedPreferences.Editor;
29import android.content.res.Configuration;
30import android.graphics.Bitmap;
Likai Ding40d36372014-11-20 08:00:28 +080031import android.graphics.SurfaceTexture;
Alok Kediya0dc64ff2013-09-27 20:22:45 +053032import android.graphics.ImageFormat;
Vijay kumar Tumatiefabd532014-03-24 18:45:35 +053033import android.hardware.Camera;
Michael Kolb8872c232013-01-29 10:33:22 -080034import android.hardware.Camera.CameraInfo;
35import android.hardware.Camera.Parameters;
Michael Kolb8872c232013-01-29 10:33:22 -080036import android.hardware.Camera.Size;
37import android.location.Location;
38import android.media.CamcorderProfile;
39import android.media.CameraProfile;
40import android.media.MediaRecorder;
41import android.net.Uri;
42import android.os.Build;
43import android.os.Bundle;
44import android.os.Handler;
45import android.os.Message;
Alok Kediya0dc64ff2013-09-27 20:22:45 +053046import android.os.SystemProperties;
Michael Kolb8872c232013-01-29 10:33:22 -080047import android.os.ParcelFileDescriptor;
48import android.os.SystemClock;
49import android.provider.MediaStore;
Ruben Brunk16007962013-04-19 15:27:57 -070050import android.provider.MediaStore.MediaColumns;
Michael Kolb8872c232013-01-29 10:33:22 -080051import android.provider.MediaStore.Video;
52import android.util.Log;
Michael Kolb8872c232013-01-29 10:33:22 -080053import android.view.KeyEvent;
Michael Kolb8872c232013-01-29 10:33:22 -080054import android.view.OrientationEventListener;
Michael Kolb8872c232013-01-29 10:33:22 -080055import android.view.View;
Michael Kolb8872c232013-01-29 10:33:22 -080056import android.view.WindowManager;
Michael Kolb8872c232013-01-29 10:33:22 -080057import android.widget.Toast;
Sai Kumar Sanagavarapubb994362013-12-03 18:33:47 +053058import android.media.EncoderCapabilities;
59import android.media.EncoderCapabilities.VideoEncoderCap;
Michael Kolb8872c232013-01-29 10:33:22 -080060
Angus Kong9ef99252013-07-18 18:04:19 -070061import com.android.camera.CameraManager.CameraPictureCallback;
Doris Liu6432cd62013-06-13 17:20:31 -070062import com.android.camera.CameraManager.CameraProxy;
Angus Kongb50b5cb2013-08-09 14:55:20 -070063import com.android.camera.app.OrientationManager;
ztenghuia16e7b52013-08-23 11:47:56 -070064import com.android.camera.exif.ExifInterface;
Michael Kolb8872c232013-01-29 10:33:22 -080065import com.android.camera.ui.RotateTextToast;
Sascha Haeberling638e6f02013-09-18 14:28:51 -070066import com.android.camera.util.AccessibilityUtils;
67import com.android.camera.util.ApiHelper;
Angus Kongb50b5cb2013-08-09 14:55:20 -070068import com.android.camera.util.CameraUtil;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070069import com.android.camera.util.UsageStatistics;
Sachin Shah89d153b2014-08-15 18:36:44 -070070import org.codeaurora.snapcam.R;
Alok Kediyad8887ed2013-09-28 17:12:35 +053071import com.android.camera.PhotoModule;
Angus Kongb50b5cb2013-08-09 14:55:20 -070072import java.io.File;
73import java.io.IOException;
74import java.text.SimpleDateFormat;
75import java.util.Date;
76import java.util.Iterator;
77import java.util.List;
Alok Kediyaaed65252013-09-23 14:31:42 +053078import java.util.HashMap;
Angus Kongb50b5cb2013-08-09 14:55:20 -070079
Michael Kolb8872c232013-01-29 10:33:22 -080080public class VideoModule implements CameraModule,
Doris Liu6827ce22013-03-12 19:24:28 -070081 VideoController,
Michael Kolb8872c232013-01-29 10:33:22 -080082 CameraPreference.OnPreferenceChangedListener,
83 ShutterButton.OnShutterButtonListener,
84 MediaRecorder.OnErrorListener,
Doris Liu3973deb2013-08-21 13:42:22 -070085 MediaRecorder.OnInfoListener {
Michael Kolb8872c232013-01-29 10:33:22 -080086
87 private static final String TAG = "CAM_VideoModule";
88
Michael Kolb8872c232013-01-29 10:33:22 -080089 private static final int CHECK_DISPLAY_ROTATION = 3;
90 private static final int CLEAR_SCREEN_DELAY = 4;
91 private static final int UPDATE_RECORD_TIME = 5;
92 private static final int ENABLE_SHUTTER_BUTTON = 6;
93 private static final int SHOW_TAP_TO_SNAPSHOT_TOAST = 7;
94 private static final int SWITCH_CAMERA = 8;
95 private static final int SWITCH_CAMERA_START_ANIMATION = 9;
Michael Kolb8872c232013-01-29 10:33:22 -080096
97 private static final int SCREEN_DELAY = 2 * 60 * 1000;
98
Shalaj Jain467b4f22014-11-10 14:01:09 -080099 private static final long SHUTTER_BUTTON_TIMEOUT = 0L; // 0ms
Michael Kolb8872c232013-01-29 10:33:22 -0800100
101 /**
102 * An unpublished intent flag requesting to start recording straight away
103 * and return as soon as recording is stopped.
104 * TODO: consider publishing by moving into MediaStore.
105 */
106 private static final String EXTRA_QUICK_CAPTURE =
107 "android.intent.extra.quickCapture";
108
Michael Kolb8872c232013-01-29 10:33:22 -0800109 // module fields
110 private CameraActivity mActivity;
Michael Kolb8872c232013-01-29 10:33:22 -0800111 private boolean mPaused;
112 private int mCameraId;
113 private Parameters mParameters;
114
Doris Liu6432cd62013-06-13 17:20:31 -0700115 private boolean mIsInReviewMode;
Michael Kolb8872c232013-01-29 10:33:22 -0800116 private boolean mSnapshotInProgress = false;
117
Michael Kolb8872c232013-01-29 10:33:22 -0800118 private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
119
120 private ComboPreferences mPreferences;
121 private PreferenceGroup mPreferenceGroup;
Santhosh Kumar H Eb2da1c12014-01-21 19:21:42 +0530122 private boolean mSaveToSDCard = false;
123
Angus Kong395ee2d2013-07-15 12:42:41 -0700124 // Preference must be read before starting preview. We check this before starting
125 // preview.
126 private boolean mPreferenceRead;
Michael Kolb8872c232013-01-29 10:33:22 -0800127
Michael Kolb8872c232013-01-29 10:33:22 -0800128 private boolean mIsVideoCaptureIntent;
129 private boolean mQuickCapture;
130
131 private MediaRecorder mMediaRecorder;
Michael Kolb8872c232013-01-29 10:33:22 -0800132
133 private boolean mSwitchingCamera;
134 private boolean mMediaRecorderRecording = false;
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +0530135 private boolean mMediaRecorderPausing = false;
Michael Kolb8872c232013-01-29 10:33:22 -0800136 private long mRecordingStartTime;
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +0530137 private long mRecordingTotalTime;
Michael Kolb8872c232013-01-29 10:33:22 -0800138 private boolean mRecordingTimeCountsDown = false;
Michael Kolb8872c232013-01-29 10:33:22 -0800139 private long mOnResumeTime;
140 // The video file that the hardware camera is about to record into
141 // (or is recording into.)
142 private String mVideoFilename;
143 private ParcelFileDescriptor mVideoFileDescriptor;
144
145 // The video file that has already been recorded, and that is being
146 // examined by the user.
147 private String mCurrentVideoFilename;
148 private Uri mCurrentVideoUri;
ztenghui70bd0242013-10-14 11:15:44 -0700149 private boolean mCurrentVideoUriFromMediaSaved;
Michael Kolb8872c232013-01-29 10:33:22 -0800150 private ContentValues mCurrentVideoValues;
151
152 private CamcorderProfile mProfile;
153
154 // The video duration limit. 0 menas no limit.
155 private int mMaxVideoDurationInMs;
156
157 // Time Lapse parameters.
158 private boolean mCaptureTimeLapse = false;
159 // Default 0. If it is larger than 0, the camcorder is in time lapse mode.
160 private int mTimeBetweenTimeLapseFrameCaptureMs = 0;
Michael Kolb8872c232013-01-29 10:33:22 -0800161
162 boolean mPreviewing = false; // True if preview is started.
163 // The display rotation in degrees. This is only valid when mPreviewing is
164 // true.
165 private int mDisplayRotation;
166 private int mCameraDisplayOrientation;
167
Doris Liu6827ce22013-03-12 19:24:28 -0700168 private int mDesiredPreviewWidth;
169 private int mDesiredPreviewHeight;
Michael Kolb8872c232013-01-29 10:33:22 -0800170 private ContentResolver mContentResolver;
171
172 private LocationManager mLocationManager;
Doris Liu6432cd62013-06-13 17:20:31 -0700173 private OrientationManager mOrientationManager;
Michael Kolb8872c232013-01-29 10:33:22 -0800174 private int mPendingSwitchCameraId;
Michael Kolb8872c232013-01-29 10:33:22 -0800175 private final Handler mHandler = new MainHandler();
Doris Liu6827ce22013-03-12 19:24:28 -0700176 private VideoUI mUI;
Doris Liu6432cd62013-06-13 17:20:31 -0700177 private CameraProxy mCameraDevice;
Cherian Deepaka1a59b92014-08-11 11:17:01 -0700178 private static final String KEY_PREVIEW_FORMAT = "preview-format";
179 private static final String FORMAT_NV12_VENUS = "nv12-venus";
Santhosh Kumar H Ef2d1e6e2014-12-16 17:18:41 +0530180 private static final String FORMAT_NV21 = "yuv420sp";
Doris Liu6432cd62013-06-13 17:20:31 -0700181
Michael Kolb8872c232013-01-29 10:33:22 -0800182 // The degrees of the device rotated clockwise from its natural orientation.
183 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
184
185 private int mZoomValue; // The current zoom value.
Doris Liu6827ce22013-03-12 19:24:28 -0700186
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +0530187 private boolean mStartRecPending = false;
188 private boolean mStopRecPending = false;
189 private boolean mStartPrevPending = false;
190 private boolean mStopPrevPending = false;
Dimitar Borisov19656472014-09-24 17:32:06 +0300191 private String mPrevSavedVideoCDS = null;
192 private String mTempVideoCDS = null;
193 private boolean mIsVideoTNREnabled;
194 private boolean mIsVideoCDSUpdated = false;
195 private boolean mOverrideCDS = false;
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +0530196
Vladimir Petrov1d7f2f22013-12-13 18:15:14 +0200197 // The preview window is on focus
198 private boolean mPreviewFocused = false;
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +0530199
Angus Kong83a99ae2013-04-17 15:37:07 -0700200 private final MediaSaveService.OnMediaSavedListener mOnVideoSavedListener =
201 new MediaSaveService.OnMediaSavedListener() {
202 @Override
203 public void onMediaSaved(Uri uri) {
204 if (uri != null) {
Doris Liu2a7f44c2013-08-12 15:18:53 -0700205 mCurrentVideoUri = uri;
ztenghui70bd0242013-10-14 11:15:44 -0700206 mCurrentVideoUriFromMediaSaved = true;
Doris Liu2a7f44c2013-08-12 15:18:53 -0700207 onVideoSaved();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700208 mActivity.notifyNewMedia(uri);
Angus Kong83a99ae2013-04-17 15:37:07 -0700209 }
210 }
211 };
212
213 private final MediaSaveService.OnMediaSavedListener mOnPhotoSavedListener =
Angus Kong86d36312013-01-31 18:22:44 -0800214 new MediaSaveService.OnMediaSavedListener() {
215 @Override
216 public void onMediaSaved(Uri uri) {
217 if (uri != null) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700218 mActivity.notifyNewMedia(uri);
Angus Kong86d36312013-01-31 18:22:44 -0800219 }
220 }
221 };
222
223
Michael Kolb8872c232013-01-29 10:33:22 -0800224 protected class CameraOpenThread extends Thread {
225 @Override
226 public void run() {
227 openCamera();
228 }
229 }
230
231 private void openCamera() {
Angus Kong4f795b82013-09-16 14:25:35 -0700232 if (mCameraDevice == null) {
233 mCameraDevice = CameraUtil.openCamera(
234 mActivity, mCameraId, mHandler,
235 mActivity.getCameraOpenErrorCallback());
Michael Kolb8872c232013-01-29 10:33:22 -0800236 }
Angus Kong4f795b82013-09-16 14:25:35 -0700237 if (mCameraDevice == null) {
238 // Error.
239 return;
240 }
241 mParameters = mCameraDevice.getParameters();
kaiyiza47e8252014-06-18 09:46:45 +0800242 mPreviewFocused = arePreviewControlsVisible();
Michael Kolb8872c232013-01-29 10:33:22 -0800243 }
244
Alok Kediyaaed65252013-09-23 14:31:42 +0530245 //QCOM data Members Starts here
246 static class DefaultHashMap<K, V> extends HashMap<K, V> {
247 private V mDefaultValue;
248
249 public void putDefault(V defaultValue) {
250 mDefaultValue = defaultValue;
251 }
252
253 @Override
254 public V get(Object key) {
255 V value = super.get(key);
256 return (value == null) ? mDefaultValue : value;
257 }
258 public K getKey(V toCheck) {
259 Iterator<K> it = this.keySet().iterator();
260 V val;
261 K key;
262 while(it.hasNext()) {
263 key = it.next();
264 val = this.get(key);
265 if (val.equals(toCheck)) {
266 return key;
267 }
268 }
269 return null;
270 }
271 }
272
273
274 private static final DefaultHashMap<String, Integer>
275 OUTPUT_FORMAT_TABLE = new DefaultHashMap<String, Integer>();
276 private static final DefaultHashMap<String, Integer>
277 VIDEO_ENCODER_TABLE = new DefaultHashMap<String, Integer>();
278 private static final DefaultHashMap<String, Integer>
279 AUDIO_ENCODER_TABLE = new DefaultHashMap<String, Integer>();
280 private static final DefaultHashMap<String, Integer>
281 VIDEOQUALITY_BITRATE_TABLE = new DefaultHashMap<String, Integer>();
282
283 static {
284 OUTPUT_FORMAT_TABLE.put("3gp", MediaRecorder.OutputFormat.THREE_GPP);
285 OUTPUT_FORMAT_TABLE.put("mp4", MediaRecorder.OutputFormat.MPEG_4);
286 OUTPUT_FORMAT_TABLE.putDefault(MediaRecorder.OutputFormat.DEFAULT);
287
288 VIDEO_ENCODER_TABLE.put("h263", MediaRecorder.VideoEncoder.H263);
289 VIDEO_ENCODER_TABLE.put("h264", MediaRecorder.VideoEncoder.H264);
Vladimir Petrovc1cd7782014-07-16 18:54:16 -0700290 VIDEO_ENCODER_TABLE.put("h265", MediaRecorder.VideoEncoder.H265);
Alok Kediyaaed65252013-09-23 14:31:42 +0530291 VIDEO_ENCODER_TABLE.put("m4v", MediaRecorder.VideoEncoder.MPEG_4_SP);
292 VIDEO_ENCODER_TABLE.putDefault(MediaRecorder.VideoEncoder.DEFAULT);
293
294 AUDIO_ENCODER_TABLE.put("amrnb", MediaRecorder.AudioEncoder.AMR_NB);
295 // Enabled once support is added in MediaRecorder.
296 // AUDIO_ENCODER_TABLE.put("qcelp", MediaRecorder.AudioEncoder.QCELP);
297 // AUDIO_ENCODER_TABLE.put("evrc", MediaRecorder.AudioEncoder.EVRC);
298 AUDIO_ENCODER_TABLE.put("amrwb", MediaRecorder.AudioEncoder.AMR_WB);
299 AUDIO_ENCODER_TABLE.put("aac", MediaRecorder.AudioEncoder.AAC);
300 AUDIO_ENCODER_TABLE.putDefault(MediaRecorder.AudioEncoder.DEFAULT);
301
302 }
303
304 private int mVideoEncoder;
305 private int mAudioEncoder;
306 private boolean mRestartPreview = false;
307 private int videoWidth;
308 private int videoHeight;
309 boolean mUnsupportedResolution = false;
Alok Kediya0dc64ff2013-09-27 20:22:45 +0530310 private boolean mUnsupportedHFRVideoSize = false;
Vijay kumar Tumati2ff6c252014-02-10 16:10:09 +0530311 private boolean mUnsupportedHSRVideoSize = false;
Alok Kediya0dc64ff2013-09-27 20:22:45 +0530312 private boolean mUnsupportedHFRVideoCodec = false;
Gaoxiang Chen1deb8752014-04-14 16:06:58 +0800313 private String mDefaultAntibanding = null;
Alok Kediyaaed65252013-09-23 14:31:42 +0530314
Michael Kolb8872c232013-01-29 10:33:22 -0800315 // This Handler is used to post message back onto the main thread of the
316 // application
317 private class MainHandler extends Handler {
318 @Override
319 public void handleMessage(Message msg) {
320 switch (msg.what) {
321
322 case ENABLE_SHUTTER_BUTTON:
Doris Liu6827ce22013-03-12 19:24:28 -0700323 mUI.enableShutter(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800324 break;
325
326 case CLEAR_SCREEN_DELAY: {
327 mActivity.getWindow().clearFlags(
328 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
329 break;
330 }
331
332 case UPDATE_RECORD_TIME: {
333 updateRecordingTime();
334 break;
335 }
336
337 case CHECK_DISPLAY_ROTATION: {
338 // Restart the preview if display rotation has changed.
339 // Sometimes this happens when the device is held upside
340 // down and camera app is opened. Rotation animation will
341 // take some time and the rotation value we have got may be
342 // wrong. Framework does not have a callback for this now.
Angus Kongb50b5cb2013-08-09 14:55:20 -0700343 if ((CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation)
Michael Kolb8872c232013-01-29 10:33:22 -0800344 && !mMediaRecorderRecording && !mSwitchingCamera) {
345 startPreview();
346 }
347 if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
348 mHandler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100);
349 }
350 break;
351 }
352
353 case SHOW_TAP_TO_SNAPSHOT_TOAST: {
354 showTapToSnapshotToast();
355 break;
356 }
357
358 case SWITCH_CAMERA: {
359 switchCamera();
360 break;
361 }
362
363 case SWITCH_CAMERA_START_ANIMATION: {
Doris Liu6432cd62013-06-13 17:20:31 -0700364 //TODO:
365 //((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera();
Michael Kolb8872c232013-01-29 10:33:22 -0800366
367 // Enable all camera controls.
368 mSwitchingCamera = false;
369 break;
370 }
371
Michael Kolb8872c232013-01-29 10:33:22 -0800372 default:
373 Log.v(TAG, "Unhandled message: " + msg.what);
374 break;
375 }
376 }
377 }
378
379 private BroadcastReceiver mReceiver = null;
380
381 private class MyBroadcastReceiver extends BroadcastReceiver {
382 @Override
383 public void onReceive(Context context, Intent intent) {
384 String action = intent.getAction();
385 if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
386 stopVideoRecording();
387 } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) {
388 Toast.makeText(mActivity,
389 mActivity.getResources().getString(R.string.wait), Toast.LENGTH_LONG).show();
390 }
391 }
392 }
393
394 private String createName(long dateTaken) {
395 Date date = new Date(dateTaken);
396 SimpleDateFormat dateFormat = new SimpleDateFormat(
397 mActivity.getString(R.string.video_file_name_format));
398
399 return dateFormat.format(date);
400 }
401
402 private int getPreferredCameraId(ComboPreferences preferences) {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700403 int intentCameraId = CameraUtil.getCameraFacingIntentExtras(mActivity);
Michael Kolb8872c232013-01-29 10:33:22 -0800404 if (intentCameraId != -1) {
405 // Testing purpose. Launch a specific camera through the intent
406 // extras.
407 return intentCameraId;
408 } else {
409 return CameraSettings.readPreferredCameraId(preferences);
410 }
411 }
412
413 private void initializeSurfaceView() {
Doris Liu6827ce22013-03-12 19:24:28 -0700414 if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { // API level < 16
Doris Liu6432cd62013-06-13 17:20:31 -0700415 mUI.initializeSurfaceView();
Michael Kolb8872c232013-01-29 10:33:22 -0800416 }
417 }
418
419 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700420 public void init(CameraActivity activity, View root) {
Michael Kolb8872c232013-01-29 10:33:22 -0800421 mActivity = activity;
Doris Liu6827ce22013-03-12 19:24:28 -0700422 mUI = new VideoUI(activity, this, root);
Michael Kolb8872c232013-01-29 10:33:22 -0800423 mPreferences = new ComboPreferences(mActivity);
424 CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal());
425 mCameraId = getPreferredCameraId(mPreferences);
426
427 mPreferences.setLocalId(mActivity, mCameraId);
428 CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
429
Doris Liu6432cd62013-06-13 17:20:31 -0700430 mOrientationManager = new OrientationManager(mActivity);
Michael Kolb8872c232013-01-29 10:33:22 -0800431
432 /*
433 * To reduce startup time, we start the preview in another thread.
434 * We make sure the preview is started at the end of onCreate.
435 */
436 CameraOpenThread cameraOpenThread = new CameraOpenThread();
437 cameraOpenThread.start();
438
439 mContentResolver = mActivity.getContentResolver();
440
Santhosh Kumar H Eb2da1c12014-01-21 19:21:42 +0530441 Storage.setSaveSDCard(
442 mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1"));
443 mSaveToSDCard = Storage.isSaveSDCard();
Michael Kolb8872c232013-01-29 10:33:22 -0800444 // Surface texture is from camera screen nail and startPreview needs it.
445 // This must be done before startPreview.
446 mIsVideoCaptureIntent = isVideoCaptureIntent();
Michael Kolb8872c232013-01-29 10:33:22 -0800447 initializeSurfaceView();
448
449 // Make sure camera device is opened.
450 try {
451 cameraOpenThread.join();
ztenghuief01a312013-10-14 15:25:16 -0700452 if (mCameraDevice == null) {
Michael Kolb8872c232013-01-29 10:33:22 -0800453 return;
454 }
455 } catch (InterruptedException ex) {
456 // ignore
457 }
458
459 readVideoPreferences();
Doris Liu6827ce22013-03-12 19:24:28 -0700460 mUI.setPrefChangedListener(this);
Michael Kolb8872c232013-01-29 10:33:22 -0800461
Michael Kolb8872c232013-01-29 10:33:22 -0800462 mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
463 mLocationManager = new LocationManager(mActivity, null);
464
Doris Liu6827ce22013-03-12 19:24:28 -0700465 mUI.setOrientationIndicator(0, false);
Michael Kolb8872c232013-01-29 10:33:22 -0800466 setDisplayOrientation();
467
Doris Liu6827ce22013-03-12 19:24:28 -0700468 mUI.showTimeLapseUI(mCaptureTimeLapse);
Michael Kolb8872c232013-01-29 10:33:22 -0800469 initializeVideoSnapshot();
470 resizeForPreviewAspectRatio();
471
472 initializeVideoControl();
473 mPendingSwitchCameraId = -1;
Doris Liu6827ce22013-03-12 19:24:28 -0700474 }
475
476 // SingleTapListener
477 // Preview area is touched. Take a picture.
478 @Override
479 public void onSingleTapUp(View view, int x, int y) {
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +0530480 if (mMediaRecorderPausing) return;
Doris Liu38605742013-08-13 15:01:52 -0700481 takeASnapshot();
482 }
483
484 private void takeASnapshot() {
Sascha Haeberlinga514b142013-08-13 16:10:01 -0700485 // Only take snapshots if video snapshot is supported by device
Susmitha Gummalla01c8ef22014-08-27 15:58:17 -0700486 if (CameraUtil.isVideoSnapshotSupported(mParameters) && !mIsVideoCaptureIntent) {
Doris Liu3973deb2013-08-21 13:42:22 -0700487 if (!mMediaRecorderRecording || mPaused || mSnapshotInProgress) {
Sascha Haeberlinga514b142013-08-13 16:10:01 -0700488 return;
489 }
Doris Liu38605742013-08-13 15:01:52 -0700490 MediaSaveService s = mActivity.getMediaSaveService();
Sascha Haeberlinga514b142013-08-13 16:10:01 -0700491 if (s == null || s.isQueueFull()) {
Doris Liu38605742013-08-13 15:01:52 -0700492 return;
493 }
494
495 // Set rotation and gps data.
496 int rotation = CameraUtil.getJpegRotation(mCameraId, mOrientation);
497 mParameters.setRotation(rotation);
498 Location loc = mLocationManager.getCurrentLocation();
499 CameraUtil.setGpsParameters(mParameters, loc);
500 mCameraDevice.setParameters(mParameters);
501
502 Log.v(TAG, "Video snapshot start");
503 mCameraDevice.takePicture(mHandler,
504 null, null, null, new JpegPictureCallback(loc));
505 showVideoSnapshotUI(true);
506 mSnapshotInProgress = true;
507 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
508 UsageStatistics.ACTION_CAPTURE_DONE, "VideoSnapshot");
Doris Liu6827ce22013-03-12 19:24:28 -0700509 }
Michael Kolb8872c232013-01-29 10:33:22 -0800510 }
511
512 @Override
513 public void onStop() {}
514
515 private void loadCameraPreferences() {
516 CameraSettings settings = new CameraSettings(mActivity, mParameters,
517 mCameraId, CameraHolder.instance().getCameraInfo());
518 // Remove the video quality preference setting when the quality is given in the intent.
519 mPreferenceGroup = filterPreferenceScreenByIntent(
520 settings.getPreferenceGroup(R.xml.video_preferences));
Vijay kumar Tumatiefabd532014-03-24 18:45:35 +0530521
522 int numOfCams = Camera.getNumberOfCameras();
523 int backCamId = CameraHolder.instance().getBackCameraId();
524 int frontCamId = CameraHolder.instance().getFrontCameraId();
525 // We need to swap the list preference contents if back camera and front camera
526 // IDs are not 0 and 1 respectively
527 if( (numOfCams == 2) && ((backCamId != CameraInfo.CAMERA_FACING_BACK)
528 || (frontCamId != CameraInfo.CAMERA_FACING_FRONT))) {
529 Log.e(TAG,"loadCameraPreferences() updating camera_id pref");
530
531 IconListPreference switchIconPref =
532 (IconListPreference)mPreferenceGroup.findPreference(
533 CameraSettings.KEY_CAMERA_ID);
534
535 int[] iconIds = {R.drawable.ic_switch_front, R.drawable.ic_switch_back};
536 switchIconPref.setIconIds(iconIds);
537
538 String[] entries = {mActivity.getResources().getString(
539 R.string.pref_camera_id_entry_front), mActivity.getResources().
540 getString(R.string.pref_camera_id_entry_back)};
541 switchIconPref.setEntries(entries);
542
543 String[] labels = {mActivity.getResources().getString(
544 R.string.pref_camera_id_label_front), mActivity.getResources().
545 getString(R.string.pref_camera_id_label_back)};
546 switchIconPref.setLabels(labels);
547
548 int[] largeIconIds = {R.drawable.ic_switch_front, R.drawable.ic_switch_back};
549 switchIconPref.setLargeIconIds(largeIconIds);
550 }
Michael Kolb8872c232013-01-29 10:33:22 -0800551 }
552
Michael Kolb8872c232013-01-29 10:33:22 -0800553 private void initializeVideoControl() {
554 loadCameraPreferences();
Doris Liu6827ce22013-03-12 19:24:28 -0700555 mUI.initializePopup(mPreferenceGroup);
Michael Kolb8872c232013-01-29 10:33:22 -0800556 }
557
Michael Kolb8872c232013-01-29 10:33:22 -0800558 @Override
559 public void onOrientationChanged(int orientation) {
560 // We keep the last known orientation. So if the user first orient
561 // the camera then point the camera to floor or sky, we still have
562 // the correct orientation.
563 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700564 int newOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -0800565
566 if (mOrientation != newOrientation) {
567 mOrientation = newOrientation;
Alok Kediya4b6f3f92013-09-28 17:39:13 +0530568 Log.v(TAG, "onOrientationChanged, update parameters");
Santhosh Kumar H E823c8f42014-10-16 11:20:34 +0530569 if ((mCameraDevice != null) && (mParameters != null)
570 && (true == mPreviewing) && !mMediaRecorderRecording){
571 setFlipValue();
572 mCameraDevice.setParameters(mParameters);
Alok Kediya4b6f3f92013-09-28 17:39:13 +0530573 }
Michael Kolb8872c232013-01-29 10:33:22 -0800574 }
575
576 // Show the toast after getting the first orientation changed.
577 if (mHandler.hasMessages(SHOW_TAP_TO_SNAPSHOT_TOAST)) {
578 mHandler.removeMessages(SHOW_TAP_TO_SNAPSHOT_TOAST);
579 showTapToSnapshotToast();
580 }
581 }
582
Michael Kolb8872c232013-01-29 10:33:22 -0800583 private void startPlayVideoActivity() {
584 Intent intent = new Intent(Intent.ACTION_VIEW);
585 intent.setDataAndType(mCurrentVideoUri, convertOutputFormatToMimeType(mProfile.fileFormat));
586 try {
Sascha Haeberlingb7639c62013-09-09 14:42:43 -0700587 mActivity
588 .startActivityForResult(intent, CameraActivity.REQ_CODE_DONT_SWITCH_TO_PREVIEW);
Michael Kolb8872c232013-01-29 10:33:22 -0800589 } catch (ActivityNotFoundException ex) {
590 Log.e(TAG, "Couldn't view video " + mCurrentVideoUri, ex);
591 }
592 }
593
ztenghui7b265a62013-09-09 14:58:44 -0700594 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800595 @OnClickAttr
596 public void onReviewPlayClicked(View v) {
597 startPlayVideoActivity();
598 }
599
ztenghui7b265a62013-09-09 14:58:44 -0700600 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800601 @OnClickAttr
602 public void onReviewDoneClicked(View v) {
Doris Liu69ef5ea2013-05-07 13:48:10 -0700603 mIsInReviewMode = false;
Michael Kolb8872c232013-01-29 10:33:22 -0800604 doReturnToCaller(true);
605 }
606
ztenghui7b265a62013-09-09 14:58:44 -0700607 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800608 @OnClickAttr
609 public void onReviewCancelClicked(View v) {
ztenghuiaf3a1972013-09-17 16:51:15 -0700610 // TODO: It should be better to not even insert the URI at all before we
611 // confirm done in review, which means we need to handle temporary video
612 // files in a quite different way than we currently had.
ztenghui70bd0242013-10-14 11:15:44 -0700613 // Make sure we don't delete the Uri sent from the video capture intent.
614 if (mCurrentVideoUriFromMediaSaved) {
ztenghuidfe5b152013-10-08 17:07:15 -0700615 mContentResolver.delete(mCurrentVideoUri, null, null);
616 }
ztenghui638bf9a2013-10-09 10:52:33 -0700617 mIsInReviewMode = false;
Michael Kolb8872c232013-01-29 10:33:22 -0800618 doReturnToCaller(false);
619 }
620
Doris Liu69ef5ea2013-05-07 13:48:10 -0700621 @Override
622 public boolean isInReviewMode() {
623 return mIsInReviewMode;
624 }
625
Michael Kolb8872c232013-01-29 10:33:22 -0800626 private void onStopVideoRecording() {
Michael Kolb8872c232013-01-29 10:33:22 -0800627 boolean recordFail = stopVideoRecording();
628 if (mIsVideoCaptureIntent) {
Doris Liu3973deb2013-08-21 13:42:22 -0700629 if (mQuickCapture) {
630 doReturnToCaller(!recordFail);
631 } else if (!recordFail) {
632 showCaptureResult();
Michael Kolb8872c232013-01-29 10:33:22 -0800633 }
634 } else if (!recordFail){
635 // Start capture animation.
636 if (!mPaused && ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) {
637 // The capture animation is disabled on ICS because we use SurfaceView
638 // for preview during recording. When the recording is done, we switch
639 // back to use SurfaceTexture for preview and we need to stop then start
640 // the preview. This will cause the preview flicker since the preview
641 // will not be continuous for a short period of time.
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700642
Sascha Haeberling37f36112013-08-06 14:31:52 -0700643 mUI.animateFlash();
Doris Liu3973deb2013-08-21 13:42:22 -0700644 mUI.animateCapture();
Michael Kolb8872c232013-01-29 10:33:22 -0800645 }
646 }
647 }
648
Doris Liu2a7f44c2013-08-12 15:18:53 -0700649 public void onVideoSaved() {
650 if (mIsVideoCaptureIntent) {
651 showCaptureResult();
652 }
653 }
654
Michael Kolb8872c232013-01-29 10:33:22 -0800655 public void onProtectiveCurtainClick(View v) {
656 // Consume clicks
657 }
658
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +0530659 public boolean isPreviewReady() {
660 if ((mStartPrevPending == true || mStopPrevPending == true))
661 return false;
662 else
663 return true;
664 }
665
666 public boolean isRecorderReady() {
667 if ((mStartRecPending == true || mStopRecPending == true))
668 return false;
669 else
670 return true;
671 }
672
Michael Kolb8872c232013-01-29 10:33:22 -0800673 @Override
674 public void onShutterButtonClick() {
Sai Kumar Sanagavarapu9b9fd082014-01-08 12:22:57 +0530675 if (mPaused || mUI.collapseCameraControls() ||
676 mSwitchingCamera) return;
Michael Kolb8872c232013-01-29 10:33:22 -0800677
678 boolean stop = mMediaRecorderRecording;
679
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +0530680 if (isPreviewReady() == false)
681 return;
682
683 if (isRecorderReady() == false)
684 return;
685
Shalaj Jain467b4f22014-11-10 14:01:09 -0800686 mUI.enableShutter(false);
687
Michael Kolb8872c232013-01-29 10:33:22 -0800688 if (stop) {
689 onStopVideoRecording();
690 } else {
691 startVideoRecording();
692 }
Michael Kolb8872c232013-01-29 10:33:22 -0800693
694 // Keep the shutter button disabled when in video capture intent
695 // mode and recording is stopped. It'll be re-enabled when
696 // re-take button is clicked.
697 if (!(mIsVideoCaptureIntent && stop)) {
698 mHandler.sendEmptyMessageDelayed(
699 ENABLE_SHUTTER_BUTTON, SHUTTER_BUTTON_TIMEOUT);
700 }
701 }
702
703 @Override
704 public void onShutterButtonFocus(boolean pressed) {
Doris Liu61f2b082013-03-27 17:25:43 -0700705 mUI.setShutterPressed(pressed);
Michael Kolb8872c232013-01-29 10:33:22 -0800706 }
707
Alok Kediyaf5b11812013-11-07 13:53:09 +0530708 @Override
709 public void onShutterButtonLongClick() {}
710
Alok Kediyaaed65252013-09-23 14:31:42 +0530711 private void qcomReadVideoPreferences() {
712 String videoEncoder = mPreferences.getString(
713 CameraSettings.KEY_VIDEO_ENCODER,
714 mActivity.getString(R.string.pref_camera_videoencoder_default));
715 mVideoEncoder = VIDEO_ENCODER_TABLE.get(videoEncoder);
716
717 Log.v(TAG, "Video Encoder selected = " +mVideoEncoder);
718
719 String audioEncoder = mPreferences.getString(
720 CameraSettings.KEY_AUDIO_ENCODER,
721 mActivity.getString(R.string.pref_camera_audioencoder_default));
722 mAudioEncoder = AUDIO_ENCODER_TABLE.get(audioEncoder);
723
724 Log.v(TAG, "Audio Encoder selected = " +mAudioEncoder);
725
726 String minutesStr = mPreferences.getString(
727 CameraSettings.KEY_VIDEO_DURATION,
728 mActivity.getString(R.string.pref_camera_video_duration_default));
729 int minutes = -1;
730 try {
731 minutes = Integer.parseInt(minutesStr);
732 } catch(NumberFormatException npe) {
733 // use default value continue
734 minutes = Integer.parseInt(mActivity.getString(
735 R.string.pref_camera_video_duration_default));
736 }
737 if (minutes == -1) {
738 // User wants lowest, set 30s */
739 mMaxVideoDurationInMs = 30000;
740 } else {
741 // 1 minute = 60000ms
742 mMaxVideoDurationInMs = 60000 * minutes;
743 }
744
Alok Kediya5302d2e2013-09-29 10:24:44 +0530745 if(mParameters.isPowerModeSupported()) {
746 String powermode = mPreferences.getString(
747 CameraSettings.KEY_POWER_MODE,
748 mActivity.getString(R.string.pref_camera_powermode_default));
749 Log.v(TAG, "read videopreferences power mode =" +powermode);
750 String old_mode = mParameters.getPowerMode();
751 if(!old_mode.equals(powermode) && mPreviewing)
752 mRestartPreview = true;
753
754 mParameters.setPowerMode(powermode);
755 }
Likai Ding8f56b812014-06-06 16:58:05 +0800756
757 // Set wavelet denoise mode
758 if (mParameters.getSupportedDenoiseModes() != null) {
759 String denoise = mPreferences.getString(CameraSettings.KEY_DENOISE,
760 mActivity.getString(R.string.pref_camera_denoise_default));
761 mParameters.setDenoise(denoise);
762 }
Alok Kediyaaed65252013-09-23 14:31:42 +0530763 }
764
Michael Kolb8872c232013-01-29 10:33:22 -0800765 private void readVideoPreferences() {
766 // The preference stores values from ListPreference and is thus string type for all values.
767 // We need to convert it to int manually.
Doris Liu3f7e0042013-07-31 11:25:09 -0700768 String videoQuality = mPreferences.getString(CameraSettings.KEY_VIDEO_QUALITY,
769 null);
770 if (videoQuality == null) {
Santhosh Kumar H E08c09042015-04-02 17:41:50 +0530771 mParameters = mCameraDevice.getParameters();
Santhosh Kumar H Ec4fb18b2013-11-15 18:54:05 +0530772 String defaultQuality = mActivity.getResources().getString(
773 R.string.pref_video_quality_default);
774 boolean hasProfile = CamcorderProfile.hasProfile(
Santhosh Kumar H E08c09042015-04-02 17:41:50 +0530775 CameraSettings.VIDEO_QUALITY_TABLE.get(defaultQuality));
Santhosh Kumar H Ec4fb18b2013-11-15 18:54:05 +0530776 if (hasProfile == true){
777 videoQuality = defaultQuality;
778 } else {
779 // check for highest quality if default quality is not supported
780 videoQuality = CameraSettings.getSupportedHighestVideoQuality(mCameraId,
781 defaultQuality, mParameters);
782 }
Doris Liu3f7e0042013-07-31 11:25:09 -0700783 mPreferences.edit().putString(CameraSettings.KEY_VIDEO_QUALITY, videoQuality);
784 }
Santhosh Kumar H E08c09042015-04-02 17:41:50 +0530785 int quality = CameraSettings.VIDEO_QUALITY_TABLE.get(videoQuality);
Michael Kolb8872c232013-01-29 10:33:22 -0800786
787 // Set video quality.
788 Intent intent = mActivity.getIntent();
789 if (intent.hasExtra(MediaStore.EXTRA_VIDEO_QUALITY)) {
790 int extraVideoQuality =
791 intent.getIntExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
792 if (extraVideoQuality > 0) {
793 quality = CamcorderProfile.QUALITY_HIGH;
794 } else { // 0 is mms.
795 quality = CamcorderProfile.QUALITY_LOW;
796 }
797 }
798
799 // Set video duration limit. The limit is read from the preference,
800 // unless it is specified in the intent.
801 if (intent.hasExtra(MediaStore.EXTRA_DURATION_LIMIT)) {
802 int seconds =
803 intent.getIntExtra(MediaStore.EXTRA_DURATION_LIMIT, 0);
804 mMaxVideoDurationInMs = 1000 * seconds;
805 } else {
806 mMaxVideoDurationInMs = CameraSettings.getMaxVideoDuration(mActivity);
807 }
808
Michael Kolb8872c232013-01-29 10:33:22 -0800809 // Read time lapse recording interval.
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700810 String frameIntervalStr = mPreferences.getString(
811 CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL,
812 mActivity.getString(R.string.pref_video_time_lapse_frame_interval_default));
813 mTimeBetweenTimeLapseFrameCaptureMs = Integer.parseInt(frameIntervalStr);
814 mCaptureTimeLapse = (mTimeBetweenTimeLapseFrameCaptureMs != 0);
Michael Kolb8872c232013-01-29 10:33:22 -0800815 // TODO: This should be checked instead directly +1000.
816 if (mCaptureTimeLapse) quality += 1000;
817 mProfile = CamcorderProfile.get(mCameraId, quality);
818 getDesiredPreviewSize();
Alok Kediyaaed65252013-09-23 14:31:42 +0530819 qcomReadVideoPreferences();
Angus Kong395ee2d2013-07-15 12:42:41 -0700820 mPreferenceRead = true;
Michael Kolb8872c232013-01-29 10:33:22 -0800821 }
822
Azam Sadiq Pasha Kapatrala Syed2c309492013-12-26 12:38:20 -0800823 private boolean is4KEnabled() {
Chiou-Hao Hsu7ec9d242014-07-21 22:57:45 -0700824 if (mProfile.quality == CamcorderProfile.QUALITY_2160P ||
Azam Sadiq Pasha Kapatrala Syed2c309492013-12-26 12:38:20 -0800825 mProfile.quality == CamcorderProfile.QUALITY_4kDCI) {
826 return true;
827 } else {
828 return false;
829 }
830 }
831
Cherian Deepaka1a59b92014-08-11 11:17:01 -0700832 private boolean is1080pEnabled() {
833 if (mProfile.quality == CamcorderProfile.QUALITY_1080P) {
834 return true;
835 } else {
836 return false;
837 }
838 }
839
satyavaraprasad yerramsetti9747e002014-10-17 12:53:48 +0530840 private boolean is720pEnabled() {
841 if (mProfile.quality == CamcorderProfile.QUALITY_720P) {
842 return true;
843 } else {
844 return false;
845 }
846 }
847
Emilian Peev759452b2014-04-29 14:10:03 -0700848 boolean isHFREnabled(int videoWidth, int videoHeight) {
849 if ((null == mPreferences) || (null == mParameters)) {
850 return false;
851 }
852
853 String HighFrameRate = mPreferences.getString(
854 CameraSettings.KEY_VIDEO_HIGH_FRAME_RATE,
855 mActivity. getString(R.string.pref_camera_hfr_default));
856
Leena Winterrowdc48e5f82014-08-21 14:12:04 -0700857 if(!("off".equals(HighFrameRate))) {
Emilian Peev759452b2014-04-29 14:10:03 -0700858 Size size = null;
859 try {
Leena Winterrowd3fab9522014-08-21 14:08:34 -0700860 if (isSupported(HighFrameRate.substring(3), mParameters.getSupportedVideoHighFrameRateModes())) {
Emilian Peev759452b2014-04-29 14:10:03 -0700861 int index = mParameters.getSupportedVideoHighFrameRateModes().indexOf(
Leena Winterrowd3fab9522014-08-21 14:08:34 -0700862 HighFrameRate.substring(3));
Emilian Peev759452b2014-04-29 14:10:03 -0700863 size = mParameters.getSupportedHfrSizes().get(index);
864 } else {
865 return false;
866 }
867 } catch (NullPointerException e) {
868 return false;
869 } catch (IndexOutOfBoundsException e) {
870 return false;
871 }
872
873 if (size != null) {
874 if (videoWidth > size.width || videoHeight > size.height) {
875 return false;
876 }
877 } else {
878 return false;
879 }
880
Leena Winterrowd3fab9522014-08-21 14:08:34 -0700881 int hfrFps = Integer.parseInt(HighFrameRate.substring(3));
Emilian Peev759452b2014-04-29 14:10:03 -0700882 int inputBitrate = videoWidth * videoHeight * hfrFps;
883
884 boolean supported = false;
885 List<VideoEncoderCap> videoEncoders = EncoderCapabilities.getVideoEncoders();
886 for (VideoEncoderCap videoEncoder: videoEncoders) {
887 if (videoEncoder.mCodec == mVideoEncoder) {
888 int maxBitrate = (videoEncoder.mMaxHFRFrameWidth *
889 videoEncoder.mMaxHFRFrameHeight *
890 videoEncoder.mMaxHFRMode);
891 if (inputBitrate > 0 && inputBitrate <= maxBitrate ) {
892 supported = true;
893 }
894 break;
895 }
896 }
897
898 return supported;
899 }
900
901 return false;
902 }
Cherian Deepaka1a59b92014-08-11 11:17:01 -0700903
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700904 @TargetApi(Build.VERSION_CODES.HONEYCOMB)
Michael Kolb8872c232013-01-29 10:33:22 -0800905 private void getDesiredPreviewSize() {
ztenghuief01a312013-10-14 15:25:16 -0700906 if (mCameraDevice == null) {
907 return;
908 }
Doris Liu6432cd62013-06-13 17:20:31 -0700909 mParameters = mCameraDevice.getParameters();
satyavaraprasad yerramsetti9747e002014-10-17 12:53:48 +0530910 if (mParameters.getSupportedVideoSizes() == null || is1080pEnabled() || is720pEnabled() ||
Emilian Peev759452b2014-04-29 14:10:03 -0700911 isHFREnabled(mProfile.videoFrameWidth, mProfile.videoFrameHeight)) {
Michael Kolb8872c232013-01-29 10:33:22 -0800912 mDesiredPreviewWidth = mProfile.videoFrameWidth;
913 mDesiredPreviewHeight = mProfile.videoFrameHeight;
Sascha Haeberling638e6f02013-09-18 14:28:51 -0700914 } else { // Driver supports separates outputs for preview and video.
915 List<Size> sizes = mParameters.getSupportedPreviewSizes();
916 Size preferred = mParameters.getPreferredPreviewSizeForVideo();
917 int product = preferred.width * preferred.height;
918 Iterator<Size> it = sizes.iterator();
919 // Remove the preview sizes that are not preferred.
920 while (it.hasNext()) {
921 Size size = it.next();
922 if (size.width * size.height > product) {
923 it.remove();
924 }
925 }
926 Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
927 (double) mProfile.videoFrameWidth / mProfile.videoFrameHeight);
928 mDesiredPreviewWidth = optimalSize.width;
929 mDesiredPreviewHeight = optimalSize.height;
Michael Kolb8872c232013-01-29 10:33:22 -0800930 }
Doris Liu6432cd62013-06-13 17:20:31 -0700931 mUI.setPreviewSize(mDesiredPreviewWidth, mDesiredPreviewHeight);
Michael Kolb8872c232013-01-29 10:33:22 -0800932 Log.v(TAG, "mDesiredPreviewWidth=" + mDesiredPreviewWidth +
933 ". mDesiredPreviewHeight=" + mDesiredPreviewHeight);
934 }
935
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +0530936 void setPreviewFrameLayoutCameraOrientation(){
937 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
938
939 //if camera mount angle is 0 or 180, we want to resize preview
940 if (info.orientation % 180 == 0)
941 mUI.cameraOrientationPreviewResize(true);
942 else
943 mUI.cameraOrientationPreviewResize(false);
944 }
945
Santhosh Kumar H Ef7e9b672013-11-12 14:42:09 +0530946 @Override
947 public void resizeForPreviewAspectRatio() {
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +0530948 setPreviewFrameLayoutCameraOrientation();
Doris Liu6827ce22013-03-12 19:24:28 -0700949 mUI.setAspectRatio(
Michael Kolb8872c232013-01-29 10:33:22 -0800950 (double) mProfile.videoFrameWidth / mProfile.videoFrameHeight);
951 }
952
953 @Override
kaiyizde529662014-07-21 16:47:27 +0800954 public void onSwitchSavePath() {
955 mUI.setPreference(CameraSettings.KEY_CAMERA_SAVEPATH, "1");
956 Toast.makeText(mActivity, R.string.on_switch_save_path_to_sdcard,
957 Toast.LENGTH_SHORT).show();
958 }
959
960 @Override
Michael Kolb8872c232013-01-29 10:33:22 -0800961 public void installIntentFilter() {
962 // install an intent filter to receive SD card related events.
963 IntentFilter intentFilter =
964 new IntentFilter(Intent.ACTION_MEDIA_EJECT);
965 intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
966 intentFilter.addDataScheme("file");
967 mReceiver = new MyBroadcastReceiver();
968 mActivity.registerReceiver(mReceiver, intentFilter);
969 }
970
971 @Override
972 public void onResumeBeforeSuper() {
973 mPaused = false;
974 }
975
976 @Override
977 public void onResumeAfterSuper() {
Doris Liu6827ce22013-03-12 19:24:28 -0700978 mUI.enableShutter(false);
Michael Kolb8872c232013-01-29 10:33:22 -0800979 mZoomValue = 0;
980
981 showVideoSnapshotUI(false);
982
Michael Kolb8872c232013-01-29 10:33:22 -0800983 if (!mPreviewing) {
Michael Kolb8872c232013-01-29 10:33:22 -0800984 openCamera();
ztenghuief01a312013-10-14 15:25:16 -0700985 if (mCameraDevice == null) {
Michael Kolb8872c232013-01-29 10:33:22 -0800986 return;
987 }
988 readVideoPreferences();
989 resizeForPreviewAspectRatio();
Angus Kong395ee2d2013-07-15 12:42:41 -0700990 startPreview();
Doris Liuc774ff92013-03-20 19:25:47 -0700991 } else {
992 // preview already started
993 mUI.enableShutter(true);
Michael Kolb8872c232013-01-29 10:33:22 -0800994 }
995
Doris Liu59390062013-10-10 17:20:56 -0700996 mUI.initDisplayChangeListener();
Michael Kolb8872c232013-01-29 10:33:22 -0800997 // Initializing it here after the preview is started.
Doris Liu6827ce22013-03-12 19:24:28 -0700998 mUI.initializeZoom(mParameters);
Michael Kolb8872c232013-01-29 10:33:22 -0800999
1000 keepScreenOnAwhile();
1001
Angus Kongce2b9492013-09-05 17:49:06 -07001002 mOrientationManager.resume();
Michael Kolb8872c232013-01-29 10:33:22 -08001003 // Initialize location service.
1004 boolean recordLocation = RecordLocationPreference.get(mPreferences,
1005 mContentResolver);
1006 mLocationManager.recordLocation(recordLocation);
1007
1008 if (mPreviewing) {
1009 mOnResumeTime = SystemClock.uptimeMillis();
1010 mHandler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100);
1011 }
Michael Kolb8872c232013-01-29 10:33:22 -08001012
Bobby Georgescu0a7dd572013-03-12 22:45:17 -07001013 UsageStatistics.onContentViewChanged(
1014 UsageStatistics.COMPONENT_CAMERA, "VideoModule");
Santhosh Kumar H Ef4f601b2013-11-29 12:45:08 +05301015 mHandler.post(new Runnable(){
1016 @Override
1017 public void run(){
1018 mActivity.updateStorageSpaceAndHint();
1019 }
1020 });
Michael Kolb8872c232013-01-29 10:33:22 -08001021 }
1022
1023 private void setDisplayOrientation() {
Angus Kongb50b5cb2013-08-09 14:55:20 -07001024 mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
1025 mCameraDisplayOrientation = CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId);
Doris Liu6432cd62013-06-13 17:20:31 -07001026 // Change the camera display orientation
1027 if (mCameraDevice != null) {
1028 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001029 }
Doris Liu6432cd62013-06-13 17:20:31 -07001030 }
1031
1032 @Override
1033 public void updateCameraOrientation() {
1034 if (mMediaRecorderRecording) return;
Angus Kongb50b5cb2013-08-09 14:55:20 -07001035 if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001036 setDisplayOrientation();
1037 }
Michael Kolb8872c232013-01-29 10:33:22 -08001038 }
1039
Doris Liu6827ce22013-03-12 19:24:28 -07001040 @Override
1041 public int onZoomChanged(int index) {
1042 // Not useful to change zoom value when the activity is paused.
1043 if (mPaused) return index;
1044 mZoomValue = index;
Doris Liu6432cd62013-06-13 17:20:31 -07001045 if (mParameters == null || mCameraDevice == null) return index;
Doris Liu6827ce22013-03-12 19:24:28 -07001046 // Set zoom parameters asynchronously
1047 mParameters.setZoom(mZoomValue);
Doris Liu6432cd62013-06-13 17:20:31 -07001048 mCameraDevice.setParameters(mParameters);
1049 Parameters p = mCameraDevice.getParameters();
Doris Liu6827ce22013-03-12 19:24:28 -07001050 if (p != null) return p.getZoom();
1051 return index;
1052 }
Angus Kong395ee2d2013-07-15 12:42:41 -07001053
Michael Kolb8872c232013-01-29 10:33:22 -08001054 private void startPreview() {
1055 Log.v(TAG, "startPreview");
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +05301056 mStartPrevPending = true;
Michael Kolb8872c232013-01-29 10:33:22 -08001057
Likai Ding40d36372014-11-20 08:00:28 +08001058 SurfaceTexture surfaceTexture = mUI.getSurfaceTexture();
1059 if (!mPreferenceRead || surfaceTexture == null || mPaused == true ||
1060 mCameraDevice == null) {
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +05301061 mStartPrevPending = false;
ztenghuief01a312013-10-14 15:25:16 -07001062 return;
1063 }
Angus Kong395ee2d2013-07-15 12:42:41 -07001064
Doris Liu6432cd62013-06-13 17:20:31 -07001065 mCameraDevice.setErrorCallback(mErrorCallback);
Michael Kolb8872c232013-01-29 10:33:22 -08001066 if (mPreviewing == true) {
1067 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001068 }
1069
Michael Kolb8872c232013-01-29 10:33:22 -08001070 setDisplayOrientation();
Doris Liu6432cd62013-06-13 17:20:31 -07001071 mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
Michael Kolb8872c232013-01-29 10:33:22 -08001072 setCameraParameters();
1073
1074 try {
Likai Ding40d36372014-11-20 08:00:28 +08001075 mCameraDevice.setPreviewTexture(surfaceTexture);
Doris Liu3973deb2013-08-21 13:42:22 -07001076 mCameraDevice.startPreview();
1077 mPreviewing = true;
1078 onPreviewStarted();
Michael Kolb8872c232013-01-29 10:33:22 -08001079 } catch (Throwable ex) {
1080 closeCamera();
1081 throw new RuntimeException("startPreview failed", ex);
Michael Kolb8872c232013-01-29 10:33:22 -08001082 }
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +05301083 mStartPrevPending = false;
Michael Kolbb1aeb392013-03-11 12:37:40 -07001084 }
1085
1086 private void onPreviewStarted() {
Doris Liu6827ce22013-03-12 19:24:28 -07001087 mUI.enableShutter(true);
Michael Kolb8872c232013-01-29 10:33:22 -08001088 }
1089
Doris Liu6827ce22013-03-12 19:24:28 -07001090 @Override
1091 public void stopPreview() {
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +05301092 mStopPrevPending = true;
1093
1094 if (!mPreviewing) {
1095 mStopPrevPending = false;
1096 return;
1097 }
Doris Liu6432cd62013-06-13 17:20:31 -07001098 mCameraDevice.stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001099 mPreviewing = false;
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +05301100 mStopPrevPending = false;
Likai Ding84793162014-06-06 11:25:20 +08001101 mUI.enableShutter(false);
Michael Kolb8872c232013-01-29 10:33:22 -08001102 }
1103
Michael Kolb8872c232013-01-29 10:33:22 -08001104 private void closeCamera() {
Michael Kolb8872c232013-01-29 10:33:22 -08001105 Log.v(TAG, "closeCamera");
Doris Liu6432cd62013-06-13 17:20:31 -07001106 if (mCameraDevice == null) {
Michael Kolb8872c232013-01-29 10:33:22 -08001107 Log.d(TAG, "already stopped.");
1108 return;
1109 }
Doris Liu6432cd62013-06-13 17:20:31 -07001110 mCameraDevice.setZoomChangeListener(null);
1111 mCameraDevice.setErrorCallback(null);
Angus Kong9ef99252013-07-18 18:04:19 -07001112 CameraHolder.instance().release();
Angus Kong395ee2d2013-07-15 12:42:41 -07001113 mCameraDevice = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001114 mPreviewing = false;
1115 mSnapshotInProgress = false;
Vladimir Petrov1d7f2f22013-12-13 18:15:14 +02001116 mPreviewFocused = false;
Michael Kolb8872c232013-01-29 10:33:22 -08001117 }
1118
1119 private void releasePreviewResources() {
Doris Liu6432cd62013-06-13 17:20:31 -07001120 if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) {
1121 mUI.hideSurfaceView();
Michael Kolb8872c232013-01-29 10:33:22 -08001122 }
1123 }
1124
1125 @Override
1126 public void onPauseBeforeSuper() {
1127 mPaused = true;
1128
Doris Liu3a45c332013-10-15 19:10:28 -07001129 mUI.showPreviewCover();
Michael Kolb8872c232013-01-29 10:33:22 -08001130 if (mMediaRecorderRecording) {
1131 // Camera will be released in onStopVideoRecording.
1132 onStopVideoRecording();
1133 } else {
1134 closeCamera();
Doris Liu3973deb2013-08-21 13:42:22 -07001135 releaseMediaRecorder();
Michael Kolb8872c232013-01-29 10:33:22 -08001136 }
Doris Liu3973deb2013-08-21 13:42:22 -07001137
1138 closeVideoFileDescriptor();
1139
Michael Kolb8872c232013-01-29 10:33:22 -08001140
1141 releasePreviewResources();
1142
1143 if (mReceiver != null) {
1144 mActivity.unregisterReceiver(mReceiver);
1145 mReceiver = null;
1146 }
1147 resetScreenOn();
1148
1149 if (mLocationManager != null) mLocationManager.recordLocation(false);
Angus Kongce2b9492013-09-05 17:49:06 -07001150 mOrientationManager.pause();
Michael Kolb8872c232013-01-29 10:33:22 -08001151
1152 mHandler.removeMessages(CHECK_DISPLAY_ROTATION);
1153 mHandler.removeMessages(SWITCH_CAMERA);
1154 mHandler.removeMessages(SWITCH_CAMERA_START_ANIMATION);
1155 mPendingSwitchCameraId = -1;
1156 mSwitchingCamera = false;
Angus Kong395ee2d2013-07-15 12:42:41 -07001157 mPreferenceRead = false;
Doris Liuc3679c02013-08-08 18:08:43 -07001158
1159 mUI.collapseCameraControls();
Doris Liu59390062013-10-10 17:20:56 -07001160 mUI.removeDisplayChangeListener();
Michael Kolb8872c232013-01-29 10:33:22 -08001161 }
1162
1163 @Override
1164 public void onPauseAfterSuper() {
1165 }
1166
1167 @Override
1168 public void onUserInteraction() {
1169 if (!mMediaRecorderRecording && !mActivity.isFinishing()) {
1170 keepScreenOnAwhile();
1171 }
1172 }
1173
1174 @Override
1175 public boolean onBackPressed() {
1176 if (mPaused) return true;
1177 if (mMediaRecorderRecording) {
1178 onStopVideoRecording();
1179 return true;
Likai Ding1e4d9572014-11-20 08:01:08 +08001180 } else if (mUI.hidePieRenderer()) {
Michael Kolb8872c232013-01-29 10:33:22 -08001181 return true;
1182 } else {
Likai Ding1e4d9572014-11-20 08:01:08 +08001183 return mUI.removeTopLevelPopup();
Michael Kolb8872c232013-01-29 10:33:22 -08001184 }
1185 }
1186
1187 @Override
1188 public boolean onKeyDown(int keyCode, KeyEvent event) {
1189 // Do not handle any key if the activity is paused.
1190 if (mPaused) {
1191 return true;
1192 }
1193
1194 switch (keyCode) {
1195 case KeyEvent.KEYCODE_CAMERA:
1196 if (event.getRepeatCount() == 0) {
Doris Liu6827ce22013-03-12 19:24:28 -07001197 mUI.clickShutter();
Michael Kolb8872c232013-01-29 10:33:22 -08001198 return true;
1199 }
1200 break;
1201 case KeyEvent.KEYCODE_DPAD_CENTER:
1202 if (event.getRepeatCount() == 0) {
Doris Liu6827ce22013-03-12 19:24:28 -07001203 mUI.clickShutter();
Michael Kolb8872c232013-01-29 10:33:22 -08001204 return true;
1205 }
1206 break;
1207 case KeyEvent.KEYCODE_MENU:
1208 if (mMediaRecorderRecording) return true;
1209 break;
1210 }
1211 return false;
1212 }
1213
1214 @Override
1215 public boolean onKeyUp(int keyCode, KeyEvent event) {
1216 switch (keyCode) {
1217 case KeyEvent.KEYCODE_CAMERA:
Doris Liu6827ce22013-03-12 19:24:28 -07001218 mUI.pressShutter(false);
Michael Kolb8872c232013-01-29 10:33:22 -08001219 return true;
1220 }
1221 return false;
1222 }
1223
Doris Liu6827ce22013-03-12 19:24:28 -07001224 @Override
1225 public boolean isVideoCaptureIntent() {
Michael Kolb8872c232013-01-29 10:33:22 -08001226 String action = mActivity.getIntent().getAction();
1227 return (MediaStore.ACTION_VIDEO_CAPTURE.equals(action));
1228 }
1229
1230 private void doReturnToCaller(boolean valid) {
1231 Intent resultIntent = new Intent();
1232 int resultCode;
1233 if (valid) {
1234 resultCode = Activity.RESULT_OK;
1235 resultIntent.setData(mCurrentVideoUri);
1236 } else {
1237 resultCode = Activity.RESULT_CANCELED;
1238 }
1239 mActivity.setResultEx(resultCode, resultIntent);
1240 mActivity.finish();
1241 }
1242
1243 private void cleanupEmptyFile() {
1244 if (mVideoFilename != null) {
1245 File f = new File(mVideoFilename);
1246 if (f.length() == 0 && f.delete()) {
1247 Log.v(TAG, "Empty video file deleted: " + mVideoFilename);
1248 mVideoFilename = null;
1249 }
1250 }
1251 }
1252
1253 private void setupMediaRecorderPreviewDisplay() {
1254 // Nothing to do here if using SurfaceTexture.
Doris Liu6432cd62013-06-13 17:20:31 -07001255 if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) {
Michael Kolb8872c232013-01-29 10:33:22 -08001256 // We stop the preview here before unlocking the device because we
1257 // need to change the SurfaceTexture to SurfaceView for preview.
1258 stopPreview();
Angus Kong9ef99252013-07-18 18:04:19 -07001259 mCameraDevice.setPreviewDisplay(mUI.getSurfaceHolder());
Michael Kolb8872c232013-01-29 10:33:22 -08001260 // The orientation for SurfaceTexture is different from that for
1261 // SurfaceView. For SurfaceTexture we don't need to consider the
1262 // display rotation. Just consider the sensor's orientation and we
1263 // will set the orientation correctly when showing the texture.
1264 // Gallery will handle the orientation for the preview. For
1265 // SurfaceView we will have to take everything into account so the
1266 // display rotation is considered.
Doris Liu6432cd62013-06-13 17:20:31 -07001267 mCameraDevice.setDisplayOrientation(
Angus Kongb50b5cb2013-08-09 14:55:20 -07001268 CameraUtil.getDisplayOrientation(mDisplayRotation, mCameraId));
Angus Kong9ef99252013-07-18 18:04:19 -07001269 mCameraDevice.startPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08001270 mPreviewing = true;
Doris Liu6827ce22013-03-12 19:24:28 -07001271 mMediaRecorder.setPreviewDisplay(mUI.getSurfaceHolder().getSurface());
Michael Kolb8872c232013-01-29 10:33:22 -08001272 }
1273 }
1274
1275 // Prepares media recorder.
1276 private void initializeRecorder() {
1277 Log.v(TAG, "initializeRecorder");
1278 // If the mCameraDevice is null, then this activity is going to finish
Doris Liu6432cd62013-06-13 17:20:31 -07001279 if (mCameraDevice == null) return;
Michael Kolb8872c232013-01-29 10:33:22 -08001280
Doris Liu6432cd62013-06-13 17:20:31 -07001281 if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) {
Michael Kolb8872c232013-01-29 10:33:22 -08001282 // Set the SurfaceView to visible so the surface gets created.
1283 // surfaceCreated() is called immediately when the visibility is
1284 // changed to visible. Thus, mSurfaceViewReady should become true
1285 // right after calling setVisibility().
Doris Liu6827ce22013-03-12 19:24:28 -07001286 mUI.showSurfaceView();
Michael Kolb8872c232013-01-29 10:33:22 -08001287 }
1288
1289 Intent intent = mActivity.getIntent();
1290 Bundle myExtras = intent.getExtras();
1291
Alok Kediyaaed65252013-09-23 14:31:42 +05301292 videoWidth = mProfile.videoFrameWidth;
1293 videoHeight = mProfile.videoFrameHeight;
1294 mUnsupportedResolution = false;
1295
Sai Kumar Sanagavarapubb994362013-12-03 18:33:47 +05301296 //check if codec supports the resolution, otherwise throw toast
1297 List<VideoEncoderCap> videoEncoders = EncoderCapabilities.getVideoEncoders();
1298 for (VideoEncoderCap videoEncoder: videoEncoders) {
Vladimir Petrov3d8233a2014-07-14 18:32:12 -07001299 if (videoEncoder.mCodec == mVideoEncoder) {
Sai Kumar Sanagavarapubb994362013-12-03 18:33:47 +05301300 if (videoWidth > videoEncoder.mMaxFrameWidth ||
Vladimir Petrov3d8233a2014-07-14 18:32:12 -07001301 videoWidth < videoEncoder.mMinFrameWidth ||
1302 videoHeight > videoEncoder.mMaxFrameHeight ||
1303 videoHeight < videoEncoder.mMinFrameHeight) {
1304 Log.e(TAG, "Selected codec " + mVideoEncoder +
1305 " does not support "+ videoWidth + "x" + videoHeight
1306 + " resolution");
1307 Log.e(TAG, "Codec capabilities: " +
1308 "mMinFrameWidth = " + videoEncoder.mMinFrameWidth + " , " +
1309 "mMinFrameHeight = " + videoEncoder.mMinFrameHeight + " , " +
1310 "mMaxFrameWidth = " + videoEncoder.mMaxFrameWidth + " , " +
1311 "mMaxFrameHeight = " + videoEncoder.mMaxFrameHeight);
1312 mUnsupportedResolution = true;
1313 Toast.makeText(mActivity, R.string.error_app_unsupported,
1314 Toast.LENGTH_LONG).show();
1315 return;
Sai Kumar Sanagavarapubb994362013-12-03 18:33:47 +05301316 }
1317 break;
Alok Kediyaaed65252013-09-23 14:31:42 +05301318 }
1319 }
1320
Michael Kolb8872c232013-01-29 10:33:22 -08001321 long requestedSizeLimit = 0;
1322 closeVideoFileDescriptor();
ztenghui70bd0242013-10-14 11:15:44 -07001323 mCurrentVideoUriFromMediaSaved = false;
Michael Kolb8872c232013-01-29 10:33:22 -08001324 if (mIsVideoCaptureIntent && myExtras != null) {
1325 Uri saveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1326 if (saveUri != null) {
1327 try {
1328 mVideoFileDescriptor =
1329 mContentResolver.openFileDescriptor(saveUri, "rw");
1330 mCurrentVideoUri = saveUri;
1331 } catch (java.io.FileNotFoundException ex) {
1332 // invalid uri
1333 Log.e(TAG, ex.toString());
1334 }
1335 }
1336 requestedSizeLimit = myExtras.getLong(MediaStore.EXTRA_SIZE_LIMIT);
1337 }
1338 mMediaRecorder = new MediaRecorder();
1339
Michael Kolb8872c232013-01-29 10:33:22 -08001340 // Unlock the camera object before passing it to media recorder.
Doris Liu6432cd62013-06-13 17:20:31 -07001341 mCameraDevice.unlock();
Doris Liu6432cd62013-06-13 17:20:31 -07001342 mMediaRecorder.setCamera(mCameraDevice.getCamera());
Alok Kediyab173e262013-09-28 18:37:22 +05301343 String hfr = mParameters.getVideoHighFrameRate();
1344 if (!mCaptureTimeLapse && ((hfr == null) || ("off".equals(hfr)))) {
Michael Kolb8872c232013-01-29 10:33:22 -08001345 mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
Alok Kediyaaed65252013-09-23 14:31:42 +05301346 mProfile.audioCodec = mAudioEncoder;
Alok Kediyab173e262013-09-28 18:37:22 +05301347 } else {
1348 mProfile.audioCodec = -1; //not set
Michael Kolb8872c232013-01-29 10:33:22 -08001349 }
Alok Kediyab173e262013-09-28 18:37:22 +05301350
Michael Kolb8872c232013-01-29 10:33:22 -08001351 mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
Alok Kediyaaed65252013-09-23 14:31:42 +05301352
1353 mProfile.videoCodec = mVideoEncoder;
1354 mProfile.duration = mMaxVideoDurationInMs;
1355
Michael Kolb8872c232013-01-29 10:33:22 -08001356 mMediaRecorder.setProfile(mProfile);
Michael Kolbd75b9ae2013-05-30 07:45:41 -07001357 mMediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
Michael Kolb8872c232013-01-29 10:33:22 -08001358 mMediaRecorder.setMaxDuration(mMaxVideoDurationInMs);
1359 if (mCaptureTimeLapse) {
1360 double fps = 1000 / (double) mTimeBetweenTimeLapseFrameCaptureMs;
1361 setCaptureRate(mMediaRecorder, fps);
1362 }
1363
1364 setRecordLocation();
1365
1366 // Set output file.
1367 // Try Uri in the intent first. If it doesn't exist, use our own
1368 // instead.
1369 if (mVideoFileDescriptor != null) {
1370 mMediaRecorder.setOutputFile(mVideoFileDescriptor.getFileDescriptor());
1371 } else {
1372 generateVideoFilename(mProfile.fileFormat);
1373 mMediaRecorder.setOutputFile(mVideoFilename);
1374 }
1375
1376 // Set maximum file size.
Angus Kong2dcc0a92013-09-25 13:00:08 -07001377 long maxFileSize = mActivity.getStorageSpaceBytes() - Storage.LOW_STORAGE_THRESHOLD_BYTES;
Michael Kolb8872c232013-01-29 10:33:22 -08001378 if (requestedSizeLimit > 0 && requestedSizeLimit < maxFileSize) {
1379 maxFileSize = requestedSizeLimit;
1380 }
1381
1382 try {
1383 mMediaRecorder.setMaxFileSize(maxFileSize);
1384 } catch (RuntimeException exception) {
1385 // We are going to ignore failure of setMaxFileSize here, as
1386 // a) The composer selected may simply not support it, or
1387 // b) The underlying media framework may not handle 64-bit range
1388 // on the size restriction.
1389 }
1390
1391 // See android.hardware.Camera.Parameters.setRotation for
1392 // documentation.
1393 // Note that mOrientation here is the device orientation, which is the opposite of
1394 // what activity.getWindowManager().getDefaultDisplay().getRotation() would return,
1395 // which is the orientation the graphics need to rotate in order to render correctly.
1396 int rotation = 0;
1397 if (mOrientation != OrientationEventListener.ORIENTATION_UNKNOWN) {
1398 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
1399 if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
1400 rotation = (info.orientation - mOrientation + 360) % 360;
1401 } else { // back-facing camera
1402 rotation = (info.orientation + mOrientation) % 360;
1403 }
1404 }
1405 mMediaRecorder.setOrientationHint(rotation);
Michael Kolbd75b9ae2013-05-30 07:45:41 -07001406 setupMediaRecorderPreviewDisplay();
Michael Kolb8872c232013-01-29 10:33:22 -08001407
1408 try {
1409 mMediaRecorder.prepare();
1410 } catch (IOException e) {
1411 Log.e(TAG, "prepare failed for " + mVideoFilename, e);
1412 releaseMediaRecorder();
1413 throw new RuntimeException(e);
1414 }
1415
1416 mMediaRecorder.setOnErrorListener(this);
1417 mMediaRecorder.setOnInfoListener(this);
1418 }
1419
Michael Kolb8872c232013-01-29 10:33:22 -08001420 private static void setCaptureRate(MediaRecorder recorder, double fps) {
1421 recorder.setCaptureRate(fps);
1422 }
1423
Michael Kolb8872c232013-01-29 10:33:22 -08001424 private void setRecordLocation() {
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001425 Location loc = mLocationManager.getCurrentLocation();
1426 if (loc != null) {
1427 mMediaRecorder.setLocation((float) loc.getLatitude(),
1428 (float) loc.getLongitude());
Michael Kolb8872c232013-01-29 10:33:22 -08001429 }
1430 }
1431
Michael Kolb8872c232013-01-29 10:33:22 -08001432 private void releaseMediaRecorder() {
1433 Log.v(TAG, "Releasing media recorder.");
1434 if (mMediaRecorder != null) {
1435 cleanupEmptyFile();
1436 mMediaRecorder.reset();
1437 mMediaRecorder.release();
1438 mMediaRecorder = null;
1439 }
1440 mVideoFilename = null;
1441 }
1442
Michael Kolb8872c232013-01-29 10:33:22 -08001443 private void generateVideoFilename(int outputFileFormat) {
1444 long dateTaken = System.currentTimeMillis();
1445 String title = createName(dateTaken);
1446 // Used when emailing.
1447 String filename = title + convertOutputFormatToFileExt(outputFileFormat);
1448 String mime = convertOutputFormatToMimeType(outputFileFormat);
Santhosh Kumar H Eb2da1c12014-01-21 19:21:42 +05301449 String path = null;
1450 if (Storage.isSaveSDCard() && SDCard.instance().isWriteable()) {
1451 path = SDCard.instance().getDirectory() + '/' + filename;
1452 } else {
1453 path = Storage.DIRECTORY + '/' + filename;
1454 }
Michael Kolb8872c232013-01-29 10:33:22 -08001455 String tmpPath = path + ".tmp";
Ruben Brunk16007962013-04-19 15:27:57 -07001456 mCurrentVideoValues = new ContentValues(9);
Michael Kolb8872c232013-01-29 10:33:22 -08001457 mCurrentVideoValues.put(Video.Media.TITLE, title);
1458 mCurrentVideoValues.put(Video.Media.DISPLAY_NAME, filename);
1459 mCurrentVideoValues.put(Video.Media.DATE_TAKEN, dateTaken);
Ruben Brunk16007962013-04-19 15:27:57 -07001460 mCurrentVideoValues.put(MediaColumns.DATE_MODIFIED, dateTaken / 1000);
Michael Kolb8872c232013-01-29 10:33:22 -08001461 mCurrentVideoValues.put(Video.Media.MIME_TYPE, mime);
1462 mCurrentVideoValues.put(Video.Media.DATA, path);
1463 mCurrentVideoValues.put(Video.Media.RESOLUTION,
1464 Integer.toString(mProfile.videoFrameWidth) + "x" +
1465 Integer.toString(mProfile.videoFrameHeight));
1466 Location loc = mLocationManager.getCurrentLocation();
1467 if (loc != null) {
1468 mCurrentVideoValues.put(Video.Media.LATITUDE, loc.getLatitude());
1469 mCurrentVideoValues.put(Video.Media.LONGITUDE, loc.getLongitude());
1470 }
Michael Kolb8872c232013-01-29 10:33:22 -08001471 mVideoFilename = tmpPath;
1472 Log.v(TAG, "New video filename: " + mVideoFilename);
1473 }
1474
Angus Kong83a99ae2013-04-17 15:37:07 -07001475 private void saveVideo() {
Michael Kolb8872c232013-01-29 10:33:22 -08001476 if (mVideoFileDescriptor == null) {
liangche7c7446d2014-07-28 15:17:05 +08001477 long duration = 0L;
1478 if (mMediaRecorderPausing == false)
1479 duration = SystemClock.uptimeMillis() - mRecordingStartTime + mRecordingTotalTime;
1480 else
1481 duration = mRecordingTotalTime;
Michael Kolb8872c232013-01-29 10:33:22 -08001482 if (duration > 0) {
1483 if (mCaptureTimeLapse) {
1484 duration = getTimeLapseVideoLength(duration);
1485 }
Michael Kolb8872c232013-01-29 10:33:22 -08001486 } else {
1487 Log.w(TAG, "Video duration <= 0 : " + duration);
1488 }
Ashok Raj Deenadayalan7539f9e2013-11-28 12:47:01 +05301489
1490 File origFile = new File(mCurrentVideoFilename);
1491 if (!origFile.exists() || origFile.length() <= 0) {
1492 Log.e(TAG, "Invalid file");
1493 mCurrentVideoValues = null;
1494 return;
1495 }
1496
Suman Mukherjee3560fdc2014-04-09 10:00:12 +05301497 /* Change the duration as per HFR selection */
1498 String hfr = mParameters.getVideoHighFrameRate();
1499 int defaultFps = 30;
1500 int hfrRatio = 1;
1501 if (!("off".equals(hfr))) {
1502 try {
1503 int hfrFps = Integer.parseInt(hfr);
1504 hfrRatio = hfrFps / defaultFps;
1505 } catch(NumberFormatException ex) {
1506 //Default value will be used
1507 Log.e(TAG,"Invalid hfr values:"+hfr);
1508 }
1509 }
1510 duration = duration * hfrRatio;
1511
Angus Kong83a99ae2013-04-17 15:37:07 -07001512 mActivity.getMediaSaveService().addVideo(mCurrentVideoFilename,
1513 duration, mCurrentVideoValues,
1514 mOnVideoSavedListener, mContentResolver);
Michael Kolb8872c232013-01-29 10:33:22 -08001515 }
1516 mCurrentVideoValues = null;
Michael Kolb8872c232013-01-29 10:33:22 -08001517 }
1518
1519 private void deleteVideoFile(String fileName) {
1520 Log.v(TAG, "Deleting video " + fileName);
1521 File f = new File(fileName);
1522 if (!f.delete()) {
1523 Log.v(TAG, "Could not delete " + fileName);
1524 }
1525 }
1526
1527 private PreferenceGroup filterPreferenceScreenByIntent(
1528 PreferenceGroup screen) {
1529 Intent intent = mActivity.getIntent();
1530 if (intent.hasExtra(MediaStore.EXTRA_VIDEO_QUALITY)) {
1531 CameraSettings.removePreferenceFromScreen(screen,
1532 CameraSettings.KEY_VIDEO_QUALITY);
1533 }
1534
1535 if (intent.hasExtra(MediaStore.EXTRA_DURATION_LIMIT)) {
1536 CameraSettings.removePreferenceFromScreen(screen,
1537 CameraSettings.KEY_VIDEO_QUALITY);
1538 }
1539 return screen;
1540 }
1541
1542 // from MediaRecorder.OnErrorListener
1543 @Override
1544 public void onError(MediaRecorder mr, int what, int extra) {
1545 Log.e(TAG, "MediaRecorder error. what=" + what + ". extra=" + extra);
Santhosh Kumar Thimmanna Bhattar923c81f2014-01-10 11:38:47 +05301546 stopVideoRecording();
Michael Kolb8872c232013-01-29 10:33:22 -08001547 if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) {
1548 // We may have run out of space on the sdcard.
Michael Kolb8872c232013-01-29 10:33:22 -08001549 mActivity.updateStorageSpaceAndHint();
1550 }
1551 }
1552
1553 // from MediaRecorder.OnInfoListener
1554 @Override
1555 public void onInfo(MediaRecorder mr, int what, int extra) {
1556 if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
1557 if (mMediaRecorderRecording) onStopVideoRecording();
1558 } else if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
1559 if (mMediaRecorderRecording) onStopVideoRecording();
1560
1561 // Show the toast.
1562 Toast.makeText(mActivity, R.string.video_reach_size_limit,
1563 Toast.LENGTH_LONG).show();
1564 }
1565 }
1566
1567 /*
1568 * Make sure we're not recording music playing in the background, ask the
1569 * MediaPlaybackService to pause playback.
1570 */
1571 private void pauseAudioPlayback() {
1572 // Shamelessly copied from MediaPlaybackService.java, which
1573 // should be public, but isn't.
1574 Intent i = new Intent("com.android.music.musicservicecommand");
1575 i.putExtra("command", "pause");
1576
1577 mActivity.sendBroadcast(i);
1578 }
1579
1580 // For testing.
1581 public boolean isRecording() {
1582 return mMediaRecorderRecording;
1583 }
1584
1585 private void startVideoRecording() {
1586 Log.v(TAG, "startVideoRecording");
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +05301587 mStartRecPending = true;
Sascha Haeberling37f36112013-08-06 14:31:52 -07001588 mUI.cancelAnimations();
Doris Liu6432cd62013-06-13 17:20:31 -07001589 mUI.setSwipingEnabled(false);
Michael Kolb8872c232013-01-29 10:33:22 -08001590
1591 mActivity.updateStorageSpaceAndHint();
Angus Kong2dcc0a92013-09-25 13:00:08 -07001592 if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Michael Kolb8872c232013-01-29 10:33:22 -08001593 Log.v(TAG, "Storage issue, ignore the start request");
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +05301594 mStartRecPending = false;
Michael Kolb8872c232013-01-29 10:33:22 -08001595 return;
1596 }
1597
Alok Kediyaa794c742013-09-28 17:46:42 +05301598 if( mUnsupportedHFRVideoSize == true) {
1599 Log.e(TAG, "Unsupported HFR and video size combinations");
1600 Toast.makeText(mActivity,R.string.error_app_unsupported_hfr, Toast.LENGTH_SHORT).show();
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +05301601 mStartRecPending = false;
Alok Kediyaa794c742013-09-28 17:46:42 +05301602 return;
1603 }
1604
Vijay kumar Tumati2ff6c252014-02-10 16:10:09 +05301605 if (mUnsupportedHSRVideoSize == true) {
1606 Log.e(TAG, "Unsupported HSR and video size combinations");
1607 Toast.makeText(mActivity,R.string.error_app_unsupported_hsr, Toast.LENGTH_SHORT).show();
1608 mStartRecPending = false;
1609 return;
1610 }
1611
Alok Kediyaa794c742013-09-28 17:46:42 +05301612 if( mUnsupportedHFRVideoCodec == true) {
1613 Log.e(TAG, "Unsupported HFR and video codec combinations");
1614 Toast.makeText(mActivity, R.string.error_app_unsupported_hfr_codec,
1615 Toast.LENGTH_SHORT).show();
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +05301616 mStartRecPending = false;
Alok Kediyaa794c742013-09-28 17:46:42 +05301617 return;
1618 }
Angus Kong9ef99252013-07-18 18:04:19 -07001619 //??
1620 //if (!mCameraDevice.waitDone()) return;
Michael Kolb8872c232013-01-29 10:33:22 -08001621 mCurrentVideoUri = null;
Doris Liu3973deb2013-08-21 13:42:22 -07001622
1623 initializeRecorder();
Alok Kediyaaed65252013-09-23 14:31:42 +05301624 if (mUnsupportedResolution == true) {
1625 Log.v(TAG, "Unsupported Resolution according to target");
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +05301626 mStartRecPending = false;
Alok Kediyaaed65252013-09-23 14:31:42 +05301627 return;
1628 }
Doris Liu3973deb2013-08-21 13:42:22 -07001629 if (mMediaRecorder == null) {
1630 Log.e(TAG, "Fail to initialize media recorder");
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +05301631 mStartRecPending = false;
Doris Liu3973deb2013-08-21 13:42:22 -07001632 return;
Michael Kolb8872c232013-01-29 10:33:22 -08001633 }
1634
1635 pauseAudioPlayback();
1636
Doris Liu3973deb2013-08-21 13:42:22 -07001637 try {
1638 mMediaRecorder.start(); // Recording is now started
1639 } catch (RuntimeException e) {
1640 Log.e(TAG, "Could not start media recorder. ", e);
1641 releaseMediaRecorder();
1642 // If start fails, frameworks will not lock the camera for us.
1643 mCameraDevice.lock();
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +05301644 mStartRecPending = false;
Doris Liu3973deb2013-08-21 13:42:22 -07001645 return;
Michael Kolb8872c232013-01-29 10:33:22 -08001646 }
1647
1648 // Make sure the video recording has started before announcing
1649 // this in accessibility.
Doris Liu6432cd62013-06-13 17:20:31 -07001650 AccessibilityUtils.makeAnnouncement(mUI.getShutterButton(),
Michael Kolb8872c232013-01-29 10:33:22 -08001651 mActivity.getString(R.string.video_recording_started));
1652
Angus Kong104e0012013-04-03 16:56:18 -07001653 // The parameters might have been altered by MediaRecorder already.
1654 // We need to force mCameraDevice to refresh before getting it.
Doris Liu6432cd62013-06-13 17:20:31 -07001655 mCameraDevice.refreshParameters();
Michael Kolb8872c232013-01-29 10:33:22 -08001656 // The parameters may have been changed by MediaRecorder upon starting
1657 // recording. We need to alter the parameters if we support camcorder
1658 // zoom. To reduce latency when setting the parameters during zoom, we
1659 // update mParameters here once.
Sascha Haeberling638e6f02013-09-18 14:28:51 -07001660 mParameters = mCameraDevice.getParameters();
Michael Kolb8872c232013-01-29 10:33:22 -08001661
Doris Liu6827ce22013-03-12 19:24:28 -07001662 mUI.enableCameraControls(false);
Michael Kolb8872c232013-01-29 10:33:22 -08001663
1664 mMediaRecorderRecording = true;
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +05301665 mMediaRecorderPausing = false;
1666 mUI.resetPauseButton();
Doris Liu6432cd62013-06-13 17:20:31 -07001667 mOrientationManager.lockOrientation();
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +05301668 mRecordingTotalTime = 0L;
Michael Kolb8872c232013-01-29 10:33:22 -08001669 mRecordingStartTime = SystemClock.uptimeMillis();
Doris Liufe6596c2013-10-08 11:03:37 -07001670 mUI.showRecordingUI(true);
Michael Kolb8872c232013-01-29 10:33:22 -08001671
1672 updateRecordingTime();
1673 keepScreenOn();
Bobby Georgescu301b6462013-04-01 15:33:17 -07001674 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
1675 UsageStatistics.ACTION_CAPTURE_START, "Video");
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +05301676 mStartRecPending = false;
Michael Kolb8872c232013-01-29 10:33:22 -08001677 }
1678
Sascha Haeberling37f36112013-08-06 14:31:52 -07001679 private Bitmap getVideoThumbnail() {
Michael Kolb8872c232013-01-29 10:33:22 -08001680 Bitmap bitmap = null;
1681 if (mVideoFileDescriptor != null) {
1682 bitmap = Thumbnail.createVideoThumbnailBitmap(mVideoFileDescriptor.getFileDescriptor(),
Doris Liu3c2fca32013-02-13 18:28:03 -08001683 mDesiredPreviewWidth);
Doris Liu2a7f44c2013-08-12 15:18:53 -07001684 } else if (mCurrentVideoUri != null) {
1685 try {
1686 mVideoFileDescriptor = mContentResolver.openFileDescriptor(mCurrentVideoUri, "r");
1687 bitmap = Thumbnail.createVideoThumbnailBitmap(
1688 mVideoFileDescriptor.getFileDescriptor(), mDesiredPreviewWidth);
1689 } catch (java.io.FileNotFoundException ex) {
1690 // invalid uri
1691 Log.e(TAG, ex.toString());
1692 }
Michael Kolb8872c232013-01-29 10:33:22 -08001693 }
Doris Liu3973deb2013-08-21 13:42:22 -07001694
Michael Kolb8872c232013-01-29 10:33:22 -08001695 if (bitmap != null) {
1696 // MetadataRetriever already rotates the thumbnail. We should rotate
1697 // it to match the UI orientation (and mirror if it is front-facing camera).
1698 CameraInfo[] info = CameraHolder.instance().getCameraInfo();
1699 boolean mirror = (info[mCameraId].facing == CameraInfo.CAMERA_FACING_FRONT);
Angus Kongb50b5cb2013-08-09 14:55:20 -07001700 bitmap = CameraUtil.rotateAndMirror(bitmap, 0, mirror);
Sascha Haeberling37f36112013-08-06 14:31:52 -07001701 }
1702 return bitmap;
1703 }
1704
1705 private void showCaptureResult() {
1706 mIsInReviewMode = true;
1707 Bitmap bitmap = getVideoThumbnail();
1708 if (bitmap != null) {
Doris Liu6827ce22013-03-12 19:24:28 -07001709 mUI.showReviewImage(bitmap);
Michael Kolb8872c232013-01-29 10:33:22 -08001710 }
Doris Liu6827ce22013-03-12 19:24:28 -07001711 mUI.showReviewControls();
1712 mUI.enableCameraControls(false);
1713 mUI.showTimeLapseUI(false);
Michael Kolb8872c232013-01-29 10:33:22 -08001714 }
1715
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +05301716 private void pauseVideoRecording() {
1717 Log.v(TAG, "pauseVideoRecording");
1718 mMediaRecorderPausing = true;
1719 mRecordingTotalTime += SystemClock.uptimeMillis() - mRecordingStartTime;
Santhosh Kumar Thimmanna Bhattar11af7682014-11-26 18:54:36 +05301720 mMediaRecorder.pause();
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +05301721 }
1722
1723 private void resumeVideoRecording() {
1724 Log.v(TAG, "resumeVideoRecording");
1725 mMediaRecorderPausing = false;
1726 mRecordingStartTime = SystemClock.uptimeMillis();
1727 updateRecordingTime();
Santhosh Kumar Thimmanna Bhattar11af7682014-11-26 18:54:36 +05301728 mMediaRecorder.start();
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +05301729 }
1730
Michael Kolb8872c232013-01-29 10:33:22 -08001731 private boolean stopVideoRecording() {
1732 Log.v(TAG, "stopVideoRecording");
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +05301733 mStopRecPending = true;
Doris Liu6432cd62013-06-13 17:20:31 -07001734 mUI.setSwipingEnabled(true);
Doris Liu2a7f44c2013-08-12 15:18:53 -07001735 if (!isVideoCaptureIntent()) {
1736 mUI.showSwitcher();
1737 }
Michael Kolb8872c232013-01-29 10:33:22 -08001738
1739 boolean fail = false;
1740 if (mMediaRecorderRecording) {
1741 boolean shouldAddToMediaStoreNow = false;
1742
1743 try {
Doris Liu3973deb2013-08-21 13:42:22 -07001744 mMediaRecorder.setOnErrorListener(null);
1745 mMediaRecorder.setOnInfoListener(null);
1746 mMediaRecorder.stop();
1747 shouldAddToMediaStoreNow = true;
Michael Kolb8872c232013-01-29 10:33:22 -08001748 mCurrentVideoFilename = mVideoFilename;
1749 Log.v(TAG, "stopVideoRecording: Setting current video filename: "
1750 + mCurrentVideoFilename);
Doris Liu6432cd62013-06-13 17:20:31 -07001751 AccessibilityUtils.makeAnnouncement(mUI.getShutterButton(),
Michael Kolb8872c232013-01-29 10:33:22 -08001752 mActivity.getString(R.string.video_recording_stopped));
1753 } catch (RuntimeException e) {
1754 Log.e(TAG, "stop fail", e);
1755 if (mVideoFilename != null) deleteVideoFile(mVideoFilename);
1756 fail = true;
1757 }
1758 mMediaRecorderRecording = false;
Sai Kumar Sanagavarapu9b9fd082014-01-08 12:22:57 +05301759
1760 //If recording stops while snapshot is in progress, we might not get jpeg callback
1761 //because cameraservice will disable picture related messages. Hence reset the
1762 //flag here so that we can take liveshots in the next recording session.
1763 mSnapshotInProgress = false;
kaiyiz48208492014-11-10 15:01:31 +08001764 showVideoSnapshotUI(false);
Sai Kumar Sanagavarapu9b9fd082014-01-08 12:22:57 +05301765
Doris Liu6432cd62013-06-13 17:20:31 -07001766 mOrientationManager.unlockOrientation();
Michael Kolb8872c232013-01-29 10:33:22 -08001767
1768 // If the activity is paused, this means activity is interrupted
1769 // during recording. Release the camera as soon as possible because
1770 // face unlock or other applications may need to use the camera.
Michael Kolb8872c232013-01-29 10:33:22 -08001771 if (mPaused) {
Doris Liu3973deb2013-08-21 13:42:22 -07001772 closeCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08001773 }
1774
Doris Liufe6596c2013-10-08 11:03:37 -07001775 mUI.showRecordingUI(false);
Michael Kolb8872c232013-01-29 10:33:22 -08001776 if (!mIsVideoCaptureIntent) {
Doris Liu6827ce22013-03-12 19:24:28 -07001777 mUI.enableCameraControls(true);
Michael Kolb8872c232013-01-29 10:33:22 -08001778 }
1779 // The orientation was fixed during video recording. Now make it
1780 // reflect the device orientation as video recording is stopped.
Doris Liu6827ce22013-03-12 19:24:28 -07001781 mUI.setOrientationIndicator(0, true);
Michael Kolb8872c232013-01-29 10:33:22 -08001782 keepScreenOnAwhile();
Doris Liu2a7f44c2013-08-12 15:18:53 -07001783 if (shouldAddToMediaStoreNow && !fail) {
1784 if (mVideoFileDescriptor == null) {
1785 saveVideo();
1786 } else if (mIsVideoCaptureIntent) {
1787 // if no file save is needed, we can show the post capture UI now
1788 showCaptureResult();
1789 }
Michael Kolb8872c232013-01-29 10:33:22 -08001790 }
1791 }
Doris Liu3973deb2013-08-21 13:42:22 -07001792 // release media recorder
1793 releaseMediaRecorder();
1794 if (!mPaused) {
1795 mCameraDevice.lock();
1796 if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) {
1797 stopPreview();
1798 mUI.hideSurfaceView();
1799 // Switch back to use SurfaceTexture for preview.
1800 startPreview();
Suman Mukherjee452fcdf2014-12-16 15:50:15 +05301801 } else {
1802 if (is4KEnabled()) {
1803 int[] fpsRange = CameraUtil.getMaxPreviewFpsRange(mParameters);
1804 if (fpsRange.length > 0) {
1805 mParameters.setPreviewFpsRange(
1806 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
1807 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
1808 } else {
1809 mParameters.setPreviewFrameRate(30);
1810 }
1811 mCameraDevice.setParameters(mParameters);
1812 }
Michael Kolb8872c232013-01-29 10:33:22 -08001813 }
1814 }
1815 // Update the parameters here because the parameters might have been altered
1816 // by MediaRecorder.
Doris Liu6432cd62013-06-13 17:20:31 -07001817 if (!mPaused) mParameters = mCameraDevice.getParameters();
Bobby Georgescu301b6462013-04-01 15:33:17 -07001818 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
1819 fail ? UsageStatistics.ACTION_CAPTURE_FAIL :
1820 UsageStatistics.ACTION_CAPTURE_DONE, "Video",
liangche7c7446d2014-07-28 15:17:05 +08001821 mMediaRecorderPausing ? mRecordingTotalTime :
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +05301822 SystemClock.uptimeMillis() - mRecordingStartTime + mRecordingTotalTime);
Ashok Raj Deenadayalan6b397152013-10-25 18:48:22 +05301823 mStopRecPending = false;
Michael Kolb8872c232013-01-29 10:33:22 -08001824 return fail;
1825 }
1826
1827 private void resetScreenOn() {
1828 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1829 mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1830 }
1831
1832 private void keepScreenOnAwhile() {
1833 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1834 mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1835 mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
1836 }
1837
1838 private void keepScreenOn() {
1839 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
1840 mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1841 }
1842
1843 private static String millisecondToTimeString(long milliSeconds, boolean displayCentiSeconds) {
1844 long seconds = milliSeconds / 1000; // round down to compute seconds
1845 long minutes = seconds / 60;
1846 long hours = minutes / 60;
1847 long remainderMinutes = minutes - (hours * 60);
1848 long remainderSeconds = seconds - (minutes * 60);
1849
1850 StringBuilder timeStringBuilder = new StringBuilder();
1851
1852 // Hours
1853 if (hours > 0) {
1854 if (hours < 10) {
1855 timeStringBuilder.append('0');
1856 }
1857 timeStringBuilder.append(hours);
1858
1859 timeStringBuilder.append(':');
1860 }
1861
1862 // Minutes
1863 if (remainderMinutes < 10) {
1864 timeStringBuilder.append('0');
1865 }
1866 timeStringBuilder.append(remainderMinutes);
1867 timeStringBuilder.append(':');
1868
1869 // Seconds
1870 if (remainderSeconds < 10) {
1871 timeStringBuilder.append('0');
1872 }
1873 timeStringBuilder.append(remainderSeconds);
1874
1875 // Centi seconds
1876 if (displayCentiSeconds) {
1877 timeStringBuilder.append('.');
1878 long remainderCentiSeconds = (milliSeconds - seconds * 1000) / 10;
1879 if (remainderCentiSeconds < 10) {
1880 timeStringBuilder.append('0');
1881 }
1882 timeStringBuilder.append(remainderCentiSeconds);
1883 }
1884
1885 return timeStringBuilder.toString();
1886 }
1887
1888 private long getTimeLapseVideoLength(long deltaMs) {
1889 // For better approximation calculate fractional number of frames captured.
1890 // This will update the video time at a higher resolution.
1891 double numberOfFrames = (double) deltaMs / mTimeBetweenTimeLapseFrameCaptureMs;
1892 return (long) (numberOfFrames / mProfile.videoFrameRate * 1000);
1893 }
1894
1895 private void updateRecordingTime() {
1896 if (!mMediaRecorderRecording) {
1897 return;
1898 }
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +05301899 if (mMediaRecorderPausing) {
1900 return;
1901 }
1902
Michael Kolb8872c232013-01-29 10:33:22 -08001903 long now = SystemClock.uptimeMillis();
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +05301904 long delta = now - mRecordingStartTime + mRecordingTotalTime;
Michael Kolb8872c232013-01-29 10:33:22 -08001905
1906 // Starting a minute before reaching the max duration
1907 // limit, we'll countdown the remaining time instead.
1908 boolean countdownRemainingTime = (mMaxVideoDurationInMs != 0
1909 && delta >= mMaxVideoDurationInMs - 60000);
1910
1911 long deltaAdjusted = delta;
1912 if (countdownRemainingTime) {
1913 deltaAdjusted = Math.max(0, mMaxVideoDurationInMs - deltaAdjusted) + 999;
1914 }
1915 String text;
1916
1917 long targetNextUpdateDelay;
1918 if (!mCaptureTimeLapse) {
1919 text = millisecondToTimeString(deltaAdjusted, false);
1920 targetNextUpdateDelay = 1000;
1921 } else {
1922 // The length of time lapse video is different from the length
1923 // of the actual wall clock time elapsed. Display the video length
1924 // only in format hh:mm:ss.dd, where dd are the centi seconds.
1925 text = millisecondToTimeString(getTimeLapseVideoLength(delta), true);
1926 targetNextUpdateDelay = mTimeBetweenTimeLapseFrameCaptureMs;
1927 }
1928
Doris Liu6827ce22013-03-12 19:24:28 -07001929 mUI.setRecordingTime(text);
Michael Kolb8872c232013-01-29 10:33:22 -08001930
1931 if (mRecordingTimeCountsDown != countdownRemainingTime) {
1932 // Avoid setting the color on every update, do it only
1933 // when it needs changing.
1934 mRecordingTimeCountsDown = countdownRemainingTime;
1935
1936 int color = mActivity.getResources().getColor(countdownRemainingTime
1937 ? R.color.recording_time_remaining_text
1938 : R.color.recording_time_elapsed_text);
1939
Doris Liu6827ce22013-03-12 19:24:28 -07001940 mUI.setRecordingTimeTextColor(color);
Michael Kolb8872c232013-01-29 10:33:22 -08001941 }
1942
1943 long actualNextUpdateDelay = targetNextUpdateDelay - (delta % targetNextUpdateDelay);
1944 mHandler.sendEmptyMessageDelayed(
1945 UPDATE_RECORD_TIME, actualNextUpdateDelay);
1946 }
1947
1948 private static boolean isSupported(String value, List<String> supported) {
1949 return supported == null ? false : supported.indexOf(value) >= 0;
1950 }
1951
Santhosh Kumar H E823c8f42014-10-16 11:20:34 +05301952 private void setFlipValue() {
1953
1954 // Read Flip mode from adb command
1955 //value: 0(default) - FLIP_MODE_OFF
1956 //value: 1 - FLIP_MODE_H
1957 //value: 2 - FLIP_MODE_V
1958 //value: 3 - FLIP_MODE_VH
1959 int preview_flip_value = SystemProperties.getInt("debug.camera.preview.flip", 0);
1960 int video_flip_value = SystemProperties.getInt("debug.camera.video.flip", 0);
1961 int picture_flip_value = SystemProperties.getInt("debug.camera.picture.flip", 0);
1962 int rotation = CameraUtil.getJpegRotation(mCameraId, mOrientation);
1963 mParameters.setRotation(rotation);
1964 if (rotation == 90 || rotation == 270) {
1965 // in case of 90 or 270 degree, V/H flip should reverse
1966 if (preview_flip_value == 1) {
1967 preview_flip_value = 2;
1968 } else if (preview_flip_value == 2) {
1969 preview_flip_value = 1;
1970 }
1971 if (video_flip_value == 1) {
1972 video_flip_value = 2;
1973 } else if (video_flip_value == 2) {
1974 video_flip_value = 1;
1975 }
1976 if (picture_flip_value == 1) {
1977 picture_flip_value = 2;
1978 } else if (picture_flip_value == 2) {
1979 picture_flip_value = 1;
1980 }
1981 }
1982 String preview_flip = CameraUtil.getFilpModeString(preview_flip_value);
1983 String video_flip = CameraUtil.getFilpModeString(video_flip_value);
1984 String picture_flip = CameraUtil.getFilpModeString(picture_flip_value);
1985
1986 if(CameraUtil.isSupported(preview_flip, CameraSettings.getSupportedFlipMode(mParameters))){
1987 mParameters.set(CameraSettings.KEY_QC_PREVIEW_FLIP, preview_flip);
1988 }
1989 if(CameraUtil.isSupported(video_flip, CameraSettings.getSupportedFlipMode(mParameters))){
1990 mParameters.set(CameraSettings.KEY_QC_VIDEO_FLIP, video_flip);
1991 }
1992 if(CameraUtil.isSupported(picture_flip, CameraSettings.getSupportedFlipMode(mParameters))){
1993 mParameters.set(CameraSettings.KEY_QC_SNAPSHOT_PICTURE_FLIP, picture_flip);
1994 }
1995
1996
1997 }
1998
Alok Kediya0dc64ff2013-09-27 20:22:45 +05301999 private void qcomSetCameraParameters(){
2000 // add QCOM Parameters here
2001 // Set color effect parameter.
2002 String colorEffect = mPreferences.getString(
2003 CameraSettings.KEY_COLOR_EFFECT,
2004 mActivity.getString(R.string.pref_camera_coloreffect_default));
2005 Log.v(TAG, "Color effect value =" + colorEffect);
2006 if (isSupported(colorEffect, mParameters.getSupportedColorEffects())) {
2007 mParameters.setColorEffect(colorEffect);
2008 }
2009
Alok Kediyae57357e2013-09-28 18:23:26 +05302010 String disMode = mPreferences.getString(
2011 CameraSettings.KEY_DIS,
2012 mActivity.getString(R.string.pref_camera_dis_default));
2013 Log.v(TAG, "DIS value =" + disMode);
Dimitar Borisova5c2a742014-10-06 18:38:12 +03002014
2015 if (is4KEnabled()) {
2016 if (isSupported(mActivity.getString(R.string.pref_camera_dis_value_disable),
2017 CameraSettings.getSupportedDISModes(mParameters))) {
2018 mParameters.set(CameraSettings.KEY_QC_DIS_MODE,
2019 mActivity.getString(R.string.pref_camera_dis_value_disable));
2020 mUI.overrideSettings(CameraSettings.KEY_DIS,
2021 mActivity.getString(R.string.pref_camera_dis_value_disable));
2022 Toast.makeText(mActivity, R.string.video_quality_4k_disable_IS,
2023 Toast.LENGTH_LONG).show();
2024 } else {
2025 Log.e(TAG, "Not supported IS mode = " +
2026 mActivity.getString(R.string.pref_camera_dis_value_disable));
2027 }
2028 } else {
2029 if (isSupported(disMode,
2030 CameraSettings.getSupportedDISModes(mParameters))) {
2031 mParameters.set(CameraSettings.KEY_QC_DIS_MODE, disMode);
2032 } else {
2033 Log.e(TAG, "Not supported IS mode = " + disMode);
2034 }
Alok Kediyae57357e2013-09-28 18:23:26 +05302035 }
2036
Gaoxiang Chen1deb8752014-04-14 16:06:58 +08002037 if (mDefaultAntibanding == null) {
2038 mDefaultAntibanding = mParameters.getAntibanding();
2039 Log.d(TAG, "default antibanding value = " + mDefaultAntibanding);
2040 }
2041
2042 if (disMode.equals("enable")) {
2043 Log.d(TAG, "dis is enabled, set antibanding to auto.");
2044 if (isSupported(Parameters.ANTIBANDING_AUTO, mParameters.getSupportedAntibanding())) {
2045 mParameters.setAntibanding(Parameters.ANTIBANDING_AUTO);
2046 }
2047 } else {
2048 if (isSupported(mDefaultAntibanding, mParameters.getSupportedAntibanding())) {
2049 mParameters.setAntibanding(mDefaultAntibanding);
2050 }
2051 }
2052 Log.d(TAG, "antiBanding value = " + mParameters.getAntibanding());
2053
Santhosh Kumar Thimmanna Bhattar48b9c1b2014-10-15 15:07:08 +05302054 String seeMoreMode = mPreferences.getString(
2055 CameraSettings.KEY_SEE_MORE,
2056 mActivity.getString(R.string.pref_camera_see_more_default));
2057 Log.v(TAG, "See More value =" + seeMoreMode);
Shwetha Kotekar943b6852014-11-12 15:53:59 -08002058
Santhosh Kumar Thimmanna Bhattar48b9c1b2014-10-15 15:07:08 +05302059 if (isSupported(seeMoreMode,
Shwetha Kotekar943b6852014-11-12 15:53:59 -08002060 CameraSettings.getSupportedSeeMoreModes(mParameters))) {
2061 if (is4KEnabled() && seeMoreMode.equals(mActivity.getString(R.string.
2062 pref_camera_see_more_value_on))) {
2063 mParameters.set(CameraSettings.KEY_QC_SEE_MORE_MODE,
2064 mActivity.getString(R.string.pref_camera_see_more_value_off));
2065 mUI.overrideSettings(CameraSettings.KEY_SEE_MORE,
2066 mActivity.getString(R.string.pref_camera_see_more_value_off));
2067 Toast.makeText(mActivity, R.string.video_quality_4k_disable_SeeMore,
2068 Toast.LENGTH_LONG).show();
2069 } else {
2070 mParameters.set(CameraSettings.KEY_QC_SEE_MORE_MODE, seeMoreMode);
2071 }
Santhosh Kumar Thimmanna Bhattar48b9c1b2014-10-15 15:07:08 +05302072 }
2073
Alok Kediya0dc64ff2013-09-27 20:22:45 +05302074 mUnsupportedHFRVideoSize = false;
2075 mUnsupportedHFRVideoCodec = false;
Vijay kumar Tumatifd5878c2014-03-05 15:54:22 +05302076 mUnsupportedHSRVideoSize = false;
Alok Kediya0dc64ff2013-09-27 20:22:45 +05302077 // To set preview format as YV12 , run command
2078 // "adb shell setprop "debug.camera.yv12" true"
2079 String yv12formatset = SystemProperties.get("debug.camera.yv12");
2080 if(yv12formatset.equals("true")) {
2081 Log.v(TAG, "preview format set to YV12");
2082 mParameters.setPreviewFormat (ImageFormat.YV12);
2083 }
Tanmaya Godbole50ebaef2014-02-11 11:49:42 -08002084
Santhosh Kumar H Ea977a932014-12-29 19:12:19 +05302085 if ( (is1080pEnabled() || is720pEnabled())
2086 && CameraUtil.isSupported(FORMAT_NV12_VENUS,
2087 CameraSettings.getSupportedPreviewFormats(mParameters)) ) {
satyavaraprasad yerramsetti9747e002014-10-17 12:53:48 +05302088 Log.v(TAG, "1080p or 720p enabled, preview format set to NV12_VENUS");
Cherian Deepaka1a59b92014-08-11 11:17:01 -07002089 mParameters.set(KEY_PREVIEW_FORMAT, FORMAT_NV12_VENUS);
Santhosh Kumar H Ea977a932014-12-29 19:12:19 +05302090 } else if (CameraUtil.isSupported(FORMAT_NV21,
2091 CameraSettings.getSupportedPreviewFormats(mParameters))){
Santhosh Kumar H Ef2d1e6e2014-12-16 17:18:41 +05302092 Log.v(TAG, "preview format set to yuv420sp");
2093 mParameters.set(KEY_PREVIEW_FORMAT, FORMAT_NV21);
Cherian Deepaka1a59b92014-08-11 11:17:01 -07002094 }
2095
Alok Kediya0dc64ff2013-09-27 20:22:45 +05302096 // Set High Frame Rate.
2097 String HighFrameRate = mPreferences.getString(
2098 CameraSettings.KEY_VIDEO_HIGH_FRAME_RATE,
2099 mActivity. getString(R.string.pref_camera_hfr_default));
Vijay kumar Tumatifd5878c2014-03-05 15:54:22 +05302100 if (("hfr".equals(HighFrameRate.substring(0,3))) ||
2101 ("hsr".equals(HighFrameRate.substring(0,3)))) {
2102 String hfrRate = HighFrameRate.substring(3);
2103 if ("hfr".equals(HighFrameRate.substring(0,3))) {
2104 mUnsupportedHFRVideoSize = true;
Vladimir Petrov3d8233a2014-07-14 18:32:12 -07002105 } else {
2106 mUnsupportedHSRVideoSize = true;
2107 }
Alok Kediya0dc64ff2013-09-27 20:22:45 +05302108 String hfrsize = videoWidth+"x"+videoHeight;
2109 Log.v(TAG, "current set resolution is : "+hfrsize);
2110 try {
Santhosh Kumar Thimmanna Bhattar1e608042014-01-16 12:40:38 +05302111 Size size = null;
Vladimir Petrov3d8233a2014-07-14 18:32:12 -07002112 if (isSupported(hfrRate, mParameters.getSupportedVideoHighFrameRateModes())) {
Santhosh Kumar Thimmanna Bhattar1e608042014-01-16 12:40:38 +05302113 int index = mParameters.getSupportedVideoHighFrameRateModes().indexOf(
Vijay kumar Tumatifd5878c2014-03-05 15:54:22 +05302114 hfrRate);
Santhosh Kumar Thimmanna Bhattar1e608042014-01-16 12:40:38 +05302115 size = mParameters.getSupportedHfrSizes().get(index);
2116 }
2117 if (size != null) {
Santhosh Kumar Thimmanna Bhattar1e608042014-01-16 12:40:38 +05302118 if (videoWidth <= size.width && videoHeight <= size.height) {
Vijay kumar Tumatifd5878c2014-03-05 15:54:22 +05302119 if ("hfr".equals(HighFrameRate.substring(0,3))) {
2120 mUnsupportedHFRVideoSize = false;
Vladimir Petrov3d8233a2014-07-14 18:32:12 -07002121 } else {
2122 mUnsupportedHSRVideoSize = false;
2123 }
Santhosh Kumar Thimmanna Bhattar1e608042014-01-16 12:40:38 +05302124 Log.v(TAG,"Current hfr resolution is supported");
Alok Kediya0dc64ff2013-09-27 20:22:45 +05302125 }
2126 }
2127 } catch (NullPointerException e){
2128 Log.e(TAG, "supported hfr sizes is null");
2129 }
2130
Vijay kumar Tumatifd5878c2014-03-05 15:54:22 +05302131 int hfrFps = Integer.parseInt(hfrRate);
Sai Kumar Sanagavarapu6758cbf2014-01-23 15:27:14 +05302132 int inputBitrate = videoWidth*videoHeight*hfrFps;
2133
2134 //check if codec supports the resolution, otherwise throw toast
2135 List<VideoEncoderCap> videoEncoders = EncoderCapabilities.getVideoEncoders();
2136 for (VideoEncoderCap videoEncoder: videoEncoders) {
2137 if (videoEncoder.mCodec == mVideoEncoder){
2138 int maxBitrate = (videoEncoder.mMaxHFRFrameWidth *
2139 videoEncoder.mMaxHFRFrameHeight *
2140 videoEncoder.mMaxHFRMode);
Vladimir Petrov3d8233a2014-07-14 18:32:12 -07002141 if (inputBitrate > maxBitrate ) {
2142 Log.e(TAG,"Selected codec "+mVideoEncoder+
Sai Kumar Sanagavarapu6758cbf2014-01-23 15:27:14 +05302143 " does not support HFR " + HighFrameRate + " with "+ videoWidth
2144 + "x" + videoHeight +" resolution");
Vladimir Petrov3d8233a2014-07-14 18:32:12 -07002145 Log.e(TAG, "Codec capabilities: " +
2146 "mMaxHFRFrameWidth = " + videoEncoder.mMaxHFRFrameWidth + " , " +
2147 "mMaxHFRFrameHeight = " + videoEncoder.mMaxHFRFrameHeight + " , " +
Sai Kumar Sanagavarapu6758cbf2014-01-23 15:27:14 +05302148 "mMaxHFRMode = " + videoEncoder.mMaxHFRMode);
Vladimir Petrov3d8233a2014-07-14 18:32:12 -07002149 if ("hfr".equals(HighFrameRate.substring(0,3))) {
2150 mUnsupportedHFRVideoSize = true;
2151 } else {
2152 mUnsupportedHSRVideoSize = true;
2153 }
Sai Kumar Sanagavarapu6758cbf2014-01-23 15:27:14 +05302154 }
2155 break;
2156 }
2157 }
Vijay kumar Tumatifd5878c2014-03-05 15:54:22 +05302158 if ("hfr".equals(HighFrameRate.substring(0,3))) {
Vladimir Petrov3d8233a2014-07-14 18:32:12 -07002159 mParameters.set(CameraSettings.KEY_VIDEO_HSR, "off");
Vijay kumar Tumatifd5878c2014-03-05 15:54:22 +05302160 if (mUnsupportedHFRVideoSize) {
2161 mParameters.setVideoHighFrameRate("off");
2162 Log.v(TAG,"Unsupported hfr resolution");
2163 } else {
2164 mParameters.setVideoHighFrameRate(hfrRate);
Vijay kumar Tumati2ff6c252014-02-10 16:10:09 +05302165 }
Vijay kumar Tumatifd5878c2014-03-05 15:54:22 +05302166 } else {
2167 mParameters.setVideoHighFrameRate("off");
2168 if (mUnsupportedHSRVideoSize) {
2169 Log.v(TAG,"Unsupported hsr resolution");
Vladimir Petrov3d8233a2014-07-14 18:32:12 -07002170 mParameters.set(CameraSettings.KEY_VIDEO_HSR, "off");
2171 } else {
2172 mParameters.set(CameraSettings.KEY_VIDEO_HSR, hfrRate);
2173 }
Vijay kumar Tumati2ff6c252014-02-10 16:10:09 +05302174 }
Vijay kumar Tumatifd5878c2014-03-05 15:54:22 +05302175 if(mVideoEncoder != MediaRecorder.VideoEncoder.H264) {
2176 mUnsupportedHFRVideoCodec = true;
2177 }
2178 } else {
2179 mParameters.setVideoHighFrameRate("off");
Vladimir Petrov3d8233a2014-07-14 18:32:12 -07002180 mParameters.set(CameraSettings.KEY_VIDEO_HSR, "off");
Vijay kumar Tumati2ff6c252014-02-10 16:10:09 +05302181 }
Santhosh Kumar H E823c8f42014-10-16 11:20:34 +05302182 setFlipValue();
Alok Kediya4b6f3f92013-09-28 17:39:13 +05302183
Dimitar Borisov19656472014-09-24 17:32:06 +03002184 // Set video CDS
2185 String video_cds = mPreferences.getString(
2186 CameraSettings.KEY_VIDEO_CDS_MODE,
2187 mActivity.getString(R.string.pref_camera_video_cds_default));
2188
2189 if ((mPrevSavedVideoCDS == null) && (video_cds != null)) {
2190 mPrevSavedVideoCDS = video_cds;
2191 }
2192
2193 if (mOverrideCDS) {
2194 video_cds = mPrevSavedVideoCDS;
2195 mOverrideCDS = false;
2196 }
2197
2198 if (CameraUtil.isSupported(video_cds,
2199 CameraSettings.getSupportedVideoCDSModes(mParameters))) {
2200 mParameters.set(CameraSettings.KEY_QC_VIDEO_CDS_MODE, video_cds);
2201 }
2202
2203 // Set video TNR
2204 String video_tnr = mPreferences.getString(
2205 CameraSettings.KEY_VIDEO_TNR_MODE,
2206 mActivity.getString(R.string.pref_camera_video_tnr_default));
2207 if (CameraUtil.isSupported(video_tnr,
2208 CameraSettings.getSupportedVideoTNRModes(mParameters))) {
2209 if (!video_tnr.equals(mActivity.getString(R.string.
2210 pref_camera_video_tnr_value_off))) {
2211 mParameters.set(CameraSettings.KEY_QC_VIDEO_CDS_MODE,
2212 mActivity.getString(R.string.pref_camera_video_cds_value_off));
2213 mUI.overrideSettings(CameraSettings.KEY_QC_VIDEO_CDS_MODE,
2214 mActivity.getString(R.string.pref_camera_video_cds_value_off));
2215 if (!mIsVideoCDSUpdated) {
2216 if (video_cds != null) {
2217 mPrevSavedVideoCDS = mTempVideoCDS;
2218 }
2219 mIsVideoTNREnabled = true;
2220 mIsVideoCDSUpdated = true;
2221 }
2222 } else if (mIsVideoTNREnabled) {
2223 mParameters.set(CameraSettings.KEY_QC_VIDEO_CDS_MODE, mPrevSavedVideoCDS);
2224 mUI.overrideSettings(CameraSettings.KEY_QC_VIDEO_CDS_MODE, mPrevSavedVideoCDS);
2225 mIsVideoTNREnabled = false;
2226 mIsVideoCDSUpdated = false;
2227 mOverrideCDS = true;
2228 } else {
2229 mTempVideoCDS = video_cds;
2230 }
2231 mParameters.set(CameraSettings.KEY_QC_VIDEO_TNR_MODE, video_tnr);
Dimitar Borisoveb0b48f2014-10-24 10:40:41 +03002232 mUI.overrideSettings(CameraSettings.KEY_QC_VIDEO_TNR_MODE, video_tnr);
Dimitar Borisov19656472014-09-24 17:32:06 +03002233 }
2234
Alok Kediyae111d532013-09-28 16:03:47 +05302235 // Set Video HDR.
2236 String videoHDR = mPreferences.getString(
2237 CameraSettings.KEY_VIDEO_HDR,
2238 mActivity.getString(R.string.pref_camera_video_hdr_default));
2239 Log.v(TAG, "Video HDR Setting =" + videoHDR);
2240 if (isSupported(videoHDR, mParameters.getSupportedVideoHDRModes())) {
2241 mParameters.setVideoHDRMode(videoHDR);
2242 } else
2243 mParameters.setVideoHDRMode("off");
Suman Mukherjee1874e962014-03-27 13:08:38 +05302244
Suman Mukherjeee49881a2014-04-23 13:02:07 +05302245 //HFR/HSR recording not supported with DIS,TimeLapse,HDR option
Suman Mukherjee1874e962014-03-27 13:08:38 +05302246 String hfr = mParameters.getVideoHighFrameRate();
Vladimir Petrov3d8233a2014-07-14 18:32:12 -07002247 String hsr = mParameters.get(CameraSettings.KEY_VIDEO_HSR);
Suman Mukherjeee49881a2014-04-23 13:02:07 +05302248 String hdr = mParameters.getVideoHDRMode();
Suman Mukherjee1874e962014-03-27 13:08:38 +05302249 if ( ((hfr != null) && (!hfr.equals("off"))) ||
2250 ((hsr != null) && (!hsr.equals("off"))) ) {
2251 // Read time lapse recording interval.
2252 String frameIntervalStr = mPreferences.getString(
2253 CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL,
2254 mActivity.getString(R.string.pref_video_time_lapse_frame_interval_default));
2255 int timeLapseInterval = Integer.parseInt(frameIntervalStr);
Suman Mukherjeee49881a2014-04-23 13:02:07 +05302256 if ( (timeLapseInterval != 0) ||
2257 (disMode.equals("enable")) ||
2258 ((hdr != null) && (!hdr.equals("off"))) ) {
2259 Log.v(TAG,"HDR/DIS/Time Lapse ON for HFR/HSR selection, turning HFR/HSR off");
Suman Mukherjee1874e962014-03-27 13:08:38 +05302260 Toast.makeText(mActivity, R.string.error_app_unsupported_hfr_selection,
2261 Toast.LENGTH_LONG).show();
2262 mParameters.setVideoHighFrameRate("off");
Vladimir Petrov3d8233a2014-07-14 18:32:12 -07002263 mParameters.set(CameraSettings.KEY_VIDEO_HSR, "off");
2264 mUI.overrideSettings(CameraSettings.KEY_VIDEO_HIGH_FRAME_RATE, "off");
2265 mUI.initializePopup(mPreferenceGroup);
Suman Mukherjee1874e962014-03-27 13:08:38 +05302266 }
2267 }
Suman Mukherjee6a57e2b2014-04-21 11:35:44 +05302268
2269 //getSupportedPictureSizes will always send a sorted a list in descending order
2270 Size biggestSize = mParameters.getSupportedPictureSizes().get(0);
2271
2272 if (biggestSize.width <= videoWidth || biggestSize.height <= videoHeight) {
2273 if (disMode.equals("enable")) {
2274 Log.v(TAG,"DIS is not supported for this video quality");
2275 Toast.makeText(mActivity, R.string.error_app_unsupported_dis,
2276 Toast.LENGTH_LONG).show();
2277 mParameters.set(CameraSettings.KEY_QC_DIS_MODE, "disable");
2278 mUI.overrideSettings(CameraSettings.KEY_DIS,"disable");
2279 }
2280 }
Apurva Rajgurue07e72a2014-07-23 16:35:54 -07002281 //setting video rotation
2282 String videoRotation = mPreferences.getString(
2283 CameraSettings.KEY_VIDEO_ROTATION,
2284 mActivity.getString(R.string.pref_camera_video_rotation_default));
2285 if (isSupported(videoRotation, mParameters.getSupportedVideoRotationValues())) {
2286 mParameters.setVideoRotation(videoRotation);
2287 }
2288
Alok Kediya0dc64ff2013-09-27 20:22:45 +05302289 }
Michael Kolb8872c232013-01-29 10:33:22 -08002290 @SuppressWarnings("deprecation")
2291 private void setCameraParameters() {
Alok Kediyae111d532013-09-28 16:03:47 +05302292 Log.d(TAG,"Preview dimension in App->"+mDesiredPreviewWidth+"X"+mDesiredPreviewHeight);
Michael Kolb8872c232013-01-29 10:33:22 -08002293 mParameters.setPreviewSize(mDesiredPreviewWidth, mDesiredPreviewHeight);
Michael Kolbd75b9ae2013-05-30 07:45:41 -07002294 mParameters.set("video-size", mProfile.videoFrameWidth+"x"+mProfile.videoFrameHeight);
Angus Kongb50b5cb2013-08-09 14:55:20 -07002295 int[] fpsRange = CameraUtil.getMaxPreviewFpsRange(mParameters);
Doris Liu6432cd62013-06-13 17:20:31 -07002296 if (fpsRange.length > 0) {
2297 mParameters.setPreviewFpsRange(
2298 fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],
2299 fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]);
2300 } else {
2301 mParameters.setPreviewFrameRate(mProfile.videoFrameRate);
2302 }
Michael Kolb8872c232013-01-29 10:33:22 -08002303
Vladimir Petrov1d7f2f22013-12-13 18:15:14 +02002304 forceFlashOffIfSupported(!mPreviewFocused);
Alok Kediyaaed65252013-09-23 14:31:42 +05302305 videoWidth = mProfile.videoFrameWidth;
2306 videoHeight = mProfile.videoFrameHeight;
2307 String recordSize = videoWidth + "x" + videoHeight;
2308 Log.e(TAG,"Video dimension in App->"+recordSize);
2309 mParameters.set("video-size", recordSize);
Michael Kolb8872c232013-01-29 10:33:22 -08002310 // Set white balance parameter.
2311 String whiteBalance = mPreferences.getString(
2312 CameraSettings.KEY_WHITE_BALANCE,
2313 mActivity.getString(R.string.pref_camera_whitebalance_default));
2314 if (isSupported(whiteBalance,
2315 mParameters.getSupportedWhiteBalance())) {
2316 mParameters.setWhiteBalance(whiteBalance);
2317 } else {
2318 whiteBalance = mParameters.getWhiteBalance();
2319 if (whiteBalance == null) {
2320 whiteBalance = Parameters.WHITE_BALANCE_AUTO;
2321 }
2322 }
2323
2324 // Set zoom.
2325 if (mParameters.isZoomSupported()) {
Alok Kediya5213f272013-10-02 17:51:19 +05302326 Parameters p = mCameraDevice.getParameters();
2327 mZoomValue = p.getZoom();
Michael Kolb8872c232013-01-29 10:33:22 -08002328 mParameters.setZoom(mZoomValue);
2329 }
2330
2331 // Set continuous autofocus.
2332 List<String> supportedFocus = mParameters.getSupportedFocusModes();
2333 if (isSupported(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO, supportedFocus)) {
2334 mParameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
2335 }
2336
Angus Kongb50b5cb2013-08-09 14:55:20 -07002337 mParameters.set(CameraUtil.RECORDING_HINT, CameraUtil.TRUE);
Michael Kolb8872c232013-01-29 10:33:22 -08002338
2339 // Enable video stabilization. Convenience methods not available in API
2340 // level <= 14
2341 String vstabSupported = mParameters.get("video-stabilization-supported");
2342 if ("true".equals(vstabSupported)) {
2343 mParameters.set("video-stabilization", "true");
2344 }
2345
2346 // Set picture size.
2347 // The logic here is different from the logic in still-mode camera.
2348 // There we determine the preview size based on the picture size, but
2349 // here we determine the picture size based on the preview size.
2350 List<Size> supported = mParameters.getSupportedPictureSizes();
Angus Kongb50b5cb2013-08-09 14:55:20 -07002351 Size optimalSize = CameraUtil.getOptimalVideoSnapshotPictureSize(supported,
Michael Kolb8872c232013-01-29 10:33:22 -08002352 (double) mDesiredPreviewWidth / mDesiredPreviewHeight);
2353 Size original = mParameters.getPictureSize();
2354 if (!original.equals(optimalSize)) {
2355 mParameters.setPictureSize(optimalSize.width, optimalSize.height);
2356 }
2357 Log.v(TAG, "Video snapshot size is " + optimalSize.width + "x" +
2358 optimalSize.height);
2359
satyavaraprasad yerramsettic2248d72014-10-31 15:01:39 +05302360 // Set jpegthumbnail size
2361 // Set a jpegthumbnail size that is closest to the Picture height and has
2362 // the right aspect ratio.
2363 Size size = mParameters.getPictureSize();
2364 List<Size> sizes = mParameters.getSupportedJpegThumbnailSizes();
2365 optimalSize = CameraUtil.getOptimalJpegThumbnailSize(sizes,
2366 (double) size.width / size.height);
2367 original = mParameters.getJpegThumbnailSize();
2368 if (!original.equals(optimalSize)) {
2369 mParameters.setJpegThumbnailSize(optimalSize.width, optimalSize.height);
2370 }
2371 Log.v(TAG, "Thumbnail size is " + optimalSize.width + "x" + optimalSize.height);
2372
Michael Kolb8872c232013-01-29 10:33:22 -08002373 // Set JPEG quality.
2374 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
2375 CameraProfile.QUALITY_HIGH);
2376 mParameters.setJpegQuality(jpegQuality);
Alok Kediya0dc64ff2013-09-27 20:22:45 +05302377 //Call Qcom related Camera Parameters
2378 qcomSetCameraParameters();
Michael Kolb8872c232013-01-29 10:33:22 -08002379
Michael Kolbd75b9ae2013-05-30 07:45:41 -07002380 boolean flag = false;
2381 if (mPreviewing) {
2382 stopPreview();
2383 flag = true;
2384 }
Doris Liu6432cd62013-06-13 17:20:31 -07002385 mCameraDevice.setParameters(mParameters);
Michael Kolbd75b9ae2013-05-30 07:45:41 -07002386 if (flag) {
2387 startPreview();
2388 }
Michael Kolb8872c232013-01-29 10:33:22 -08002389 // Keep preview size up to date.
Doris Liu6432cd62013-06-13 17:20:31 -07002390 mParameters = mCameraDevice.getParameters();
Sascha Haeberlingf8b877c2013-09-09 17:32:48 -07002391
2392 // Update UI based on the new parameters.
2393 mUI.updateOnScreenIndicators(mParameters, mPreferences);
Michael Kolb8872c232013-01-29 10:33:22 -08002394 }
2395
2396 @Override
2397 public void onActivityResult(int requestCode, int resultCode, Intent data) {
Doris Liu3973deb2013-08-21 13:42:22 -07002398 // Do nothing.
Michael Kolb8872c232013-01-29 10:33:22 -08002399 }
2400
Michael Kolb8872c232013-01-29 10:33:22 -08002401 @Override
2402 public void onConfigurationChanged(Configuration newConfig) {
Doris Liu6a0de792013-02-26 10:54:25 -08002403 Log.v(TAG, "onConfigurationChanged");
Michael Kolb8872c232013-01-29 10:33:22 -08002404 setDisplayOrientation();
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +05302405 resizeForPreviewAspectRatio();
Michael Kolb8872c232013-01-29 10:33:22 -08002406 }
2407
2408 @Override
2409 public void onOverriddenPreferencesClicked() {
2410 }
2411
2412 @Override
2413 // TODO: Delete this after old camera code is removed
2414 public void onRestorePreferencesClicked() {
2415 }
2416
Michael Kolb8872c232013-01-29 10:33:22 -08002417 @Override
Sai Kumar Sanagavarapu35125312014-05-16 19:42:48 +05302418 public void onSharedPreferenceChanged(ListPreference pref) {
2419 onSharedPreferenceChanged();
2420 }
2421
2422 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08002423 public void onSharedPreferenceChanged() {
2424 // ignore the events after "onPause()" or preview has not started yet
Sascha Haeberlingf8b877c2013-09-09 17:32:48 -07002425 if (mPaused) {
2426 return;
2427 }
Michael Kolb8872c232013-01-29 10:33:22 -08002428 synchronized (mPreferences) {
2429 // If mCameraDevice is not ready then we can set the parameter in
2430 // startPreview().
Doris Liu6432cd62013-06-13 17:20:31 -07002431 if (mCameraDevice == null) return;
Michael Kolb8872c232013-01-29 10:33:22 -08002432
2433 boolean recordLocation = RecordLocationPreference.get(
2434 mPreferences, mContentResolver);
2435 mLocationManager.recordLocation(recordLocation);
2436
Michael Kolb8872c232013-01-29 10:33:22 -08002437 readVideoPreferences();
Doris Liu6827ce22013-03-12 19:24:28 -07002438 mUI.showTimeLapseUI(mCaptureTimeLapse);
Michael Kolb8872c232013-01-29 10:33:22 -08002439 // We need to restart the preview if preview size is changed.
2440 Size size = mParameters.getPreviewSize();
2441 if (size.width != mDesiredPreviewWidth
Alok Kediya5302d2e2013-09-29 10:24:44 +05302442 || size.height != mDesiredPreviewHeight || mRestartPreview) {
Doris Liu3973deb2013-08-21 13:42:22 -07002443
2444 stopPreview();
Michael Kolb8872c232013-01-29 10:33:22 -08002445 resizeForPreviewAspectRatio();
2446 startPreview(); // Parameters will be set in startPreview().
2447 } else {
2448 setCameraParameters();
2449 }
Alok Kediya5302d2e2013-09-29 10:24:44 +05302450 mRestartPreview = false;
Michael Kolb87880792013-04-30 15:38:49 -07002451 mUI.updateOnScreenIndicators(mParameters, mPreferences);
Santhosh Kumar H Eb2da1c12014-01-21 19:21:42 +05302452 Storage.setSaveSDCard(
2453 mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1"));
2454 mActivity.updateStorageSpaceAndHint();
Michael Kolb8872c232013-01-29 10:33:22 -08002455 }
2456 }
2457
Doris Liu6827ce22013-03-12 19:24:28 -07002458 protected void setCameraId(int cameraId) {
2459 ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID);
2460 pref.setValue("" + cameraId);
Michael Kolb8872c232013-01-29 10:33:22 -08002461 }
2462
2463 private void switchCamera() {
Sascha Haeberlingf8b877c2013-09-09 17:32:48 -07002464 if (mPaused) {
2465 return;
2466 }
Michael Kolb8872c232013-01-29 10:33:22 -08002467
2468 Log.d(TAG, "Start to switch camera.");
2469 mCameraId = mPendingSwitchCameraId;
2470 mPendingSwitchCameraId = -1;
Doris Liu6827ce22013-03-12 19:24:28 -07002471 setCameraId(mCameraId);
Michael Kolb8872c232013-01-29 10:33:22 -08002472
2473 closeCamera();
Doris Liu6827ce22013-03-12 19:24:28 -07002474 mUI.collapseCameraControls();
Michael Kolb8872c232013-01-29 10:33:22 -08002475 // Restart the camera and initialize the UI. From onCreate.
2476 mPreferences.setLocalId(mActivity, mCameraId);
2477 CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
2478 openCamera();
2479 readVideoPreferences();
2480 startPreview();
2481 initializeVideoSnapshot();
2482 resizeForPreviewAspectRatio();
2483 initializeVideoControl();
2484
2485 // From onResume
Doris Liu6432cd62013-06-13 17:20:31 -07002486 mZoomValue = 0;
Doris Liu6827ce22013-03-12 19:24:28 -07002487 mUI.initializeZoom(mParameters);
2488 mUI.setOrientationIndicator(0, false);
Michael Kolb8872c232013-01-29 10:33:22 -08002489
Doris Liu6432cd62013-06-13 17:20:31 -07002490 // Start switch camera animation. Post a message because
2491 // onFrameAvailable from the old camera may already exist.
2492 mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION);
Michael Kolb87880792013-04-30 15:38:49 -07002493 mUI.updateOnScreenIndicators(mParameters, mPreferences);
Suman Mukherjee446cfa42014-05-29 12:20:47 +05302494
2495 //Display timelapse msg depending upon selection in front/back camera.
2496 mUI.showTimeLapseUI(mCaptureTimeLapse);
Michael Kolb8872c232013-01-29 10:33:22 -08002497 }
2498
2499 // Preview texture has been copied. Now camera can be released and the
2500 // animation can be started.
2501 @Override
2502 public void onPreviewTextureCopied() {
2503 mHandler.sendEmptyMessage(SWITCH_CAMERA);
2504 }
2505
2506 @Override
2507 public void onCaptureTextureCopied() {
2508 }
2509
Michael Kolb8872c232013-01-29 10:33:22 -08002510 private void initializeVideoSnapshot() {
Doris Liu537718c2013-02-20 16:29:44 -08002511 if (mParameters == null) return;
Angus Kongb50b5cb2013-08-09 14:55:20 -07002512 if (CameraUtil.isVideoSnapshotSupported(mParameters) && !mIsVideoCaptureIntent) {
Michael Kolb8872c232013-01-29 10:33:22 -08002513 // Show the tap to focus toast if this is the first start.
2514 if (mPreferences.getBoolean(
2515 CameraSettings.KEY_VIDEO_FIRST_USE_HINT_SHOWN, true)) {
2516 // Delay the toast for one second to wait for orientation.
2517 mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_SNAPSHOT_TOAST, 1000);
2518 }
Michael Kolb8872c232013-01-29 10:33:22 -08002519 }
2520 }
2521
2522 void showVideoSnapshotUI(boolean enabled) {
Doris Liu537718c2013-02-20 16:29:44 -08002523 if (mParameters == null) return;
Angus Kongb50b5cb2013-08-09 14:55:20 -07002524 if (CameraUtil.isVideoSnapshotSupported(mParameters) && !mIsVideoCaptureIntent) {
Doris Liu6432cd62013-06-13 17:20:31 -07002525 if (enabled) {
Sascha Haeberling37f36112013-08-06 14:31:52 -07002526 mUI.animateFlash();
Doris Liu3973deb2013-08-21 13:42:22 -07002527 mUI.animateCapture();
Michael Kolb8872c232013-01-29 10:33:22 -08002528 } else {
Doris Liu6827ce22013-03-12 19:24:28 -07002529 mUI.showPreviewBorder(enabled);
Michael Kolb8872c232013-01-29 10:33:22 -08002530 }
Doris Liu6827ce22013-03-12 19:24:28 -07002531 mUI.enableShutter(!enabled);
Michael Kolb8872c232013-01-29 10:33:22 -08002532 }
2533 }
2534
ztenghui7b265a62013-09-09 14:58:44 -07002535 private void forceFlashOffIfSupported(boolean forceOff) {
2536 String flashMode;
2537 if (!forceOff) {
2538 flashMode = mPreferences.getString(
2539 CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE,
2540 mActivity.getString(R.string.pref_camera_video_flashmode_default));
2541 } else {
2542 flashMode = Parameters.FLASH_MODE_OFF;
2543 }
2544 List<String> supportedFlash = mParameters.getSupportedFlashModes();
2545 if (isSupported(flashMode, supportedFlash)) {
2546 mParameters.setFlashMode(flashMode);
2547 } else {
2548 flashMode = mParameters.getFlashMode();
2549 if (flashMode == null) {
2550 flashMode = mActivity.getString(
2551 R.string.pref_camera_flashmode_no_flash);
Michael Kolb8872c232013-01-29 10:33:22 -08002552 }
Michael Kolb8872c232013-01-29 10:33:22 -08002553 }
2554 }
2555
ztenghui7b265a62013-09-09 14:58:44 -07002556 /**
2557 * Used to update the flash mode. Video mode can turn on the flash as torch
2558 * mode, which we would like to turn on and off when we switching in and
2559 * out to the preview.
2560 *
2561 * @param forceOff whether we want to force the flash off.
2562 */
2563 private void forceFlashOff(boolean forceOff) {
2564 if (!mPreviewing || mParameters.getFlashMode() == null) {
2565 return;
2566 }
2567 forceFlashOffIfSupported(forceOff);
2568 mCameraDevice.setParameters(mParameters);
ztenghui285a5be2013-10-09 15:59:47 -07002569 mUI.updateOnScreenIndicators(mParameters, mPreferences);
ztenghui7b265a62013-09-09 14:58:44 -07002570 }
2571
Michael Kolb8872c232013-01-29 10:33:22 -08002572 @Override
ztenghui7b265a62013-09-09 14:58:44 -07002573 public void onPreviewFocusChanged(boolean previewFocused) {
2574 mUI.onPreviewFocusChanged(previewFocused);
2575 forceFlashOff(!previewFocused);
Vladimir Petrov1d7f2f22013-12-13 18:15:14 +02002576 mPreviewFocused = previewFocused;
Michael Kolb8872c232013-01-29 10:33:22 -08002577 }
2578
Erin Dahlgren3044d8c2013-10-10 18:23:45 -07002579 @Override
2580 public boolean arePreviewControlsVisible() {
2581 return mUI.arePreviewControlsVisible();
2582 }
2583
Angus Kong9ef99252013-07-18 18:04:19 -07002584 private final class JpegPictureCallback implements CameraPictureCallback {
Michael Kolb8872c232013-01-29 10:33:22 -08002585 Location mLocation;
2586
2587 public JpegPictureCallback(Location loc) {
2588 mLocation = loc;
2589 }
2590
2591 @Override
Angus Kong9ef99252013-07-18 18:04:19 -07002592 public void onPictureTaken(byte [] jpegData, CameraProxy camera) {
Michael Kolb8872c232013-01-29 10:33:22 -08002593 Log.v(TAG, "onPictureTaken");
Sai Kumar Sanagavarapu9b9fd082014-01-08 12:22:57 +05302594 if(!mSnapshotInProgress || mPaused || mCameraDevice == null) return;
Michael Kolb8872c232013-01-29 10:33:22 -08002595 mSnapshotInProgress = false;
2596 showVideoSnapshotUI(false);
2597 storeImage(jpegData, mLocation);
2598 }
2599 }
2600
2601 private void storeImage(final byte[] data, Location loc) {
2602 long dateTaken = System.currentTimeMillis();
Angus Kongb50b5cb2013-08-09 14:55:20 -07002603 String title = CameraUtil.createJpegName(dateTaken);
Angus Kong0d00a892013-03-26 11:40:40 -07002604 ExifInterface exif = Exif.getExif(data);
2605 int orientation = Exif.getOrientation(exif);
Alok Kediyad8887ed2013-09-28 17:12:35 +05302606 Size s = mParameters.getPictureSize();
Angus Kong86d36312013-01-31 18:22:44 -08002607 mActivity.getMediaSaveService().addImage(
Alok Kediyad8887ed2013-09-28 17:12:35 +05302608 data, title, dateTaken, loc, s.width, s.height, orientation,
2609 exif, mOnPhotoSavedListener, mContentResolver,
2610 PhotoModule.PIXEL_FORMAT_JPEG);
Michael Kolb8872c232013-01-29 10:33:22 -08002611 }
2612
Michael Kolb8872c232013-01-29 10:33:22 -08002613 private String convertOutputFormatToMimeType(int outputFileFormat) {
2614 if (outputFileFormat == MediaRecorder.OutputFormat.MPEG_4) {
2615 return "video/mp4";
2616 }
2617 return "video/3gpp";
2618 }
2619
2620 private String convertOutputFormatToFileExt(int outputFileFormat) {
2621 if (outputFileFormat == MediaRecorder.OutputFormat.MPEG_4) {
2622 return ".mp4";
2623 }
2624 return ".3gp";
2625 }
2626
2627 private void closeVideoFileDescriptor() {
2628 if (mVideoFileDescriptor != null) {
2629 try {
2630 mVideoFileDescriptor.close();
2631 } catch (IOException e) {
2632 Log.e(TAG, "Fail to close fd", e);
2633 }
2634 mVideoFileDescriptor = null;
2635 }
2636 }
2637
2638 private void showTapToSnapshotToast() {
2639 new RotateTextToast(mActivity, R.string.video_snapshot_hint, 0)
2640 .show();
2641 // Clear the preference.
2642 Editor editor = mPreferences.edit();
2643 editor.putBoolean(CameraSettings.KEY_VIDEO_FIRST_USE_HINT_SHOWN, false);
2644 editor.apply();
2645 }
2646
Michael Kolb8872c232013-01-29 10:33:22 -08002647 @Override
2648 public boolean updateStorageHintOnResume() {
2649 return true;
2650 }
2651
2652 // required by OnPreferenceChangedListener
2653 @Override
2654 public void onCameraPickerClicked(int cameraId) {
2655 if (mPaused || mPendingSwitchCameraId != -1) return;
2656
2657 mPendingSwitchCameraId = cameraId;
Doris Liu6432cd62013-06-13 17:20:31 -07002658 Log.d(TAG, "Start to copy texture.");
2659 // We need to keep a preview frame for the animation before
2660 // releasing the camera. This will trigger onPreviewTextureCopied.
2661 // TODO: ((CameraScreenNail) mActivity.mCameraScreenNail).copyTexture();
2662 // Disable all camera controls.
2663 mSwitchingCamera = true;
Sascha Haeberling0d63b892013-08-19 11:29:04 -07002664 switchCamera();
Michael Kolb8872c232013-01-29 10:33:22 -08002665
Doris Liu6a0de792013-02-26 10:54:25 -08002666 }
2667
2668 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08002669 public void onShowSwitcherPopup() {
Doris Liu6827ce22013-03-12 19:24:28 -07002670 mUI.onShowSwitcherPopup();
Michael Kolb8872c232013-01-29 10:33:22 -08002671 }
Angus Kong86d36312013-01-31 18:22:44 -08002672
2673 @Override
2674 public void onMediaSaveServiceConnected(MediaSaveService s) {
2675 // do nothing.
2676 }
Angus Kong395ee2d2013-07-15 12:42:41 -07002677
2678 @Override
2679 public void onPreviewUIReady() {
2680 startPreview();
2681 }
2682
2683 @Override
2684 public void onPreviewUIDestroyed() {
2685 stopPreview();
2686 }
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +05302687
2688 @Override
2689 public void onButtonPause() {
2690 pauseVideoRecording();
2691 }
2692
2693 @Override
2694 public void onButtonContinue() {
2695 resumeVideoRecording();
2696 }
2697
Michael Kolb8872c232013-01-29 10:33:22 -08002698}