summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera/CaptureModule.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/camera/CaptureModule.java')
-rw-r--r--src/com/android/camera/CaptureModule.java526
1 files changed, 503 insertions, 23 deletions
diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java
index ee4bcc724..336e7b410 100644
--- a/src/com/android/camera/CaptureModule.java
+++ b/src/com/android/camera/CaptureModule.java
@@ -22,6 +22,7 @@ package com.android.camera;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.content.ContentResolver;
+import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -45,15 +46,22 @@ import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.Face;
import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.params.StreamConfigurationMap;
+import android.location.Location;
+import android.media.AudioManager;
+import android.media.CamcorderProfile;
import android.media.CameraProfile;
import android.media.Image;
import android.media.ImageReader;
+import android.media.MediaMetadataRetriever;
+import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Debug;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemClock;
+import android.provider.MediaStore;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
@@ -76,15 +84,20 @@ import com.android.camera.ui.ModuleSwitcher;
import com.android.camera.ui.RotateTextToast;
import com.android.camera.util.CameraUtil;
import com.android.camera.util.PersistUtil;
+import com.android.camera.util.SettingTranslation;
import com.android.internal.util.MemInfoReader;
import org.codeaurora.snapcam.R;
import org.codeaurora.snapcam.filter.ClearSightImageProcessor;
+import java.io.File;
+import java.io.IOException;
import java.nio.ByteBuffer;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -109,10 +122,6 @@ public class CaptureModule implements CameraModule, PhotoController,
private static final MeteringRectangle[] ZERO_WEIGHT_3A_REGION = new MeteringRectangle[]{
new MeteringRectangle(0, 0, 0, 0, 0)};
/**
- * Conversion from screen rotation to JPEG orientation.
- */
- private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
- /**
* Camera state: Showing camera preview.
*/
private static final int STATE_PREVIEW = 0;
@@ -143,12 +152,6 @@ public class CaptureModule implements CameraModule, PhotoController,
// we can change it based on memory status or other requirements.
private static final int LONGSHOT_CANCEL_THRESHOLD = 40 * 1024 * 1024;
- static {
- ORIENTATIONS.append(Surface.ROTATION_0, 90);
- ORIENTATIONS.append(Surface.ROTATION_90, 0);
- ORIENTATIONS.append(Surface.ROTATION_180, 270);
- ORIENTATIONS.append(Surface.ROTATION_270, 180);
- }
private static final int MAX_IMAGE_NUM = 8;
MeteringRectangle[][] mAFRegions = new MeteringRectangle[MAX_NUM_CAM][];
@@ -238,6 +241,28 @@ public class CaptureModule implements CameraModule, PhotoController,
private int[] mPrecaptureRequestHashCode = new int[MAX_NUM_CAM];
private int[] mLockRequestHashCode = new int[MAX_NUM_CAM];
private final Handler mHandler = new MainHandler();
+ private CameraCaptureSession mPreviewSession;
+ private Size mPreviewSize;
+ private Size mPictureSize;
+ private Size mVideoPreviewSize;
+ private Size mVideoSize;
+
+ private MediaRecorder mMediaRecorder;
+ private boolean mIsRecordingVideo;
+ // The video duration limit. 0 means no limit.
+ private int mMaxVideoDurationInMs;
+ private boolean mIsMute = false;
+ // Default 0. If it is larger than 0, the camcorder is in time lapse mode.
+ private int mTimeBetweenTimeLapseFrameCaptureMs = 0;
+ private boolean mCaptureTimeLapse = false;
+ private CamcorderProfile mProfile;
+ private static final int UPDATE_RECORD_TIME = 5;
+ private ContentValues mCurrentVideoValues;
+ private String mVideoFilename;
+ private boolean mMediaRecorderPausing = false;
+ private long mRecordingStartTime;
+ private long mRecordingTotalTime;
+ private boolean mRecordingTimeCountsDown = false;
private class MediaSaveNotifyThread extends Thread {
private Uri uri;
@@ -274,6 +299,17 @@ public class CaptureModule implements CameraModule, PhotoController,
}
private MediaSaveNotifyThread mediaSaveNotifyThread;
+
+ private final MediaSaveService.OnMediaSavedListener mOnVideoSavedListener =
+ new MediaSaveService.OnMediaSavedListener() {
+ @Override
+ public void onMediaSaved(Uri uri) {
+ if (uri != null) {
+ mActivity.notifyNewMedia(uri);
+ }
+ }
+ };
+
private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener =
new MediaSaveService.OnMediaSavedListener() {
@Override
@@ -634,6 +670,7 @@ public class CaptureModule implements CameraModule, PhotoController,
}
// When the session is ready, we start displaying the preview.
mCaptureSession[id] = cameraCaptureSession;
+ mPreviewSession = cameraCaptureSession;
initializePreviewConfiguration(id);
try {
if (isBackCamera() && getCameraMode() == DUAL_MODE) {
@@ -1085,28 +1122,29 @@ public class CaptureModule implements CameraModule, PhotoController,
}
mCameraId[i] = cameraId;
- String pictureSize = mSettingsManager.getValue(SettingsManager
- .KEY_PICTURE_SIZE);
+ if (i == getMainCameraId()) {
+ String pictureSize = mSettingsManager.getValue(SettingsManager
+ .KEY_PICTURE_SIZE);
- Size size = parsePictureSize(pictureSize);
+ Size size = parsePictureSize(pictureSize);
- if (i == getMainCameraId()) {
Point screenSize = new Point();
mActivity.getWindowManager().getDefaultDisplay().getSize(screenSize);
Size[] prevSizes = map.getOutputSizes(imageFormat);
mFrameProcPreviewOutputSize = getOptimalPreviewSize(size, prevSizes, screenSize.x,
screenSize.y);
- mUI.setPreviewSize(mFrameProcPreviewOutputSize.getWidth(), mFrameProcPreviewOutputSize.getHeight());
}
+
if (isClearSightOn()) {
if(i == getMainCameraId()) {
- ClearSightImageProcessor.getInstance().init(size.getWidth(), size.getHeight(),
- mActivity, mOnMediaSavedListener);
+ ClearSightImageProcessor.getInstance().init(mPictureSize.getWidth(),
+ mPictureSize.getHeight(), mActivity, mOnMediaSavedListener);
ClearSightImageProcessor.getInstance().setCallback(this);
}
} else {
// No Clearsight
- mImageReader[i] = ImageReader.newInstance(size.getWidth(), size.getHeight(), imageFormat, MAX_IMAGE_NUM);
+ mImageReader[i] = ImageReader.newInstance(mPictureSize.getWidth(),
+ mPictureSize.getHeight(), imageFormat, MAX_IMAGE_NUM);
if(mPostProcessor.isFilterOn() && i == getMainCameraId()) {
mImageReader[i].setOnImageAvailableListener(mPostProcessor, mImageAvailableHandler);
// if(mFrameProcessor.isFrameFilterEnabled()) {
@@ -1138,8 +1176,8 @@ public class CaptureModule implements CameraModule, PhotoController,
}, mImageAvailableHandler);
}
}
-
}
+ mMediaRecorder = new MediaRecorder();
mAutoFocusRegionSupported = mSettingsManager.isAutoFocusRegionSupported(mCameraIdList);
mAutoExposureRegionSupported = mSettingsManager.isAutoExposureRegionSupported(mCameraIdList);
} catch (CameraAccessException e) {
@@ -1233,6 +1271,10 @@ public class CaptureModule implements CameraModule, PhotoController,
mCameraDevice[i] = null;
mCameraOpened[i] = false;
}
+ if (null != mMediaRecorder) {
+ mMediaRecorder.release();
+ mMediaRecorder = null;
+ }
}
} catch (InterruptedException e) {
mCameraOpenCloseLock.release();
@@ -1367,6 +1409,9 @@ public class CaptureModule implements CameraModule, PhotoController,
@Override
public void onPauseBeforeSuper() {
mPaused = true;
+ if (mIsRecordingVideo) {
+ stopRecordingVideo(getMainCameraId());
+ }
}
@Override
@@ -1412,9 +1457,19 @@ public class CaptureModule implements CameraModule, PhotoController,
return PostProcessor.FILTER_NONE;
}
+ private void initializeValues() {
+ updatePictureSize();
+ updateVideoSize();
+ updateTimeLapseSetting();
+ estimateJpegFileSize();
+ updateMaxVideoDuration();
+ }
+
@Override
public void onResumeAfterSuper() {
Log.d(TAG, "onResume " + getCameraMode());
+ initializeValues();
+ mUI.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());;
mUI.showSurfaceView();
mUI.setSwitcherIndex();
mCameraIdList = new ArrayList<>();
@@ -1470,7 +1525,6 @@ public class CaptureModule implements CameraModule, PhotoController,
mActivity.updateStorageSpaceAndHint();
}
});
- estimateJpegFileSize();
mUI.enableShutter(true);
}
@@ -1642,7 +1696,7 @@ public class CaptureModule implements CameraModule, PhotoController,
}
private boolean isTouchToFocusAllowed() {
- if (isTakingPicture() || isSceneModeOn()) return false;
+ if (isTakingPicture() || mIsRecordingVideo || isSceneModeOn()) return false;
return true;
}
@@ -1685,7 +1739,7 @@ public class CaptureModule implements CameraModule, PhotoController,
@Override
public void onPreviewUIReady() {
- if (mPaused) {
+ if (mPaused || mIsRecordingVideo) {
return;
}
Log.d(TAG, "onPreviewUIReady");
@@ -1790,6 +1844,411 @@ public class CaptureModule implements CameraModule, PhotoController,
}
}
+ private void updatePictureSize() {
+ String pictureSize = mSettingsManager.getValue(SettingsManager.KEY_PICTURE_SIZE);
+ mPictureSize = parsePictureSize(pictureSize);
+ Point screenSize = new Point();
+ mActivity.getWindowManager().getDefaultDisplay().getSize(screenSize);
+ Size[] prevSizes = mSettingsManager.getSupportedOutputSize(getMainCameraId(),
+ SurfaceHolder.class);
+ mPreviewSize = getOptimalPreviewSize(mPictureSize, prevSizes, screenSize.x, screenSize.y);
+ }
+
+ public boolean isRecordingVideo() {
+ return mIsRecordingVideo;
+ }
+
+ public void setMute(boolean enable, boolean isValue) {
+ AudioManager am = (AudioManager) mActivity.getSystemService(Context.AUDIO_SERVICE);
+ am.setMicrophoneMute(enable);
+ if (isValue) {
+ mIsMute = enable;
+ }
+ }
+
+ public boolean isAudioMute() {
+ return mIsMute;
+ }
+
+ private void updateVideoSize() {
+ String videoSize = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_QUALITY);
+ mVideoSize = parsePictureSize(videoSize);
+ Point screenSize = new Point();
+ mActivity.getWindowManager().getDefaultDisplay().getSize(screenSize);
+ Size[] prevSizes = mSettingsManager.getSupportedOutputSize(getMainCameraId(),
+ MediaRecorder.class);
+ mVideoPreviewSize = getOptimalPreviewSize(mVideoSize, prevSizes, screenSize.x, screenSize.y);
+ }
+
+ private void updateMaxVideoDuration() {
+ String minutesStr = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_DURATION);
+ int minutes = Integer.parseInt(minutesStr);
+ if (minutes == -1) {
+ // User wants lowest, set 30s */
+ mMaxVideoDurationInMs = 30000;
+ } else {
+ // 1 minute = 60000ms
+ mMaxVideoDurationInMs = 60000 * minutes;
+ }
+ }
+
+ private void startRecordingVideo(int cameraId) {
+ if (null == mCameraDevice[cameraId]) {
+ return;
+ }
+ Log.d(TAG, "StartRecordingVideo " + cameraId);
+ mIsRecordingVideo = true;
+ mMediaRecorderPausing = false;
+ mUI.hideUIwhileRecording();
+ mUI.clearFocus();
+ mCameraHandler.removeMessages(CANCEL_TOUCH_FOCUS, cameraId);
+ mState[cameraId] = STATE_PREVIEW;
+ mControlAFMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE;
+ closePreviewSession();
+ boolean changed = mUI.setPreviewSize(mVideoPreviewSize.getWidth(), mVideoPreviewSize
+ .getHeight());
+ if (changed) {
+ mUI.hideSurfaceView();
+ mUI.showSurfaceView();
+ }
+
+ try {
+ setUpMediaRecorder(cameraId);
+ final CaptureRequest.Builder mPreviewBuilder = mCameraDevice[cameraId]
+ .createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
+ List<Surface> surfaces = new ArrayList<>();
+
+ Surface previewSurface = getPreviewSurface(cameraId);
+ surfaces.add(previewSurface);
+ mPreviewBuilder.addTarget(previewSurface);
+ surfaces.add(mMediaRecorder.getSurface());
+ mPreviewBuilder.addTarget(mMediaRecorder.getSurface());
+
+ mCameraDevice[cameraId].createCaptureSession(surfaces, new CameraCaptureSession
+ .StateCallback() {
+
+ @Override
+ public void onConfigured(CameraCaptureSession cameraCaptureSession) {
+ Log.d(TAG, "StartRecordingVideo session onConfigured");
+ mPreviewSession = cameraCaptureSession;
+ try {
+ setUpVideoCaptureRequestBuilder(mPreviewBuilder);
+ mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, mCameraHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ mMediaRecorder.start();
+ mUI.clearFocus();
+ mUI.resetPauseButton();
+ mRecordingTotalTime = 0L;
+ mRecordingStartTime = SystemClock.uptimeMillis();
+ mUI.showRecordingUI(true);
+ updateRecordingTime();
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
+ Toast.makeText(mActivity, "Video Failed", Toast.LENGTH_SHORT).show();
+ }
+ }, null);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void updateTimeLapseSetting() {
+ String value = mSettingsManager.getValue(SettingsManager
+ .KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL);
+ if (value == null) return;
+ int time = Integer.parseInt(value);
+ mTimeBetweenTimeLapseFrameCaptureMs = time;
+ mCaptureTimeLapse = mTimeBetweenTimeLapseFrameCaptureMs != 0;
+ mUI.showTimeLapseUI(mCaptureTimeLapse);
+ }
+
+ private void setUpVideoCaptureRequestBuilder(CaptureRequest.Builder builder) {
+ builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
+ builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest
+ .CONTROL_AF_MODE_CONTINUOUS_VIDEO);
+ builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
+ applyVideoStabilization(builder);
+ applyNoiseReduction(builder);
+ applyColorEffect(builder);
+ applyWhiteBalance(builder);
+ applyVideoFlash(builder);
+ }
+
+ private void applyVideoFlash(CaptureRequest.Builder builder) {
+ String value = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_FLASH_MODE);
+ if (value == null) return;
+
+ if (value.equals("torch")) {
+ builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
+ } else {
+ builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
+ }
+ }
+
+ private void applyNoiseReduction(CaptureRequest.Builder builder) {
+ String value = mSettingsManager.getValue(SettingsManager.KEY_NOISE_REDUCTION);
+ if (value == null) return;
+ int noiseReduction = SettingTranslation.getNoiseReduction(value);
+ builder.set(CaptureRequest.NOISE_REDUCTION_MODE, noiseReduction);
+ }
+
+ private void applyVideoStabilization(CaptureRequest.Builder builder) {
+ String value = mSettingsManager.getValue(SettingsManager.KEY_DIS);
+ if (value == null) return;
+ if (value.equals("enable")) {
+ builder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest
+ .CONTROL_VIDEO_STABILIZATION_MODE_ON);
+ } else {
+ builder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest
+ .CONTROL_VIDEO_STABILIZATION_MODE_OFF);
+ }
+ }
+
+ private long getTimeLapseVideoLength(long deltaMs) {
+ // For better approximation calculate fractional number of frames captured.
+ // This will update the video time at a higher resolution.
+ double numberOfFrames = (double) deltaMs / mTimeBetweenTimeLapseFrameCaptureMs;
+ return (long) (numberOfFrames / mProfile.videoFrameRate * 1000);
+ }
+
+ private void updateRecordingTime() {
+ if (!mIsRecordingVideo) {
+ return;
+ }
+ if (mMediaRecorderPausing) {
+ return;
+ }
+
+ long now = SystemClock.uptimeMillis();
+ long delta = now - mRecordingStartTime + mRecordingTotalTime;
+
+ // Starting a minute before reaching the max duration
+ // limit, we'll countdown the remaining time instead.
+ boolean countdownRemainingTime = (mMaxVideoDurationInMs != 0
+ && delta >= mMaxVideoDurationInMs - 60000);
+
+ long deltaAdjusted = delta;
+ if (countdownRemainingTime) {
+ deltaAdjusted = Math.max(0, mMaxVideoDurationInMs - deltaAdjusted) + 999;
+ }
+ String text;
+
+ long targetNextUpdateDelay;
+ if (!mCaptureTimeLapse) {
+ text = CameraUtil.millisecondToTimeString(deltaAdjusted, false);
+ targetNextUpdateDelay = 1000;
+ } else {
+ // The length of time lapse video is different from the length
+ // of the actual wall clock time elapsed. Display the video length
+ // only in format hh:mm:ss.dd, where dd are the centi seconds.
+ text = CameraUtil.millisecondToTimeString(getTimeLapseVideoLength(delta), true);
+ targetNextUpdateDelay = mTimeBetweenTimeLapseFrameCaptureMs;
+ }
+
+ mUI.setRecordingTime(text);
+
+ if (mRecordingTimeCountsDown != countdownRemainingTime) {
+ // Avoid setting the color on every update, do it only
+ // when it needs changing.
+ mRecordingTimeCountsDown = countdownRemainingTime;
+
+ int color = mActivity.getResources().getColor(countdownRemainingTime
+ ? R.color.recording_time_remaining_text
+ : R.color.recording_time_elapsed_text);
+
+ mUI.setRecordingTimeTextColor(color);
+ }
+
+ long actualNextUpdateDelay = targetNextUpdateDelay - (delta % targetNextUpdateDelay);
+ mHandler.sendEmptyMessageDelayed(
+ UPDATE_RECORD_TIME, actualNextUpdateDelay);
+ }
+
+ private void pauseVideoRecording() {
+ Log.v(TAG, "pauseVideoRecording");
+ mMediaRecorderPausing = true;
+ mRecordingTotalTime += SystemClock.uptimeMillis() - mRecordingStartTime;
+ mMediaRecorder.pause();
+ }
+
+ private void resumeVideoRecording() {
+ Log.v(TAG, "resumeVideoRecording");
+ mMediaRecorderPausing = false;
+ mRecordingStartTime = SystemClock.uptimeMillis();
+ updateRecordingTime();
+ mMediaRecorder.start();
+ }
+
+ public void onButtonPause() {
+ pauseVideoRecording();
+ }
+
+ public void onButtonContinue() {
+ resumeVideoRecording();
+ }
+
+ private void stopRecordingVideo(int cameraId) {
+ Log.d(TAG, "stopRecordingVideo " + cameraId);
+
+ // Stop recording
+ closePreviewSession();
+ mMediaRecorder.stop();
+ mMediaRecorder.reset();
+
+ saveVideo();
+
+ mUI.showRecordingUI(false);
+ mIsRecordingVideo = false;
+ boolean changed = mUI.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
+ if (changed) {
+ mUI.hideSurfaceView();
+ mUI.showSurfaceView();
+ } else {
+ createSession(cameraId);
+ }
+ mUI.showUIafterRecording();
+ }
+
+ private void closePreviewSession() {
+ Log.d(TAG, "closePreviewSession");
+ if (mPreviewSession != null) {
+ mPreviewSession.close();
+ mPreviewSession = null;
+ }
+ }
+
+ private String createName(long dateTaken) {
+ Date date = new Date(dateTaken);
+ SimpleDateFormat dateFormat = new SimpleDateFormat(
+ mActivity.getString(R.string.video_file_name_format));
+
+ return dateFormat.format(date);
+ }
+
+ private String generateVideoFilename(int outputFileFormat) {
+ long dateTaken = System.currentTimeMillis();
+ String title = createName(dateTaken);
+ String filename = title + CameraUtil.convertOutputFormatToFileExt(outputFileFormat);
+ String mime = CameraUtil.convertOutputFormatToMimeType(outputFileFormat);
+ String path;
+ if (Storage.isSaveSDCard() && SDCard.instance().isWriteable()) {
+ path = SDCard.instance().getDirectory() + '/' + filename;
+ } else {
+ path = Storage.DIRECTORY + '/' + filename;
+ }
+ mCurrentVideoValues = new ContentValues(9);
+ mCurrentVideoValues.put(MediaStore.Video.Media.TITLE, title);
+ mCurrentVideoValues.put(MediaStore.Video.Media.DISPLAY_NAME, filename);
+ mCurrentVideoValues.put(MediaStore.Video.Media.DATE_TAKEN, dateTaken);
+ mCurrentVideoValues.put(MediaStore.MediaColumns.DATE_MODIFIED, dateTaken / 1000);
+ mCurrentVideoValues.put(MediaStore.Video.Media.MIME_TYPE, mime);
+ mCurrentVideoValues.put(MediaStore.Video.Media.DATA, path);
+ mCurrentVideoValues.put(MediaStore.Video.Media.RESOLUTION,
+ "" + mVideoSize.getWidth() + "x" + mVideoSize.getHeight());
+ Location loc = mLocationManager.getCurrentLocation();
+ if (loc != null) {
+ mCurrentVideoValues.put(MediaStore.Video.Media.LATITUDE, loc.getLatitude());
+ mCurrentVideoValues.put(MediaStore.Video.Media.LONGITUDE, loc.getLongitude());
+ }
+ mVideoFilename = path;
+ return path;
+ }
+
+ private void saveVideo() {
+ File origFile = new File(mVideoFilename);
+ if (!origFile.exists() || origFile.length() <= 0) {
+ Log.e(TAG, "Invalid file");
+ mCurrentVideoValues = null;
+ return;
+ }
+
+ long duration = 0L;
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+
+ try {
+ retriever.setDataSource(mVideoFilename);
+ duration = Long.valueOf(retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_DURATION));
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "cannot access the file");
+ }
+ retriever.release();
+
+ mActivity.getMediaSaveService().addVideo(mVideoFilename,
+ duration, mCurrentVideoValues,
+ mOnVideoSavedListener, mContentResolver);
+ mCurrentVideoValues = null;
+ }
+
+ private void setUpMediaRecorder(int cameraId) throws IOException {
+ Log.d(TAG, "setUpMediaRecorder");
+ String videoSize = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_QUALITY);
+ int size = CameraSettings.VIDEO_QUALITY_TABLE.get(videoSize);
+ if (mCaptureTimeLapse)
+ size = CameraSettings.getTimeLapseQualityFor(size);
+ mProfile = CamcorderProfile.get(cameraId, size);
+
+ int videoEncoder = SettingTranslation
+ .getVideoEncoder(mSettingsManager.getValue(SettingsManager.KEY_VIDEO_ENCODER));
+ int audioEncoder = SettingTranslation
+ .getAudioEncoder(mSettingsManager.getValue(SettingsManager.KEY_AUDIO_ENCODER));
+
+ int outputFormat = MediaRecorder.OutputFormat.MPEG_4;
+
+ if (!mCaptureTimeLapse) {
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ }
+ mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
+
+ mMediaRecorder.setOutputFormat(mProfile.fileFormat);
+ String fileName = generateVideoFilename(outputFormat);
+ Log.v(TAG, "New video filename: " + fileName);
+ mMediaRecorder.setOutputFile(fileName);
+ mMediaRecorder.setVideoEncodingBitRate(mProfile.videoBitRate);
+ mMediaRecorder.setVideoFrameRate(mProfile.videoFrameRate);
+ mMediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
+ mMediaRecorder.setVideoEncoder(videoEncoder);
+ if (!mCaptureTimeLapse) {
+ mMediaRecorder.setAudioEncodingBitRate(mProfile.audioBitRate);
+ mMediaRecorder.setAudioChannels(mProfile.audioChannels);
+ mMediaRecorder.setAudioSamplingRate(mProfile.audioSampleRate);
+ mMediaRecorder.setAudioEncoder(audioEncoder);
+ }
+ mMediaRecorder.setMaxDuration(mMaxVideoDurationInMs);
+ if (mCaptureTimeLapse) {
+ double fps = 1000 / (double) mTimeBetweenTimeLapseFrameCaptureMs;
+ mMediaRecorder.setCaptureRate(fps);
+ }
+ Location loc = mLocationManager.getCurrentLocation();
+ if (loc != null) {
+ mMediaRecorder.setLocation((float) loc.getLatitude(),
+ (float) loc.getLongitude());
+ }
+ int rotation = CameraUtil.getJpegRotation(cameraId, mOrientation);
+ String videoRotation = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_ROTATION);
+ if (videoRotation != null) {
+ rotation += Integer.parseInt(videoRotation);
+ rotation = rotation % 360;
+ }
+ mMediaRecorder.setOrientationHint(rotation);
+ mMediaRecorder.prepare();
+ }
+
+ public void onVideoButtonClick() {
+ if (getCameraMode() == DUAL_MODE) return;
+ if (mIsRecordingVideo) {
+ stopRecordingVideo(getMainCameraId());
+ } else {
+ startRecordingVideo(getMainCameraId());
+ }
+ }
+
@Override
public void onShutterButtonClick() {
if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
@@ -2226,13 +2685,25 @@ public class CaptureModule implements CameraModule, PhotoController,
case SettingsManager.KEY_JPEG_QUALITY:
estimateJpegFileSize();
continue;
+ case SettingsManager.KEY_VIDEO_DURATION:
+ updateMaxVideoDuration();
+ continue;
+ case SettingsManager.KEY_VIDEO_QUALITY:
+ updateVideoSize();
+ continue;
+ case SettingsManager.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL:
+ updateTimeLapseSetting();
+ continue;
case SettingsManager.KEY_CAMERA2:
switchCameraMode(value);
return;
+ case SettingsManager.KEY_PICTURE_SIZE:
+ updatePictureSize();
+ if (count == 0) restart();
+ return;
case SettingsManager.KEY_CAMERA_ID:
case SettingsManager.KEY_MONO_ONLY:
case SettingsManager.KEY_CLEARSIGHT:
- case SettingsManager.KEY_PICTURE_SIZE:
case SettingsManager.KEY_MONO_PREVIEW:
if (count == 0) restart();
return;
@@ -2414,5 +2885,14 @@ public class CaptureModule implements CameraModule, PhotoController,
public MainHandler() {
super(Looper.getMainLooper());
}
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case UPDATE_RECORD_TIME: {
+ updateRecordingTime();
+ break;
+ }
+ }
+ }
}
}