diff options
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; } /** |