Commit 5c7ce5d4 authored by mcasas's avatar mcasas Committed by Commit bot

ImageCapture: wire PhotoCapabilities' ISO, width, height and PhotoSettings' width and height

This CL continues implementing ImageCapture:

- adds |iso|, |imageHeight| and |imageWidth| to PhotoCapabilities
 (each is a MediaSettingsRange).
- adds |imageHeight| and |imageWidth| to PhotoSettings.
- extends image_capture.mojom to support all the previous new
 fields
- wires Android's "old" and "new" Camera API to provide the
 capabilities and listen to the Settings (seems like the
 "old" does not reliably support ISO).
- extends the FakeVideoCaptureDeviceTest and the LayoutTests
 for these new features.

Note that setOptions() is not synchronous with takePhoto(),
so VideoCaptureDeviceAndroid holds on to the latest, if any,
requested capture resolution.

BUG=518807

Review-Url: https://codereview.chromium.org/2164473002
Cr-Commit-Position: refs/heads/master@{#407298}
parent db52a181
...@@ -12,18 +12,83 @@ import org.chromium.base.annotations.JNINamespace; ...@@ -12,18 +12,83 @@ import org.chromium.base.annotations.JNINamespace;
**/ **/
@JNINamespace("media") @JNINamespace("media")
class PhotoCapabilities { class PhotoCapabilities {
public final int maxIso;
public final int minIso;
public final int currentIso;
public final int maxHeight;
public final int minHeight;
public final int currentHeight;
public final int maxWidth;
public final int minWidth;
public final int currentWidth;
public final int maxZoom; public final int maxZoom;
public final int minZoom; public final int minZoom;
public final int currentZoom; public final int currentZoom;
public final boolean autoFocusInUse; public final boolean autoFocusInUse;
PhotoCapabilities(int maxZoom, int minZoom, int currentZoom, boolean autoFocusInUse) { PhotoCapabilities(int maxIso, int minIso, int currentIso, int maxHeight, int minHeight,
int currentHeight, int maxWidth, int minWidth, int currentWidth, int maxZoom,
int minZoom, int currentZoom, boolean autoFocusInUse) {
this.maxIso = maxIso;
this.minIso = minIso;
this.currentIso = currentIso;
this.maxHeight = maxHeight;
this.minHeight = minHeight;
this.currentHeight = currentHeight;
this.maxWidth = maxWidth;
this.minWidth = minWidth;
this.currentWidth = currentWidth;
this.maxZoom = maxZoom; this.maxZoom = maxZoom;
this.minZoom = minZoom; this.minZoom = minZoom;
this.currentZoom = currentZoom; this.currentZoom = currentZoom;
this.autoFocusInUse = autoFocusInUse; this.autoFocusInUse = autoFocusInUse;
} }
@CalledByNative
public int getMinIso() {
return minIso;
}
@CalledByNative
public int getMaxIso() {
return maxIso;
}
@CalledByNative
public int getCurrentIso() {
return currentIso;
}
@CalledByNative
public int getMinHeight() {
return minHeight;
}
@CalledByNative
public int getMaxHeight() {
return maxHeight;
}
@CalledByNative
public int getCurrentHeight() {
return currentHeight;
}
@CalledByNative
public int getMinWidth() {
return minWidth;
}
@CalledByNative
public int getMaxWidth() {
return maxWidth;
}
@CalledByNative
public int getCurrentWidth() {
return currentWidth;
}
@CalledByNative @CalledByNative
public int getMinZoom() { public int getMinZoom() {
return minZoom; return minZoom;
......
...@@ -57,7 +57,7 @@ public abstract class VideoCapture { ...@@ -57,7 +57,7 @@ public abstract class VideoCapture {
public abstract void setZoom(int zoom); public abstract void setZoom(int zoom);
@CalledByNative @CalledByNative
public abstract boolean takePhoto(final long callbackId); public abstract boolean takePhoto(final long callbackId, int width, int height);
@CalledByNative @CalledByNative
public abstract void deallocate(); public abstract void deallocate();
......
...@@ -296,6 +296,27 @@ public abstract class VideoCaptureCamera ...@@ -296,6 +296,27 @@ public abstract class VideoCaptureCamera
@Override @Override
public PhotoCapabilities getPhotoCapabilities() { public PhotoCapabilities getPhotoCapabilities() {
final android.hardware.Camera.Parameters parameters = getCameraParameters(mCamera); final android.hardware.Camera.Parameters parameters = getCameraParameters(mCamera);
Log.d(TAG, " CAM params: " + parameters.flatten());
// Before the Camera2 API there was no official way to retrieve the supported, if any, ISO
// values from |parameters|; some platforms had "iso-values", others "iso-mode-values" etc.
// Ignore them.
final int maxIso = 0;
final int currentIso = 0;
final int minIso = 0;
List<android.hardware.Camera.Size> supportedSizes = parameters.getSupportedPictureSizes();
int minWidth = Integer.MAX_VALUE;
int minHeight = Integer.MAX_VALUE;
int maxWidth = 0;
int maxHeight = 0;
for (android.hardware.Camera.Size size : supportedSizes) {
if (size.width < minWidth) minWidth = size.width;
if (size.height < minHeight) minHeight = size.height;
if (size.width > maxWidth) maxWidth = size.width;
if (size.height > maxHeight) maxHeight = size.height;
}
final android.hardware.Camera.Size currentSize = parameters.getPreviewSize();
int maxZoom = 0; int maxZoom = 0;
int currentZoom = 0; int currentZoom = 0;
...@@ -316,7 +337,9 @@ public abstract class VideoCaptureCamera ...@@ -316,7 +337,9 @@ public abstract class VideoCaptureCamera
|| focusMode.equals(android.hardware.Camera.Parameters.FOCUS_MODE_INFINITY) || focusMode.equals(android.hardware.Camera.Parameters.FOCUS_MODE_INFINITY)
|| focusMode.equals(android.hardware.Camera.Parameters.FOCUS_MODE_EDOF); || focusMode.equals(android.hardware.Camera.Parameters.FOCUS_MODE_EDOF);
return new PhotoCapabilities(maxZoom, minZoom, currentZoom, !isFocusManual); return new PhotoCapabilities(minIso, maxIso, currentIso, maxHeight, minHeight,
currentSize.height, maxWidth, minWidth, currentSize.width, maxZoom, minZoom,
currentZoom, !isFocusManual);
} }
@Override @Override
...@@ -338,7 +361,7 @@ public abstract class VideoCaptureCamera ...@@ -338,7 +361,7 @@ public abstract class VideoCaptureCamera
} }
@Override @Override
public boolean takePhoto(final long callbackId) { public boolean takePhoto(final long callbackId, int width, int height) {
if (mCamera == null || !mIsRunning) { if (mCamera == null || !mIsRunning) {
Log.e(TAG, "takePhoto: mCamera is null or is not running"); Log.e(TAG, "takePhoto: mCamera is null or is not running");
return false; return false;
...@@ -352,13 +375,41 @@ public abstract class VideoCaptureCamera ...@@ -352,13 +375,41 @@ public abstract class VideoCaptureCamera
android.hardware.Camera.Parameters parameters = getCameraParameters(mCamera); android.hardware.Camera.Parameters parameters = getCameraParameters(mCamera);
parameters.setRotation(getCameraRotation()); parameters.setRotation(getCameraRotation());
mCamera.setParameters(parameters); final android.hardware.Camera.Size original_size = parameters.getPictureSize();
List<android.hardware.Camera.Size> supportedSizes = parameters.getSupportedPictureSizes();
android.hardware.Camera.Size closestSize = null;
int minDiff = Integer.MAX_VALUE;
for (android.hardware.Camera.Size size : supportedSizes) {
final int diff = ((width > 0) ? Math.abs(size.width - width) : 0)
+ ((height > 0) ? Math.abs(size.height - height) : 0);
if (diff < minDiff) {
minDiff = diff;
closestSize = size;
}
}
Log.d(TAG, "requested resolution: (%dx%d)", width, height);
if (minDiff != Integer.MAX_VALUE) {
Log.d(TAG, " matched (%dx%d)", closestSize.width, closestSize.height);
parameters.setPictureSize(closestSize.width, closestSize.height);
}
try { try {
mCamera.setParameters(parameters);
mCamera.takePicture(null, null, null, new CrPictureCallback()); mCamera.takePicture(null, null, null, new CrPictureCallback());
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
Log.e(TAG, "takePicture ", ex); Log.e(TAG, "takePicture ", ex);
return false; return false;
} }
// Restore original parameters.
parameters.setPictureSize(original_size.width, original_size.height);
try {
mCamera.setParameters(parameters);
} catch (RuntimeException ex) {
Log.e(TAG, "takePicture ", ex);
return false;
}
return true; return true;
} }
......
...@@ -21,6 +21,7 @@ import android.media.ImageReader; ...@@ -21,6 +21,7 @@ import android.media.ImageReader;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.util.Range;
import android.util.Size; import android.util.Size;
import android.view.Surface; import android.view.Surface;
...@@ -319,6 +320,27 @@ public class VideoCaptureCamera2 extends VideoCapture { ...@@ -319,6 +320,27 @@ public class VideoCaptureCamera2 extends VideoCapture {
} }
} }
// Finds the closest Size to (|width|x|height|) in |sizes|, and returns it or null.
// Ignores |width| or |height| if either is zero (== don't care).
private static Size findClosestSizeInArray(Size[] sizes, int width, int height) {
if (sizes == null) return null;
Size closestSize = null;
int minDiff = Integer.MAX_VALUE;
for (Size size : sizes) {
final int diff = ((width > 0) ? Math.abs(size.getWidth() - width) : 0)
+ ((height > 0) ? Math.abs(size.getHeight() - height) : 0);
if (diff < minDiff) {
minDiff = diff;
closestSize = size;
}
}
if (minDiff == Integer.MAX_VALUE) {
Log.e(TAG, "Couldn't find resolution close to (%dx%d)", width, height);
return null;
}
return closestSize;
}
static boolean isLegacyDevice(Context appContext, int id) { static boolean isLegacyDevice(Context appContext, int id) {
final CameraCharacteristics cameraCharacteristics = final CameraCharacteristics cameraCharacteristics =
getCameraCharacteristics(appContext, id); getCameraCharacteristics(appContext, id);
...@@ -435,18 +457,8 @@ public class VideoCaptureCamera2 extends VideoCapture { ...@@ -435,18 +457,8 @@ public class VideoCaptureCamera2 extends VideoCapture {
// Find closest supported size. // Find closest supported size.
final Size[] supportedSizes = streamMap.getOutputSizes(ImageFormat.YUV_420_888); final Size[] supportedSizes = streamMap.getOutputSizes(ImageFormat.YUV_420_888);
if (supportedSizes == null) return false; final Size closestSupportedSize = findClosestSizeInArray(supportedSizes, width, height);
Size closestSupportedSize = null; if (closestSupportedSize == null) {
int minDiff = Integer.MAX_VALUE;
for (Size size : supportedSizes) {
final int diff =
Math.abs(size.getWidth() - width) + Math.abs(size.getHeight() - height);
if (diff < minDiff) {
minDiff = diff;
closestSupportedSize = size;
}
}
if (minDiff == Integer.MAX_VALUE) {
Log.e(TAG, "No supported resolutions."); Log.e(TAG, "No supported resolutions.");
return false; return false;
} }
...@@ -518,11 +530,36 @@ public class VideoCaptureCamera2 extends VideoCapture { ...@@ -518,11 +530,36 @@ public class VideoCaptureCamera2 extends VideoCapture {
public PhotoCapabilities getPhotoCapabilities() { public PhotoCapabilities getPhotoCapabilities() {
final CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(mContext, mId); final CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(mContext, mId);
int minIso = 0;
int maxIso = 0;
final Range<Integer> iso_range =
cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
if (iso_range != null) {
minIso = iso_range.getLower();
maxIso = iso_range.getUpper();
}
final int currentIso = mPreviewRequest.get(CaptureRequest.SENSOR_SENSITIVITY);
final StreamConfigurationMap streamMap =
cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
final Size[] supportedSizes = streamMap.getOutputSizes(ImageFormat.JPEG);
int minWidth = Integer.MAX_VALUE;
int minHeight = Integer.MAX_VALUE;
int maxWidth = 0;
int maxHeight = 0;
for (Size size : supportedSizes) {
if (size.getWidth() < minWidth) minWidth = size.getWidth();
if (size.getHeight() < minHeight) minHeight = size.getHeight();
if (size.getWidth() > maxWidth) maxWidth = size.getWidth();
if (size.getHeight() > maxHeight) maxHeight = size.getHeight();
}
final int currentHeight = mCaptureFormat.getHeight();
final int currentWidth = mCaptureFormat.getWidth();
// The Min and Max zoom are returned as x100 by the API to avoid using floating point. There // The Min and Max zoom are returned as x100 by the API to avoid using floating point. There
// is no min-zoom per se, so clamp it to always 100 (TODO(mcasas): make const member). // is no min-zoom per se, so clamp it to always 100 (TODO(mcasas): make const member).
final int minZoom = 100; final int minZoom = 100;
final int maxZoom = Math.round(mMaxZoom * 100); final int maxZoom = Math.round(mMaxZoom * 100);
// Width Ratio x100 is used as measure of current zoom. // Width Ratio x100 is used as measure of current zoom.
final int currentZoom = 100 * mPreviewRequest.get(CaptureRequest.SCALER_CROP_REGION).width() final int currentZoom = 100 * mPreviewRequest.get(CaptureRequest.SCALER_CROP_REGION).width()
/ cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE) / cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE)
...@@ -533,7 +570,9 @@ public class VideoCaptureCamera2 extends VideoCapture { ...@@ -533,7 +570,9 @@ public class VideoCaptureCamera2 extends VideoCapture {
final boolean isFocusManual = (focusMode == CameraMetadata.CONTROL_AF_MODE_OFF) final boolean isFocusManual = (focusMode == CameraMetadata.CONTROL_AF_MODE_OFF)
|| (focusMode == CameraMetadata.CONTROL_AF_MODE_EDOF); || (focusMode == CameraMetadata.CONTROL_AF_MODE_EDOF);
return new PhotoCapabilities(maxZoom, minZoom, currentZoom, !isFocusManual); return new PhotoCapabilities(minIso, maxIso, currentIso, maxHeight, minHeight,
currentHeight, maxWidth, minWidth, currentWidth, maxZoom, minZoom, currentZoom,
!isFocusManual);
} }
@Override @Override
...@@ -562,12 +601,24 @@ public class VideoCaptureCamera2 extends VideoCapture { ...@@ -562,12 +601,24 @@ public class VideoCaptureCamera2 extends VideoCapture {
} }
@Override @Override
public boolean takePhoto(final long callbackId) { public boolean takePhoto(final long callbackId, int width, int height) {
Log.d(TAG, "takePhoto " + callbackId); Log.d(TAG, "takePhoto " + callbackId);
if (mCameraDevice == null || mCameraState != CameraState.STARTED) return false; if (mCameraDevice == null || mCameraState != CameraState.STARTED) return false;
final ImageReader imageReader = ImageReader.newInstance(mCaptureFormat.getWidth(), final CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(mContext, mId);
mCaptureFormat.getHeight(), ImageFormat.JPEG, 1 /* maxImages */); final StreamConfigurationMap streamMap =
cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
final Size[] supportedSizes = streamMap.getOutputSizes(ImageFormat.JPEG);
final Size closestSize = findClosestSizeInArray(supportedSizes, width, height);
Log.d(TAG, "requested resolution: (%dx%d)", width, height);
if (closestSize != null) {
Log.d(TAG, " matched (%dx%d)", closestSize.getWidth(), closestSize.getHeight());
}
final ImageReader imageReader = ImageReader.newInstance(
(closestSize != null) ? closestSize.getWidth() : mCaptureFormat.getWidth(),
(closestSize != null) ? closestSize.getHeight() : mCaptureFormat.getHeight(),
ImageFormat.JPEG, 1 /* maxImages */);
HandlerThread thread = new HandlerThread("CameraPicture"); HandlerThread thread = new HandlerThread("CameraPicture");
thread.start(); thread.start();
......
...@@ -24,6 +24,58 @@ bool PhotoCapabilities::RegisterPhotoCapabilities(JNIEnv* env) { ...@@ -24,6 +24,58 @@ bool PhotoCapabilities::RegisterPhotoCapabilities(JNIEnv* env) {
return RegisterNativesImpl(env); return RegisterNativesImpl(env);
} }
int PhotoCapabilities::getMinIso() const {
DCHECK(!object_.is_null());
return Java_PhotoCapabilities_getMinIso(AttachCurrentThread(), object_.obj());
}
int PhotoCapabilities::getMaxIso() const {
DCHECK(!object_.is_null());
return Java_PhotoCapabilities_getMaxIso(AttachCurrentThread(), object_.obj());
}
int PhotoCapabilities::getCurrentIso() const {
DCHECK(!object_.is_null());
return Java_PhotoCapabilities_getCurrentIso(AttachCurrentThread(),
object_.obj());
}
int PhotoCapabilities::getMinHeight() const {
DCHECK(!object_.is_null());
return Java_PhotoCapabilities_getMinHeight(AttachCurrentThread(),
object_.obj());
}
int PhotoCapabilities::getMaxHeight() const {
DCHECK(!object_.is_null());
return Java_PhotoCapabilities_getMaxHeight(AttachCurrentThread(),
object_.obj());
}
int PhotoCapabilities::getCurrentHeight() const {
DCHECK(!object_.is_null());
return Java_PhotoCapabilities_getCurrentHeight(AttachCurrentThread(),
object_.obj());
}
int PhotoCapabilities::getMinWidth() const {
DCHECK(!object_.is_null());
return Java_PhotoCapabilities_getMinWidth(AttachCurrentThread(),
object_.obj());
}
int PhotoCapabilities::getMaxWidth() const {
DCHECK(!object_.is_null());
return Java_PhotoCapabilities_getMaxWidth(AttachCurrentThread(),
object_.obj());
}
int PhotoCapabilities::getCurrentWidth() const {
DCHECK(!object_.is_null());
return Java_PhotoCapabilities_getCurrentWidth(AttachCurrentThread(),
object_.obj());
}
int PhotoCapabilities::getMinZoom() const { int PhotoCapabilities::getMinZoom() const {
DCHECK(!object_.is_null()); DCHECK(!object_.is_null());
return Java_PhotoCapabilities_getMinZoom(AttachCurrentThread(), return Java_PhotoCapabilities_getMinZoom(AttachCurrentThread(),
......
...@@ -19,6 +19,15 @@ class PhotoCapabilities { ...@@ -19,6 +19,15 @@ class PhotoCapabilities {
static bool RegisterPhotoCapabilities(JNIEnv* env); static bool RegisterPhotoCapabilities(JNIEnv* env);
int getMinIso() const;
int getMaxIso() const;
int getCurrentIso() const;
int getMinHeight() const;
int getMaxHeight() const;
int getCurrentHeight() const;
int getMinWidth() const;
int getMaxWidth() const;
int getCurrentWidth() const;
int getMinZoom() const; int getMinZoom() const;
int getMaxZoom() const; int getMaxZoom() const;
int getCurrentZoom() const; int getCurrentZoom() const;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/android/jni_android.h" #include "base/android/jni_android.h"
#include "base/android/jni_array.h" #include "base/android/jni_array.h"
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "jni/VideoCapture_jni.h" #include "jni/VideoCapture_jni.h"
#include "media/capture/video/android/photo_capabilities.h" #include "media/capture/video/android/photo_capabilities.h"
...@@ -151,7 +152,9 @@ void VideoCaptureDeviceAndroid::TakePhoto(TakePhotoCallback callback) { ...@@ -151,7 +152,9 @@ void VideoCaptureDeviceAndroid::TakePhoto(TakePhotoCallback callback) {
std::unique_ptr<TakePhotoCallback> heap_callback( std::unique_ptr<TakePhotoCallback> heap_callback(
new TakePhotoCallback(std::move(callback))); new TakePhotoCallback(std::move(callback)));
const intptr_t callback_id = reinterpret_cast<intptr_t>(heap_callback.get()); const intptr_t callback_id = reinterpret_cast<intptr_t>(heap_callback.get());
if (!Java_VideoCapture_takePhoto(env, j_capture_.obj(), callback_id)) if (!Java_VideoCapture_takePhoto(env, j_capture_.obj(), callback_id,
next_photo_resolution_.width(),
next_photo_resolution_.height()))
return; return;
{ {
...@@ -171,6 +174,18 @@ void VideoCaptureDeviceAndroid::GetPhotoCapabilities( ...@@ -171,6 +174,18 @@ void VideoCaptureDeviceAndroid::GetPhotoCapabilities(
// PhotoCapabilities to mojom::PhotoCapabilitiesPtr, https://crbug.com/622002. // PhotoCapabilities to mojom::PhotoCapabilitiesPtr, https://crbug.com/622002.
mojom::PhotoCapabilitiesPtr photo_capabilities = mojom::PhotoCapabilitiesPtr photo_capabilities =
mojom::PhotoCapabilities::New(); mojom::PhotoCapabilities::New();
photo_capabilities->iso = mojom::Range::New();
photo_capabilities->iso->current = caps.getCurrentIso();
photo_capabilities->iso->max = caps.getMaxIso();
photo_capabilities->iso->min = caps.getMinIso();
photo_capabilities->height = mojom::Range::New();
photo_capabilities->height->current = caps.getCurrentHeight();
photo_capabilities->height->max = caps.getMaxHeight();
photo_capabilities->height->min = caps.getMinHeight();
photo_capabilities->width = mojom::Range::New();
photo_capabilities->width->current = caps.getCurrentWidth();
photo_capabilities->width->max = caps.getMaxWidth();
photo_capabilities->width->min = caps.getMinWidth();
photo_capabilities->zoom = mojom::Range::New(); photo_capabilities->zoom = mojom::Range::New();
photo_capabilities->zoom->current = caps.getCurrentZoom(); photo_capabilities->zoom->current = caps.getCurrentZoom();
photo_capabilities->zoom->max = caps.getMaxZoom(); photo_capabilities->zoom->max = caps.getMaxZoom();
...@@ -185,6 +200,18 @@ void VideoCaptureDeviceAndroid::SetPhotoOptions( ...@@ -185,6 +200,18 @@ void VideoCaptureDeviceAndroid::SetPhotoOptions(
mojom::PhotoSettingsPtr settings, mojom::PhotoSettingsPtr settings,
SetPhotoOptionsCallback callback) { SetPhotoOptionsCallback callback) {
JNIEnv* env = AttachCurrentThread(); JNIEnv* env = AttachCurrentThread();
// |width| and/or |height| are kept for the next TakePhoto()s.
if (settings->has_width || settings->has_height)
next_photo_resolution_.SetSize(0, 0);
if (settings->has_width) {
next_photo_resolution_.set_width(
base::saturated_cast<int>(settings->width));
}
if (settings->has_height) {
next_photo_resolution_.set_height(
base::saturated_cast<int>(settings->height));
}
if (settings->has_zoom) if (settings->has_zoom)
Java_VideoCapture_setZoom(env, j_capture_.obj(), settings->zoom); Java_VideoCapture_setZoom(env, j_capture_.obj(), settings->zoom);
callback.Run(true); callback.Run(true);
......
...@@ -117,6 +117,8 @@ class CAPTURE_EXPORT VideoCaptureDeviceAndroid : public VideoCaptureDevice { ...@@ -117,6 +117,8 @@ class CAPTURE_EXPORT VideoCaptureDeviceAndroid : public VideoCaptureDevice {
base::Lock photo_callbacks_lock_; base::Lock photo_callbacks_lock_;
std::list<std::unique_ptr<TakePhotoCallback>> photo_callbacks_; std::list<std::unique_ptr<TakePhotoCallback>> photo_callbacks_;
gfx::Size next_photo_resolution_;
Name device_name_; Name device_name_;
VideoCaptureFormat capture_format_; VideoCaptureFormat capture_format_;
......
...@@ -181,6 +181,19 @@ void FakeVideoCaptureDevice::GetPhotoCapabilities( ...@@ -181,6 +181,19 @@ void FakeVideoCaptureDevice::GetPhotoCapabilities(
GetPhotoCapabilitiesCallback callback) { GetPhotoCapabilitiesCallback callback) {
mojom::PhotoCapabilitiesPtr photo_capabilities = mojom::PhotoCapabilitiesPtr photo_capabilities =
mojom::PhotoCapabilities::New(); mojom::PhotoCapabilities::New();
photo_capabilities->iso = mojom::Range::New();
photo_capabilities->iso->current = 100;
photo_capabilities->iso->max = 100;
photo_capabilities->iso->min = 100;
photo_capabilities->height = mojom::Range::New();
photo_capabilities->height->current = capture_format_.frame_size.height();
photo_capabilities->height->max = 1080;
photo_capabilities->height->min = 240;
photo_capabilities->width = mojom::Range::New();
photo_capabilities->width->current = capture_format_.frame_size.width();
photo_capabilities->width->max = 1920;
photo_capabilities->width->min = 320;
photo_capabilities->focus_mode = mojom::FocusMode::UNAVAILABLE;
photo_capabilities->zoom = mojom::Range::New(); photo_capabilities->zoom = mojom::Range::New();
photo_capabilities->zoom->current = current_zoom_; photo_capabilities->zoom->current = current_zoom_;
photo_capabilities->zoom->max = kMaxZoom; photo_capabilities->zoom->max = kMaxZoom;
......
...@@ -320,6 +320,17 @@ TEST_F(FakeVideoCaptureDeviceTest, GetAndSetCapabilities) { ...@@ -320,6 +320,17 @@ TEST_F(FakeVideoCaptureDeviceTest, GetAndSetCapabilities) {
auto* capabilities = image_capture_client_->capabilities(); auto* capabilities = image_capture_client_->capabilities();
ASSERT_TRUE(capabilities); ASSERT_TRUE(capabilities);
EXPECT_EQ(100u, capabilities->iso->min);
EXPECT_EQ(100u, capabilities->iso->max);
EXPECT_EQ(100u, capabilities->iso->current);
EXPECT_EQ(capture_params.requested_format.frame_size.height(),
static_cast<int>(capabilities->height->current));
EXPECT_EQ(240u, capabilities->height->min);
EXPECT_EQ(1080u, capabilities->height->max);
EXPECT_EQ(capture_params.requested_format.frame_size.width(),
static_cast<int>(capabilities->width->current));
EXPECT_EQ(320u, capabilities->width->min);
EXPECT_EQ(1920u, capabilities->width->max);
EXPECT_EQ(100u, capabilities->zoom->min); EXPECT_EQ(100u, capabilities->zoom->min);
EXPECT_EQ(400u, capabilities->zoom->max); EXPECT_EQ(400u, capabilities->zoom->max);
EXPECT_GE(capabilities->zoom->current, capabilities->zoom->min); EXPECT_GE(capabilities->zoom->current, capabilities->zoom->min);
......
...@@ -19,6 +19,9 @@ enum FocusMode { UNAVAILABLE, AUTO, MANUAL }; ...@@ -19,6 +19,9 @@ enum FocusMode { UNAVAILABLE, AUTO, MANUAL };
// Equivalent to idl PhotoCapabilities, // Equivalent to idl PhotoCapabilities,
// https://w3c.github.io/mediacapture-image/#photocapabilities // https://w3c.github.io/mediacapture-image/#photocapabilities
struct PhotoCapabilities { struct PhotoCapabilities {
Range iso;
Range height;
Range width;
Range zoom; Range zoom;
FocusMode focus_mode; FocusMode focus_mode;
}; };
...@@ -29,6 +32,10 @@ struct PhotoSettings { ...@@ -29,6 +32,10 @@ struct PhotoSettings {
// uint32 cannot be nullable, i.e. uint32? does not work, use instead a flag. // uint32 cannot be nullable, i.e. uint32? does not work, use instead a flag.
bool has_zoom; bool has_zoom;
uint32 zoom; uint32 zoom;
bool has_width;
uint32 width;
bool has_height;
uint32 height;
}; };
// |source_id| is the renderer-side UUID identifier of the image capture device. // |source_id| is the renderer-side UUID identifier of the image capture device.
......
...@@ -33,13 +33,37 @@ async_test(function(t) { ...@@ -33,13 +33,37 @@ async_test(function(t) {
}) })
.then(capabilities => { .then(capabilities => {
assert_true(capabilities instanceof PhotoCapabilities); assert_true(capabilities instanceof PhotoCapabilities);
assert_true(capabilities.zoom instanceof MediaSettingsRange);
assert_true(capabilities.iso instanceof MediaSettingsRange);
assert_equals(capabilities.iso.max, mock_capabilities.iso.max);
assert_equals(capabilities.iso.min, mock_capabilities.iso.min);
assert_equals(capabilities.iso.current,
mock_capabilities.iso.current);
assert_true(capabilities.imageHeight instanceof MediaSettingsRange);
assert_equals(capabilities.imageHeight.max,
mock_capabilities.height.max);
assert_equals(capabilities.imageHeight.min,
mock_capabilities.height.min);
assert_equals(capabilities.imageHeight.current,
mock_capabilities.height.current);
assert_true(capabilities.imageWidth instanceof MediaSettingsRange);
assert_equals(capabilities.imageWidth.max,
mock_capabilities.width.max);
assert_equals(capabilities.imageWidth.min,
mock_capabilities.width.min);
assert_equals(capabilities.imageWidth.current,
mock_capabilities.width.current);
assert_true(capabilities.zoom instanceof MediaSettingsRange);
assert_equals(capabilities.zoom.max, mock_capabilities.zoom.max); assert_equals(capabilities.zoom.max, mock_capabilities.zoom.max);
assert_equals(capabilities.zoom.min, mock_capabilities.zoom.min); assert_equals(capabilities.zoom.min, mock_capabilities.zoom.min);
assert_equals(capabilities.zoom.current, assert_equals(capabilities.zoom.current,
mock_capabilities.zoom.current); mock_capabilities.zoom.current);
assert_equals(capabilities.focusMode, mock_capabilities.focusMode);
t.done(); t.done();
}) })
.catch(error => { .catch(error => {
......
...@@ -14,7 +14,14 @@ let mockImageCaptureReady = define( ...@@ -14,7 +14,14 @@ let mockImageCaptureReady = define(
imageCapture.ImageCapture.name, imageCapture.ImageCapture.name,
pipe => this.bindToPipe(pipe)); pipe => this.bindToPipe(pipe));
this.capabilities_ = { capabilities: { zoom : { min : 0, max : 10, current : 5 } } }; this.capabilities_ = { capabilities : {
iso : { min : 100, max : 12000, current : 400 },
height : { min : 240, max : 2448, current : 240 },
width : { min : 320, max : 3264, current : 320 },
width : { min : 320, max : 3264, current : 320 },
zoom : { min : 0, max : 10, current : 5 },
focusMode : "unavailable",
}};
this.settings_ = null; this.settings_ = null;
} }
......
...@@ -19,7 +19,7 @@ async_test(function(t) { ...@@ -19,7 +19,7 @@ async_test(function(t) {
var stream = canvas.captureStream(); var stream = canvas.captureStream();
var theMock = null; var theMock = null;
const optionsDict = { zoom : 7 }; const optionsDict = { zoom : 7, imageWidth : 1080, imageHeight : 100 };
mockImageCaptureReady mockImageCaptureReady
.then(mock => { .then(mock => {
theMock = mock; theMock = mock;
...@@ -32,8 +32,12 @@ async_test(function(t) { ...@@ -32,8 +32,12 @@ async_test(function(t) {
return capturer.setOptions(optionsDict); return capturer.setOptions(optionsDict);
}) })
.then(function() { .then(function() {
assert_equals(1, theMock.options().has_zoom, 'has_zoom must be true'); assert_true(theMock.options().has_zoom, 'has_zoom must be true');
assert_equals(optionsDict.zoom, theMock.options().zoom, 'zoom value'); assert_equals(optionsDict.zoom, theMock.options().zoom, 'zoom value');
assert_equals(true, theMock.options().has_width, 'has_width must be true');
assert_equals(optionsDict.imageWidth, theMock.options().width, 'width value');
assert_equals(true, theMock.options().has_height, 'has_height must be true');
assert_equals(optionsDict.imageHeight, theMock.options().height, 'height value');
t.done(); t.done();
}) })
.catch(error => { .catch(error => {
......
...@@ -4444,6 +4444,9 @@ interface Permissions ...@@ -4444,6 +4444,9 @@ interface Permissions
interface PhotoCapabilities interface PhotoCapabilities
attribute @@toStringTag attribute @@toStringTag
getter focusMode getter focusMode
getter imageHeight
getter imageWidth
getter iso
getter zoom getter zoom
method constructor method constructor
interface Plugin interface Plugin
......
...@@ -118,6 +118,12 @@ ScriptPromise ImageCapture::setOptions(ScriptState* scriptState, const PhotoSett ...@@ -118,6 +118,12 @@ ScriptPromise ImageCapture::setOptions(ScriptState* scriptState, const PhotoSett
settings->has_zoom = photoSettings.hasZoom(); settings->has_zoom = photoSettings.hasZoom();
if (settings->has_zoom) if (settings->has_zoom)
settings->zoom = photoSettings.zoom(); settings->zoom = photoSettings.zoom();
settings->has_height = photoSettings.hasImageHeight();
if (settings->has_height)
settings->height = photoSettings.imageHeight();
settings->has_width = photoSettings.hasImageWidth();
if (settings->has_width)
settings->width = photoSettings.imageWidth();
m_service->SetOptions(m_streamTrack->component()->source()->id(), std::move(settings), convertToBaseCallback(WTF::bind(&ImageCapture::onSetOptions, wrapPersistent(this), wrapPersistent(resolver)))); m_service->SetOptions(m_streamTrack->component()->source()->id(), std::move(settings), convertToBaseCallback(WTF::bind(&ImageCapture::onSetOptions, wrapPersistent(this), wrapPersistent(resolver))));
return promise; return promise;
...@@ -197,8 +203,14 @@ void ImageCapture::onCapabilities(ScriptPromiseResolver* resolver, media::mojom: ...@@ -197,8 +203,14 @@ void ImageCapture::onCapabilities(ScriptPromiseResolver* resolver, media::mojom:
resolver->reject(DOMException::create(UnknownError, "platform error")); resolver->reject(DOMException::create(UnknownError, "platform error"));
} else { } else {
// TODO(mcasas): Should be using a mojo::StructTraits. // TODO(mcasas): Should be using a mojo::StructTraits.
MediaSettingsRange* iso = MediaSettingsRange::create(capabilities->iso->max, capabilities->iso->min, capabilities->iso->current);
MediaSettingsRange* height = MediaSettingsRange::create(capabilities->height->max, capabilities->height->min, capabilities->height->current);
MediaSettingsRange* width = MediaSettingsRange::create(capabilities->width->max, capabilities->width->min, capabilities->width->current);
MediaSettingsRange* zoom = MediaSettingsRange::create(capabilities->zoom->max, capabilities->zoom->min, capabilities->zoom->current); MediaSettingsRange* zoom = MediaSettingsRange::create(capabilities->zoom->max, capabilities->zoom->min, capabilities->zoom->current);
PhotoCapabilities* caps = PhotoCapabilities::create(); PhotoCapabilities* caps = PhotoCapabilities::create();
caps->setIso(iso);
caps->setImageHeight(height);
caps->setImageWidth(width);
caps->setZoom(zoom); caps->setZoom(zoom);
caps->setFocusMode(capabilities->focus_mode); caps->setFocusMode(capabilities->focus_mode);
resolver->resolve(caps); resolver->resolve(caps);
......
...@@ -12,10 +12,6 @@ PhotoCapabilities* PhotoCapabilities::create() ...@@ -12,10 +12,6 @@ PhotoCapabilities* PhotoCapabilities::create()
return new PhotoCapabilities(); return new PhotoCapabilities();
} }
MediaSettingsRange* PhotoCapabilities::zoom() const { return m_zoom; }
void PhotoCapabilities::setZoom(MediaSettingsRange* value) { m_zoom = value; }
String PhotoCapabilities::focusMode() const String PhotoCapabilities::focusMode() const
{ {
switch (m_focusMode) { switch (m_focusMode) {
...@@ -31,13 +27,11 @@ String PhotoCapabilities::focusMode() const ...@@ -31,13 +27,11 @@ String PhotoCapabilities::focusMode() const
return emptyString(); return emptyString();
} }
void PhotoCapabilities::setFocusMode(media::mojom::blink::FocusMode focusMode)
{
m_focusMode = focusMode;
}
DEFINE_TRACE(PhotoCapabilities) DEFINE_TRACE(PhotoCapabilities)
{ {
visitor->trace(m_iso);
visitor->trace(m_imageHeight);
visitor->trace(m_imageWidth);
visitor->trace(m_zoom); visitor->trace(m_zoom);
} }
......
...@@ -20,17 +20,29 @@ public: ...@@ -20,17 +20,29 @@ public:
static PhotoCapabilities* create(); static PhotoCapabilities* create();
virtual ~PhotoCapabilities() = default; virtual ~PhotoCapabilities() = default;
MediaSettingsRange* zoom() const; MediaSettingsRange* iso() const { return m_iso; }
void setZoom(MediaSettingsRange* value); void setIso(MediaSettingsRange* value) { m_iso = value; }
MediaSettingsRange* imageHeight() const { return m_imageHeight; }
void setImageHeight(MediaSettingsRange* value) { m_imageHeight = value; }
MediaSettingsRange* imageWidth() const { return m_imageWidth; }
void setImageWidth(MediaSettingsRange* value) { m_imageWidth = value; }
MediaSettingsRange* zoom() const { return m_zoom; }
void setZoom(MediaSettingsRange* value) { m_zoom = value; }
String focusMode() const; String focusMode() const;
void setFocusMode(media::mojom::blink::FocusMode); void setFocusMode(media::mojom::blink::FocusMode focusMode) { m_focusMode = focusMode; }
DECLARE_VIRTUAL_TRACE(); DECLARE_VIRTUAL_TRACE();
private: private:
PhotoCapabilities() = default; PhotoCapabilities() = default;
Member<MediaSettingsRange> m_iso;
Member<MediaSettingsRange> m_imageHeight;
Member<MediaSettingsRange> m_imageWidth;
Member<MediaSettingsRange> m_zoom; Member<MediaSettingsRange> m_zoom;
media::mojom::blink::FocusMode m_focusMode = media::mojom::blink::FocusMode::UNAVAILABLE; media::mojom::blink::FocusMode m_focusMode = media::mojom::blink::FocusMode::UNAVAILABLE;
}; };
......
...@@ -13,6 +13,14 @@ enum FocusMode { ...@@ -13,6 +13,14 @@ enum FocusMode {
[ [
RuntimeEnabled=ImageCapture, RuntimeEnabled=ImageCapture,
] interface PhotoCapabilities { ] interface PhotoCapabilities {
// TODO(mcasas): Update the Spec where these members are not readonly.
// https://github.com/w3c/mediacapture-image/issues/29
readonly attribute MediaSettingsRange iso;
// TODO(mcasas): Replace these two with supported and current resolutions.
// https://github.com/w3c/mediacapture-image/issues/30
readonly attribute MediaSettingsRange imageHeight;
readonly attribute MediaSettingsRange imageWidth;
readonly attribute MediaSettingsRange zoom; readonly attribute MediaSettingsRange zoom;
readonly attribute FocusMode focusMode; readonly attribute FocusMode focusMode;
// TODO(mcasas): Implement all other PhotoCapabilities fields // TODO(mcasas): Implement all other PhotoCapabilities fields
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
RuntimeEnabled=ImageCapture RuntimeEnabled=ImageCapture
] dictionary PhotoSettings { ] dictionary PhotoSettings {
unsigned long zoom; unsigned long zoom;
unsigned long imageHeight;
unsigned long imageWidth;
// TODO(mcasas): Implement all other PhotoSettings fields // TODO(mcasas): Implement all other PhotoSettings fields
// https://crbug.com/518807 // https://crbug.com/518807
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment