summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/Camera.java13
-rw-r--r--core/java/android/hardware/camera2/impl/CameraMetadataNative.java216
-rw-r--r--core/java/android/hardware/camera2/impl/GetCommand.java33
-rw-r--r--core/java/android/hardware/camera2/impl/SetCommand.java33
-rw-r--r--core/java/android/hardware/camera2/legacy/BurstHolder.java21
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyResultMapper.java33
-rw-r--r--core/java/android/hardware/camera2/legacy/RequestHolder.java200
-rw-r--r--core/java/android/hardware/camera2/legacy/RequestThreadManager.java50
-rw-r--r--core/java/android/hardware/camera2/marshal/MarshalRegistry.java23
-rw-r--r--core/java/android/hardware/camera2/utils/CloseableLock.java40
-rw-r--r--core/java/android/hardware/camera2/utils/TypeReference.java6
11 files changed, 491 insertions, 177 deletions
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 4c73e6a..eadfa73 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -2423,6 +2423,19 @@ public class Camera {
return Camera.this;
}
+
+ /**
+ * Value equality check.
+ *
+ * @hide
+ */
+ public boolean same(Parameters other) {
+ if (this == other) {
+ return true;
+ }
+ return other != null && Parameters.this.mMap.equals(other.mMap);
+ }
+
/**
* Writes the current Parameters to the log.
* @hide
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 6de5c25..ebab563 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -56,7 +56,6 @@ import android.location.LocationManager;
import android.os.Parcelable;
import android.os.Parcel;
import android.util.Log;
-import android.util.Pair;
import android.util.Size;
import com.android.internal.util.Preconditions;
@@ -79,7 +78,7 @@ public class CameraMetadataNative implements Parcelable {
private final Class<T> mType;
private final TypeReference<T> mTypeReference;
private final String mName;
-
+ private final int mHash;
/**
* Visible for testing only.
*
@@ -95,6 +94,7 @@ public class CameraMetadataNative implements Parcelable {
mName = name;
mType = type;
mTypeReference = TypeReference.createSpecializedTypeReference(type);
+ mHash = mName.hashCode() ^ mTypeReference.hashCode();
}
/**
@@ -113,6 +113,7 @@ public class CameraMetadataNative implements Parcelable {
mName = name;
mType = (Class<T>)typeReference.getRawType();
mTypeReference = typeReference;
+ mHash = mName.hashCode() ^ mTypeReference.hashCode();
}
/**
@@ -137,7 +138,7 @@ public class CameraMetadataNative implements Parcelable {
*/
@Override
public final int hashCode() {
- return mName.hashCode() ^ mTypeReference.hashCode();
+ return mHash;
}
/**
@@ -156,6 +157,10 @@ public class CameraMetadataNative implements Parcelable {
return true;
}
+ if (o == null || this.hashCode() != o.hashCode()) {
+ return false;
+ }
+
Key<?> lhs;
if (o instanceof CaptureResult.Key) {
@@ -337,11 +342,11 @@ public class CameraMetadataNative implements Parcelable {
public <T> T get(Key<T> key) {
Preconditions.checkNotNull(key, "key must not be null");
- Pair<T, Boolean> override = getOverride(key);
- if (override.second) {
- return override.first;
+ // Check if key has been overridden to use a wrapper class on the java side.
+ GetCommand g = sGetCommandMap.get(key);
+ if (g != null) {
+ return (T) g.getValue(this, key);
}
-
return getBase(key);
}
@@ -371,7 +376,9 @@ public class CameraMetadataNative implements Parcelable {
* type to the key.
*/
public <T> void set(Key<T> key, T value) {
- if (setOverride(key, value)) {
+ SetCommand s = sSetCommandMap.get(key);
+ if (s != null) {
+ s.setValue(this, value);
return;
}
@@ -449,44 +456,119 @@ public class CameraMetadataNative implements Parcelable {
ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
return marshaler.unmarshal(buffer);
}
- // Need overwrite some metadata that has different definitions between native
- // and managed sides.
- @SuppressWarnings("unchecked")
- private <T> Pair<T, Boolean> getOverride(Key<T> key) {
- T value = null;
- boolean override = true;
-
- if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_FORMATS)) {
- value = (T) getAvailableFormats();
- } else if (key.equals(CaptureResult.STATISTICS_FACES)) {
- value = (T) getFaces();
- } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) {
- value = (T) getFaceRectangles();
- } else if (key.equals(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)) {
- value = (T) getStreamConfigurationMap();
- } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AE)) {
- value = (T) getMaxRegions(key);
- } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB)) {
- value = (T) getMaxRegions(key);
- } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AF)) {
- value = (T) getMaxRegions(key);
- } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW)) {
- value = (T) getMaxNumOutputs(key);
- } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC)) {
- value = (T) getMaxNumOutputs(key);
- } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING)) {
- value = (T) getMaxNumOutputs(key);
- } else if (key.equals(CaptureRequest.TONEMAP_CURVE)) {
- value = (T) getTonemapCurve();
- } else if (key.equals(CaptureResult.JPEG_GPS_LOCATION)) {
- value = (T) getGpsLocation();
- } else if (key.equals(CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP)) {
- value = (T) getLensShadingMap();
- } else {
- override = false;
- }
- return Pair.create(value, override);
+ // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden
+ // metadata.
+ private static final HashMap<Key<?>, GetCommand> sGetCommandMap =
+ new HashMap<Key<?>, GetCommand>();
+ static {
+ sGetCommandMap.put(
+ CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(), new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getAvailableFormats();
+ }
+ });
+ sGetCommandMap.put(
+ CaptureResult.STATISTICS_FACES.getNativeKey(), new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getFaceRectangles();
+ }
+ });
+ sGetCommandMap.put(
+ CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(), new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getFaces();
+ }
+ });
+ sGetCommandMap.put(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP.getNativeKey(),
+ new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getStreamConfigurationMap();
+ }
+ });
+ sGetCommandMap.put(
+ CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey(), new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getMaxRegions(key);
+ }
+ });
+ sGetCommandMap.put(
+ CameraCharacteristics.CONTROL_MAX_REGIONS_AWB.getNativeKey(), new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getMaxRegions(key);
+ }
+ });
+ sGetCommandMap.put(
+ CameraCharacteristics.CONTROL_MAX_REGIONS_AF.getNativeKey(), new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getMaxRegions(key);
+ }
+ });
+ sGetCommandMap.put(
+ CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW.getNativeKey(), new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getMaxNumOutputs(key);
+ }
+ });
+ sGetCommandMap.put(
+ CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC.getNativeKey(), new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getMaxNumOutputs(key);
+ }
+ });
+ sGetCommandMap.put(
+ CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING.getNativeKey(),
+ new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getMaxNumOutputs(key);
+ }
+ });
+ sGetCommandMap.put(
+ CaptureRequest.TONEMAP_CURVE.getNativeKey(), new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getTonemapCurve();
+ }
+ });
+ sGetCommandMap.put(
+ CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getGpsLocation();
+ }
+ });
+ sGetCommandMap.put(
+ CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey(),
+ new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getLensShadingMap();
+ }
+ });
}
private int[] getAvailableFormats() {
@@ -759,19 +841,37 @@ public class CameraMetadataNative implements Parcelable {
writeValues(tag, values);
}
- // Set the camera metadata override.
- private <T> boolean setOverride(Key<T> key, T value) {
- if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_FORMATS)) {
- return setAvailableFormats((int[]) value);
- } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) {
- return setFaceRectangles((Rect[]) value);
- } else if (key.equals(CaptureRequest.TONEMAP_CURVE)) {
- return setTonemapCurve((TonemapCurve) value);
- } else if (key.equals(CaptureResult.JPEG_GPS_LOCATION)) {
- return setGpsLocation((Location) value);
- }
- // For other keys, set() falls back to setBase().
- return false;
+ // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden
+ // metadata.
+ private static final HashMap<Key<?>, SetCommand> sSetCommandMap =
+ new HashMap<Key<?>, SetCommand>();
+ static {
+ sSetCommandMap.put(CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(),
+ new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setAvailableFormats((int[]) value);
+ }
+ });
+ sSetCommandMap.put(CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(),
+ new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setFaceRectangles((Rect[]) value);
+ }
+ });
+ sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setTonemapCurve((TonemapCurve) value);
+ }
+ });
+ sSetCommandMap.put(CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setGpsLocation((Location) value);
+ }
+ });
}
private boolean setAvailableFormats(int[] value) {
diff --git a/core/java/android/hardware/camera2/impl/GetCommand.java b/core/java/android/hardware/camera2/impl/GetCommand.java
new file mode 100644
index 0000000..a3c677a
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/GetCommand.java
@@ -0,0 +1,33 @@
+/*
+ * 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 android.hardware.camera2.impl;
+
+/**
+ * Getter interface for use with Command pattern metadata value getters.
+ */
+public interface GetCommand {
+
+ /**
+ * Get the value from the given {@link CameraMetadataNative} object.
+ *
+ * @param metadata the {@link CameraMetadataNative} object to get the value from.
+ * @param key the {@link CameraMetadataNative.Key} to look up.
+ * @param <T> the type of the value.
+ * @return the value for a given {@link CameraMetadataNative.Key}.
+ */
+ public <T> T getValue(CameraMetadataNative metadata, CameraMetadataNative.Key<T> key);
+}
diff --git a/core/java/android/hardware/camera2/impl/SetCommand.java b/core/java/android/hardware/camera2/impl/SetCommand.java
new file mode 100644
index 0000000..82a01b2
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/SetCommand.java
@@ -0,0 +1,33 @@
+/*
+ * 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 android.hardware.camera2.impl;
+
+/**
+ * Setter interface for use with Command pattern metadata value setters.
+ */
+public interface SetCommand {
+
+ /**
+ * Set the value in the given metadata.
+ *
+ * @param metadata {@link CameraMetadataNative} to set value in.
+ * @param value value to set.
+ * @param <T> type of the value to set.
+ */
+ public <T> void setValue(/*inout*/CameraMetadataNative metadata,
+ T value);
+}
diff --git a/core/java/android/hardware/camera2/legacy/BurstHolder.java b/core/java/android/hardware/camera2/legacy/BurstHolder.java
index e35eb50..c141c51 100644
--- a/core/java/android/hardware/camera2/legacy/BurstHolder.java
+++ b/core/java/android/hardware/camera2/legacy/BurstHolder.java
@@ -17,6 +17,9 @@
package android.hardware.camera2.legacy;
import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.util.Log;
+import android.view.Surface;
import java.util.ArrayList;
import java.util.List;
@@ -25,8 +28,8 @@ import java.util.List;
* Immutable container for a burst of capture results.
*/
public class BurstHolder {
-
- private final ArrayList<CaptureRequest> mRequests;
+ private static final String TAG = "BurstHolder";
+ private final ArrayList<RequestHolder.Builder> mRequestBuilders;
private final boolean mRepeating;
private final int mRequestId;
@@ -38,7 +41,13 @@ public class BurstHolder {
* @param requests a {@link java.util.List} of {@link CaptureRequest}s in this burst.
*/
public BurstHolder(int requestId, boolean repeating, List<CaptureRequest> requests) {
- mRequests = new ArrayList<CaptureRequest>(requests);
+ mRequestBuilders = new ArrayList<RequestHolder.Builder>();
+ int i = 0;
+ for (CaptureRequest r : requests) {
+ mRequestBuilders.add(new RequestHolder.Builder(requestId, /*subsequenceId*/i,
+ /*request*/r, repeating));
+ ++i;
+ }
mRepeating = repeating;
mRequestId = requestId;
}
@@ -61,7 +70,7 @@ public class BurstHolder {
* Return the number of requests in this burst sequence.
*/
public int getNumberOfRequests() {
- return mRequests.size();
+ return mRequestBuilders.size();
}
/**
@@ -73,8 +82,8 @@ public class BurstHolder {
public List<RequestHolder> produceRequestHolders(long frameNumber) {
ArrayList<RequestHolder> holders = new ArrayList<RequestHolder>();
int i = 0;
- for (CaptureRequest r : mRequests) {
- holders.add(new RequestHolder(mRequestId, i, r, mRepeating, frameNumber + i));
+ for (RequestHolder.Builder b : mRequestBuilders) {
+ holders.add(b.build(frameNumber + i));
++i;
}
return holders;
diff --git a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
index a10a2af..88f95e1 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
@@ -28,15 +28,12 @@ import android.hardware.camera2.legacy.ParameterUtils.WeightedRectangle;
import android.hardware.camera2.legacy.ParameterUtils.ZoomData;
import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.utils.ListUtils;
-import android.hardware.camera2.utils.ParamsUtils;
import android.util.Log;
-import android.util.Rational;
import android.util.Size;
import java.util.ArrayList;
import java.util.List;
-import static com.android.internal.util.Preconditions.*;
import static android.hardware.camera2.CaptureResult.*;
/**
@@ -46,6 +43,36 @@ public class LegacyResultMapper {
private static final String TAG = "LegacyResultMapper";
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+ private LegacyRequest mCachedRequest = null;
+ private CameraMetadataNative mCachedResult = null;
+
+ /**
+ * Generate capture result metadata from the legacy camera request.
+ *
+ * <p>This method caches and reuses the result from the previous call to this method if
+ * the {@code parameters} of the subsequent {@link LegacyRequest} passed to this method
+ * have not changed.</p>
+ *
+ * @param legacyRequest a non-{@code null} legacy request containing the latest parameters
+ * @param timestamp the timestamp to use for this result in nanoseconds.
+ *
+ * @return {@link CameraMetadataNative} object containing result metadata.
+ */
+ public CameraMetadataNative cachedConvertResultMetadata(
+ LegacyRequest legacyRequest, long timestamp) {
+ if (mCachedRequest != null && legacyRequest.parameters.same(mCachedRequest.parameters)) {
+ CameraMetadataNative newResult = new CameraMetadataNative(mCachedResult);
+
+ // sensor.timestamp
+ newResult.set(CaptureResult.SENSOR_TIMESTAMP, timestamp);
+ return newResult;
+ }
+
+ mCachedRequest = legacyRequest;
+ mCachedResult = convertResultMetadata(mCachedRequest, timestamp);
+ return mCachedResult;
+ }
+
/**
* Generate capture result metadata from the legacy camera request.
*
diff --git a/core/java/android/hardware/camera2/legacy/RequestHolder.java b/core/java/android/hardware/camera2/legacy/RequestHolder.java
index e674736..9f27093 100644
--- a/core/java/android/hardware/camera2/legacy/RequestHolder.java
+++ b/core/java/android/hardware/camera2/legacy/RequestHolder.java
@@ -23,6 +23,8 @@ import android.view.Surface;
import java.util.Collection;
+import static com.android.internal.util.Preconditions.*;
+
/**
* Immutable container for a single capture request and associated information.
*/
@@ -34,14 +36,131 @@ public class RequestHolder {
private final int mRequestId;
private final int mSubsequeceId;
private final long mFrameNumber;
+ private final boolean mHasJpegTargets;
+ private final boolean mHasPreviewTargets;
+
+ /**
+ * Returns true if the given surface requires jpeg buffers.
+ *
+ * @param s a {@link android.view.Surface} to check.
+ * @return true if the surface requires a jpeg buffer.
+ */
+ public static boolean jpegType(Surface s)
+ throws LegacyExceptionUtils.BufferQueueAbandonedException {
+ return LegacyCameraDevice.detectSurfaceType(s) ==
+ CameraMetadataNative.NATIVE_JPEG_FORMAT;
+ }
+
+ /**
+ * Returns true if the given surface requires non-jpeg buffer types.
+ *
+ * <p>
+ * "Jpeg buffer" refers to the buffers returned in the jpeg
+ * {@link android.hardware.Camera.PictureCallback}. Non-jpeg buffers are created using a tee
+ * of the preview stream drawn to the surface
+ * set via {@link android.hardware.Camera#setPreviewDisplay(android.view.SurfaceHolder)} or
+ * equivalent methods.
+ * </p>
+ * @param s a {@link android.view.Surface} to check.
+ * @return true if the surface requires a non-jpeg buffer type.
+ */
+ public static boolean previewType(Surface s)
+ throws LegacyExceptionUtils.BufferQueueAbandonedException {
+ return LegacyCameraDevice.detectSurfaceType(s) !=
+ CameraMetadataNative.NATIVE_JPEG_FORMAT;
+ }
+
+ /**
+ * Returns true if any of the surfaces targeted by the contained request require jpeg buffers.
+ */
+ private static boolean requestContainsJpegTargets(CaptureRequest request) {
+ for (Surface s : request.getTargets()) {
+ try {
+ if (jpegType(s)) {
+ return true;
+ }
+ } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+ Log.w(TAG, "Surface abandoned, skipping...", e);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if any of the surfaces targeted by the contained request require a
+ * non-jpeg buffer type.
+ */
+ private static boolean requestContainsPreviewTargets(CaptureRequest request) {
+ for (Surface s : request.getTargets()) {
+ try {
+ if (previewType(s)) {
+ return true;
+ }
+ } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+ Log.w(TAG, "Surface abandoned, skipping...", e);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * A builder class for {@link RequestHolder} objects.
+ *
+ * <p>
+ * This allows per-request queries to be cached for repeating {@link CaptureRequest} objects.
+ * </p>
+ */
+ public final static class Builder {
+ private final int mRequestId;
+ private final int mSubsequenceId;
+ private final CaptureRequest mRequest;
+ private final boolean mRepeating;
+ private final boolean mHasJpegTargets;
+ private final boolean mHasPreviewTargets;
+
+ /**
+ * Construct a new {@link Builder} to generate {@link RequestHolder} objects.
+ *
+ * @param requestId the ID to set in {@link RequestHolder} objects.
+ * @param subsequenceId the sequence ID to set in {@link RequestHolder} objects.
+ * @param request the original {@link CaptureRequest} to set in {@link RequestHolder}
+ * objects.
+ * @param repeating {@code true} if the request is repeating.
+ */
+ public Builder(int requestId, int subsequenceId, CaptureRequest request,
+ boolean repeating) {
+ checkNotNull(request, "request must not be null");
+ mRequestId = requestId;
+ mSubsequenceId = subsequenceId;
+ mRequest = request;
+ mRepeating = repeating;
+ mHasJpegTargets = requestContainsJpegTargets(mRequest);
+ mHasPreviewTargets = requestContainsPreviewTargets(mRequest);
+ }
- RequestHolder(int requestId, int subsequenceId, CaptureRequest request, boolean repeating,
- long frameNumber) {
+ /**
+ * Build a new {@link RequestHolder} using with parameters generated from this
+ * {@link Builder}.
+ *
+ * @param frameNumber the {@code framenumber} to generate in the {@link RequestHolder}.
+ * @return a {@link RequestHolder} constructed with the {@link Builder}'s parameters.
+ */
+ public RequestHolder build(long frameNumber) {
+ return new RequestHolder(mRequestId, mSubsequenceId, mRequest, mRepeating, frameNumber,
+ mHasJpegTargets, mHasPreviewTargets);
+ }
+ }
+
+ private RequestHolder(int requestId, int subsequenceId, CaptureRequest request,
+ boolean repeating, long frameNumber, boolean hasJpegTargets,
+ boolean hasPreviewTargets) {
mRepeating = repeating;
mRequest = request;
mRequestId = requestId;
mSubsequeceId = subsequenceId;
mFrameNumber = frameNumber;
+ mHasJpegTargets = hasJpegTargets;
+ mHasPreviewTargets = hasPreviewTargets;
}
/**
@@ -90,86 +209,15 @@ public class RequestHolder {
* Returns true if any of the surfaces targeted by the contained request require jpeg buffers.
*/
public boolean hasJpegTargets() {
- for (Surface s : getHolderTargets()) {
- try {
- if (jpegType(s)) {
- return true;
- }
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.w(TAG, "Surface abandoned, skipping...", e);
- }
- }
- return false;
+ return mHasJpegTargets;
}
/**
* Returns true if any of the surfaces targeted by the contained request require a
* non-jpeg buffer type.
*/
- public boolean hasPreviewTargets() {
- for (Surface s : getHolderTargets()) {
- try {
- if (previewType(s)) {
- return true;
- }
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.w(TAG, "Surface abandoned, skipping...", e);
- }
- }
- return false;
+ public boolean hasPreviewTargets(){
+ return mHasPreviewTargets;
}
- /**
- * Return the first surface targeted by the contained request that requires a
- * non-jpeg buffer type.
- */
- public Surface getFirstPreviewTarget() {
- for (Surface s : getHolderTargets()) {
- try {
- if (previewType(s)) {
- return s;
- }
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.w(TAG, "Surface abandoned, skipping...", e);
- }
- }
- return null;
- }
-
- /**
- * Returns true if the given surface requires jpeg buffers.
- *
- * @param s a {@link Surface} to check.
- * @return true if the surface requires a jpeg buffer.
- */
- public static boolean jpegType(Surface s)
- throws LegacyExceptionUtils.BufferQueueAbandonedException {
- if (LegacyCameraDevice.detectSurfaceType(s) ==
- CameraMetadataNative.NATIVE_JPEG_FORMAT) {
- return true;
- }
- return false;
- }
-
- /**
- * Returns true if the given surface requires non-jpeg buffer types.
- *
- * <p>
- * "Jpeg buffer" refers to the buffers returned in the jpeg
- * {@link android.hardware.Camera.PictureCallback}. Non-jpeg buffers are created using a tee
- * of the preview stream drawn to the surface
- * set via {@link android.hardware.Camera#setPreviewDisplay(android.view.SurfaceHolder)} or
- * equivalent methods.
- * </p>
- * @param s a {@link Surface} to check.
- * @return true if the surface requires a non-jpeg buffer type.
- */
- public static boolean previewType(Surface s)
- throws LegacyExceptionUtils.BufferQueueAbandonedException {
- if (LegacyCameraDevice.detectSurfaceType(s) !=
- CameraMetadataNative.NATIVE_JPEG_FORMAT) {
- return true;
- }
- return false;
- }
}
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index 7d1be3b..cc7a90e 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -207,15 +207,17 @@ public class RequestThreadManager {
@Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
RequestHolder holder = mInFlightPreview;
+
+ if (DEBUG) {
+ mPrevCounter.countAndLog();
+ }
+
if (holder == null) {
mGLThreadManager.queueNewFrame(null);
Log.w(TAG, "Dropping preview frame.");
return;
}
- if (DEBUG) {
- mPrevCounter.countAndLog();
- }
mInFlightPreview = null;
if (holder.hasPreviewTargets()) {
@@ -278,7 +280,6 @@ public class RequestThreadManager {
startPreview();
}
-
private void configureOutputs(Collection<Surface> outputs) throws IOException {
stopPreview();
if (mGLThreadManager != null) {
@@ -395,6 +396,7 @@ public class RequestThreadManager {
mPreviewTexture.setOnFrameAvailableListener(mPreviewCallback);
}
+ mCamera.setParameters(mParams);
// TODO: configure the JPEG surface with some arbitrary size
// using LegacyCameraDevice.nativeConfigureSurface
}
@@ -530,6 +532,7 @@ public class RequestThreadManager {
private final Handler.Callback mRequestHandlerCb = new Handler.Callback() {
private boolean mCleanup = false;
+ private LegacyResultMapper mMapper = new LegacyResultMapper();
@Override
public boolean handleMessage(Message msg) {
@@ -540,6 +543,10 @@ public class RequestThreadManager {
if (DEBUG) {
Log.d(TAG, "Request thread handling message:" + msg.what);
}
+ long startTime = 0;
+ if (DEBUG) {
+ startTime = SystemClock.elapsedRealtimeNanos();
+ }
switch (msg.what) {
case MSG_CONFIGURE_OUTPUTS:
ConfigureHolder config = (ConfigureHolder) msg.obj;
@@ -553,6 +560,10 @@ public class RequestThreadManager {
throw new IOError(e);
}
config.condition.open();
+ if (DEBUG) {
+ long totalTime = SystemClock.elapsedRealtimeNanos() - startTime;
+ Log.d(TAG, "Configure took " + totalTime + " ns");
+ }
break;
case MSG_SUBMIT_CAPTURE_REQUEST:
Handler handler = RequestThreadManager.this.mRequestThread.getHandler();
@@ -573,6 +584,8 @@ public class RequestThreadManager {
nextBurst.first.produceRequestHolders(nextBurst.second);
for (RequestHolder holder : requests) {
CaptureRequest request = holder.getRequest();
+
+ boolean paramsChanged = false;
if (mLastRequest == null || mLastRequest.captureRequest != request) {
// The intermediate buffer is sometimes null, but we always need
@@ -587,9 +600,13 @@ public class RequestThreadManager {
// Parameters are mutated as a side-effect
LegacyMetadataMapper.convertRequestMetadata(/*inout*/legacyRequest);
- mParams = legacyRequest.parameters;
- mCamera.setParameters(mParams);
+ if (!mParams.same(legacyRequest.parameters)) {
+ mParams = legacyRequest.parameters;
+ mCamera.setParameters(mParams);
+ paramsChanged = true;
+ }
}
+
mDeviceState.setCaptureStart(holder);
long timestamp = 0;
try {
@@ -616,16 +633,29 @@ public class RequestThreadManager {
// TODO: err handling
throw new IOError(e);
}
+
if (timestamp == 0) {
timestamp = SystemClock.elapsedRealtimeNanos();
}
- // Update parameters to the latest that we think the camera is using
- mLastRequest.setParameters(mCamera.getParameters());
- CameraMetadataNative result =
- LegacyResultMapper.convertResultMetadata(mLastRequest, timestamp);
+
+ if (paramsChanged) {
+ if (DEBUG) {
+ Log.d(TAG, "Params changed -- getting new Parameters from HAL.");
+ }
+ mParams = mCamera.getParameters();
+
+ // Update parameters to the latest that we think the camera is using
+ mLastRequest.setParameters(mParams);
+ }
+
+
+ CameraMetadataNative result = mMapper.cachedConvertResultMetadata(
+ mLastRequest, timestamp);
mDeviceState.setCaptureResult(holder, result);
}
if (DEBUG) {
+ long totalTime = SystemClock.elapsedRealtimeNanos() - startTime;
+ Log.d(TAG, "Capture request took " + totalTime + " ns");
mRequestCounter.countAndLog();
}
break;
diff --git a/core/java/android/hardware/camera2/marshal/MarshalRegistry.java b/core/java/android/hardware/camera2/marshal/MarshalRegistry.java
index 92d9057..ba821e4 100644
--- a/core/java/android/hardware/camera2/marshal/MarshalRegistry.java
+++ b/core/java/android/hardware/camera2/marshal/MarshalRegistry.java
@@ -81,17 +81,18 @@ public class MarshalRegistry {
break;
}
}
- }
- if (marshaler == null) {
- throw new UnsupportedOperationException(
- "Could not find marshaler that matches the requested " +
- "combination of type reference " +
- typeToken + " and native type " +
- MarshalHelpers.toStringNativeType(nativeType));
- }
+ if (marshaler == null) {
+ throw new UnsupportedOperationException(
+ "Could not find marshaler that matches the requested " +
+ "combination of type reference " +
+ typeToken + " and native type " +
+ MarshalHelpers.toStringNativeType(nativeType));
+ }
- sMarshalerMap.put(marshalToken, marshaler);
+ // Only put when no cached version exists to avoid +0.5ms lookup per call.
+ sMarshalerMap.put(marshalToken, marshaler);
+ }
return marshaler;
}
@@ -100,10 +101,12 @@ public class MarshalRegistry {
public MarshalToken(TypeReference<T> typeReference, int nativeType) {
this.typeReference = typeReference;
this.nativeType = nativeType;
+ this.hash = typeReference.hashCode() ^ nativeType;
}
final TypeReference<T> typeReference;
final int nativeType;
+ private final int hash;
@Override
public boolean equals(Object other) {
@@ -118,7 +121,7 @@ public class MarshalRegistry {
@Override
public int hashCode() {
- return typeReference.hashCode() ^ nativeType;
+ return hash;
}
}
diff --git a/core/java/android/hardware/camera2/utils/CloseableLock.java b/core/java/android/hardware/camera2/utils/CloseableLock.java
index af55055..9ac89c8 100644
--- a/core/java/android/hardware/camera2/utils/CloseableLock.java
+++ b/core/java/android/hardware/camera2/utils/CloseableLock.java
@@ -110,7 +110,9 @@ public class CloseableLock implements AutoCloseable {
@Override
public void close() {
if (mClosed) {
- log("close - already closed; ignoring");
+ if (VERBOSE) {
+ log("close - already closed; ignoring");
+ }
return;
}
@@ -139,7 +141,9 @@ public class CloseableLock implements AutoCloseable {
mLock.unlock();
}
- log("close - completed");
+ if (VERBOSE) {
+ log("close - completed");
+ }
}
/**
@@ -169,7 +173,9 @@ public class CloseableLock implements AutoCloseable {
// Lock is already closed, all further acquisitions will fail
if (mClosed) {
- log("acquire lock early aborted (already closed)");
+ if (VERBOSE) {
+ log("acquire lock early aborted (already closed)");
+ }
return null;
}
@@ -187,7 +193,9 @@ public class CloseableLock implements AutoCloseable {
// Did another thread #close while we were waiting? Unblock immediately.
if (mClosed) {
- log("acquire lock unblocked aborted (already closed)");
+ if (VERBOSE) {
+ log("acquire lock unblocked aborted (already closed)");
+ }
return null;
}
}
@@ -200,7 +208,9 @@ public class CloseableLock implements AutoCloseable {
mLock.unlock();
}
- log("acquired lock (local own count = " + ownedLocks + "");
+ if (VERBOSE) {
+ log("acquired lock (local own count = " + ownedLocks + ")");
+ }
return new ScopedLock();
}
@@ -231,7 +241,9 @@ public class CloseableLock implements AutoCloseable {
// Lock is already closed, all further acquisitions will fail
if (mClosed) {
- log("acquire exclusive lock early aborted (already closed)");
+ if (VERBOSE) {
+ log("acquire exclusive lock early aborted (already closed)");
+ }
return null;
}
@@ -254,7 +266,9 @@ public class CloseableLock implements AutoCloseable {
// Did another thread #close while we were waiting? Unblock immediately.
if (mClosed) {
- log("acquire exclusive lock unblocked aborted (already closed)");
+ if (VERBOSE) {
+ log("acquire exclusive lock unblocked aborted (already closed)");
+ }
return null;
}
}
@@ -267,7 +281,9 @@ public class CloseableLock implements AutoCloseable {
mLock.unlock();
}
- log("acquired exclusive lock (local own count = " + ownedLocks + "");
+ if (VERBOSE) {
+ log("acquired exclusive lock (local own count = " + ownedLocks + ")");
+ }
return new ScopedLock();
}
@@ -318,13 +334,13 @@ public class CloseableLock implements AutoCloseable {
mLock.unlock();
}
- log("released lock (local lock count " + ownedLocks + ")");
+ if (VERBOSE) {
+ log("released lock (local lock count " + ownedLocks + ")");
+ }
}
private void log(String what) {
- if (VERBOSE) {
- Log.v(TAG + "[" + mName + "]", what);
- }
+ Log.v(TAG + "[" + mName + "]", what);
}
}
diff --git a/core/java/android/hardware/camera2/utils/TypeReference.java b/core/java/android/hardware/camera2/utils/TypeReference.java
index d0c919c..24ce124 100644
--- a/core/java/android/hardware/camera2/utils/TypeReference.java
+++ b/core/java/android/hardware/camera2/utils/TypeReference.java
@@ -46,6 +46,7 @@ import static com.android.internal.util.Preconditions.*;
*/
public abstract class TypeReference<T> {
private final Type mType;
+ private final int mHash;
/**
* Create a new type reference for {@code T}.
@@ -73,6 +74,7 @@ public abstract class TypeReference<T> {
throw new IllegalArgumentException(
"Including a type variable in a type reference is not allowed");
}
+ mHash = mType.hashCode();
}
/**
@@ -84,11 +86,11 @@ public abstract class TypeReference<T> {
private TypeReference(Type type) {
mType = type;
-
if (containsTypeVariable(mType)) {
throw new IllegalArgumentException(
"Including a type variable in a type reference is not allowed");
}
+ mHash = mType.hashCode();
}
private static class SpecializedTypeReference<T> extends TypeReference<T> {
@@ -249,7 +251,7 @@ public abstract class TypeReference<T> {
*/
@Override
public int hashCode() {
- return mType.hashCode();
+ return mHash;
}
/**