Chromium Code Reviews| Index: media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java |
| diff --git a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java |
| index ded4ec4d89860560ef8dcc0965e71670c50e9f0d..15eac8e2e9d2895f18c9e01d5ea2291fe010f454 100644 |
| --- a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java |
| +++ b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java |
| @@ -255,6 +255,7 @@ public class VideoCaptureCamera2 extends VideoCapture { |
| private int mWhiteBalanceMode = AndroidMeteringMode.CONTINUOUS; |
| private int mIso = 0; |
| private boolean mRedEyeReduction = false; |
| + private int mFillLightMode = AndroidFillLightMode.OFF; |
| // Service function to grab CameraCharacteristics and handle exceptions. |
| private static CameraCharacteristics getCameraCharacteristics(Context appContext, int id) { |
| @@ -312,68 +313,103 @@ public class VideoCaptureCamera2 extends VideoCapture { |
| previewRequestBuilder.set(CaptureRequest.EDGE_MODE, CameraMetadata.EDGE_MODE_FAST); |
| previewRequestBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, |
| CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON); |
| + |
| + configureCommonCaptureSettings(previewRequestBuilder); |
| + |
| + List<Surface> surfaceList = new ArrayList<Surface>(1); |
| + // TODO(mcasas): Hold on to this Surface and release() it when not needed. |
| + surfaceList.add(imageReader.getSurface()); |
| + |
| + mPreviewRequest = previewRequestBuilder.build(); |
| + final CrPreviewSessionListener captureSessionListener = |
| + new CrPreviewSessionListener(mPreviewRequest); |
| + try { |
| + mCameraDevice.createCaptureSession(surfaceList, captureSessionListener, null); |
| + } catch (CameraAccessException | IllegalArgumentException | SecurityException ex) { |
| + Log.e(TAG, "createCaptureSession: ", ex); |
| + return false; |
| + } |
| + // Wait for trigger on CrPreviewSessionListener.onConfigured(); |
| + return true; |
| + } |
| + |
| + private void configureCommonCaptureSettings(CaptureRequest.Builder requestBuilder) { |
| + // |mFocusMode| indicates if we're in auto/continuous, single-shot or manual mode. |
| if (mFocusMode == AndroidMeteringMode.CONTINUOUS) { |
| - Log.d(TAG, "Focus: CONTROL_AF_MODE_CONTINUOUS_PICTURE"); |
| - previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, |
| + requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, |
| CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE); |
| } else if (mFocusMode == AndroidMeteringMode.SINGLE_SHOT) { |
| - Log.d(TAG, "Focus: triggering a single shot"); |
| - previewRequestBuilder.set( |
| - CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_AUTO); |
| - previewRequestBuilder.set( |
| + requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, |
| + CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE); |
| + requestBuilder.set( |
| CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START); |
| + } else if (mFocusMode == AndroidMeteringMode.FIXED) { |
| + requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_OFF); |
| + // TODO(mcasas): Support controlling LENS_FOCUS_DISTANCE in this mode. |
| } |
| - if (mExposureMode == AndroidMeteringMode.FIXED) { |
| - previewRequestBuilder.set( |
| - CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_OFF); |
| + // |mExposureMode| and |mFillLightMode| interact to configure the AE and Flash modes. In a |
| + // nutshell, FLASH_MODE is only effective if the auto-exposure is ON/OFF, otherwise the |
| + // auto-exposure related flash control (ON_{AUTO,ALWAYS}_FLASH{_REDEYE) takes priority. |
| + if (mExposureMode == AndroidMeteringMode.NONE |
| + || mExposureMode == AndroidMeteringMode.FIXED) { |
| + requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_OFF); |
| } else { |
| - // TODO(mcasas): Factor the flash settings when wired. |
| - previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, mRedEyeReduction |
| - ? CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE |
| - : CameraMetadata.CONTROL_AE_MODE_ON); |
| + requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON); |
| } |
| - previewRequestBuilder.set( |
| - CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, mExposureCompensation); |
| + switch (mFillLightMode) { |
| + case AndroidFillLightMode.OFF: |
| + requestBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF); |
| + break; |
| + case AndroidFillLightMode.AUTO: |
| + // Setting the AE to CONTROL_AE_MODE_ON_AUTO_FLASH[_REDEYE] overrides FLASH_MODE. |
| + requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, mRedEyeReduction |
| + ? CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE |
| + : CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH); |
| + break; |
| + case AndroidFillLightMode.FLASH: |
| + // Setting the AE to CONTROL_AE_MODE_ON_ALWAYS_FLASH overrides FLASH_MODE. |
| + requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, |
| + CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH); |
| + break; |
| + case AndroidFillLightMode.TORCH: |
| + requestBuilder.set( |
| + CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON); |
| + requestBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH); |
| + break; |
| + case AndroidFillLightMode.NONE: |
| + // NONE is only used for getting capabilities, to signify "no flash unit". Ignore. |
| + } |
| + requestBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, mExposureCompensation); |
| // White Balance mode AndroidMeteringMode.SINGLE_SHOT is not supported. |
| - // TODO(mcasas): support FIXED mode, i.e. the scene mode. |
| if (mWhiteBalanceMode == AndroidMeteringMode.CONTINUOUS) { |
| - previewRequestBuilder.set( |
| + requestBuilder.set(CaptureRequest.CONTROL_AWB_LOCK, false); |
| + requestBuilder.set( |
| CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_AUTO); |
| - } else if (mWhiteBalanceMode == AndroidMeteringMode.UNAVAILABLE) { |
| - previewRequestBuilder.set( |
| + // TODO(mcasas): support different luminant color temperatures, e.g. DAYLIGHT, SHADE. |
|
scheib
2016/09/03 00:21:57
I've jumped to the 'always TODO(issue#)' style bas
mcasas
2016/09/03 01:21:07
I know, this was just me being lazy since
I'm work
|
| + // https://github.com/w3c/mediacapture-image/pull/54 |
| + } else if (mWhiteBalanceMode == AndroidMeteringMode.NONE) { |
| + requestBuilder.set(CaptureRequest.CONTROL_AWB_LOCK, false); |
| + requestBuilder.set( |
| CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_OFF); |
| + } else if (mWhiteBalanceMode == AndroidMeteringMode.FIXED) { |
| + requestBuilder.set(CaptureRequest.CONTROL_AWB_LOCK, true); |
| } |
| if (mAreaOfInterest != null) { |
| MeteringRectangle[] array = {mAreaOfInterest}; |
| Log.d(TAG, "Area of interest %s", mAreaOfInterest.toString()); |
| - previewRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, array); |
| - previewRequestBuilder.set(CaptureRequest.CONTROL_AE_REGIONS, array); |
| - previewRequestBuilder.set(CaptureRequest.CONTROL_AWB_REGIONS, array); |
| + requestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, array); |
| + requestBuilder.set(CaptureRequest.CONTROL_AE_REGIONS, array); |
| + requestBuilder.set(CaptureRequest.CONTROL_AWB_REGIONS, array); |
| } |
| if (!mCropRect.isEmpty()) { |
| - previewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, mCropRect); |
| + requestBuilder.set(CaptureRequest.SCALER_CROP_REGION, mCropRect); |
| } |
| - if (mIso > 0) previewRequestBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, mIso); |
| - |
| - List<Surface> surfaceList = new ArrayList<Surface>(1); |
| - // TODO(mcasas): Hold on to this Surface and release() it when not needed. |
| - surfaceList.add(imageReader.getSurface()); |
| - mPreviewRequest = previewRequestBuilder.build(); |
| - final CrPreviewSessionListener captureSessionListener = |
| - new CrPreviewSessionListener(mPreviewRequest); |
| - try { |
| - mCameraDevice.createCaptureSession(surfaceList, captureSessionListener, null); |
| - } catch (CameraAccessException | IllegalArgumentException | SecurityException ex) { |
| - Log.e(TAG, "createCaptureSession: ", ex); |
| - return false; |
| - } |
| - // Wait for trigger on CrPreviewSessionListener.onConfigured(); |
| - return true; |
| + if (mIso > 0) requestBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, mIso); |
| } |
| private void changeCameraStateAndNotify(CameraState state) { |
| @@ -637,7 +673,7 @@ public class VideoCaptureCamera2 extends VideoCapture { |
| final int focusMode = mPreviewRequest.get(CaptureRequest.CONTROL_AF_MODE); |
| // Classify the Focus capabilities. In CONTINUOUS and SINGLE_SHOT, we can call |
| // autoFocus(AutoFocusCallback) to configure region(s) to focus onto. |
| - int jniFocusMode = AndroidMeteringMode.UNAVAILABLE; |
| + int jniFocusMode = AndroidMeteringMode.NONE; |
| if (focusMode == CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_VIDEO |
| || focusMode == CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE) { |
| jniFocusMode = AndroidMeteringMode.CONTINUOUS; |
| @@ -654,7 +690,7 @@ public class VideoCaptureCamera2 extends VideoCapture { |
| int jniExposureMode = AndroidMeteringMode.CONTINUOUS; |
| if (mPreviewRequest.get(CaptureRequest.CONTROL_AE_MODE) |
| == CameraMetadata.CONTROL_AE_MODE_OFF) { |
| - jniExposureMode = AndroidMeteringMode.UNAVAILABLE; |
| + jniExposureMode = AndroidMeteringMode.NONE; |
| } |
| if (mPreviewRequest.get(CaptureRequest.CONTROL_AE_LOCK)) { |
| jniExposureMode = AndroidMeteringMode.FIXED; |
| @@ -675,20 +711,49 @@ public class VideoCaptureCamera2 extends VideoCapture { |
| final int whiteBalanceMode = mPreviewRequest.get(CaptureRequest.CONTROL_AWB_MODE); |
| if (whiteBalanceMode == CameraMetadata.CONTROL_AWB_MODE_OFF) { |
| - builder.setWhiteBalanceMode(AndroidMeteringMode.UNAVAILABLE); |
| + builder.setWhiteBalanceMode(AndroidMeteringMode.NONE); |
| } else if (whiteBalanceMode == CameraMetadata.CONTROL_AWB_MODE_AUTO) { |
| builder.setWhiteBalanceMode(AndroidMeteringMode.CONTINUOUS); |
| } else { |
| builder.setWhiteBalanceMode(AndroidMeteringMode.FIXED); |
| } |
| + if (!cameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)) { |
| + builder.setFillLightMode(AndroidFillLightMode.NONE); |
| + } else { |
| + // CONTROL_AE_MODE overrides FLASH_MODE control unless it's in ON or OFF states. |
| + switch (mPreviewRequest.get(CaptureRequest.CONTROL_AE_MODE)) { |
| + case CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH: |
| + case CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE: |
| + builder.setFillLightMode(AndroidFillLightMode.AUTO); |
| + break; |
| + case CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH: |
| + builder.setFillLightMode(AndroidFillLightMode.FLASH); |
| + break; |
| + case CameraMetadata.CONTROL_AE_MODE_OFF: |
| + case CameraMetadata.CONTROL_AE_MODE_ON: |
| + final Integer flashMode = mPreviewRequest.get(CaptureRequest.FLASH_MODE); |
| + if (flashMode == CameraMetadata.FLASH_MODE_OFF) { |
| + builder.setFillLightMode(AndroidFillLightMode.OFF); |
| + } else if (flashMode == CameraMetadata.FLASH_MODE_SINGLE) { |
| + builder.setFillLightMode(AndroidFillLightMode.FLASH); |
| + } else if (flashMode == CameraMetadata.FLASH_MODE_TORCH) { |
| + builder.setFillLightMode(AndroidFillLightMode.TORCH); |
| + } |
| + break; |
| + default: |
| + builder.setFillLightMode(AndroidFillLightMode.NONE); |
| + } |
| + } |
| + |
| return builder.build(); |
| } |
| @Override |
| public void setPhotoOptions(int zoom, int focusMode, int exposureMode, int width, int height, |
| float[] pointsOfInterest2D, boolean hasExposureCompensation, int exposureCompensation, |
| - int whiteBalanceMode, int iso, boolean hasRedEyeReduction, boolean redEyeReduction) { |
| + int whiteBalanceMode, int iso, boolean hasRedEyeReduction, boolean redEyeReduction, |
| + int fillLightMode) { |
| final CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(mContext, mId); |
| final Rect canvas = |
| cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); |
| @@ -714,9 +779,8 @@ public class VideoCaptureCamera2 extends VideoCapture { |
| if (mAreaOfInterest != null && !mAreaOfInterest.getRect().isEmpty() && zoom > 0) { |
| mAreaOfInterest = null; |
| } |
| - // Also clear |mAreaOfInterest| if the user sets it as UNAVAILABLE. |
| - if (mFocusMode == AndroidMeteringMode.UNAVAILABLE |
| - || mExposureMode == AndroidMeteringMode.UNAVAILABLE) { |
| + // Also clear |mAreaOfInterest| if the user sets it as NONE. |
| + if (mFocusMode == AndroidMeteringMode.NONE || mExposureMode == AndroidMeteringMode.NONE) { |
| mAreaOfInterest = null; |
| } |
| // Update |mAreaOfInterest| if the camera supports and there are |pointsOfInterest2D|. |
| @@ -756,6 +820,7 @@ public class VideoCaptureCamera2 extends VideoCapture { |
| if (iso > 0) mIso = iso; |
| if (hasRedEyeReduction) mRedEyeReduction = redEyeReduction; |
| + if (fillLightMode != AndroidFillLightMode.NOT_SET) mFillLightMode = fillLightMode; |
| final Handler mainHandler = new Handler(mContext.getMainLooper()); |
| mainHandler.removeCallbacks(mRestartCapture); |
| @@ -807,48 +872,8 @@ public class VideoCaptureCamera2 extends VideoCapture { |
| } |
| photoRequestBuilder.addTarget(imageReader.getSurface()); |
| photoRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, getCameraRotation()); |
| - if (!mCropRect.isEmpty()) { |
| - photoRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, mCropRect); |
| - } |
| - if (mFocusMode == AndroidMeteringMode.CONTINUOUS) { |
| - photoRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, |
| - CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE); |
| - } else if (mFocusMode == AndroidMeteringMode.SINGLE_SHOT) { |
| - photoRequestBuilder.set( |
| - CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START); |
| - } |
| - |
| - if (mExposureMode == AndroidMeteringMode.FIXED) { |
| - photoRequestBuilder.set( |
| - CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_OFF); |
| - } else { |
| - // TODO(mcasas): Factor the flash settings when wired. |
| - photoRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, mRedEyeReduction |
| - ? CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE |
| - : CameraMetadata.CONTROL_AE_MODE_ON); |
| - } |
| - photoRequestBuilder.set( |
| - CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, mExposureCompensation); |
| - |
| - // White Balance mode AndroidMeteringMode.SINGLE_SHOT is not supported. |
| - // TODO(mcasas): support FIXED mode, i.e. the scene mode. |
| - if (mWhiteBalanceMode == AndroidMeteringMode.CONTINUOUS) { |
| - photoRequestBuilder.set( |
| - CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_AUTO); |
| - } else if (mWhiteBalanceMode == AndroidMeteringMode.UNAVAILABLE) { |
| - photoRequestBuilder.set( |
| - CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_OFF); |
| - } |
| - |
| - if (mAreaOfInterest != null) { |
| - MeteringRectangle[] array = {mAreaOfInterest}; |
| - Log.d(TAG, "Area of interest %s", mAreaOfInterest.toString()); |
| - photoRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, array); |
| - photoRequestBuilder.set(CaptureRequest.CONTROL_AE_REGIONS, array); |
| - photoRequestBuilder.set(CaptureRequest.CONTROL_AWB_REGIONS, array); |
| - } |
| - if (mIso > 0) photoRequestBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, mIso); |
| + configureCommonCaptureSettings(photoRequestBuilder); |
| final CaptureRequest photoRequest = photoRequestBuilder.build(); |
| final CrPhotoSessionListener sessionListener = |