diff --git a/camera/.clang-format b/camera/.clang-format
index 77b4a86..a6eb858 100644
--- a/camera/.clang-format
+++ b/camera/.clang-format
@@ -11,7 +11,7 @@ AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
-AllowShortFunctionsOnASingleLine: All
+AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
@@ -50,7 +50,7 @@ CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
-ContinuationIndentWidth: 4
+ContinuationIndentWidth: 8
Cpp11BracedListStyle: true
DerivePointerAlignment: true
DisableFormat: false
diff --git a/camera/MultiCameraApplication/AndroidManifest.xml b/camera/MultiCameraApplication/AndroidManifest.xml
index 2919c63..3be0329 100644
--- a/camera/MultiCameraApplication/AndroidManifest.xml
+++ b/camera/MultiCameraApplication/AndroidManifest.xml
@@ -1,52 +1,61 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/camera/MultiCameraApplication/java/com/intel/multicamera/AutoFitTextureView.java b/camera/MultiCameraApplication/java/com/intel/multicamera/AutoFitTextureView.java
index b3d28b9..12ce3b5 100644
--- a/camera/MultiCameraApplication/java/com/intel/multicamera/AutoFitTextureView.java
+++ b/camera/MultiCameraApplication/java/com/intel/multicamera/AutoFitTextureView.java
@@ -26,8 +26,12 @@
public class AutoFitTextureView extends TextureView {
private int mRatioWidth = 0;
private int mRatioHeight = 0;
- public AutoFitTextureView(Context context) { this(context, null); }
- public AutoFitTextureView(Context context, AttributeSet attrs) { this(context, attrs, 0); }
+ public AutoFitTextureView(Context context) {
+ this(context, null);
+ }
+ public AutoFitTextureView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
diff --git a/camera/MultiCameraApplication/java/com/intel/multicamera/BotmLeftCam.java b/camera/MultiCameraApplication/java/com/intel/multicamera/BotmLeftCam.java
index 6a05ae0..1d7459d 100644
--- a/camera/MultiCameraApplication/java/com/intel/multicamera/BotmLeftCam.java
+++ b/camera/MultiCameraApplication/java/com/intel/multicamera/BotmLeftCam.java
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 The Android Open Source Project
* Copyright (c) 2019 Intel Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,6 +23,8 @@
import android.content.*;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
+import android.graphics.Matrix;
+import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.*;
import android.hardware.camera2.params.StreamConfigurationMap;
@@ -71,14 +74,15 @@ public class BotmLeftCam {
protected CameraCaptureSession cameraCaptureSessions;
protected CaptureRequest captureRequest;
protected CaptureRequest.Builder captureRequestBuilder;
- private Size imageDimension;
+ private Size imageDimension, previewSize;
private ImageReader imageReader;
private File file;
- private static final int REQUEST_CAMERA_PERMISSION = 200;
- private final int PERMISSIONS_REQUEST_SNAPSHOT = 3;
-
private Handler mBackgroundHandler;
private HandlerThread mBackgroundThread;
+ private static final int SENSOR_ORIENTATION_DEFAULT_DEGREES = 90;
+ private static final int SENSOR_ORIENTATION_INVERSE_DEGREES = 270;
+ private static final SparseIntArray DEFAULT_ORIENTATIONS = new SparseIntArray();
+ private static final SparseIntArray INVERSE_ORIENTATIONS = new SparseIntArray();
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private SharedPreferences settings;
/**
@@ -92,6 +96,11 @@ public class BotmLeftCam {
private ContentValues mCurrentVideoValues, mCurrentPictureValues;
byte[] jpegLength;
+ /**
+ * Orientation of the camera sensor
+ */
+ private int mSensorOrientation;
+
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
@@ -151,24 +160,31 @@ public void onClick(View view) {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
// open your camera here
- openCamera();
+ openCamera(width, height);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Transform you image captured size according to the surface width and height
+ configureTransform(width, height);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
- public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ }
};
- public void openCamera() {
+ public void openCamera(int width, int height) {
CameraManager manager = (CameraManager)mActivity.getSystemService(Context.CAMERA_SERVICE);
Log.e(TAG, "is camera open");
try {
+ if (!((manager.getCameraIdList().length >= 3) &&
+ (manager.getCameraIdList().length <= 4))) {
+ Log.e(TAG, "this camera is not connected ");
+ return;
+ }
cameraId = manager.getCameraIdList()[2];
Log.e(TAG, "is camera open ID" + cameraId);
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
@@ -176,23 +192,29 @@ public void openCamera() {
characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) return;
- // Add permission for camera and let user grant the permission
- if (ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.CAMERA) !=
- PackageManager.PERMISSION_GRANTED &&
- ActivityCompat.checkSelfPermission(mActivity,
- Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
- PackageManager.PERMISSION_GRANTED &&
- ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.RECORD_AUDIO) !=
- PackageManager.PERMISSION_GRANTED) {
- ActivityCompat.requestPermissions(
- mActivity,
- new String[] {Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO,
- Manifest.permission.WRITE_EXTERNAL_STORAGE},
- REQUEST_CAMERA_PERMISSION);
- return;
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
+ String Key = SettingsActivity.SettingsFragment.getchangedPrefKey();
+
+ if (Key.compareTo("video_list") == 0) {
+ String videoQuality = settings.getString("video_list", "medium");
+
+ int quality = SettingsActivity.SettingsFragment.getVideoQuality(0, videoQuality);
+ Log.d(TAG, "Selected video quality for '" + videoQuality + "' is " + quality);
+
+ mProfile = CamcorderProfile.get(0, quality);
+ previewSize = new Size(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
+
+ configureTransform(width, height);
+ } else {
+ previewSize = SettingsActivity.SettingsFragment.sizeFromSettingString(
+ settings.getString("capture_list", "640x480"));
+ Log.d(TAG,
+ "Selected imageDimension" + previewSize.getWidth() + previewSize.getHeight());
+ configureTransform(width, height);
}
- mMediaRecorder = new MediaRecorder();
+ mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
+ configureTransform(width, height);
startBackgroundThread();
manager.openCamera(cameraId, stateCallback, null);
@@ -213,21 +235,46 @@ public void onOpened(CameraDevice camera) {
}
@Override
public void onDisconnected(CameraDevice camera) {
- cameraDevice.close();
+ Log.e(TAG, "onDisconnected");
+ closeCamera();
}
@Override
public void onError(CameraDevice camera, int error) {
- cameraDevice.close();
- cameraDevice = null;
+ Log.e(TAG, "onError");
+ closeCamera();
}
};
+ private void configureTransform(int viewWidth, int viewHeight) {
+ if (null == textureView || null == previewSize) {
+ return;
+ }
+ int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
+ Matrix matrix = new Matrix();
+ RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
+ Log.e(TAG, "configureTransform() viewWidth: " + viewWidth + " viewHeight: " + viewHeight);
+ RectF bufferRect = new RectF(0, 0, previewSize.getHeight(), previewSize.getWidth());
+ float centerX = viewRect.centerX();
+ float centerY = viewRect.centerY();
+ if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
+ bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
+ matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
+ float scale = Math.max((float)viewHeight / previewSize.getHeight(),
+ (float)viewWidth / previewSize.getWidth());
+ matrix.postScale(scale, scale, centerX, centerY);
+ matrix.postRotate(90 * (rotation - 2), centerX, centerY);
+ } else if (Surface.ROTATION_180 == rotation) {
+ matrix.postRotate(180, centerX, centerY);
+ }
+ textureView.setTransform(matrix);
+ }
+
protected void createCameraPreview() {
try {
closePreviewSession();
SurfaceTexture texture = textureView.getSurfaceTexture();
if (texture == null) return;
-
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
String Key = SettingsActivity.SettingsFragment.getchangedPrefKey();
imageDimension = SettingsActivity.SettingsFragment.sizeFromSettingString(
@@ -246,31 +293,44 @@ protected void createCameraPreview() {
Surface surface = new Surface(texture);
captureRequestBuilder =
- cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(
- Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
- @Override
- public void onConfigured(CameraCaptureSession cameraCaptureSession) {
- // The camera is already closed
- if (null == cameraDevice) {
- return;
+ Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
+ @Override
+ public void onConfigured(CameraCaptureSession cameraCaptureSession) {
+ // The camera is already closed
+ if (null == cameraDevice) {
+ return;
+ }
+ // When the session is ready, we start displaying the preview.
+ cameraCaptureSessions = cameraCaptureSession;
+ updatePreview();
}
- // When the session is ready, we start displaying the preview.
- cameraCaptureSessions = cameraCaptureSession;
- updatePreview();
- }
- @Override
- public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
- Toast.makeText(mActivity, "Configuration change", Toast.LENGTH_SHORT)
- .show();
- }
- }, null);
+ @Override
+ public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
+ Toast.makeText(mActivity, "Configuration change", Toast.LENGTH_SHORT)
+ .show();
+ }
+ }, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
+ public void releaseMedia() {
+ if (null != mMediaRecorder) {
+ try {
+ mMediaRecorder.stop();
+ } catch (IllegalStateException ex) {
+ Log.d(TAG, "Stop called before start");
+ }
+ mMediaRecorder.reset();
+ mMediaRecorder.release();
+ mMediaRecorder = null;
+ }
+ }
+
public void closeCamera() {
closePreviewSession();
if (null != cameraDevice) {
@@ -281,11 +341,7 @@ public void closeCamera() {
imageReader.close();
imageReader = null;
}
- if (null != mMediaRecorder) {
- mMediaRecorder.reset();
- mMediaRecorder.release();
- mMediaRecorder = null;
- }
+ releaseMedia();
stopBackgroundThread();
}
@@ -293,7 +349,7 @@ public void closeCamera() {
* Starts a background thread and its {@link Handler}.
*/
private void startBackgroundThread() {
- mBackgroundThread = new HandlerThread("Camera-$cameraId");
+ mBackgroundThread = new HandlerThread("Camera-3");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
@@ -329,6 +385,20 @@ protected void updatePreview() {
}
}
+ /**
+ * Retrieves the JPEG orientation from the specified screen rotation.
+ *
+ * @param rotation The screen rotation.
+ * @return The JPEG orientation (one of 0, 90, 270, and 360)
+ */
+ private int getOrientation(int rotation) {
+ // Sensor orientation is 90 for most devices, or 270 for some devices (eg. Nexus 5X)
+ // We have to take that into account and rotate JPEG properly.
+ // For devices with orientation of 90, we simply return our mapping from ORIENTATIONS.
+ // For devices with orientation of 270, we need to rotate the JPEG 180 degrees.
+ return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;
+ }
+
protected void takePicture() {
if (null == cameraDevice) {
Log.e(TAG, "cameraDevice is null");
@@ -336,32 +406,24 @@ protected void takePicture() {
}
try {
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
imageDimension = SettingsActivity.SettingsFragment.sizeFromSettingString(
- settings.getString("capture_list", "640x480"));
-
+ settings.getString("capture_list", "640x480"));
+ Log.d(TAG, "Selected imageDimension" + imageDimension.getWidth() +
+ imageDimension.getHeight());
ImageReader reader = ImageReader.newInstance(
- imageDimension.getWidth(), imageDimension.getHeight(), ImageFormat.JPEG, 1);
+ imageDimension.getWidth(), imageDimension.getHeight(), ImageFormat.JPEG, 1);
List outputSurfaces = new ArrayList(2);
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(textureView.getSurfaceTexture()));
captureRequestBuilder =
- cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+ cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureRequestBuilder.addTarget(reader.getSurface());
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE,
CameraMetadata.CONTROL_MODE_AUTO);
// Orientation
int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
- captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
-
- // Add permission for camera and let user grant the permission
- if (ActivityCompat.checkSelfPermission(mActivity,
- Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
- PackageManager.PERMISSION_GRANTED) {
- ActivityCompat.requestPermissions(
- mActivity, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
- PERMISSIONS_REQUEST_SNAPSHOT);
- return;
- }
+ captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
String fileDetails[] = Utils.generateFileDetails(Utils.MEDIA_TYPE_IMAGE);
if (fileDetails == null || fileDetails.length < 5) {
@@ -370,77 +432,78 @@ protected void takePicture() {
}
mPictureFilename = fileDetails[3];
mCurrentPictureValues =
- Utils.getContentValues(Utils.MEDIA_TYPE_IMAGE, fileDetails,
- imageDimension.getWidth(), imageDimension.getHeight());
+ Utils.getContentValues(Utils.MEDIA_TYPE_IMAGE, fileDetails,
+ imageDimension.getWidth(), imageDimension.getHeight());
file = new File(mPictureFilename);
ImageReader.OnImageAvailableListener readerListener =
- new ImageReader.OnImageAvailableListener() {
- @Override
- public void onImageAvailable(ImageReader reader) {
- Image image = null;
- try {
- image = reader.acquireLatestImage();
- ByteBuffer buffer = image.getPlanes()[0].getBuffer();
- byte[] bytes = new byte[buffer.capacity()];
- buffer.get(bytes);
- jpegLength = bytes;
- mCurrentPictureValues.put(MediaStore.Images.ImageColumns.SIZE,
- jpegLength);
-
- save(bytes);
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (image != null) {
- image.close();
+ new ImageReader.OnImageAvailableListener() {
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ Image image = null;
+ try {
+ image = reader.acquireLatestImage();
+ ByteBuffer buffer = image.getPlanes()[0].getBuffer();
+ byte[] bytes = new byte[buffer.capacity()];
+ buffer.get(bytes);
+ jpegLength = bytes;
+ mCurrentPictureValues.put(MediaStore.Images.ImageColumns.SIZE,
+ jpegLength);
+
+ save(bytes);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (image != null) {
+ image.close();
+ }
}
}
- }
- private void save(byte[] bytes) throws IOException {
- OutputStream output = null;
- try {
- output = new FileOutputStream(file);
- output.write(bytes);
- } finally {
- if (null != output) {
- output.close();
+ private void save(byte[] bytes) throws IOException {
+ OutputStream output = null;
+ try {
+ output = new FileOutputStream(file);
+ output.write(bytes);
+ } finally {
+ if (null != output) {
+ output.close();
+ }
}
}
- }
- };
+ };
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener =
- new CameraCaptureSession.CaptureCallback() {
- @Override
- public void onCaptureCompleted(CameraCaptureSession session,
- CaptureRequest request,
- TotalCaptureResult result) {
- super.onCaptureCompleted(session, request, result);
- Toast.makeText(mActivity, "Saved:" + file, Toast.LENGTH_SHORT).show();
-
- createCameraPreview();
- }
- };
+ new CameraCaptureSession.CaptureCallback() {
+ @Override
+ public void onCaptureCompleted(CameraCaptureSession session,
+ CaptureRequest request,
+ TotalCaptureResult result) {
+ super.onCaptureCompleted(session, request, result);
+ Toast.makeText(mActivity, "Saved:" + file, Toast.LENGTH_SHORT).show();
+
+ createCameraPreview();
+ }
+ };
cameraDevice.createCaptureSession(
- outputSurfaces, new CameraCaptureSession.StateCallback() {
- @Override
- public void onConfigured(CameraCaptureSession session) {
- try {
- session.capture(captureRequestBuilder.build(), captureListener,
- mBackgroundHandler);
- } catch (CameraAccessException e) {
- e.printStackTrace();
+ outputSurfaces, new CameraCaptureSession.StateCallback() {
+ @Override
+ public void onConfigured(CameraCaptureSession session) {
+ try {
+ session.capture(captureRequestBuilder.build(), captureListener,
+ mBackgroundHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
}
- }
- @Override
- public void onConfigureFailed(CameraCaptureSession session) {}
- }, mBackgroundHandler);
+ @Override
+ public void onConfigureFailed(CameraCaptureSession session) {
+ }
+ }, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
@@ -448,11 +511,18 @@ public void onConfigureFailed(CameraCaptureSession session) {}
/* Recording Start*/
private void startRecordingVideo() {
- if (null == cameraDevice || !textureView.isAvailable() || null == mProfile) {
+ if (null == cameraDevice || !textureView.isAvailable()) {
return;
}
try {
closePreviewSession();
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
+ String videoQuality = settings.getString("video_list", "medium");
+
+ int quality = SettingsActivity.SettingsFragment.getVideoQuality(0, videoQuality);
+ Log.d(TAG, "Selected video quality for '" + videoQuality + "' is " + quality);
+
+ mProfile = CamcorderProfile.get(0, quality);
setUpMediaRecorder();
SurfaceTexture texture = textureView.getSurfaceTexture();
if (texture == null) return;
@@ -507,9 +577,10 @@ private void setUpMediaRecorder() throws IOException {
if (null == mActivity) {
return;
}
+
+ mMediaRecorder = new MediaRecorder();
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
- mMediaRecorder.setProfile(mProfile);
String fileDetails[] = Utils.generateFileDetails(Utils.MEDIA_TYPE_VIDEO);
if (fileDetails == null || fileDetails.length < 5) {
@@ -518,19 +589,34 @@ private void setUpMediaRecorder() throws IOException {
}
mVideoFilename = fileDetails[3];
mCurrentVideoValues =
- Utils.getContentValues(Utils.MEDIA_TYPE_VIDEO, fileDetails, mProfile.videoFrameWidth,
- mProfile.videoFrameHeight);
+ Utils.getContentValues(Utils.MEDIA_TYPE_VIDEO, fileDetails,
+ mProfile.videoFrameWidth, mProfile.videoFrameHeight);
+ mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
/**
* set output file in media recorder
*/
mMediaRecorder.setOutputFile(mVideoFilename);
-
+ mMediaRecorder.setVideoEncodingBitRate(10000000);
+ mMediaRecorder.setVideoFrameRate(30);
+ mMediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
+ mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+ mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+
+ int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
+ switch (mSensorOrientation) {
+ case SENSOR_ORIENTATION_DEFAULT_DEGREES:
+ mMediaRecorder.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation));
+ break;
+ case SENSOR_ORIENTATION_INVERSE_DEGREES:
+ mMediaRecorder.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation));
+ break;
+ }
try {
mMediaRecorder.prepare();
} catch (IOException ex) {
Log.e(TAG, "prepare failed for " + mVideoFilename, ex);
- mMediaRecorder.reset();
+ releaseMedia();
throw new RuntimeException(ex);
}
}
@@ -546,9 +632,9 @@ private void closePreviewSession() {
private void stopRecordingVideo() {
mIsRecordingVideo = false;
TakeVideoButton.setText(R.string.record);
+
// Stop recording
- mMediaRecorder.stop();
- mMediaRecorder.reset();
+ releaseMedia();
if (null != mActivity) {
Toast.makeText(mActivity, "Video saved: " + mVideoFilename, Toast.LENGTH_SHORT).show();
diff --git a/camera/MultiCameraApplication/java/com/intel/multicamera/BotmRightCam.java b/camera/MultiCameraApplication/java/com/intel/multicamera/BotmRightCam.java
index 6fec868..3772ccd 100644
--- a/camera/MultiCameraApplication/java/com/intel/multicamera/BotmRightCam.java
+++ b/camera/MultiCameraApplication/java/com/intel/multicamera/BotmRightCam.java
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 The Android Open Source Project
* Copyright (c) 2019 Intel Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,6 +23,8 @@
import android.content.*;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
+import android.graphics.Matrix;
+import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.*;
import android.hardware.camera2.params.StreamConfigurationMap;
@@ -71,14 +74,15 @@ public class BotmRightCam {
protected CameraCaptureSession cameraCaptureSessions;
protected CaptureRequest captureRequest;
protected CaptureRequest.Builder captureRequestBuilder;
- private Size imageDimension;
+ private Size imageDimension, previewSize;
private ImageReader imageReader;
private File file;
- private static final int REQUEST_CAMERA_PERMISSION = 200;
- private final int PERMISSIONS_REQUEST_SNAPSHOT = 3;
-
private Handler mBackgroundHandler;
private HandlerThread mBackgroundThread;
+ private static final int SENSOR_ORIENTATION_DEFAULT_DEGREES = 90;
+ private static final int SENSOR_ORIENTATION_INVERSE_DEGREES = 270;
+ private static final SparseIntArray DEFAULT_ORIENTATIONS = new SparseIntArray();
+ private static final SparseIntArray INVERSE_ORIENTATIONS = new SparseIntArray();
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private SharedPreferences settings;
/**
@@ -92,6 +96,11 @@ public class BotmRightCam {
private ContentValues mCurrentVideoValues, mCurrentPictureValues;
byte[] jpegLength;
+ /**
+ * Orientation of the camera sensor
+ */
+ private int mSensorOrientation;
+
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
@@ -151,48 +160,59 @@ public void onClick(View view) {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
// open your camera here
- openCamera();
+ openCamera(width, height);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Transform you image captured size according to the surface width and height
+ configureTransform(width, height);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
- public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ }
};
- public void openCamera() {
+ public void openCamera(int width, int height) {
CameraManager manager = (CameraManager)mActivity.getSystemService(Context.CAMERA_SERVICE);
Log.e(TAG, "is camera open");
try {
+ if (manager.getCameraIdList().length != 4) {
+ Log.e(TAG, "this camera is not connected ");
+ return;
+ }
+
cameraId = manager.getCameraIdList()[3];
Log.e(TAG, "is camera open ID" + cameraId);
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map =
- characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) return;
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
+ String Key = SettingsActivity.SettingsFragment.getchangedPrefKey();
- // Add permission for camera and let user grant the permission
- if (ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.CAMERA) !=
- PackageManager.PERMISSION_GRANTED &&
- ActivityCompat.checkSelfPermission(mActivity,
- Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
- PackageManager.PERMISSION_GRANTED &&
- ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.RECORD_AUDIO) !=
- PackageManager.PERMISSION_GRANTED) {
- ActivityCompat.requestPermissions(
- mActivity,
- new String[] {Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO,
- Manifest.permission.WRITE_EXTERNAL_STORAGE},
- REQUEST_CAMERA_PERMISSION);
- return;
- }
- mMediaRecorder = new MediaRecorder();
+ if (Key.compareTo("video_list") == 0) {
+ String videoQuality = settings.getString("video_list", "medium");
+
+ int quality = SettingsActivity.SettingsFragment.getVideoQuality(0, videoQuality);
+ Log.d(TAG, "Selected video quality for '" + videoQuality + "' is " + quality);
+ mProfile = CamcorderProfile.get(0, quality);
+ previewSize = new Size(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
+
+ configureTransform(width, height);
+ } else {
+ previewSize = SettingsActivity.SettingsFragment.sizeFromSettingString(
+ settings.getString("capture_list", "640x480"));
+ Log.d(TAG,
+ "Selected imageDimension" + previewSize.getWidth() + previewSize.getHeight());
+ configureTransform(width, height);
+ }
+ mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
+ configureTransform(width, height);
startBackgroundThread();
manager.openCamera(cameraId, stateCallback, null);
@@ -218,16 +238,41 @@ public void onDisconnected(CameraDevice camera) {
}
@Override
public void onError(CameraDevice camera, int error) {
- cameraDevice.close();
- cameraDevice = null;
+ Log.e(TAG, "onError");
+ closeCamera();
}
};
+ private void configureTransform(int viewWidth, int viewHeight) {
+ if (null == textureView || null == previewSize) {
+ return;
+ }
+ int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
+ Matrix matrix = new Matrix();
+ RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
+ Log.e(TAG, "configureTransform() viewWidth: " + viewWidth + " viewHeight: " + viewHeight);
+ RectF bufferRect = new RectF(0, 0, previewSize.getHeight(), previewSize.getWidth());
+ float centerX = viewRect.centerX();
+ float centerY = viewRect.centerY();
+ if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
+ bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
+ matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
+ float scale = Math.max((float)viewHeight / previewSize.getHeight(),
+ (float)viewWidth / previewSize.getWidth());
+ matrix.postScale(scale, scale, centerX, centerY);
+ matrix.postRotate(90 * (rotation - 2), centerX, centerY);
+ } else if (Surface.ROTATION_180 == rotation) {
+ matrix.postRotate(180, centerX, centerY);
+ }
+ textureView.setTransform(matrix);
+ }
+
protected void createCameraPreview() {
try {
closePreviewSession();
SurfaceTexture texture = textureView.getSurfaceTexture();
if (texture == null) return;
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
String Key = SettingsActivity.SettingsFragment.getchangedPrefKey();
imageDimension = SettingsActivity.SettingsFragment.sizeFromSettingString(
@@ -247,31 +292,44 @@ protected void createCameraPreview() {
Surface surface = new Surface(texture);
captureRequestBuilder =
- cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(
- Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
- @Override
- public void onConfigured(CameraCaptureSession cameraCaptureSession) {
- // The camera is already closed
- if (null == cameraDevice) {
- return;
+ Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
+ @Override
+ public void onConfigured(CameraCaptureSession cameraCaptureSession) {
+ // The camera is already closed
+ if (null == cameraDevice) {
+ return;
+ }
+ // When the session is ready, we start displaying the preview.
+ cameraCaptureSessions = cameraCaptureSession;
+ updatePreview();
}
- // When the session is ready, we start displaying the preview.
- cameraCaptureSessions = cameraCaptureSession;
- updatePreview();
- }
- @Override
- public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
- Toast.makeText(mActivity, "Configuration change", Toast.LENGTH_SHORT)
- .show();
- }
- }, null);
+ @Override
+ public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
+ Toast.makeText(mActivity, "Configuration change", Toast.LENGTH_SHORT)
+ .show();
+ }
+ }, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
+ public void releaseMedia() {
+ if (null != mMediaRecorder) {
+ try {
+ mMediaRecorder.stop();
+ } catch (IllegalStateException ex) {
+ Log.d(TAG, "Stop called before start");
+ }
+ mMediaRecorder.reset();
+ mMediaRecorder.release();
+ mMediaRecorder = null;
+ }
+ }
+
public void closeCamera() {
closePreviewSession();
if (null != cameraDevice) {
@@ -282,11 +340,7 @@ public void closeCamera() {
imageReader.close();
imageReader = null;
}
- if (null != mMediaRecorder) {
- mMediaRecorder.reset();
- mMediaRecorder.release();
- mMediaRecorder = null;
- }
+ releaseMedia();
stopBackgroundThread();
}
@@ -294,7 +348,7 @@ public void closeCamera() {
* Starts a background thread and its {@link Handler}.
*/
private void startBackgroundThread() {
- mBackgroundThread = new HandlerThread("Camera-$cameraId");
+ mBackgroundThread = new HandlerThread("Camera-4");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
@@ -330,6 +384,20 @@ protected void updatePreview() {
}
}
+ /**
+ * Retrieves the JPEG orientation from the specified screen rotation.
+ *
+ * @param rotation The screen rotation.
+ * @return The JPEG orientation (one of 0, 90, 270, and 360)
+ */
+ private int getOrientation(int rotation) {
+ // Sensor orientation is 90 for most devices, or 270 for some devices (eg. Nexus 5X)
+ // We have to take that into account and rotate JPEG properly.
+ // For devices with orientation of 90, we simply return our mapping from ORIENTATIONS.
+ // For devices with orientation of 270, we need to rotate the JPEG 180 degrees.
+ return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;
+ }
+
protected void takePicture() {
if (null == cameraDevice) {
Log.e(TAG, "cameraDevice is null");
@@ -337,32 +405,24 @@ protected void takePicture() {
}
try {
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
imageDimension = SettingsActivity.SettingsFragment.sizeFromSettingString(
- settings.getString("capture_list", "640x480"));
-
+ settings.getString("capture_list", "640x480"));
+ Log.d(TAG, "Selected imageDimension" + imageDimension.getWidth() +
+ imageDimension.getHeight());
ImageReader reader = ImageReader.newInstance(
- imageDimension.getWidth(), imageDimension.getHeight(), ImageFormat.JPEG, 1);
+ imageDimension.getWidth(), imageDimension.getHeight(), ImageFormat.JPEG, 1);
List outputSurfaces = new ArrayList(2);
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(textureView.getSurfaceTexture()));
captureRequestBuilder =
- cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+ cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureRequestBuilder.addTarget(reader.getSurface());
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE,
CameraMetadata.CONTROL_MODE_AUTO);
// Orientation
int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
- captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
-
- // Add permission for camera and let user grant the permission
- if (ActivityCompat.checkSelfPermission(mActivity,
- Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
- PackageManager.PERMISSION_GRANTED) {
- ActivityCompat.requestPermissions(
- mActivity, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
- PERMISSIONS_REQUEST_SNAPSHOT);
- return;
- }
+ captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
String fileDetails[] = Utils.generateFileDetails(Utils.MEDIA_TYPE_IMAGE);
if (fileDetails == null || fileDetails.length < 5) {
@@ -371,77 +431,78 @@ protected void takePicture() {
}
mPictureFilename = fileDetails[3];
mCurrentPictureValues =
- Utils.getContentValues(Utils.MEDIA_TYPE_IMAGE, fileDetails,
- imageDimension.getWidth(), imageDimension.getHeight());
+ Utils.getContentValues(Utils.MEDIA_TYPE_IMAGE, fileDetails,
+ imageDimension.getWidth(), imageDimension.getHeight());
file = new File(mPictureFilename);
ImageReader.OnImageAvailableListener readerListener =
- new ImageReader.OnImageAvailableListener() {
- @Override
- public void onImageAvailable(ImageReader reader) {
- Image image = null;
- try {
- image = reader.acquireLatestImage();
- ByteBuffer buffer = image.getPlanes()[0].getBuffer();
- byte[] bytes = new byte[buffer.capacity()];
- buffer.get(bytes);
- jpegLength = bytes;
- mCurrentPictureValues.put(MediaStore.Images.ImageColumns.SIZE,
- jpegLength);
-
- save(bytes);
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (image != null) {
- image.close();
+ new ImageReader.OnImageAvailableListener() {
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ Image image = null;
+ try {
+ image = reader.acquireLatestImage();
+ ByteBuffer buffer = image.getPlanes()[0].getBuffer();
+ byte[] bytes = new byte[buffer.capacity()];
+ buffer.get(bytes);
+ jpegLength = bytes;
+ mCurrentPictureValues.put(MediaStore.Images.ImageColumns.SIZE,
+ jpegLength);
+
+ save(bytes);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (image != null) {
+ image.close();
+ }
}
}
- }
- private void save(byte[] bytes) throws IOException {
- OutputStream output = null;
- try {
- output = new FileOutputStream(file);
- output.write(bytes);
- } finally {
- if (null != output) {
- output.close();
+ private void save(byte[] bytes) throws IOException {
+ OutputStream output = null;
+ try {
+ output = new FileOutputStream(file);
+ output.write(bytes);
+ } finally {
+ if (null != output) {
+ output.close();
+ }
}
}
- }
- };
+ };
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener =
- new CameraCaptureSession.CaptureCallback() {
- @Override
- public void onCaptureCompleted(CameraCaptureSession session,
- CaptureRequest request,
- TotalCaptureResult result) {
- super.onCaptureCompleted(session, request, result);
- Toast.makeText(mActivity, "Saved:" + file, Toast.LENGTH_SHORT).show();
-
- createCameraPreview();
- }
- };
+ new CameraCaptureSession.CaptureCallback() {
+ @Override
+ public void onCaptureCompleted(CameraCaptureSession session,
+ CaptureRequest request,
+ TotalCaptureResult result) {
+ super.onCaptureCompleted(session, request, result);
+ Toast.makeText(mActivity, "Saved:" + file, Toast.LENGTH_SHORT).show();
+
+ createCameraPreview();
+ }
+ };
cameraDevice.createCaptureSession(
- outputSurfaces, new CameraCaptureSession.StateCallback() {
- @Override
- public void onConfigured(CameraCaptureSession session) {
- try {
- session.capture(captureRequestBuilder.build(), captureListener,
- mBackgroundHandler);
- } catch (CameraAccessException e) {
- e.printStackTrace();
+ outputSurfaces, new CameraCaptureSession.StateCallback() {
+ @Override
+ public void onConfigured(CameraCaptureSession session) {
+ try {
+ session.capture(captureRequestBuilder.build(), captureListener,
+ mBackgroundHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
}
- }
- @Override
- public void onConfigureFailed(CameraCaptureSession session) {}
- }, mBackgroundHandler);
+ @Override
+ public void onConfigureFailed(CameraCaptureSession session) {
+ }
+ }, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
@@ -449,11 +510,18 @@ public void onConfigureFailed(CameraCaptureSession session) {}
/* Recording Start*/
private void startRecordingVideo() {
- if (null == cameraDevice || !textureView.isAvailable() || null == mProfile) {
+ if (null == cameraDevice || !textureView.isAvailable()) {
return;
}
try {
closePreviewSession();
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
+ String videoQuality = settings.getString("video_list", "medium");
+
+ int quality = SettingsActivity.SettingsFragment.getVideoQuality(0, videoQuality);
+ Log.d(TAG, "Selected video quality for '" + videoQuality + "' is " + quality);
+
+ mProfile = CamcorderProfile.get(0, quality);
setUpMediaRecorder();
SurfaceTexture texture = textureView.getSurfaceTexture();
if (texture == null) return;
@@ -508,9 +576,10 @@ private void setUpMediaRecorder() throws IOException {
if (null == mActivity) {
return;
}
+
+ mMediaRecorder = new MediaRecorder();
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
- mMediaRecorder.setProfile(mProfile);
String fileDetails[] = Utils.generateFileDetails(Utils.MEDIA_TYPE_VIDEO);
if (fileDetails == null || fileDetails.length < 5) {
@@ -519,19 +588,34 @@ private void setUpMediaRecorder() throws IOException {
}
mVideoFilename = fileDetails[3];
mCurrentVideoValues =
- Utils.getContentValues(Utils.MEDIA_TYPE_VIDEO, fileDetails, mProfile.videoFrameWidth,
- mProfile.videoFrameHeight);
+ Utils.getContentValues(Utils.MEDIA_TYPE_VIDEO, fileDetails,
+ mProfile.videoFrameWidth, mProfile.videoFrameHeight);
+ mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
/**
* set output file in media recorder
*/
mMediaRecorder.setOutputFile(mVideoFilename);
-
+ mMediaRecorder.setVideoEncodingBitRate(10000000);
+ mMediaRecorder.setVideoFrameRate(30);
+ mMediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
+ mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+ mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+
+ int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
+ switch (mSensorOrientation) {
+ case SENSOR_ORIENTATION_DEFAULT_DEGREES:
+ mMediaRecorder.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation));
+ break;
+ case SENSOR_ORIENTATION_INVERSE_DEGREES:
+ mMediaRecorder.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation));
+ break;
+ }
try {
mMediaRecorder.prepare();
} catch (IOException ex) {
Log.e(TAG, "prepare failed for " + mVideoFilename, ex);
- mMediaRecorder.reset();
+ releaseMedia();
throw new RuntimeException(ex);
}
}
@@ -547,9 +631,9 @@ private void closePreviewSession() {
private void stopRecordingVideo() {
mIsRecordingVideo = false;
TakeVideoButton.setText(R.string.record);
+
// Stop recording
- mMediaRecorder.stop();
- mMediaRecorder.reset();
+ releaseMedia();
if (null != mActivity) {
Toast.makeText(mActivity, "Video saved: " + mVideoFilename, Toast.LENGTH_SHORT).show();
diff --git a/camera/MultiCameraApplication/java/com/intel/multicamera/MainActivity.java b/camera/MultiCameraApplication/java/com/intel/multicamera/MainActivity.java
index 30a040b..1b85b06 100644
--- a/camera/MultiCameraApplication/java/com/intel/multicamera/MainActivity.java
+++ b/camera/MultiCameraApplication/java/com/intel/multicamera/MainActivity.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 The Android Open Source Project
* Copyright (c) 2019 Intel Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +17,7 @@
package com.intel.multicamera;
+import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -34,6 +36,7 @@
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
+import androidx.core.app.ActivityCompat;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@@ -41,17 +44,19 @@ public class MainActivity extends AppCompatActivity {
* An {@link AutoFitTextureView} for camera preview.
*/
private AutoFitTextureView mTopLeftCam_textureView, mTopRightCam_textureView,
- mBotmLeftCam_textureView, mBotmRightCam_textureView;
+ mBotmLeftCam_textureView, mBotmRightCam_textureView;
private Button mTopLeftCam_PictureButton, mTopRightCam_PictureButton,
- mBotmLeftCam_PictureButton, mBotmRightCam_PictureButton, mTopLeftCam_RecordButton,
- mTopRightCam_RecordButton, mBotmLeftCam_RecordButton, mBotmRightCam_RecordButton;
+ mBotmLeftCam_PictureButton, mBotmRightCam_PictureButton, mTopLeftCam_RecordButton,
+ mTopRightCam_RecordButton, mBotmLeftCam_RecordButton, mBotmRightCam_RecordButton;
private int numOfCameras;
private static final int REQUEST_CAMERA_PERMISSION = 200;
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private FrameLayout frameView0, frameView1, frameView2, frameView3;
+ private boolean mHasCriticalPermissions = false;
+
TopLeftCam mTopLeftCam;
TopRightCam mTopRightCam;
BotmLeftCam mBotmLeftCam;
@@ -71,12 +76,19 @@ protected void onCreate(Bundle savedInstanceState) {
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
+ checkPermissions();
+ if (!mHasCriticalPermissions) {
+ Log.v(TAG, "onCreate: Missing critical permissions.");
+ finish();
+ return;
+ }
+
setVisibilityFrameLayout();
}
public void Open_TopLeftCam() {
mTopLeftCam_textureView = findViewById(R.id.textureview0);
- assert mTopLeftCam_textureView != null;
+ if (mTopLeftCam_textureView == null) return;
mTopLeftCam_PictureButton = findViewById(R.id.Picture0);
mTopLeftCam_RecordButton = findViewById(R.id.Record0);
@@ -92,7 +104,7 @@ else if (isImageCaptureIntent())
public void Open_TopRightCam() {
mTopRightCam_textureView = findViewById(R.id.textureview1);
- assert mTopRightCam_textureView != null;
+ if (mTopRightCam_textureView == null) return;
mTopRightCam_PictureButton = findViewById(R.id.Picture1);
mTopRightCam_RecordButton = findViewById(R.id.Record1);
@@ -103,7 +115,7 @@ public void Open_TopRightCam() {
public void Open_BotmLeftCam() {
mBotmLeftCam_textureView = findViewById(R.id.textureview2);
- assert mTopRightCam_textureView != null;
+ if (mBotmLeftCam_textureView == null) return;
mBotmLeftCam_PictureButton = findViewById(R.id.Picture2);
mBotmLeftCam_RecordButton = findViewById(R.id.Record2);
@@ -114,7 +126,7 @@ public void Open_BotmLeftCam() {
public void Open_BotmRightCam() {
mBotmRightCam_textureView = findViewById(R.id.textureview3);
- assert mTopRightCam_textureView != null;
+ if (mBotmRightCam_textureView == null) return;
mBotmRightCam_PictureButton = findViewById(R.id.Picture3);
mBotmRightCam_RecordButton = findViewById(R.id.Record3);
@@ -144,7 +156,7 @@ public void setVisibilityFrameLayout() {
numOfCameras = manager.getCameraIdList().length;
// if (numCameras != "") { numOfCameras = Integer.parseInt(numCameras); }
Log.d(TAG, "onCreate Inside openCamera() Total Cameras: " +
- manager.getCameraIdList().length);
+ manager.getCameraIdList().length);
if (numOfCameras == 1) {
frameView1.setVisibility(FrameLayout.INVISIBLE);
@@ -184,11 +196,10 @@ public void onRequestPermissionsResult(int requestCode, String[] permissions,
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
// close the app
- Toast
- .makeText(MainActivity.this,
- "Sorry!!!, you can't use this app without granting permission",
- Toast.LENGTH_LONG)
- .show();
+ Toast.makeText(MainActivity.this,
+ "Sorry!!!, you can't use this app without granting permission",
+ Toast.LENGTH_LONG)
+ .show();
finish();
}
}
@@ -200,26 +211,121 @@ private void manageTopLeftCam() {
frameView0.setVisibility(FrameLayout.VISIBLE);
} else if (mTopLeftCam_textureView == null) {
mTopLeftCam_textureView = findViewById(R.id.textureview0);
- assert mTopLeftCam_textureView != null;
+ if (mTopLeftCam_textureView == null) return;
}
if (mTopLeftCam_textureView.isAvailable()) {
frameView0.setVisibility(FrameLayout.VISIBLE);
- mTopLeftCam.openCamera();
+ mTopLeftCam.openCamera(mTopLeftCam_textureView.getWidth(),
+ mTopLeftCam_textureView.getHeight());
} else {
mTopLeftCam_textureView.setSurfaceTextureListener(mTopLeftCam.textureListener);
}
}
+ private void manageTopRightCam() {
+ if (mTopRightCam == null) {
+ Open_TopRightCam();
+ frameView1.setVisibility(FrameLayout.VISIBLE);
+
+ } else if (mTopRightCam_textureView == null) {
+ mTopRightCam_textureView = findViewById(R.id.textureview1);
+ if (mTopRightCam_textureView == null) return;
+ }
+
+ if (mTopRightCam_textureView.isAvailable()) {
+ frameView1.setVisibility(FrameLayout.VISIBLE);
+ mTopRightCam.openCamera(mTopRightCam_textureView.getWidth(),
+ mTopRightCam_textureView.getHeight());
+ } else {
+ mTopRightCam_textureView.setSurfaceTextureListener(mTopRightCam.textureListener);
+ }
+ }
+
+ private void manageBotmLeftCam() {
+ if (mBotmLeftCam == null) {
+ Open_BotmLeftCam();
+ frameView2.setVisibility(FrameLayout.VISIBLE);
+
+ } else if (mBotmLeftCam_textureView == null) {
+ mBotmLeftCam_textureView = findViewById(R.id.textureview2);
+ if (mBotmLeftCam_textureView == null) return;
+ }
+
+ if (mBotmLeftCam_textureView.isAvailable()) {
+ frameView2.setVisibility(FrameLayout.VISIBLE);
+ mBotmLeftCam.openCamera(mBotmLeftCam_textureView.getWidth(),
+ mBotmLeftCam_textureView.getHeight());
+ } else {
+ mBotmLeftCam_textureView.setSurfaceTextureListener(mBotmLeftCam.textureListener);
+ }
+ }
+
+ private void manageBotmRightCam() {
+ if (mBotmRightCam == null) {
+ Open_BotmRightCam();
+ frameView3.setVisibility(FrameLayout.VISIBLE);
+
+ } else if (mBotmRightCam_textureView == null) {
+ mBotmRightCam_textureView = findViewById(R.id.textureview3);
+ if (mBotmRightCam_textureView == null) return;
+ }
+
+ if (mBotmRightCam_textureView.isAvailable()) {
+ frameView3.setVisibility(FrameLayout.VISIBLE);
+ mBotmRightCam.openCamera(mBotmRightCam_textureView.getWidth(),
+ mBotmRightCam_textureView.getHeight());
+ } else {
+ mBotmRightCam_textureView.setSurfaceTextureListener(mBotmRightCam.textureListener);
+ }
+ }
+
+ /**
+ * Checks if any of the needed Android runtime permissions are missing.
+ * If they are, then launch the permissions activity under one of the following conditions:
+ * a) The permissions dialogs have not run yet. We will ask for permission only once.
+ * b) If the missing permissions are critical to the app running, we will display a fatal error
+ * dialog. Critical permissions are: camera, microphone and storage. The app cannot run without
+ * them. Non-critical permission is location.
+ */
+ private void checkPermissions() {
+ if (ActivityCompat.checkSelfPermission(getApplicationContext(),
+ Manifest.permission.CAMERA) ==
+ PackageManager.PERMISSION_GRANTED &&
+ ActivityCompat.checkSelfPermission(getApplicationContext(),
+ Manifest.permission.RECORD_AUDIO) ==
+ PackageManager.PERMISSION_GRANTED &&
+ ActivityCompat.checkSelfPermission(getApplicationContext(),
+ Manifest.permission.READ_EXTERNAL_STORAGE) ==
+ PackageManager.PERMISSION_GRANTED) {
+ mHasCriticalPermissions = true;
+ } else {
+ mHasCriticalPermissions = false;
+ }
+
+ if (!mHasCriticalPermissions) {
+ Intent intent = new Intent(this, PermissionsActivity.class);
+ startActivity(intent);
+ finish();
+ }
+ }
+
@Override
protected void onResume() {
super.onResume();
Log.e(TAG, "onResume");
+ checkPermissions();
+ if (!mHasCriticalPermissions) {
+ Log.v(TAG, "onResume: Missing critical permissions.");
+ finish();
+ return;
+ }
+
CameraManager manager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);
try {
numOfCameras = manager.getCameraIdList().length;
- Log.d(TAG, "Total Cameras: " + manager.getCameraIdList().length);
+ Log.d(TAG, "onResume Total Cameras: " + manager.getCameraIdList().length);
} catch (CameraAccessException e) {
e.printStackTrace();
}
@@ -227,17 +333,17 @@ protected void onResume() {
if (numOfCameras == 1) {
manageTopLeftCam();
} else if (numOfCameras == 2) {
- if (mTopLeftCam_textureView.isAvailable()) {
- mTopLeftCam.openCamera();
- } else {
- mTopLeftCam_textureView.setSurfaceTextureListener(mTopLeftCam.textureListener);
- }
-
- if (mTopRightCam_textureView.isAvailable()) {
- mTopRightCam.openCamera();
- } else {
- mTopRightCam_textureView.setSurfaceTextureListener(mTopRightCam.textureListener);
- }
+ manageTopLeftCam();
+ manageTopRightCam();
+ } else if (numOfCameras == 3) {
+ manageTopLeftCam();
+ manageBotmLeftCam();
+ manageTopRightCam();
+ } else if (numOfCameras == 4) {
+ manageTopLeftCam();
+ manageTopRightCam();
+ manageBotmLeftCam();
+ manageBotmRightCam();
} else {
Log.d(TAG, "onResume No CAMERA CONNECTED");
frameView0.setVisibility(FrameLayout.INVISIBLE);
diff --git a/camera/MultiCameraApplication/java/com/intel/multicamera/PermissionsActivity.java b/camera/MultiCameraApplication/java/com/intel/multicamera/PermissionsActivity.java
new file mode 100644
index 0000000..d790051
--- /dev/null
+++ b/camera/MultiCameraApplication/java/com/intel/multicamera/PermissionsActivity.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.multicamera;
+
+import android.Manifest;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.*;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Window;
+import android.view.WindowManager;
+import androidx.core.app.ActivityCompat;
+import androidx.preference.PreferenceManager;
+
+/**
+ * Activity that shows permissions request dialogs and handles lack of critical permissions.
+ */
+public class PermissionsActivity extends QuickActivity {
+ private String TAG = "PermissionsActivity";
+
+ private static int PERMISSION_REQUEST_CODE = 1;
+ private static int RESULT_CODE_OK = 1;
+ private static int RESULT_CODE_FAILED = 2;
+
+ private int mIndexPermissionRequestCamera;
+ private int mIndexPermissionRequestMicrophone;
+ private int mIndexPermissionRequestLocation;
+ private int mIndexPermissionRequestStorage;
+ private boolean mShouldRequestCameraPermission;
+ private boolean mShouldRequestMicrophonePermission;
+ private boolean mShouldRequestLocationPermission;
+ private boolean mShouldRequestStoragePermission;
+ private int mNumPermissionsToRequest;
+ private boolean mFlagHasCameraPermission;
+ private boolean mFlagHasMicrophonePermission;
+ private boolean mFlagHasStoragePermission;
+
+ /**
+ * Close activity when secure app passes lock screen or screen turns
+ * off.
+
+ private final BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.v(TAG, "received intent, finishing: " + intent.getAction());
+ finish();
+ }
+ };
+ */
+
+ @Override
+ protected void onCreateTasks(Bundle savedInstanceState) {
+ setContentView(R.layout.permissions);
+
+ // Filter for screen off so that we can finish permissions activity
+ // when screen is off.
+ // IntentFilter filter_screen_off = new IntentFilter(Intent.ACTION_SCREEN_OFF);
+ // registerReceiver(mShutdownReceiver, filter_screen_off);
+
+ Window win = getWindow();
+ win.clearFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+ }
+
+ @Override
+ protected void onResumeTasks() {
+ mNumPermissionsToRequest = 0;
+ checkPermissions();
+ }
+
+ @Override
+ protected void onDestroyTasks() {
+ Log.v(TAG, "onDestroy: unregistering receivers");
+
+ // unregisterReceiver(mShutdownReceiver);
+ }
+
+ /**
+ * Package private conversion method to turn String storage format into
+ * booleans.
+ *
+ * @param value String to be converted to boolean
+ * @return boolean value of stored String
+ */
+ public boolean convertToBoolean(String value) {
+ boolean ret = false;
+
+ if (value.compareTo("false") == 0) {
+ ret = false;
+ Log.d(TAG, "####FALSE");
+
+ } else if (value.compareTo("true") == 0) {
+ Log.d(TAG, "####TRUE");
+ ret = true;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Retrieve a setting's value as a String, manually specifiying
+ * a default value.
+ */
+ public String getString(String key, String defaultValue) {
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
+ try {
+ return preferences.getString(key, defaultValue);
+ } catch (ClassCastException e) {
+ Log.w(TAG, "existing preference with invalid type, removing and returning default", e);
+ preferences.edit().remove(key).apply();
+ return defaultValue;
+ }
+ }
+
+ private void checkPermissions() {
+ if (ActivityCompat.checkSelfPermission(getApplicationContext(),
+ Manifest.permission.CAMERA) !=
+ PackageManager.PERMISSION_GRANTED) {
+ mNumPermissionsToRequest++;
+ mShouldRequestCameraPermission = true;
+ } else {
+ mFlagHasCameraPermission = true;
+ }
+
+ if (ActivityCompat.checkSelfPermission(getApplicationContext(),
+ Manifest.permission.RECORD_AUDIO) !=
+ PackageManager.PERMISSION_GRANTED) {
+ mNumPermissionsToRequest++;
+ mShouldRequestMicrophonePermission = true;
+ } else {
+ mFlagHasMicrophonePermission = true;
+ }
+
+ if (ActivityCompat.checkSelfPermission(getApplicationContext(),
+ Manifest.permission.READ_EXTERNAL_STORAGE) !=
+ PackageManager.PERMISSION_GRANTED) {
+ mNumPermissionsToRequest++;
+ mShouldRequestStoragePermission = true;
+ } else {
+ mFlagHasStoragePermission = true;
+ }
+
+ if (mNumPermissionsToRequest != 0) {
+ if (!convertToBoolean(getString("pref_has_seen_permissions_dialogs", "false"))) {
+ buildPermissionsRequest();
+ } else {
+ // Permissions dialog has already been shown, or we're on
+ // lockscreen, and we're still missing permissions.
+ handlePermissionsFailure();
+ }
+ } else {
+ handlePermissionsSuccess();
+ }
+ }
+
+ private void buildPermissionsRequest() {
+ String[] permissionsToRequest = new String[mNumPermissionsToRequest];
+ int permissionsRequestIndex = 0;
+
+ if (mShouldRequestCameraPermission) {
+ permissionsToRequest[permissionsRequestIndex] = Manifest.permission.CAMERA;
+ mIndexPermissionRequestCamera = permissionsRequestIndex;
+ permissionsRequestIndex++;
+ }
+ if (mShouldRequestMicrophonePermission) {
+ permissionsToRequest[permissionsRequestIndex] = Manifest.permission.RECORD_AUDIO;
+ mIndexPermissionRequestMicrophone = permissionsRequestIndex;
+ permissionsRequestIndex++;
+ }
+ if (mShouldRequestStoragePermission) {
+ permissionsToRequest[permissionsRequestIndex] =
+ Manifest.permission.WRITE_EXTERNAL_STORAGE;
+ mIndexPermissionRequestStorage = permissionsRequestIndex;
+ permissionsRequestIndex++;
+ }
+
+ Log.v(TAG, "requestPermissions count: " + permissionsToRequest.length);
+ requestPermissions(permissionsToRequest, PERMISSION_REQUEST_CODE);
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String permissions[],
+ int[] grantResults) {
+ Log.v(TAG, "onPermissionsResult counts: " + permissions.length + ":" + grantResults.length);
+
+ SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
+ settings.edit().putString("pref_has_seen_permissions_dialogs", "true").apply();
+
+ if (mShouldRequestCameraPermission) {
+ if (grantResults.length > 0 &&
+ grantResults[mIndexPermissionRequestCamera] == PackageManager.PERMISSION_GRANTED) {
+ mFlagHasCameraPermission = true;
+ } else {
+ handlePermissionsFailure();
+ }
+ }
+ if (mShouldRequestMicrophonePermission) {
+ if (grantResults.length > 0 && grantResults[mIndexPermissionRequestMicrophone] ==
+ PackageManager.PERMISSION_GRANTED) {
+ mFlagHasMicrophonePermission = true;
+ } else {
+ handlePermissionsFailure();
+ }
+ }
+ if (mShouldRequestStoragePermission) {
+ if (grantResults.length > 0 &&
+ grantResults[mIndexPermissionRequestStorage] == PackageManager.PERMISSION_GRANTED) {
+ mFlagHasStoragePermission = true;
+ } else {
+ handlePermissionsFailure();
+ }
+ }
+
+ if (mFlagHasCameraPermission && mFlagHasMicrophonePermission && mFlagHasStoragePermission) {
+ handlePermissionsSuccess();
+ } else {
+ // Permissions dialog has already been shown
+ // and we're still missing permissions.
+ handlePermissionsFailure();
+ }
+ }
+
+ private void handlePermissionsSuccess() {
+ Intent intent = new Intent(this, MainActivity.class);
+ startActivity(intent);
+ finish();
+ }
+
+ private void handlePermissionsFailure() {
+ new AlertDialog.Builder(this)
+ .setTitle(getResources().getString(R.string.camera_error_title))
+ .setMessage(getResources().getString(R.string.error_permissions))
+ .setCancelable(false)
+ .setOnKeyListener(new Dialog.OnKeyListener() {
+ @Override
+ public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ finish();
+ }
+ return true;
+ }
+ })
+ .setNegativeButton(getResources().getString(R.string.dialog_dismiss),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ })
+ .show();
+ }
+}
diff --git a/camera/MultiCameraApplication/java/com/intel/multicamera/QuickActivity.java b/camera/MultiCameraApplication/java/com/intel/multicamera/QuickActivity.java
new file mode 100644
index 0000000..b839edb
--- /dev/null
+++ b/camera/MultiCameraApplication/java/com/intel/multicamera/QuickActivity.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intel.multicamera;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.util.Log;
+
+/**
+ * Workaround for lockscreen double-onResume() bug:
+ *
+ * We track 3 startup situations:
+ *
+ * - Normal startup -- e.g. from GEL.
+ * - Secure lock screen startup -- e.g. with a keycode.
+ * - Non-secure lock screen startup -- e.g. with just a swipe.
+ *
+ * The KeyguardManager service can be queried to determine which state we are in.
+ * If started from the lock screen, the activity may be quickly started,
+ * resumed, paused, stopped, and then started and resumed again. This is
+ * problematic for launch time from the lock screen because we typically open the
+ * camera in onResume() and close it in onPause(). These camera operations take
+ * a long time to complete. To workaround it, this class filters out
+ * high-frequency onResume()->onPause() sequences if the KeyguardManager
+ * indicates that we have started from the lock screen.
+ *
+ *
+ * Subclasses should override the appropriate on[Create|Start...]Tasks() method
+ * in place of the original.
+ *
+ *
+ * Sequences of onResume() followed quickly by onPause(), when the activity is
+ * started from a lockscreen will result in a quick no-op.
+ *
+ */
+public abstract class QuickActivity extends Activity {
+ private String TAG = "QuickActivity";
+
+ /** onResume tasks delay from secure lockscreen. */
+ private static final long ON_RESUME_DELAY_SECURE_MILLIS = 30;
+ /** onResume tasks delay from non-secure lockscreen. */
+ private static final long ON_RESUME_DELAY_NON_SECURE_MILLIS = 15;
+
+ /** A reference to the main handler on which to run lifecycle methods. */
+ private Handler mMainHandler;
+
+ /**
+ * True if onResume tasks have been skipped, and made false again once they
+ * are executed within the onResume() method or from a delayed Runnable.
+ */
+ private boolean mSkippedFirstOnResume = false;
+
+ /** When application execution started in SystemClock.elapsedRealtimeNanos(). */
+ protected long mExecutionStartNanoTime = 0;
+ /** Was this session started with onCreate(). */
+ protected boolean mStartupOnCreate = false;
+
+ /**
+ * A runnable for deferring tasks to be performed in onResume() if starting
+ * from the lockscreen.
+ */
+ private final Runnable mOnResumeTasks = new Runnable() {
+ @Override
+ public void run() {
+ if (mSkippedFirstOnResume) {
+ Log.v(TAG, "delayed Runnable --> onResumeTasks()");
+ // Doing the tasks, can set to false.
+ mSkippedFirstOnResume = false;
+ onResumeTasks();
+ }
+ }
+ };
+
+ @Override
+ protected final void onNewIntent(Intent intent) {
+ logLifecycle("onNewIntent", true);
+ Log.v(TAG, "Intent Action = " + intent.getAction());
+ setIntent(intent);
+ super.onNewIntent(intent);
+ onNewIntentTasks(intent);
+ logLifecycle("onNewIntent", false);
+ }
+
+ @Override
+ protected final void onCreate(Bundle bundle) {
+ mExecutionStartNanoTime = SystemClock.elapsedRealtimeNanos();
+ logLifecycle("onCreate", true);
+ mStartupOnCreate = true;
+ super.onCreate(bundle);
+ mMainHandler = new Handler(getMainLooper());
+ onCreateTasks(bundle);
+ logLifecycle("onCreate", false);
+ }
+
+ @Override
+ protected final void onStart() {
+ logLifecycle("onStart", true);
+ onStartTasks();
+ super.onStart();
+ logLifecycle("onStart", false);
+ }
+
+ @Override
+ protected final void onResume() {
+ logLifecycle("onResume", true);
+
+ // For lockscreen launch, there are two possible flows:
+ // 1. onPause() does not occur before mOnResumeTasks is executed:
+ // Runnable mOnResumeTasks sets mSkippedFirstOnResume to false
+ // 2. onPause() occurs within ON_RESUME_DELAY_*_MILLIS:
+ // a. Runnable mOnResumeTasks is removed
+ // b. onPauseTasks() is skipped, mSkippedFirstOnResume remains true
+ // c. next onResume() will immediately execute onResumeTasks()
+ // and set mSkippedFirstOnResume to false
+
+ mMainHandler.removeCallbacks(mOnResumeTasks);
+ if (mSkippedFirstOnResume == false) {
+ long delay = mSkippedFirstOnResume ? ON_RESUME_DELAY_SECURE_MILLIS
+ : ON_RESUME_DELAY_NON_SECURE_MILLIS;
+ // Skipping onResumeTasks; set to true.
+ mSkippedFirstOnResume = true;
+ Log.v(TAG, "onResume() --> postDelayed(mOnResumeTasks," + delay + ")");
+ mMainHandler.postDelayed(mOnResumeTasks, delay);
+ } else {
+ Log.v(TAG, "onResume --> onResumeTasks()");
+ // Doing the tasks, can set to false.
+ mSkippedFirstOnResume = false;
+ onResumeTasks();
+ }
+ super.onResume();
+ logLifecycle("onResume", false);
+ }
+
+ @Override
+ protected final void onPause() {
+ logLifecycle("onPause", true);
+ mMainHandler.removeCallbacks(mOnResumeTasks);
+ // Only run onPauseTasks if we have not skipped onResumeTasks in a
+ // first call to onResume. If we did skip onResumeTasks (note: we
+ // just killed any delayed Runnable), we also skip onPauseTasks to
+ // adhere to lifecycle state machine.
+ if (mSkippedFirstOnResume == false) {
+ Log.v(TAG, "onPause --> onPauseTasks()");
+ onPauseTasks();
+ }
+ super.onPause();
+ mStartupOnCreate = false;
+ logLifecycle("onPause", false);
+ }
+
+ @Override
+ protected final void onStop() {
+ if (isChangingConfigurations()) {
+ Log.v(TAG, "changing configurations");
+ }
+ logLifecycle("onStop", true);
+ onStopTasks();
+ super.onStop();
+ logLifecycle("onStop", false);
+ }
+
+ @Override
+ protected final void onRestart() {
+ logLifecycle("onRestart", true);
+ super.onRestart();
+ // TODO Support onRestartTasks() and handle the workaround for that too.
+ logLifecycle("onRestart", false);
+ }
+
+ @Override
+ protected final void onDestroy() {
+ logLifecycle("onDestroy", true);
+ onDestroyTasks();
+ super.onDestroy();
+ logLifecycle("onDestroy", false);
+ }
+
+ private void logLifecycle(String methodName, boolean start) {
+ String prefix = start ? "START" : "END";
+ Log.v(TAG, prefix + " " + methodName + ": Activity = " + toString());
+ }
+
+ /**
+ * Subclasses should override this in place of {@link Activity#onNewIntent}.
+ */
+ protected void onNewIntentTasks(Intent newIntent) {
+ }
+
+ /**
+ * Subclasses should override this in place of {@link Activity#onCreate}.
+ */
+ protected void onCreateTasks(Bundle savedInstanceState) {
+ }
+
+ /**
+ * Subclasses should override this in place of {@link Activity#onStart}.
+ */
+ protected void onStartTasks() {
+ }
+
+ /**
+ * Subclasses should override this in place of {@link Activity#onResume}.
+ */
+ protected void onResumeTasks() {
+ }
+
+ /**
+ * Subclasses should override this in place of {@link Activity#onPause}.
+ */
+ protected void onPauseTasks() {
+ }
+
+ /**
+ * Subclasses should override this in place of {@link Activity#onStop}.
+ */
+ protected void onStopTasks() {
+ }
+
+ /**
+ * Subclasses should override this in place of {@link Activity#onDestroy}.
+ */
+ protected void onDestroyTasks() {
+ }
+}
diff --git a/camera/MultiCameraApplication/java/com/intel/multicamera/SettingsActivity.java b/camera/MultiCameraApplication/java/com/intel/multicamera/SettingsActivity.java
index 68f7231..bf385e1 100644
--- a/camera/MultiCameraApplication/java/com/intel/multicamera/SettingsActivity.java
+++ b/camera/MultiCameraApplication/java/com/intel/multicamera/SettingsActivity.java
@@ -64,9 +64,9 @@ protected void onCreate(Bundle savedInstanceState) {
if (GlobalVariable.numOfCameras != 0) getSupportedSize(manager);
getFragmentManager()
- .beginTransaction()
- .replace(R.id.settings, new SettingsFragment())
- .commit();
+ .beginTransaction()
+ .replace(R.id.settings, new SettingsFragment())
+ .commit();
}
public void getSupportedSize(CameraManager manager) {
@@ -80,12 +80,12 @@ public void getSupportedSize(CameraManager manager) {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(camerId);
StreamConfigurationMap map =
- characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) {
}
GlobalVariable.SupportedSizes =
- new ArrayList<>(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)));
+ new ArrayList<>(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)));
} catch (CameraAccessException e) {
e.printStackTrace();
@@ -93,7 +93,7 @@ public void getSupportedSize(CameraManager manager) {
}
public static class SettingsFragment
- extends PreferenceFragment implements OnSharedPreferenceChangeListener {
+ extends PreferenceFragment implements OnSharedPreferenceChangeListener {
public String TAG = "SettingsFragment";
public static final String SIZE_LARGE = "large";
public static final String SIZE_MEDIUM = "medium";
@@ -105,9 +105,9 @@ public static class SettingsFragment
private static final String SIZE_SETTING_STRING_DIMENSION_DELIMITER = "x";
public static SparseArray sCachedSelectedVideoQualities =
- new SparseArray(3);
+ new SparseArray(3);
private static String mPrefChangedKey = null;
- static boolean isPrefChangedKeyChnaged = false;
+ static boolean isPrefChangedKeyChanged = false;
/** The selected {@link CamcorderProfile} qualities. */
public static class SelectedVideoQualities {
public int large = -1;
@@ -133,11 +133,11 @@ public int getFromSetting(String sizeSetting) {
/** Video qualities sorted by size. */
public static int[] sVideoQualities =
- new int[] {// CamcorderProfile.QUALITY_HIGH,
- CamcorderProfile.QUALITY_1080P, CamcorderProfile.QUALITY_720P,
- CamcorderProfile.QUALITY_480P, CamcorderProfile.QUALITY_CIF,
- CamcorderProfile.QUALITY_QVGA, CamcorderProfile.QUALITY_QCIF,
- CamcorderProfile.QUALITY_LOW};
+ new int[] {// CamcorderProfile.QUALITY_HIGH,
+ CamcorderProfile.QUALITY_1080P, CamcorderProfile.QUALITY_720P,
+ CamcorderProfile.QUALITY_480P, CamcorderProfile.QUALITY_CIF,
+ CamcorderProfile.QUALITY_QVGA, CamcorderProfile.QUALITY_QCIF,
+ CamcorderProfile.QUALITY_LOW};
static SelectedVideoQualities VideoQualities;
public int numOfCameras = GlobalVariable.numOfCameras;
@@ -150,7 +150,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.root_preferences, rootKey);
mCamcorderProfileNames = getResources().getStringArray(R.array.camcorder_profile_names);
- isPrefChangedKeyChnaged = false;
+ isPrefChangedKeyChanged = false;
}
@Override
@@ -171,7 +171,7 @@ public void onResume() {
// Put in the summaries for the currently set values.
final PreferenceGroup Prf_Resolution =
- (PreferenceGroup)findPreference("pref_resolution");
+ (PreferenceGroup)findPreference("pref_resolution");
fillEntriesAndSummaries(Prf_Resolution);
}
@@ -179,26 +179,25 @@ public void onResume() {
Log.d(TAG, "SettingsFragment onResume end");
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(
- this);
+ this);
}
@Override
public void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(
- this);
+ this);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String Key) {
setSummary(findPreference(Key));
mPrefChangedKey = Key;
- isPrefChangedKeyChnaged = true;
+ isPrefChangedKeyChanged = true;
}
public static String getchangedPrefKey() {
- if (isPrefChangedKeyChnaged == true) {
- isPrefChangedKeyChnaged = false;
+ if (isPrefChangedKeyChanged == true) {
return mPrefChangedKey;
} else {
return DEFAULT_KEY;
@@ -302,8 +301,8 @@ public static Size sizeFromSettingString(String sizeSettingString) {
private String getSizeSummaryString(Size size) {
int width = size.getWidth();
int height = size.getHeight();
- String result =
- getResources().getString(R.string.setting_summary_width_and_height, width, height);
+ String result = getResources().getString(R.string.setting_summary_width_and_height,
+ width, height);
return result;
}
diff --git a/camera/MultiCameraApplication/java/com/intel/multicamera/TopLeftCam.java b/camera/MultiCameraApplication/java/com/intel/multicamera/TopLeftCam.java
index 3233405..83c95d9 100644
--- a/camera/MultiCameraApplication/java/com/intel/multicamera/TopLeftCam.java
+++ b/camera/MultiCameraApplication/java/com/intel/multicamera/TopLeftCam.java
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 The Android Open Source Project
* Copyright (c) 2019 Intel Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,6 +23,8 @@
import android.content.*;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
+import android.graphics.Matrix;
+import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.*;
import android.hardware.camera2.params.StreamConfigurationMap;
@@ -30,9 +33,11 @@
import android.media.ImageReader;
import android.media.MediaRecorder;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import android.util.Log;
import android.util.Size;
@@ -71,16 +76,19 @@ public class TopLeftCam {
protected CameraCaptureSession cameraCaptureSessions;
protected CaptureRequest captureRequest;
protected CaptureRequest.Builder captureRequestBuilder;
- private Size imageDimension;
+ private Size imageDimension, previewSize;
private ImageReader imageReader;
private File file;
- private static final int REQUEST_CAMERA_PERMISSION = 200;
- private final int PERMISSIONS_REQUEST_SNAPSHOT = 3;
-
private Handler mBackgroundHandler;
private HandlerThread mBackgroundThread;
+ private static final int SENSOR_ORIENTATION_DEFAULT_DEGREES = 90;
+ private static final int SENSOR_ORIENTATION_INVERSE_DEGREES = 270;
+ private static final SparseIntArray DEFAULT_ORIENTATIONS = new SparseIntArray();
+ private static final SparseIntArray INVERSE_ORIENTATIONS = new SparseIntArray();
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private SharedPreferences settings;
+ private Uri mCurrentVideoUri = null;
+ private ParcelFileDescriptor mVideoFileDescriptor = null;
/**
* Whether the app is recording video now
*/
@@ -93,6 +101,10 @@ public class TopLeftCam {
byte[] jpegLength;
private boolean mIsVideoCaptureIntent, mIsImageCaptureIntent, mIsonDoneClicked;
+ /**
+ * Orientation of the camera sensor
+ */
+ private int mSensorOrientation;
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
@@ -193,56 +205,88 @@ public void onClick(View view) {
});
}
- public void onDoneClicked() { doReturnToCaller(true); }
+ public void onDoneClicked() {
+ doReturnToCaller(true);
+ }
+
+ private void doReturnToCaller(boolean valid) {
+ Intent resultIntent = new Intent();
+ int resultCode;
+ if (mIsVideoCaptureIntent) {
+ mIsVideoCaptureIntent = false;
+ resultCode = Activity.RESULT_OK;
+ resultIntent.setData(mCurrentVideoUri);
+ resultIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ mActivity.setResult(resultCode, resultIntent);
+ } else if (mIsImageCaptureIntent) {
+ mIsImageCaptureIntent = false;
+ resultCode = Activity.RESULT_OK;
+ mActivity.setResult(resultCode);
+ }
- private void doReturnToCaller(boolean valid) { mActivity.finish(); }
+ mActivity.finish();
+ }
TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
// open your camera here
- openCamera();
+ openCamera(width, height);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Transform you image captured size according to the surface width and height
+ configureTransform(width, height);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
- public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ }
};
- public void openCamera() {
+ public void openCamera(int width, int height) {
CameraManager manager = (CameraManager)mActivity.getSystemService(Context.CAMERA_SERVICE);
Log.e(TAG, "is camera open");
try {
+ if (!((manager.getCameraIdList().length >= 1) &&
+ (manager.getCameraIdList().length <= 4))) {
+ Log.e(TAG, "this camera is not connected ");
+ return;
+ }
+
cameraId = manager.getCameraIdList()[0];
Log.e(TAG, "is camera open ID" + cameraId);
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map =
- characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) return;
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
+ String Key = SettingsActivity.SettingsFragment.getchangedPrefKey();
- // Add permission for camera and let user grant the permission
- if (ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.CAMERA) !=
- PackageManager.PERMISSION_GRANTED &&
- ActivityCompat.checkSelfPermission(mActivity,
- Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
- PackageManager.PERMISSION_GRANTED &&
- ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.RECORD_AUDIO) !=
- PackageManager.PERMISSION_GRANTED) {
- ActivityCompat.requestPermissions(
- mActivity,
- new String[] {Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO,
- Manifest.permission.WRITE_EXTERNAL_STORAGE},
- REQUEST_CAMERA_PERMISSION);
- return;
+ if (Key.compareTo("video_list") == 0) {
+ String videoQuality = settings.getString("video_list", "medium");
+
+ int quality = SettingsActivity.SettingsFragment.getVideoQuality(0, videoQuality);
+ Log.d(TAG, "Selected video quality for '" + videoQuality + "' is " + quality);
+
+ mProfile = CamcorderProfile.get(0, quality);
+ previewSize = new Size(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
+
+ configureTransform(width, height);
+ } else {
+ previewSize = SettingsActivity.SettingsFragment.sizeFromSettingString(
+ settings.getString("capture_list", "640x480"));
+ Log.d(TAG,
+ "Selected imageDimension" + previewSize.getWidth() + previewSize.getHeight());
+ configureTransform(width, height);
}
- mMediaRecorder = new MediaRecorder();
+ mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
+
+ configureTransform(width, height);
startBackgroundThread();
manager.openCamera(cameraId, stateCallback, null);
@@ -269,18 +313,42 @@ public void onDisconnected(CameraDevice camera) {
}
@Override
public void onError(CameraDevice camera, int error) {
- cameraDevice.close();
- cameraDevice = null;
+ Log.e(TAG, "onError");
+ closeCamera();
}
};
+ private void configureTransform(int viewWidth, int viewHeight) {
+ if (null == textureView || null == previewSize) {
+ return;
+ }
+ int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
+ Matrix matrix = new Matrix();
+ RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
+ Log.e(TAG, "configureTransform() viewWidth: " + viewWidth + " viewHeight: " + viewHeight);
+ RectF bufferRect = new RectF(0, 0, previewSize.getHeight(), previewSize.getWidth());
+ float centerX = viewRect.centerX();
+ float centerY = viewRect.centerY();
+ if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
+ bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
+ matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
+ float scale = Math.max((float)viewHeight / previewSize.getHeight(),
+ (float)viewWidth / previewSize.getWidth());
+ matrix.postScale(scale, scale, centerX, centerY);
+ matrix.postRotate(90 * (rotation - 2), centerX, centerY);
+ } else if (Surface.ROTATION_180 == rotation) {
+ matrix.postRotate(180, centerX, centerY);
+ }
+ textureView.setTransform(matrix);
+ }
+
protected void createCameraPreview() {
try {
closePreviewSession();
SurfaceTexture texture = textureView.getSurfaceTexture();
if (texture == null) return;
int quality = -1;
-
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
String Key = SettingsActivity.SettingsFragment.getchangedPrefKey();
String videoQuality = settings.getString("video_list", "medium");
@@ -300,31 +368,44 @@ protected void createCameraPreview() {
Surface surface = new Surface(texture);
captureRequestBuilder =
- cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(
- Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
- @Override
- public void onConfigured(CameraCaptureSession cameraCaptureSession) {
- // The camera is already closed
- if (null == cameraDevice) {
- return;
+ Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
+ @Override
+ public void onConfigured(CameraCaptureSession cameraCaptureSession) {
+ // The camera is already closed
+ if (null == cameraDevice) {
+ return;
+ }
+ // When the session is ready, we start displaying the preview.
+ cameraCaptureSessions = cameraCaptureSession;
+ updatePreview();
}
- // When the session is ready, we start displaying the preview.
- cameraCaptureSessions = cameraCaptureSession;
- updatePreview();
- }
- @Override
- public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
- Toast.makeText(mActivity, "Configuration change", Toast.LENGTH_SHORT)
- .show();
- }
- }, null);
+ @Override
+ public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
+ Toast.makeText(mActivity, "Configuration change", Toast.LENGTH_SHORT)
+ .show();
+ }
+ }, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
+ public void releaseMedia() {
+ if (null != mMediaRecorder) {
+ try {
+ mMediaRecorder.stop();
+ } catch (IllegalStateException ex) {
+ Log.d(TAG, "Stop called before start");
+ }
+ mMediaRecorder.reset();
+ mMediaRecorder.release();
+ mMediaRecorder = null;
+ }
+ }
+
public void closeCamera() {
closePreviewSession();
if (null != cameraDevice) {
@@ -335,11 +416,8 @@ public void closeCamera() {
imageReader.close();
imageReader = null;
}
- if (null != mMediaRecorder) {
- mMediaRecorder.reset();
- mMediaRecorder.release();
- mMediaRecorder = null;
- }
+ releaseMedia();
+ closeVideoFileDescriptor();
stopBackgroundThread();
}
@@ -347,7 +425,7 @@ public void closeCamera() {
* Starts a background thread and its {@link Handler}.
*/
private void startBackgroundThread() {
- mBackgroundThread = new HandlerThread("Camera-$cameraId");
+ mBackgroundThread = new HandlerThread("Camera_0");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
@@ -383,6 +461,20 @@ protected void updatePreview() {
}
}
+ /**
+ * Retrieves the JPEG orientation from the specified screen rotation.
+ *
+ * @param rotation The screen rotation.
+ * @return The JPEG orientation (one of 0, 90, 270, and 360)
+ */
+ private int getOrientation(int rotation) {
+ // Sensor orientation is 90 for most devices, or 270 for some devices (eg. Nexus 5X)
+ // We have to take that into account and rotate JPEG properly.
+ // For devices with orientation of 90, we simply return our mapping from ORIENTATIONS.
+ // For devices with orientation of 270, we need to rotate the JPEG 180 degrees.
+ return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;
+ }
+
protected void takePicture() {
if (null == cameraDevice) {
Log.e(TAG, "cameraDevice is null");
@@ -390,8 +482,11 @@ protected void takePicture() {
}
try {
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
imageDimension = SettingsActivity.SettingsFragment.sizeFromSettingString(
- settings.getString("capture_list", "640x480"));
+ settings.getString("capture_list", "640x480"));
+ Log.d(TAG, "Selected imageDimension " + imageDimension.getWidth() +
+ imageDimension.getHeight());
ImageReader reader = ImageReader.newInstance(
imageDimension.getWidth(), imageDimension.getHeight(), ImageFormat.JPEG, 1);
@@ -399,23 +494,13 @@ protected void takePicture() {
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(textureView.getSurfaceTexture()));
captureRequestBuilder =
- cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+ cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureRequestBuilder.addTarget(reader.getSurface());
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE,
CameraMetadata.CONTROL_MODE_AUTO);
// Orientation
int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
- captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
-
- // Add permission for camera and let user grant the permission
- if (ActivityCompat.checkSelfPermission(mActivity,
- Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
- PackageManager.PERMISSION_GRANTED) {
- ActivityCompat.requestPermissions(
- mActivity, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
- PERMISSIONS_REQUEST_SNAPSHOT);
- return;
- }
+ captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
String fileDetails[] = Utils.generateFileDetails(Utils.MEDIA_TYPE_IMAGE);
if (fileDetails == null || fileDetails.length < 5) {
@@ -424,77 +509,78 @@ protected void takePicture() {
}
mPictureFilename = fileDetails[3];
mCurrentPictureValues =
- Utils.getContentValues(Utils.MEDIA_TYPE_IMAGE, fileDetails,
- imageDimension.getWidth(), imageDimension.getHeight());
+ Utils.getContentValues(Utils.MEDIA_TYPE_IMAGE, fileDetails,
+ imageDimension.getWidth(), imageDimension.getHeight());
file = new File(mPictureFilename);
ImageReader.OnImageAvailableListener readerListener =
- new ImageReader.OnImageAvailableListener() {
- @Override
- public void onImageAvailable(ImageReader reader) {
- Image image = null;
- try {
- image = reader.acquireLatestImage();
- ByteBuffer buffer = image.getPlanes()[0].getBuffer();
- byte[] bytes = new byte[buffer.capacity()];
- buffer.get(bytes);
- jpegLength = bytes;
- mCurrentPictureValues.put(MediaStore.Images.ImageColumns.SIZE,
- jpegLength);
-
- save(bytes);
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (image != null) {
- image.close();
+ new ImageReader.OnImageAvailableListener() {
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ Image image = null;
+ try {
+ image = reader.acquireLatestImage();
+ ByteBuffer buffer = image.getPlanes()[0].getBuffer();
+ byte[] bytes = new byte[buffer.capacity()];
+ buffer.get(bytes);
+ jpegLength = bytes;
+ mCurrentPictureValues.put(MediaStore.Images.ImageColumns.SIZE,
+ jpegLength);
+
+ save(bytes);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (image != null) {
+ image.close();
+ }
}
}
- }
- private void save(byte[] bytes) throws IOException {
- OutputStream output = null;
- try {
- output = new FileOutputStream(file);
- output.write(bytes);
- } finally {
- if (null != output) {
- output.close();
+ private void save(byte[] bytes) throws IOException {
+ OutputStream output = null;
+ try {
+ output = new FileOutputStream(file);
+ output.write(bytes);
+ } finally {
+ if (null != output) {
+ output.close();
+ }
}
}
- }
- };
+ };
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener =
- new CameraCaptureSession.CaptureCallback() {
- @Override
- public void onCaptureCompleted(CameraCaptureSession session,
- CaptureRequest request,
- TotalCaptureResult result) {
- super.onCaptureCompleted(session, request, result);
- Toast.makeText(mActivity, "Saved:" + file, Toast.LENGTH_SHORT).show();
-
- createCameraPreview();
- }
- };
+ new CameraCaptureSession.CaptureCallback() {
+ @Override
+ public void onCaptureCompleted(CameraCaptureSession session,
+ CaptureRequest request,
+ TotalCaptureResult result) {
+ super.onCaptureCompleted(session, request, result);
+ Toast.makeText(mActivity, "Saved:" + file, Toast.LENGTH_SHORT).show();
+
+ createCameraPreview();
+ }
+ };
cameraDevice.createCaptureSession(
- outputSurfaces, new CameraCaptureSession.StateCallback() {
- @Override
- public void onConfigured(CameraCaptureSession session) {
- try {
- session.capture(captureRequestBuilder.build(), captureListener,
- mBackgroundHandler);
- } catch (CameraAccessException e) {
- e.printStackTrace();
+ outputSurfaces, new CameraCaptureSession.StateCallback() {
+ @Override
+ public void onConfigured(CameraCaptureSession session) {
+ try {
+ session.capture(captureRequestBuilder.build(), captureListener,
+ mBackgroundHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
}
- }
- @Override
- public void onConfigureFailed(CameraCaptureSession session) {}
- }, mBackgroundHandler);
+ @Override
+ public void onConfigureFailed(CameraCaptureSession session) {
+ }
+ }, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
@@ -502,11 +588,19 @@ public void onConfigureFailed(CameraCaptureSession session) {}
/* Recording Start*/
private void startRecordingVideo() {
- if (null == cameraDevice || !textureView.isAvailable() || null == mProfile) {
+ if (null == cameraDevice || !textureView.isAvailable()) {
return;
}
try {
closePreviewSession();
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
+ String videoQuality = settings.getString("video_list", "medium");
+
+ int quality = SettingsActivity.SettingsFragment.getVideoQuality(0, videoQuality);
+ Log.d(TAG, "Selected video quality for '" + videoQuality + "' is " + quality);
+
+ mProfile = CamcorderProfile.get(0, quality);
+
setUpMediaRecorder();
SurfaceTexture texture = textureView.getSurfaceTexture();
if (texture == null) return;
@@ -562,30 +656,73 @@ private void setUpMediaRecorder() throws IOException {
return;
}
+ String result = null;
+ ContentResolver mContentResolver = mActivity.getContentResolver();
+
+ Intent intent = mActivity.getIntent();
+ Bundle extras = intent.getExtras();
+
+ closeVideoFileDescriptor();
+
+ if (mIsVideoCaptureIntent && extras != null) {
+ Uri saveUri = extras.getParcelable(MediaStore.EXTRA_OUTPUT);
+ if (saveUri != null) {
+ try {
+ mVideoFileDescriptor = mContentResolver.openFileDescriptor(saveUri, "rw");
+ mCurrentVideoUri = saveUri;
+ mVideoFilename = Utils.getFileNameFromUri(saveUri);
+ } catch (java.io.FileNotFoundException ex) {
+ // invalid uri
+ Log.e(TAG, ex.toString());
+ }
+ }
+ }
+
+ mMediaRecorder = new MediaRecorder();
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
- mMediaRecorder.setProfile(mProfile);
- String fileDetails[] = Utils.generateFileDetails(Utils.MEDIA_TYPE_VIDEO);
- if (fileDetails == null || fileDetails.length < 5) {
- Log.e(TAG, "Invalid file details");
- return;
+ if (mVideoFileDescriptor != null) {
+ mMediaRecorder.setOutputFile(mVideoFileDescriptor.getFileDescriptor());
+ mVideoFilename = "CtsCameraIntents.mp4";
+ } else {
+ String fileDetails[] = Utils.generateFileDetails(Utils.MEDIA_TYPE_VIDEO);
+ if (fileDetails == null || fileDetails.length < 5) {
+ Log.e(TAG, "Invalid file details");
+ return;
+ }
+ mVideoFilename = fileDetails[3];
+ mCurrentVideoValues =
+ Utils.getContentValues(Utils.MEDIA_TYPE_VIDEO, fileDetails,
+ mProfile.videoFrameWidth, mProfile.videoFrameHeight);
+
+ /**
+ * set output file in media recorder
+ */
+ mMediaRecorder.setOutputFile(mVideoFilename);
}
- mVideoFilename = fileDetails[3];
- mCurrentVideoValues =
- Utils.getContentValues(Utils.MEDIA_TYPE_VIDEO, fileDetails, mProfile.videoFrameWidth,
- mProfile.videoFrameHeight);
-
- /**
- * set output file in media recorder
- */
- mMediaRecorder.setOutputFile(mVideoFilename);
+ mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
+ mMediaRecorder.setVideoEncodingBitRate(10000000);
+ mMediaRecorder.setVideoFrameRate(30);
+ mMediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
+ mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+ mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+
+ int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
+ switch (mSensorOrientation) {
+ case SENSOR_ORIENTATION_DEFAULT_DEGREES:
+ mMediaRecorder.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation));
+ break;
+ case SENSOR_ORIENTATION_INVERSE_DEGREES:
+ mMediaRecorder.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation));
+ break;
+ }
try {
mMediaRecorder.prepare();
} catch (IOException ex) {
Log.e(TAG, "prepare failed for " + mVideoFilename, ex);
- mMediaRecorder.reset();
+ releaseMedia();
throw new RuntimeException(ex);
}
}
@@ -601,16 +738,27 @@ private void closePreviewSession() {
private void stopRecordingVideo() {
mIsRecordingVideo = false;
TakeVideoButton.setText(R.string.record);
+
// Stop recording
- mMediaRecorder.stop();
- mMediaRecorder.reset();
+ releaseMedia();
if (null != mActivity) {
Toast.makeText(mActivity, "Video saved: " + mVideoFilename, Toast.LENGTH_SHORT).show();
Log.d(TAG, "Video saved: " + mVideoFilename);
}
mVideoFilename = null;
-
+ closeVideoFileDescriptor();
createCameraPreview();
}
+
+ private void closeVideoFileDescriptor() {
+ if (mVideoFileDescriptor != null) {
+ try {
+ mVideoFileDescriptor.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Fail to close fd", e);
+ }
+ mVideoFileDescriptor = null;
+ }
+ }
}
diff --git a/camera/MultiCameraApplication/java/com/intel/multicamera/TopRightCam.java b/camera/MultiCameraApplication/java/com/intel/multicamera/TopRightCam.java
index e0f824a..21e73c2 100644
--- a/camera/MultiCameraApplication/java/com/intel/multicamera/TopRightCam.java
+++ b/camera/MultiCameraApplication/java/com/intel/multicamera/TopRightCam.java
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 The Android Open Source Project
* Copyright (c) 2019 Intel Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,6 +23,8 @@
import android.content.*;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
+import android.graphics.Matrix;
+import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.*;
import android.hardware.camera2.params.StreamConfigurationMap;
@@ -71,14 +74,15 @@ public class TopRightCam {
protected CameraCaptureSession cameraCaptureSessions;
protected CaptureRequest captureRequest;
protected CaptureRequest.Builder captureRequestBuilder;
- private Size imageDimension;
+ private Size imageDimension, previewSize;
private ImageReader imageReader;
private File file;
- private static final int REQUEST_CAMERA_PERMISSION = 200;
- private final int PERMISSIONS_REQUEST_SNAPSHOT = 3;
-
private Handler mBackgroundHandler;
private HandlerThread mBackgroundThread;
+ private static final int SENSOR_ORIENTATION_DEFAULT_DEGREES = 90;
+ private static final int SENSOR_ORIENTATION_INVERSE_DEGREES = 270;
+ private static final SparseIntArray DEFAULT_ORIENTATIONS = new SparseIntArray();
+ private static final SparseIntArray INVERSE_ORIENTATIONS = new SparseIntArray();
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private SharedPreferences settings;
/**
@@ -92,6 +96,11 @@ public class TopRightCam {
private ContentValues mCurrentVideoValues, mCurrentPictureValues;
byte[] jpegLength;
+ /**
+ * Orientation of the camera sensor
+ */
+ private int mSensorOrientation;
+
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
@@ -151,49 +160,60 @@ public void onClick(View view) {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
// open your camera here
- openCamera();
+ openCamera(width, height);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Transform you image captured size according to the surface width and height
+ configureTransform(width, height);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
- public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ }
};
- public void openCamera() {
+ public void openCamera(int width, int height) {
CameraManager manager = (CameraManager)mActivity.getSystemService(Context.CAMERA_SERVICE);
Log.e(TAG, "is camera open");
try {
+ if (!((manager.getCameraIdList().length >= 2) &&
+ (manager.getCameraIdList().length <= 4))) {
+ Log.e(TAG, "this camera is not connected ");
+ return;
+ }
cameraId = manager.getCameraIdList()[1];
Log.e(TAG, "is camera open ID" + cameraId);
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map =
- characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) return;
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
+ String Key = SettingsActivity.SettingsFragment.getchangedPrefKey();
- // Add permission for camera and let user grant the permission
- if (ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.CAMERA) !=
- PackageManager.PERMISSION_GRANTED &&
- ActivityCompat.checkSelfPermission(mActivity,
- Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
- PackageManager.PERMISSION_GRANTED &&
- ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.RECORD_AUDIO) !=
- PackageManager.PERMISSION_GRANTED) {
- ActivityCompat.requestPermissions(
- mActivity,
- new String[] {Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO,
- Manifest.permission.WRITE_EXTERNAL_STORAGE},
- REQUEST_CAMERA_PERMISSION);
- return;
- }
+ if (Key.compareTo("video_list") == 0) {
+ String videoQuality = settings.getString("video_list", "medium");
+
+ int quality = SettingsActivity.SettingsFragment.getVideoQuality(0, videoQuality);
+ Log.d(TAG, "Selected video quality for '" + videoQuality + "' is " + quality);
+
+ mProfile = CamcorderProfile.get(0, quality);
+ previewSize = new Size(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
- mMediaRecorder = new MediaRecorder();
+ configureTransform(width, height);
+ } else {
+ previewSize = SettingsActivity.SettingsFragment.sizeFromSettingString(
+ settings.getString("capture_list", "640x480"));
+ Log.d(TAG,
+ "Selected imageDimension" + previewSize.getWidth() + previewSize.getHeight());
+ configureTransform(width, height);
+ }
+ mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
+ configureTransform(width, height);
startBackgroundThread();
manager.openCamera(cameraId, stateCallback, null);
@@ -219,17 +239,42 @@ public void onDisconnected(CameraDevice camera) {
}
@Override
public void onError(CameraDevice camera, int error) {
- cameraDevice.close();
- cameraDevice = null;
+ Log.e(TAG, "onError");
+ closeCamera();
}
};
+ private void configureTransform(int viewWidth, int viewHeight) {
+ if (null == textureView || null == previewSize) {
+ return;
+ }
+ int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
+ Matrix matrix = new Matrix();
+ RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
+ Log.e(TAG, "configureTransform() viewWidth: " + viewWidth + " viewHeight: " + viewHeight);
+ RectF bufferRect = new RectF(0, 0, previewSize.getHeight(), previewSize.getWidth());
+ float centerX = viewRect.centerX();
+ float centerY = viewRect.centerY();
+ if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
+ bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
+ matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
+ float scale = Math.max((float)viewHeight / previewSize.getHeight(),
+ (float)viewWidth / previewSize.getWidth());
+ matrix.postScale(scale, scale, centerX, centerY);
+ matrix.postRotate(90 * (rotation - 2), centerX, centerY);
+ } else if (Surface.ROTATION_180 == rotation) {
+ matrix.postRotate(180, centerX, centerY);
+ }
+ textureView.setTransform(matrix);
+ }
+
protected void createCameraPreview() {
try {
closePreviewSession();
SurfaceTexture texture = textureView.getSurfaceTexture();
if (texture == null) return;
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
String Key = SettingsActivity.SettingsFragment.getchangedPrefKey();
imageDimension = SettingsActivity.SettingsFragment.sizeFromSettingString(
@@ -249,31 +294,44 @@ protected void createCameraPreview() {
Surface surface = new Surface(texture);
captureRequestBuilder =
- cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(
- Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
- @Override
- public void onConfigured(CameraCaptureSession cameraCaptureSession) {
- // The camera is already closed
- if (null == cameraDevice) {
- return;
+ Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
+ @Override
+ public void onConfigured(CameraCaptureSession cameraCaptureSession) {
+ // The camera is already closed
+ if (null == cameraDevice) {
+ return;
+ }
+ // When the session is ready, we start displaying the preview.
+ cameraCaptureSessions = cameraCaptureSession;
+ updatePreview();
}
- // When the session is ready, we start displaying the preview.
- cameraCaptureSessions = cameraCaptureSession;
- updatePreview();
- }
- @Override
- public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
- Toast.makeText(mActivity, "Configuration change", Toast.LENGTH_SHORT)
- .show();
- }
- }, null);
+ @Override
+ public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
+ Toast.makeText(mActivity, "Configuration change", Toast.LENGTH_SHORT)
+ .show();
+ }
+ }, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
+ public void releaseMedia() {
+ if (null != mMediaRecorder) {
+ try {
+ mMediaRecorder.stop();
+ } catch (IllegalStateException ex) {
+ Log.d(TAG, "Stop called before start");
+ }
+ mMediaRecorder.reset();
+ mMediaRecorder.release();
+ mMediaRecorder = null;
+ }
+ }
+
public void closeCamera() {
closePreviewSession();
if (null != cameraDevice) {
@@ -284,11 +342,7 @@ public void closeCamera() {
imageReader.close();
imageReader = null;
}
- if (null != mMediaRecorder) {
- mMediaRecorder.reset();
- mMediaRecorder.release();
- mMediaRecorder = null;
- }
+ releaseMedia();
stopBackgroundThread();
}
@@ -296,7 +350,7 @@ public void closeCamera() {
* Starts a background thread and its {@link Handler}.
*/
private void startBackgroundThread() {
- mBackgroundThread = new HandlerThread("Camera-$cameraId");
+ mBackgroundThread = new HandlerThread("Camera_1");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
@@ -332,6 +386,20 @@ protected void updatePreview() {
}
}
+ /**
+ * Retrieves the JPEG orientation from the specified screen rotation.
+ *
+ * @param rotation The screen rotation.
+ * @return The JPEG orientation (one of 0, 90, 270, and 360)
+ */
+ private int getOrientation(int rotation) {
+ // Sensor orientation is 90 for most devices, or 270 for some devices (eg. Nexus 5X)
+ // We have to take that into account and rotate JPEG properly.
+ // For devices with orientation of 90, we simply return our mapping from ORIENTATIONS.
+ // For devices with orientation of 270, we need to rotate the JPEG 180 degrees.
+ return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;
+ }
+
protected void takePicture() {
if (null == cameraDevice) {
Log.e(TAG, "cameraDevice is null");
@@ -339,32 +407,24 @@ protected void takePicture() {
}
try {
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
imageDimension = SettingsActivity.SettingsFragment.sizeFromSettingString(
- settings.getString("capture_list", "640x480"));
-
+ settings.getString("capture_list", "640x480"));
+ Log.d(TAG, "Selected imageDimension: " + imageDimension.getWidth() +
+ imageDimension.getHeight());
ImageReader reader = ImageReader.newInstance(
- imageDimension.getWidth(), imageDimension.getHeight(), ImageFormat.JPEG, 1);
+ imageDimension.getWidth(), imageDimension.getHeight(), ImageFormat.JPEG, 1);
List outputSurfaces = new ArrayList(2);
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(textureView.getSurfaceTexture()));
captureRequestBuilder =
- cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+ cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureRequestBuilder.addTarget(reader.getSurface());
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE,
CameraMetadata.CONTROL_MODE_AUTO);
// Orientation
int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
- captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
-
- // Add permission for camera and let user grant the permission
- if (ActivityCompat.checkSelfPermission(mActivity,
- Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
- PackageManager.PERMISSION_GRANTED) {
- ActivityCompat.requestPermissions(
- mActivity, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
- PERMISSIONS_REQUEST_SNAPSHOT);
- return;
- }
+ captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
String fileDetails[] = Utils.generateFileDetails(Utils.MEDIA_TYPE_IMAGE);
if (fileDetails == null || fileDetails.length < 5) {
@@ -373,77 +433,78 @@ protected void takePicture() {
}
mPictureFilename = fileDetails[3];
mCurrentPictureValues =
- Utils.getContentValues(Utils.MEDIA_TYPE_IMAGE, fileDetails,
- imageDimension.getWidth(), imageDimension.getHeight());
+ Utils.getContentValues(Utils.MEDIA_TYPE_IMAGE, fileDetails,
+ imageDimension.getWidth(), imageDimension.getHeight());
file = new File(mPictureFilename);
ImageReader.OnImageAvailableListener readerListener =
- new ImageReader.OnImageAvailableListener() {
- @Override
- public void onImageAvailable(ImageReader reader) {
- Image image = null;
- try {
- image = reader.acquireLatestImage();
- ByteBuffer buffer = image.getPlanes()[0].getBuffer();
- byte[] bytes = new byte[buffer.capacity()];
- buffer.get(bytes);
- jpegLength = bytes;
- mCurrentPictureValues.put(MediaStore.Images.ImageColumns.SIZE,
- jpegLength);
-
- save(bytes);
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (image != null) {
- image.close();
+ new ImageReader.OnImageAvailableListener() {
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ Image image = null;
+ try {
+ image = reader.acquireLatestImage();
+ ByteBuffer buffer = image.getPlanes()[0].getBuffer();
+ byte[] bytes = new byte[buffer.capacity()];
+ buffer.get(bytes);
+ jpegLength = bytes;
+ mCurrentPictureValues.put(MediaStore.Images.ImageColumns.SIZE,
+ jpegLength);
+
+ save(bytes);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (image != null) {
+ image.close();
+ }
}
}
- }
- private void save(byte[] bytes) throws IOException {
- OutputStream output = null;
- try {
- output = new FileOutputStream(file);
- output.write(bytes);
- } finally {
- if (null != output) {
- output.close();
+ private void save(byte[] bytes) throws IOException {
+ OutputStream output = null;
+ try {
+ output = new FileOutputStream(file);
+ output.write(bytes);
+ } finally {
+ if (null != output) {
+ output.close();
+ }
}
}
- }
- };
+ };
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener =
- new CameraCaptureSession.CaptureCallback() {
- @Override
- public void onCaptureCompleted(CameraCaptureSession session,
- CaptureRequest request,
- TotalCaptureResult result) {
- super.onCaptureCompleted(session, request, result);
- Toast.makeText(mActivity, "Saved:" + file, Toast.LENGTH_SHORT).show();
-
- createCameraPreview();
- }
- };
+ new CameraCaptureSession.CaptureCallback() {
+ @Override
+ public void onCaptureCompleted(CameraCaptureSession session,
+ CaptureRequest request,
+ TotalCaptureResult result) {
+ super.onCaptureCompleted(session, request, result);
+ Toast.makeText(mActivity, "Saved:" + file, Toast.LENGTH_SHORT).show();
+
+ createCameraPreview();
+ }
+ };
cameraDevice.createCaptureSession(
- outputSurfaces, new CameraCaptureSession.StateCallback() {
- @Override
- public void onConfigured(CameraCaptureSession session) {
- try {
- session.capture(captureRequestBuilder.build(), captureListener,
- mBackgroundHandler);
- } catch (CameraAccessException e) {
- e.printStackTrace();
+ outputSurfaces, new CameraCaptureSession.StateCallback() {
+ @Override
+ public void onConfigured(CameraCaptureSession session) {
+ try {
+ session.capture(captureRequestBuilder.build(), captureListener,
+ mBackgroundHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
}
- }
- @Override
- public void onConfigureFailed(CameraCaptureSession session) {}
- }, mBackgroundHandler);
+ @Override
+ public void onConfigureFailed(CameraCaptureSession session) {
+ }
+ }, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
@@ -451,11 +512,18 @@ public void onConfigureFailed(CameraCaptureSession session) {}
/* Recording Start*/
private void startRecordingVideo() {
- if (null == cameraDevice || !textureView.isAvailable() || null == mProfile) {
+ if (null == cameraDevice || !textureView.isAvailable()) {
return;
}
try {
closePreviewSession();
+ settings = PreferenceManager.getDefaultSharedPreferences(mActivity);
+ String videoQuality = settings.getString("video_list", "medium");
+
+ int quality = SettingsActivity.SettingsFragment.getVideoQuality(0, videoQuality);
+ Log.d(TAG, "Selected video quality for '" + videoQuality + "' is " + quality);
+
+ mProfile = CamcorderProfile.get(0, quality);
setUpMediaRecorder();
SurfaceTexture texture = textureView.getSurfaceTexture();
if (texture == null) return;
@@ -510,9 +578,10 @@ private void setUpMediaRecorder() throws IOException {
if (null == mActivity) {
return;
}
+
+ mMediaRecorder = new MediaRecorder();
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
- mMediaRecorder.setProfile(mProfile);
String fileDetails[] = Utils.generateFileDetails(Utils.MEDIA_TYPE_VIDEO);
if (fileDetails == null || fileDetails.length < 5) {
@@ -521,19 +590,35 @@ private void setUpMediaRecorder() throws IOException {
}
mVideoFilename = fileDetails[3];
mCurrentVideoValues =
- Utils.getContentValues(Utils.MEDIA_TYPE_VIDEO, fileDetails, mProfile.videoFrameWidth,
- mProfile.videoFrameHeight);
+ Utils.getContentValues(Utils.MEDIA_TYPE_VIDEO, fileDetails,
+ mProfile.videoFrameWidth, mProfile.videoFrameHeight);
+ mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
/**
* set output file in media recorder
*/
mMediaRecorder.setOutputFile(mVideoFilename);
+ mMediaRecorder.setVideoEncodingBitRate(10000000);
+ mMediaRecorder.setVideoFrameRate(30);
+ mMediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
+ mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+ mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+
+ int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
+ switch (mSensorOrientation) {
+ case SENSOR_ORIENTATION_DEFAULT_DEGREES:
+ mMediaRecorder.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation));
+ break;
+ case SENSOR_ORIENTATION_INVERSE_DEGREES:
+ mMediaRecorder.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation));
+ break;
+ }
try {
mMediaRecorder.prepare();
} catch (IOException ex) {
Log.e(TAG, "prepare failed for " + mVideoFilename, ex);
- mMediaRecorder.reset();
+ releaseMedia();
throw new RuntimeException(ex);
}
}
@@ -549,9 +634,9 @@ private void closePreviewSession() {
private void stopRecordingVideo() {
mIsRecordingVideo = false;
TakeVideoButton.setText(R.string.record);
+
// Stop recording
- mMediaRecorder.stop();
- mMediaRecorder.reset();
+ releaseMedia();
if (null != mActivity) {
Toast.makeText(mActivity, "Video saved: " + mVideoFilename, Toast.LENGTH_SHORT).show();
diff --git a/camera/MultiCameraApplication/java/com/intel/multicamera/Utils.java b/camera/MultiCameraApplication/java/com/intel/multicamera/Utils.java
index ae9e6f1..32a3289 100644
--- a/camera/MultiCameraApplication/java/com/intel/multicamera/Utils.java
+++ b/camera/MultiCameraApplication/java/com/intel/multicamera/Utils.java
@@ -67,8 +67,8 @@ public static File createOutputmediaStorageDir() {
}
File mediaStorageDir =
- new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
- "MultiCamera");
+ new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
+ "MultiCamera");
// This location works best if you want the created images to be shared
// between applications and persist after your app has been uninstalled.
@@ -121,6 +121,16 @@ public static void broadcastNewVideo(Context context, ContentValues values) {
context.sendBroadcast(new Intent(ACTION_NEW_VIDEO, uri));
}
+ public static String getFileNameFromUri(Uri uri) {
+ String result = null;
+ result = uri.getPath();
+ int cut = result.lastIndexOf('/');
+ if (cut != -1) {
+ result = result.substring(cut + 1);
+ }
+ return result;
+ }
+
public static String[] generateFileDetails(int type) {
File mediaStorageDir = createOutputmediaStorageDir();
if (mediaStorageDir == null) {
@@ -184,8 +194,10 @@ public static ContentValues getContentValues(int type, String fileDetails[], int
Long.valueOf(fileDetails[4]) / 1000);
contentValue.put(MediaStore.Video.Media.MIME_TYPE, fileDetails[2]);
contentValue.put(MediaStore.Video.Media.DATA, fileDetails[3]);
- contentValue.put(MediaStore.MediaColumns.WIDTH, width);
- contentValue.put(MediaStore.MediaColumns.HEIGHT, height);
+ contentValue.put(MediaStore.Video.Media.WIDTH, width);
+ contentValue.put(MediaStore.Video.Media.HEIGHT, height);
+ contentValue.put(MediaStore.Video.Media.RESOLUTION,
+ Integer.toString(width) + "x" + Integer.toString(height));
}
return contentValue;
}
diff --git a/camera/MultiCameraApplication/res/layout/permissions.xml b/camera/MultiCameraApplication/res/layout/permissions.xml
new file mode 100644
index 0000000..eec475b
--- /dev/null
+++ b/camera/MultiCameraApplication/res/layout/permissions.xml
@@ -0,0 +1,21 @@
+
+
+
diff --git a/camera/MultiCameraApplication/res/values/strings.xml b/camera/MultiCameraApplication/res/values/strings.xml
index b5b36cd..b97c7ef 100644
--- a/camera/MultiCameraApplication/res/values/strings.xml
+++ b/camera/MultiCameraApplication/res/values/strings.xml
@@ -59,4 +59,14 @@
"'IMG'_yyyyMMdd_HHmmss"
+
+
+ Camera error
+
+
+ The app does not have critical permissions needed to run. Please check your permissions settings.
+
+
+ Dismiss
+