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

Commit 4c2292ef authored by Wu-cheng Li's avatar Wu-cheng Li
Browse files

Add camera face detection API.

API are still hidden.

bug:4460717
Change-Id: I1a515061f141a89bd61c875257712789fb15d2d4
parent 83f463f6
Loading
Loading
Loading
Loading
+193 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.hardware;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.graphics.ImageFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.os.Handler;
@@ -35,6 +36,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;


/**
 * The Camera class is used to set image capture settings, start/stop preview,
 * snap pictures, and retrieve frames for encoding for video.  This class is a
@@ -128,7 +130,9 @@ public class Camera {
    private static final int CAMERA_MSG_POSTVIEW_FRAME   = 0x040;
    private static final int CAMERA_MSG_RAW_IMAGE        = 0x080;
    private static final int CAMERA_MSG_COMPRESSED_IMAGE = 0x100;
    private static final int CAMERA_MSG_ALL_MSGS         = 0x1FF;
    private static final int CAMERA_MSG_RAW_IMAGE_NOTIFY = 0x200;
    private static final int CAMERA_MSG_FACE             = 0x400;
    private static final int CAMERA_MSG_ALL_MSGS         = 0x4FF;

    private int mNativeContext; // accessed by native methods
    private EventHandler mEventHandler;
@@ -139,9 +143,11 @@ public class Camera {
    private PictureCallback mPostviewCallback;
    private AutoFocusCallback mAutoFocusCallback;
    private OnZoomChangeListener mZoomListener;
    private FaceDetectionListener mFaceListener;
    private ErrorCallback mErrorCallback;
    private boolean mOneShot;
    private boolean mWithBuffer;
    private boolean mFaceDetectionRunning = false;

    /**
     * Broadcast Action:  A new picture is taken by the camera, and the entry of
@@ -159,6 +165,25 @@ public class Camera {
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";

    /**
     * Hardware face detection. It does not use much CPU.
     *
     * @see #startFaceDetection(int)
     * @see Parameters#getMaxNumDetectedFaces(int)
     * @see #CAMERA_FACE_DETECTION_SW
     * @hide
     */
    public static final int CAMERA_FACE_DETECTION_HW = 0;

    /**
     * Software face detection. It uses some CPU. Applications must use
     * {@link #setPreviewTexture(SurfaceTexture)} for preview in this mode.
     *
     * @see #CAMERA_FACE_DETECTION_HW
     * @hide
     */
    public static final int CAMERA_FACE_DETECTION_SW = 1;

    /**
     * Returns the number of physical cameras available on this device.
     */
@@ -295,6 +320,7 @@ public class Camera {
     */
    public final void release() {
        native_release();
        mFaceDetectionRunning = false;
    }

    /**
@@ -460,7 +486,12 @@ public class Camera {
     * Stops capturing and drawing preview frames to the surface, and
     * resets the camera for a future call to {@link #startPreview()}.
     */
    public native final void stopPreview();
    public final void stopPreview() {
        _stopPreview();
        mFaceDetectionRunning = false;
    }

    private native final void _stopPreview();

    /**
     * Return current preview state.
@@ -690,6 +721,12 @@ public class Camera {
                }
                return;

            case CAMERA_MSG_FACE:
                if (mFaceListener != null) {
                    mFaceListener.onFaceDetection((FaceMetadata[])msg.obj, mCamera);
                }
                return;

            case CAMERA_MSG_ERROR :
                Log.e(TAG, "Error " + msg.arg1);
                if (mErrorCallback != null) {
@@ -1031,6 +1068,139 @@ public class Camera {
        mZoomListener = listener;
    }

    /**
     * Callback interface for face detected in the preview frame.
     *
     * @hide
     */
    public interface FaceDetectionListener
    {
        /**
         * Notify the listener of the detected faces in the preview frame.
         *
         * @param faceMetadata the face information. The list is sorted by the
         *        score. The highest score is the first element.
         * @param camera  the Camera service object
         */
        void onFaceDetection(FaceMetadata[] faceMetadata, Camera camera);
    }

    /**
     * Registers a listener to be notified about the face detected of the
     * preview frame.
     *
     * @param listener the listener to notify
     * @see #startFaceDetection(int)
     * @hide
     */
    public final void setFaceDetectionListener(FaceDetectionListener listener)
    {
        mFaceListener = listener;
    }

    /**
     * Start the face detection. This should be called after preview is started.
     * The camera will notify {@link FaceDetectionListener} of the detected
     * faces in the preview frame. The detected faces may be the same as the
     * previous ones. Applications should call {@link #stopFaceDetection} to
     * stop the face detection. This method is supported if {@link
     * Parameters#getMaxNumDetectedFaces(int)} returns a number larger than 0.
     * Hardware and software face detection cannot be used at the same time.
     * If the face detection has started, apps should not call this again.
     *
     * In hardware face detection mode, {@link Parameters#setWhiteBalance(String)},
     * {@link Parameters#setFocusAreas(List)}, and {@link Parameters#setMeteringAreas(List)}
     * have no effect.
     *
     * @param type face detection type. This can be either {@link
     *        #CAMERA_FACE_DETECTION_HW} or {@link #CAMERA_FACE_DETECTION_SW}
     * @throws IllegalArgumentException if the face detection type is
     *         unsupported or invalid.
     * @throws RuntimeException if the method fails or the face detection is
     *         already running.
     * @see #CAMERA_FACE_DETECTION_HW
     * @see #CAMERA_FACE_DETECTION_SW
     * @see FaceDetectionListener
     * @see #stopFaceDetection()
     * @see Parameters#getMaxNumDetectedFaces(int)
     * @hide
     */
    public final void startFaceDetection(int type) {
        if (type != CAMERA_FACE_DETECTION_HW && type != CAMERA_FACE_DETECTION_SW) {
            throw new IllegalArgumentException("Invalid face detection type " + type);
        }
        if (mFaceDetectionRunning) {
            throw new RuntimeException("Face detection is already running");
        }
        _startFaceDetection(type);
        mFaceDetectionRunning = true;
    }

    /**
     * Stop the face detection.
     *
     * @see #startFaceDetection(int)
     * @hide
     */
    public final void stopFaceDetection() {
        _stopFaceDetection();
        mFaceDetectionRunning = false;
    }

    private native final void _startFaceDetection(int type);
    private native final void _stopFaceDetection();

    /**
     * The information of a face.
     *
     * @hide
     */
    public static class FaceMetadata {
        /**
         * Bounds of the face. (-1000, -1000) represents the top-left of the
         * camera field of view, and (1000, 1000) represents the bottom-right of
         * the field of view. This is supported by both hardware and software
         * face detection.
         *
         * @see #startFaceDetection(int)
         */
        Rect face;

        /**
         * The confidence level of the face. The range is 1 to 100. 100 is the
         * highest confidence. This is supported by both hardware and software
         * face detction.
         *
         * @see #startFaceDetection(int)
         */
        int score;

        /**
         * An unique id per face while the face is visible to the tracker. If
         * the face leaves the field-of-view and comes back, it will get a new
         * id. If the value is 0, id is not supported.
         */
        int id;

        /**
         * The coordinates of the center of the left eye. null if this is not
         * supported.
         */
        Point leftEye;

        /**
         * The coordinates of the center of the right eye. null if this is not
         * supported.
         */
        Point rightEye;

        /**
         * The coordinates of the center of the mouth. null if this is not
         * supported.
         */
        Point mouth;
    }

    // Error codes match the enum in include/ui/Camera.h

    /**
@@ -1295,6 +1465,8 @@ public class Camera {
        private static final String KEY_VIDEO_SIZE = "video-size";
        private static final String KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO =
                                            "preferred-preview-size-for-video";
        private static final String KEY_MAX_NUM_DETECTED_FACES_HW = "max-num-detected-faces-hw";
        private static final String KEY_MAX_NUM_DETECTED_FACES_SW = "max-num-detected-faces-sw";

        // Parameter key suffix for supported values.
        private static final String SUPPORTED_VALUES_SUFFIX = "-values";
@@ -2977,6 +3149,25 @@ public class Camera {
            set(KEY_METERING_AREAS, meteringAreas);
        }

        /**
         * Gets the maximum number of detected faces supported. This is the
         * maximum length of the list returned from {@link FaceDetectionListener}.
         * If the return value is 0, face detection of the specified type is not
         * supported.
         *
         * @return the maximum number of detected face supported by the camera.
         * @see #startFaceDetection(int)
         * @hide
         */
        public int getMaxNumDetectedFaces(int type) {
            if (type == CAMERA_FACE_DETECTION_HW) {
                return getInt(KEY_MAX_NUM_DETECTED_FACES_HW, 0);
            } else if (type == CAMERA_FACE_DETECTION_SW){
                return getInt(KEY_MAX_NUM_DETECTED_FACES_SW, 0);
            }
            throw new IllegalArgumentException("Invalid face detection type " + type);
        }

        // Splits a comma delimited string to an ArrayList of String.
        // Return null if the passing string is null or the size is 0.
        private ArrayList<String> split(String str) {
+48 −1
Original line number Diff line number Diff line
@@ -38,6 +38,12 @@ struct fields_t {
    jfieldID    surfaceTexture;
    jfieldID    facing;
    jfieldID    orientation;
    jfieldID    face_rectangle;
    jfieldID    face_score;
    jfieldID    rect_left;
    jfieldID    rect_top;
    jfieldID    rect_right;
    jfieldID    rect_bottom;
    jmethodID   post_event;
};

@@ -708,6 +714,35 @@ static void android_hardware_Camera_setDisplayOrientation(JNIEnv *env, jobject t
    }
}

static void android_hardware_Camera_startFaceDetection(JNIEnv *env, jobject thiz,
        jint type, jobjectArray face)
{
    LOGV("startFaceDetection");
    JNICameraContext* context;
    sp<Camera> camera = get_native_camera(env, thiz, &context);
    if (camera == 0) return;

    status_t rc = camera->sendCommand(CAMERA_CMD_START_FACE_DETECTION, type, 0);
    if (rc == BAD_VALUE) {
        char msg[64];
        snprintf(msg, sizeof(msg), "invalid face detection type=%d", type);
        jniThrowException(env, "java/lang/IllegalArgumentException", msg);
    } else if (rc != NO_ERROR) {
        jniThrowRuntimeException(env, "start face detection failed");
    }
}

static void android_hardware_Camera_stopFaceDetection(JNIEnv *env, jobject thiz)
{
    LOGV("stopFaceDetection");
    sp<Camera> camera = get_native_camera(env, thiz, NULL);
    if (camera == 0) return;

    if (camera->sendCommand(CAMERA_CMD_STOP_FACE_DETECTION, 0, 0) != NO_ERROR) {
        jniThrowRuntimeException(env, "stop face detection failed");
    }
}

//-------------------------------------------------

static JNINativeMethod camMethods[] = {
@@ -732,7 +767,7 @@ static JNINativeMethod camMethods[] = {
  { "startPreview",
    "()V",
    (void *)android_hardware_Camera_startPreview },
  { "stopPreview",
  { "_stopPreview",
    "()V",
    (void *)android_hardware_Camera_stopPreview },
  { "previewEnabled",
@@ -777,6 +812,12 @@ static JNINativeMethod camMethods[] = {
  { "setDisplayOrientation",
    "(I)V",
    (void *)android_hardware_Camera_setDisplayOrientation },
  { "_startFaceDetection",
    "(I)V",
    (void *)android_hardware_Camera_startFaceDetection },
  { "_stopFaceDetection",
    "()V",
    (void *)android_hardware_Camera_stopFaceDetection},
};

struct field {
@@ -818,6 +859,12 @@ int register_android_hardware_Camera(JNIEnv *env)
          ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I", &fields.surfaceTexture },
        { "android/hardware/Camera$CameraInfo", "facing",   "I", &fields.facing },
        { "android/hardware/Camera$CameraInfo", "orientation",   "I", &fields.orientation },
        { "android/hardware/Camera$FaceMetadata", "face", "Landroid/graphics/Rect;", &fields.face_rectangle },
        { "android/hardware/Camera$FaceMetadata", "score", "I", &fields.face_score },
        { "android/graphics/Rect", "left", "I", &fields.rect_left },
        { "android/graphics/Rect", "top", "I", &fields.rect_top },
        { "android/graphics/Rect", "right", "I", &fields.rect_right },
        { "android/graphics/Rect", "bottom", "I", &fields.rect_bottom },
    };

    if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
+10 −0
Original line number Diff line number Diff line
@@ -455,6 +455,16 @@ public:
    // Example: "176x144,1280x720". Read only.
    static const char KEY_SUPPORTED_VIDEO_SIZES[];

    // The maximum number of detected faces supported by hardware face
    // detection. If the value is 0, hardware face detection is not supported.
    // Example: "5". Read only
    static const char KEY_MAX_NUM_DETECTED_FACES_HW[];

    // The maximum number of detected faces supported by software face
    // detection. If the value is 0, software face detection is not supported.
    // Example: "5". Read only
    static const char KEY_MAX_NUM_DETECTED_FACES_SW[];

    // Preferred preview frame size in pixels for video recording.
    // The width and height must be one of the supported sizes retrieved
    // via KEY_SUPPORTED_PREVIEW_SIZES. This key can be used only when
+2 −0
Original line number Diff line number Diff line
@@ -84,6 +84,8 @@ const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format";
const char CameraParameters::KEY_VIDEO_SIZE[] = "video-size";
const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values";
const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video";
const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW[] = "max-num-detected-faces-hw";
const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW[] = "max-num-detected-faces-sw";

const char CameraParameters::TRUE[] = "true";
const char CameraParameters::FALSE[] = "false";