Add camera face detection API.
API are still hidden. bug:4460717 Change-Id: I1a515061f141a89bd61c875257712789fb15d2d4
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user