Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b3a78b2c authored by Igor Murashkin's avatar Igor Murashkin
Browse files

camera2: Add re-usable data types for camera metadata key/values

Adds new types to public API:
* ColorSpaceTransform
* Range<T>
* SizeF (android.util)
* MeteringRectangle

Minor changes to:
* Size (docs and move to android.util)
* Preconditions (@hide)

Adds helper class:
* HashCodeHelpers

Change-Id: Ied6749a19234f3af9da838f365f8d68d90251aaf
parent 52957450
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -12217,6 +12217,14 @@ package android.hardware.camera2 {
    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
  }
  public final class ColorSpaceTransform {
    ctor public ColorSpaceTransform(android.hardware.camera2.Rational[]);
    ctor public ColorSpaceTransform(int[]);
    method public void copyElements(android.hardware.camera2.Rational[], int);
    method public void copyElements(int[], int);
    method public android.hardware.camera2.Rational getElement(int, int);
  }
  public final class Face {
    method public android.graphics.Rect getBounds();
    method public int getId();
@@ -12229,6 +12237,21 @@ package android.hardware.camera2 {
    field public static final int SCORE_MIN = 1; // 0x1
  }
  public final class MeteringRectangle {
    ctor public MeteringRectangle(int, int, int, int, int);
    ctor public MeteringRectangle(android.graphics.Point, android.util.Size, int);
    ctor public MeteringRectangle(android.graphics.Rect, int);
    method public boolean equals(android.hardware.camera2.MeteringRectangle);
    method public int getHeight();
    method public int getMeteringWeight();
    method public android.graphics.Rect getRect();
    method public android.util.Size getSize();
    method public android.graphics.Point getUpperLeftPoint();
    method public int getWidth();
    method public int getX();
    method public int getY();
  }
  public final class Rational {
    ctor public Rational(int, int);
    method public int getDenominator();
@@ -28709,6 +28732,25 @@ package android.util {
    method public void set(T, V);
  }
  public final class Range {
    ctor public Range(T, T);
    method public static android.util.Range<T> create(T, T);
    method public T getLower();
    method public T getUpper();
  }
  public final class Size {
    ctor public Size(int, int);
    method public int getHeight();
    method public int getWidth();
  }
  public final class SizeF {
    ctor public SizeF(float, float);
    method public float getHeight();
    method public float getWidth();
  }
  public class SparseArray implements java.lang.Cloneable {
    ctor public SparseArray();
    ctor public SparseArray(int);
+239 −0
Original line number Diff line number Diff line
/*
 * 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 for describing a 3x3 matrix of {@link Rational} values in row-major order.
 *
 * <p>This matrix maps a transform from one color space to another. For the particular color space
 * source and target, see the appropriate camera metadata documentation for the key that provides
 * this value.</p>
 *
 * @see CameraMetadata
 */
public final class ColorSpaceTransform {

    /** The number of rows in this matrix. */
    private static final int ROWS = 3;

    /** The number of columns in this matrix. */
    private static final int COLUMNS = 3;

    /** The number of total Rational elements in this matrix. */
    private static final int COUNT = ROWS * COLUMNS;

    /** Number of int elements in a rational. */
    private static final int RATIONAL_SIZE = 2;

    /** Numerator offset inside a rational (pair). */
    private static final int OFFSET_NUMERATOR = 0;

    /** Denominator offset inside a rational (pair). */
    private static final int OFFSET_DENOMINATOR = 1;

    /** Number of int elements in this matrix. */
    private static final int COUNT_INT = ROWS * COLUMNS * RATIONAL_SIZE;

    /**
     * Create a new immutable {@link ColorSpaceTransform} instance from a {@link Rational} array.
     *
     * <p>The elements must be stored in a row-major order.</p>
     *
     * @param elements An array of {@code 9} elements
     *
     * @throws IllegalArgumentException
     *            if the count of {@code elements} is not {@code 9}
     * @throws NullPointerException
     *            if {@code elements} or any sub-element is {@code null}
     */
    public ColorSpaceTransform(Rational[] elements) {

        checkNotNull(elements, "elements must not be null");
        if (elements.length != COUNT) {
            throw new IllegalArgumentException("elements must be " + COUNT + " length");
        }

        mElements = new int[COUNT_INT];

        for (int i = 0; i < elements.length; ++i) {
            checkNotNull(elements, "element[" + i + "] must not be null");
            mElements[i * RATIONAL_SIZE + OFFSET_NUMERATOR] = elements[i].getNumerator();
            mElements[i * RATIONAL_SIZE + OFFSET_DENOMINATOR] = elements[i].getDenominator();
        }
    }

    /**
     * Create a new immutable {@link ColorSpaceTransform} instance from an {@code int} array.
     *
     * <p>The elements must be stored in a row-major order. Each rational is stored
     * contiguously as a {@code (numerator, denominator)} pair.</p>
     *
     * <p>In particular:<pre>{@code
     * int[] elements = new int[
     *     N11, D11, N12, D12, N13, D13,
     *     N21, D21, N22, D22, N23, D23,
     *     N31, D31, N32, D32, N33, D33
     * ];
     *
     * new ColorSpaceTransform(elements)}</pre>
     *
     * where {@code Nij} and {@code Dij} is the numerator and denominator for row {@code i} and
     * column {@code j}.</p>
     *
     * @param elements An array of {@code 18} elements
     *
     * @throws IllegalArgumentException
     *            if the count of {@code elements} is not {@code 18}
     * @throws NullPointerException
     *            if {@code elements} is {@code null}
     */
    public ColorSpaceTransform(int[] elements) {
        checkNotNull(elements, "elements must not be null");
        if (elements.length != COUNT_INT) {
            throw new IllegalArgumentException("elements must be " + COUNT_INT + " length");
        }

        for (int i = 0; i < elements.length; ++i) {
            checkNotNull(elements, "element " + i + " must not be null");
        }

        mElements = Arrays.copyOf(elements, elements.length);
    }

    /**
     * Get an element of this matrix by its row and column.
     *
     * <p>The rows must be within the range [0, 3),
     * and the column must be within the range [0, 3).</p>
     *
     * @return element (non-{@code null})
     *
     * @throws IllegalArgumentException if column or row was out of range
     */
    public Rational getElement(int column, int row) {
        if (column < 0 || column >= COLUMNS) {
            throw new IllegalArgumentException("column out of range");
        } else if (row < 0 || row >= ROWS) {
            throw new IllegalArgumentException("row out of range");
        }

        int numerator = mElements[row * ROWS * RATIONAL_SIZE + column + OFFSET_NUMERATOR];
        int denominator = mElements[row * ROWS * RATIONAL_SIZE + column + OFFSET_DENOMINATOR];

        return new Rational(numerator, denominator);
    }

    /**
     * Copy the {@link Rational} elements in row-major order from this matrix into the destination.
     *
     * @param destination
     *          an array big enough to hold at least {@code 9} 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 copyElements(Rational[] destination, int offset) {
        checkArgumentNonnegative(offset, "offset must not be negative");
        checkNotNull(destination, "destination must not be null");
        if (destination.length + offset < COUNT) {
            throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
        }

        for (int i = 0, j = 0; i < COUNT; ++i, j += RATIONAL_SIZE) {
            int numerator = mElements[j + OFFSET_NUMERATOR];
            int denominator = mElements[j + OFFSET_DENOMINATOR];

            destination[i + offset] = new Rational(numerator, denominator);
        }
    }

    /**
     * Copy the {@link Rational} elements in row-major order from this matrix into the destination.
     *
     * <p>Each element is stored as a contiguous rational packed as a
     * {@code (numerator, denominator)} pair of ints, identical to the
     * {@link ColorSpaceTransform#ColorSpaceTransform(int[]) constructor}.</p>
     *
     * @param destination
     *          an array big enough to hold at least {@code 18} 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.
     *
     * @see ColorSpaceTransform#ColorSpaceTransform(int[])
     */
    public void copyElements(int[] destination, int offset) {
        checkArgumentNonnegative(offset, "offset must not be negative");
        checkNotNull(destination, "destination must not be null");
        if (destination.length + offset < COUNT_INT) {
            throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
        }

        // Manual copy faster than System#arraycopy for very small loops
        for (int i = 0; i < COUNT_INT; ++i) {
            destination[i + offset] = mElements[i];
        }
    }

    /**
     * Check if this {@link ColorSpaceTransform} is equal to another {@link ColorSpaceTransform}.
     *
     * <p>Two color space transforms 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(final Object obj) {
        if (obj == null) {
            return false;
        }
        if (this == obj) {
            return true;
        }
        if (obj instanceof ColorSpaceTransform) {
            final ColorSpaceTransform other = (ColorSpaceTransform) obj;
            return Arrays.equals(mElements, other.mElements);
        }
        return false;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {
        return HashCodeHelpers.hashCode(mElements);
    }

    private final int[] mElements;
};
+224 −0
Original line number Diff line number Diff line
/*
 * 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.util.Size;
import static com.android.internal.util.Preconditions.*;

import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.camera2.impl.HashCodeHelpers;

/**
 * An immutable class to represent a rectangle {@code (x,y, width, height)} with an
 * additional weight component.
 *
 * </p>The rectangle is defined to be inclusive of the specified coordinates.</p>
 *
 * <p>When used with a {@link CaptureRequest}, the coordinate system is based on the active pixel
 * array, with {@code (0,0)} being the top-left pixel in the
 * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE active pixel array}, and
 * {@code (android.sensor.info.activeArraySize.width - 1,
 * android.sensor.info.activeArraySize.height - 1)}
 * being the bottom-right pixel in the active pixel array.
 * </p>
 *
 * <p>The metering weight is nonnegative.</p>
 */
public final class MeteringRectangle {

    private final int mX;
    private final int mY;
    private final int mWidth;
    private final int mHeight;
    private final int mWeight;

    /**
     * Create a new metering rectangle.
     *
     * @param x coordinate >= 0
     * @param y coordinate >= 0
     * @param width width >= 0
     * @param height height >= 0
     * @param meteringWeight weight >= 0
     *
     * @throws IllegalArgumentException if any of the parameters were non-negative
     */
    public MeteringRectangle(int x, int y, int width, int height, int meteringWeight) {
        mX = checkArgumentNonnegative(x, "x must be nonnegative");
        mY = checkArgumentNonnegative(y, "y must be nonnegative");
        mWidth = checkArgumentNonnegative(width, "width must be nonnegative");
        mHeight = checkArgumentNonnegative(height, "height must be nonnegative");
        mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
    }

    /**
     * Create a new metering rectangle.
     *
     * @param xy a non-{@code null} {@link Point} with both x,y >= 0
     * @param dimensions a non-{@code null} {@link android.util.Size Size} with width, height >= 0
     * @param meteringWeight weight >= 0
     *
     * @throws IllegalArgumentException if any of the parameters were non-negative
     * @throws NullPointerException if any of the arguments were null
     */
    public MeteringRectangle(Point xy, Size dimensions, int meteringWeight) {
        checkNotNull(xy, "xy must not be null");
        checkNotNull(dimensions, "dimensions must not be null");

        mX = checkArgumentNonnegative(xy.x, "x must be nonnegative");
        mY = checkArgumentNonnegative(xy.y, "y must be nonnegative");
        mWidth = checkArgumentNonnegative(dimensions.getWidth(), "width must be nonnegative");
        mHeight = checkArgumentNonnegative(dimensions.getHeight(), "height must be nonnegative");
        mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
    }

    /**
     * Create a new metering rectangle.
     *
     * @param rect a non-{@code null} rectangle with all x,y,w,h dimensions >= 0
     * @param meteringWeight weight >= 0
     *
     * @throws IllegalArgumentException if any of the parameters were non-negative
     * @throws NullPointerException if any of the arguments were null
     */
    public MeteringRectangle(Rect rect, int meteringWeight) {
        checkNotNull(rect, "rect must not be null");

        mX = checkArgumentNonnegative(rect.left, "rect.left must be nonnegative");
        mY = checkArgumentNonnegative(rect.top, "rect.top must be nonnegative");
        mWidth = checkArgumentNonnegative(rect.width(), "rect.width must be nonnegative");
        mHeight = checkArgumentNonnegative(rect.height(), "rect.height must be nonnegative");
        mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
    }

    /**
     * Return the X coordinate of the left side of the rectangle.
     *
     * @return x coordinate >= 0
     */
    public int getX() {
        return mX;
    }

    /**
     * Return the Y coordinate of the upper side of the rectangle.
     *
     * @return y coordinate >= 0
     */
    public int getY() {
        return mY;
    }

    /**
     * Return the width of the rectangle.
     *
     * @return width >= 0
     */
    public int getWidth() {
        return mWidth;
    }

    /**
     * Return the height of the rectangle.
     *
     * @return height >= 0
     */
    public int getHeight() {
        return mHeight;
    }

    /**
     * Return the metering weight of the rectangle.
     *
     * @return weight >= 0
     */
    public int getMeteringWeight() {
        return mWeight;
    }

    /**
     * Convenience method to create the upper-left (X,Y) coordinate as a {@link Point}.
     *
     * @return {@code (x,y)} point with both x,y >= 0
     */
    public Point getUpperLeftPoint() {
        return new Point(mX, mY);
    }

    /**
     * Convenience method to create the size from this metering rectangle.
     *
     * <p>This strips away the X,Y,weight from the rectangle.</p>
     *
     * @return a Size with non-negative width and height
     */
    public Size getSize() {
        return new Size(mWidth, mHeight);
    }

    /**
     * Convenience method to create a {@link Rect} from this metering rectangle.
     *
     * <p>This strips away the weight from the rectangle.</p>
     *
     * @return a {@link Rect} with non-negative x1, y1, x2, y2
     */
    public Rect getRect() {
        return new Rect(mX, mY, mX + mWidth, mY + mHeight);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(final Object other) {
        if (other instanceof MeteringRectangle) {
            return equals(other);
        }
        return false;
    }

    /**
     * Compare two metering rectangles to see if they are equal.
     *
     * Two weighted rectangles are only considered equal if each of their components
     * (x, y, width, height, weight) is respectively equal.
     *
     * @param other Another MeteringRectangle
     *
     * @return {@code true} if the metering rectangles are equal, {@code false} otherwise
     */
    public boolean equals(final MeteringRectangle other) {
        if (other == null) {
            return false;
        }

        return (mX == other.mX
                && mY == other.mY
                && mWidth == other.mWidth
                && mHeight == other.mHeight
                && mWidth == other.mWidth);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {
        return HashCodeHelpers.hashCode(mX, mY, mWidth, mHeight, mWeight);
    }
}
+41 −16
Original line number Diff line number Diff line
@@ -16,32 +16,55 @@

package android.hardware.camera2;

// TODO: Delete this class, since it was moved to android.util as public API

/**
 * A simple immutable class for describing the dimensions of camera image
 * buffers.
 * Immutable class for describing width and height dimensions in pixels.
 *
 * @hide
 */
public final class Size {
    /**
     * Create a new immutable Size instance
     * Create a new immutable Size instance.
     *
     * @param width The width to store in the Size instance
     * @param height The height to store in the Size instance
     * @param width The width of the size, in pixels
     * @param height The height of the size, in pixels
     */
    public Size(int width, int height) {
    public Size(final int width, final int height) {
        mWidth = width;
        mHeight = height;
    }

    /**
     * Get the width of the size (in pixels).
     * @return width
     */
    public final int getWidth() {
        return mWidth;
    }

    /**
     * Get the height of the size (in pixels).
     * @return height
     */
    public final int getHeight() {
        return mHeight;
    }

    /**
     * Check if this size is equal to another size.
     * <p>
     * Two sizes are equal if and only if both their widths and heights are
     * equal.
     * </p>
     * <p>
     * A size object is never equal to any other type of object.
     * </p>
     *
     * @return {@code true} if the objects were equal, {@code false} otherwise
     */
    @Override
    public boolean equals(Object obj) {
    public boolean equals(final Object obj) {
        if (obj == null) {
            return false;
        }
@@ -49,27 +72,29 @@ public final class Size {
            return true;
        }
        if (obj instanceof Size) {
            Size other = (Size) obj;
            final Size other = (Size) obj;
            return mWidth == other.mWidth && mHeight == other.mHeight;
        }
        return false;
    }

    /**
     * Return the size represented as a string with the format {@code "WxH"}
     *
     * @return string representation of the size
     */
    @Override
    public String toString() {
        return mWidth + "x" + mHeight;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {
        final long INT_MASK = 0xffffffffL;

        long asLong = INT_MASK & mWidth;
        asLong <<= 32;

        asLong |= (INT_MASK & mHeight);

        return ((Long)asLong).hashCode();
        // assuming most sizes are <2^16, doing a rotate will give us perfect hashing
        return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
    }

    private final int mWidth;
+143 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading