Loading core/java/android/hardware/camera2/impl/CameraMetadataNative.java +80 −6 Original line number Original line Diff line number Diff line Loading @@ -67,6 +67,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.ArrayList; import java.util.HashMap; import java.util.HashMap; import java.util.List; /** /** * Implementation of camera metadata marshal/unmarshal across Binder to * Implementation of camera metadata marshal/unmarshal across Binder to Loading Loading @@ -227,6 +228,7 @@ public class CameraMetadataNative implements Parcelable { private static final String CELLID_PROCESS = "CELLID"; private static final String CELLID_PROCESS = "CELLID"; private static final String GPS_PROCESS = "GPS"; private static final String GPS_PROCESS = "GPS"; private static final int FACE_LANDMARK_SIZE = 6; private static String translateLocationProviderToProcess(final String provider) { private static String translateLocationProviderToProcess(final String provider) { if (provider == null) { if (provider == null) { Loading Loading @@ -347,7 +349,7 @@ public class CameraMetadataNative implements Parcelable { // Check if key has been overridden to use a wrapper class on the java side. // Check if key has been overridden to use a wrapper class on the java side. GetCommand g = sGetCommandMap.get(key); GetCommand g = sGetCommandMap.get(key); if (g != null) { if (g != null) { return (T) g.getValue(this, key); return g.getValue(this, key); } } return getBase(key); return getBase(key); } } Loading Loading @@ -587,9 +589,71 @@ public class CameraMetadataNative implements Parcelable { return availableFormats; return availableFormats; } } private Face[] getFaces() { private boolean setFaces(Face[] faces) { final int FACE_LANDMARK_SIZE = 6; if (faces == null) { return false; } int numFaces = faces.length; // Detect if all faces are SIMPLE or not; count # of valid faces boolean fullMode = true; for (Face face : faces) { if (face == null) { numFaces--; Log.w(TAG, "setFaces - null face detected, skipping"); continue; } if (face.getId() == Face.ID_UNSUPPORTED) { fullMode = false; } } Rect[] faceRectangles = new Rect[numFaces]; byte[] faceScores = new byte[numFaces]; int[] faceIds = null; int[] faceLandmarks = null; if (fullMode) { faceIds = new int[numFaces]; faceLandmarks = new int[numFaces * FACE_LANDMARK_SIZE]; } int i = 0; for (Face face : faces) { if (face == null) { continue; } faceRectangles[i] = face.getBounds(); faceScores[i] = (byte)face.getScore(); if (fullMode) { faceIds[i] = face.getId(); int j = 0; faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().x; faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().y; faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().x; faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().y; faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().x; faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().y; } i++; } set(CaptureResult.STATISTICS_FACE_RECTANGLES, faceRectangles); set(CaptureResult.STATISTICS_FACE_IDS, faceIds); set(CaptureResult.STATISTICS_FACE_LANDMARKS, faceLandmarks); set(CaptureResult.STATISTICS_FACE_SCORES, faceScores); return true; } private Face[] getFaces() { Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE); Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE); if (faceDetectMode == null) { if (faceDetectMode == null) { Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE"); Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE"); Loading Loading @@ -653,9 +717,12 @@ public class CameraMetadataNative implements Parcelable { if (faceScores[i] <= Face.SCORE_MAX && if (faceScores[i] <= Face.SCORE_MAX && faceScores[i] >= Face.SCORE_MIN && faceScores[i] >= Face.SCORE_MIN && faceIds[i] >= 0) { faceIds[i] >= 0) { Point leftEye = new Point(faceLandmarks[i*6], faceLandmarks[i*6+1]); Point leftEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE], Point rightEye = new Point(faceLandmarks[i*6+2], faceLandmarks[i*6+3]); faceLandmarks[i*FACE_LANDMARK_SIZE+1]); Point mouth = new Point(faceLandmarks[i*6+4], faceLandmarks[i*6+5]); Point rightEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+2], faceLandmarks[i*FACE_LANDMARK_SIZE+3]); Point mouth = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+4], faceLandmarks[i*FACE_LANDMARK_SIZE+5]); Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i], Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i], leftEye, rightEye, mouth); leftEye, rightEye, mouth); faceList.add(face); faceList.add(face); Loading Loading @@ -865,6 +932,13 @@ public class CameraMetadataNative implements Parcelable { metadata.setFaceRectangles((Rect[]) value); metadata.setFaceRectangles((Rect[]) value); } } }); }); sSetCommandMap.put(CaptureResult.STATISTICS_FACES.getNativeKey(), new SetCommand() { @Override public <T> void setValue(CameraMetadataNative metadata, T value) { metadata.setFaces((Face[])value); } }); sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() { sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() { @Override @Override public <T> void setValue(CameraMetadataNative metadata, T value) { public <T> void setValue(CameraMetadataNative metadata, T value) { Loading core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java 0 → 100644 +231 −0 Original line number Original line 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.legacy; import android.graphics.Rect; import android.hardware.Camera; import android.hardware.Camera.FaceDetectionListener; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.legacy.ParameterUtils.ZoomData; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.params.Face; import android.hardware.camera2.utils.ListUtils; import android.hardware.camera2.utils.ParamsUtils; import android.util.Log; import android.util.Size; import com.android.internal.util.ArrayUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static android.hardware.camera2.CaptureRequest.*; import static com.android.internal.util.Preconditions.*; /** * Map legacy face detect callbacks into face detection results. */ @SuppressWarnings("deprecation") public class LegacyFaceDetectMapper { private static String TAG = "LegacyFaceDetectMapper"; private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); private final Camera mCamera; private final boolean mFaceDetectSupported; private boolean mFaceDetectEnabled = false; private final Object mLock = new Object(); private Camera.Face[] mFaces; private Camera.Face[] mFacesPrev; /** * Instantiate a new face detect mapper. * * @param camera a non-{@code null} camera1 device * @param characteristics a non-{@code null} camera characteristics for that camera1 * * @throws NullPointerException if any of the args were {@code null} */ public LegacyFaceDetectMapper(Camera camera, CameraCharacteristics characteristics) { mCamera = checkNotNull(camera, "camera must not be null"); checkNotNull(characteristics, "characteristics must not be null"); mFaceDetectSupported = ArrayUtils.contains( characteristics.get( CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES), STATISTICS_FACE_DETECT_MODE_SIMPLE); if (!mFaceDetectSupported) { return; } mCamera.setFaceDetectionListener(new FaceDetectionListener() { @Override public void onFaceDetection(Camera.Face[] faces, Camera camera) { int lengthFaces = faces == null ? 0 : faces.length; synchronized (mLock) { if (mFaceDetectEnabled) { mFaces = faces; } else if (lengthFaces > 0) { // stopFaceDetectMode could race against the requests, print a debug log Log.d(TAG, "onFaceDetection - Ignored some incoming faces since" + "face detection was disabled"); } } if (VERBOSE) { Log.v(TAG, "onFaceDetection - read " + lengthFaces + " faces"); } } }); } /** * Process the face detect mode from the capture request into an api1 face detect toggle. * * <p>This method should be called after the parameters are {@link LegacyRequestMapper mapped} * with the request.</p> * * <p>Callbacks are processed in the background, and the next call to {@link #mapResultTriggers} * will have the latest faces detected as reflected by the camera1 callbacks.</p> * * <p>None of the arguments will be mutated.</p> * * @param captureRequest a non-{@code null} request * @param parameters a non-{@code null} parameters corresponding to this request (read-only) */ public void processFaceDetectMode(CaptureRequest captureRequest, Camera.Parameters parameters) { checkNotNull(captureRequest, "captureRequest must not be null"); /* * statistics.faceDetectMode */ int fdMode = ParamsUtils.getOrDefault(captureRequest, STATISTICS_FACE_DETECT_MODE, STATISTICS_FACE_DETECT_MODE_OFF); if (fdMode != STATISTICS_FACE_DETECT_MODE_OFF && !mFaceDetectSupported) { Log.w(TAG, "processFaceDetectMode - Ignoring statistics.faceDetectMode; " + "face detection is not available"); return; } // Print some warnings out in case the values were wrong switch (fdMode) { case STATISTICS_FACE_DETECT_MODE_OFF: case STATISTICS_FACE_DETECT_MODE_SIMPLE: break; case STATISTICS_FACE_DETECT_MODE_FULL: Log.w(TAG, "processFaceDetectMode - statistics.faceDetectMode == FULL unsupported, " + "downgrading to SIMPLE"); break; default: Log.w(TAG, "processFaceDetectMode - ignoring unknown statistics.faceDetectMode = " + fdMode); return; } boolean enableFaceDetect = fdMode != STATISTICS_FACE_DETECT_MODE_OFF; synchronized (mLock) { // Enable/disable face detection if it's changed since last time if (enableFaceDetect != mFaceDetectEnabled) { if (enableFaceDetect) { mCamera.startFaceDetection(); if (VERBOSE) { Log.v(TAG, "processFaceDetectMode - start face detection"); } } else { mCamera.stopFaceDetection(); if (VERBOSE) { Log.v(TAG, "processFaceDetectMode - stop face detection"); } mFaces = null; } mFaceDetectEnabled = enableFaceDetect; } } } /** * Update the {@code result} camera metadata map with the new value for the * {@code statistics.faces} and {@code statistics.faceDetectMode}. * * <p>Face detect callbacks are processed in the background, and each call to * {@link #mapResultFaces} will have the latest faces as reflected by the camera1 callbacks.</p> * * @param result a non-{@code null} result * @param legacyRequest a non-{@code null} request (read-only) */ public void mapResultFaces(CameraMetadataNative result, LegacyRequest legacyRequest) { checkNotNull(result, "result must not be null"); checkNotNull(legacyRequest, "legacyRequest must not be null"); Camera.Face[] faces, previousFaces; int fdMode; synchronized (mLock) { fdMode = mFaceDetectEnabled ? STATISTICS_FACE_DETECT_MODE_SIMPLE : STATISTICS_FACE_DETECT_MODE_OFF; if (mFaceDetectEnabled) { faces = mFaces; } else { faces = null; } previousFaces = mFacesPrev; mFacesPrev = faces; } CameraCharacteristics characteristics = legacyRequest.characteristics; CaptureRequest request = legacyRequest.captureRequest; Size previewSize = legacyRequest.previewSize; Camera.Parameters params = legacyRequest.parameters; Rect activeArray = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); ZoomData zoomData = ParameterUtils.convertScalerCropRegion(activeArray, request.get(CaptureRequest.SCALER_CROP_REGION), previewSize, params); List<Face> convertedFaces = new ArrayList<>(); if (faces != null) { for (Camera.Face face : faces) { if (face != null) { convertedFaces.add( ParameterUtils.convertFaceFromLegacy(face, activeArray, zoomData)); } else { Log.w(TAG, "mapResultFaces - read NULL face from camera1 device"); } } } if (VERBOSE && previousFaces != faces) { // Log only in verbose and IF the faces changed Log.v(TAG, "mapResultFaces - changed to " + ListUtils.listToString(convertedFaces)); } result.set(CaptureResult.STATISTICS_FACES, convertedFaces.toArray(new Face[0])); result.set(CaptureResult.STATISTICS_FACE_DETECT_MODE, fdMode); } } core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -247,7 +247,8 @@ public class LegacyFocusStateMapper { // No action necessary. The callbacks will handle transitions. // No action necessary. The callbacks will handle transitions. break; break; default: default: Log.w(TAG, "mapTriggers - ignoring unknown control.afTrigger = " + afTrigger); Log.w(TAG, "processRequestTriggers - ignoring unknown control.afTrigger = " + afTrigger); } } } } Loading core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java +42 −0 Original line number Original line Diff line number Diff line Loading @@ -203,6 +203,11 @@ public class LegacyMetadataMapper { */ */ mapSensor(m, p); mapSensor(m, p); /* * statistics.* */ mapStatistics(m, p); /* /* * sync.* * sync.* */ */ Loading Loading @@ -486,6 +491,18 @@ public class LegacyMetadataMapper { } } private static void mapControlOther(CameraMetadataNative m, Camera.Parameters p) { private static void mapControlOther(CameraMetadataNative m, Camera.Parameters p) { /* * android.control.availableVideoStabilizationModes */ { int stabModes[] = p.isVideoStabilizationSupported() ? new int[] { CONTROL_VIDEO_STABILIZATION_MODE_OFF, CONTROL_VIDEO_STABILIZATION_MODE_ON } : new int[] { CONTROL_VIDEO_STABILIZATION_MODE_OFF }; m.set(CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, stabModes); } /* /* * android.control.maxRegions * android.control.maxRegions */ */ Loading Loading @@ -742,6 +759,31 @@ public class LegacyMetadataMapper { m.set(SENSOR_INFO_PIXEL_ARRAY_SIZE, largestJpegSize); m.set(SENSOR_INFO_PIXEL_ARRAY_SIZE, largestJpegSize); } } private static void mapStatistics(CameraMetadataNative m, Parameters p) { /* * statistics.info.availableFaceDetectModes */ int[] fdModes; if (p.getMaxNumDetectedFaces() > 0) { fdModes = new int[] { STATISTICS_FACE_DETECT_MODE_OFF, STATISTICS_FACE_DETECT_MODE_SIMPLE // FULL is never-listed, since we have no way to query it statically }; } else { fdModes = new int[] { STATISTICS_FACE_DETECT_MODE_OFF }; } m.set(STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, fdModes); /* * statistics.info.maxFaceCount */ m.set(STATISTICS_INFO_MAX_FACE_COUNT, p.getMaxNumDetectedFaces()); } private static void mapSync(CameraMetadataNative m, Parameters p) { private static void mapSync(CameraMetadataNative m, Parameters p) { /* /* * sync.maxLatency * sync.maxLatency Loading core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java +12 −2 Original line number Original line Diff line number Diff line Loading @@ -150,10 +150,8 @@ public class LegacyRequestMapper { if (supported) { if (supported) { params.setPreviewFpsRange(legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], params.setPreviewFpsRange(legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); params.setRecordingHint(false); } else { } else { Log.w(TAG, "Unsupported FPS range set [" + legacyFps[0] + "," + legacyFps[1] + "]"); Log.w(TAG, "Unsupported FPS range set [" + legacyFps[0] + "," + legacyFps[1] + "]"); params.setRecordingHint(true); } } } } Loading Loading @@ -248,6 +246,18 @@ public class LegacyRequestMapper { // TODO: Don't add control.awbLock to availableRequestKeys if it's not supported // TODO: Don't add control.awbLock to availableRequestKeys if it's not supported } } // control.videoStabilizationMode { Integer stabMode = getIfSupported(request, CONTROL_VIDEO_STABILIZATION_MODE, /*defaultValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF, params.isVideoStabilizationSupported(), /*allowedValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF); if (stabMode != null) { params.setVideoStabilization(stabMode == CONTROL_VIDEO_STABILIZATION_MODE_ON); } } // lens.focusDistance // lens.focusDistance { { boolean infinityFocusSupported = boolean infinityFocusSupported = Loading Loading
core/java/android/hardware/camera2/impl/CameraMetadataNative.java +80 −6 Original line number Original line Diff line number Diff line Loading @@ -67,6 +67,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.ArrayList; import java.util.HashMap; import java.util.HashMap; import java.util.List; /** /** * Implementation of camera metadata marshal/unmarshal across Binder to * Implementation of camera metadata marshal/unmarshal across Binder to Loading Loading @@ -227,6 +228,7 @@ public class CameraMetadataNative implements Parcelable { private static final String CELLID_PROCESS = "CELLID"; private static final String CELLID_PROCESS = "CELLID"; private static final String GPS_PROCESS = "GPS"; private static final String GPS_PROCESS = "GPS"; private static final int FACE_LANDMARK_SIZE = 6; private static String translateLocationProviderToProcess(final String provider) { private static String translateLocationProviderToProcess(final String provider) { if (provider == null) { if (provider == null) { Loading Loading @@ -347,7 +349,7 @@ public class CameraMetadataNative implements Parcelable { // Check if key has been overridden to use a wrapper class on the java side. // Check if key has been overridden to use a wrapper class on the java side. GetCommand g = sGetCommandMap.get(key); GetCommand g = sGetCommandMap.get(key); if (g != null) { if (g != null) { return (T) g.getValue(this, key); return g.getValue(this, key); } } return getBase(key); return getBase(key); } } Loading Loading @@ -587,9 +589,71 @@ public class CameraMetadataNative implements Parcelable { return availableFormats; return availableFormats; } } private Face[] getFaces() { private boolean setFaces(Face[] faces) { final int FACE_LANDMARK_SIZE = 6; if (faces == null) { return false; } int numFaces = faces.length; // Detect if all faces are SIMPLE or not; count # of valid faces boolean fullMode = true; for (Face face : faces) { if (face == null) { numFaces--; Log.w(TAG, "setFaces - null face detected, skipping"); continue; } if (face.getId() == Face.ID_UNSUPPORTED) { fullMode = false; } } Rect[] faceRectangles = new Rect[numFaces]; byte[] faceScores = new byte[numFaces]; int[] faceIds = null; int[] faceLandmarks = null; if (fullMode) { faceIds = new int[numFaces]; faceLandmarks = new int[numFaces * FACE_LANDMARK_SIZE]; } int i = 0; for (Face face : faces) { if (face == null) { continue; } faceRectangles[i] = face.getBounds(); faceScores[i] = (byte)face.getScore(); if (fullMode) { faceIds[i] = face.getId(); int j = 0; faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().x; faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().y; faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().x; faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().y; faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().x; faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().y; } i++; } set(CaptureResult.STATISTICS_FACE_RECTANGLES, faceRectangles); set(CaptureResult.STATISTICS_FACE_IDS, faceIds); set(CaptureResult.STATISTICS_FACE_LANDMARKS, faceLandmarks); set(CaptureResult.STATISTICS_FACE_SCORES, faceScores); return true; } private Face[] getFaces() { Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE); Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE); if (faceDetectMode == null) { if (faceDetectMode == null) { Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE"); Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE"); Loading Loading @@ -653,9 +717,12 @@ public class CameraMetadataNative implements Parcelable { if (faceScores[i] <= Face.SCORE_MAX && if (faceScores[i] <= Face.SCORE_MAX && faceScores[i] >= Face.SCORE_MIN && faceScores[i] >= Face.SCORE_MIN && faceIds[i] >= 0) { faceIds[i] >= 0) { Point leftEye = new Point(faceLandmarks[i*6], faceLandmarks[i*6+1]); Point leftEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE], Point rightEye = new Point(faceLandmarks[i*6+2], faceLandmarks[i*6+3]); faceLandmarks[i*FACE_LANDMARK_SIZE+1]); Point mouth = new Point(faceLandmarks[i*6+4], faceLandmarks[i*6+5]); Point rightEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+2], faceLandmarks[i*FACE_LANDMARK_SIZE+3]); Point mouth = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+4], faceLandmarks[i*FACE_LANDMARK_SIZE+5]); Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i], Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i], leftEye, rightEye, mouth); leftEye, rightEye, mouth); faceList.add(face); faceList.add(face); Loading Loading @@ -865,6 +932,13 @@ public class CameraMetadataNative implements Parcelable { metadata.setFaceRectangles((Rect[]) value); metadata.setFaceRectangles((Rect[]) value); } } }); }); sSetCommandMap.put(CaptureResult.STATISTICS_FACES.getNativeKey(), new SetCommand() { @Override public <T> void setValue(CameraMetadataNative metadata, T value) { metadata.setFaces((Face[])value); } }); sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() { sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() { @Override @Override public <T> void setValue(CameraMetadataNative metadata, T value) { public <T> void setValue(CameraMetadataNative metadata, T value) { Loading
core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java 0 → 100644 +231 −0 Original line number Original line 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.legacy; import android.graphics.Rect; import android.hardware.Camera; import android.hardware.Camera.FaceDetectionListener; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.legacy.ParameterUtils.ZoomData; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.params.Face; import android.hardware.camera2.utils.ListUtils; import android.hardware.camera2.utils.ParamsUtils; import android.util.Log; import android.util.Size; import com.android.internal.util.ArrayUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static android.hardware.camera2.CaptureRequest.*; import static com.android.internal.util.Preconditions.*; /** * Map legacy face detect callbacks into face detection results. */ @SuppressWarnings("deprecation") public class LegacyFaceDetectMapper { private static String TAG = "LegacyFaceDetectMapper"; private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); private final Camera mCamera; private final boolean mFaceDetectSupported; private boolean mFaceDetectEnabled = false; private final Object mLock = new Object(); private Camera.Face[] mFaces; private Camera.Face[] mFacesPrev; /** * Instantiate a new face detect mapper. * * @param camera a non-{@code null} camera1 device * @param characteristics a non-{@code null} camera characteristics for that camera1 * * @throws NullPointerException if any of the args were {@code null} */ public LegacyFaceDetectMapper(Camera camera, CameraCharacteristics characteristics) { mCamera = checkNotNull(camera, "camera must not be null"); checkNotNull(characteristics, "characteristics must not be null"); mFaceDetectSupported = ArrayUtils.contains( characteristics.get( CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES), STATISTICS_FACE_DETECT_MODE_SIMPLE); if (!mFaceDetectSupported) { return; } mCamera.setFaceDetectionListener(new FaceDetectionListener() { @Override public void onFaceDetection(Camera.Face[] faces, Camera camera) { int lengthFaces = faces == null ? 0 : faces.length; synchronized (mLock) { if (mFaceDetectEnabled) { mFaces = faces; } else if (lengthFaces > 0) { // stopFaceDetectMode could race against the requests, print a debug log Log.d(TAG, "onFaceDetection - Ignored some incoming faces since" + "face detection was disabled"); } } if (VERBOSE) { Log.v(TAG, "onFaceDetection - read " + lengthFaces + " faces"); } } }); } /** * Process the face detect mode from the capture request into an api1 face detect toggle. * * <p>This method should be called after the parameters are {@link LegacyRequestMapper mapped} * with the request.</p> * * <p>Callbacks are processed in the background, and the next call to {@link #mapResultTriggers} * will have the latest faces detected as reflected by the camera1 callbacks.</p> * * <p>None of the arguments will be mutated.</p> * * @param captureRequest a non-{@code null} request * @param parameters a non-{@code null} parameters corresponding to this request (read-only) */ public void processFaceDetectMode(CaptureRequest captureRequest, Camera.Parameters parameters) { checkNotNull(captureRequest, "captureRequest must not be null"); /* * statistics.faceDetectMode */ int fdMode = ParamsUtils.getOrDefault(captureRequest, STATISTICS_FACE_DETECT_MODE, STATISTICS_FACE_DETECT_MODE_OFF); if (fdMode != STATISTICS_FACE_DETECT_MODE_OFF && !mFaceDetectSupported) { Log.w(TAG, "processFaceDetectMode - Ignoring statistics.faceDetectMode; " + "face detection is not available"); return; } // Print some warnings out in case the values were wrong switch (fdMode) { case STATISTICS_FACE_DETECT_MODE_OFF: case STATISTICS_FACE_DETECT_MODE_SIMPLE: break; case STATISTICS_FACE_DETECT_MODE_FULL: Log.w(TAG, "processFaceDetectMode - statistics.faceDetectMode == FULL unsupported, " + "downgrading to SIMPLE"); break; default: Log.w(TAG, "processFaceDetectMode - ignoring unknown statistics.faceDetectMode = " + fdMode); return; } boolean enableFaceDetect = fdMode != STATISTICS_FACE_DETECT_MODE_OFF; synchronized (mLock) { // Enable/disable face detection if it's changed since last time if (enableFaceDetect != mFaceDetectEnabled) { if (enableFaceDetect) { mCamera.startFaceDetection(); if (VERBOSE) { Log.v(TAG, "processFaceDetectMode - start face detection"); } } else { mCamera.stopFaceDetection(); if (VERBOSE) { Log.v(TAG, "processFaceDetectMode - stop face detection"); } mFaces = null; } mFaceDetectEnabled = enableFaceDetect; } } } /** * Update the {@code result} camera metadata map with the new value for the * {@code statistics.faces} and {@code statistics.faceDetectMode}. * * <p>Face detect callbacks are processed in the background, and each call to * {@link #mapResultFaces} will have the latest faces as reflected by the camera1 callbacks.</p> * * @param result a non-{@code null} result * @param legacyRequest a non-{@code null} request (read-only) */ public void mapResultFaces(CameraMetadataNative result, LegacyRequest legacyRequest) { checkNotNull(result, "result must not be null"); checkNotNull(legacyRequest, "legacyRequest must not be null"); Camera.Face[] faces, previousFaces; int fdMode; synchronized (mLock) { fdMode = mFaceDetectEnabled ? STATISTICS_FACE_DETECT_MODE_SIMPLE : STATISTICS_FACE_DETECT_MODE_OFF; if (mFaceDetectEnabled) { faces = mFaces; } else { faces = null; } previousFaces = mFacesPrev; mFacesPrev = faces; } CameraCharacteristics characteristics = legacyRequest.characteristics; CaptureRequest request = legacyRequest.captureRequest; Size previewSize = legacyRequest.previewSize; Camera.Parameters params = legacyRequest.parameters; Rect activeArray = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); ZoomData zoomData = ParameterUtils.convertScalerCropRegion(activeArray, request.get(CaptureRequest.SCALER_CROP_REGION), previewSize, params); List<Face> convertedFaces = new ArrayList<>(); if (faces != null) { for (Camera.Face face : faces) { if (face != null) { convertedFaces.add( ParameterUtils.convertFaceFromLegacy(face, activeArray, zoomData)); } else { Log.w(TAG, "mapResultFaces - read NULL face from camera1 device"); } } } if (VERBOSE && previousFaces != faces) { // Log only in verbose and IF the faces changed Log.v(TAG, "mapResultFaces - changed to " + ListUtils.listToString(convertedFaces)); } result.set(CaptureResult.STATISTICS_FACES, convertedFaces.toArray(new Face[0])); result.set(CaptureResult.STATISTICS_FACE_DETECT_MODE, fdMode); } }
core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -247,7 +247,8 @@ public class LegacyFocusStateMapper { // No action necessary. The callbacks will handle transitions. // No action necessary. The callbacks will handle transitions. break; break; default: default: Log.w(TAG, "mapTriggers - ignoring unknown control.afTrigger = " + afTrigger); Log.w(TAG, "processRequestTriggers - ignoring unknown control.afTrigger = " + afTrigger); } } } } Loading
core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java +42 −0 Original line number Original line Diff line number Diff line Loading @@ -203,6 +203,11 @@ public class LegacyMetadataMapper { */ */ mapSensor(m, p); mapSensor(m, p); /* * statistics.* */ mapStatistics(m, p); /* /* * sync.* * sync.* */ */ Loading Loading @@ -486,6 +491,18 @@ public class LegacyMetadataMapper { } } private static void mapControlOther(CameraMetadataNative m, Camera.Parameters p) { private static void mapControlOther(CameraMetadataNative m, Camera.Parameters p) { /* * android.control.availableVideoStabilizationModes */ { int stabModes[] = p.isVideoStabilizationSupported() ? new int[] { CONTROL_VIDEO_STABILIZATION_MODE_OFF, CONTROL_VIDEO_STABILIZATION_MODE_ON } : new int[] { CONTROL_VIDEO_STABILIZATION_MODE_OFF }; m.set(CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, stabModes); } /* /* * android.control.maxRegions * android.control.maxRegions */ */ Loading Loading @@ -742,6 +759,31 @@ public class LegacyMetadataMapper { m.set(SENSOR_INFO_PIXEL_ARRAY_SIZE, largestJpegSize); m.set(SENSOR_INFO_PIXEL_ARRAY_SIZE, largestJpegSize); } } private static void mapStatistics(CameraMetadataNative m, Parameters p) { /* * statistics.info.availableFaceDetectModes */ int[] fdModes; if (p.getMaxNumDetectedFaces() > 0) { fdModes = new int[] { STATISTICS_FACE_DETECT_MODE_OFF, STATISTICS_FACE_DETECT_MODE_SIMPLE // FULL is never-listed, since we have no way to query it statically }; } else { fdModes = new int[] { STATISTICS_FACE_DETECT_MODE_OFF }; } m.set(STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, fdModes); /* * statistics.info.maxFaceCount */ m.set(STATISTICS_INFO_MAX_FACE_COUNT, p.getMaxNumDetectedFaces()); } private static void mapSync(CameraMetadataNative m, Parameters p) { private static void mapSync(CameraMetadataNative m, Parameters p) { /* /* * sync.maxLatency * sync.maxLatency Loading
core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java +12 −2 Original line number Original line Diff line number Diff line Loading @@ -150,10 +150,8 @@ public class LegacyRequestMapper { if (supported) { if (supported) { params.setPreviewFpsRange(legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], params.setPreviewFpsRange(legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); params.setRecordingHint(false); } else { } else { Log.w(TAG, "Unsupported FPS range set [" + legacyFps[0] + "," + legacyFps[1] + "]"); Log.w(TAG, "Unsupported FPS range set [" + legacyFps[0] + "," + legacyFps[1] + "]"); params.setRecordingHint(true); } } } } Loading Loading @@ -248,6 +246,18 @@ public class LegacyRequestMapper { // TODO: Don't add control.awbLock to availableRequestKeys if it's not supported // TODO: Don't add control.awbLock to availableRequestKeys if it's not supported } } // control.videoStabilizationMode { Integer stabMode = getIfSupported(request, CONTROL_VIDEO_STABILIZATION_MODE, /*defaultValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF, params.isVideoStabilizationSupported(), /*allowedValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF); if (stabMode != null) { params.setVideoStabilization(stabMode == CONTROL_VIDEO_STABILIZATION_MODE_ON); } } // lens.focusDistance // lens.focusDistance { { boolean infinityFocusSupported = boolean infinityFocusSupported = Loading