From 981e056c013e6472be3ed4561a9123f030274bf8 Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Thu, 12 Mar 2015 13:39:26 -0700 Subject: [PATCH] Camera: update createStream API to add new rotation field Change-Id: I0f4343a0bfa7bf09ba887c78a1da1c08daa35333 --- .../hardware/camera2/ICameraDeviceUser.aidl | 4 +- .../hardware/camera2/impl/CameraDeviceImpl.java | 46 +++++++++++-------- .../camera2/legacy/CameraDeviceUserShim.java | 9 +++- .../camera2/params/OutputConfiguration.aidl | 20 ++++++++ .../camera2/params/OutputConfiguration.java | 53 +++++++++++++++++++++- .../integration/CameraDeviceBinderTest.java | 16 ++++--- 6 files changed, 118 insertions(+), 30 deletions(-) create mode 100644 core/java/android/hardware/camera2/params/OutputConfiguration.aidl diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl index d286d381f6e8..01f2396805c8 100644 --- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl +++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl @@ -16,7 +16,7 @@ package android.hardware.camera2; -import android.view.Surface; +import android.hardware.camera2.params.OutputConfiguration; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.CaptureRequest; @@ -66,7 +66,7 @@ interface ICameraDeviceUser int deleteStream(int streamId); // non-negative value is the stream ID. negative value is status_t - int createStream(in Surface surface); + int createStream(in OutputConfiguration outputConfiguration); int createDefaultRequest(int templateId, out CameraMetadataNative request); diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index c5267cbe497f..38f8e3947f9f 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -79,7 +79,8 @@ public class CameraDeviceImpl extends CameraDevice { private int mRepeatingRequestId = REQUEST_ID_NONE; private final ArrayList mRepeatingRequestIdDeletedList = new ArrayList(); // Map stream IDs to Surfaces - private final SparseArray mConfiguredOutputs = new SparseArray(); + private final SparseArray mConfiguredOutputs = + new SparseArray(); private final String mCameraId; private final CameraCharacteristics mCharacteristics; @@ -315,7 +316,11 @@ public class CameraDeviceImpl extends CameraDevice { public void configureOutputs(List outputs) throws CameraAccessException { // Leave this here for backwards compatibility with older code using this directly - configureOutputsChecked(outputs); + ArrayList outputConfigs = new ArrayList<>(outputs.size()); + for (Surface s : outputs) { + outputConfigs.add(new OutputConfiguration(s)); + } + configureOutputsChecked(outputConfigs); } /** @@ -334,28 +339,30 @@ public class CameraDeviceImpl extends CameraDevice { * * @throws CameraAccessException if there were any unexpected problems during configuration */ - public boolean configureOutputsChecked(List outputs) throws CameraAccessException { + public boolean configureOutputsChecked(List outputs) + throws CameraAccessException { // Treat a null input the same an empty list if (outputs == null) { - outputs = new ArrayList(); + outputs = new ArrayList(); } boolean success = false; synchronized(mInterfaceLock) { checkIfCameraClosedOrInError(); - - HashSet addSet = new HashSet(outputs); // Streams to create - List deleteList = new ArrayList(); // Streams to delete + // Streams to create + HashSet addSet = new HashSet(outputs); + // Streams to delete + List deleteList = new ArrayList(); // Determine which streams need to be created, which to be deleted for (int i = 0; i < mConfiguredOutputs.size(); ++i) { int streamId = mConfiguredOutputs.keyAt(i); - Surface s = mConfiguredOutputs.valueAt(i); + OutputConfiguration outConfig = mConfiguredOutputs.valueAt(i); - if (!outputs.contains(s)) { + if (!outputs.contains(outConfig)) { deleteList.add(streamId); } else { - addSet.remove(s); // Don't create a stream previously created + addSet.remove(outConfig); // Don't create a stream previously created } } @@ -373,9 +380,11 @@ public class CameraDeviceImpl extends CameraDevice { } // Add all new streams - for (Surface s : addSet) { - int streamId = mRemoteDevice.createStream(s); - mConfiguredOutputs.put(streamId, s); + for (OutputConfiguration outConfig : outputs) { + if (addSet.contains(outConfig)) { + int streamId = mRemoteDevice.createStream(outConfig); + mConfiguredOutputs.put(streamId, outConfig); + } } try { @@ -444,12 +453,9 @@ public class CameraDeviceImpl extends CameraDevice { // TODO: dont block for this boolean configureSuccess = true; CameraAccessException pendingException = null; - List outSurfaces = new ArrayList<>(outputConfigurations.size()); - for (OutputConfiguration config : outputConfigurations) { - outSurfaces.add(config.getSurface()); - } try { - configureSuccess = configureOutputsChecked(outSurfaces); // and then block until IDLE + // configure outputs and then block until IDLE + configureSuccess = configureOutputsChecked(outputConfigurations); } catch (CameraAccessException e) { configureSuccess = false; pendingException = e; @@ -458,6 +464,10 @@ public class CameraDeviceImpl extends CameraDevice { } } + List outSurfaces = new ArrayList<>(outputConfigurations.size()); + for (OutputConfiguration config : outputConfigurations) { + outSurfaces.add(config.getSurface()); + } // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise. CameraCaptureSessionImpl newSession = new CameraCaptureSessionImpl(mNextSessionId++, diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java index 26cd498751d0..70f34637970d 100644 --- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java +++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java @@ -26,6 +26,7 @@ import android.hardware.camera2.ICameraDeviceUser; import android.hardware.camera2.utils.LongParcelable; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.impl.CaptureResultExtras; +import android.hardware.camera2.params.OutputConfiguration; import android.hardware.camera2.utils.CameraBinderDecorator; import android.hardware.camera2.utils.CameraRuntimeException; import android.os.ConditionVariable; @@ -504,7 +505,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser { } @Override - public int createStream(Surface surface) { + public int createStream(OutputConfiguration outputConfiguration) { if (DEBUG) { Log.d(TAG, "createStream called."); } @@ -518,8 +519,12 @@ public class CameraDeviceUserShim implements ICameraDeviceUser { Log.e(TAG, "Cannot create stream, beginConfigure hasn't been called yet."); return CameraBinderDecorator.INVALID_OPERATION; } + if (outputConfiguration.getRotation() != OutputConfiguration.ROTATION_0) { + Log.e(TAG, "Cannot create stream, stream rotation is not supported."); + return CameraBinderDecorator.INVALID_OPERATION; + } int id = ++mSurfaceIdCounter; - mSurfaces.put(id, surface); + mSurfaces.put(id, outputConfiguration.getSurface()); return id; } } diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.aidl b/core/java/android/hardware/camera2/params/OutputConfiguration.aidl new file mode 100644 index 000000000000..0921cd8e77b5 --- /dev/null +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2015 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 android.hardware.camera2.params; + +/** @hide */ +parcelable OutputConfiguration; diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java index 47c784ebf22c..0a4ed396ad53 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -18,19 +18,22 @@ package android.hardware.camera2.params; import android.hardware.camera2.CameraDevice; +import android.util.Log; import android.view.Surface; +import android.os.Parcel; +import android.os.Parcelable; import static com.android.internal.util.Preconditions.*; /** - * Immutable class for describing camera output, which contains a {@link Surface} and its specific + * A class for describing camera output, which contains a {@link Surface} and its specific * configuration for creating capture session. * * @see CameraDevice#createCaptureSession * * @hide */ -public final class OutputConfiguration { +public final class OutputConfiguration implements Parcelable { /** * Rotation constant: 0 degree rotation (no rotation) @@ -93,6 +96,18 @@ public final class OutputConfiguration { } /** + * Create an OutputConfiguration from Parcel. + */ + private OutputConfiguration(Parcel source) { + int rotation = source.readInt(); + Surface surface = Surface.CREATOR.createFromParcel(source); + checkNotNull(surface, "Surface must not be null"); + checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant"); + mSurface = surface; + mRotation = rotation; + } + + /** * Get the {@link Surface} associated with this {@link OutputConfiguration}. * * @return the {@link Surface} associated with this {@link OutputConfiguration}. @@ -111,6 +126,40 @@ public final class OutputConfiguration { return mRotation; } + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public OutputConfiguration createFromParcel(Parcel source) { + try { + OutputConfiguration outputConfiguration = new OutputConfiguration(source); + return outputConfiguration; + } catch (Exception e) { + Log.e(TAG, "Exception creating OutputConfiguration from parcel", e); + return null; + } + } + + @Override + public OutputConfiguration[] newArray(int size) { + return new OutputConfiguration[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + if (dest == null) { + throw new IllegalArgumentException("dest must not be null"); + } + dest.writeInt(mRotation); + mSurface.writeToParcel(dest, flags); + } + + private static final String TAG = "OutputConfiguration"; private final Surface mSurface; private final int mRotation; } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java index d756d058e0f1..e05e1fc59f52 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java @@ -25,6 +25,7 @@ import android.hardware.camera2.ICameraDeviceCallbacks; import android.hardware.camera2.ICameraDeviceUser; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.impl.CaptureResultExtras; +import android.hardware.camera2.params.OutputConfiguration; import android.hardware.camera2.utils.BinderHolder; import android.media.Image; import android.media.ImageReader; @@ -67,6 +68,7 @@ public class CameraDeviceBinderTest extends AndroidTestCase { private CameraBinderTestUtils mUtils; private ICameraDeviceCallbacks.Stub mMockCb; private Surface mSurface; + private OutputConfiguration mOutputConfiguration; private HandlerThread mHandlerThread; private Handler mHandler; ImageReader mImageReader; @@ -147,6 +149,7 @@ public class CameraDeviceBinderTest extends AndroidTestCase { MAX_NUM_IMAGES); mImageReader.setOnImageAvailableListener(new ImageDropperListener(), mHandler); mSurface = mImageReader.getSurface(); + mOutputConfiguration = new OutputConfiguration(mSurface); } private CaptureRequest.Builder createDefaultBuilder(boolean needStream) throws Exception { @@ -161,7 +164,7 @@ public class CameraDeviceBinderTest extends AndroidTestCase { assertFalse(request.isEmpty()); assertFalse(metadata.isEmpty()); if (needStream) { - int streamId = mCameraUser.createStream(mSurface); + int streamId = mCameraUser.createStream(mOutputConfiguration); assertEquals(0, streamId); request.addTarget(mSurface); } @@ -234,11 +237,11 @@ public class CameraDeviceBinderTest extends AndroidTestCase { @SmallTest public void testCreateStream() throws Exception { - int streamId = mCameraUser.createStream(mSurface); + int streamId = mCameraUser.createStream(mOutputConfiguration); assertEquals(0, streamId); assertEquals(CameraBinderTestUtils.ALREADY_EXISTS, - mCameraUser.createStream(mSurface)); + mCameraUser.createStream(mOutputConfiguration)); assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId)); } @@ -255,18 +258,19 @@ public class CameraDeviceBinderTest extends AndroidTestCase { public void testCreateStreamTwo() throws Exception { // Create first stream - int streamId = mCameraUser.createStream(mSurface); + int streamId = mCameraUser.createStream(mOutputConfiguration); assertEquals(0, streamId); assertEquals(CameraBinderTestUtils.ALREADY_EXISTS, - mCameraUser.createStream(mSurface)); + mCameraUser.createStream(mOutputConfiguration)); // Create second stream with a different surface. SurfaceTexture surfaceTexture = new SurfaceTexture(/* ignored */0); surfaceTexture.setDefaultBufferSize(640, 480); Surface surface2 = new Surface(surfaceTexture); + OutputConfiguration output2 = new OutputConfiguration(surface2); - int streamId2 = mCameraUser.createStream(surface2); + int streamId2 = mCameraUser.createStream(output2); assertEquals(1, streamId2); // Clean up streams -- 2.11.0