Camera: update createStream API to add new rotation field

Change-Id: I0f4343a0bfa7bf09ba887c78a1da1c08daa35333
This commit is contained in:
Yin-Chia Yeh
2015-03-12 13:39:26 -07:00
parent 4011e20921
commit bfbbee7566
6 changed files with 118 additions and 30 deletions

View File

@@ -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);

View File

@@ -79,7 +79,8 @@ public class CameraDeviceImpl extends CameraDevice {
private int mRepeatingRequestId = REQUEST_ID_NONE;
private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<Integer>();
// Map stream IDs to Surfaces
private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>();
private final SparseArray<OutputConfiguration> mConfiguredOutputs =
new SparseArray<OutputConfiguration>();
private final String mCameraId;
private final CameraCharacteristics mCharacteristics;
@@ -315,7 +316,11 @@ public class CameraDeviceImpl extends CameraDevice {
public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
// Leave this here for backwards compatibility with older code using this directly
configureOutputsChecked(outputs);
ArrayList<OutputConfiguration> 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<Surface> outputs) throws CameraAccessException {
public boolean configureOutputsChecked(List<OutputConfiguration> outputs)
throws CameraAccessException {
// Treat a null input the same an empty list
if (outputs == null) {
outputs = new ArrayList<Surface>();
outputs = new ArrayList<OutputConfiguration>();
}
boolean success = false;
synchronized(mInterfaceLock) {
checkIfCameraClosedOrInError();
HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
// Streams to create
HashSet<OutputConfiguration> addSet = new HashSet<OutputConfiguration>(outputs);
// Streams to delete
List<Integer> deleteList = new ArrayList<Integer>();
// 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<Surface> 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<Surface> 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++,

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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)
@@ -92,6 +95,18 @@ public final class OutputConfiguration {
mRotation = rotation;
}
/**
* 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}.
*
@@ -111,6 +126,40 @@ public final class OutputConfiguration {
return mRotation;
}
public static final Parcelable.Creator<OutputConfiguration> CREATOR =
new Parcelable.Creator<OutputConfiguration>() {
@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;
}

View File

@@ -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