aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShuzhen Wang <shuzhenwang@google.com>2018-01-22 18:54:04 -0800
committerShuzhen Wang <shuzhenwang@google.com>2018-05-10 11:37:32 -0700
commit78a60a74ac85b7315180bb18c9d0b34f253ba234 (patch)
treefe3eec16c14d8f75bc9fcb0742d314b6a079b029
parenta2724412e11396864fbccccc469041af3972332e (diff)
downloadpdk-78a60a74ac85b7315180bb18c9d0b34f253ba234.tar.gz
- Ability to select between all available cameras - Ability to stream physical streams for logical camera. Test: Run TestingCamera2 and select between cameras Bug: 76013895 Change-Id: I83ea3f3e118d2471ac4fb97b74968c13425022ff
-rw-r--r--apps/TestingCamera2/res/layout/main.xml13
-rw-r--r--apps/TestingCamera2/res/values/strings.xml1
-rw-r--r--apps/TestingCamera2/src/com/android/testingcamera2/v1/CameraOps.java88
-rw-r--r--apps/TestingCamera2/src/com/android/testingcamera2/v1/TestingCamera2.java84
4 files changed, 162 insertions, 24 deletions
diff --git a/apps/TestingCamera2/res/layout/main.xml b/apps/TestingCamera2/res/layout/main.xml
index ad12d43..488265d 100644
--- a/apps/TestingCamera2/res/layout/main.xml
+++ b/apps/TestingCamera2/res/layout/main.xml
@@ -39,6 +39,11 @@
android:layout_width="240dp"
android:layout_height="180dp" />
+ <SurfaceView
+ android:id="@+id/preview_view2"
+ android:layout_width="240dp"
+ android:layout_height="180dp" />
+
</GridLayout>
<ScrollView
@@ -54,6 +59,14 @@
android:layout_marginLeft="5dp"
android:orientation="vertical" >
+ <Spinner
+ android:id="@+id/camera_id_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:spinnerMode="dropdown"
+ android:prompt="@string/camera_id_spinner_prompt"
+ />
+
<Button
android:id="@+id/info_button"
android:text="@string/info_button_label"
diff --git a/apps/TestingCamera2/res/values/strings.xml b/apps/TestingCamera2/res/values/strings.xml
index 5f749aa..c3bc711 100644
--- a/apps/TestingCamera2/res/values/strings.xml
+++ b/apps/TestingCamera2/res/values/strings.xml
@@ -86,6 +86,7 @@
<!-- V1 strings -->
<string name="v1_app_name">TestingCam2</string>
+ <string name="camera_id_spinner_prompt">Camera Id</string>
<string name="info_button_label">JPEG!</string>
<string name="flush_button_label">Flush device</string>
<string name="focus_lock_button_label">Focus Lock</string>
diff --git a/apps/TestingCamera2/src/com/android/testingcamera2/v1/CameraOps.java b/apps/TestingCamera2/src/com/android/testingcamera2/v1/CameraOps.java
index aae07e9..753fa00 100644
--- a/apps/TestingCamera2/src/com/android/testingcamera2/v1/CameraOps.java
+++ b/apps/TestingCamera2/src/com/android/testingcamera2/v1/CameraOps.java
@@ -26,6 +26,7 @@ import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureRequest.Builder;
+import android.hardware.camera2.params.OutputConfiguration;
import android.util.Size;
import android.media.Image;
import android.media.ImageReader;
@@ -45,6 +46,7 @@ import com.android.ex.camera2.blocking.BlockingSessionCallback;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Set;
/**
* A camera controller class that runs in its own thread, to
@@ -67,6 +69,7 @@ public class CameraOps {
private final BlockingStateCallback mDeviceListener =
new BlockingStateCallback();
+ private String mCameraId;
private CameraDevice mCamera;
private CameraCaptureSession mSession;
@@ -80,6 +83,7 @@ public class CameraOps {
private CaptureRequest.Builder mRecordingRequestBuilder;
List<Surface> mOutputSurfaces = new ArrayList<Surface>(2);
private Surface mPreviewSurface;
+ private Surface mPreviewSurface2;
// How many JPEG buffers do we want to hold on to at once
private static final int MAX_CONCURRENT_JPEGS = 2;
@@ -103,6 +107,11 @@ public class CameraOps {
private final Listener mListener;
private final Handler mListenerHandler;
+ // Physical camera id of the current logical multi-camera. "" if this is not a logical
+ // multi-camera.
+ private String mPhysicalCameraId1;
+ private String mPhysicalCameraId2;
+
private void checkOk() {
if (mStatus < STATUS_OK) {
throw new IllegalStateException(String.format("Device not OK: %d", mStatus ));
@@ -173,18 +182,36 @@ public class CameraOps {
}
private void minimalOpenCamera() throws ApiFailureException {
- if (mCamera == null) {
- final String[] devices;
- final CameraCharacteristics characteristics;
+ // Open camera if not yet opened, or the currently opened camera is not the right one.
+ if (mCamera == null || !mCameraId.equals(mCamera.getId())) {
+ closeDevice();
+ mPhysicalCameraId1 = "";
+ mPhysicalCameraId2 = "";
+ final CameraCharacteristics characteristics;
try {
- devices = mCameraManager.getCameraIdList();
- if (devices == null || devices.length == 0) {
- throw new ApiFailureException("no devices");
+ CameraCharacteristics c = mCameraManager.getCameraCharacteristics(mCameraId);
+ int[] caps = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+ for (int cap : caps) {
+ if (CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
+ != cap) {
+ continue;
+ }
+
+ Set<String> physicalIds = c.getPhysicalCameraIds();
+ if (physicalIds.size() != 2) {
+ throw new ApiFailureException(
+ "3 or more physical cameras are not yet supported");
+ }
+ String[] physicalIdsArray = physicalIds.toArray(new String[2]);
+ mPhysicalCameraId1 = physicalIdsArray[0];
+ mPhysicalCameraId2 = physicalIdsArray[1];
+ break;
}
- mCamera = mBlockingCameraManager.openCamera(devices[0],
+ Log.i(TAG, "Opening " + mCameraId);
+ mCamera = mBlockingCameraManager.openCamera(mCameraId,
mDeviceListener, mOpsHandler);
- mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCamera.getId());
+ mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
characteristics = mCameraCharacteristics;
} catch (CameraAccessException e) {
throw new ApiFailureException("open failure", e);
@@ -197,7 +224,7 @@ public class CameraOps {
mListenerHandler.post(new Runnable() {
@Override
public void run() {
- mListener.onCameraOpened(devices[0], characteristics);
+ mListener.onCameraOpened(mCameraId, characteristics);
}
});
}
@@ -212,11 +239,20 @@ public class CameraOps {
mSession = sessionListener.waitAndGetSession(IDLE_WAIT_MS);
}
+ private void configureOutputsByConfigs(List<OutputConfiguration> outputConfigs)
+ throws CameraAccessException {
+ BlockingSessionCallback sessionListener = new BlockingSessionCallback();
+ mCamera.createCaptureSessionByOutputConfigurations(outputConfigs, sessionListener, mOpsHandler);
+ mSession = sessionListener.waitAndGetSession(IDLE_WAIT_MS);
+ }
+
/**
* Set up SurfaceView dimensions for camera preview
*/
- public void minimalPreviewConfig(SurfaceHolder previewHolder) throws ApiFailureException {
+ public void minimalPreviewConfig(String cameraId, SurfaceHolder previewHolder,
+ SurfaceHolder previewHolder2) throws ApiFailureException {
+ mCameraId = cameraId;
minimalOpenCamera();
try {
CameraCharacteristics properties =
@@ -236,7 +272,9 @@ public class CameraOps {
}
Log.i(TAG, "Set preview size to " + sz.toString());
previewHolder.setFixedSize(sz.getWidth(), sz.getHeight());
+ previewHolder2.setFixedSize(sz.getWidth(), sz.getHeight());
mPreviewSurface = previewHolder.getSurface();
+ mPreviewSurface2 = previewHolder2.getSurface();
} catch (CameraAccessException e) {
throw new ApiFailureException("Error setting up minimal preview", e);
}
@@ -329,24 +367,40 @@ public class CameraOps {
/**
* Configure streams and run minimal preview
*/
- public void minimalPreview(SurfaceHolder previewHolder, CameraControls camCtl)
- throws ApiFailureException {
+ public void minimalPreview(SurfaceHolder previewHolder, SurfaceHolder previewHolder2,
+ CameraControls camCtl) throws ApiFailureException {
minimalOpenCamera();
- if (mPreviewSurface == null) {
+ if (mPreviewSurface == null || mPreviewSurface2 == null) {
throw new ApiFailureException("Preview surface is not created");
}
try {
- List<Surface> outputSurfaces = new ArrayList<Surface>(/*capacity*/1);
- outputSurfaces.add(mPreviewSurface);
-
- configureOutputs(outputSurfaces);
+ List<OutputConfiguration> outputConfigs =
+ new ArrayList<OutputConfiguration>(/*capacity*/2);
+ boolean isLogicalCamera =
+ !mPhysicalCameraId1.equals("") && !mPhysicalCameraId2.equals("");
+ if (isLogicalCamera) {
+ OutputConfiguration config1 = new OutputConfiguration(previewHolder.getSurface());
+ config1.setPhysicalCameraId(mPhysicalCameraId1);
+ outputConfigs.add(config1);
+
+ OutputConfiguration config2 = new OutputConfiguration(previewHolder2.getSurface());
+ config2.setPhysicalCameraId(mPhysicalCameraId2);
+ outputConfigs.add(config2);
+ } else {
+ OutputConfiguration config = new OutputConfiguration(previewHolder.getSurface());
+ outputConfigs.add(config);
+ }
+ configureOutputsByConfigs(outputConfigs);
mPreviewRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
updateCaptureRequest(mPreviewRequestBuilder, camCtl);
mPreviewRequestBuilder.addTarget(mPreviewSurface);
+ if (isLogicalCamera) {
+ mPreviewRequestBuilder.addTarget(mPreviewSurface2);
+ }
mSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, null);
} catch (CameraAccessException e) {
diff --git a/apps/TestingCamera2/src/com/android/testingcamera2/v1/TestingCamera2.java b/apps/TestingCamera2/src/com/android/testingcamera2/v1/TestingCamera2.java
index 9bd3113..7a4a9b5 100644
--- a/apps/TestingCamera2/src/com/android/testingcamera2/v1/TestingCamera2.java
+++ b/apps/TestingCamera2/src/com/android/testingcamera2/v1/TestingCamera2.java
@@ -71,6 +71,8 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
private static final String TAG = "TestingCamera2";
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
private CameraOps mCameraOps;
+ private String[] mAvailableCameraIds;
+ private String mCameraId;
private static final int mSeekBarMax = 100;
private static final long MAX_EXPOSURE = 200000000L; // 200ms
private static final long MIN_EXPOSURE = 100000L; // 100us
@@ -85,10 +87,14 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
private int mLastOrientation = ORIENTATION_UNINITIALIZED;
private OrientationEventListener mOrientationEventListener;
private SurfaceView mPreviewView;
+ private SurfaceView mPreviewView2;
private ImageView mStillView;
private SurfaceHolder mCurrentPreviewHolder = null;
+ private SurfaceHolder mCurrentPreviewHolder2 = null;
+ private Spinner mCameraIdSpinner;
+ private OnItemSelectedListener mCameraIdSelectionListener;
private Button mInfoButton;
private Button mFlushButton;
private ToggleButton mFocusLockToggle;
@@ -127,8 +133,12 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
mPreviewView = (SurfaceView) findViewById(R.id.preview_view);
mPreviewView.getHolder().addCallback(this);
+ mPreviewView2 = (SurfaceView) findViewById(R.id.preview_view2);
+ mPreviewView2.getHolder().addCallback(this);
+
mStillView = (ImageView) findViewById(R.id.still_view);
+ mCameraIdSpinner = (Spinner) findViewById(R.id.camera_id_spinner);
mInfoButton = (Button) findViewById(R.id.info_button);
mInfoButton.setOnClickListener(mInfoButtonListener);
mFlushButton = (Button) findViewById(R.id.flush_button);
@@ -180,6 +190,25 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
logException("Cannot create camera ops!",e);
}
+ // Map available camera Ids to camera id spinner dropdown list of strings
+ try {
+ mAvailableCameraIds = mCameraOps.getDevices();
+ if (mAvailableCameraIds == null || mAvailableCameraIds.length == 0) {
+ throw new ApiFailureException("no devices");
+ }
+ } catch(ApiFailureException e) {
+ logException("CameraOps::getDevices failed!",e);
+ }
+ mCameraId = mAvailableCameraIds[0];
+ ArrayAdapter<String> cameraIdDataAdapter = new ArrayAdapter<>(TestingCamera2.this,
+ android.R.layout.simple_spinner_item, mAvailableCameraIds);
+ mCameraIdSpinner.setAdapter(cameraIdDataAdapter);
+
+ /*
+ * Change the camera ID and update preview when camera ID spinner's selected item changes
+ */
+ mCameraIdSpinner.setOnItemSelectedListener(mCameraIdSelectedListener);
+
mOrientationEventListener = new OrientationEventListener(this) {
@Override
public void onOrientationChanged(int orientation) {
@@ -237,8 +266,10 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
private void setUpPreview() {
try {
- mCameraOps.minimalPreviewConfig(mPreviewView.getHolder());
+ mCameraOps.minimalPreviewConfig(mCameraId, mPreviewView.getHolder(),
+ mPreviewView2.getHolder());
mCurrentPreviewHolder = mPreviewView.getHolder();
+ mCurrentPreviewHolder2 = mPreviewView2.getHolder();
} catch (ApiFailureException e) {
logException("Can't configure preview surface: ",e);
}
@@ -255,6 +286,7 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
logException("Can't close device: ",e);
}
mCurrentPreviewHolder = null;
+ mCurrentPreviewHolder2 = null;
}
@Override
@@ -289,6 +321,7 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
private void updatePreviewOrientation() {
LayoutParams params = mPreviewView.getLayoutParams();
+ LayoutParams params2 = mPreviewView2.getLayoutParams();
int width = params.width;
int height = params.height;
@@ -323,8 +356,11 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
}
params.width = width;
params.height = height;
-
mPreviewView.setLayoutParams(params);
+
+ params2.width = width;
+ params2.height = height;
+ mPreviewView2.setLayoutParams(params2);
}
}
@@ -338,9 +374,11 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
Log.v(TAG, String.format("surfaceChanged: format %x, width %d, height %d", format,
width, height));
}
- if (mCurrentPreviewHolder != null && holder == mCurrentPreviewHolder) {
+ if ((mCurrentPreviewHolder != null && holder == mCurrentPreviewHolder) ||
+ (mCurrentPreviewHolder2 != null && holder == mCurrentPreviewHolder2)) {
try {
- mCameraOps.minimalPreview(holder, mCameraControl);
+ mCameraOps.minimalPreview(mCurrentPreviewHolder, mCurrentPreviewHolder2,
+ mCameraControl);
} catch (ApiFailureException e) {
logException("Can't start minimal preview: ", e);
}
@@ -366,8 +404,9 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
try {
mCameraOps.minimalJpegCapture(mCaptureCallback, mCaptureResultListener,
uiHandler, mCameraControl);
- if (mCurrentPreviewHolder != null) {
- mCameraOps.minimalPreview(mCurrentPreviewHolder, mCameraControl);
+ if (mCurrentPreviewHolder != null && mCurrentPreviewHolder2 != null) {
+ mCameraOps.minimalPreview(mCurrentPreviewHolder,
+ mCurrentPreviewHolder2, mCameraControl);
}
} catch (ApiFailureException e) {
logException("Can't take a JPEG! ", e);
@@ -702,6 +741,36 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
}
};
+ private final OnItemSelectedListener mCameraIdSelectedListener =
+ new OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position,
+ long id) {
+ String cameraId = mAvailableCameraIds[position];
+
+ if (cameraId != mCameraId) {
+ Log.i(TAG, "Switch to camera " + cameraId);
+ try {
+ mCameraOps.minimalPreviewConfig(cameraId, mPreviewView.getHolder(),
+ mPreviewView2.getHolder());
+
+ if (mCurrentPreviewHolder != null && mCurrentPreviewHolder2 != null) {
+ mCameraOps.minimalPreview(mCurrentPreviewHolder,
+ mCurrentPreviewHolder2, mCameraControl);
+ }
+ } catch (ApiFailureException e) {
+ logException("Can't configure preview surface: ", e);
+ }
+ mCameraId = cameraId;
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ // Do nothing
+ }
+ };
+
private final CameraOps.Listener mCameraOpsListener = new CameraOps.Listener() {
@Override
public void onCameraOpened(String cameraId, CameraCharacteristics characteristics) {
@@ -726,7 +795,8 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(TestingCamera2.this,
android.R.layout.simple_spinner_item, afModeList);
- dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ dataAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
mFocusModeSpinner.setAdapter(dataAdapter);
/*