summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorByunghun Jeon <bjeon@codeaurora.org>2016-06-17 15:52:25 -0700
committerSteve Kondik <steve@cyngn.com>2016-08-21 18:46:32 -0700
commitff3c5a7464b23054bedfb0e621a5e41b7c28e605 (patch)
treeb65578e9d54131944a91be674c5e21a357b89de4
parent752fd4bdf258147be89ece3d9e022630865d266d (diff)
downloadandroid_packages_apps_Snap-ff3c5a7464b23054bedfb0e621a5e41b7c28e605.zip
android_packages_apps_Snap-ff3c5a7464b23054bedfb0e621a5e41b7c28e605.tar.gz
android_packages_apps_Snap-ff3c5a7464b23054bedfb0e621a5e41b7c28e605.tar.bz2
SnapdragonCamera: Allow take snapshot while recording video
Allow take snapshot while recording video by showing shutter button. Directly call capture when shutter button is pressed. Change-Id: Iae4d42d8878ea82b459ec67709b0ad8e340c8226 CRs-Fixed: 1028463
-rw-r--r--res/values/camera2arrays.xml10
-rw-r--r--res/values/qcomstrings.xml9
-rw-r--r--res/xml/capture_preferences.xml7
-rw-r--r--src/com/android/camera/CaptureModule.java165
-rw-r--r--src/com/android/camera/CaptureUI.java5
-rw-r--r--src/com/android/camera/SettingsManager.java7
6 files changed, 175 insertions, 28 deletions
diff --git a/res/values/camera2arrays.xml b/res/values/camera2arrays.xml
index ac569f4..0898384 100644
--- a/res/values/camera2arrays.xml
+++ b/res/values/camera2arrays.xml
@@ -795,4 +795,14 @@ for time lapse recording -->
<item>off</item>
<item>on</item>
</string-array>
+
+ <string-array name="pref_camera2_videosnap_entries" translatable="true">
+ <item>@string/pref_camera2_videosnap_entry_enable</item>
+ <item>@string/pref_camera2_videosnap_entry_disable</item>
+ </string-array>
+
+ <string-array name="pref_camera2_videosnap_entryvalues" translatable="false">
+ <item>@string/pref_camera2_videosnap_value_enable</item>
+ <item>@string/pref_camera2_videosnap_value_disable</item>
+ </string-array>
</resources>
diff --git a/res/values/qcomstrings.xml b/res/values/qcomstrings.xml
index 6710a95..c099acf 100644
--- a/res/values/qcomstrings.xml
+++ b/res/values/qcomstrings.xml
@@ -578,4 +578,13 @@
<string name="pref_camera2_noise_reduction_value_fast" translatable="false">fast</string>
<string name="pref_camera2_noise_reduction_value_high_quality" translatable="false">high-quality</string>
+ <string name="pref_camera2_videosnap_default" translatable="false">enable</string>
+ <string name="pref_camera2_videosnap_title" translatable="true">Auto Snapshot Size</string>
+
+ <string name="pref_camera2_videosnap_value_enable" translatable="true">enable</string>
+ <string name="pref_camera2_videosnap_value_disable" translatable="true">disable</string>
+
+ <string name="pref_camera2_videosnap_entry_enable" translatable="true">Enable</string>
+ <string name="pref_camera2_videosnap_entry_disable" translatable="true">Disable</string>
+
</resources>
diff --git a/res/xml/capture_preferences.xml b/res/xml/capture_preferences.xml
index 06f816c..d7d478d 100644
--- a/res/xml/capture_preferences.xml
+++ b/res/xml/capture_preferences.xml
@@ -266,4 +266,11 @@
camera:key="pref_camera2_facedetection_key"
camera:singleIcon="@drawable/ic_settings_facerec"
camera:title="@string/pref_camera_facedetection_title"/>
+
+ <ListPreference
+ camera:defaultValue="@string/pref_camera2_videosnap_default"
+ camera:entries="@array/pref_camera2_videosnap_entries"
+ camera:entryValues="@array/pref_camera2_videosnap_entryvalues"
+ camera:key="pref_camera2_videosnap_key"
+ camera:title="@string/pref_camera2_videosnap_title" />
</PreferenceGroup>
diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java
index e966ea1..a7448ae 100644
--- a/src/com/android/camera/CaptureModule.java
+++ b/src/com/android/camera/CaptureModule.java
@@ -27,7 +27,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
-import android.graphics.Camera;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Point;
@@ -64,7 +63,6 @@ import android.os.SystemClock;
import android.provider.MediaStore;
import android.util.Log;
import android.util.Size;
-import android.util.SparseIntArray;
import android.view.Display;
import android.view.KeyEvent;
import android.view.OrientationEventListener;
@@ -95,12 +93,10 @@ 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;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -241,11 +237,12 @@ 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 CameraCaptureSession mCurrentSession;
private Size mPreviewSize;
private Size mPictureSize;
private Size mVideoPreviewSize;
private Size mVideoSize;
+ private Size mVideoSnapshotSize;
private MediaRecorder mMediaRecorder;
private boolean mIsRecordingVideo;
@@ -263,6 +260,7 @@ public class CaptureModule implements CameraModule, PhotoController,
private long mRecordingStartTime;
private long mRecordingTotalTime;
private boolean mRecordingTimeCountsDown = false;
+ private ImageReader mVideoSnapshotImageReader;
private class MediaSaveNotifyThread extends Thread {
private Uri uri;
@@ -684,7 +682,7 @@ public class CaptureModule implements CameraModule, PhotoController,
}
// When the session is ready, we start displaying the preview.
mCaptureSession[id] = cameraCaptureSession;
- mPreviewSession = cameraCaptureSession;
+ mCurrentSession = cameraCaptureSession;
initializePreviewConfiguration(id);
setDisplayOrientation();
updateFaceDetection();
@@ -1054,6 +1052,50 @@ public class CaptureModule implements CameraModule, PhotoController,
}
}
+ private void captureVideoSnapshot(final int id) {
+ Log.d(TAG, "captureStillPicture " + id);
+ try {
+ if (null == mActivity || null == mCameraDevice[id]) {
+ warningToast("Camera is not ready yet to take a video snapshot.");
+ return;
+ }
+ CaptureRequest.Builder captureBuilder =
+ mCameraDevice[id].createCaptureRequest(CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
+
+ captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, CameraUtil.getJpegRotation(id, mOrientation));
+ applyVideoSnapshot(captureBuilder, id);
+
+ captureBuilder.addTarget(mVideoSnapshotImageReader.getSurface());
+
+ mCurrentSession.capture(captureBuilder.build(),
+ new CameraCaptureSession.CaptureCallback() {
+
+ @Override
+ public void onCaptureCompleted(CameraCaptureSession session,
+ CaptureRequest request,
+ TotalCaptureResult result) {
+ Log.d(TAG, "captureVideoSnapshot onCaptureCompleted: " + id);
+ }
+
+ @Override
+ public void onCaptureFailed(CameraCaptureSession session,
+ CaptureRequest request,
+ CaptureFailure result) {
+ Log.d(TAG, "captureVideoSnapshot onCaptureFailed: " + id);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(CameraCaptureSession session, int
+ sequenceId, long frameNumber) {
+ Log.d(TAG, "captureVideoSnapshot onCaptureSequenceCompleted: " + id);
+ }
+ }, mCaptureCallbackHandler);
+ } catch (CameraAccessException e) {
+ Log.d(TAG, "captureVideoSnapshot failed");
+ e.printStackTrace();
+ }
+ }
+
/**
* Run the precapture sequence for capturing a still image. This method should be called when
* we get a response in {@link #mCaptureCallback} from {@link #lockFocus()}.
@@ -1201,6 +1243,36 @@ public class CaptureModule implements CameraModule, PhotoController,
}
}
+ private void createVideoSnapshotImageReader() {
+ if (mVideoSnapshotImageReader != null) {
+ mVideoSnapshotImageReader.close();
+ }
+ mVideoSnapshotImageReader = ImageReader.newInstance(mVideoSnapshotSize.getWidth(),
+ mVideoSnapshotSize.getHeight(), ImageFormat.JPEG, MAX_IMAGE_NUM);
+ mVideoSnapshotImageReader.setOnImageAvailableListener(
+ new ImageReader.OnImageAvailableListener() {
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ Image image = reader.acquireNextImage();
+ mCaptureStartTime = System.currentTimeMillis();
+ mNamedImages.nameNewImage(mCaptureStartTime);
+ NamedEntity name = mNamedImages.getNextNameEntity();
+ String title = (name == null) ? null : name.title;
+ long date = (name == null) ? -1 : name.date;
+
+ ByteBuffer buffer = image.getPlanes()[0].getBuffer();
+ byte[] bytes = new byte[buffer.remaining()];
+ mLastJpegData = bytes;
+ buffer.get(bytes);
+
+ mActivity.getMediaSaveService().addImage(bytes, title, date,
+ null, image.getWidth(), image.getHeight(), 0, null,
+ mOnMediaSavedListener, mContentResolver, "jpeg");
+ image.close();
+ }
+ }, mImageAvailableHandler);
+ }
+
/**
* Unlock the focus. This method should be called when still image capture sequence is
* finished.
@@ -1291,6 +1363,11 @@ public class CaptureModule implements CameraModule, PhotoController,
mMediaRecorder.release();
mMediaRecorder = null;
}
+
+ if (null != mVideoSnapshotImageReader) {
+ mVideoSnapshotImageReader.close();
+ mVideoSnapshotImageReader = null;
+ }
}
} catch (InterruptedException e) {
mCameraOpenCloseLock.release();
@@ -1337,6 +1414,13 @@ public class CaptureModule implements CameraModule, PhotoController,
applyFaceDetect(builder, id);
}
+ private void applyVideoSnapshot(CaptureRequest.Builder builder, int id) {
+ builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
+ applyWhiteBalance(builder);
+ applyColorEffect(builder);
+ applyVideoFlash(builder);
+ }
+
private void applyCommonSettings(CaptureRequest.Builder builder, int id) {
builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
builder.set(CaptureRequest.CONTROL_AF_MODE, mControlAFMode);
@@ -1485,6 +1569,7 @@ public class CaptureModule implements CameraModule, PhotoController,
private void initializeValues() {
updatePictureSize();
updateVideoSize();
+ updateVideoSnapshotSize();
updateTimeLapseSetting();
estimateJpegFileSize();
updateMaxVideoDuration();
@@ -1921,6 +2006,16 @@ public class CaptureModule implements CameraModule, PhotoController,
mVideoPreviewSize = getOptimalPreviewSize(mVideoSize, prevSizes, screenSize.x, screenSize.y);
}
+ private void updateVideoSnapshotSize() {
+ String auto = mSettingsManager.getValue(SettingsManager.KEY_AUTO_VIDEOSNAP_SIZE);
+ if (auto != null && auto.equals("enable")) {
+ Size[] sizes = mSettingsManager.getSupportedOutputSize(getMainCameraId(), ImageFormat.JPEG);
+ mVideoSnapshotSize = getMaxSizeWithRatio(sizes, mVideoSize);
+ } else {
+ mVideoSnapshotSize = mPictureSize;
+ }
+ }
+
private void updateMaxVideoDuration() {
String minutesStr = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_DURATION);
int minutes = Integer.parseInt(minutesStr);
@@ -1955,6 +2050,7 @@ public class CaptureModule implements CameraModule, PhotoController,
try {
setUpMediaRecorder(cameraId);
+ createVideoSnapshotImageReader();
final CaptureRequest.Builder mPreviewBuilder = mCameraDevice[cameraId]
.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
List<Surface> surfaces = new ArrayList<>();
@@ -1964,6 +2060,7 @@ public class CaptureModule implements CameraModule, PhotoController,
mPreviewBuilder.addTarget(previewSurface);
surfaces.add(mMediaRecorder.getSurface());
mPreviewBuilder.addTarget(mMediaRecorder.getSurface());
+ surfaces.add(mVideoSnapshotImageReader.getSurface());
mCameraDevice[cameraId].createCaptureSession(surfaces, new CameraCaptureSession
.StateCallback() {
@@ -1971,10 +2068,10 @@ public class CaptureModule implements CameraModule, PhotoController,
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
Log.d(TAG, "StartRecordingVideo session onConfigured");
- mPreviewSession = cameraCaptureSession;
+ mCurrentSession = cameraCaptureSession;
try {
setUpVideoCaptureRequestBuilder(mPreviewBuilder);
- mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, mCameraHandler);
+ mCurrentSession.setRepeatingRequest(mPreviewBuilder.build(), null, mCameraHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
@@ -2158,9 +2255,9 @@ public class CaptureModule implements CameraModule, PhotoController,
private void closePreviewSession() {
Log.d(TAG, "closePreviewSession");
- if (mPreviewSession != null) {
- mPreviewSession.close();
- mPreviewSession = null;
+ if (mCurrentSession != null) {
+ mCurrentSession.close();
+ mCurrentSession = null;
}
}
@@ -2298,22 +2395,26 @@ public class CaptureModule implements CameraModule, PhotoController,
return;
}
- String timer = mSettingsManager.getValue(SettingsManager.KEY_TIMER);
-
- int seconds = Integer.parseInt(timer);
- // When shutter button is pressed, check whether the previous countdown is
- // finished. If not, cancel the previous countdown and start a new one.
- if (mUI.isCountingDown()) {
- mUI.cancelCountDown();
- }
- if (seconds > 0) {
- mUI.startCountDown(seconds, true);
+ if (mIsRecordingVideo) {
+ captureVideoSnapshot(getMainCameraId());
} else {
- if(mPostProcessor.isFilterOn() && mPostProcessor.isItBusy()) {
- warningToast("It's still busy processing previous scene mode request.");
- return;
+ String timer = mSettingsManager.getValue(SettingsManager.KEY_TIMER);
+
+ int seconds = Integer.parseInt(timer);
+ // When shutter button is pressed, check whether the previous countdown is
+ // finished. If not, cancel the previous countdown and start a new one.
+ if (mUI.isCountingDown()) {
+ mUI.cancelCountDown();
+ }
+ if (seconds > 0) {
+ mUI.startCountDown(seconds, true);
+ } else {
+ if (mPostProcessor.isFilterOn() && mPostProcessor.isItBusy()) {
+ warningToast("It's still busy processing previous scene mode request.");
+ return;
+ }
+ takePicture();
}
- takePicture();
}
}
@@ -2740,6 +2841,9 @@ public class CaptureModule implements CameraModule, PhotoController,
case SettingsManager.KEY_VIDEO_QUALITY:
updateVideoSize();
continue;
+ case SettingsManager.KEY_AUTO_VIDEOSNAP_SIZE:
+ updateVideoSnapshotSize();
+ continue;
case SettingsManager.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL:
updateTimeLapseSetting();
continue;
@@ -2881,6 +2985,17 @@ public class CaptureModule implements CameraModule, PhotoController,
return optimal;
}
+ private Size getMaxSizeWithRatio(Size[] sizes, Size reference) {
+ float ratio = (float) reference.getWidth() / reference.getHeight();
+ for (Size size: sizes) {
+ float prevRatio = (float) size.getWidth() / size.getHeight();
+ if (Math.abs(prevRatio - ratio) < 0.01) {
+ return size;
+ }
+ }
+ return sizes[0];
+ }
+
/**
* Compares two {@code Size}s based on their areas.
*/
diff --git a/src/com/android/camera/CaptureUI.java b/src/com/android/camera/CaptureUI.java
index c6576d7..f5f23fa 100644
--- a/src/com/android/camera/CaptureUI.java
+++ b/src/com/android/camera/CaptureUI.java
@@ -112,7 +112,8 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
SettingsManager.KEY_VIDEO_ENCODER,
SettingsManager.KEY_AUDIO_ENCODER,
SettingsManager.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL,
- SettingsManager.KEY_VIDEO_ROTATION
+ SettingsManager.KEY_VIDEO_ROTATION,
+ SettingsManager.KEY_AUTO_VIDEOSNAP_SIZE
};
private CameraActivity mActivity;
private View mRootView;
@@ -522,7 +523,6 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
mFrontBackSwitcher.setVisibility(View.INVISIBLE);
mFilterModeSwitcher.setVisibility(View.INVISIBLE);
mSceneModeSwitcher.setVisibility(View.INVISIBLE);
- mShutterButton.setVisibility(View.INVISIBLE);
}
public void showUIafterRecording() {
@@ -530,7 +530,6 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
mFrontBackSwitcher.setVisibility(View.VISIBLE);
mFilterModeSwitcher.setVisibility(View.VISIBLE);
mSceneModeSwitcher.setVisibility(View.VISIBLE);
- mShutterButton.setVisibility(View.VISIBLE);
}
public void hideSwitcher() {
diff --git a/src/com/android/camera/SettingsManager.java b/src/com/android/camera/SettingsManager.java
index 57dc624..37976f1 100644
--- a/src/com/android/camera/SettingsManager.java
+++ b/src/com/android/camera/SettingsManager.java
@@ -104,6 +104,7 @@ public class SettingsManager implements ListMenu.SettingsListener {
public static final String KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL =
"pref_camera2_video_time_lapse_frame_interval_key";
public static final String KEY_FACE_DETECTION = "pref_camera2_facedetection_key";
+ public static final String KEY_AUTO_VIDEOSNAP_SIZE = "pref_camera2_videosnap_key";
private static final String TAG = "SnapCam_SettingsManager";
private static SettingsManager sInstance;
@@ -730,6 +731,12 @@ public class SettingsManager implements ListMenu.SettingsListener {
return res;
}
+ public Size[] getSupportedOutputSize(int cameraId, int format) {
+ StreamConfigurationMap map = mCharacteristics.get(cameraId).get(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ return map.getOutputSizes(format);
+ }
+
public Size[] getSupportedOutputSize(int cameraId, Class cl) {
StreamConfigurationMap map = mCharacteristics.get(cameraId).get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);