field public static final int SCORE_MIN = 1; // 0x1
}
+ public final class LensShadingMap {
+ method public void copyGainFactors(float[], int);
+ method public int getColumnCount();
+ method public float getGainFactor(int, int, int);
+ method public int getGainFactorCount();
+ method public android.hardware.camera2.RggbChannelVector getGainFactorVector(int, int);
+ method public int getRowCount();
+ field public static final float MINIMUM_GAIN_FACTOR = 1.0f;
+ }
+
public final class MeteringRectangle {
ctor public MeteringRectangle(int, int, int, int, int);
ctor public MeteringRectangle(android.graphics.Point, android.util.Size, int);
method public int getNumerator();
}
+ public final class RggbChannelVector {
+ ctor public RggbChannelVector(float, float, float, float);
+ method public void copyTo(float[], int);
+ method public float getBlue();
+ method public float getComponent(int);
+ method public float getGreenEven();
+ method public float getGreenOdd();
+ method public final float getRed();
+ field public static final int BLUE = 3; // 0x3
+ field public static final int COUNT = 4; // 0x4
+ field public static final int GREEN_EVEN = 1; // 0x1
+ field public static final int GREEN_ODD = 2; // 0x2
+ field public static final int RED = 0; // 0x0
+ }
+
public final class Size {
ctor public Size(int, int);
method public final int getHeight();
method public final int getWidth();
}
+ public final class StreamConfigurationMap {
+ method public final int[] getOutputFormats();
+ method public long getOutputMinFrameDuration(int, android.util.Size);
+ method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
+ method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
+ method public android.util.Size[] getOutputSizes(int);
+ method public long getOutputStallDuration(int, android.util.Size);
+ method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+ method public boolean isOutputSupportedFor(int);
+ method public static boolean isOutputSupportedFor(java.lang.Class<T>);
+ method public boolean isOutputSupportedFor(android.view.Surface);
+ }
+
+ public final class TonemapCurve {
+ method public void copyColorCurve(int, float[], int);
+ method public android.graphics.PointF getPoint(int, int);
+ method public int getPointCount(int);
+ field public static final int CHANNEL_BLUE = 2; // 0x2
+ field public static final int CHANNEL_GREEN = 1; // 0x1
+ field public static final int CHANNEL_RED = 0; // 0x0
+ field public static final float LEVEL_BLACK = 0.0f;
+ field public static final float LEVEL_WHITE = 1.0f;
+ field public static final int POINT_SIZE = 2; // 0x2
+ }
+
}
package android.hardware.display {
*
* <p>The camera device will query each Surface's size and formats upon this
* call, so they must be set to a valid setting at this time (in particular:
- * if the format is user-visible, it must be one of android.scaler.availableFormats;
- * and the size must be one of android.scaler.available[Processed|Jpeg]Sizes).</p>
+ * if the format is user-visible, it must be one of
+ * {@link StreamConfigurationMap#getOutputFormats}; and the size must be one of
+ * {@link StreamConfigurationMap#getOutputSizes(int)}).</p>
*
* <p>When this method is called with valid Surfaces, the device will transition to the {@link
* StateListener#onBusy busy state}. Once configuration is complete, the device will transition
* @see StateListener#onUnconfigured
* @see #stopRepeating
* @see #flush
+ * @see StreamConfigurationMap#getOutputFormats()
+ * @see StreamConfigurationMap#getOutputSizes(int)
+ * @see StreamConfigurationMap#getOutputSizes(Class)
*/
public void configureOutputs(List<Surface> outputs) throws CameraAccessException;
--- /dev/null
+/*
+ * 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;
+
+import static com.android.internal.util.Preconditions.*;
+import static android.hardware.camera2.RggbChannelVector.*;
+
+import android.hardware.camera2.impl.HashCodeHelpers;
+
+import java.util.Arrays;
+
+/**
+ * Immutable class for describing a {@code 4 x N x M} lens shading map of floats.
+ *
+ * @see CameraCharacteristics#LENS_SHADING_MAP
+ */
+public final class LensShadingMap {
+
+ /**
+ * The smallest gain factor in this map.
+ *
+ * <p>All values in this map will be at least this large.</p>
+ */
+ public static final float MINIMUM_GAIN_FACTOR = 1.0f;
+
+ /**
+ * Create a new immutable LensShadingMap instance.
+ *
+ * <p>The elements must be stored in a row-major order (fully packed).</p>
+ *
+ * <p>This constructor takes over the array; do not write to the array afterwards.</p>
+ *
+ * @param elements
+ * An array of elements whose length is
+ * {@code RggbChannelVector.COUNT * rows * columns}
+ *
+ * @throws IllegalArgumentException
+ * if the {@code elements} array length is invalid,
+ * if any of the subelems are not finite or less than {@value #MINIMUM_GAIN_FACTOR},
+ * or if rows or columns is not positive
+ * @throws NullPointerException
+ * if {@code elements} is {@code null}
+ *
+ * @hide
+ */
+ public LensShadingMap(final float[] elements, final int rows, final int columns) {
+
+ mRows = checkArgumentPositive(rows, "rows must be positive");
+ mColumns = checkArgumentPositive(rows, "columns must be positive");
+ mElements = checkNotNull(elements, "elements must not be null");
+
+ if (elements.length != getGainFactorCount()) {
+ throw new IllegalArgumentException("elements must be " + getGainFactorCount() +
+ " length");
+ }
+
+ // Every element must be finite and >= 1.0f
+ checkArrayElementsInRange(elements, MINIMUM_GAIN_FACTOR, Float.MAX_VALUE, "elements");
+ }
+
+ /**
+ * Get the number of rows in this map.
+ */
+ public int getRowCount() {
+ return mRows;
+ }
+
+ /**
+ * Get the number of columns in this map.
+ */
+ public int getColumnCount() {
+ return mColumns;
+ }
+
+ /**
+ * Get the total number of gain factors in this map.
+ *
+ * <p>A single gain factor contains exactly one color channel.
+ * Use with {@link #copyGainFactors} to allocate a large-enough array.</p>
+ */
+ public int getGainFactorCount() {
+ return mRows * mColumns * COUNT;
+ }
+
+ /**
+ * Get a single color channel gain factor from this lens shading map by its row and column.
+ *
+ * <p>The rows must be within the range [0, {@link #getRowCount}),
+ * the column must be within the range [0, {@link #getColumnCount}),
+ * and the color channel must be within the range [0, {@value RggbChannelVector#COUNT}).</p>
+ *
+ * <p>The channel order is {@code [R, Geven, Godd, B]}, where
+ * {@code Geven} is the green channel for the even rows of a Bayer pattern, and
+ * {@code Godd} is the odd rows.
+ * </p>
+ *
+ * @param colorChannel color channel from {@code [R, Geven, Godd, B]}
+ * @param column within the range [0, {@link #getColumnCount})
+ * @param row within the range [0, {@link #getRowCount})
+ *
+ * @return a gain factor >= {@value #MINIMUM_GAIN_FACTOR}
+ *
+ * @throws IllegalArgumentException if any of the parameters was out of range
+ *
+ * @see #RED
+ * @see #GREEN_EVEN
+ * @see #GREEN_ODD
+ * @see #BLUE
+ * @see #getRowCount
+ * @see #getColumnCount
+ */
+ public float getGainFactor(final int colorChannel, final int column, final int row) {
+ if (colorChannel < 0 || colorChannel > COUNT) {
+ throw new IllegalArgumentException("colorChannel out of range");
+ } else if (column < 0 || column >= mColumns) {
+ throw new IllegalArgumentException("column out of range");
+ } else if (row < 0 || row >= mRows) {
+ throw new IllegalArgumentException("row out of range");
+ }
+
+ return mElements[colorChannel + (row * mColumns + column) * COUNT ];
+ }
+
+ /**
+ * Get a gain factor vector from this lens shading map by its row and column.
+ *
+ * <p>The rows must be within the range [0, {@link #getRowCount}),
+ * the column must be within the range [0, {@link #getColumnCount}).</p>
+ *
+ * @param column within the range [0, {@link #getColumnCount})
+ * @param row within the range [0, {@link #getRowCount})
+ *
+ * @return an {@link RggbChannelVector} where each gain factor >= {@value #MINIMUM_GAIN_FACTOR}
+ *
+ * @throws IllegalArgumentException if any of the parameters was out of range
+ *
+ * @see #getRowCount
+ * @see #getColumnCount
+ */
+ public RggbChannelVector getGainFactorVector(final int column, final int row) {
+ if (column < 0 || column >= mColumns) {
+ throw new IllegalArgumentException("column out of range");
+ } else if (row < 0 || row >= mRows) {
+ throw new IllegalArgumentException("row out of range");
+ }
+
+ final int offset = (row * mColumns + column) * COUNT;
+
+ final float red =
+ mElements[RED + offset];
+ final float greenEven =
+ mElements[GREEN_EVEN + offset];
+ final float greenOdd =
+ mElements[GREEN_ODD + offset];
+ final float blue =
+ mElements[BLUE + offset];
+
+ return new RggbChannelVector(red, greenEven, greenOdd, blue);
+ }
+
+ /**
+ * Copy all gain factors in row-major order from this lens shading map into the destination.
+ *
+ * <p>Each gain factor will be >= {@link #MINIMUM_GAIN_FACTOR}.</p>
+ *
+ * @param destination
+ * an array big enough to hold at least {@link RggbChannelVector#COUNT}
+ * elements after the {@code offset}
+ * @param offset
+ * a non-negative offset into the array
+ * @throws NullPointerException
+ * If {@code destination} was {@code null}
+ * @throws IllegalArgumentException
+ * If offset was negative
+ * @throws ArrayIndexOutOfBoundsException
+ * If there's not enough room to write the elements at the specified destination and
+ * offset.
+ *
+ * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
+ */
+ public void copyGainFactors(final float[] destination, final int offset) {
+ checkArgumentNonnegative(offset, "offset must not be negative");
+ checkNotNull(destination, "destination must not be null");
+ if (destination.length + offset < getGainFactorCount()) {
+ throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
+ }
+
+ System.arraycopy(mElements, /*srcPos*/0, destination, offset, getGainFactorCount());
+ }
+
+ /**
+ * Check if this LensShadingMap is equal to another LensShadingMap.
+ *
+ * <p>Two lens shading maps are equal if and only if they have the same rows/columns,
+ * and all of their elements are {@link Object#equals equal}.</p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof LensShadingMap) {
+ final LensShadingMap other = (LensShadingMap) obj;
+ return mRows == other.mRows
+ && mColumns == other.mColumns
+ && Arrays.equals(mElements, other.mElements);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ int elemsHash = HashCodeHelpers.hashCode(mElements);
+ return HashCodeHelpers.hashCode(mRows, mColumns, elemsHash);
+ }
+
+
+ private final int mRows;
+ private final int mColumns;
+ private final float[] mElements;
+};
--- /dev/null
+/*
+ * 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;
+
+import static com.android.internal.util.Preconditions.*;
+
+import android.hardware.camera2.impl.HashCodeHelpers;
+
+import java.util.Arrays;
+
+/**
+ * Immutable class to store the input to output formats
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP map} to be used for with
+ * camera image reprocessing.
+ *
+ * <p>
+ * The mapping of image formats that are supported by this camera device for input streams,
+ * to their corresponding output formats.</p>
+ *
+ * <p>
+ * Attempting to configure an input stream with output streams not listed as available in this map
+ * is not valid.
+ * </p>
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ *
+ * <!-- hide this until we expose input streams through public API -->
+ * @hide
+ */
+public final class ReprocessFormatsMap {
+ /**
+ * Create a new {@link ReprocessFormatsMap}
+ *
+ * <p>This value is encoded as a variable-size array-of-arrays.
+ * The inner array always contains {@code [format, length, ...]} where ... has length elements.
+ * An inner array is followed by another inner array if the total metadata entry size hasn't
+ * yet been exceeded.</p>
+ *
+ * <p>Entry must not be {@code null}. Empty array is acceptable.</p>
+ *
+ * <p>The entry array ownership is passed to this instance after construction; do not
+ * write to it afterwards.</p>
+ *
+ * @param entry Array of ints, not yet deserialized (not-null)
+ *
+ * @throws IllegalArgumentException
+ * if the data was poorly formatted
+ * (missing output format length or too few output formats)
+ * @throws NullPointerException
+ * if entry was null
+ *
+ * @hide
+ */
+ public ReprocessFormatsMap(final int[] entry) {
+ checkNotNull(entry, "entry must not be null");
+
+ int numInputs = 0;
+ int left = entry.length;
+ for (int i = 0; i < entry.length; ) {
+ final int format = entry[i];
+
+ left--;
+ i++;
+
+ if (left < 1) {
+ throw new IllegalArgumentException(
+ String.format("Input %x had no output format length listed", format));
+ }
+
+ final int length = entry[i];
+ left--;
+ i++;
+
+ if (length > 0) {
+ if (left < length) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Input %x had too few output formats listed (actual: %d, " +
+ "expected: %d)", format, left, length));
+ }
+
+ i += length;
+ left -= length;
+ }
+
+ numInputs++;
+ }
+
+ mEntry = entry;
+ mInputCount = numInputs;
+ }
+
+ /**
+ * Get a list of all input image formats that can be used to reprocess an input
+ * stream into an output stream.
+ *
+ * <p>Use this input format to look up the available output formats with {@link #getOutputs}.
+ * </p>
+ *
+ * @return an array of inputs (possibly empty, but never {@code null})
+ *
+ * @see ImageFormat
+ * @see #getOutputs
+ */
+ public int[] getInputs() {
+ final int[] inputs = new int[mInputCount];
+
+ int left = mEntry.length;
+ for (int i = 0, j = 0; i < mEntry.length; j++) {
+ final int format = mEntry[i];
+
+ left--;
+ i++;
+
+ if (left < 1) {
+ throw new AssertionError(
+ String.format("Input %x had no output format length listed", format));
+ }
+ // TODO: check format is a valid input format
+
+ final int length = mEntry[i];
+ left--;
+ i++;
+
+ if (length > 0) {
+ if (left < length) {
+ throw new AssertionError(
+ String.format(
+ "Input %x had too few output formats listed (actual: %d, " +
+ "expected: %d)", format, left, length));
+ }
+
+ i += length;
+ left -= length;
+ }
+
+ // TODO: check output format is a valid output format
+
+ inputs[j] = format;
+ }
+
+ return inputs;
+ }
+
+ /**
+ * Get the list of output formats that can be reprocessed into from the input {@code format}.
+ *
+ * <p>The input {@code format} must be one of the formats returned by {@link #getInputs}.</p>
+ *
+ * @param format an input format
+ *
+ * @return list of output image formats
+ *
+ * @see ImageFormat
+ * @see #getInputs
+ */
+ public int[] getOutputs(final int format) {
+
+ int left = mEntry.length;
+ for (int i = 0; i < mEntry.length; ) {
+ final int inputFormat = mEntry[i];
+
+ left--;
+ i++;
+
+ if (left < 1) {
+ throw new AssertionError(
+ String.format("Input %x had no output format length listed", format));
+ }
+
+ final int length = mEntry[i];
+ left--;
+ i++;
+
+ if (length > 0) {
+ if (left < length) {
+ throw new AssertionError(
+ String.format(
+ "Input %x had too few output formats listed (actual: %d, " +
+ "expected: %d)", format, left, length));
+ }
+ }
+
+ if (inputFormat == format) {
+ int[] outputs = new int[length];
+
+ // Copying manually faster than System.arraycopy for small arrays
+ for (int k = 0; k < length; ++k) {
+ outputs[k] = mEntry[i + k];
+ }
+
+ return outputs;
+ }
+
+ i += length;
+ left -= length;
+
+ }
+
+ throw new IllegalArgumentException(
+ String.format("Input format %x was not one in #getInputs", format));
+ }
+
+ /**
+ * Check if this {@link ReprocessFormatsMap} is equal to another
+ * {@link ReprocessFormatsMap}.
+ *
+ * <p>These two objects are only equal if and only if each of the respective elements is equal.
+ * </p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof ReprocessFormatsMap) {
+ final ReprocessFormatsMap other = (ReprocessFormatsMap) obj;
+ // Do not compare anything besides mEntry, since the rest of the values are derived
+ return Arrays.equals(mEntry, other.mEntry);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ // Do not hash anything besides mEntry since the rest of the values are derived
+ return HashCodeHelpers.hashCode(mEntry);
+ }
+
+ private final int[] mEntry;
+ /*
+ * Dependent fields: values are derived from mEntry
+ */
+ private final int mInputCount;
+}
--- /dev/null
+/*
+ * 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;
+
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Immutable class to store a 4-element vector of floats indexable by a bayer RAW 2x2 pixel block.
+ */
+public final class RggbChannelVector {
+ /**
+ * The number of color channels in this vector.
+ */
+ public static final int COUNT = 4;
+
+ /** Red color channel in a bayer Raw pattern. */
+ public static final int RED = 0;
+
+ /** Green color channel in a bayer Raw pattern used by the even rows. */
+ public static final int GREEN_EVEN = 1;
+
+ /** Green color channel in a bayer Raw pattern used by the odd rows. */
+ public static final int GREEN_ODD = 2;
+
+ /** Blue color channel in a bayer Raw pattern. */
+ public static final int BLUE = 3;
+
+ /**
+ * Create a new {@link RggbChannelVector} from an RGGB 2x2 pixel.
+ *
+ * <p>All pixel values are considered normalized within {@code [0.0f, 1.0f]}
+ * (i.e. {@code 1.0f} could be linearized to {@code 255} if converting to a
+ * non-floating point pixel representation).</p>
+ *
+ * <p>All arguments must be finite; NaN and infinity is not allowed.</p>
+ *
+ * @param red red pixel
+ * @param greenEven green pixel (even row)
+ * @param greenOdd green pixel (odd row)
+ * @param blue blue pixel
+ *
+ * @throws IllegalArgumentException if any of the arguments were not finite
+ */
+ public RggbChannelVector(final float red, final float greenEven, final float greenOdd,
+ final float blue) {
+ mRed = checkArgumentFinite(red, "red");
+ mGreenEven = checkArgumentFinite(greenEven, "greenEven");
+ mGreenOdd = checkArgumentFinite(greenOdd, "greenOdd");
+ mBlue = checkArgumentFinite(blue, "blue");
+ }
+
+ /**
+ * Get the red component.
+ *
+ * @return a floating point value (guaranteed to be finite)
+ */
+ public final float getRed() {
+ return mRed;
+ }
+
+ /**
+ * Get the green (even rows) component.
+ *
+ * @return a floating point value (guaranteed to be finite)
+ */
+ public float getGreenEven() {
+ return mGreenEven;
+ }
+
+ /**
+ * Get the green (odd rows) component.
+ *
+ * @return a floating point value (guaranteed to be finite)
+ */
+ public float getGreenOdd() {
+ return mGreenOdd;
+ }
+
+ /**
+ * Get the blue component.
+ *
+ * @return a floating point value (guaranteed to be finite)
+ */
+ public float getBlue() {
+ return mBlue;
+ }
+
+ /**
+ * Get the component by the color channel index.
+ *
+ * <p>{@code colorChannel} must be one of {@link #RED}, {@link #GREEN_EVEN}, {@link #GREEN_ODD},
+ * {@link #BLUE}.</p>
+ *
+ * @param colorChannel greater or equal to {@code 0} and less than {@link #COUNT}
+ * @return a floating point value (guaranteed to be finite)
+ *
+ * @throws IllegalArgumentException if {@code colorChannel} was out of range
+ */
+ public float getComponent(final int colorChannel) {
+ if (colorChannel < 0 || colorChannel >= COUNT) {
+ throw new IllegalArgumentException("Color channel out of range");
+ }
+
+ switch (colorChannel) {
+ case RED:
+ return mRed;
+ case GREEN_EVEN:
+ return mGreenEven;
+ case GREEN_ODD:
+ return mGreenOdd;
+ case BLUE:
+ return mBlue;
+ default:
+ throw new AssertionError("Unhandled case " + colorChannel);
+ }
+ }
+
+ /**
+ * Copy the vector into the destination in the order {@code [R, Geven, Godd, B]}.
+ *
+ * @param destination
+ * an array big enough to hold at least {@value #COUNT} elements after the
+ * {@code offset}
+ * @param offset
+ * a non-negative offset into the array
+ *
+ * @throws NullPointerException
+ * If {@code destination} was {@code null}
+ * @throws ArrayIndexOutOfBoundsException
+ * If there's not enough room to write the elements at the specified destination and
+ * offset.
+ */
+ public void copyTo(final float[] destination, final int offset) {
+ checkNotNull(destination, "destination must not be null");
+ if (destination.length + offset < COUNT) {
+ throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
+ }
+
+ destination[offset + RED] = mRed;
+ destination[offset + GREEN_EVEN] = mGreenEven;
+ destination[offset + GREEN_ODD] = mGreenOdd;
+ destination[offset + BLUE] = mBlue;
+ }
+
+ /**
+ * Check if this {@link RggbChannelVector} is equal to another {@link RggbChannelVector}.
+ *
+ * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof RggbChannelVector) {
+ final RggbChannelVector other = (RggbChannelVector) obj;
+ return mRed == other.mRed &&
+ mGreenEven == other.mGreenEven &&
+ mGreenOdd == other.mGreenOdd &&
+ mBlue == other.mBlue;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return Float.floatToIntBits(mRed) ^
+ Float.floatToIntBits(mGreenEven) ^
+ Float.floatToIntBits(mGreenOdd) ^
+ Float.floatToIntBits(mBlue);
+ }
+
+ private final float mRed;
+ private final float mGreenEven;
+ private final float mGreenOdd;
+ private final float mBlue;
+}
--- /dev/null
+/*
+ * 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;
+
+import static com.android.internal.util.Preconditions.*;
+import static android.hardware.camera2.StreamConfigurationMap.checkArgumentFormatInternal;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.impl.HashCodeHelpers;
+import android.util.Size;
+
+/**
+ * Immutable class to store the available stream
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS configurations} to be used
+ * when configuring streams with {@link CameraDevice#configureOutputs}.
+ * <!-- TODO: link to input stream configuration -->
+ *
+ * <p>This is the authoritative list for all input/output formats (and sizes respectively
+ * for that format) that are supported by a camera device.</p>
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ *
+ * @hide
+ */
+public final class StreamConfiguration {
+
+ /**
+ * Create a new {@link StreamConfiguration}.
+ *
+ * @param format image format
+ * @param width image width, in pixels (positive)
+ * @param height image height, in pixels (positive)
+ * @param input true if this is an input configuration, false for output configurations
+ *
+ * @throws IllegalArgumentException
+ * if width/height were not positive
+ * or if the format was not user-defined in ImageFormat/PixelFormat
+ * (IMPL_DEFINED is ok)
+ *
+ * @hide
+ */
+ public StreamConfiguration(
+ final int format, final int width, final int height, final boolean input) {
+ mFormat = checkArgumentFormatInternal(format);
+ mWidth = checkArgumentPositive(width, "width must be positive");
+ mHeight = checkArgumentPositive(width, "height must be positive");
+ mInput = input;
+ }
+
+ /**
+ * Get the image {@code format} in this stream configuration.
+ *
+ * @return an integer format
+ *
+ * @see ImageFormat
+ */
+ public final int getFormat() {
+ return mFormat;
+ }
+
+
+ /**
+ * Return the width of the stream configuration.
+ *
+ * @return width > 0
+ */
+ public int getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Return the height of the stream configuration.
+ *
+ * @return height > 0
+ */
+ public int getHeight() {
+ return mHeight;
+ }
+
+ /**
+ * Convenience method to return the size of this stream configuration.
+ *
+ * @return a Size with positive width and height
+ */
+ public Size getSize() {
+ return new Size(mWidth, mHeight);
+ }
+
+ /**
+ * Determines if this configuration is usable for input streams.
+ *
+ * <p>Input and output stream configurations are not interchangeable;
+ * input stream configurations must be used when configuring inputs.</p>
+ *
+ * @return {@code true} if input configuration, {@code false} otherwise
+ */
+ public boolean isInput() {
+ return mInput;
+ }
+
+ /**
+ * Determines if this configuration is usable for output streams.
+ *
+ * <p>Input and output stream configurations are not interchangeable;
+ * out stream configurations must be used when configuring outputs.</p>
+ *
+ * @return {@code true} if output configuration, {@code false} otherwise
+ *
+ * @see CameraDevice#configureOutputs
+ */
+ public boolean isOutput() {
+ return !mInput;
+ }
+
+ /**
+ * Check if this {@link StreamConfiguration} is equal to another {@link StreamConfiguration}.
+ *
+ * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof StreamConfiguration) {
+ final StreamConfiguration other = (StreamConfiguration) obj;
+ return mFormat == other.mFormat &&
+ mWidth == other.mWidth &&
+ mHeight == other.mHeight &&
+ mInput == other.mInput;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight, mInput ? 1 : 0);
+ }
+
+ private final int mFormat;
+ private final int mWidth;
+ private final int mHeight;
+ private final boolean mInput;
+}
--- /dev/null
+/*
+ * 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;
+
+import static com.android.internal.util.Preconditions.*;
+import static android.hardware.camera2.StreamConfigurationMap.checkArgumentFormatInternal;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.impl.HashCodeHelpers;
+import android.util.Size;
+
+/**
+ * Immutable class to store a time duration for any given format/size combination.
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
+ *
+ * @hide
+ */
+public final class StreamConfigurationDuration {
+
+ /**
+ * Create a new {@link StreamConfigurationDuration}.
+ *
+ * @param format image format
+ * @param width image width, in pixels (positive)
+ * @param height image height, in pixels (positive)
+ * @param durationNs duration in nanoseconds (non-negative)
+ *
+ * @throws IllegalArgumentException
+ * if width/height were not positive, or durationNs was negative
+ * or if the format was not user-defined in ImageFormat/PixelFormat
+ * (IMPL_DEFINED is OK)
+ *
+ *
+ * @hide
+ */
+ public StreamConfigurationDuration(
+ final int format, final int width, final int height, final long durationNs) {
+ mFormat = checkArgumentFormatInternal(format);
+ mWidth = checkArgumentPositive(width, "width must be positive");
+ mHeight = checkArgumentPositive(width, "height must be positive");
+ mDurationNs = checkArgumentNonnegative(durationNs, "durationNs must be non-negative");
+ }
+
+ /**
+ * Get the image {@code format} in this stream configuration duration
+ *
+ * @return an integer format
+ *
+ * @see ImageFormat
+ */
+ public final int getFormat() {
+ return mFormat;
+ }
+
+
+ /**
+ * Return the width of the stream configuration duration.
+ *
+ * @return width > 0
+ */
+ public int getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Return the height of the stream configuration duration
+ *
+ * @return height > 0
+ */
+ public int getHeight() {
+ return mHeight;
+ }
+
+ /**
+ * Convenience method to return the size of this stream configuration duration.
+ *
+ * @return a Size with positive width and height
+ */
+ public Size getSize() {
+ return new Size(mWidth, mHeight);
+ }
+
+ /**
+ * Get the time duration (in nanoseconds).
+ *
+ * @return long >= 0
+ */
+ public long getDuration() {
+ return mDurationNs;
+ }
+
+ /**
+ * Check if this {@link StreamConfigurationDuration} is equal to another
+ * {@link StreamConfigurationDuration}.
+ *
+ * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof StreamConfigurationDuration) {
+ final StreamConfigurationDuration other = (StreamConfigurationDuration) obj;
+ return mFormat == other.mFormat &&
+ mWidth == other.mWidth &&
+ mHeight == other.mHeight &&
+ mDurationNs == other.mDurationNs;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight,
+ (int) mDurationNs, (int)(mDurationNs >>> Integer.SIZE));
+ }
+
+ private final int mFormat;
+ private final int mWidth;
+ private final int mHeight;
+ private final long mDurationNs;
+}
--- /dev/null
+/*
+ * 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;
+
+import android.graphics.ImageFormat;
+import android.graphics.PixelFormat;
+import android.hardware.camera2.impl.HashCodeHelpers;
+import android.view.Surface;
+import android.util.Size;
+
+import java.util.Arrays;
+
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Immutable class to store the available stream
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS configurations} to be used
+ * when configuring streams with {@link CameraDevice#configureOutputs}.
+ * <!-- TODO: link to input stream configuration -->
+ *
+ * <p>This is the authoritative list for all <!-- input/ -->output formats (and sizes respectively
+ * for that format) that are supported by a camera device.</p>
+ *
+ * <p>This also contains the minimum frame durations and stall durations for each format/size
+ * combination that can be used to calculate effective frame rate when submitting multiple captures.
+ * </p>
+ *
+ * <p>An instance of this object is available from {@link CameraCharacteristics} using
+ * the {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS} key and the
+ * {@link CameraCharacteristics#get} method.</p.
+ *
+ * <pre>{@code
+ * CameraCharacteristics characteristics = ...;
+ * StreamConfigurationMap configs = characteristics.get(
+ * CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ * }</pre>
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ * @see CameraDevice#configureOutputs
+ */
+public final class StreamConfigurationMap {
+
+ /**
+ * Create a new {@link StreamConfigurationMap}.
+ *
+ * <p>The array parameters ownership is passed to this object after creation; do not
+ * write to them after this constructor is invoked.</p>
+ *
+ * @param configurations a non-{@code null} array of {@link StreamConfiguration}
+ * @param durations a non-{@code null} array of {@link StreamConfigurationDuration}
+ *
+ * @throws NullPointerException if any of the arguments or subelements were {@code null}
+ *
+ * @hide
+ */
+ public StreamConfigurationMap(
+ StreamConfiguration[] configurations,
+ StreamConfigurationDuration[] durations) {
+ // TODO: format check against ImageFormat/PixelFormat ?
+
+ mConfigurations = checkArrayElementsNotNull(configurations, "configurations");
+ mDurations = checkArrayElementsNotNull(durations, "durations");
+
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Get the image {@code format} output formats in this stream configuration.
+ *
+ * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
+ * or in {@link PixelFormat} (and there is no possibility of collision).</p>
+ *
+ * <p>Formats listed in this array are guaranteed to return true if queried with
+ * {@link #isOutputSupportedFor(int).</p>
+ *
+ * @return an array of integer format
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public final int[] getOutputFormats() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Get the image {@code format} input formats in this stream configuration.
+ *
+ * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
+ * or in {@link PixelFormat} (and there is no possibility of collision).</p>
+ *
+ * @return an array of integer format
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ *
+ * @hide
+ */
+ public final int[] getInputFormats() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Get the supported input sizes for this input format.
+ *
+ * <p>The format must have come from {@link #getInputFormats}; otherwise
+ * {@code null} is returned.</p>
+ *
+ * @param format a format from {@link #getInputFormats}
+ * @return a non-empty array of sizes, or {@code null} if the format was not available.
+ *
+ * @hide
+ */
+ public Size[] getInputSizes(final int format) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Determine whether or not output streams can be
+ * {@link CameraDevice#configureOutputs configured} with a particular user-defined format.
+ *
+ * <p>This method determines that the output {@code format} is supported by the camera device;
+ * each output {@code surface} target may or may not itself support that {@code format}.
+ * Refer to the class which provides the surface for additional documentation.</p>
+ *
+ * <p>Formats for which this returns {@code true} are guaranteed to exist in the result
+ * returned by {@link #getOutputSizes}.</p>
+ *
+ * @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
+ * @return
+ * {@code true} iff using a {@code surface} with this {@code format} will be
+ * supported with {@link CameraDevice#configureOutputs}
+ *
+ * @throws IllegalArgumentException
+ * if the image format was not a defined named constant
+ * from either {@link ImageFormat} or {@link PixelFormat}
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ * @see CameraDevice#configureOutputs
+ */
+ public boolean isOutputSupportedFor(int format) {
+ checkArgumentFormat(format);
+
+ final int[] formats = getOutputFormats();
+ for (int i = 0; i < formats.length; ++i) {
+ if (format == formats[i]) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Determine whether or not output streams can be configured with a particular class
+ * as a consumer.
+ *
+ * <p>The following list is generally usable for outputs:
+ * <ul>
+ * <li>{@link android.media.ImageReader} -
+ * Recommended for image processing or streaming to external resources (such as a file or
+ * network)
+ * <li>{@link android.media.MediaRecorder} -
+ * Recommended for recording video (simple to use)
+ * <li>{@link android.media.MediaCodec} -
+ * Recommended for recording video (more complicated to use, with more flexibility)
+ * <li>{@link android.renderscript.Allocation} -
+ * Recommended for image processing with {@link android.renderscript RenderScript}
+ * <li>{@link android.view.SurfaceHolder} -
+ * Recommended for low-power camera preview with {@link android.view.SurfaceView}
+ * <li>{@link android.graphics.SurfaceTexture} -
+ * Recommended for OpenGL-accelerated preview processing or compositing with
+ * {@link android.view.TextureView}
+ * </ul>
+ * </p>
+ *
+ * <p>Generally speaking this means that creating a {@link Surface} from that class <i>may</i>
+ * provide a producer endpoint that is suitable to be used with
+ * {@link CameraDevice#configureOutputs}.</p>
+ *
+ * <p>Since not all of the above classes support output of all format and size combinations,
+ * the particular combination should be queried with {@link #isOutputSupportedFor(Surface)}.</p>
+ *
+ * @param klass a non-{@code null} {@link Class} object reference
+ * @return {@code true} if this class is supported as an output, {@code false} otherwise
+ *
+ * @throws NullPointerException if {@code klass} was {@code null}
+ *
+ * @see CameraDevice#configureOutputs
+ * @see #isOutputSupportedFor(Surface)
+ */
+ public static <T> boolean isOutputSupportedFor(final Class<T> klass) {
+ checkNotNull(klass, "klass must not be null");
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Determine whether or not the {@code surface} in its current state is suitable to be
+ * {@link CameraDevice#configureOutputs configured} as an output.
+ *
+ * <p>Not all surfaces are usable with the {@link CameraDevice}, and not all configurations
+ * of that {@code surface} are compatible. Some classes that provide the {@code surface} are
+ * compatible with the {@link CameraDevice} in general
+ * (see {@link #isOutputSupportedFor(Class)}, but it is the caller's responsibility to put the
+ * {@code surface} into a state that will be compatible with the {@link CameraDevice}.</p>
+ *
+ * <p>Reasons for a {@code surface} being specifically incompatible might be:
+ * <ul>
+ * <li>Using a format that's not listed by {@link #getOutputFormats}
+ * <li>Using a format/size combination that's not listed by {@link #getOutputSizes}
+ * <li>The {@code surface} itself is not in a state where it can service a new producer.</p>
+ * </li>
+ * </ul>
+ *
+ * This is not an exhaustive list; see the particular class's documentation for further
+ * possible reasons of incompatibility.</p>
+ *
+ * @param surface a non-{@code null} {@link Surface} object reference
+ * @return {@code true} if this is supported, {@code false} otherwise
+ *
+ * @throws NullPointerException if {@code surface} was {@code null}
+ *
+ * @see CameraDevice#configureOutputs
+ * @see #isOutputSupportedFor(Class)
+ */
+ public boolean isOutputSupportedFor(final Surface surface) {
+ checkNotNull(surface, "surface must not be null");
+
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Get a list of sizes compatible with {@code klass} to use as an output.
+ *
+ * <p>Since some of the supported classes may support additional formats beyond
+ * an opaque/implementation-defined (under-the-hood) format; this function only returns
+ * sizes for the implementation-defined format.</p>
+ *
+ * <p>Some classes such as {@link android.media.ImageReader} may only support user-defined
+ * formats; in particular {@link #isOutputSupportedFor(Class)} will return {@code true} for
+ * that class and this method will return an empty array (but not {@code null}).</p>
+ *
+ * <p>If a well-defined format such as {@code NV21} is required, use
+ * {@link #getOutputSizes(int)} instead.</p>
+ *
+ * <p>The {@code klass} should be a supported output, that querying
+ * {@code #isOutputSupportedFor(Class)} should return {@code true}.</p>
+ *
+ * @param klass
+ * a non-{@code null} {@link Class} object reference
+ * @return
+ * an array of supported sizes for implementation-defined formats,
+ * or {@code null} iff the {@code klass} is not a supported output
+ *
+ * @throws NullPointerException if {@code klass} was {@code null}
+ *
+ * @see #isOutputSupportedFor(Class)
+ */
+ public <T> Size[] getOutputSizes(final Class<T> klass) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Get a list of sizes compatible with the requested image {@code format}.
+ *
+ * <p>The {@code format} should be a supported format (one of the formats returned by
+ * {@link #getOutputFormats}).</p>
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @return
+ * an array of supported sizes,
+ * or {@code null} if the {@code format} is not a supported output
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ * @see #getOutputFormats
+ */
+ public Size[] getOutputSizes(final int format) {
+ try {
+ checkArgumentFormatSupported(format, /*output*/true);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
+ * for the format/size combination (in nanoseconds).
+ *
+ * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p>
+ * <p>{@code size} should be one of the ones returned by
+ * {@link #getOutputSizes(int)}.</p>
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @param size an output-compatible size
+ * @return a minimum frame duration {@code >=} 0 in nanoseconds
+ *
+ * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} was {@code null}
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
+ * @see CaptureRequest#SENSOR_FRAME_DURATION
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public long getOutputMinFrameDuration(final int format, final Size size) {
+ checkArgumentFormatSupported(format, /*output*/true);
+
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
+ * for the class/size combination (in nanoseconds).
+ *
+ * <p>This assumes a the {@code klass} is set up to use an implementation-defined format.
+ * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
+ *
+ * <p>{@code klass} should be one of the ones which is supported by
+ * {@link #isOutputSupportedFor(Class)}.</p>
+ *
+ * <p>{@code size} should be one of the ones returned by
+ * {@link #getOutputSizes(int)}.</p>
+ *
+ * @param klass
+ * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a
+ * non-empty array returned by {@link #getOutputSizes(Class)}
+ * @param size an output-compatible size
+ * @return a minimum frame duration {@code >=} 0 in nanoseconds
+ *
+ * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
+ * @see CaptureRequest#SENSOR_FRAME_DURATION
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Get the {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS stall duration}
+ * for the format/size combination (in nanoseconds).
+ *
+ * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p>
+ * <p>{@code size} should be one of the ones returned by
+ * {@link #getOutputSizes(int)}.</p>
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @param size an output-compatible size
+ * @return a stall duration {@code >=} 0 in nanoseconds
+ *
+ * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} was {@code null}
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public long getOutputStallDuration(final int format, final Size size) {
+ checkArgumentFormatSupported(format, /*output*/true);
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Get the {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS stall duration}
+ * for the class/size combination (in nanoseconds).
+ *
+ * <p>This assumes a the {@code klass} is set up to use an implementation-defined format.
+ * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
+ *
+ * <p>{@code klass} should be one of the ones with a non-empty array returned by
+ * {@link #getOutputSizes(Class)}.</p>
+ *
+ * <p>{@code size} should be one of the ones returned by
+ * {@link #getOutputSizes(Class)}.</p>
+ *
+ * @param klass
+ * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a
+ * non-empty array returned by {@link #getOutputSizes(Class)}
+ * @param size an output-compatible size
+ * @return a minimum frame duration {@code >=} 0 in nanoseconds
+ *
+ * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
+ * @see CaptureRequest#SENSOR_FRAME_DURATION
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public <T> long getOutputStallDuration(final Class<T> klass, final Size size) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Check if this {@link StreamConfigurationMap} is equal to another
+ * {@link StreamConfigurationMap}.
+ *
+ * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof StreamConfigurationMap) {
+ final StreamConfigurationMap other = (StreamConfigurationMap) obj;
+ // TODO: do we care about order?
+ return Arrays.equals(mConfigurations, other.mConfigurations) &&
+ Arrays.equals(mDurations, other.mDurations);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ // TODO: do we care about order?
+ return HashCodeHelpers.hashCode(mConfigurations) ^ HashCodeHelpers.hashCode(mDurations);
+ }
+
+ // Check that the argument is supported by #getOutputFormats or #getInputFormats
+ private int checkArgumentFormatSupported(int format, boolean output) {
+ checkArgumentFormat(format);
+
+ int[] formats = output ? getOutputFormats() : getInputFormats();
+ for (int i = 0; i < formats.length; ++i) {
+ if (format == formats[i]) {
+ return format;
+ }
+ }
+
+ throw new IllegalArgumentException(String.format(
+ "format %x is not supported by this stream configuration map", format));
+ }
+
+ /**
+ * Ensures that the format is either user-defined or implementation defined.
+ *
+ * <p>Any invalid/undefined formats will raise an exception.</p>
+ *
+ * @param format image format
+ * @return the format
+ *
+ * @throws IllegalArgumentException if the format was invalid
+ */
+ static int checkArgumentFormatInternal(int format) {
+ if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ return format;
+ }
+
+ return checkArgumentFormat(format);
+ }
+
+ /**
+ * Ensures that the format is user-defined in either ImageFormat or PixelFormat.
+ *
+ * <p>Any invalid/undefined formats will raise an exception, including implementation-defined.
+ * </p>
+ *
+ * <p>Note that {@code @hide} and deprecated formats will not pass this check.</p>
+ *
+ * @param format image format
+ * @return the format
+ *
+ * @throws IllegalArgumentException if the format was not user-defined
+ */
+ static int checkArgumentFormat(int format) {
+ if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
+ throw new IllegalArgumentException(String.format(
+ "format %x was not defined in either ImageFormat or PixelFormat", format));
+ }
+
+ return format;
+ }
+
+ private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
+
+ private final StreamConfiguration[] mConfigurations;
+ private final StreamConfigurationDuration[] mDurations;
+
+}
--- /dev/null
+/*
+ * 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;
+
+import static com.android.internal.util.Preconditions.*;
+
+import android.graphics.PointF;
+import android.hardware.camera2.impl.HashCodeHelpers;
+
+import java.util.Arrays;
+
+/**
+ * Immutable class for describing a {@code 2 x M x 3} tonemap curve of floats.
+ *
+ * <p>This defines red, green, and blue curves that the {@link CameraDevice} will
+ * use as the tonemapping/contrast/gamma curve when {@link CaptureRequest#TONEMAP_MODE} is
+ * set to {@link CameraMetadata#TONEMAP_MODE_CONTRAST_CURVE}.</p>
+ *
+ * <p>The total number of points {@code (Pin, Pout)} for each color channel can be no more than
+ * {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS}.</p>
+ *
+ * <p>The coordinate system for each point is within the inclusive range
+ * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p>
+ *
+ * @see CaptureRequest#TONEMAP_CURVE_BLUE
+ * @see CaptureRequest#TONEMAP_CURVE_GREEN
+ * @see CaptureRequest#TONEMAP_CURVE_RED
+ * @see CameraMetadata#TONEMAP_MODE_CONTRAST_CURVE
+ * @see CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS
+ */
+public final class TonemapCurve {
+ /**
+ * Lower bound tonemap value corresponding to pure black for a single color channel.
+ */
+ public static final float LEVEL_BLACK = 0.0f;
+
+ /**
+ * Upper bound tonemap value corresponding to a pure white for a single color channel.
+ */
+ public static final float LEVEL_WHITE = 1.0f;
+
+ /**
+ * Number of elements in a {@code (Pin, Pout)} point;
+ */
+ public static final int POINT_SIZE = 2;
+
+ /**
+ * Index of the red color channel curve.
+ */
+ public static final int CHANNEL_RED = 0;
+ /**
+ * Index of the green color channel curve.
+ */
+ public static final int CHANNEL_GREEN = 1;
+ /**
+ * Index of the blue color channel curve.
+ */
+ public static final int CHANNEL_BLUE = 2;
+
+ /**
+ * Create a new immutable TonemapCurve instance.
+ *
+ * <p>Values are stored as a contiguous {@code (Pin, Pout}) point.</p>
+ *
+ * <p>All parameters may have independent length but should have at most
+ * {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS} * {@value #POINT_SIZE} elements.</p>
+ *
+ * <p>All sub-elements must be in the inclusive range of
+ * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p>
+ *
+ * <p>This constructor copies the array contents and does not retain ownership of the array.</p>
+ *
+ * @param elements An array of elements whose length is {@code CHANNEL_COUNT * rows * columns}
+ *
+ * @throws IllegalArgumentException
+ * if the {@code elements} array length is invalid,
+ * if any of the subelems are not finite
+ * @throws NullPointerException
+ * if any of the parameters is {@code null}
+ *
+ * @hide
+ */
+ public TonemapCurve(float[] red, float[] green, float[] blue) {
+ // TODO: maxCurvePoints check?
+
+ checkNotNull(red, "red must not be null");
+ checkNotNull(green, "green must not be null");
+ checkNotNull(blue, "blue must not be null");
+
+ checkArgumentArrayLengthDivisibleBy(red, POINT_SIZE, "red");
+ checkArgumentArrayLengthDivisibleBy(green, POINT_SIZE, "green");
+ checkArgumentArrayLengthDivisibleBy(blue, POINT_SIZE, "blue");
+
+ checkArrayElementsInRange(red, LEVEL_BLACK, LEVEL_WHITE, "red");
+ checkArrayElementsInRange(green, LEVEL_BLACK, LEVEL_WHITE, "green");
+ checkArrayElementsInRange(blue, LEVEL_BLACK, LEVEL_WHITE, "blue");
+
+ mRed = Arrays.copyOf(red, red.length);
+ mGreen = Arrays.copyOf(green, green.length);
+ mBlue = Arrays.copyOf(blue, blue.length);
+ }
+
+ private static void checkArgumentArrayLengthDivisibleBy(float[] array,
+ int divisible, String arrayName) {
+ if (array.length % divisible != 0) {
+ throw new IllegalArgumentException(arrayName + " size must be divisible by "
+ + divisible);
+ }
+ }
+
+ private static int checkArgumentColorChannel(int colorChannel) {
+ switch (colorChannel) {
+ case CHANNEL_RED:
+ case CHANNEL_GREEN:
+ case CHANNEL_BLUE:
+ break;
+ default:
+ throw new IllegalArgumentException("colorChannel out of range");
+ }
+
+ return colorChannel;
+ }
+
+ /**
+ * Get the number of points stored in this tonemap curve for the specified color channel.
+ *
+ * @param colorChannel one of {@link #CHANNEL_RED}, {@link #CHANNEL_GREEN}, {@link #CHANNEL_BLUE}
+ * @return number of points stored in this tonemap for that color's curve (>= 0)
+ *
+ * @throws IllegalArgumentException if {@code colorChannel} was out of range
+ */
+ public int getPointCount(int colorChannel) {
+ checkArgumentColorChannel(colorChannel);
+
+ return getCurve(colorChannel).length / POINT_SIZE;
+ }
+
+ /**
+ * Get the point for a color channel at a specified index.
+ *
+ * <p>The index must be at least 0 but no greater than {@link #getPointCount(int)} for
+ * that {@code colorChannel}.</p>
+ *
+ * <p>All returned coordinates in the point are between the range of
+ * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p>
+ *
+ * @param colorChannel {@link #CHANNEL_RED}, {@link #CHANNEL_GREEN}, or {@link #CHANNEL_BLUE}
+ * @param index at least 0 but no greater than {@code getPointCount(colorChannel)}
+ * @return the {@code (Pin, Pout)} pair mapping the tone for that index
+ *
+ * @throws IllegalArgumentException if {@code colorChannel} or {@code index} was out of range
+ *
+ * @see #LEVEL_BLACK
+ * @see #LEVEL_WHITE
+ */
+ public PointF getPoint(int colorChannel, int index) {
+ checkArgumentColorChannel(colorChannel);
+ if (index < 0 || index >= getPointCount(colorChannel)) {
+ throw new IllegalArgumentException("index out of range");
+ }
+
+ final float[] curve = getCurve(colorChannel);
+
+ final float pIn = curve[index * POINT_SIZE + OFFSET_POINT_IN];
+ final float pOut = curve[index * POINT_SIZE + OFFSET_POINT_OUT];
+
+ return new PointF(pIn, pOut);
+ }
+
+ /**
+ * Copy the color curve for a single color channel from this tonemap curve into the destination.
+ *
+ * <p>
+ * <!--The output is encoded the same as in the constructor -->
+ * Values are stored as packed {@code (Pin, Pout}) points, and there are a total of
+ * {@link #getPointCount} points for that respective channel.</p>
+ *
+ * <p>All returned coordinates are between the range of
+ * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p>
+ *
+ * @param destination
+ * an array big enough to hold at least {@link #getPointCount} {@code *}
+ * {@link #POINT_SIZE} elements after the {@code offset}
+ * @param offset
+ * a non-negative offset into the array
+ * @throws NullPointerException
+ * If {@code destination} was {@code null}
+ * @throws IllegalArgumentException
+ * If offset was negative
+ * @throws ArrayIndexOutOfBoundsException
+ * If there's not enough room to write the elements at the specified destination and
+ * offset.
+ *
+ * @see CaptureRequest#TONEMAP_CURVE_BLUE
+ * @see CaptureRequest#TONEMAP_CURVE_RED
+ * @see CaptureRequest#TONEMAP_CURVE_GREEN
+ * @see #LEVEL_BLACK
+ * @see #LEVEL_WHITE
+ */
+ public void copyColorCurve(int colorChannel, float[] destination,
+ int offset) {
+ checkArgumentNonnegative(offset, "offset must not be negative");
+ checkNotNull(destination, "destination must not be null");
+
+ if (destination.length + offset < getPointCount(colorChannel) * POINT_SIZE) {
+ throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
+ }
+
+ float[] curve = getCurve(colorChannel);
+ System.arraycopy(curve, /*srcPos*/0, destination, offset, curve.length);
+ }
+
+ /**
+ * Check if this TonemapCurve is equal to another TonemapCurve.
+ *
+ * <p>Two matrices are equal if and only if all of their elements are
+ * {@link Object#equals equal}.</p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof TonemapCurve) {
+ final TonemapCurve other = (TonemapCurve) obj;
+ return Arrays.equals(mRed, other.mRed) &&
+ Arrays.equals(mGreen, other.mGreen) &&
+ Arrays.equals(mBlue, other.mBlue);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ if (mHashCalculated) {
+ // Avoid re-calculating hash. Data is immutable so this is both legal and faster.
+ return mHashCode;
+ }
+
+ mHashCode = HashCodeHelpers.hashCode(mRed, mGreen, mBlue);
+ mHashCalculated = true;
+
+ return mHashCode;
+ }
+
+ private float[] getCurve(int colorChannel) {
+ switch (colorChannel) {
+ case CHANNEL_RED:
+ return mRed;
+ case CHANNEL_GREEN:
+ return mGreen;
+ case CHANNEL_BLUE:
+ return mBlue;
+ default:
+ throw new AssertionError("colorChannel out of range");
+ }
+ }
+
+ private final static int OFFSET_POINT_IN = 0;
+ private final static int OFFSET_POINT_OUT = 1;
+
+ private final float[] mRed;
+ private final float[] mGreen;
+ private final float[] mBlue;
+
+ private int mHashCode;
+ private boolean mHashCalculated = false;
+};
}
return -1;
}
+
+ /**
+ * Determine whether or not this is a public-visible {@code format}.
+ *
+ * <p>In particular, {@code @hide} formats will return {@code false}.</p>
+ *
+ * <p>Any other formats (including UNKNOWN) will return {@code false}.</p>
+ *
+ * @param format an integer format
+ * @return a boolean
+ *
+ * @hide
+ */
+ public static boolean isPublicFormat(int format) {
+ switch (format) {
+ case RGB_565:
+ case NV16:
+ case YUY2:
+ case YV12:
+ case NV21:
+ case YUV_420_888:
+ case RAW_SENSOR:
+ return true;
+ }
+
+ return false;
+ }
}
info.bytesPerPixel = 1;
break;
default:
- throw new IllegalArgumentException("unkonwon pixel format " + format);
+ throw new IllegalArgumentException("unknown pixel format " + format);
}
}
public int bytesPerPixel;
public int bitsPerPixel;
+
+ /**
+ * Determine whether or not this is a public-visible and non-deprecated {@code format}.
+ *
+ * <p>In particular, {@code @hide} formats will return {@code false}.</p>
+ *
+ * <p>Any other indirect formats (such as {@code TRANSPARENT} or {@code TRANSLUCENT})
+ * will return {@code false}.</p>
+ *
+ * @param format an integer format
+ * @return a boolean
+ *
+ * @hide
+ */
+ public static boolean isPublicFormat(int format) {
+ switch (format) {
+ case RGBA_8888:
+ case RGBX_8888:
+ case RGB_888:
+ case RGB_565:
+ return true;
+ }
+
+ return false;
+ }
}