CameraITS: add support for zoom in 3a/video
Details: Allowed zoom ratio to be passed in do_3a() and for basic video recording/preview recording.
Bug: 215603925
Test: tested locally on Pixel device.
Change-Id: Iedd884052dc182533b569fceb0967e150748e1a1
diff --git a/apps/CameraITS/utils/its_session_utils.py b/apps/CameraITS/utils/its_session_utils.py
index 76496d5..890d1e9 100644
--- a/apps/CameraITS/utils/its_session_utils.py
+++ b/apps/CameraITS/utils/its_session_utils.py
@@ -390,6 +390,17 @@
if data['tag'] != 'cameraClosed':
raise error_util.CameraItsError('Invalid command response')
+ def zoom_ratio_within_range(self, zoom_ratio):
+ """Determine if a given zoom ratio is within device zoom range.
+
+ Args:
+ zoom_ratio: float; zoom ratio requested
+ Returns:
+ Boolean: True, if zoom_ratio inside device range. False otherwise.
+ """
+ zoom_range = self.props['android.control.zoomRatioRange']
+ return zoom_ratio >= zoom_range[0] and zoom_ratio <= zoom_range[1]
+
def get_sensors(self):
"""Get all sensors on the device.
@@ -475,7 +486,8 @@
return data['strValue'] == 'true'
def do_basic_recording(self, profile_id, quality, duration,
- video_stabilization_mode=0, hlg10_enabled=False):
+ video_stabilization_mode=0, hlg10_enabled=False,
+ zoom_ratio=None):
"""Issue a recording request and read back the video recording object.
The recording will be done with the format specified in quality. These
@@ -492,6 +504,7 @@
0: 'OFF', 1: 'ON', 2: 'PREVIEW'
hlg10_enabled: boolean: True Enable 10-bit HLG video recording, False
record using the regular SDR profile
+ zoom_ratio: float; zoom ratio. None if default zoom
Returns:
video_recorded_object: The recorded object returned from ItsService which
contains path at which the recording is saved on the device, quality of
@@ -515,6 +528,11 @@
'recordingDuration': duration,
'videoStabilizationMode': video_stabilization_mode,
'hlg10Enabled': hlg10_enabled}
+ if zoom_ratio:
+ if self.zoom_ratio_within_range(zoom_ratio):
+ cmd['zoomRatio'] = zoom_ratio
+ else:
+ raise AssertionError(f'Zoom ratio {zoom_ratio} out of range')
self.sock.send(json.dumps(cmd).encode() + '\n'.encode())
timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT
self.sock.settimeout(timeout)
@@ -525,7 +543,8 @@
logging.debug('VideoRecordingObject: %s', data)
return data['objValue']
- def do_preview_recording(self, video_size, duration, stabilize):
+ def do_preview_recording(self, video_size, duration, stabilize,
+ zoom_ratio=None):
"""Issue a preview request and read back the preview recording object.
The resolution of the preview and its recording will be determined by
@@ -537,6 +556,7 @@
video_size: str; Preview resolution at which to record. ex. "1920x1080"
duration: int; The time in seconds for which the video will be recorded.
stabilize: boolean; Whether the preview should be stabilized or not
+ zoom_ratio: float; zoom ratio. None if default zoom
Returns:
video_recorded_object: The recorded object returned from ItsService which
contains path at which the recording is saved on the device, quality of
@@ -562,6 +582,11 @@
'recordingDuration': duration,
'stabilize': stabilize
}
+ if zoom_ratio:
+ if self.zoom_ratio_within_range(zoom_ratio):
+ cmd['zoomRatio'] = zoom_ratio
+ else:
+ raise AssertionError(f'Zoom ratio {zoom_ratio} out of range')
self.sock.send(json.dumps(cmd).encode() + '\n'.encode())
timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT
self.sock.settimeout(timeout)
@@ -1222,7 +1247,8 @@
get_results=False,
ev_comp=0,
auto_flash=False,
- mono_camera=False):
+ mono_camera=False,
+ zoom_ratio=None):
"""Perform a 3A operation on the device.
Triggers some or all of AE, AWB, and AF, and returns once they have
@@ -1244,6 +1270,7 @@
ev_comp: An EV compensation value to use when running AE.
auto_flash: AE control boolean to enable auto flash.
mono_camera: Boolean for monochrome camera.
+ zoom_ratio: Zoom ratio. None if default zoom
Region format in args:
Arguments are lists of weighted regions; each weighted region is a
@@ -1281,6 +1308,11 @@
cmd['autoFlash'] = True
if self._hidden_physical_id:
cmd['physicalId'] = self._hidden_physical_id
+ if zoom_ratio:
+ if self.zoom_ratio_within_range(zoom_ratio):
+ cmd['zoomRatio'] = zoom_ratio
+ else:
+ raise AssertionError(f'Zoom ratio {zoom_ratio} out of range')
self.sock.send(json.dumps(cmd).encode() + '\n'.encode())
# Wait for each specified 3A to converge.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index 4a6b877..950248a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -182,6 +182,7 @@
public static final String VIB_PATTERN_KEY = "pattern";
public static final String EVCOMP_KEY = "evComp";
public static final String AUTO_FLASH_KEY = "autoFlash";
+ public static final String ZOOM_RATIO_KEY = "zoomRatio";
public static final String AUDIO_RESTRICTION_MODE_KEY = "mode";
private CameraManager mCameraManager = null;
@@ -268,19 +269,23 @@
public Size videoSize;
public int videoFrameRate; // -1 implies video framerate was not set by the test
public int fileFormat;
+ public double zoomRatio;
public VideoRecordingObject(String recordedOutputPath,
- String quality, Size videoSize, int videoFrameRate, int fileFormat) {
+ String quality, Size videoSize, int videoFrameRate,
+ int fileFormat, double zoomRatio) {
this.recordedOutputPath = recordedOutputPath;
this.quality = quality;
this.videoSize = videoSize;
this.videoFrameRate = videoFrameRate;
this.fileFormat = fileFormat;
+ this.zoomRatio = zoomRatio;
}
VideoRecordingObject(String recordedOutputPath, String quality, Size videoSize,
- int fileFormat) {
- this(recordedOutputPath, quality, videoSize, INVALID_FRAME_RATE, fileFormat);
+ int fileFormat, double zoomRatio) {
+ this(recordedOutputPath, quality, videoSize,
+ INVALID_FRAME_RATE, fileFormat, zoomRatio);
}
public boolean isFrameRateValid() {
@@ -812,14 +817,17 @@
int recordingDuration = cmdObj.getInt("recordingDuration");
int videoStabilizationMode = cmdObj.getInt("videoStabilizationMode");
boolean hlg10Enabled = cmdObj.getBoolean("hlg10Enabled");
+ double zoomRatio = cmdObj.optDouble("zoomRatio");
doBasicRecording(cameraId, profileId, quality, recordingDuration,
- videoStabilizationMode, hlg10Enabled);
+ videoStabilizationMode, hlg10Enabled, zoomRatio);
} else if ("doPreviewRecording".equals(cmdObj.getString("cmdName"))) {
String cameraId = cmdObj.getString("cameraId");
String videoSize = cmdObj.getString("videoSize");
int recordingDuration = cmdObj.getInt("recordingDuration");
boolean stabilize = cmdObj.getBoolean("stabilize");
- doBasicPreviewRecording(cameraId, videoSize, recordingDuration, stabilize);
+ double zoomRatio = cmdObj.optDouble("zoomRatio");
+ doBasicPreviewRecording(cameraId, videoSize, recordingDuration,
+ stabilize, zoomRatio);
} else if ("isHLG10Supported".equals(cmdObj.getString("cmdName"))) {
String cameraId = cmdObj.getString("cameraId");
int profileId = cmdObj.getInt("profileId");
@@ -1454,6 +1462,11 @@
Logt.i(TAG, String.format("Running with auto flash mode."));
}
+ double zoomRatio = params.optDouble(ZOOM_RATIO_KEY);
+ if (!Double.isNaN(zoomRatio)) {
+ Logt.i(TAG, String.format("Running 3A with zoom ratio: %f", zoomRatio));
+ }
+
// By default, AE and AF both get triggered, but the user can optionally override this.
// Also, AF won't get triggered if the lens is fixed-focus.
if (params.has(TRIGGER_KEY)) {
@@ -1550,6 +1563,10 @@
CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
}
+ if (!Double.isNaN(zoomRatio)) {
+ req.set(CaptureRequest.CONTROL_ZOOM_RATIO, (float) zoomRatio);
+ }
+
if (mConvergedAE && mNeedsLockedAE) {
req.set(CaptureRequest.CONTROL_AE_LOCK, true);
}
@@ -1921,13 +1938,14 @@
}
private void doBasicRecording(String cameraId, int profileId, String quality,
- int recordingDuration, int videoStabilizationMode, boolean hlg10Enabled)
+ int recordingDuration, int videoStabilizationMode,
+ boolean hlg10Enabled, double zoomRatio)
throws ItsException {
final long SESSION_CLOSE_TIMEOUT_MS = 3000;
if (!hlg10Enabled) {
doBasicRecording(cameraId, profileId, quality, recordingDuration,
- videoStabilizationMode);
+ videoStabilizationMode, zoomRatio);
return;
}
@@ -1946,7 +1964,8 @@
String outputFilePath = getOutputMediaFile(cameraDeviceId, videoSize, quality, fileFormat,
/* hlg10Enabled= */ true,
/* stabilized= */
- videoStabilizationMode != CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_OFF);
+ videoStabilizationMode != CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_OFF,
+ zoomRatio);
assert (outputFilePath != null);
MediaCodecList list = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
@@ -1994,7 +2013,7 @@
// Configure and create capture session.
try {
configureAndCreateCaptureSession(CameraDevice.TEMPLATE_RECORD, mRecordSurface,
- videoStabilizationMode, DynamicRangeProfiles.HLG10, mockCallback);
+ videoStabilizationMode, DynamicRangeProfiles.HLG10, mockCallback, zoomRatio);
} catch (CameraAccessException e) {
throw new ItsException("Access error: ", e);
}
@@ -2032,12 +2051,13 @@
// Send VideoRecordingObject for further processing.
VideoRecordingObject obj = new VideoRecordingObject(outputFilePath,
- quality, videoSize, camcorderProfile.videoFrameRate, fileFormat);
+ quality, videoSize, camcorderProfile.videoFrameRate, fileFormat, zoomRatio);
mSocketRunnableObj.sendVideoRecordingObject(obj);
}
private void doBasicRecording(String cameraId, int profileId, String quality,
- int recordingDuration, int videoStabilizationMode) throws ItsException {
+ int recordingDuration, int videoStabilizationMode,
+ double zoomRatio) throws ItsException {
int cameraDeviceId = Integer.parseInt(cameraId);
mMediaRecorder = new MediaRecorder();
CamcorderProfile camcorderProfile = getCamcorderProfile(cameraDeviceId, profileId);
@@ -2053,7 +2073,8 @@
int fileFormat = camcorderProfile.fileFormat;
String outputFilePath = getOutputMediaFile(cameraDeviceId, videoSize, quality,
fileFormat, /* stabilized= */
- videoStabilizationMode != CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_OFF);
+ videoStabilizationMode != CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_OFF,
+ zoomRatio);
assert(outputFilePath != null);
Log.i(TAG, "Video recording outputFilePath:"+ outputFilePath);
setupMediaRecorderWithProfile(cameraDeviceId, camcorderProfile, outputFilePath);
@@ -2068,7 +2089,7 @@
// Configure and create capture session.
try {
configureAndCreateCaptureSession(CameraDevice.TEMPLATE_RECORD, mRecordSurface,
- videoStabilizationMode);
+ videoStabilizationMode, zoomRatio);
} catch (android.hardware.camera2.CameraAccessException e) {
throw new ItsException("Access error: ", e);
}
@@ -2098,7 +2119,7 @@
// Send VideoRecordingObject for further processing.
VideoRecordingObject obj = new VideoRecordingObject(outputFilePath,
- quality, videoSize, camcorderProfile.videoFrameRate, fileFormat);
+ quality, videoSize, camcorderProfile.videoFrameRate, fileFormat, zoomRatio);
mSocketRunnableObj.sendVideoRecordingObject(obj);
}
@@ -2113,7 +2134,7 @@
* ImageReader to the MediaRecorder surface which is encoded into a video.
*/
private void doBasicPreviewRecording(String cameraId, String videoSizeString,
- int recordingDuration, boolean stabilize)
+ int recordingDuration, boolean stabilize, double zoomRatio)
throws ItsException {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
@@ -2135,7 +2156,7 @@
int fileFormat = MediaRecorder.OutputFormat.DEFAULT;
String outputFilePath = getOutputMediaFile(cameraDeviceId, videoSize,
- /* quality= */"preview", fileFormat, stabilize);
+ /* quality= */"preview", fileFormat, stabilize, zoomRatio);
assert outputFilePath != null;
try (PreviewRecorder pr = new PreviewRecorder(cameraDeviceId, videoSize,
@@ -2144,7 +2165,7 @@
? CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION
: CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_OFF;
configureAndCreateCaptureSession(CameraDevice.TEMPLATE_PREVIEW,
- pr.getCameraSurface(), stabilizationMode);
+ pr.getCameraSurface(), stabilizationMode, zoomRatio);
pr.recordPreview(recordingDuration * 1000L);
mSession.close();
} catch (CameraAccessException e) {
@@ -2154,22 +2175,26 @@
Log.i(TAG, "Preview recording complete: " + outputFilePath);
// Send VideoRecordingObject for further processing.
VideoRecordingObject obj = new VideoRecordingObject(outputFilePath, /* quality= */"preview",
- videoSize, fileFormat);
+ videoSize, fileFormat, zoomRatio);
mSocketRunnableObj.sendVideoRecordingObject(obj);
}
private void configureAndCreateCaptureSession(int requestTemplate, Surface recordSurface,
- int videoStabilizationMode) throws CameraAccessException {
+ int videoStabilizationMode, double zoomRatio) throws CameraAccessException {
configureAndCreateCaptureSession(requestTemplate, recordSurface, videoStabilizationMode,
- DynamicRangeProfiles.STANDARD, /* stateCallback= */ null);
+ DynamicRangeProfiles.STANDARD, /* stateCallback= */ null, zoomRatio);
}
private void configureAndCreateCaptureSession(int requestTemplate, Surface recordSurface,
int videoStabilizationMode, long dynamicRangeProfile,
- CameraCaptureSession.StateCallback stateCallback) throws CameraAccessException {
+ CameraCaptureSession.StateCallback stateCallback,
+ double zoomRatio) throws CameraAccessException {
assert (recordSurface != null);
// Create capture request builder
mCaptureRequestBuilder = mCamera.createCaptureRequest(requestTemplate);
+ if (!Double.isNaN(zoomRatio)) {
+ mCaptureRequestBuilder.set(CaptureRequest.CONTROL_ZOOM_RATIO, (float) zoomRatio);
+ }
switch (videoStabilizationMode) {
case CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON:
@@ -2250,13 +2275,13 @@
}
private String getOutputMediaFile(int cameraId, Size videoSize, String quality,
- int fileFormat, boolean stabilized) {
+ int fileFormat, boolean stabilized, double zoomRatio) {
return getOutputMediaFile(cameraId, videoSize, quality, fileFormat,
- /* hlg10Enabled= */false, stabilized);
+ /* hlg10Enabled= */false, stabilized, zoomRatio);
}
private String getOutputMediaFile(int cameraId, Size videoSize, String quality,
- int fileFormat, boolean hlg10Enabled, boolean stabilized) {
+ int fileFormat, boolean hlg10Enabled, boolean stabilized, double zoomRatio) {
// If any quality has file format other than 3gp and webm then the
// recording file will have mp4 as default extension.
String fileExtension = "";
@@ -2281,7 +2306,11 @@
}
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String fileName = mediaStorageDir.getPath() + File.separator +
- "VID_" + timestamp + '_' + cameraId + '_' + quality + '_' + videoSize;
+ "VID_" + timestamp + '_' + cameraId + '_' + quality + '_' +
+ videoSize;
+ if (!Double.isNaN(zoomRatio)) {
+ fileName += "_" + zoomRatio;
+ }
if (hlg10Enabled) {
fileName += "_hlg10";
}