OSDN Git Service

Add camera face detection API.
authorWu-cheng Li <wuchengli@google.com>
Thu, 21 Jul 2011 18:37:11 +0000 (02:37 +0800)
committerWu-cheng Li <wuchengli@google.com>
Tue, 26 Jul 2011 21:25:35 +0000 (05:25 +0800)
API are still hidden.

bug:4460717
Change-Id: I1a515061f141a89bd61c875257712789fb15d2d4

core/java/android/hardware/Camera.java
core/jni/android_hardware_Camera.cpp
include/camera/CameraParameters.h
libs/camera/CameraParameters.cpp

index a168260..d6dbc15 100644 (file)
@@ -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
@@ -160,6 +166,25 @@ public class Camera {
     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.
      */
     public native static int getNumberOfCameras();
@@ -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) {
index 4687ee0..3328fc8 100644 (file)
@@ -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)
index 83d4f6d..d2f398a 100644 (file)
@@ -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
index 9392cf2..d8fef09 100644 (file)
@@ -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";