1*b7c941bbSAndroid Build Coastguard Worker# Copyright 2013 The Android Open Source Project 2*b7c941bbSAndroid Build Coastguard Worker# 3*b7c941bbSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*b7c941bbSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*b7c941bbSAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*b7c941bbSAndroid Build Coastguard Worker# 7*b7c941bbSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*b7c941bbSAndroid Build Coastguard Worker# 9*b7c941bbSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*b7c941bbSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*b7c941bbSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*b7c941bbSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*b7c941bbSAndroid Build Coastguard Worker# limitations under the License. 14*b7c941bbSAndroid Build Coastguard Worker"""Utility functions to form an ItsSession and perform various camera actions. 15*b7c941bbSAndroid Build Coastguard Worker""" 16*b7c941bbSAndroid Build Coastguard Worker 17*b7c941bbSAndroid Build Coastguard Worker 18*b7c941bbSAndroid Build Coastguard Workerimport collections 19*b7c941bbSAndroid Build Coastguard Workerimport fnmatch 20*b7c941bbSAndroid Build Coastguard Workerimport glob 21*b7c941bbSAndroid Build Coastguard Workerimport json 22*b7c941bbSAndroid Build Coastguard Workerimport logging 23*b7c941bbSAndroid Build Coastguard Workerimport math 24*b7c941bbSAndroid Build Coastguard Workerimport os 25*b7c941bbSAndroid Build Coastguard Workerimport socket 26*b7c941bbSAndroid Build Coastguard Workerimport subprocess 27*b7c941bbSAndroid Build Coastguard Workerimport sys 28*b7c941bbSAndroid Build Coastguard Workerimport time 29*b7c941bbSAndroid Build Coastguard Workerimport types 30*b7c941bbSAndroid Build Coastguard Workerimport unicodedata 31*b7c941bbSAndroid Build Coastguard Worker 32*b7c941bbSAndroid Build Coastguard Workerfrom mobly.controllers.android_device_lib import adb 33*b7c941bbSAndroid Build Coastguard Workerimport numpy 34*b7c941bbSAndroid Build Coastguard Worker 35*b7c941bbSAndroid Build Coastguard Workerimport camera_properties_utils 36*b7c941bbSAndroid Build Coastguard Workerimport capture_request_utils 37*b7c941bbSAndroid Build Coastguard Workerimport error_util 38*b7c941bbSAndroid Build Coastguard Workerimport image_processing_utils 39*b7c941bbSAndroid Build Coastguard Workerimport its_device_utils 40*b7c941bbSAndroid Build Coastguard Workerimport opencv_processing_utils 41*b7c941bbSAndroid Build Coastguard Workerimport ui_interaction_utils 42*b7c941bbSAndroid Build Coastguard Worker 43*b7c941bbSAndroid Build Coastguard WorkerANDROID13_API_LEVEL = 33 44*b7c941bbSAndroid Build Coastguard WorkerANDROID14_API_LEVEL = 34 45*b7c941bbSAndroid Build Coastguard WorkerANDROID15_API_LEVEL = 35 46*b7c941bbSAndroid Build Coastguard WorkerANDROID16_API_LEVEL = 36 47*b7c941bbSAndroid Build Coastguard WorkerCHART_DISTANCE_NO_SCALING = 0 48*b7c941bbSAndroid Build Coastguard WorkerIMAGE_FORMAT_JPEG = 256 49*b7c941bbSAndroid Build Coastguard WorkerIMAGE_FORMAT_YUV_420_888 = 35 50*b7c941bbSAndroid Build Coastguard WorkerJCA_CAPTURE_PATH_TAG = 'JCA_CAPTURE_PATH' 51*b7c941bbSAndroid Build Coastguard WorkerJCA_CAPTURE_STATUS_TAG = 'JCA_CAPTURE_STATUS' 52*b7c941bbSAndroid Build Coastguard WorkerLOAD_SCENE_DELAY_SEC = 3 53*b7c941bbSAndroid Build Coastguard WorkerPREVIEW_MAX_TESTED_AREA = 1920 * 1440 54*b7c941bbSAndroid Build Coastguard WorkerPREVIEW_MIN_TESTED_AREA = 320 * 240 55*b7c941bbSAndroid Build Coastguard WorkerPRIVATE_FORMAT = 'priv' 56*b7c941bbSAndroid Build Coastguard WorkerJPEG_R_FMT_STR = 'jpeg_r' 57*b7c941bbSAndroid Build Coastguard WorkerSCALING_TO_FILE_ATOL = 0.01 58*b7c941bbSAndroid Build Coastguard WorkerSINGLE_CAPTURE_NCAP = 1 59*b7c941bbSAndroid Build Coastguard WorkerSUB_CAMERA_SEPARATOR = '.' 60*b7c941bbSAndroid Build Coastguard Worker# pylint: disable=line-too-long 61*b7c941bbSAndroid Build Coastguard Worker# Allowed tablets as listed on https://source.android.com/docs/compatibility/cts/camera-its-box#tablet-requirements 62*b7c941bbSAndroid Build Coastguard Worker# List entries must be entered in lowercase 63*b7c941bbSAndroid Build Coastguard WorkerTABLET_ALLOWLIST = ( 64*b7c941bbSAndroid Build Coastguard Worker 'dragon', # Google Pixel C 65*b7c941bbSAndroid Build Coastguard Worker 'hnhey-q', # Honor Pad 8 66*b7c941bbSAndroid Build Coastguard Worker 'hwcmr09', # Huawei MediaPad M5 67*b7c941bbSAndroid Build Coastguard Worker 'x306f', # Lenovo Tab M10 HD (Gen 2) 68*b7c941bbSAndroid Build Coastguard Worker 'x606f', # Lenovo Tab M10 Plus 69*b7c941bbSAndroid Build Coastguard Worker 'j606f', # Lenovo Tab P11 70*b7c941bbSAndroid Build Coastguard Worker 'tb350fu', # Lenovo Tab P11 (Gen 2) 71*b7c941bbSAndroid Build Coastguard Worker 'agta', # Nokia T21 72*b7c941bbSAndroid Build Coastguard Worker 'gta4lwifi', # Samsung Galaxy Tab A7 73*b7c941bbSAndroid Build Coastguard Worker 'gta8wifi', # Samsung Galaxy Tab A8 74*b7c941bbSAndroid Build Coastguard Worker 'gta8', # Samsung Galaxy Tab A8 LTE 75*b7c941bbSAndroid Build Coastguard Worker 'gta9pwifi', # Samsung Galaxy Tab A9+ 76*b7c941bbSAndroid Build Coastguard Worker 'gta9p', # Samsung Galaxy Tab A9+ 5G 77*b7c941bbSAndroid Build Coastguard Worker 'dpd2221', # Vivo Pad2 78*b7c941bbSAndroid Build Coastguard Worker 'nabu', # Xiaomi Pad 5 79*b7c941bbSAndroid Build Coastguard Worker 'nabu_tw', # Xiaomi Pad 5 80*b7c941bbSAndroid Build Coastguard Worker 'xun', # Xiaomi Redmi Pad SE 81*b7c941bbSAndroid Build Coastguard Worker 'yunluo', # Xiaomi Redmi Pad 82*b7c941bbSAndroid Build Coastguard Worker) 83*b7c941bbSAndroid Build Coastguard WorkerTABLET_DEFAULT_BRIGHTNESS = 192 # 8-bit tablet 75% brightness 84*b7c941bbSAndroid Build Coastguard WorkerTABLET_LEGACY_BRIGHTNESS = 96 85*b7c941bbSAndroid Build Coastguard WorkerTABLET_LEGACY_NAME = 'dragon' 86*b7c941bbSAndroid Build Coastguard Worker# List entries must be entered in lowercase 87*b7c941bbSAndroid Build Coastguard WorkerTABLET_OS_VERSION = types.MappingProxyType({ 88*b7c941bbSAndroid Build Coastguard Worker 'nabu': ANDROID13_API_LEVEL, 89*b7c941bbSAndroid Build Coastguard Worker 'nabu_tw': ANDROID13_API_LEVEL, 90*b7c941bbSAndroid Build Coastguard Worker 'yunluo': ANDROID14_API_LEVEL 91*b7c941bbSAndroid Build Coastguard Worker }) 92*b7c941bbSAndroid Build Coastguard WorkerTABLET_REQUIREMENTS_URL = 'https://source.android.com/docs/compatibility/cts/camera-its-box#tablet-allowlist' 93*b7c941bbSAndroid Build Coastguard WorkerTABLET_BRIGHTNESS_ERROR_MSG = ('Tablet brightness not set as per ' 94*b7c941bbSAndroid Build Coastguard Worker f'{TABLET_REQUIREMENTS_URL} in the config file') 95*b7c941bbSAndroid Build Coastguard WorkerTABLET_NOT_ALLOWED_ERROR_MSG = ('Tablet model or tablet Android version is ' 96*b7c941bbSAndroid Build Coastguard Worker 'not on our allowlist, please refer to ' 97*b7c941bbSAndroid Build Coastguard Worker f'{TABLET_REQUIREMENTS_URL}') 98*b7c941bbSAndroid Build Coastguard WorkerTAP_COORDINATES = (500, 500) # Location to tap tablet screen via adb 99*b7c941bbSAndroid Build Coastguard WorkerUSE_CASE_CROPPED_RAW = 6 100*b7c941bbSAndroid Build Coastguard WorkerVIDEO_SCENES = ('scene_video',) 101*b7c941bbSAndroid Build Coastguard WorkerNOT_YET_MANDATED_MESSAGE = 'Not yet mandated test' 102*b7c941bbSAndroid Build Coastguard WorkerRESULT_OK_STATUS = '-1' 103*b7c941bbSAndroid Build Coastguard Worker 104*b7c941bbSAndroid Build Coastguard Worker_FLASH_MODE_OFF = 0 105*b7c941bbSAndroid Build Coastguard Worker_VALIDATE_LIGHTING_PATCH_H = 0.05 106*b7c941bbSAndroid Build Coastguard Worker_VALIDATE_LIGHTING_PATCH_W = 0.05 107*b7c941bbSAndroid Build Coastguard Worker_VALIDATE_LIGHTING_REGIONS = { 108*b7c941bbSAndroid Build Coastguard Worker 'top-left': (0, 0), 109*b7c941bbSAndroid Build Coastguard Worker 'top-right': (0, 1-_VALIDATE_LIGHTING_PATCH_H), 110*b7c941bbSAndroid Build Coastguard Worker 'bottom-left': (1-_VALIDATE_LIGHTING_PATCH_W, 0), 111*b7c941bbSAndroid Build Coastguard Worker 'bottom-right': (1-_VALIDATE_LIGHTING_PATCH_W, 112*b7c941bbSAndroid Build Coastguard Worker 1-_VALIDATE_LIGHTING_PATCH_H), 113*b7c941bbSAndroid Build Coastguard Worker} 114*b7c941bbSAndroid Build Coastguard Worker_MODULAR_MACRO_OFFSET = 0.35 # Determined empirically from modular rig testing 115*b7c941bbSAndroid Build Coastguard Worker_VALIDATE_LIGHTING_REGIONS_MODULAR_UW = { 116*b7c941bbSAndroid Build Coastguard Worker 'top-left': (_MODULAR_MACRO_OFFSET, _MODULAR_MACRO_OFFSET), 117*b7c941bbSAndroid Build Coastguard Worker 'bottom-left': (_MODULAR_MACRO_OFFSET, 118*b7c941bbSAndroid Build Coastguard Worker 1-_MODULAR_MACRO_OFFSET-_VALIDATE_LIGHTING_PATCH_H), 119*b7c941bbSAndroid Build Coastguard Worker 'top-right': (1-_MODULAR_MACRO_OFFSET-_VALIDATE_LIGHTING_PATCH_W, 120*b7c941bbSAndroid Build Coastguard Worker _MODULAR_MACRO_OFFSET), 121*b7c941bbSAndroid Build Coastguard Worker 'bottom-right': (1-_MODULAR_MACRO_OFFSET-_VALIDATE_LIGHTING_PATCH_W, 122*b7c941bbSAndroid Build Coastguard Worker 1-_MODULAR_MACRO_OFFSET-_VALIDATE_LIGHTING_PATCH_H), 123*b7c941bbSAndroid Build Coastguard Worker} 124*b7c941bbSAndroid Build Coastguard Worker_VALIDATE_LIGHTING_MACRO_FOV_THRESH = 110 125*b7c941bbSAndroid Build Coastguard Worker_VALIDATE_LIGHTING_THRESH = 0.05 # Determined empirically from scene[1:6] tests 126*b7c941bbSAndroid Build Coastguard Worker_VALIDATE_LIGHTING_THRESH_DARK = 0.3 # Determined empirically for night test 127*b7c941bbSAndroid Build Coastguard Worker_CMD_NAME_STR = 'cmdName' 128*b7c941bbSAndroid Build Coastguard Worker_OBJ_VALUE_STR = 'objValue' 129*b7c941bbSAndroid Build Coastguard Worker_STR_VALUE_STR = 'strValue' 130*b7c941bbSAndroid Build Coastguard Worker_TAG_STR = 'tag' 131*b7c941bbSAndroid Build Coastguard Worker_CAMERA_ID_STR = 'cameraId' 132*b7c941bbSAndroid Build Coastguard Worker_EXTRA_TIMEOUT_FACTOR = 10 133*b7c941bbSAndroid Build Coastguard Worker_COPY_SCENE_DELAY_SEC = 1 134*b7c941bbSAndroid Build Coastguard Worker_DST_SCENE_DIR = '/sdcard/Download/' 135*b7c941bbSAndroid Build Coastguard Worker_BIT_HLG10 = 0x01 # bit 1 for feature mask 136*b7c941bbSAndroid Build Coastguard Worker_BIT_STABILIZATION = 0x02 # bit 2 for feature mask 137*b7c941bbSAndroid Build Coastguard Worker 138*b7c941bbSAndroid Build Coastguard Worker 139*b7c941bbSAndroid Build Coastguard Workerdef validate_tablet(tablet_name, brightness, device_id): 140*b7c941bbSAndroid Build Coastguard Worker """Ensures tablet brightness is set according to documentation. 141*b7c941bbSAndroid Build Coastguard Worker 142*b7c941bbSAndroid Build Coastguard Worker https://source.android.com/docs/compatibility/cts/camera-its-box#tablet-allowlist 143*b7c941bbSAndroid Build Coastguard Worker Args: 144*b7c941bbSAndroid Build Coastguard Worker tablet_name: tablet product name specified by `ro.product.device`. 145*b7c941bbSAndroid Build Coastguard Worker brightness: brightness specified by config file. 146*b7c941bbSAndroid Build Coastguard Worker device_id: str; ID of the device. 147*b7c941bbSAndroid Build Coastguard Worker """ 148*b7c941bbSAndroid Build Coastguard Worker tablet_name = tablet_name.lower() 149*b7c941bbSAndroid Build Coastguard Worker if tablet_name not in TABLET_ALLOWLIST: 150*b7c941bbSAndroid Build Coastguard Worker raise AssertionError( 151*b7c941bbSAndroid Build Coastguard Worker f'Tablet product name: {tablet_name}. {TABLET_NOT_ALLOWED_ERROR_MSG}' 152*b7c941bbSAndroid Build Coastguard Worker ) 153*b7c941bbSAndroid Build Coastguard Worker if tablet_name in TABLET_OS_VERSION: 154*b7c941bbSAndroid Build Coastguard Worker if (device_sdk := get_build_sdk_version( 155*b7c941bbSAndroid Build Coastguard Worker device_id)) < TABLET_OS_VERSION[tablet_name]: 156*b7c941bbSAndroid Build Coastguard Worker raise AssertionError( 157*b7c941bbSAndroid Build Coastguard Worker f' Tablet product name: {tablet_name}. ' 158*b7c941bbSAndroid Build Coastguard Worker f'Android version: {device_sdk}. {TABLET_NOT_ALLOWED_ERROR_MSG}' 159*b7c941bbSAndroid Build Coastguard Worker ) 160*b7c941bbSAndroid Build Coastguard Worker name_to_brightness = { 161*b7c941bbSAndroid Build Coastguard Worker TABLET_LEGACY_NAME: TABLET_LEGACY_BRIGHTNESS, 162*b7c941bbSAndroid Build Coastguard Worker } 163*b7c941bbSAndroid Build Coastguard Worker if tablet_name in name_to_brightness: 164*b7c941bbSAndroid Build Coastguard Worker if brightness != name_to_brightness[tablet_name]: 165*b7c941bbSAndroid Build Coastguard Worker raise AssertionError(TABLET_BRIGHTNESS_ERROR_MSG) 166*b7c941bbSAndroid Build Coastguard Worker else: 167*b7c941bbSAndroid Build Coastguard Worker if brightness != TABLET_DEFAULT_BRIGHTNESS: 168*b7c941bbSAndroid Build Coastguard Worker raise AssertionError(TABLET_BRIGHTNESS_ERROR_MSG) 169*b7c941bbSAndroid Build Coastguard Worker 170*b7c941bbSAndroid Build Coastguard Worker 171*b7c941bbSAndroid Build Coastguard Workerdef check_apk_installed(device_id, package_name): 172*b7c941bbSAndroid Build Coastguard Worker """Verifies that an APK is installed on a given device. 173*b7c941bbSAndroid Build Coastguard Worker 174*b7c941bbSAndroid Build Coastguard Worker Args: 175*b7c941bbSAndroid Build Coastguard Worker device_id: str; ID of the device. 176*b7c941bbSAndroid Build Coastguard Worker package_name: str; name of the package that should be installed. 177*b7c941bbSAndroid Build Coastguard Worker """ 178*b7c941bbSAndroid Build Coastguard Worker verify_cts_cmd = ( 179*b7c941bbSAndroid Build Coastguard Worker f'adb -s {device_id} shell pm list packages | ' 180*b7c941bbSAndroid Build Coastguard Worker f'grep {package_name}' 181*b7c941bbSAndroid Build Coastguard Worker ) 182*b7c941bbSAndroid Build Coastguard Worker bytes_output = subprocess.check_output( 183*b7c941bbSAndroid Build Coastguard Worker verify_cts_cmd, stderr=subprocess.STDOUT, shell=True 184*b7c941bbSAndroid Build Coastguard Worker ) 185*b7c941bbSAndroid Build Coastguard Worker output = str(bytes_output.decode('utf-8')).strip() 186*b7c941bbSAndroid Build Coastguard Worker if package_name not in output: 187*b7c941bbSAndroid Build Coastguard Worker raise AssertionError( 188*b7c941bbSAndroid Build Coastguard Worker f'{package_name} not installed on device {device_id}!' 189*b7c941bbSAndroid Build Coastguard Worker ) 190*b7c941bbSAndroid Build Coastguard Worker 191*b7c941bbSAndroid Build Coastguard Worker 192*b7c941bbSAndroid Build Coastguard Workerdef get_array_size(buffer): 193*b7c941bbSAndroid Build Coastguard Worker """Get array size based on different NumPy versions' functions. 194*b7c941bbSAndroid Build Coastguard Worker 195*b7c941bbSAndroid Build Coastguard Worker Args: 196*b7c941bbSAndroid Build Coastguard Worker buffer: A NumPy array. 197*b7c941bbSAndroid Build Coastguard Worker 198*b7c941bbSAndroid Build Coastguard Worker Returns: 199*b7c941bbSAndroid Build Coastguard Worker buffer_size: The size of the buffer. 200*b7c941bbSAndroid Build Coastguard Worker """ 201*b7c941bbSAndroid Build Coastguard Worker np_version = numpy.__version__ 202*b7c941bbSAndroid Build Coastguard Worker if np_version.startswith(('1.25', '1.26', '2.')): 203*b7c941bbSAndroid Build Coastguard Worker buffer_size = numpy.prod(buffer.shape) 204*b7c941bbSAndroid Build Coastguard Worker else: 205*b7c941bbSAndroid Build Coastguard Worker buffer_size = numpy.product(buffer.shape) 206*b7c941bbSAndroid Build Coastguard Worker return buffer_size 207*b7c941bbSAndroid Build Coastguard Worker 208*b7c941bbSAndroid Build Coastguard Worker 209*b7c941bbSAndroid Build Coastguard Workerclass ItsSession(object): 210*b7c941bbSAndroid Build Coastguard Worker """Controls a device over adb to run ITS scripts. 211*b7c941bbSAndroid Build Coastguard Worker 212*b7c941bbSAndroid Build Coastguard Worker The script importing this module (on the host machine) prepares JSON 213*b7c941bbSAndroid Build Coastguard Worker objects encoding CaptureRequests, specifying sets of parameters to use 214*b7c941bbSAndroid Build Coastguard Worker when capturing an image using the Camera2 APIs. This class encapsulates 215*b7c941bbSAndroid Build Coastguard Worker sending the requests to the device, monitoring the device's progress, and 216*b7c941bbSAndroid Build Coastguard Worker copying the resultant captures back to the host machine when done. TCP 217*b7c941bbSAndroid Build Coastguard Worker forwarded over adb is the transport mechanism used. 218*b7c941bbSAndroid Build Coastguard Worker 219*b7c941bbSAndroid Build Coastguard Worker The device must have CtsVerifier.apk installed. 220*b7c941bbSAndroid Build Coastguard Worker 221*b7c941bbSAndroid Build Coastguard Worker Attributes: 222*b7c941bbSAndroid Build Coastguard Worker sock: The open socket. 223*b7c941bbSAndroid Build Coastguard Worker """ 224*b7c941bbSAndroid Build Coastguard Worker 225*b7c941bbSAndroid Build Coastguard Worker # Open a connection to localhost:<host_port>, forwarded to port 6000 on the 226*b7c941bbSAndroid Build Coastguard Worker # device. <host_port> is determined at run-time to support multiple 227*b7c941bbSAndroid Build Coastguard Worker # connected devices. 228*b7c941bbSAndroid Build Coastguard Worker IPADDR = '127.0.0.1' 229*b7c941bbSAndroid Build Coastguard Worker REMOTE_PORT = 6000 230*b7c941bbSAndroid Build Coastguard Worker BUFFER_SIZE = 4096 231*b7c941bbSAndroid Build Coastguard Worker 232*b7c941bbSAndroid Build Coastguard Worker # LOCK_PORT is used as a mutex lock to protect the list of forwarded ports 233*b7c941bbSAndroid Build Coastguard Worker # among all processes. The script assumes LOCK_PORT is available and will 234*b7c941bbSAndroid Build Coastguard Worker # try to use ports between CLIENT_PORT_START and 235*b7c941bbSAndroid Build Coastguard Worker # CLIENT_PORT_START+MAX_NUM_PORTS-1 on host for ITS sessions. 236*b7c941bbSAndroid Build Coastguard Worker CLIENT_PORT_START = 6000 237*b7c941bbSAndroid Build Coastguard Worker MAX_NUM_PORTS = 100 238*b7c941bbSAndroid Build Coastguard Worker LOCK_PORT = CLIENT_PORT_START + MAX_NUM_PORTS 239*b7c941bbSAndroid Build Coastguard Worker 240*b7c941bbSAndroid Build Coastguard Worker # Seconds timeout on each socket operation. 241*b7c941bbSAndroid Build Coastguard Worker SOCK_TIMEOUT = 20.0 242*b7c941bbSAndroid Build Coastguard Worker # Seconds timeout on performance measurement socket operation 243*b7c941bbSAndroid Build Coastguard Worker SOCK_TIMEOUT_FOR_PERF_MEASURE = 40.0 244*b7c941bbSAndroid Build Coastguard Worker # Seconds timeout on preview recording socket operation. 245*b7c941bbSAndroid Build Coastguard Worker SOCK_TIMEOUT_PREVIEW = 30.0 # test_imu_drift is 30s 246*b7c941bbSAndroid Build Coastguard Worker 247*b7c941bbSAndroid Build Coastguard Worker # Additional timeout in seconds when ITS service is doing more complicated 248*b7c941bbSAndroid Build Coastguard Worker # operations, for example: issuing warmup requests before actual capture. 249*b7c941bbSAndroid Build Coastguard Worker EXTRA_SOCK_TIMEOUT = 5.0 250*b7c941bbSAndroid Build Coastguard Worker 251*b7c941bbSAndroid Build Coastguard Worker PACKAGE = 'com.android.cts.verifier.camera.its' 252*b7c941bbSAndroid Build Coastguard Worker INTENT_START = 'com.android.cts.verifier.camera.its.START' 253*b7c941bbSAndroid Build Coastguard Worker 254*b7c941bbSAndroid Build Coastguard Worker # This string must be in sync with ItsService. Updated when interface 255*b7c941bbSAndroid Build Coastguard Worker # between script and ItsService is changed. 256*b7c941bbSAndroid Build Coastguard Worker ITS_SERVICE_VERSION = '1.0' 257*b7c941bbSAndroid Build Coastguard Worker 258*b7c941bbSAndroid Build Coastguard Worker SEC_TO_NSEC = 1000*1000*1000.0 259*b7c941bbSAndroid Build Coastguard Worker adb = 'adb -d' 260*b7c941bbSAndroid Build Coastguard Worker 261*b7c941bbSAndroid Build Coastguard Worker # Predefine camera props. Save props extracted from the function, 262*b7c941bbSAndroid Build Coastguard Worker # "get_camera_properties". 263*b7c941bbSAndroid Build Coastguard Worker props = None 264*b7c941bbSAndroid Build Coastguard Worker 265*b7c941bbSAndroid Build Coastguard Worker IMAGE_FORMAT_LIST_1 = [ 266*b7c941bbSAndroid Build Coastguard Worker 'jpegImage', 'rawImage', 'raw10Image', 'raw12Image', 'rawStatsImage', 267*b7c941bbSAndroid Build Coastguard Worker 'dngImage', 'y8Image', 'jpeg_rImage', 268*b7c941bbSAndroid Build Coastguard Worker 'rawQuadBayerImage', 'rawQuadBayerStatsImage', 269*b7c941bbSAndroid Build Coastguard Worker 'raw10StatsImage', 'raw10QuadBayerStatsImage', 'raw10QuadBayerImage' 270*b7c941bbSAndroid Build Coastguard Worker ] 271*b7c941bbSAndroid Build Coastguard Worker 272*b7c941bbSAndroid Build Coastguard Worker IMAGE_FORMAT_LIST_2 = [ 273*b7c941bbSAndroid Build Coastguard Worker 'jpegImage', 'rawImage', 'raw10Image', 'raw12Image', 'rawStatsImage', 274*b7c941bbSAndroid Build Coastguard Worker 'yuvImage', 'jpeg_rImage', 275*b7c941bbSAndroid Build Coastguard Worker 'rawQuadBayerImage', 'rawQuadBayerStatsImage', 276*b7c941bbSAndroid Build Coastguard Worker 'raw10StatsImage', 'raw10QuadBayerStatsImage', 'raw10QuadBayerImage' 277*b7c941bbSAndroid Build Coastguard Worker ] 278*b7c941bbSAndroid Build Coastguard Worker 279*b7c941bbSAndroid Build Coastguard Worker CAP_JPEG = {'format': 'jpeg'} 280*b7c941bbSAndroid Build Coastguard Worker CAP_RAW = {'format': 'raw'} 281*b7c941bbSAndroid Build Coastguard Worker CAP_CROPPED_RAW = {'format': 'raw', 'useCase': USE_CASE_CROPPED_RAW} 282*b7c941bbSAndroid Build Coastguard Worker CAP_YUV = {'format': 'yuv'} 283*b7c941bbSAndroid Build Coastguard Worker CAP_RAW_YUV = [{'format': 'raw'}, {'format': 'yuv'}] 284*b7c941bbSAndroid Build Coastguard Worker 285*b7c941bbSAndroid Build Coastguard Worker def __init_socket_port(self): 286*b7c941bbSAndroid Build Coastguard Worker """Initialize the socket port for the host to forward requests to the device. 287*b7c941bbSAndroid Build Coastguard Worker 288*b7c941bbSAndroid Build Coastguard Worker This method assumes localhost's LOCK_PORT is available and will try to 289*b7c941bbSAndroid Build Coastguard Worker use ports between CLIENT_PORT_START and CLIENT_PORT_START+MAX_NUM_PORTS-1 290*b7c941bbSAndroid Build Coastguard Worker """ 291*b7c941bbSAndroid Build Coastguard Worker num_retries = 100 292*b7c941bbSAndroid Build Coastguard Worker retry_wait_time_sec = 0.05 293*b7c941bbSAndroid Build Coastguard Worker 294*b7c941bbSAndroid Build Coastguard Worker # Bind a socket to use as mutex lock 295*b7c941bbSAndroid Build Coastguard Worker socket_lock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 296*b7c941bbSAndroid Build Coastguard Worker for i in range(num_retries): 297*b7c941bbSAndroid Build Coastguard Worker try: 298*b7c941bbSAndroid Build Coastguard Worker socket_lock.bind((ItsSession.IPADDR, ItsSession.LOCK_PORT)) 299*b7c941bbSAndroid Build Coastguard Worker break 300*b7c941bbSAndroid Build Coastguard Worker except (socket.error, socket.timeout) as socket_issue: 301*b7c941bbSAndroid Build Coastguard Worker if i == num_retries - 1: 302*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError( 303*b7c941bbSAndroid Build Coastguard Worker self._device_id, 'socket lock returns error') from socket_issue 304*b7c941bbSAndroid Build Coastguard Worker else: 305*b7c941bbSAndroid Build Coastguard Worker time.sleep(retry_wait_time_sec) 306*b7c941bbSAndroid Build Coastguard Worker 307*b7c941bbSAndroid Build Coastguard Worker # Check if a port is already assigned to the device. 308*b7c941bbSAndroid Build Coastguard Worker command = 'adb forward --list' 309*b7c941bbSAndroid Build Coastguard Worker proc = subprocess.Popen(command.split(), stdout=subprocess.PIPE) 310*b7c941bbSAndroid Build Coastguard Worker # pylint: disable=unused-variable 311*b7c941bbSAndroid Build Coastguard Worker output, error = proc.communicate() 312*b7c941bbSAndroid Build Coastguard Worker port = None 313*b7c941bbSAndroid Build Coastguard Worker used_ports = [] 314*b7c941bbSAndroid Build Coastguard Worker for line in output.decode('utf-8').split(os.linesep): 315*b7c941bbSAndroid Build Coastguard Worker # each line should be formatted as: 316*b7c941bbSAndroid Build Coastguard Worker # "<device_id> tcp:<host_port> tcp:<remote_port>" 317*b7c941bbSAndroid Build Coastguard Worker forward_info = line.split() 318*b7c941bbSAndroid Build Coastguard Worker if len(forward_info) >= 3 and len( 319*b7c941bbSAndroid Build Coastguard Worker forward_info[1]) > 4 and forward_info[1][:4] == 'tcp:' and len( 320*b7c941bbSAndroid Build Coastguard Worker forward_info[2]) > 4 and forward_info[2][:4] == 'tcp:': 321*b7c941bbSAndroid Build Coastguard Worker local_p = int(forward_info[1][4:]) 322*b7c941bbSAndroid Build Coastguard Worker remote_p = int(forward_info[2][4:]) 323*b7c941bbSAndroid Build Coastguard Worker if forward_info[ 324*b7c941bbSAndroid Build Coastguard Worker 0] == self._device_id and remote_p == ItsSession.REMOTE_PORT: 325*b7c941bbSAndroid Build Coastguard Worker port = local_p 326*b7c941bbSAndroid Build Coastguard Worker break 327*b7c941bbSAndroid Build Coastguard Worker else: 328*b7c941bbSAndroid Build Coastguard Worker used_ports.append(local_p) 329*b7c941bbSAndroid Build Coastguard Worker 330*b7c941bbSAndroid Build Coastguard Worker # Find the first available port if no port is assigned to the device. 331*b7c941bbSAndroid Build Coastguard Worker if port is None: 332*b7c941bbSAndroid Build Coastguard Worker for p in range(ItsSession.CLIENT_PORT_START, 333*b7c941bbSAndroid Build Coastguard Worker ItsSession.CLIENT_PORT_START + ItsSession.MAX_NUM_PORTS): 334*b7c941bbSAndroid Build Coastguard Worker if self.check_port_availability(p, used_ports): 335*b7c941bbSAndroid Build Coastguard Worker port = p 336*b7c941bbSAndroid Build Coastguard Worker break 337*b7c941bbSAndroid Build Coastguard Worker 338*b7c941bbSAndroid Build Coastguard Worker if port is None: 339*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError(self._device_id, 340*b7c941bbSAndroid Build Coastguard Worker ' cannot find an available ' + 'port') 341*b7c941bbSAndroid Build Coastguard Worker 342*b7c941bbSAndroid Build Coastguard Worker # Release the socket as mutex unlock 343*b7c941bbSAndroid Build Coastguard Worker socket_lock.close() 344*b7c941bbSAndroid Build Coastguard Worker 345*b7c941bbSAndroid Build Coastguard Worker # Connect to the socket 346*b7c941bbSAndroid Build Coastguard Worker self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 347*b7c941bbSAndroid Build Coastguard Worker self.sock.connect((self.IPADDR, port)) 348*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(self.SOCK_TIMEOUT) 349*b7c941bbSAndroid Build Coastguard Worker 350*b7c941bbSAndroid Build Coastguard Worker def check_port_availability(self, check_port, used_ports): 351*b7c941bbSAndroid Build Coastguard Worker """Check if the port is available or not. 352*b7c941bbSAndroid Build Coastguard Worker 353*b7c941bbSAndroid Build Coastguard Worker Args: 354*b7c941bbSAndroid Build Coastguard Worker check_port: Port to check for availability 355*b7c941bbSAndroid Build Coastguard Worker used_ports: List of used ports 356*b7c941bbSAndroid Build Coastguard Worker 357*b7c941bbSAndroid Build Coastguard Worker Returns: 358*b7c941bbSAndroid Build Coastguard Worker True if the given port is available and can be assigned to the device. 359*b7c941bbSAndroid Build Coastguard Worker """ 360*b7c941bbSAndroid Build Coastguard Worker if check_port not in used_ports: 361*b7c941bbSAndroid Build Coastguard Worker # Try to run "adb forward" with the port 362*b7c941bbSAndroid Build Coastguard Worker command = ('%s forward tcp:%d tcp:%d' % 363*b7c941bbSAndroid Build Coastguard Worker (self.adb, check_port, self.REMOTE_PORT)) 364*b7c941bbSAndroid Build Coastguard Worker proc = subprocess.Popen( 365*b7c941bbSAndroid Build Coastguard Worker command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) 366*b7c941bbSAndroid Build Coastguard Worker error = proc.communicate()[1] 367*b7c941bbSAndroid Build Coastguard Worker 368*b7c941bbSAndroid Build Coastguard Worker # Check if there is no error 369*b7c941bbSAndroid Build Coastguard Worker if error is None or error.find('error'.encode()) < 0: 370*b7c941bbSAndroid Build Coastguard Worker return True 371*b7c941bbSAndroid Build Coastguard Worker else: 372*b7c941bbSAndroid Build Coastguard Worker return False 373*b7c941bbSAndroid Build Coastguard Worker 374*b7c941bbSAndroid Build Coastguard Worker def __wait_for_service(self): 375*b7c941bbSAndroid Build Coastguard Worker """Wait for ItsService to be ready and reboot the device if needed. 376*b7c941bbSAndroid Build Coastguard Worker 377*b7c941bbSAndroid Build Coastguard Worker This also includes the optional reboot handling: if the user 378*b7c941bbSAndroid Build Coastguard Worker provides a "reboot" or "reboot=N" arg, then reboot the device, 379*b7c941bbSAndroid Build Coastguard Worker waiting for N seconds (default 30) before returning. 380*b7c941bbSAndroid Build Coastguard Worker """ 381*b7c941bbSAndroid Build Coastguard Worker 382*b7c941bbSAndroid Build Coastguard Worker for s in sys.argv[1:]: 383*b7c941bbSAndroid Build Coastguard Worker if s[:6] == 'reboot': 384*b7c941bbSAndroid Build Coastguard Worker duration = 30 385*b7c941bbSAndroid Build Coastguard Worker if len(s) > 7 and s[6] == '=': 386*b7c941bbSAndroid Build Coastguard Worker duration = int(s[7:]) 387*b7c941bbSAndroid Build Coastguard Worker logging.debug('Rebooting device') 388*b7c941bbSAndroid Build Coastguard Worker its_device_utils.run(f'{self.adb} reboot') 389*b7c941bbSAndroid Build Coastguard Worker its_device_utils.run(f'{self.adb} wait-for-device') 390*b7c941bbSAndroid Build Coastguard Worker time.sleep(duration) 391*b7c941bbSAndroid Build Coastguard Worker logging.debug('Reboot complete') 392*b7c941bbSAndroid Build Coastguard Worker 393*b7c941bbSAndroid Build Coastguard Worker # Flush logcat so following code won't be misled by previous 394*b7c941bbSAndroid Build Coastguard Worker # 'ItsService ready' log. 395*b7c941bbSAndroid Build Coastguard Worker its_device_utils.run(f'{self.adb} logcat -c') 396*b7c941bbSAndroid Build Coastguard Worker time.sleep(1) 397*b7c941bbSAndroid Build Coastguard Worker 398*b7c941bbSAndroid Build Coastguard Worker its_device_utils.run( 399*b7c941bbSAndroid Build Coastguard Worker f'{self.adb} shell am force-stop --user cur {self.PACKAGE}') 400*b7c941bbSAndroid Build Coastguard Worker its_device_utils.run( 401*b7c941bbSAndroid Build Coastguard Worker f'{self.adb} shell am start-foreground-service --user cur ' 402*b7c941bbSAndroid Build Coastguard Worker f'-t text/plain -a {self.INTENT_START}' 403*b7c941bbSAndroid Build Coastguard Worker ) 404*b7c941bbSAndroid Build Coastguard Worker 405*b7c941bbSAndroid Build Coastguard Worker # Wait until the socket is ready to accept a connection. 406*b7c941bbSAndroid Build Coastguard Worker proc = subprocess.Popen( 407*b7c941bbSAndroid Build Coastguard Worker self.adb.split() + ['logcat'], stdout=subprocess.PIPE) 408*b7c941bbSAndroid Build Coastguard Worker logcat = proc.stdout 409*b7c941bbSAndroid Build Coastguard Worker while True: 410*b7c941bbSAndroid Build Coastguard Worker line = logcat.readline().strip() 411*b7c941bbSAndroid Build Coastguard Worker if line.find(b'ItsService ready') >= 0: 412*b7c941bbSAndroid Build Coastguard Worker break 413*b7c941bbSAndroid Build Coastguard Worker proc.kill() 414*b7c941bbSAndroid Build Coastguard Worker proc.communicate() 415*b7c941bbSAndroid Build Coastguard Worker 416*b7c941bbSAndroid Build Coastguard Worker def __init__(self, device_id=None, camera_id=None, hidden_physical_id=None, 417*b7c941bbSAndroid Build Coastguard Worker override_to_portrait=None): 418*b7c941bbSAndroid Build Coastguard Worker self._camera_id = camera_id 419*b7c941bbSAndroid Build Coastguard Worker self._device_id = device_id 420*b7c941bbSAndroid Build Coastguard Worker self._hidden_physical_id = hidden_physical_id 421*b7c941bbSAndroid Build Coastguard Worker self._override_to_portrait = override_to_portrait 422*b7c941bbSAndroid Build Coastguard Worker 423*b7c941bbSAndroid Build Coastguard Worker # Initialize device id and adb command. 424*b7c941bbSAndroid Build Coastguard Worker self.adb = 'adb -s ' + self._device_id 425*b7c941bbSAndroid Build Coastguard Worker self.__wait_for_service() 426*b7c941bbSAndroid Build Coastguard Worker self.__init_socket_port() 427*b7c941bbSAndroid Build Coastguard Worker 428*b7c941bbSAndroid Build Coastguard Worker def __enter__(self): 429*b7c941bbSAndroid Build Coastguard Worker self.close_camera() 430*b7c941bbSAndroid Build Coastguard Worker self.__open_camera() 431*b7c941bbSAndroid Build Coastguard Worker return self 432*b7c941bbSAndroid Build Coastguard Worker 433*b7c941bbSAndroid Build Coastguard Worker def __exit__(self, exec_type, exec_value, exec_traceback): 434*b7c941bbSAndroid Build Coastguard Worker if hasattr(self, 'sock') and self.sock: 435*b7c941bbSAndroid Build Coastguard Worker self.close_camera() 436*b7c941bbSAndroid Build Coastguard Worker self.sock.close() 437*b7c941bbSAndroid Build Coastguard Worker return False 438*b7c941bbSAndroid Build Coastguard Worker 439*b7c941bbSAndroid Build Coastguard Worker def override_with_hidden_physical_camera_props(self, props): 440*b7c941bbSAndroid Build Coastguard Worker """Check that it is a valid sub-camera backing the logical camera. 441*b7c941bbSAndroid Build Coastguard Worker 442*b7c941bbSAndroid Build Coastguard Worker If current session is for a hidden physical camera, check that it is a valid 443*b7c941bbSAndroid Build Coastguard Worker sub-camera backing the logical camera, override self.props, and return the 444*b7c941bbSAndroid Build Coastguard Worker characteristics of sub-camera. Otherwise, return "props" directly. 445*b7c941bbSAndroid Build Coastguard Worker 446*b7c941bbSAndroid Build Coastguard Worker Args: 447*b7c941bbSAndroid Build Coastguard Worker props: Camera properties object. 448*b7c941bbSAndroid Build Coastguard Worker 449*b7c941bbSAndroid Build Coastguard Worker Returns: 450*b7c941bbSAndroid Build Coastguard Worker The properties of the hidden physical camera if possible. 451*b7c941bbSAndroid Build Coastguard Worker """ 452*b7c941bbSAndroid Build Coastguard Worker if self._hidden_physical_id: 453*b7c941bbSAndroid Build Coastguard Worker if not camera_properties_utils.logical_multi_camera(props): 454*b7c941bbSAndroid Build Coastguard Worker logging.debug('cam %s not a logical multi-camera: no change in props.', 455*b7c941bbSAndroid Build Coastguard Worker self._hidden_physical_id) 456*b7c941bbSAndroid Build Coastguard Worker return props 457*b7c941bbSAndroid Build Coastguard Worker physical_ids = camera_properties_utils.logical_multi_camera_physical_ids( 458*b7c941bbSAndroid Build Coastguard Worker props) 459*b7c941bbSAndroid Build Coastguard Worker if self._hidden_physical_id not in physical_ids: 460*b7c941bbSAndroid Build Coastguard Worker raise AssertionError(f'{self._hidden_physical_id} is not a hidden ' 461*b7c941bbSAndroid Build Coastguard Worker f'sub-camera of {self._camera_id}') 462*b7c941bbSAndroid Build Coastguard Worker logging.debug('Overriding cam %s props', self._hidden_physical_id) 463*b7c941bbSAndroid Build Coastguard Worker props = self.get_camera_properties_by_id(self._hidden_physical_id) 464*b7c941bbSAndroid Build Coastguard Worker self.props = props 465*b7c941bbSAndroid Build Coastguard Worker return props 466*b7c941bbSAndroid Build Coastguard Worker 467*b7c941bbSAndroid Build Coastguard Worker def get_camera_properties(self): 468*b7c941bbSAndroid Build Coastguard Worker """Get the camera properties object for the device. 469*b7c941bbSAndroid Build Coastguard Worker 470*b7c941bbSAndroid Build Coastguard Worker Returns: 471*b7c941bbSAndroid Build Coastguard Worker The Python dictionary object for the CameraProperties object. 472*b7c941bbSAndroid Build Coastguard Worker """ 473*b7c941bbSAndroid Build Coastguard Worker cmd = {} 474*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'getCameraProperties' 475*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 476*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 477*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'cameraProperties': 478*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 479*b7c941bbSAndroid Build Coastguard Worker self.props = data[_OBJ_VALUE_STR]['cameraProperties'] 480*b7c941bbSAndroid Build Coastguard Worker return data[_OBJ_VALUE_STR]['cameraProperties'] 481*b7c941bbSAndroid Build Coastguard Worker 482*b7c941bbSAndroid Build Coastguard Worker def get_session_properties(self, out_surfaces, cap_request): 483*b7c941bbSAndroid Build Coastguard Worker """Get the camera properties object for a session configuration. 484*b7c941bbSAndroid Build Coastguard Worker 485*b7c941bbSAndroid Build Coastguard Worker Args: 486*b7c941bbSAndroid Build Coastguard Worker out_surfaces: output surfaces used to query session props. 487*b7c941bbSAndroid Build Coastguard Worker cap_request: capture request used to query session props. 488*b7c941bbSAndroid Build Coastguard Worker 489*b7c941bbSAndroid Build Coastguard Worker Returns: 490*b7c941bbSAndroid Build Coastguard Worker The Python dictionary object for the CameraProperties object. 491*b7c941bbSAndroid Build Coastguard Worker """ 492*b7c941bbSAndroid Build Coastguard Worker cmd = {} 493*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'getCameraSessionProperties' 494*b7c941bbSAndroid Build Coastguard Worker if out_surfaces: 495*b7c941bbSAndroid Build Coastguard Worker if isinstance(out_surfaces, list): 496*b7c941bbSAndroid Build Coastguard Worker cmd['outputSurfaces'] = out_surfaces 497*b7c941bbSAndroid Build Coastguard Worker else: 498*b7c941bbSAndroid Build Coastguard Worker cmd['outputSurfaces'] = [out_surfaces] 499*b7c941bbSAndroid Build Coastguard Worker formats = [ 500*b7c941bbSAndroid Build Coastguard Worker c['format'] if 'format' in c else 'yuv' for c in cmd['outputSurfaces'] 501*b7c941bbSAndroid Build Coastguard Worker ] 502*b7c941bbSAndroid Build Coastguard Worker formats = [s if s != 'jpg' else 'jpeg' for s in formats] 503*b7c941bbSAndroid Build Coastguard Worker else: 504*b7c941bbSAndroid Build Coastguard Worker max_yuv_size = capture_request_utils.get_available_output_sizes( 505*b7c941bbSAndroid Build Coastguard Worker 'yuv', self.props)[0] 506*b7c941bbSAndroid Build Coastguard Worker formats = ['yuv'] 507*b7c941bbSAndroid Build Coastguard Worker cmd['outputSurfaces'] = [{ 508*b7c941bbSAndroid Build Coastguard Worker 'format': 'yuv', 509*b7c941bbSAndroid Build Coastguard Worker 'width': max_yuv_size[0], 510*b7c941bbSAndroid Build Coastguard Worker 'height': max_yuv_size[1] 511*b7c941bbSAndroid Build Coastguard Worker }] 512*b7c941bbSAndroid Build Coastguard Worker cmd['captureRequest'] = cap_request 513*b7c941bbSAndroid Build Coastguard Worker 514*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 515*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 516*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'cameraProperties': 517*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 518*b7c941bbSAndroid Build Coastguard Worker self.props = data[_OBJ_VALUE_STR]['cameraProperties'] 519*b7c941bbSAndroid Build Coastguard Worker return data[_OBJ_VALUE_STR]['cameraProperties'] 520*b7c941bbSAndroid Build Coastguard Worker 521*b7c941bbSAndroid Build Coastguard Worker def get_camera_properties_by_id(self, camera_id, override_to_portrait=None): 522*b7c941bbSAndroid Build Coastguard Worker """Get the camera properties object for device with camera_id. 523*b7c941bbSAndroid Build Coastguard Worker 524*b7c941bbSAndroid Build Coastguard Worker Args: 525*b7c941bbSAndroid Build Coastguard Worker camera_id: The ID string of the camera 526*b7c941bbSAndroid Build Coastguard Worker override_to_portrait: Optional value for overrideToPortrait 527*b7c941bbSAndroid Build Coastguard Worker 528*b7c941bbSAndroid Build Coastguard Worker Returns: 529*b7c941bbSAndroid Build Coastguard Worker The Python dictionary object for the CameraProperties object. Empty 530*b7c941bbSAndroid Build Coastguard Worker if no such device exists. 531*b7c941bbSAndroid Build Coastguard Worker """ 532*b7c941bbSAndroid Build Coastguard Worker cmd = {} 533*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'getCameraPropertiesById' 534*b7c941bbSAndroid Build Coastguard Worker cmd[_CAMERA_ID_STR] = camera_id 535*b7c941bbSAndroid Build Coastguard Worker if override_to_portrait is not None: 536*b7c941bbSAndroid Build Coastguard Worker cmd['overrideToPortrait'] = override_to_portrait 537*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 538*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 539*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'cameraProperties': 540*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 541*b7c941bbSAndroid Build Coastguard Worker return data[_OBJ_VALUE_STR]['cameraProperties'] 542*b7c941bbSAndroid Build Coastguard Worker 543*b7c941bbSAndroid Build Coastguard Worker def __read_response_from_socket(self): 544*b7c941bbSAndroid Build Coastguard Worker """Reads a line (newline-terminated) string serialization of JSON object. 545*b7c941bbSAndroid Build Coastguard Worker 546*b7c941bbSAndroid Build Coastguard Worker Returns: 547*b7c941bbSAndroid Build Coastguard Worker Deserialized json obj. 548*b7c941bbSAndroid Build Coastguard Worker """ 549*b7c941bbSAndroid Build Coastguard Worker chars = [] 550*b7c941bbSAndroid Build Coastguard Worker while not chars or chars[-1] != '\n': 551*b7c941bbSAndroid Build Coastguard Worker ch = self.sock.recv(1).decode('utf-8') 552*b7c941bbSAndroid Build Coastguard Worker if not ch: 553*b7c941bbSAndroid Build Coastguard Worker # Socket was probably closed; otherwise don't get empty strings 554*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Problem with socket on device side') 555*b7c941bbSAndroid Build Coastguard Worker chars.append(ch) 556*b7c941bbSAndroid Build Coastguard Worker line = ''.join(chars) 557*b7c941bbSAndroid Build Coastguard Worker jobj = json.loads(line) 558*b7c941bbSAndroid Build Coastguard Worker # Optionally read a binary buffer of a fixed size. 559*b7c941bbSAndroid Build Coastguard Worker buf = None 560*b7c941bbSAndroid Build Coastguard Worker if 'bufValueSize' in jobj: 561*b7c941bbSAndroid Build Coastguard Worker n = jobj['bufValueSize'] 562*b7c941bbSAndroid Build Coastguard Worker buf = bytearray(n) 563*b7c941bbSAndroid Build Coastguard Worker view = memoryview(buf) 564*b7c941bbSAndroid Build Coastguard Worker while n > 0: 565*b7c941bbSAndroid Build Coastguard Worker nbytes = self.sock.recv_into(view, n) 566*b7c941bbSAndroid Build Coastguard Worker view = view[nbytes:] 567*b7c941bbSAndroid Build Coastguard Worker n -= nbytes 568*b7c941bbSAndroid Build Coastguard Worker buf = numpy.frombuffer(buf, dtype=numpy.uint8) 569*b7c941bbSAndroid Build Coastguard Worker return jobj, buf 570*b7c941bbSAndroid Build Coastguard Worker 571*b7c941bbSAndroid Build Coastguard Worker def __open_camera(self): 572*b7c941bbSAndroid Build Coastguard Worker """Get the camera ID to open if it is an argument as a single camera. 573*b7c941bbSAndroid Build Coastguard Worker 574*b7c941bbSAndroid Build Coastguard Worker This allows passing camera=# to individual tests at command line 575*b7c941bbSAndroid Build Coastguard Worker and camera=#,#,# or an no camera argv with tools/run_all_tests.py. 576*b7c941bbSAndroid Build Coastguard Worker In case the camera is a logical multi-camera, to run ITS on the 577*b7c941bbSAndroid Build Coastguard Worker hidden physical sub-camera, pass camera=[logical ID]:[physical ID] 578*b7c941bbSAndroid Build Coastguard Worker to an individual test at the command line, and same applies to multiple 579*b7c941bbSAndroid Build Coastguard Worker camera IDs for tools/run_all_tests.py: camera=#,#:#,#:#,# 580*b7c941bbSAndroid Build Coastguard Worker """ 581*b7c941bbSAndroid Build Coastguard Worker if not self._camera_id: 582*b7c941bbSAndroid Build Coastguard Worker self._camera_id = 0 583*b7c941bbSAndroid Build Coastguard Worker for s in sys.argv[1:]: 584*b7c941bbSAndroid Build Coastguard Worker if s[:7] == 'camera=' and len(s) > 7: 585*b7c941bbSAndroid Build Coastguard Worker camera_ids = s[7:].split(',') 586*b7c941bbSAndroid Build Coastguard Worker camera_id_combos = parse_camera_ids(camera_ids) 587*b7c941bbSAndroid Build Coastguard Worker if len(camera_id_combos) == 1: 588*b7c941bbSAndroid Build Coastguard Worker self._camera_id = camera_id_combos[0].id 589*b7c941bbSAndroid Build Coastguard Worker self._hidden_physical_id = camera_id_combos[0].sub_id 590*b7c941bbSAndroid Build Coastguard Worker 591*b7c941bbSAndroid Build Coastguard Worker logging.debug('Opening camera: %s', self._camera_id) 592*b7c941bbSAndroid Build Coastguard Worker cmd = {_CMD_NAME_STR: 'open', _CAMERA_ID_STR: self._camera_id} 593*b7c941bbSAndroid Build Coastguard Worker if self._override_to_portrait is not None: 594*b7c941bbSAndroid Build Coastguard Worker cmd['overrideToPortrait'] = self._override_to_portrait 595*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 596*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 597*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'cameraOpened': 598*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 599*b7c941bbSAndroid Build Coastguard Worker 600*b7c941bbSAndroid Build Coastguard Worker def close_camera(self): 601*b7c941bbSAndroid Build Coastguard Worker cmd = {_CMD_NAME_STR: 'close'} 602*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 603*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 604*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'cameraClosed': 605*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 606*b7c941bbSAndroid Build Coastguard Worker 607*b7c941bbSAndroid Build Coastguard Worker def zoom_ratio_within_range(self, zoom_ratio): 608*b7c941bbSAndroid Build Coastguard Worker """Determine if a given zoom ratio is within device zoom range. 609*b7c941bbSAndroid Build Coastguard Worker 610*b7c941bbSAndroid Build Coastguard Worker Args: 611*b7c941bbSAndroid Build Coastguard Worker zoom_ratio: float; zoom ratio requested 612*b7c941bbSAndroid Build Coastguard Worker Returns: 613*b7c941bbSAndroid Build Coastguard Worker Boolean: True, if zoom_ratio inside device range. False otherwise. 614*b7c941bbSAndroid Build Coastguard Worker """ 615*b7c941bbSAndroid Build Coastguard Worker zoom_range = self.props['android.control.zoomRatioRange'] 616*b7c941bbSAndroid Build Coastguard Worker return zoom_ratio >= zoom_range[0] and zoom_ratio <= zoom_range[1] 617*b7c941bbSAndroid Build Coastguard Worker 618*b7c941bbSAndroid Build Coastguard Worker def get_sensors(self): 619*b7c941bbSAndroid Build Coastguard Worker """Get all sensors on the device. 620*b7c941bbSAndroid Build Coastguard Worker 621*b7c941bbSAndroid Build Coastguard Worker Returns: 622*b7c941bbSAndroid Build Coastguard Worker A Python dictionary that returns keys and booleans for each sensor. 623*b7c941bbSAndroid Build Coastguard Worker """ 624*b7c941bbSAndroid Build Coastguard Worker cmd = {} 625*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'checkSensorExistence' 626*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 627*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 628*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'sensorExistence': 629*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid response for command: %s' % 630*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR]) 631*b7c941bbSAndroid Build Coastguard Worker return data[_OBJ_VALUE_STR] 632*b7c941bbSAndroid Build Coastguard Worker 633*b7c941bbSAndroid Build Coastguard Worker def get_default_camera_pkg(self): 634*b7c941bbSAndroid Build Coastguard Worker """Get default camera app package name. 635*b7c941bbSAndroid Build Coastguard Worker 636*b7c941bbSAndroid Build Coastguard Worker Returns: 637*b7c941bbSAndroid Build Coastguard Worker Default camera app pkg name. 638*b7c941bbSAndroid Build Coastguard Worker """ 639*b7c941bbSAndroid Build Coastguard Worker cmd = {} 640*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'doGetDefaultCameraPkgName' 641*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 642*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 643*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'defaultCameraPkg': 644*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid response for command: %s' % 645*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR]) 646*b7c941bbSAndroid Build Coastguard Worker return data['strValue'] 647*b7c941bbSAndroid Build Coastguard Worker 648*b7c941bbSAndroid Build Coastguard Worker def check_gain_map_present(self, file_path): 649*b7c941bbSAndroid Build Coastguard Worker """Check if the image has gainmap present or not. 650*b7c941bbSAndroid Build Coastguard Worker 651*b7c941bbSAndroid Build Coastguard Worker The image stored at file_path is decoded and analyzed 652*b7c941bbSAndroid Build Coastguard Worker to check whether the gainmap is present or not. If the image 653*b7c941bbSAndroid Build Coastguard Worker captured is UltraHDR, it should have gainmap present. 654*b7c941bbSAndroid Build Coastguard Worker 655*b7c941bbSAndroid Build Coastguard Worker Args: 656*b7c941bbSAndroid Build Coastguard Worker file_path: path of the image to be analyzed on DUT. 657*b7c941bbSAndroid Build Coastguard Worker Returns: 658*b7c941bbSAndroid Build Coastguard Worker Boolean: True if the image has gainmap present. 659*b7c941bbSAndroid Build Coastguard Worker """ 660*b7c941bbSAndroid Build Coastguard Worker cmd = {} 661*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'doGainMapCheck' 662*b7c941bbSAndroid Build Coastguard Worker cmd['filePath'] = file_path 663*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 664*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 665*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'gainmapPresent': 666*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError( 667*b7c941bbSAndroid Build Coastguard Worker 'Invalid response for command: %s' % cmd[_CMD_NAME_STR]) 668*b7c941bbSAndroid Build Coastguard Worker return data['strValue'] 669*b7c941bbSAndroid Build Coastguard Worker 670*b7c941bbSAndroid Build Coastguard Worker def start_sensor_events(self): 671*b7c941bbSAndroid Build Coastguard Worker """Start collecting sensor events on the device. 672*b7c941bbSAndroid Build Coastguard Worker 673*b7c941bbSAndroid Build Coastguard Worker See get_sensor_events for more info. 674*b7c941bbSAndroid Build Coastguard Worker 675*b7c941bbSAndroid Build Coastguard Worker Returns: 676*b7c941bbSAndroid Build Coastguard Worker Nothing. 677*b7c941bbSAndroid Build Coastguard Worker """ 678*b7c941bbSAndroid Build Coastguard Worker cmd = {} 679*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'startSensorEvents' 680*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 681*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 682*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'sensorEventsStarted': 683*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid response for command: %s' % 684*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR]) 685*b7c941bbSAndroid Build Coastguard Worker 686*b7c941bbSAndroid Build Coastguard Worker def get_sensor_events(self): 687*b7c941bbSAndroid Build Coastguard Worker """Get a trace of all sensor events on the device. 688*b7c941bbSAndroid Build Coastguard Worker 689*b7c941bbSAndroid Build Coastguard Worker The trace starts when the start_sensor_events function is called. If 690*b7c941bbSAndroid Build Coastguard Worker the test runs for a long time after this call, then the device's 691*b7c941bbSAndroid Build Coastguard Worker internal memory can fill up. Calling get_sensor_events gets all events 692*b7c941bbSAndroid Build Coastguard Worker from the device, and then stops the device from collecting events and 693*b7c941bbSAndroid Build Coastguard Worker clears the internal buffer; to start again, the start_sensor_events 694*b7c941bbSAndroid Build Coastguard Worker call must be used again. 695*b7c941bbSAndroid Build Coastguard Worker 696*b7c941bbSAndroid Build Coastguard Worker Events from the accelerometer, compass, and gyro are returned; each 697*b7c941bbSAndroid Build Coastguard Worker has a timestamp and x,y,z values. 698*b7c941bbSAndroid Build Coastguard Worker 699*b7c941bbSAndroid Build Coastguard Worker Note that sensor events are only produced if the device isn't in its 700*b7c941bbSAndroid Build Coastguard Worker standby mode (i.e.) if the screen is on. 701*b7c941bbSAndroid Build Coastguard Worker 702*b7c941bbSAndroid Build Coastguard Worker Returns: 703*b7c941bbSAndroid Build Coastguard Worker A Python dictionary with three keys ("accel", "mag", "gyro") each 704*b7c941bbSAndroid Build Coastguard Worker of which maps to a list of objects containing "time","x","y","z" 705*b7c941bbSAndroid Build Coastguard Worker keys. 706*b7c941bbSAndroid Build Coastguard Worker """ 707*b7c941bbSAndroid Build Coastguard Worker cmd = {} 708*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'getSensorEvents' 709*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 710*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT 711*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 712*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 713*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'sensorEvents': 714*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid response for command: %s ' % 715*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR]) 716*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(self.SOCK_TIMEOUT) 717*b7c941bbSAndroid Build Coastguard Worker return data[_OBJ_VALUE_STR] 718*b7c941bbSAndroid Build Coastguard Worker 719*b7c941bbSAndroid Build Coastguard Worker def get_camera_ids(self): 720*b7c941bbSAndroid Build Coastguard Worker """Returns the list of all camera_ids. 721*b7c941bbSAndroid Build Coastguard Worker 722*b7c941bbSAndroid Build Coastguard Worker Returns: 723*b7c941bbSAndroid Build Coastguard Worker List of camera ids on the device. 724*b7c941bbSAndroid Build Coastguard Worker """ 725*b7c941bbSAndroid Build Coastguard Worker cmd = {'cmdName': 'getCameraIds'} 726*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 727*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT 728*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 729*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 730*b7c941bbSAndroid Build Coastguard Worker if data['tag'] != 'cameraIds': 731*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 732*b7c941bbSAndroid Build Coastguard Worker return data['objValue'] 733*b7c941bbSAndroid Build Coastguard Worker 734*b7c941bbSAndroid Build Coastguard Worker def get_camera_name(self): 735*b7c941bbSAndroid Build Coastguard Worker """Gets the camera name. 736*b7c941bbSAndroid Build Coastguard Worker 737*b7c941bbSAndroid Build Coastguard Worker Returns: 738*b7c941bbSAndroid Build Coastguard Worker The camera name with camera id and/or hidden physical id. 739*b7c941bbSAndroid Build Coastguard Worker """ 740*b7c941bbSAndroid Build Coastguard Worker if self._hidden_physical_id: 741*b7c941bbSAndroid Build Coastguard Worker return f'{self._camera_id}.{self._hidden_physical_id}' 742*b7c941bbSAndroid Build Coastguard Worker else: 743*b7c941bbSAndroid Build Coastguard Worker return self._camera_id 744*b7c941bbSAndroid Build Coastguard Worker 745*b7c941bbSAndroid Build Coastguard Worker def get_unavailable_physical_cameras(self, camera_id): 746*b7c941bbSAndroid Build Coastguard Worker """Get the unavailable physical cameras ids. 747*b7c941bbSAndroid Build Coastguard Worker 748*b7c941bbSAndroid Build Coastguard Worker Args: 749*b7c941bbSAndroid Build Coastguard Worker camera_id: int; device id 750*b7c941bbSAndroid Build Coastguard Worker Returns: 751*b7c941bbSAndroid Build Coastguard Worker List of all physical camera ids which are unavailable. 752*b7c941bbSAndroid Build Coastguard Worker """ 753*b7c941bbSAndroid Build Coastguard Worker cmd = {_CMD_NAME_STR: 'doGetUnavailablePhysicalCameras', 754*b7c941bbSAndroid Build Coastguard Worker _CAMERA_ID_STR: camera_id} 755*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 756*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT 757*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 758*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 759*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'unavailablePhysicalCameras': 760*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 761*b7c941bbSAndroid Build Coastguard Worker return data[_OBJ_VALUE_STR] 762*b7c941bbSAndroid Build Coastguard Worker 763*b7c941bbSAndroid Build Coastguard Worker def is_hlg10_recording_supported_for_profile(self, profile_id): 764*b7c941bbSAndroid Build Coastguard Worker """Query whether the camera device supports HLG10 video recording. 765*b7c941bbSAndroid Build Coastguard Worker 766*b7c941bbSAndroid Build Coastguard Worker Args: 767*b7c941bbSAndroid Build Coastguard Worker profile_id: int; profile id corresponding to the quality level. 768*b7c941bbSAndroid Build Coastguard Worker Returns: 769*b7c941bbSAndroid Build Coastguard Worker Boolean: True if device supports HLG10 video recording, False in 770*b7c941bbSAndroid Build Coastguard Worker all other cases. 771*b7c941bbSAndroid Build Coastguard Worker """ 772*b7c941bbSAndroid Build Coastguard Worker cmd = {} 773*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'isHLG10SupportedForProfile' 774*b7c941bbSAndroid Build Coastguard Worker cmd[_CAMERA_ID_STR] = self._camera_id 775*b7c941bbSAndroid Build Coastguard Worker cmd['profileId'] = profile_id 776*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 777*b7c941bbSAndroid Build Coastguard Worker 778*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 779*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'hlg10Response': 780*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Failed to query HLG10 support') 781*b7c941bbSAndroid Build Coastguard Worker return data[_STR_VALUE_STR] == 'true' 782*b7c941bbSAndroid Build Coastguard Worker 783*b7c941bbSAndroid Build Coastguard Worker def is_hlg10_recording_supported_for_size_and_fps( 784*b7c941bbSAndroid Build Coastguard Worker self, video_size, max_fps): 785*b7c941bbSAndroid Build Coastguard Worker """Query whether the camera device supports HLG10 video recording. 786*b7c941bbSAndroid Build Coastguard Worker 787*b7c941bbSAndroid Build Coastguard Worker Args: 788*b7c941bbSAndroid Build Coastguard Worker video_size: String; the hlg10 video recording size. 789*b7c941bbSAndroid Build Coastguard Worker max_fps: int; the maximum frame rate of the camera. 790*b7c941bbSAndroid Build Coastguard Worker Returns: 791*b7c941bbSAndroid Build Coastguard Worker Boolean: True if device supports HLG10 video recording, False in 792*b7c941bbSAndroid Build Coastguard Worker all other cases. 793*b7c941bbSAndroid Build Coastguard Worker """ 794*b7c941bbSAndroid Build Coastguard Worker cmd = {} 795*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'isHLG10SupportedForSizeAndFps' 796*b7c941bbSAndroid Build Coastguard Worker cmd[_CAMERA_ID_STR] = self._camera_id 797*b7c941bbSAndroid Build Coastguard Worker cmd['videoSize'] = video_size 798*b7c941bbSAndroid Build Coastguard Worker cmd['maxFps'] = max_fps 799*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 800*b7c941bbSAndroid Build Coastguard Worker 801*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 802*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'hlg10Response': 803*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Failed to query HLG10 support') 804*b7c941bbSAndroid Build Coastguard Worker return data[_STR_VALUE_STR] == 'true' 805*b7c941bbSAndroid Build Coastguard Worker 806*b7c941bbSAndroid Build Coastguard Worker def is_p3_capture_supported(self): 807*b7c941bbSAndroid Build Coastguard Worker """Query whether the camera device supports P3 image capture. 808*b7c941bbSAndroid Build Coastguard Worker 809*b7c941bbSAndroid Build Coastguard Worker Returns: 810*b7c941bbSAndroid Build Coastguard Worker Boolean: True, if device supports P3 image capture, False in 811*b7c941bbSAndroid Build Coastguard Worker all other cases. 812*b7c941bbSAndroid Build Coastguard Worker """ 813*b7c941bbSAndroid Build Coastguard Worker cmd = {} 814*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'isP3Supported' 815*b7c941bbSAndroid Build Coastguard Worker cmd[_CAMERA_ID_STR] = self._camera_id 816*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 817*b7c941bbSAndroid Build Coastguard Worker 818*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 819*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'p3Response': 820*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Failed to query P3 support') 821*b7c941bbSAndroid Build Coastguard Worker return data[_STR_VALUE_STR] == 'true' 822*b7c941bbSAndroid Build Coastguard Worker 823*b7c941bbSAndroid Build Coastguard Worker def is_landscape_to_portrait_enabled(self): 824*b7c941bbSAndroid Build Coastguard Worker """Query whether the device has enabled the landscape to portrait property. 825*b7c941bbSAndroid Build Coastguard Worker 826*b7c941bbSAndroid Build Coastguard Worker Returns: 827*b7c941bbSAndroid Build Coastguard Worker Boolean: True, if the device has the system property enabled. False 828*b7c941bbSAndroid Build Coastguard Worker otherwise. 829*b7c941bbSAndroid Build Coastguard Worker """ 830*b7c941bbSAndroid Build Coastguard Worker cmd = {} 831*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'isLandscapeToPortraitEnabled' 832*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 833*b7c941bbSAndroid Build Coastguard Worker 834*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 835*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'landscapeToPortraitEnabledResponse': 836*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError( 837*b7c941bbSAndroid Build Coastguard Worker 'Failed to query landscape to portrait system property') 838*b7c941bbSAndroid Build Coastguard Worker return data[_STR_VALUE_STR] == 'true' 839*b7c941bbSAndroid Build Coastguard Worker 840*b7c941bbSAndroid Build Coastguard Worker def get_supported_video_sizes_capped(self, camera_id): 841*b7c941bbSAndroid Build Coastguard Worker """Get the supported video sizes for camera id. 842*b7c941bbSAndroid Build Coastguard Worker 843*b7c941bbSAndroid Build Coastguard Worker Args: 844*b7c941bbSAndroid Build Coastguard Worker camera_id: int; device id 845*b7c941bbSAndroid Build Coastguard Worker Returns: 846*b7c941bbSAndroid Build Coastguard Worker Sorted list of supported video sizes. 847*b7c941bbSAndroid Build Coastguard Worker """ 848*b7c941bbSAndroid Build Coastguard Worker 849*b7c941bbSAndroid Build Coastguard Worker cmd = { 850*b7c941bbSAndroid Build Coastguard Worker _CMD_NAME_STR: 'doGetSupportedVideoSizesCapped', 851*b7c941bbSAndroid Build Coastguard Worker _CAMERA_ID_STR: camera_id, 852*b7c941bbSAndroid Build Coastguard Worker } 853*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 854*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT 855*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 856*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 857*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'supportedVideoSizes': 858*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 859*b7c941bbSAndroid Build Coastguard Worker if not data[_STR_VALUE_STR]: 860*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('No supported video sizes') 861*b7c941bbSAndroid Build Coastguard Worker return data[_STR_VALUE_STR].split(';') 862*b7c941bbSAndroid Build Coastguard Worker 863*b7c941bbSAndroid Build Coastguard Worker def do_basic_recording(self, profile_id, quality, duration, 864*b7c941bbSAndroid Build Coastguard Worker video_stabilization_mode=0, hlg10_enabled=False, 865*b7c941bbSAndroid Build Coastguard Worker zoom_ratio=None, ae_target_fps_min=None, 866*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_max=None, antibanding_mode=None, 867*b7c941bbSAndroid Build Coastguard Worker face_detect_mode=None): 868*b7c941bbSAndroid Build Coastguard Worker """Issue a recording request and read back the video recording object. 869*b7c941bbSAndroid Build Coastguard Worker 870*b7c941bbSAndroid Build Coastguard Worker The recording will be done with the format specified in quality. These 871*b7c941bbSAndroid Build Coastguard Worker quality levels correspond to the profiles listed in CamcorderProfile. 872*b7c941bbSAndroid Build Coastguard Worker The duration is the time in seconds for which the video will be recorded. 873*b7c941bbSAndroid Build Coastguard Worker The recorded object consists of a path on the device at which the 874*b7c941bbSAndroid Build Coastguard Worker recorded video is saved. 875*b7c941bbSAndroid Build Coastguard Worker 876*b7c941bbSAndroid Build Coastguard Worker Args: 877*b7c941bbSAndroid Build Coastguard Worker profile_id: int; profile id corresponding to the quality level. 878*b7c941bbSAndroid Build Coastguard Worker quality: Video recording quality such as High, Low, VGA. 879*b7c941bbSAndroid Build Coastguard Worker duration: The time in seconds for which the video will be recorded. 880*b7c941bbSAndroid Build Coastguard Worker video_stabilization_mode: Video stabilization mode ON/OFF. Value can be 881*b7c941bbSAndroid Build Coastguard Worker 0: 'OFF', 1: 'ON', 2: 'PREVIEW' 882*b7c941bbSAndroid Build Coastguard Worker hlg10_enabled: boolean: True Enable 10-bit HLG video recording, False 883*b7c941bbSAndroid Build Coastguard Worker record using the regular SDR profile 884*b7c941bbSAndroid Build Coastguard Worker zoom_ratio: float; zoom ratio. None if default zoom 885*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_min: int; CONTROL_AE_TARGET_FPS_RANGE min. Set if not None 886*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_max: int; CONTROL_AE_TARGET_FPS_RANGE max. Set if not None 887*b7c941bbSAndroid Build Coastguard Worker antibanding_mode: int; CONTROL_AE_ANTIBANDING_MODE. Set if not None 888*b7c941bbSAndroid Build Coastguard Worker face_detect_mode: int; STATISTICS_FACE_DETECT_MODE. Set if not None 889*b7c941bbSAndroid Build Coastguard Worker Returns: 890*b7c941bbSAndroid Build Coastguard Worker video_recorded_object: The recorded object returned from ItsService which 891*b7c941bbSAndroid Build Coastguard Worker contains path at which the recording is saved on the device, quality of 892*b7c941bbSAndroid Build Coastguard Worker the recorded video, video size of the recorded video, video frame rate 893*b7c941bbSAndroid Build Coastguard Worker and 'hlg10' if 'hlg10_enabled' is set to True. 894*b7c941bbSAndroid Build Coastguard Worker Ex: 895*b7c941bbSAndroid Build Coastguard Worker VideoRecordingObject: { 896*b7c941bbSAndroid Build Coastguard Worker 'tag': 'recordingResponse', 897*b7c941bbSAndroid Build Coastguard Worker 'objValue': { 898*b7c941bbSAndroid Build Coastguard Worker 'recordedOutputPath': 899*b7c941bbSAndroid Build Coastguard Worker '/storage/emulated/0/Android/data/com.android.cts.verifier' 900*b7c941bbSAndroid Build Coastguard Worker '/files/VideoITS/VID_20220324_080414_0_CIF_352x288.mp4', 901*b7c941bbSAndroid Build Coastguard Worker 'quality': 'CIF', 902*b7c941bbSAndroid Build Coastguard Worker 'videoFrameRate': 30, 903*b7c941bbSAndroid Build Coastguard Worker 'videoSize': '352x288' 904*b7c941bbSAndroid Build Coastguard Worker } 905*b7c941bbSAndroid Build Coastguard Worker } 906*b7c941bbSAndroid Build Coastguard Worker """ 907*b7c941bbSAndroid Build Coastguard Worker cmd = {_CMD_NAME_STR: 'doBasicRecording', _CAMERA_ID_STR: self._camera_id, 908*b7c941bbSAndroid Build Coastguard Worker 'profileId': profile_id, 'quality': quality, 909*b7c941bbSAndroid Build Coastguard Worker 'recordingDuration': duration, 910*b7c941bbSAndroid Build Coastguard Worker 'videoStabilizationMode': video_stabilization_mode, 911*b7c941bbSAndroid Build Coastguard Worker 'hlg10Enabled': hlg10_enabled} 912*b7c941bbSAndroid Build Coastguard Worker if zoom_ratio: 913*b7c941bbSAndroid Build Coastguard Worker if self.zoom_ratio_within_range(zoom_ratio): 914*b7c941bbSAndroid Build Coastguard Worker cmd['zoomRatio'] = zoom_ratio 915*b7c941bbSAndroid Build Coastguard Worker else: 916*b7c941bbSAndroid Build Coastguard Worker raise AssertionError(f'Zoom ratio {zoom_ratio} out of range') 917*b7c941bbSAndroid Build Coastguard Worker if ae_target_fps_min and ae_target_fps_max: 918*b7c941bbSAndroid Build Coastguard Worker cmd['aeTargetFpsMin'] = ae_target_fps_min 919*b7c941bbSAndroid Build Coastguard Worker cmd['aeTargetFpsMax'] = ae_target_fps_max 920*b7c941bbSAndroid Build Coastguard Worker if antibanding_mode: 921*b7c941bbSAndroid Build Coastguard Worker cmd['aeAntibandingMode'] = antibanding_mode 922*b7c941bbSAndroid Build Coastguard Worker else: 923*b7c941bbSAndroid Build Coastguard Worker cmd['aeAntibandingMode'] = 0 924*b7c941bbSAndroid Build Coastguard Worker if face_detect_mode: 925*b7c941bbSAndroid Build Coastguard Worker cmd['faceDetectMode'] = face_detect_mode 926*b7c941bbSAndroid Build Coastguard Worker else: 927*b7c941bbSAndroid Build Coastguard Worker cmd['faceDetectMode'] = 0 928*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 929*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT 930*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 931*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 932*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'recordingResponse': 933*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError( 934*b7c941bbSAndroid Build Coastguard Worker f'Invalid response for command: {cmd[_CMD_NAME_STR]}') 935*b7c941bbSAndroid Build Coastguard Worker return data[_OBJ_VALUE_STR] 936*b7c941bbSAndroid Build Coastguard Worker 937*b7c941bbSAndroid Build Coastguard Worker def _execute_preview_recording(self, cmd): 938*b7c941bbSAndroid Build Coastguard Worker """Send preview recording command over socket and retrieve output object. 939*b7c941bbSAndroid Build Coastguard Worker 940*b7c941bbSAndroid Build Coastguard Worker Args: 941*b7c941bbSAndroid Build Coastguard Worker cmd: dict; Mapping from command key to corresponding value 942*b7c941bbSAndroid Build Coastguard Worker Returns: 943*b7c941bbSAndroid Build Coastguard Worker video_recorded_object: The recorded object returned from ItsService which 944*b7c941bbSAndroid Build Coastguard Worker contains path at which the recording is saved on the device, quality of 945*b7c941bbSAndroid Build Coastguard Worker the recorded video which is always set to "preview", video size of the 946*b7c941bbSAndroid Build Coastguard Worker recorded video, video frame rate. 947*b7c941bbSAndroid Build Coastguard Worker Ex: 948*b7c941bbSAndroid Build Coastguard Worker VideoRecordingObject: { 949*b7c941bbSAndroid Build Coastguard Worker 'tag': 'recordingResponse', 950*b7c941bbSAndroid Build Coastguard Worker 'objValue': { 951*b7c941bbSAndroid Build Coastguard Worker 'recordedOutputPath': '/storage/emulated/0/Android/data/' 952*b7c941bbSAndroid Build Coastguard Worker 'com.android.cts.verifier/files/VideoITS/' 953*b7c941bbSAndroid Build Coastguard Worker 'VID_20220324_080414_0_CIF_352x288.mp4', 954*b7c941bbSAndroid Build Coastguard Worker 'quality': 'preview', 955*b7c941bbSAndroid Build Coastguard Worker 'videoSize': '352x288' 956*b7c941bbSAndroid Build Coastguard Worker } 957*b7c941bbSAndroid Build Coastguard Worker } 958*b7c941bbSAndroid Build Coastguard Worker """ 959*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 960*b7c941bbSAndroid Build Coastguard Worker timeout = (self.SOCK_TIMEOUT_PREVIEW + 961*b7c941bbSAndroid Build Coastguard Worker self.EXTRA_SOCK_TIMEOUT * _EXTRA_TIMEOUT_FACTOR) 962*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 963*b7c941bbSAndroid Build Coastguard Worker 964*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 965*b7c941bbSAndroid Build Coastguard Worker logging.debug('VideoRecordingObject: %s', str(data)) 966*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'recordingResponse': 967*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError( 968*b7c941bbSAndroid Build Coastguard Worker f'Invalid response from command{cmd[_CMD_NAME_STR]}') 969*b7c941bbSAndroid Build Coastguard Worker return data[_OBJ_VALUE_STR] 970*b7c941bbSAndroid Build Coastguard Worker 971*b7c941bbSAndroid Build Coastguard Worker def do_preview_recording_multiple_surfaces( 972*b7c941bbSAndroid Build Coastguard Worker self, output_surfaces, duration, stabilize, ois=False, 973*b7c941bbSAndroid Build Coastguard Worker zoom_ratio=None, ae_target_fps_min=None, ae_target_fps_max=None, 974*b7c941bbSAndroid Build Coastguard Worker antibanding_mode=None, face_detect_mode=None): 975*b7c941bbSAndroid Build Coastguard Worker """Issue a preview request and read back the preview recording object. 976*b7c941bbSAndroid Build Coastguard Worker 977*b7c941bbSAndroid Build Coastguard Worker The resolution of the preview and its recording will be determined by 978*b7c941bbSAndroid Build Coastguard Worker video_size. The duration is the time in seconds for which the preview will 979*b7c941bbSAndroid Build Coastguard Worker be recorded. The recorded object consists of a path on the device at 980*b7c941bbSAndroid Build Coastguard Worker which the recorded video is saved. 981*b7c941bbSAndroid Build Coastguard Worker 982*b7c941bbSAndroid Build Coastguard Worker Args: 983*b7c941bbSAndroid Build Coastguard Worker output_surfaces: list; The list of output surfaces used for creating 984*b7c941bbSAndroid Build Coastguard Worker preview recording session. The first surface 985*b7c941bbSAndroid Build Coastguard Worker is used for recording. 986*b7c941bbSAndroid Build Coastguard Worker duration: int; The time in seconds for which the video will be recorded. 987*b7c941bbSAndroid Build Coastguard Worker stabilize: boolean; Whether the preview should be stabilized or not 988*b7c941bbSAndroid Build Coastguard Worker ois: boolean; Whether the preview should be optically stabilized or not 989*b7c941bbSAndroid Build Coastguard Worker zoom_ratio: float; static zoom ratio. None if default zoom 990*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_min: int; CONTROL_AE_TARGET_FPS_RANGE min. Set if not None 991*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_max: int; CONTROL_AE_TARGET_FPS_RANGE max. Set if not None 992*b7c941bbSAndroid Build Coastguard Worker antibanding_mode: int; CONTROL_AE_ANTIBANDING_MODE. Set if not None 993*b7c941bbSAndroid Build Coastguard Worker face_detect_mode: int; STATISTICS_FACE_DETECT_MODE. Set if not None 994*b7c941bbSAndroid Build Coastguard Worker Returns: 995*b7c941bbSAndroid Build Coastguard Worker video_recorded_object: The recorded object returned from ItsService 996*b7c941bbSAndroid Build Coastguard Worker """ 997*b7c941bbSAndroid Build Coastguard Worker cam_id = self._camera_id 998*b7c941bbSAndroid Build Coastguard Worker if 'physicalCamera' in output_surfaces[0]: 999*b7c941bbSAndroid Build Coastguard Worker cam_id = output_surfaces[0]['physicalCamera'] 1000*b7c941bbSAndroid Build Coastguard Worker cmd = { 1001*b7c941bbSAndroid Build Coastguard Worker _CMD_NAME_STR: 'doStaticPreviewRecording', 1002*b7c941bbSAndroid Build Coastguard Worker _CAMERA_ID_STR: cam_id, 1003*b7c941bbSAndroid Build Coastguard Worker 'outputSurfaces': output_surfaces, 1004*b7c941bbSAndroid Build Coastguard Worker 'recordingDuration': duration, 1005*b7c941bbSAndroid Build Coastguard Worker 'stabilize': stabilize, 1006*b7c941bbSAndroid Build Coastguard Worker 'ois': ois, 1007*b7c941bbSAndroid Build Coastguard Worker } 1008*b7c941bbSAndroid Build Coastguard Worker if zoom_ratio: 1009*b7c941bbSAndroid Build Coastguard Worker if self.zoom_ratio_within_range(zoom_ratio): 1010*b7c941bbSAndroid Build Coastguard Worker cmd['zoomRatio'] = zoom_ratio 1011*b7c941bbSAndroid Build Coastguard Worker else: 1012*b7c941bbSAndroid Build Coastguard Worker raise AssertionError(f'Zoom ratio {zoom_ratio} out of range') 1013*b7c941bbSAndroid Build Coastguard Worker if ae_target_fps_min and ae_target_fps_max: 1014*b7c941bbSAndroid Build Coastguard Worker cmd['aeTargetFpsMin'] = ae_target_fps_min 1015*b7c941bbSAndroid Build Coastguard Worker cmd['aeTargetFpsMax'] = ae_target_fps_max 1016*b7c941bbSAndroid Build Coastguard Worker if antibanding_mode is not None: 1017*b7c941bbSAndroid Build Coastguard Worker cmd['aeAntibandingMode'] = antibanding_mode 1018*b7c941bbSAndroid Build Coastguard Worker if face_detect_mode is not None: 1019*b7c941bbSAndroid Build Coastguard Worker cmd['faceDetectMode'] = face_detect_mode 1020*b7c941bbSAndroid Build Coastguard Worker return self._execute_preview_recording(cmd) 1021*b7c941bbSAndroid Build Coastguard Worker 1022*b7c941bbSAndroid Build Coastguard Worker def do_preview_recording( 1023*b7c941bbSAndroid Build Coastguard Worker self, video_size, duration, stabilize, ois=False, zoom_ratio=None, 1024*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_min=None, ae_target_fps_max=None, hlg10_enabled=False, 1025*b7c941bbSAndroid Build Coastguard Worker antibanding_mode=None, face_detect_mode=None): 1026*b7c941bbSAndroid Build Coastguard Worker """Issue a preview request and read back the preview recording object. 1027*b7c941bbSAndroid Build Coastguard Worker 1028*b7c941bbSAndroid Build Coastguard Worker The resolution of the preview and its recording will be determined by 1029*b7c941bbSAndroid Build Coastguard Worker video_size. The duration is the time in seconds for which the preview will 1030*b7c941bbSAndroid Build Coastguard Worker be recorded. The recorded object consists of a path on the device at 1031*b7c941bbSAndroid Build Coastguard Worker which the recorded video is saved. 1032*b7c941bbSAndroid Build Coastguard Worker 1033*b7c941bbSAndroid Build Coastguard Worker Args: 1034*b7c941bbSAndroid Build Coastguard Worker video_size: str; Preview resolution at which to record. ex. "1920x1080" 1035*b7c941bbSAndroid Build Coastguard Worker duration: int; The time in seconds for which the video will be recorded. 1036*b7c941bbSAndroid Build Coastguard Worker stabilize: boolean; Whether the preview should be stabilized or not 1037*b7c941bbSAndroid Build Coastguard Worker ois: boolean; Whether the preview should be optically stabilized or not 1038*b7c941bbSAndroid Build Coastguard Worker zoom_ratio: float; static zoom ratio. None if default zoom 1039*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_min: int; CONTROL_AE_TARGET_FPS_RANGE min. Set if not None 1040*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_max: int; CONTROL_AE_TARGET_FPS_RANGE max. Set if not None 1041*b7c941bbSAndroid Build Coastguard Worker hlg10_enabled: boolean; True Eanable 10-bit HLG video recording, False 1042*b7c941bbSAndroid Build Coastguard Worker record using the regular SDK profile. 1043*b7c941bbSAndroid Build Coastguard Worker antibanding_mode: int; CONTROL_AE_ANTIBANDING_MODE. Set if not None 1044*b7c941bbSAndroid Build Coastguard Worker face_detect_mode: int; STATISTICS_FACE_DETECT_MODE. Set if not None 1045*b7c941bbSAndroid Build Coastguard Worker Returns: 1046*b7c941bbSAndroid Build Coastguard Worker video_recorded_object: The recorded object returned from ItsService 1047*b7c941bbSAndroid Build Coastguard Worker """ 1048*b7c941bbSAndroid Build Coastguard Worker output_surfaces = self.preview_surface(video_size, hlg10_enabled) 1049*b7c941bbSAndroid Build Coastguard Worker return self.do_preview_recording_multiple_surfaces( 1050*b7c941bbSAndroid Build Coastguard Worker output_surfaces, duration, stabilize, ois, zoom_ratio, 1051*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_min, ae_target_fps_max, antibanding_mode, 1052*b7c941bbSAndroid Build Coastguard Worker face_detect_mode) 1053*b7c941bbSAndroid Build Coastguard Worker 1054*b7c941bbSAndroid Build Coastguard Worker def do_preview_recording_with_dynamic_zoom(self, video_size, stabilize, 1055*b7c941bbSAndroid Build Coastguard Worker sweep_zoom, 1056*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_min=None, 1057*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_max=None, 1058*b7c941bbSAndroid Build Coastguard Worker padded_frames=False): 1059*b7c941bbSAndroid Build Coastguard Worker """Issue a preview request with dynamic zoom and read back output object. 1060*b7c941bbSAndroid Build Coastguard Worker 1061*b7c941bbSAndroid Build Coastguard Worker The resolution of the preview and its recording will be determined by 1062*b7c941bbSAndroid Build Coastguard Worker video_size. The duration will be determined by the duration at each zoom 1063*b7c941bbSAndroid Build Coastguard Worker ratio and the total number of zoom ratios. The recorded object consists 1064*b7c941bbSAndroid Build Coastguard Worker of a path on the device at which the recorded video is saved. 1065*b7c941bbSAndroid Build Coastguard Worker 1066*b7c941bbSAndroid Build Coastguard Worker Args: 1067*b7c941bbSAndroid Build Coastguard Worker video_size: str; Preview resolution at which to record. ex. "1920x1080" 1068*b7c941bbSAndroid Build Coastguard Worker stabilize: boolean; Whether the preview should be stabilized or not 1069*b7c941bbSAndroid Build Coastguard Worker sweep_zoom: tuple of (zoom_start, zoom_end, step_size, step_duration). 1070*b7c941bbSAndroid Build Coastguard Worker Used to control zoom ratio during recording. 1071*b7c941bbSAndroid Build Coastguard Worker zoom_start (float) is the starting zoom ratio during recording 1072*b7c941bbSAndroid Build Coastguard Worker zoom_end (float) is the ending zoom ratio during recording 1073*b7c941bbSAndroid Build Coastguard Worker step_size (float) is the step for zoom ratio during recording 1074*b7c941bbSAndroid Build Coastguard Worker step_duration (float) sleep in ms between zoom ratios 1075*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_min: int; CONTROL_AE_TARGET_FPS_RANGE min. Set if not None 1076*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_max: int; CONTROL_AE_TARGET_FPS_RANGE max. Set if not None 1077*b7c941bbSAndroid Build Coastguard Worker padded_frames: boolean; Whether to add additional frames at the beginning 1078*b7c941bbSAndroid Build Coastguard Worker and end of recording to workaround issue with MediaRecorder. 1079*b7c941bbSAndroid Build Coastguard Worker Returns: 1080*b7c941bbSAndroid Build Coastguard Worker video_recorded_object: The recorded object returned from ItsService 1081*b7c941bbSAndroid Build Coastguard Worker """ 1082*b7c941bbSAndroid Build Coastguard Worker output_surface = self.preview_surface(video_size) 1083*b7c941bbSAndroid Build Coastguard Worker cmd = { 1084*b7c941bbSAndroid Build Coastguard Worker _CMD_NAME_STR: 'doDynamicZoomPreviewRecording', 1085*b7c941bbSAndroid Build Coastguard Worker _CAMERA_ID_STR: self._camera_id, 1086*b7c941bbSAndroid Build Coastguard Worker 'outputSurfaces': output_surface, 1087*b7c941bbSAndroid Build Coastguard Worker 'stabilize': stabilize, 1088*b7c941bbSAndroid Build Coastguard Worker 'ois': False 1089*b7c941bbSAndroid Build Coastguard Worker } 1090*b7c941bbSAndroid Build Coastguard Worker zoom_start, zoom_end, step_size, step_duration = sweep_zoom 1091*b7c941bbSAndroid Build Coastguard Worker if (not self.zoom_ratio_within_range(zoom_start) or 1092*b7c941bbSAndroid Build Coastguard Worker not self.zoom_ratio_within_range(zoom_end)): 1093*b7c941bbSAndroid Build Coastguard Worker raise AssertionError( 1094*b7c941bbSAndroid Build Coastguard Worker f'Starting zoom ratio {zoom_start} or ' 1095*b7c941bbSAndroid Build Coastguard Worker f'ending zoom ratio {zoom_end} out of range' 1096*b7c941bbSAndroid Build Coastguard Worker ) 1097*b7c941bbSAndroid Build Coastguard Worker if zoom_start > zoom_end or step_size < 0: 1098*b7c941bbSAndroid Build Coastguard Worker raise NotImplementedError('Only increasing zoom ratios are supported') 1099*b7c941bbSAndroid Build Coastguard Worker cmd['zoomStart'] = zoom_start 1100*b7c941bbSAndroid Build Coastguard Worker cmd['zoomEnd'] = zoom_end 1101*b7c941bbSAndroid Build Coastguard Worker cmd['stepSize'] = step_size 1102*b7c941bbSAndroid Build Coastguard Worker cmd['stepDuration'] = step_duration 1103*b7c941bbSAndroid Build Coastguard Worker cmd['hlg10Enabled'] = False 1104*b7c941bbSAndroid Build Coastguard Worker cmd['paddedFrames'] = padded_frames 1105*b7c941bbSAndroid Build Coastguard Worker if ae_target_fps_min and ae_target_fps_max: 1106*b7c941bbSAndroid Build Coastguard Worker cmd['aeTargetFpsMin'] = ae_target_fps_min 1107*b7c941bbSAndroid Build Coastguard Worker cmd['aeTargetFpsMax'] = ae_target_fps_max 1108*b7c941bbSAndroid Build Coastguard Worker return self._execute_preview_recording(cmd) 1109*b7c941bbSAndroid Build Coastguard Worker 1110*b7c941bbSAndroid Build Coastguard Worker def do_preview_recording_with_dynamic_ae_awb_region( 1111*b7c941bbSAndroid Build Coastguard Worker self, video_size, ae_awb_regions, ae_awb_region_duration, stabilize=False, 1112*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_min=None, ae_target_fps_max=None): 1113*b7c941bbSAndroid Build Coastguard Worker """Issue a preview request with dynamic 3A region and read back output object. 1114*b7c941bbSAndroid Build Coastguard Worker 1115*b7c941bbSAndroid Build Coastguard Worker The resolution of the preview and its recording will be determined by 1116*b7c941bbSAndroid Build Coastguard Worker video_size. The recorded object consists of a path on the device at which 1117*b7c941bbSAndroid Build Coastguard Worker the recorded video is saved. 1118*b7c941bbSAndroid Build Coastguard Worker 1119*b7c941bbSAndroid Build Coastguard Worker Args: 1120*b7c941bbSAndroid Build Coastguard Worker video_size: str; Preview resolution at which to record. ex. "1920x1080" 1121*b7c941bbSAndroid Build Coastguard Worker ae_awb_regions: dictionary of (aeAwbRegionOne/Two/Three/Four). 1122*b7c941bbSAndroid Build Coastguard Worker Used to control 3A region during recording. 1123*b7c941bbSAndroid Build Coastguard Worker aeAwbRegionOne (metering rectangle) first ae/awb region of recording. 1124*b7c941bbSAndroid Build Coastguard Worker aeAwbRegionTwo (metering rectangle) second ae/awb region of recording. 1125*b7c941bbSAndroid Build Coastguard Worker aeAwbRegionThree (metering rectangle) third ae/awb region of recording. 1126*b7c941bbSAndroid Build Coastguard Worker aeAwbRegionFour (metering rectangle) fourth ae/awb region of recording. 1127*b7c941bbSAndroid Build Coastguard Worker ae_awb_region_duration: float; sleep in ms between 3A regions. 1128*b7c941bbSAndroid Build Coastguard Worker stabilize: boolean; Whether the preview should be stabilized. 1129*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_min: int; If not none, set CONTROL_AE_TARGET_FPS_RANGE min. 1130*b7c941bbSAndroid Build Coastguard Worker ae_target_fps_max: int; If not none, set CONTROL_AE_TARGET_FPS_RANGE max. 1131*b7c941bbSAndroid Build Coastguard Worker Returns: 1132*b7c941bbSAndroid Build Coastguard Worker video_recorded_object: The recorded object returned from ItsService. 1133*b7c941bbSAndroid Build Coastguard Worker """ 1134*b7c941bbSAndroid Build Coastguard Worker output_surface = self.preview_surface(video_size) 1135*b7c941bbSAndroid Build Coastguard Worker cmd = { 1136*b7c941bbSAndroid Build Coastguard Worker _CMD_NAME_STR: 'doDynamicMeteringRegionPreviewRecording', 1137*b7c941bbSAndroid Build Coastguard Worker _CAMERA_ID_STR: self._camera_id, 1138*b7c941bbSAndroid Build Coastguard Worker 'outputSurfaces': output_surface, 1139*b7c941bbSAndroid Build Coastguard Worker 'stabilize': stabilize, 1140*b7c941bbSAndroid Build Coastguard Worker 'ois': False, 1141*b7c941bbSAndroid Build Coastguard Worker 'aeAwbRegionDuration': ae_awb_region_duration 1142*b7c941bbSAndroid Build Coastguard Worker } 1143*b7c941bbSAndroid Build Coastguard Worker 1144*b7c941bbSAndroid Build Coastguard Worker cmd['aeAwbRegionOne'] = ae_awb_regions['aeAwbRegionOne'] 1145*b7c941bbSAndroid Build Coastguard Worker cmd['aeAwbRegionTwo'] = ae_awb_regions['aeAwbRegionTwo'] 1146*b7c941bbSAndroid Build Coastguard Worker cmd['aeAwbRegionThree'] = ae_awb_regions['aeAwbRegionThree'] 1147*b7c941bbSAndroid Build Coastguard Worker cmd['aeAwbRegionFour'] = ae_awb_regions['aeAwbRegionFour'] 1148*b7c941bbSAndroid Build Coastguard Worker cmd['hlg10Enabled'] = False 1149*b7c941bbSAndroid Build Coastguard Worker if ae_target_fps_min and ae_target_fps_max: 1150*b7c941bbSAndroid Build Coastguard Worker cmd['aeTargetFpsMin'] = ae_target_fps_min 1151*b7c941bbSAndroid Build Coastguard Worker cmd['aeTargetFpsMax'] = ae_target_fps_max 1152*b7c941bbSAndroid Build Coastguard Worker return self._execute_preview_recording(cmd) 1153*b7c941bbSAndroid Build Coastguard Worker 1154*b7c941bbSAndroid Build Coastguard Worker def get_supported_video_qualities(self, camera_id): 1155*b7c941bbSAndroid Build Coastguard Worker """Get all supported video qualities for this camera device. 1156*b7c941bbSAndroid Build Coastguard Worker 1157*b7c941bbSAndroid Build Coastguard Worker ie. ['480:4', '1080:6', '2160:8', '720:5', 'CIF:3', 'HIGH:1', 'LOW:0', 1158*b7c941bbSAndroid Build Coastguard Worker 'QCIF:2', 'QVGA:7'] 1159*b7c941bbSAndroid Build Coastguard Worker 1160*b7c941bbSAndroid Build Coastguard Worker Args: 1161*b7c941bbSAndroid Build Coastguard Worker camera_id: device id 1162*b7c941bbSAndroid Build Coastguard Worker Returns: 1163*b7c941bbSAndroid Build Coastguard Worker List of all supported video qualities and corresponding profileIds. 1164*b7c941bbSAndroid Build Coastguard Worker """ 1165*b7c941bbSAndroid Build Coastguard Worker cmd = {} 1166*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'getSupportedVideoQualities' 1167*b7c941bbSAndroid Build Coastguard Worker cmd[_CAMERA_ID_STR] = camera_id 1168*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 1169*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 1170*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'supportedVideoQualities': 1171*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 1172*b7c941bbSAndroid Build Coastguard Worker return data[_STR_VALUE_STR].split(';')[:-1] # remove the last appended ';' 1173*b7c941bbSAndroid Build Coastguard Worker 1174*b7c941bbSAndroid Build Coastguard Worker def get_all_supported_preview_sizes(self, camera_id, filter_recordable=False): 1175*b7c941bbSAndroid Build Coastguard Worker """Get all supported preview resolutions for this camera device. 1176*b7c941bbSAndroid Build Coastguard Worker 1177*b7c941bbSAndroid Build Coastguard Worker ie. ['640x480', '800x600', '1280x720', '1440x1080', '1920x1080'] 1178*b7c941bbSAndroid Build Coastguard Worker 1179*b7c941bbSAndroid Build Coastguard Worker Note: resolutions are sorted by width x height in ascending order 1180*b7c941bbSAndroid Build Coastguard Worker 1181*b7c941bbSAndroid Build Coastguard Worker Args: 1182*b7c941bbSAndroid Build Coastguard Worker camera_id: int; device id 1183*b7c941bbSAndroid Build Coastguard Worker filter_recordable: filter preview sizes if supported for video recording 1184*b7c941bbSAndroid Build Coastguard Worker using MediaRecorder 1185*b7c941bbSAndroid Build Coastguard Worker 1186*b7c941bbSAndroid Build Coastguard Worker Returns: 1187*b7c941bbSAndroid Build Coastguard Worker List of all supported preview resolutions in ascending order. 1188*b7c941bbSAndroid Build Coastguard Worker """ 1189*b7c941bbSAndroid Build Coastguard Worker cmd = { 1190*b7c941bbSAndroid Build Coastguard Worker _CMD_NAME_STR: 'getSupportedPreviewSizes', 1191*b7c941bbSAndroid Build Coastguard Worker _CAMERA_ID_STR: camera_id, 1192*b7c941bbSAndroid Build Coastguard Worker 'filter_recordable': filter_recordable, 1193*b7c941bbSAndroid Build Coastguard Worker } 1194*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 1195*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT 1196*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 1197*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 1198*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'supportedPreviewSizes': 1199*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 1200*b7c941bbSAndroid Build Coastguard Worker if not data[_STR_VALUE_STR]: 1201*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('No supported preview sizes') 1202*b7c941bbSAndroid Build Coastguard Worker supported_preview_sizes = data[_STR_VALUE_STR].split(';') 1203*b7c941bbSAndroid Build Coastguard Worker logging.debug('Supported preview sizes: %s', supported_preview_sizes) 1204*b7c941bbSAndroid Build Coastguard Worker return supported_preview_sizes 1205*b7c941bbSAndroid Build Coastguard Worker 1206*b7c941bbSAndroid Build Coastguard Worker def get_supported_preview_sizes(self, camera_id): 1207*b7c941bbSAndroid Build Coastguard Worker """Get supported preview resolutions for this camera device. 1208*b7c941bbSAndroid Build Coastguard Worker 1209*b7c941bbSAndroid Build Coastguard Worker ie. ['640x480', '800x600', '1280x720', '1440x1080', '1920x1080'] 1210*b7c941bbSAndroid Build Coastguard Worker 1211*b7c941bbSAndroid Build Coastguard Worker Note: resolutions are sorted by width x height in ascending order 1212*b7c941bbSAndroid Build Coastguard Worker Note: max resolution is capped at 1440x1920. 1213*b7c941bbSAndroid Build Coastguard Worker Note: min resolution is capped at 320x240. 1214*b7c941bbSAndroid Build Coastguard Worker 1215*b7c941bbSAndroid Build Coastguard Worker Args: 1216*b7c941bbSAndroid Build Coastguard Worker camera_id: int; device id 1217*b7c941bbSAndroid Build Coastguard Worker 1218*b7c941bbSAndroid Build Coastguard Worker Returns: 1219*b7c941bbSAndroid Build Coastguard Worker List of all supported preview resolutions with floor & ceiling set 1220*b7c941bbSAndroid Build Coastguard Worker by _CONSTANTS in ascending order. 1221*b7c941bbSAndroid Build Coastguard Worker """ 1222*b7c941bbSAndroid Build Coastguard Worker supported_preview_sizes = self.get_all_supported_preview_sizes(camera_id) 1223*b7c941bbSAndroid Build Coastguard Worker resolution_to_area = lambda s: int(s.split('x')[0])*int(s.split('x')[1]) 1224*b7c941bbSAndroid Build Coastguard Worker supported_preview_sizes = [size for size in supported_preview_sizes 1225*b7c941bbSAndroid Build Coastguard Worker if (resolution_to_area(size) 1226*b7c941bbSAndroid Build Coastguard Worker <= PREVIEW_MAX_TESTED_AREA 1227*b7c941bbSAndroid Build Coastguard Worker and resolution_to_area(size) 1228*b7c941bbSAndroid Build Coastguard Worker >= PREVIEW_MIN_TESTED_AREA)] 1229*b7c941bbSAndroid Build Coastguard Worker logging.debug( 1230*b7c941bbSAndroid Build Coastguard Worker 'Supported preview sizes (MIN: %d, MAX: %d area in pixels): %s', 1231*b7c941bbSAndroid Build Coastguard Worker PREVIEW_MIN_TESTED_AREA, PREVIEW_MAX_TESTED_AREA, 1232*b7c941bbSAndroid Build Coastguard Worker supported_preview_sizes 1233*b7c941bbSAndroid Build Coastguard Worker ) 1234*b7c941bbSAndroid Build Coastguard Worker return supported_preview_sizes 1235*b7c941bbSAndroid Build Coastguard Worker 1236*b7c941bbSAndroid Build Coastguard Worker def get_supported_extension_preview_sizes(self, camera_id, extension): 1237*b7c941bbSAndroid Build Coastguard Worker """Get all supported preview resolutions for the extension mode. 1238*b7c941bbSAndroid Build Coastguard Worker 1239*b7c941bbSAndroid Build Coastguard Worker ie. ['640x480', '800x600', '1280x720', '1440x1080', '1920x1080'] 1240*b7c941bbSAndroid Build Coastguard Worker 1241*b7c941bbSAndroid Build Coastguard Worker Note: resolutions are sorted by width x height in ascending order 1242*b7c941bbSAndroid Build Coastguard Worker 1243*b7c941bbSAndroid Build Coastguard Worker Args: 1244*b7c941bbSAndroid Build Coastguard Worker camera_id: int; device id 1245*b7c941bbSAndroid Build Coastguard Worker extension: int; camera extension mode 1246*b7c941bbSAndroid Build Coastguard Worker 1247*b7c941bbSAndroid Build Coastguard Worker Returns: 1248*b7c941bbSAndroid Build Coastguard Worker List of all supported camera extension preview resolutions in 1249*b7c941bbSAndroid Build Coastguard Worker ascending order. 1250*b7c941bbSAndroid Build Coastguard Worker """ 1251*b7c941bbSAndroid Build Coastguard Worker cmd = { 1252*b7c941bbSAndroid Build Coastguard Worker _CMD_NAME_STR: 'getSupportedExtensionPreviewSizes', 1253*b7c941bbSAndroid Build Coastguard Worker _CAMERA_ID_STR: camera_id, 1254*b7c941bbSAndroid Build Coastguard Worker "extension": extension # pylint: disable=g-inconsistent-quotes 1255*b7c941bbSAndroid Build Coastguard Worker } 1256*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 1257*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT 1258*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 1259*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 1260*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'supportedExtensionPreviewSizes': 1261*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 1262*b7c941bbSAndroid Build Coastguard Worker if not data[_STR_VALUE_STR]: 1263*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('No supported extension preview sizes') 1264*b7c941bbSAndroid Build Coastguard Worker supported_preview_sizes = data[_STR_VALUE_STR].split(';') 1265*b7c941bbSAndroid Build Coastguard Worker logging.debug('Supported extension preview sizes: %s', supported_preview_sizes) 1266*b7c941bbSAndroid Build Coastguard Worker return supported_preview_sizes 1267*b7c941bbSAndroid Build Coastguard Worker 1268*b7c941bbSAndroid Build Coastguard Worker def get_queryable_stream_combinations(self): 1269*b7c941bbSAndroid Build Coastguard Worker """Get all queryable stream combinations for this camera device. 1270*b7c941bbSAndroid Build Coastguard Worker 1271*b7c941bbSAndroid Build Coastguard Worker This function parses the queryable stream combinations string 1272*b7c941bbSAndroid Build Coastguard Worker returned from ItsService. The return value includes both the 1273*b7c941bbSAndroid Build Coastguard Worker string and the parsed result. 1274*b7c941bbSAndroid Build Coastguard Worker 1275*b7c941bbSAndroid Build Coastguard Worker One example of the queryable stream combination string is: 1276*b7c941bbSAndroid Build Coastguard Worker 1277*b7c941bbSAndroid Build Coastguard Worker 'priv:1920x1080+jpeg:4032x2268;priv:1280x720+priv:1280x720' 1278*b7c941bbSAndroid Build Coastguard Worker 1279*b7c941bbSAndroid Build Coastguard Worker which can be parsed to: 1280*b7c941bbSAndroid Build Coastguard Worker 1281*b7c941bbSAndroid Build Coastguard Worker [ 1282*b7c941bbSAndroid Build Coastguard Worker { 1283*b7c941bbSAndroid Build Coastguard Worker "name": "priv:1920x1080+jpeg:4032x2268", 1284*b7c941bbSAndroid Build Coastguard Worker "combination": [ 1285*b7c941bbSAndroid Build Coastguard Worker { 1286*b7c941bbSAndroid Build Coastguard Worker "format": "priv", 1287*b7c941bbSAndroid Build Coastguard Worker "size": "1920x1080" 1288*b7c941bbSAndroid Build Coastguard Worker } 1289*b7c941bbSAndroid Build Coastguard Worker { 1290*b7c941bbSAndroid Build Coastguard Worker "format": "jpeg", 1291*b7c941bbSAndroid Build Coastguard Worker "size": "4032x2268" 1292*b7c941bbSAndroid Build Coastguard Worker } 1293*b7c941bbSAndroid Build Coastguard Worker ] 1294*b7c941bbSAndroid Build Coastguard Worker } 1295*b7c941bbSAndroid Build Coastguard Worker { 1296*b7c941bbSAndroid Build Coastguard Worker "name": "priv:1280x720+priv:1280x720", 1297*b7c941bbSAndroid Build Coastguard Worker "combination": [ 1298*b7c941bbSAndroid Build Coastguard Worker { 1299*b7c941bbSAndroid Build Coastguard Worker "format": "priv", 1300*b7c941bbSAndroid Build Coastguard Worker "size": "1280x720" 1301*b7c941bbSAndroid Build Coastguard Worker }, 1302*b7c941bbSAndroid Build Coastguard Worker { 1303*b7c941bbSAndroid Build Coastguard Worker "format": "priv", 1304*b7c941bbSAndroid Build Coastguard Worker "size": "1280x720" 1305*b7c941bbSAndroid Build Coastguard Worker } 1306*b7c941bbSAndroid Build Coastguard Worker ] 1307*b7c941bbSAndroid Build Coastguard Worker } 1308*b7c941bbSAndroid Build Coastguard Worker ] 1309*b7c941bbSAndroid Build Coastguard Worker 1310*b7c941bbSAndroid Build Coastguard Worker Returns: 1311*b7c941bbSAndroid Build Coastguard Worker Tuple of: 1312*b7c941bbSAndroid Build Coastguard Worker - queryable stream combination string, and 1313*b7c941bbSAndroid Build Coastguard Worker - parsed stream combinations 1314*b7c941bbSAndroid Build Coastguard Worker """ 1315*b7c941bbSAndroid Build Coastguard Worker cmd = { 1316*b7c941bbSAndroid Build Coastguard Worker _CMD_NAME_STR: 'getQueryableStreamCombinations', 1317*b7c941bbSAndroid Build Coastguard Worker } 1318*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 1319*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT 1320*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 1321*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 1322*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'queryableStreamCombinations': 1323*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 1324*b7c941bbSAndroid Build Coastguard Worker if not data[_STR_VALUE_STR]: 1325*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('No queryable stream combinations') 1326*b7c941bbSAndroid Build Coastguard Worker 1327*b7c941bbSAndroid Build Coastguard Worker # Parse the stream combination string 1328*b7c941bbSAndroid Build Coastguard Worker combinations = [{ 1329*b7c941bbSAndroid Build Coastguard Worker 'name': c, 'combination': [ 1330*b7c941bbSAndroid Build Coastguard Worker {'format': s.split(':')[0], 1331*b7c941bbSAndroid Build Coastguard Worker 'size': s.split(':')[1]} for s in c.split('+')]} 1332*b7c941bbSAndroid Build Coastguard Worker for c in data[_STR_VALUE_STR].split(';')] 1333*b7c941bbSAndroid Build Coastguard Worker 1334*b7c941bbSAndroid Build Coastguard Worker return data[_STR_VALUE_STR], combinations 1335*b7c941bbSAndroid Build Coastguard Worker 1336*b7c941bbSAndroid Build Coastguard Worker def get_supported_extensions(self, camera_id): 1337*b7c941bbSAndroid Build Coastguard Worker """Get all supported camera extensions for this camera device. 1338*b7c941bbSAndroid Build Coastguard Worker 1339*b7c941bbSAndroid Build Coastguard Worker ie. [EXTENSION_AUTOMATIC, EXTENSION_BOKEH, 1340*b7c941bbSAndroid Build Coastguard Worker EXTENSION_FACE_RETOUCH, EXTENSION_HDR, EXTENSION_NIGHT] 1341*b7c941bbSAndroid Build Coastguard Worker where EXTENSION_AUTOMATIC is 0, EXTENSION_BOKEH is 1, etc. 1342*b7c941bbSAndroid Build Coastguard Worker 1343*b7c941bbSAndroid Build Coastguard Worker Args: 1344*b7c941bbSAndroid Build Coastguard Worker camera_id: int; device ID 1345*b7c941bbSAndroid Build Coastguard Worker Returns: 1346*b7c941bbSAndroid Build Coastguard Worker List of all supported extensions (as int) in ascending order. 1347*b7c941bbSAndroid Build Coastguard Worker """ 1348*b7c941bbSAndroid Build Coastguard Worker cmd = { 1349*b7c941bbSAndroid Build Coastguard Worker 'cmdName': 'getSupportedExtensions', 1350*b7c941bbSAndroid Build Coastguard Worker 'cameraId': camera_id 1351*b7c941bbSAndroid Build Coastguard Worker } 1352*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 1353*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT 1354*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 1355*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 1356*b7c941bbSAndroid Build Coastguard Worker if data['tag'] != 'supportedExtensions': 1357*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 1358*b7c941bbSAndroid Build Coastguard Worker if not data['strValue']: 1359*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('No supported extensions') 1360*b7c941bbSAndroid Build Coastguard Worker return [int(x) for x in str(data['strValue'][1:-1]).split(', ') if x] 1361*b7c941bbSAndroid Build Coastguard Worker 1362*b7c941bbSAndroid Build Coastguard Worker def get_supported_extension_sizes(self, camera_id, extension, image_format): 1363*b7c941bbSAndroid Build Coastguard Worker """Get all supported camera sizes for this camera, extension, and format. 1364*b7c941bbSAndroid Build Coastguard Worker 1365*b7c941bbSAndroid Build Coastguard Worker Sorts in ascending order according to area, i.e. 1366*b7c941bbSAndroid Build Coastguard Worker ['640x480', '800x600', '1280x720', '1440x1080', '1920x1080'] 1367*b7c941bbSAndroid Build Coastguard Worker 1368*b7c941bbSAndroid Build Coastguard Worker Args: 1369*b7c941bbSAndroid Build Coastguard Worker camera_id: int; device ID 1370*b7c941bbSAndroid Build Coastguard Worker extension: int; the integer value of the extension. 1371*b7c941bbSAndroid Build Coastguard Worker image_format: int; the integer value of the format. 1372*b7c941bbSAndroid Build Coastguard Worker Returns: 1373*b7c941bbSAndroid Build Coastguard Worker List of sizes supported for this camera, extension, and format. 1374*b7c941bbSAndroid Build Coastguard Worker """ 1375*b7c941bbSAndroid Build Coastguard Worker cmd = { 1376*b7c941bbSAndroid Build Coastguard Worker 'cmdName': 'getSupportedExtensionSizes', 1377*b7c941bbSAndroid Build Coastguard Worker 'cameraId': camera_id, 1378*b7c941bbSAndroid Build Coastguard Worker 'extension': extension, 1379*b7c941bbSAndroid Build Coastguard Worker 'format': image_format 1380*b7c941bbSAndroid Build Coastguard Worker } 1381*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 1382*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT 1383*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 1384*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 1385*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'supportedExtensionSizes': 1386*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 1387*b7c941bbSAndroid Build Coastguard Worker if not data[_STR_VALUE_STR]: 1388*b7c941bbSAndroid Build Coastguard Worker logging.debug('No supported extension sizes') 1389*b7c941bbSAndroid Build Coastguard Worker return '' 1390*b7c941bbSAndroid Build Coastguard Worker return data[_STR_VALUE_STR].split(';') 1391*b7c941bbSAndroid Build Coastguard Worker 1392*b7c941bbSAndroid Build Coastguard Worker def get_display_size(self): 1393*b7c941bbSAndroid Build Coastguard Worker """Get the display size of the screen. 1394*b7c941bbSAndroid Build Coastguard Worker 1395*b7c941bbSAndroid Build Coastguard Worker Returns: 1396*b7c941bbSAndroid Build Coastguard Worker The size of the display resolution in pixels. 1397*b7c941bbSAndroid Build Coastguard Worker """ 1398*b7c941bbSAndroid Build Coastguard Worker cmd = { 1399*b7c941bbSAndroid Build Coastguard Worker 'cmdName': 'getDisplaySize' 1400*b7c941bbSAndroid Build Coastguard Worker } 1401*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 1402*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT 1403*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 1404*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 1405*b7c941bbSAndroid Build Coastguard Worker if data['tag'] != 'displaySize': 1406*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 1407*b7c941bbSAndroid Build Coastguard Worker if not data['strValue']: 1408*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('No display size') 1409*b7c941bbSAndroid Build Coastguard Worker return data['strValue'].split('x') 1410*b7c941bbSAndroid Build Coastguard Worker 1411*b7c941bbSAndroid Build Coastguard Worker def get_max_camcorder_profile_size(self, camera_id): 1412*b7c941bbSAndroid Build Coastguard Worker """Get the maximum camcorder profile size for this camera device. 1413*b7c941bbSAndroid Build Coastguard Worker 1414*b7c941bbSAndroid Build Coastguard Worker Args: 1415*b7c941bbSAndroid Build Coastguard Worker camera_id: int; device id 1416*b7c941bbSAndroid Build Coastguard Worker Returns: 1417*b7c941bbSAndroid Build Coastguard Worker The maximum size among all camcorder profiles supported by this camera. 1418*b7c941bbSAndroid Build Coastguard Worker """ 1419*b7c941bbSAndroid Build Coastguard Worker cmd = { 1420*b7c941bbSAndroid Build Coastguard Worker 'cmdName': 'getMaxCamcorderProfileSize', 1421*b7c941bbSAndroid Build Coastguard Worker 'cameraId': camera_id 1422*b7c941bbSAndroid Build Coastguard Worker } 1423*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 1424*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT 1425*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 1426*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 1427*b7c941bbSAndroid Build Coastguard Worker if data['tag'] != 'maxCamcorderProfileSize': 1428*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 1429*b7c941bbSAndroid Build Coastguard Worker if not data['strValue']: 1430*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('No max camcorder profile size') 1431*b7c941bbSAndroid Build Coastguard Worker return data['strValue'].split('x') 1432*b7c941bbSAndroid Build Coastguard Worker 1433*b7c941bbSAndroid Build Coastguard Worker def do_simple_capture(self, cmd, out_surface): 1434*b7c941bbSAndroid Build Coastguard Worker """Issue single capture request via command and read back image/metadata. 1435*b7c941bbSAndroid Build Coastguard Worker 1436*b7c941bbSAndroid Build Coastguard Worker Args: 1437*b7c941bbSAndroid Build Coastguard Worker cmd: Dictionary specifying command name, requests, and output surface. 1438*b7c941bbSAndroid Build Coastguard Worker out_surface: Dictionary describing output surface. 1439*b7c941bbSAndroid Build Coastguard Worker Returns: 1440*b7c941bbSAndroid Build Coastguard Worker An object which contains following fields: 1441*b7c941bbSAndroid Build Coastguard Worker * data: the image data as a numpy array of bytes. 1442*b7c941bbSAndroid Build Coastguard Worker * width: the width of the captured image. 1443*b7c941bbSAndroid Build Coastguard Worker * height: the height of the captured image. 1444*b7c941bbSAndroid Build Coastguard Worker * format: image format 1445*b7c941bbSAndroid Build Coastguard Worker * metadata: the capture result object 1446*b7c941bbSAndroid Build Coastguard Worker """ 1447*b7c941bbSAndroid Build Coastguard Worker fmt = out_surface['format'] if 'format' in out_surface else 'yuv' 1448*b7c941bbSAndroid Build Coastguard Worker if fmt == 'jpg': fmt = 'jpeg' 1449*b7c941bbSAndroid Build Coastguard Worker 1450*b7c941bbSAndroid Build Coastguard Worker # we only have 1 capture request and 1 surface by definition. 1451*b7c941bbSAndroid Build Coastguard Worker ncap = SINGLE_CAPTURE_NCAP 1452*b7c941bbSAndroid Build Coastguard Worker 1453*b7c941bbSAndroid Build Coastguard Worker cam_id = None 1454*b7c941bbSAndroid Build Coastguard Worker bufs = {} 1455*b7c941bbSAndroid Build Coastguard Worker yuv_bufs = {} 1456*b7c941bbSAndroid Build Coastguard Worker if self._hidden_physical_id: 1457*b7c941bbSAndroid Build Coastguard Worker out_surface['physicalCamera'] = self._hidden_physical_id 1458*b7c941bbSAndroid Build Coastguard Worker 1459*b7c941bbSAndroid Build Coastguard Worker if 'physicalCamera' in out_surface: 1460*b7c941bbSAndroid Build Coastguard Worker cam_id = out_surface['physicalCamera'] 1461*b7c941bbSAndroid Build Coastguard Worker else: 1462*b7c941bbSAndroid Build Coastguard Worker cam_id = self._camera_id 1463*b7c941bbSAndroid Build Coastguard Worker 1464*b7c941bbSAndroid Build Coastguard Worker bufs[cam_id] = { 1465*b7c941bbSAndroid Build Coastguard Worker 'raw': [], 1466*b7c941bbSAndroid Build Coastguard Worker 'raw10': [], 1467*b7c941bbSAndroid Build Coastguard Worker 'raw12': [], 1468*b7c941bbSAndroid Build Coastguard Worker 'rawStats': [], 1469*b7c941bbSAndroid Build Coastguard Worker 'dng': [], 1470*b7c941bbSAndroid Build Coastguard Worker 'jpeg': [], 1471*b7c941bbSAndroid Build Coastguard Worker 'y8': [], 1472*b7c941bbSAndroid Build Coastguard Worker 'rawQuadBayer': [], 1473*b7c941bbSAndroid Build Coastguard Worker 'rawQuadBayerStats': [], 1474*b7c941bbSAndroid Build Coastguard Worker 'raw10Stats': [], 1475*b7c941bbSAndroid Build Coastguard Worker 'raw10QuadBayerStats': [], 1476*b7c941bbSAndroid Build Coastguard Worker 'raw10QuadBayer': [], 1477*b7c941bbSAndroid Build Coastguard Worker } 1478*b7c941bbSAndroid Build Coastguard Worker 1479*b7c941bbSAndroid Build Coastguard Worker # Only allow yuv output to multiple targets 1480*b7c941bbSAndroid Build Coastguard Worker yuv_surface = None 1481*b7c941bbSAndroid Build Coastguard Worker if cam_id == self._camera_id: 1482*b7c941bbSAndroid Build Coastguard Worker if 'physicalCamera' not in out_surface: 1483*b7c941bbSAndroid Build Coastguard Worker if out_surface['format'] == 'yuv': 1484*b7c941bbSAndroid Build Coastguard Worker yuv_surface = out_surface 1485*b7c941bbSAndroid Build Coastguard Worker else: 1486*b7c941bbSAndroid Build Coastguard Worker if ('physicalCamera' in out_surface and 1487*b7c941bbSAndroid Build Coastguard Worker out_surface['physicalCamera'] == cam_id): 1488*b7c941bbSAndroid Build Coastguard Worker if out_surface['format'] == 'yuv': 1489*b7c941bbSAndroid Build Coastguard Worker yuv_surface = out_surface 1490*b7c941bbSAndroid Build Coastguard Worker 1491*b7c941bbSAndroid Build Coastguard Worker # Compute the buffer size of YUV targets 1492*b7c941bbSAndroid Build Coastguard Worker yuv_maxsize_1d = 0 1493*b7c941bbSAndroid Build Coastguard Worker if yuv_surface is not None: 1494*b7c941bbSAndroid Build Coastguard Worker if ('width' not in yuv_surface and 'height' not in yuv_surface): 1495*b7c941bbSAndroid Build Coastguard Worker if self.props is None: 1496*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Camera props are unavailable') 1497*b7c941bbSAndroid Build Coastguard Worker yuv_maxsize_2d = capture_request_utils.get_available_output_sizes( 1498*b7c941bbSAndroid Build Coastguard Worker 'yuv', self.props)[0] 1499*b7c941bbSAndroid Build Coastguard Worker # YUV420 size = 1.5 bytes per pixel 1500*b7c941bbSAndroid Build Coastguard Worker yuv_maxsize_1d = (yuv_maxsize_2d[0] * yuv_maxsize_2d[1] * 3) // 2 1501*b7c941bbSAndroid Build Coastguard Worker if 'width' in yuv_surface and 'height' in yuv_surface: 1502*b7c941bbSAndroid Build Coastguard Worker yuv_size = (yuv_surface['width'] * yuv_surface['height'] * 3) // 2 1503*b7c941bbSAndroid Build Coastguard Worker else: 1504*b7c941bbSAndroid Build Coastguard Worker yuv_size = yuv_maxsize_1d 1505*b7c941bbSAndroid Build Coastguard Worker 1506*b7c941bbSAndroid Build Coastguard Worker yuv_bufs[cam_id] = {yuv_size: []} 1507*b7c941bbSAndroid Build Coastguard Worker 1508*b7c941bbSAndroid Build Coastguard Worker cam_ids = self._camera_id 1509*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT) 1510*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 1511*b7c941bbSAndroid Build Coastguard Worker 1512*b7c941bbSAndroid Build Coastguard Worker nbufs = 0 1513*b7c941bbSAndroid Build Coastguard Worker md = None 1514*b7c941bbSAndroid Build Coastguard Worker physical_md = None 1515*b7c941bbSAndroid Build Coastguard Worker width = None 1516*b7c941bbSAndroid Build Coastguard Worker height = None 1517*b7c941bbSAndroid Build Coastguard Worker capture_results_returned = False 1518*b7c941bbSAndroid Build Coastguard Worker while (nbufs < ncap) or (not capture_results_returned): 1519*b7c941bbSAndroid Build Coastguard Worker json_obj, buf = self.__read_response_from_socket() 1520*b7c941bbSAndroid Build Coastguard Worker if (json_obj[_TAG_STR] in ItsSession.IMAGE_FORMAT_LIST_1 and 1521*b7c941bbSAndroid Build Coastguard Worker buf is not None): 1522*b7c941bbSAndroid Build Coastguard Worker fmt = json_obj[_TAG_STR][:-5] 1523*b7c941bbSAndroid Build Coastguard Worker bufs[self._camera_id][fmt].append(buf) 1524*b7c941bbSAndroid Build Coastguard Worker nbufs += 1 1525*b7c941bbSAndroid Build Coastguard Worker elif json_obj[_TAG_STR] == 'yuvImage': 1526*b7c941bbSAndroid Build Coastguard Worker buf_size = get_array_size(buf) 1527*b7c941bbSAndroid Build Coastguard Worker yuv_bufs[self._camera_id][buf_size].append(buf) 1528*b7c941bbSAndroid Build Coastguard Worker nbufs += 1 1529*b7c941bbSAndroid Build Coastguard Worker elif json_obj[_TAG_STR] == 'captureResults': 1530*b7c941bbSAndroid Build Coastguard Worker capture_results_returned = True 1531*b7c941bbSAndroid Build Coastguard Worker md = json_obj[_OBJ_VALUE_STR]['captureResult'] 1532*b7c941bbSAndroid Build Coastguard Worker physical_md = json_obj[_OBJ_VALUE_STR]['physicalResults'] 1533*b7c941bbSAndroid Build Coastguard Worker outputs = json_obj[_OBJ_VALUE_STR]['outputs'] 1534*b7c941bbSAndroid Build Coastguard Worker returned_fmt = outputs[0]['format'] 1535*b7c941bbSAndroid Build Coastguard Worker if fmt != returned_fmt: 1536*b7c941bbSAndroid Build Coastguard Worker raise AssertionError( 1537*b7c941bbSAndroid Build Coastguard Worker f'Incorrect format. Requested: {fmt}, ' 1538*b7c941bbSAndroid Build Coastguard Worker f'Received: {returned_fmt}') 1539*b7c941bbSAndroid Build Coastguard Worker width = outputs[0]['width'] 1540*b7c941bbSAndroid Build Coastguard Worker height = outputs[0]['height'] 1541*b7c941bbSAndroid Build Coastguard Worker requested_width = out_surface['width'] 1542*b7c941bbSAndroid Build Coastguard Worker requested_height = out_surface['height'] 1543*b7c941bbSAndroid Build Coastguard Worker if requested_width != width or requested_height != height: 1544*b7c941bbSAndroid Build Coastguard Worker raise AssertionError( 1545*b7c941bbSAndroid Build Coastguard Worker 'Incorrect size. ' 1546*b7c941bbSAndroid Build Coastguard Worker f'Requested: {requested_width}x{requested_height}, ' 1547*b7c941bbSAndroid Build Coastguard Worker f'Received: {width}x{height}') 1548*b7c941bbSAndroid Build Coastguard Worker else: 1549*b7c941bbSAndroid Build Coastguard Worker tag_string = unicodedata.normalize('NFKD', json_obj[_TAG_STR]).encode( 1550*b7c941bbSAndroid Build Coastguard Worker 'ascii', 'ignore') 1551*b7c941bbSAndroid Build Coastguard Worker for x in ItsSession.IMAGE_FORMAT_LIST_2: 1552*b7c941bbSAndroid Build Coastguard Worker x = bytes(x, encoding='utf-8') 1553*b7c941bbSAndroid Build Coastguard Worker if tag_string.startswith(x): 1554*b7c941bbSAndroid Build Coastguard Worker if x == b'yuvImage': 1555*b7c941bbSAndroid Build Coastguard Worker physical_id = json_obj[_TAG_STR][len(x):] 1556*b7c941bbSAndroid Build Coastguard Worker if physical_id in cam_ids: 1557*b7c941bbSAndroid Build Coastguard Worker buf_size = get_array_size(buf) 1558*b7c941bbSAndroid Build Coastguard Worker yuv_bufs[physical_id][buf_size].append(buf) 1559*b7c941bbSAndroid Build Coastguard Worker nbufs += 1 1560*b7c941bbSAndroid Build Coastguard Worker else: 1561*b7c941bbSAndroid Build Coastguard Worker physical_id = json_obj[_TAG_STR][len(x):] 1562*b7c941bbSAndroid Build Coastguard Worker if physical_id in cam_ids: 1563*b7c941bbSAndroid Build Coastguard Worker fmt = x[:-5].decode('UTF-8') 1564*b7c941bbSAndroid Build Coastguard Worker bufs[physical_id][fmt].append(buf) 1565*b7c941bbSAndroid Build Coastguard Worker nbufs += 1 1566*b7c941bbSAndroid Build Coastguard Worker 1567*b7c941bbSAndroid Build Coastguard Worker if 'physicalCamera' in out_surface: 1568*b7c941bbSAndroid Build Coastguard Worker cam_id = out_surface['physicalCamera'] 1569*b7c941bbSAndroid Build Coastguard Worker else: 1570*b7c941bbSAndroid Build Coastguard Worker cam_id = self._camera_id 1571*b7c941bbSAndroid Build Coastguard Worker ret = {'width': width, 'height': height, 'format': fmt} 1572*b7c941bbSAndroid Build Coastguard Worker if cam_id == self._camera_id: 1573*b7c941bbSAndroid Build Coastguard Worker ret['metadata'] = md 1574*b7c941bbSAndroid Build Coastguard Worker else: 1575*b7c941bbSAndroid Build Coastguard Worker if cam_id in physical_md: 1576*b7c941bbSAndroid Build Coastguard Worker ret['metadata'] = physical_md[cam_id] 1577*b7c941bbSAndroid Build Coastguard Worker 1578*b7c941bbSAndroid Build Coastguard Worker if fmt == 'yuv': 1579*b7c941bbSAndroid Build Coastguard Worker buf_size = (width * height * 3) // 2 1580*b7c941bbSAndroid Build Coastguard Worker ret['data'] = yuv_bufs[cam_id][buf_size][0] 1581*b7c941bbSAndroid Build Coastguard Worker else: 1582*b7c941bbSAndroid Build Coastguard Worker ret['data'] = bufs[cam_id][fmt][0] 1583*b7c941bbSAndroid Build Coastguard Worker 1584*b7c941bbSAndroid Build Coastguard Worker return ret 1585*b7c941bbSAndroid Build Coastguard Worker 1586*b7c941bbSAndroid Build Coastguard Worker def do_jca_capture(self, dut, log_path, flash, facing): 1587*b7c941bbSAndroid Build Coastguard Worker """Take a capture using JCA, modifying capture settings using the UI. 1588*b7c941bbSAndroid Build Coastguard Worker 1589*b7c941bbSAndroid Build Coastguard Worker Selects UI elements to modify settings, and presses the capture button. 1590*b7c941bbSAndroid Build Coastguard Worker Reads response from socket containing the capture path, and 1591*b7c941bbSAndroid Build Coastguard Worker pulls the image from the DUT. 1592*b7c941bbSAndroid Build Coastguard Worker 1593*b7c941bbSAndroid Build Coastguard Worker This method is included here because an ITS session is needed to retrieve 1594*b7c941bbSAndroid Build Coastguard Worker the capture path from the device. 1595*b7c941bbSAndroid Build Coastguard Worker 1596*b7c941bbSAndroid Build Coastguard Worker Args: 1597*b7c941bbSAndroid Build Coastguard Worker dut: An Android controller device object. 1598*b7c941bbSAndroid Build Coastguard Worker log_path: str; log path to save screenshots. 1599*b7c941bbSAndroid Build Coastguard Worker flash: str; constant describing the desired flash mode. 1600*b7c941bbSAndroid Build Coastguard Worker Acceptable values: 'OFF' and 'AUTO'. 1601*b7c941bbSAndroid Build Coastguard Worker facing: str; constant describing the direction the camera lens faces. 1602*b7c941bbSAndroid Build Coastguard Worker Acceptable values: camera_properties_utils.LENS_FACING[BACK, FRONT] 1603*b7c941bbSAndroid Build Coastguard Worker Returns: 1604*b7c941bbSAndroid Build Coastguard Worker The host-side path of the capture. 1605*b7c941bbSAndroid Build Coastguard Worker """ 1606*b7c941bbSAndroid Build Coastguard Worker ui_interaction_utils.open_jca_viewfinder(dut, log_path) 1607*b7c941bbSAndroid Build Coastguard Worker ui_interaction_utils.switch_jca_camera(dut, log_path, facing) 1608*b7c941bbSAndroid Build Coastguard Worker # Bring up settings, switch flash mode, and close settings 1609*b7c941bbSAndroid Build Coastguard Worker dut.ui(res=ui_interaction_utils.QUICK_SETTINGS_RESOURCE_ID).click() 1610*b7c941bbSAndroid Build Coastguard Worker if flash not in ui_interaction_utils.FLASH_MODE_TO_CLICKS: 1611*b7c941bbSAndroid Build Coastguard Worker raise ValueError(f'Flash mode {flash} not supported') 1612*b7c941bbSAndroid Build Coastguard Worker for _ in range(ui_interaction_utils.FLASH_MODE_TO_CLICKS[flash]): 1613*b7c941bbSAndroid Build Coastguard Worker dut.ui(res=ui_interaction_utils.QUICK_SET_FLASH_RESOURCE_ID).click() 1614*b7c941bbSAndroid Build Coastguard Worker dut.take_screenshot(log_path, prefix='flash_mode_set') 1615*b7c941bbSAndroid Build Coastguard Worker dut.ui(res=ui_interaction_utils.QUICK_SETTINGS_RESOURCE_ID).click() 1616*b7c941bbSAndroid Build Coastguard Worker # Take capture 1617*b7c941bbSAndroid Build Coastguard Worker dut.ui(res=ui_interaction_utils.CAPTURE_BUTTON_RESOURCE_ID).click() 1618*b7c941bbSAndroid Build Coastguard Worker return self.get_and_pull_jca_capture(dut, log_path) 1619*b7c941bbSAndroid Build Coastguard Worker 1620*b7c941bbSAndroid Build Coastguard Worker def do_jca_video_capture(self, dut, log_path, duration): 1621*b7c941bbSAndroid Build Coastguard Worker """Take a capture using JCA using the UI. 1622*b7c941bbSAndroid Build Coastguard Worker 1623*b7c941bbSAndroid Build Coastguard Worker Captures JCA video by holding the capture button with requested duration. 1624*b7c941bbSAndroid Build Coastguard Worker Reads response from socket containing the capture path, and 1625*b7c941bbSAndroid Build Coastguard Worker pulls the image from the DUT. 1626*b7c941bbSAndroid Build Coastguard Worker 1627*b7c941bbSAndroid Build Coastguard Worker This method is included here because an ITS session is needed to retrieve 1628*b7c941bbSAndroid Build Coastguard Worker the capture path from the device. 1629*b7c941bbSAndroid Build Coastguard Worker 1630*b7c941bbSAndroid Build Coastguard Worker Args: 1631*b7c941bbSAndroid Build Coastguard Worker dut: An Android controller device object. 1632*b7c941bbSAndroid Build Coastguard Worker log_path: str; log path to save screenshots. 1633*b7c941bbSAndroid Build Coastguard Worker duration: int; requested video duration, in ms. 1634*b7c941bbSAndroid Build Coastguard Worker Returns: 1635*b7c941bbSAndroid Build Coastguard Worker The host-side path of the capture. 1636*b7c941bbSAndroid Build Coastguard Worker """ 1637*b7c941bbSAndroid Build Coastguard Worker # Make sure JCA is started 1638*b7c941bbSAndroid Build Coastguard Worker jca_capture_button_visible = dut.ui( 1639*b7c941bbSAndroid Build Coastguard Worker res=ui_interaction_utils.CAPTURE_BUTTON_RESOURCE_ID).wait.exists( 1640*b7c941bbSAndroid Build Coastguard Worker ui_interaction_utils.UI_OBJECT_WAIT_TIME_SECONDS) 1641*b7c941bbSAndroid Build Coastguard Worker if not jca_capture_button_visible: 1642*b7c941bbSAndroid Build Coastguard Worker raise AssertionError('JCA was not started! Please use' 1643*b7c941bbSAndroid Build Coastguard Worker 'open_jca_viewfinder() or do_jca_video_setup()' 1644*b7c941bbSAndroid Build Coastguard Worker 'in ui_interaction_utils.py to start JCA.') 1645*b7c941bbSAndroid Build Coastguard Worker dut.ui(res=ui_interaction_utils.CAPTURE_BUTTON_RESOURCE_ID).click(duration) 1646*b7c941bbSAndroid Build Coastguard Worker return self.get_and_pull_jca_capture(dut, log_path) 1647*b7c941bbSAndroid Build Coastguard Worker 1648*b7c941bbSAndroid Build Coastguard Worker def get_and_pull_jca_capture(self, dut, log_path): 1649*b7c941bbSAndroid Build Coastguard Worker """Retrieve a capture path from the socket and pulls capture to host. 1650*b7c941bbSAndroid Build Coastguard Worker 1651*b7c941bbSAndroid Build Coastguard Worker Args: 1652*b7c941bbSAndroid Build Coastguard Worker dut: An Android controller device object. 1653*b7c941bbSAndroid Build Coastguard Worker log_path: str; log path to save screenshots. 1654*b7c941bbSAndroid Build Coastguard Worker Returns: 1655*b7c941bbSAndroid Build Coastguard Worker The host-side path of the capture. 1656*b7c941bbSAndroid Build Coastguard Worker Raises: 1657*b7c941bbSAndroid Build Coastguard Worker CameraItsError: If unexpected data is retrieved from the socket. 1658*b7c941bbSAndroid Build Coastguard Worker """ 1659*b7c941bbSAndroid Build Coastguard Worker capture_path, capture_status = None, None 1660*b7c941bbSAndroid Build Coastguard Worker while not capture_path or not capture_status: 1661*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 1662*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] == JCA_CAPTURE_PATH_TAG: 1663*b7c941bbSAndroid Build Coastguard Worker capture_path = data[_STR_VALUE_STR] 1664*b7c941bbSAndroid Build Coastguard Worker elif data[_TAG_STR] == JCA_CAPTURE_STATUS_TAG: 1665*b7c941bbSAndroid Build Coastguard Worker capture_status = data[_STR_VALUE_STR] 1666*b7c941bbSAndroid Build Coastguard Worker else: 1667*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError( 1668*b7c941bbSAndroid Build Coastguard Worker f'Invalid response {data[_TAG_STR]} for JCA capture') 1669*b7c941bbSAndroid Build Coastguard Worker if capture_status != RESULT_OK_STATUS: 1670*b7c941bbSAndroid Build Coastguard Worker logging.error('Capture failed! Expected status %d, received %d', 1671*b7c941bbSAndroid Build Coastguard Worker RESULT_OK_STATUS, capture_status) 1672*b7c941bbSAndroid Build Coastguard Worker logging.debug('capture path: %s', capture_path) 1673*b7c941bbSAndroid Build Coastguard Worker _, capture_name = os.path.split(capture_path) 1674*b7c941bbSAndroid Build Coastguard Worker its_device_utils.run(f'adb -s {dut.serial} pull {capture_path} {log_path}') 1675*b7c941bbSAndroid Build Coastguard Worker return os.path.join(log_path, capture_name) 1676*b7c941bbSAndroid Build Coastguard Worker 1677*b7c941bbSAndroid Build Coastguard Worker def do_capture_with_flash(self, 1678*b7c941bbSAndroid Build Coastguard Worker preview_request_start, 1679*b7c941bbSAndroid Build Coastguard Worker preview_request_idle, 1680*b7c941bbSAndroid Build Coastguard Worker still_capture_req, 1681*b7c941bbSAndroid Build Coastguard Worker out_surface): 1682*b7c941bbSAndroid Build Coastguard Worker """Issue capture request with flash and read back the image and metadata. 1683*b7c941bbSAndroid Build Coastguard Worker 1684*b7c941bbSAndroid Build Coastguard Worker Captures a single image with still_capture_req as capture request 1685*b7c941bbSAndroid Build Coastguard Worker with flash. It triggers the precapture sequence with preview request 1686*b7c941bbSAndroid Build Coastguard Worker preview_request_start with capture intent preview by setting aePrecapture 1687*b7c941bbSAndroid Build Coastguard Worker trigger to Start. This is followed by repeated preview requests 1688*b7c941bbSAndroid Build Coastguard Worker preview_request_idle with aePrecaptureTrigger set to IDLE. 1689*b7c941bbSAndroid Build Coastguard Worker Once the AE is converged, a single image is captured still_capture_req 1690*b7c941bbSAndroid Build Coastguard Worker during which the flash must be fired. 1691*b7c941bbSAndroid Build Coastguard Worker Note: The part where we read output data from socket is cloned from 1692*b7c941bbSAndroid Build Coastguard Worker do_capture and will be consolidated in U. 1693*b7c941bbSAndroid Build Coastguard Worker 1694*b7c941bbSAndroid Build Coastguard Worker Args: 1695*b7c941bbSAndroid Build Coastguard Worker preview_request_start: Preview request with aePrecaptureTrigger set to 1696*b7c941bbSAndroid Build Coastguard Worker Start 1697*b7c941bbSAndroid Build Coastguard Worker preview_request_idle: Preview request with aePrecaptureTrigger set to Idle 1698*b7c941bbSAndroid Build Coastguard Worker still_capture_req: Single still capture request. 1699*b7c941bbSAndroid Build Coastguard Worker out_surface: Specifications of the output image formats and 1700*b7c941bbSAndroid Build Coastguard Worker sizes to use for capture. Supports yuv and jpeg. 1701*b7c941bbSAndroid Build Coastguard Worker Returns: 1702*b7c941bbSAndroid Build Coastguard Worker An object which contains following fields: 1703*b7c941bbSAndroid Build Coastguard Worker * data: the image data as a numpy array of bytes. 1704*b7c941bbSAndroid Build Coastguard Worker * width: the width of the captured image. 1705*b7c941bbSAndroid Build Coastguard Worker * height: the height of the captured image. 1706*b7c941bbSAndroid Build Coastguard Worker * format: image format 1707*b7c941bbSAndroid Build Coastguard Worker * metadata: the capture result object 1708*b7c941bbSAndroid Build Coastguard Worker """ 1709*b7c941bbSAndroid Build Coastguard Worker cmd = {} 1710*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'doCaptureWithFlash' 1711*b7c941bbSAndroid Build Coastguard Worker cmd['previewRequestStart'] = [preview_request_start] 1712*b7c941bbSAndroid Build Coastguard Worker cmd['previewRequestIdle'] = [preview_request_idle] 1713*b7c941bbSAndroid Build Coastguard Worker cmd['stillCaptureRequest'] = [still_capture_req] 1714*b7c941bbSAndroid Build Coastguard Worker cmd['outputSurfaces'] = [out_surface] 1715*b7c941bbSAndroid Build Coastguard Worker if 'android.control.aeMode' in still_capture_req: 1716*b7c941bbSAndroid Build Coastguard Worker logging.debug('Capturing image with aeMode: %d', 1717*b7c941bbSAndroid Build Coastguard Worker still_capture_req['android.control.aeMode']) 1718*b7c941bbSAndroid Build Coastguard Worker return self.do_simple_capture(cmd, out_surface) 1719*b7c941bbSAndroid Build Coastguard Worker 1720*b7c941bbSAndroid Build Coastguard Worker def do_capture_with_extensions(self, 1721*b7c941bbSAndroid Build Coastguard Worker cap_request, 1722*b7c941bbSAndroid Build Coastguard Worker extension, 1723*b7c941bbSAndroid Build Coastguard Worker out_surface): 1724*b7c941bbSAndroid Build Coastguard Worker """Issue extension capture request(s), and read back image(s) and metadata. 1725*b7c941bbSAndroid Build Coastguard Worker 1726*b7c941bbSAndroid Build Coastguard Worker Args: 1727*b7c941bbSAndroid Build Coastguard Worker cap_request: The Python dict/list specifying the capture(s), which will be 1728*b7c941bbSAndroid Build Coastguard Worker converted to JSON and sent to the device. 1729*b7c941bbSAndroid Build Coastguard Worker extension: The extension to be requested. 1730*b7c941bbSAndroid Build Coastguard Worker out_surface: specifications of the output image format and 1731*b7c941bbSAndroid Build Coastguard Worker size to use for the capture. 1732*b7c941bbSAndroid Build Coastguard Worker 1733*b7c941bbSAndroid Build Coastguard Worker Returns: 1734*b7c941bbSAndroid Build Coastguard Worker An object, list of objects, or list of lists of objects, where each 1735*b7c941bbSAndroid Build Coastguard Worker object contains the following fields: 1736*b7c941bbSAndroid Build Coastguard Worker * data: the image data as a numpy array of bytes. 1737*b7c941bbSAndroid Build Coastguard Worker * width: the width of the captured image. 1738*b7c941bbSAndroid Build Coastguard Worker * height: the height of the captured image. 1739*b7c941bbSAndroid Build Coastguard Worker * format: image the format, in [ 1740*b7c941bbSAndroid Build Coastguard Worker "yuv","jpeg","raw","raw10","raw12","rawStats","dng"]. 1741*b7c941bbSAndroid Build Coastguard Worker * metadata: the capture result object (Python dictionary). 1742*b7c941bbSAndroid Build Coastguard Worker """ 1743*b7c941bbSAndroid Build Coastguard Worker cmd = {} 1744*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'doCaptureWithExtensions' 1745*b7c941bbSAndroid Build Coastguard Worker cmd['repeatRequests'] = [] 1746*b7c941bbSAndroid Build Coastguard Worker cmd['captureRequests'] = [cap_request] 1747*b7c941bbSAndroid Build Coastguard Worker cmd['extension'] = extension 1748*b7c941bbSAndroid Build Coastguard Worker cmd['outputSurfaces'] = [out_surface] 1749*b7c941bbSAndroid Build Coastguard Worker 1750*b7c941bbSAndroid Build Coastguard Worker logging.debug('Capturing image with EXTENSIONS.') 1751*b7c941bbSAndroid Build Coastguard Worker return self.do_simple_capture(cmd, out_surface) 1752*b7c941bbSAndroid Build Coastguard Worker 1753*b7c941bbSAndroid Build Coastguard Worker def do_capture(self, 1754*b7c941bbSAndroid Build Coastguard Worker cap_request, 1755*b7c941bbSAndroid Build Coastguard Worker out_surfaces=None, 1756*b7c941bbSAndroid Build Coastguard Worker reprocess_format=None, 1757*b7c941bbSAndroid Build Coastguard Worker repeat_request=None, 1758*b7c941bbSAndroid Build Coastguard Worker reuse_session=False, 1759*b7c941bbSAndroid Build Coastguard Worker first_surface_for_3a=False): 1760*b7c941bbSAndroid Build Coastguard Worker """Issue capture request(s), and read back the image(s) and metadata. 1761*b7c941bbSAndroid Build Coastguard Worker 1762*b7c941bbSAndroid Build Coastguard Worker The main top-level function for capturing one or more images using the 1763*b7c941bbSAndroid Build Coastguard Worker device. Captures a single image if cap_request is a single object, and 1764*b7c941bbSAndroid Build Coastguard Worker captures a burst if it is a list of objects. 1765*b7c941bbSAndroid Build Coastguard Worker 1766*b7c941bbSAndroid Build Coastguard Worker The optional repeat_request field can be used to assign a repeating 1767*b7c941bbSAndroid Build Coastguard Worker request list ran in background for 3 seconds to warm up the capturing 1768*b7c941bbSAndroid Build Coastguard Worker pipeline before start capturing. The repeat_requests will be ran on a 1769*b7c941bbSAndroid Build Coastguard Worker 640x480 YUV surface without sending any data back. The caller needs to 1770*b7c941bbSAndroid Build Coastguard Worker make sure the stream configuration defined by out_surfaces and 1771*b7c941bbSAndroid Build Coastguard Worker repeat_request are valid or do_capture may fail because device does not 1772*b7c941bbSAndroid Build Coastguard Worker support such stream configuration. 1773*b7c941bbSAndroid Build Coastguard Worker 1774*b7c941bbSAndroid Build Coastguard Worker The out_surfaces field can specify the width(s), height(s), and 1775*b7c941bbSAndroid Build Coastguard Worker format(s) of the captured image. The formats may be "yuv", "jpeg", 1776*b7c941bbSAndroid Build Coastguard Worker "dng", "raw", "raw10", "raw12", "rawStats" or "y8". The default is a 1777*b7c941bbSAndroid Build Coastguard Worker YUV420 frame ("yuv") corresponding to a full sensor frame. 1778*b7c941bbSAndroid Build Coastguard Worker 1779*b7c941bbSAndroid Build Coastguard Worker 1. Optionally the out_surfaces field can specify physical camera id(s) if 1780*b7c941bbSAndroid Build Coastguard Worker the current camera device is a logical multi-camera. The physical camera 1781*b7c941bbSAndroid Build Coastguard Worker id must refer to a physical camera backing this logical camera device. 1782*b7c941bbSAndroid Build Coastguard Worker 2. Optionally The output_surfaces field can also specify the use case(s) if 1783*b7c941bbSAndroid Build Coastguard Worker the current camera device has STREAM_USE_CASE capability. 1784*b7c941bbSAndroid Build Coastguard Worker 1785*b7c941bbSAndroid Build Coastguard Worker Note that one or more surfaces can be specified, allowing a capture to 1786*b7c941bbSAndroid Build Coastguard Worker request images back in multiple formats (e.g.) raw+yuv, raw+jpeg, 1787*b7c941bbSAndroid Build Coastguard Worker yuv+jpeg, raw+yuv+jpeg. If the size is omitted for a surface, the 1788*b7c941bbSAndroid Build Coastguard Worker default is the largest resolution available for the format of that 1789*b7c941bbSAndroid Build Coastguard Worker surface. At most one output surface can be specified for a given format, 1790*b7c941bbSAndroid Build Coastguard Worker and raw+dng, raw10+dng, and raw+raw10 are not supported as combinations. 1791*b7c941bbSAndroid Build Coastguard Worker 1792*b7c941bbSAndroid Build Coastguard Worker If reprocess_format is not None, for each request, an intermediate 1793*b7c941bbSAndroid Build Coastguard Worker buffer of the given reprocess_format will be captured from camera and 1794*b7c941bbSAndroid Build Coastguard Worker the intermediate buffer will be reprocessed to the output surfaces. The 1795*b7c941bbSAndroid Build Coastguard Worker following settings will be turned off when capturing the intermediate 1796*b7c941bbSAndroid Build Coastguard Worker buffer and will be applied when reprocessing the intermediate buffer. 1797*b7c941bbSAndroid Build Coastguard Worker 1. android.noiseReduction.mode 1798*b7c941bbSAndroid Build Coastguard Worker 2. android.edge.mode 1799*b7c941bbSAndroid Build Coastguard Worker 3. android.reprocess.effectiveExposureFactor 1800*b7c941bbSAndroid Build Coastguard Worker 1801*b7c941bbSAndroid Build Coastguard Worker Supported reprocess format are "yuv" and "private". Supported output 1802*b7c941bbSAndroid Build Coastguard Worker surface formats when reprocessing is enabled are "yuv" and "jpeg". 1803*b7c941bbSAndroid Build Coastguard Worker 1804*b7c941bbSAndroid Build Coastguard Worker Example of a single capture request: 1805*b7c941bbSAndroid Build Coastguard Worker 1806*b7c941bbSAndroid Build Coastguard Worker { 1807*b7c941bbSAndroid Build Coastguard Worker "android.sensor.exposureTime": 100*1000*1000, 1808*b7c941bbSAndroid Build Coastguard Worker "android.sensor.sensitivity": 100 1809*b7c941bbSAndroid Build Coastguard Worker } 1810*b7c941bbSAndroid Build Coastguard Worker 1811*b7c941bbSAndroid Build Coastguard Worker Example of a list of capture requests: 1812*b7c941bbSAndroid Build Coastguard Worker [ 1813*b7c941bbSAndroid Build Coastguard Worker { 1814*b7c941bbSAndroid Build Coastguard Worker "android.sensor.exposureTime": 100*1000*1000, 1815*b7c941bbSAndroid Build Coastguard Worker "android.sensor.sensitivity": 100 1816*b7c941bbSAndroid Build Coastguard Worker }, 1817*b7c941bbSAndroid Build Coastguard Worker { 1818*b7c941bbSAndroid Build Coastguard Worker "android.sensor.exposureTime": 100*1000*1000, 1819*b7c941bbSAndroid Build Coastguard Worker "android.sensor.sensitivity": 200 1820*b7c941bbSAndroid Build Coastguard Worker } 1821*b7c941bbSAndroid Build Coastguard Worker ] 1822*b7c941bbSAndroid Build Coastguard Worker 1823*b7c941bbSAndroid Build Coastguard Worker Example of output surface specifications: 1824*b7c941bbSAndroid Build Coastguard Worker { 1825*b7c941bbSAndroid Build Coastguard Worker "width": 640, 1826*b7c941bbSAndroid Build Coastguard Worker "height": 480, 1827*b7c941bbSAndroid Build Coastguard Worker "format": "yuv" 1828*b7c941bbSAndroid Build Coastguard Worker } 1829*b7c941bbSAndroid Build Coastguard Worker [ 1830*b7c941bbSAndroid Build Coastguard Worker { 1831*b7c941bbSAndroid Build Coastguard Worker "format": "jpeg" 1832*b7c941bbSAndroid Build Coastguard Worker }, 1833*b7c941bbSAndroid Build Coastguard Worker { 1834*b7c941bbSAndroid Build Coastguard Worker "format": "raw" 1835*b7c941bbSAndroid Build Coastguard Worker } 1836*b7c941bbSAndroid Build Coastguard Worker ] 1837*b7c941bbSAndroid Build Coastguard Worker 1838*b7c941bbSAndroid Build Coastguard Worker The following variables defined in this class are shortcuts for 1839*b7c941bbSAndroid Build Coastguard Worker specifying one or more formats where each output is the full size for 1840*b7c941bbSAndroid Build Coastguard Worker that format; they can be used as values for the out_surfaces arguments: 1841*b7c941bbSAndroid Build Coastguard Worker 1842*b7c941bbSAndroid Build Coastguard Worker CAP_RAW 1843*b7c941bbSAndroid Build Coastguard Worker CAP_DNG 1844*b7c941bbSAndroid Build Coastguard Worker CAP_YUV 1845*b7c941bbSAndroid Build Coastguard Worker CAP_JPEG 1846*b7c941bbSAndroid Build Coastguard Worker CAP_RAW_YUV 1847*b7c941bbSAndroid Build Coastguard Worker CAP_DNG_YUV 1848*b7c941bbSAndroid Build Coastguard Worker CAP_RAW_JPEG 1849*b7c941bbSAndroid Build Coastguard Worker CAP_DNG_JPEG 1850*b7c941bbSAndroid Build Coastguard Worker CAP_YUV_JPEG 1851*b7c941bbSAndroid Build Coastguard Worker CAP_RAW_YUV_JPEG 1852*b7c941bbSAndroid Build Coastguard Worker CAP_DNG_YUV_JPEG 1853*b7c941bbSAndroid Build Coastguard Worker 1854*b7c941bbSAndroid Build Coastguard Worker If multiple formats are specified, then this function returns multiple 1855*b7c941bbSAndroid Build Coastguard Worker capture objects, one for each requested format. If multiple formats and 1856*b7c941bbSAndroid Build Coastguard Worker multiple captures (i.e. a burst) are specified, then this function 1857*b7c941bbSAndroid Build Coastguard Worker returns multiple lists of capture objects. In both cases, the order of 1858*b7c941bbSAndroid Build Coastguard Worker the returned objects matches the order of the requested formats in the 1859*b7c941bbSAndroid Build Coastguard Worker out_surfaces parameter. For example: 1860*b7c941bbSAndroid Build Coastguard Worker 1861*b7c941bbSAndroid Build Coastguard Worker yuv_cap = do_capture(req1) 1862*b7c941bbSAndroid Build Coastguard Worker yuv_cap = do_capture(req1,yuv_fmt) 1863*b7c941bbSAndroid Build Coastguard Worker yuv_cap, raw_cap = do_capture(req1, [yuv_fmt,raw_fmt]) 1864*b7c941bbSAndroid Build Coastguard Worker yuv_caps = do_capture([req1,req2], yuv_fmt) 1865*b7c941bbSAndroid Build Coastguard Worker yuv_caps, raw_caps = do_capture([req1,req2], [yuv_fmt,raw_fmt]) 1866*b7c941bbSAndroid Build Coastguard Worker 1867*b7c941bbSAndroid Build Coastguard Worker The "rawStats" format processes the raw image and returns a new image 1868*b7c941bbSAndroid Build Coastguard Worker of statistics from the raw image. The format takes additional keys, 1869*b7c941bbSAndroid Build Coastguard Worker "gridWidth" and "gridHeight" which are size of grid cells in a 2D grid 1870*b7c941bbSAndroid Build Coastguard Worker of the raw image. For each grid cell, the mean and variance of each raw 1871*b7c941bbSAndroid Build Coastguard Worker channel is computed, and the do_capture call returns two 4-element float 1872*b7c941bbSAndroid Build Coastguard Worker images of dimensions (rawWidth / gridWidth, rawHeight / gridHeight), 1873*b7c941bbSAndroid Build Coastguard Worker concatenated back-to-back, where the first image contains the 4-channel 1874*b7c941bbSAndroid Build Coastguard Worker means and the second contains the 4-channel variances. Note that only 1875*b7c941bbSAndroid Build Coastguard Worker pixels in the active array crop region are used; pixels outside this 1876*b7c941bbSAndroid Build Coastguard Worker region (for example optical black rows) are cropped out before the 1877*b7c941bbSAndroid Build Coastguard Worker gridding and statistics computation is performed. 1878*b7c941bbSAndroid Build Coastguard Worker 1879*b7c941bbSAndroid Build Coastguard Worker For the rawStats format, if the gridWidth is not provided then the raw 1880*b7c941bbSAndroid Build Coastguard Worker image width is used as the default, and similarly for gridHeight. With 1881*b7c941bbSAndroid Build Coastguard Worker this, the following is an example of a output description that computes 1882*b7c941bbSAndroid Build Coastguard Worker the mean and variance across each image row: 1883*b7c941bbSAndroid Build Coastguard Worker { 1884*b7c941bbSAndroid Build Coastguard Worker "gridHeight": 1, 1885*b7c941bbSAndroid Build Coastguard Worker "format": "rawStats" 1886*b7c941bbSAndroid Build Coastguard Worker } 1887*b7c941bbSAndroid Build Coastguard Worker 1888*b7c941bbSAndroid Build Coastguard Worker Args: 1889*b7c941bbSAndroid Build Coastguard Worker cap_request: The Python dict/list specifying the capture(s), which will be 1890*b7c941bbSAndroid Build Coastguard Worker converted to JSON and sent to the device. 1891*b7c941bbSAndroid Build Coastguard Worker out_surfaces: (Optional) specifications of the output image formats and 1892*b7c941bbSAndroid Build Coastguard Worker sizes to use for each capture. 1893*b7c941bbSAndroid Build Coastguard Worker reprocess_format: (Optional) The reprocessing format. If not 1894*b7c941bbSAndroid Build Coastguard Worker None,reprocessing will be enabled. 1895*b7c941bbSAndroid Build Coastguard Worker repeat_request: Repeating request list. 1896*b7c941bbSAndroid Build Coastguard Worker reuse_session: True if ItsService.java should try to use 1897*b7c941bbSAndroid Build Coastguard Worker the existing CameraCaptureSession. 1898*b7c941bbSAndroid Build Coastguard Worker first_surface_for_3a: Use first surface in out_surfaces for 3A, not capture 1899*b7c941bbSAndroid Build Coastguard Worker Only applicable if out_surfaces contains at least 1 surface. 1900*b7c941bbSAndroid Build Coastguard Worker 1901*b7c941bbSAndroid Build Coastguard Worker Returns: 1902*b7c941bbSAndroid Build Coastguard Worker An object, list of objects, or list of lists of objects, where each 1903*b7c941bbSAndroid Build Coastguard Worker object contains the following fields: 1904*b7c941bbSAndroid Build Coastguard Worker * data: the image data as a numpy array of bytes. 1905*b7c941bbSAndroid Build Coastguard Worker * width: the width of the captured image. 1906*b7c941bbSAndroid Build Coastguard Worker * height: the height of the captured image. 1907*b7c941bbSAndroid Build Coastguard Worker * format: image the format, in [ 1908*b7c941bbSAndroid Build Coastguard Worker "yuv","jpeg","raw","raw10","raw12","rawStats","dng"]. 1909*b7c941bbSAndroid Build Coastguard Worker * metadata: the capture result object (Python dictionary). 1910*b7c941bbSAndroid Build Coastguard Worker """ 1911*b7c941bbSAndroid Build Coastguard Worker cmd = {} 1912*b7c941bbSAndroid Build Coastguard Worker if reprocess_format is not None: 1913*b7c941bbSAndroid Build Coastguard Worker if repeat_request is not None: 1914*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError( 1915*b7c941bbSAndroid Build Coastguard Worker 'repeating request + reprocessing is not supported') 1916*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'doReprocessCapture' 1917*b7c941bbSAndroid Build Coastguard Worker cmd['reprocessFormat'] = reprocess_format 1918*b7c941bbSAndroid Build Coastguard Worker else: 1919*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'doCapture' 1920*b7c941bbSAndroid Build Coastguard Worker 1921*b7c941bbSAndroid Build Coastguard Worker if repeat_request is None: 1922*b7c941bbSAndroid Build Coastguard Worker cmd['repeatRequests'] = [] 1923*b7c941bbSAndroid Build Coastguard Worker elif not isinstance(repeat_request, list): 1924*b7c941bbSAndroid Build Coastguard Worker cmd['repeatRequests'] = [repeat_request] 1925*b7c941bbSAndroid Build Coastguard Worker else: 1926*b7c941bbSAndroid Build Coastguard Worker cmd['repeatRequests'] = repeat_request 1927*b7c941bbSAndroid Build Coastguard Worker 1928*b7c941bbSAndroid Build Coastguard Worker if not isinstance(cap_request, list): 1929*b7c941bbSAndroid Build Coastguard Worker cmd['captureRequests'] = [cap_request] 1930*b7c941bbSAndroid Build Coastguard Worker else: 1931*b7c941bbSAndroid Build Coastguard Worker cmd['captureRequests'] = cap_request 1932*b7c941bbSAndroid Build Coastguard Worker 1933*b7c941bbSAndroid Build Coastguard Worker if out_surfaces: 1934*b7c941bbSAndroid Build Coastguard Worker if isinstance(out_surfaces, list): 1935*b7c941bbSAndroid Build Coastguard Worker cmd['outputSurfaces'] = out_surfaces 1936*b7c941bbSAndroid Build Coastguard Worker else: 1937*b7c941bbSAndroid Build Coastguard Worker cmd['outputSurfaces'] = [out_surfaces] 1938*b7c941bbSAndroid Build Coastguard Worker formats = [ 1939*b7c941bbSAndroid Build Coastguard Worker c['format'] if 'format' in c else 'yuv' for c in cmd['outputSurfaces'] 1940*b7c941bbSAndroid Build Coastguard Worker ] 1941*b7c941bbSAndroid Build Coastguard Worker formats = [s if s != 'jpg' else 'jpeg' for s in formats] 1942*b7c941bbSAndroid Build Coastguard Worker else: 1943*b7c941bbSAndroid Build Coastguard Worker max_yuv_size = capture_request_utils.get_available_output_sizes( 1944*b7c941bbSAndroid Build Coastguard Worker 'yuv', self.props)[0] 1945*b7c941bbSAndroid Build Coastguard Worker formats = ['yuv'] 1946*b7c941bbSAndroid Build Coastguard Worker cmd['outputSurfaces'] = [{ 1947*b7c941bbSAndroid Build Coastguard Worker 'format': 'yuv', 1948*b7c941bbSAndroid Build Coastguard Worker 'width': max_yuv_size[0], 1949*b7c941bbSAndroid Build Coastguard Worker 'height': max_yuv_size[1] 1950*b7c941bbSAndroid Build Coastguard Worker }] 1951*b7c941bbSAndroid Build Coastguard Worker 1952*b7c941bbSAndroid Build Coastguard Worker cmd['reuseSession'] = reuse_session 1953*b7c941bbSAndroid Build Coastguard Worker cmd['firstSurfaceFor3A'] = first_surface_for_3a 1954*b7c941bbSAndroid Build Coastguard Worker 1955*b7c941bbSAndroid Build Coastguard Worker requested_surfaces = cmd['outputSurfaces'][:] 1956*b7c941bbSAndroid Build Coastguard Worker if first_surface_for_3a: 1957*b7c941bbSAndroid Build Coastguard Worker formats.pop(0) 1958*b7c941bbSAndroid Build Coastguard Worker requested_surfaces.pop(0) 1959*b7c941bbSAndroid Build Coastguard Worker 1960*b7c941bbSAndroid Build Coastguard Worker ncap = len(cmd['captureRequests']) 1961*b7c941bbSAndroid Build Coastguard Worker nsurf = len(formats) 1962*b7c941bbSAndroid Build Coastguard Worker 1963*b7c941bbSAndroid Build Coastguard Worker cam_ids = [] 1964*b7c941bbSAndroid Build Coastguard Worker bufs = {} 1965*b7c941bbSAndroid Build Coastguard Worker yuv_bufs = {} 1966*b7c941bbSAndroid Build Coastguard Worker for i, s in enumerate(cmd['outputSurfaces']): 1967*b7c941bbSAndroid Build Coastguard Worker if self._hidden_physical_id: 1968*b7c941bbSAndroid Build Coastguard Worker s['physicalCamera'] = self._hidden_physical_id 1969*b7c941bbSAndroid Build Coastguard Worker 1970*b7c941bbSAndroid Build Coastguard Worker if 'physicalCamera' in s: 1971*b7c941bbSAndroid Build Coastguard Worker cam_id = s['physicalCamera'] 1972*b7c941bbSAndroid Build Coastguard Worker else: 1973*b7c941bbSAndroid Build Coastguard Worker cam_id = self._camera_id 1974*b7c941bbSAndroid Build Coastguard Worker 1975*b7c941bbSAndroid Build Coastguard Worker if cam_id not in cam_ids: 1976*b7c941bbSAndroid Build Coastguard Worker cam_ids.append(cam_id) 1977*b7c941bbSAndroid Build Coastguard Worker bufs[cam_id] = { 1978*b7c941bbSAndroid Build Coastguard Worker 'raw': [], 1979*b7c941bbSAndroid Build Coastguard Worker 'raw10': [], 1980*b7c941bbSAndroid Build Coastguard Worker 'raw12': [], 1981*b7c941bbSAndroid Build Coastguard Worker 'rawStats': [], 1982*b7c941bbSAndroid Build Coastguard Worker 'dng': [], 1983*b7c941bbSAndroid Build Coastguard Worker 'jpeg': [], 1984*b7c941bbSAndroid Build Coastguard Worker 'jpeg_r': [], 1985*b7c941bbSAndroid Build Coastguard Worker 'y8': [], 1986*b7c941bbSAndroid Build Coastguard Worker 'rawQuadBayer': [], 1987*b7c941bbSAndroid Build Coastguard Worker 'rawQuadBayerStats': [], 1988*b7c941bbSAndroid Build Coastguard Worker 'raw10Stats': [], 1989*b7c941bbSAndroid Build Coastguard Worker 'raw10QuadBayerStats': [], 1990*b7c941bbSAndroid Build Coastguard Worker 'raw10QuadBayer': [], 1991*b7c941bbSAndroid Build Coastguard Worker } 1992*b7c941bbSAndroid Build Coastguard Worker 1993*b7c941bbSAndroid Build Coastguard Worker for cam_id in cam_ids: 1994*b7c941bbSAndroid Build Coastguard Worker # Only allow yuv output to multiple targets 1995*b7c941bbSAndroid Build Coastguard Worker if cam_id == self._camera_id: 1996*b7c941bbSAndroid Build Coastguard Worker yuv_surfaces = [ 1997*b7c941bbSAndroid Build Coastguard Worker s for s in requested_surfaces 1998*b7c941bbSAndroid Build Coastguard Worker if s['format'] == 'yuv' and 'physicalCamera' not in s 1999*b7c941bbSAndroid Build Coastguard Worker ] 2000*b7c941bbSAndroid Build Coastguard Worker formats_for_id = [ 2001*b7c941bbSAndroid Build Coastguard Worker s['format'] 2002*b7c941bbSAndroid Build Coastguard Worker for s in requested_surfaces 2003*b7c941bbSAndroid Build Coastguard Worker if 'physicalCamera' not in s 2004*b7c941bbSAndroid Build Coastguard Worker ] 2005*b7c941bbSAndroid Build Coastguard Worker else: 2006*b7c941bbSAndroid Build Coastguard Worker yuv_surfaces = [ 2007*b7c941bbSAndroid Build Coastguard Worker s for s in requested_surfaces if s['format'] == 'yuv' and 2008*b7c941bbSAndroid Build Coastguard Worker 'physicalCamera' in s and s['physicalCamera'] == cam_id 2009*b7c941bbSAndroid Build Coastguard Worker ] 2010*b7c941bbSAndroid Build Coastguard Worker formats_for_id = [ 2011*b7c941bbSAndroid Build Coastguard Worker s['format'] 2012*b7c941bbSAndroid Build Coastguard Worker for s in requested_surfaces 2013*b7c941bbSAndroid Build Coastguard Worker if 'physicalCamera' in s and s['physicalCamera'] == cam_id 2014*b7c941bbSAndroid Build Coastguard Worker ] 2015*b7c941bbSAndroid Build Coastguard Worker 2016*b7c941bbSAndroid Build Coastguard Worker n_yuv = len(yuv_surfaces) 2017*b7c941bbSAndroid Build Coastguard Worker # Compute the buffer size of YUV targets 2018*b7c941bbSAndroid Build Coastguard Worker yuv_maxsize_1d = 0 2019*b7c941bbSAndroid Build Coastguard Worker for s in yuv_surfaces: 2020*b7c941bbSAndroid Build Coastguard Worker if ('width' not in s and 'height' not in s): 2021*b7c941bbSAndroid Build Coastguard Worker if self.props is None: 2022*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Camera props are unavailable') 2023*b7c941bbSAndroid Build Coastguard Worker yuv_maxsize_2d = capture_request_utils.get_available_output_sizes( 2024*b7c941bbSAndroid Build Coastguard Worker 'yuv', self.props)[0] 2025*b7c941bbSAndroid Build Coastguard Worker # YUV420 size = 1.5 bytes per pixel 2026*b7c941bbSAndroid Build Coastguard Worker yuv_maxsize_1d = (yuv_maxsize_2d[0] * yuv_maxsize_2d[1] * 3) // 2 2027*b7c941bbSAndroid Build Coastguard Worker break 2028*b7c941bbSAndroid Build Coastguard Worker yuv_sizes = [ 2029*b7c941bbSAndroid Build Coastguard Worker (c['width'] * c['height'] * 3) // 2 2030*b7c941bbSAndroid Build Coastguard Worker if 'width' in c and 'height' in c else yuv_maxsize_1d 2031*b7c941bbSAndroid Build Coastguard Worker for c in yuv_surfaces 2032*b7c941bbSAndroid Build Coastguard Worker ] 2033*b7c941bbSAndroid Build Coastguard Worker # Currently we don't pass enough metadata from ItsService to distinguish 2034*b7c941bbSAndroid Build Coastguard Worker # different yuv stream of same buffer size 2035*b7c941bbSAndroid Build Coastguard Worker if len(yuv_sizes) != len(set(yuv_sizes)): 2036*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError( 2037*b7c941bbSAndroid Build Coastguard Worker 'ITS does not support yuv outputs of same buffer size') 2038*b7c941bbSAndroid Build Coastguard Worker if len(formats_for_id) > len(set(formats_for_id)): 2039*b7c941bbSAndroid Build Coastguard Worker if n_yuv != len(formats_for_id) - len(set(formats_for_id)) + 1: 2040*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Duplicate format requested') 2041*b7c941bbSAndroid Build Coastguard Worker 2042*b7c941bbSAndroid Build Coastguard Worker yuv_bufs[cam_id] = {size: [] for size in yuv_sizes} 2043*b7c941bbSAndroid Build Coastguard Worker 2044*b7c941bbSAndroid Build Coastguard Worker logging.debug('yuv bufs: %s', yuv_bufs) 2045*b7c941bbSAndroid Build Coastguard Worker raw_formats = 0 2046*b7c941bbSAndroid Build Coastguard Worker raw_formats += 1 if 'dng' in formats else 0 2047*b7c941bbSAndroid Build Coastguard Worker raw_formats += 1 if 'raw' in formats else 0 2048*b7c941bbSAndroid Build Coastguard Worker raw_formats += 1 if 'raw10' in formats else 0 2049*b7c941bbSAndroid Build Coastguard Worker raw_formats += 1 if 'raw12' in formats else 0 2050*b7c941bbSAndroid Build Coastguard Worker raw_formats += 1 if 'rawStats' in formats else 0 2051*b7c941bbSAndroid Build Coastguard Worker raw_formats += 1 if 'rawQuadBayer' in formats else 0 2052*b7c941bbSAndroid Build Coastguard Worker raw_formats += 1 if 'rawQuadBayerStats' in formats else 0 2053*b7c941bbSAndroid Build Coastguard Worker raw_formats += 1 if 'raw10Stats' in formats else 0 2054*b7c941bbSAndroid Build Coastguard Worker raw_formats += 1 if 'raw10QuadBayer' in formats else 0 2055*b7c941bbSAndroid Build Coastguard Worker raw_formats += 1 if 'raw10QuadBayerStats' in formats else 0 2056*b7c941bbSAndroid Build Coastguard Worker 2057*b7c941bbSAndroid Build Coastguard Worker if raw_formats > 1: 2058*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Different raw formats not supported') 2059*b7c941bbSAndroid Build Coastguard Worker 2060*b7c941bbSAndroid Build Coastguard Worker # Detect long exposure time and set timeout accordingly 2061*b7c941bbSAndroid Build Coastguard Worker longest_exp_time = 0 2062*b7c941bbSAndroid Build Coastguard Worker for req in cmd['captureRequests']: 2063*b7c941bbSAndroid Build Coastguard Worker if 'android.sensor.exposureTime' in req and req[ 2064*b7c941bbSAndroid Build Coastguard Worker 'android.sensor.exposureTime'] > longest_exp_time: 2065*b7c941bbSAndroid Build Coastguard Worker longest_exp_time = req['android.sensor.exposureTime'] 2066*b7c941bbSAndroid Build Coastguard Worker 2067*b7c941bbSAndroid Build Coastguard Worker extended_timeout = longest_exp_time // self.SEC_TO_NSEC + self.SOCK_TIMEOUT 2068*b7c941bbSAndroid Build Coastguard Worker if repeat_request: 2069*b7c941bbSAndroid Build Coastguard Worker extended_timeout += self.EXTRA_SOCK_TIMEOUT 2070*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(extended_timeout) 2071*b7c941bbSAndroid Build Coastguard Worker 2072*b7c941bbSAndroid Build Coastguard Worker logging.debug('Capturing %d frame%s with %d format%s [%s]', ncap, 2073*b7c941bbSAndroid Build Coastguard Worker 's' if ncap > 1 else '', nsurf, 's' if nsurf > 1 else '', 2074*b7c941bbSAndroid Build Coastguard Worker ','.join(formats)) 2075*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 2076*b7c941bbSAndroid Build Coastguard Worker 2077*b7c941bbSAndroid Build Coastguard Worker # Wait for ncap*nsurf images and ncap metadata responses. 2078*b7c941bbSAndroid Build Coastguard Worker # Assume that captures come out in the same order as requested in 2079*b7c941bbSAndroid Build Coastguard Worker # the burst, however individual images of different formats can come 2080*b7c941bbSAndroid Build Coastguard Worker # out in any order for that capture. 2081*b7c941bbSAndroid Build Coastguard Worker nbufs = 0 2082*b7c941bbSAndroid Build Coastguard Worker mds = [] 2083*b7c941bbSAndroid Build Coastguard Worker physical_mds = [] 2084*b7c941bbSAndroid Build Coastguard Worker widths = None 2085*b7c941bbSAndroid Build Coastguard Worker heights = None 2086*b7c941bbSAndroid Build Coastguard Worker camera_id = ( 2087*b7c941bbSAndroid Build Coastguard Worker self._camera_id 2088*b7c941bbSAndroid Build Coastguard Worker if not self._hidden_physical_id 2089*b7c941bbSAndroid Build Coastguard Worker else self._hidden_physical_id 2090*b7c941bbSAndroid Build Coastguard Worker ) 2091*b7c941bbSAndroid Build Coastguard Worker logging.debug('Using camera_id %s to store buffers', camera_id) 2092*b7c941bbSAndroid Build Coastguard Worker while nbufs < ncap * nsurf or len(mds) < ncap: 2093*b7c941bbSAndroid Build Coastguard Worker json_obj, buf = self.__read_response_from_socket() 2094*b7c941bbSAndroid Build Coastguard Worker if (json_obj[_TAG_STR] in ItsSession.IMAGE_FORMAT_LIST_1 and 2095*b7c941bbSAndroid Build Coastguard Worker buf is not None): 2096*b7c941bbSAndroid Build Coastguard Worker fmt = json_obj[_TAG_STR][:-5] 2097*b7c941bbSAndroid Build Coastguard Worker bufs[camera_id][fmt].append(buf) 2098*b7c941bbSAndroid Build Coastguard Worker nbufs += 1 2099*b7c941bbSAndroid Build Coastguard Worker # Physical camera is appended to the tag string of a private capture 2100*b7c941bbSAndroid Build Coastguard Worker elif json_obj[_TAG_STR].startswith('privImage'): 2101*b7c941bbSAndroid Build Coastguard Worker # The private image format buffers are opaque to camera clients 2102*b7c941bbSAndroid Build Coastguard Worker # and cannot be accessed. 2103*b7c941bbSAndroid Build Coastguard Worker nbufs += 1 2104*b7c941bbSAndroid Build Coastguard Worker elif json_obj[_TAG_STR] == 'yuvImage': 2105*b7c941bbSAndroid Build Coastguard Worker buf_size = get_array_size(buf) 2106*b7c941bbSAndroid Build Coastguard Worker yuv_bufs[camera_id][buf_size].append(buf) 2107*b7c941bbSAndroid Build Coastguard Worker nbufs += 1 2108*b7c941bbSAndroid Build Coastguard Worker elif json_obj[_TAG_STR] == 'captureResults': 2109*b7c941bbSAndroid Build Coastguard Worker mds.append(json_obj[_OBJ_VALUE_STR]['captureResult']) 2110*b7c941bbSAndroid Build Coastguard Worker physical_mds.append(json_obj[_OBJ_VALUE_STR]['physicalResults']) 2111*b7c941bbSAndroid Build Coastguard Worker outputs = json_obj[_OBJ_VALUE_STR]['outputs'] 2112*b7c941bbSAndroid Build Coastguard Worker widths = [out['width'] for out in outputs] 2113*b7c941bbSAndroid Build Coastguard Worker heights = [out['height'] for out in outputs] 2114*b7c941bbSAndroid Build Coastguard Worker else: 2115*b7c941bbSAndroid Build Coastguard Worker tag_string = unicodedata.normalize('NFKD', json_obj[_TAG_STR]).encode( 2116*b7c941bbSAndroid Build Coastguard Worker 'ascii', 'ignore') 2117*b7c941bbSAndroid Build Coastguard Worker for x in ItsSession.IMAGE_FORMAT_LIST_2: 2118*b7c941bbSAndroid Build Coastguard Worker x = bytes(x, encoding='utf-8') 2119*b7c941bbSAndroid Build Coastguard Worker if tag_string.startswith(x): 2120*b7c941bbSAndroid Build Coastguard Worker if x == b'yuvImage': 2121*b7c941bbSAndroid Build Coastguard Worker physical_id = json_obj[_TAG_STR][len(x):] 2122*b7c941bbSAndroid Build Coastguard Worker if physical_id in cam_ids: 2123*b7c941bbSAndroid Build Coastguard Worker buf_size = get_array_size(buf) 2124*b7c941bbSAndroid Build Coastguard Worker yuv_bufs[physical_id][buf_size].append(buf) 2125*b7c941bbSAndroid Build Coastguard Worker nbufs += 1 2126*b7c941bbSAndroid Build Coastguard Worker else: 2127*b7c941bbSAndroid Build Coastguard Worker physical_id = json_obj[_TAG_STR][len(x):] 2128*b7c941bbSAndroid Build Coastguard Worker if physical_id in cam_ids: 2129*b7c941bbSAndroid Build Coastguard Worker fmt = x[:-5].decode('UTF-8') 2130*b7c941bbSAndroid Build Coastguard Worker bufs[physical_id][fmt].append(buf) 2131*b7c941bbSAndroid Build Coastguard Worker nbufs += 1 2132*b7c941bbSAndroid Build Coastguard Worker rets = [] 2133*b7c941bbSAndroid Build Coastguard Worker for j, fmt in enumerate(formats): 2134*b7c941bbSAndroid Build Coastguard Worker objs = [] 2135*b7c941bbSAndroid Build Coastguard Worker if 'physicalCamera' in requested_surfaces[j]: 2136*b7c941bbSAndroid Build Coastguard Worker cam_id = requested_surfaces[j]['physicalCamera'] 2137*b7c941bbSAndroid Build Coastguard Worker else: 2138*b7c941bbSAndroid Build Coastguard Worker cam_id = self._camera_id 2139*b7c941bbSAndroid Build Coastguard Worker 2140*b7c941bbSAndroid Build Coastguard Worker for i in range(ncap): 2141*b7c941bbSAndroid Build Coastguard Worker obj = {} 2142*b7c941bbSAndroid Build Coastguard Worker obj['width'] = widths[j] 2143*b7c941bbSAndroid Build Coastguard Worker obj['height'] = heights[j] 2144*b7c941bbSAndroid Build Coastguard Worker obj['format'] = fmt 2145*b7c941bbSAndroid Build Coastguard Worker if cam_id == self._camera_id: 2146*b7c941bbSAndroid Build Coastguard Worker obj['metadata'] = mds[i] 2147*b7c941bbSAndroid Build Coastguard Worker else: 2148*b7c941bbSAndroid Build Coastguard Worker for physical_md in physical_mds[i]: 2149*b7c941bbSAndroid Build Coastguard Worker if cam_id in physical_md: 2150*b7c941bbSAndroid Build Coastguard Worker obj['metadata'] = physical_md[cam_id] 2151*b7c941bbSAndroid Build Coastguard Worker break 2152*b7c941bbSAndroid Build Coastguard Worker 2153*b7c941bbSAndroid Build Coastguard Worker if fmt == 'yuv': 2154*b7c941bbSAndroid Build Coastguard Worker buf_size = (widths[j] * heights[j] * 3) // 2 2155*b7c941bbSAndroid Build Coastguard Worker obj['data'] = yuv_bufs[cam_id][buf_size][i] 2156*b7c941bbSAndroid Build Coastguard Worker elif fmt != 'priv': 2157*b7c941bbSAndroid Build Coastguard Worker obj['data'] = bufs[cam_id][fmt][i] 2158*b7c941bbSAndroid Build Coastguard Worker objs.append(obj) 2159*b7c941bbSAndroid Build Coastguard Worker rets.append(objs if ncap > 1 else objs[0]) 2160*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(self.SOCK_TIMEOUT) 2161*b7c941bbSAndroid Build Coastguard Worker if len(rets) > 1 or (isinstance(rets[0], dict) and 2162*b7c941bbSAndroid Build Coastguard Worker isinstance(cap_request, list)): 2163*b7c941bbSAndroid Build Coastguard Worker return rets 2164*b7c941bbSAndroid Build Coastguard Worker else: 2165*b7c941bbSAndroid Build Coastguard Worker return rets[0] 2166*b7c941bbSAndroid Build Coastguard Worker 2167*b7c941bbSAndroid Build Coastguard Worker def do_vibrate(self, pattern): 2168*b7c941bbSAndroid Build Coastguard Worker """Cause the device to vibrate to a specific pattern. 2169*b7c941bbSAndroid Build Coastguard Worker 2170*b7c941bbSAndroid Build Coastguard Worker Args: 2171*b7c941bbSAndroid Build Coastguard Worker pattern: Durations (ms) for which to turn on or off the vibrator. 2172*b7c941bbSAndroid Build Coastguard Worker The first value indicates the number of milliseconds to wait 2173*b7c941bbSAndroid Build Coastguard Worker before turning the vibrator on. The next value indicates the 2174*b7c941bbSAndroid Build Coastguard Worker number of milliseconds for which to keep the vibrator on 2175*b7c941bbSAndroid Build Coastguard Worker before turning it off. Subsequent values alternate between 2176*b7c941bbSAndroid Build Coastguard Worker durations in milliseconds to turn the vibrator off or to turn 2177*b7c941bbSAndroid Build Coastguard Worker the vibrator on. 2178*b7c941bbSAndroid Build Coastguard Worker 2179*b7c941bbSAndroid Build Coastguard Worker Returns: 2180*b7c941bbSAndroid Build Coastguard Worker Nothing. 2181*b7c941bbSAndroid Build Coastguard Worker """ 2182*b7c941bbSAndroid Build Coastguard Worker cmd = {} 2183*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'doVibrate' 2184*b7c941bbSAndroid Build Coastguard Worker cmd['pattern'] = pattern 2185*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 2186*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 2187*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'vibrationStarted': 2188*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid response for command: %s' % 2189*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR]) 2190*b7c941bbSAndroid Build Coastguard Worker 2191*b7c941bbSAndroid Build Coastguard Worker def set_audio_restriction(self, mode): 2192*b7c941bbSAndroid Build Coastguard Worker """Set the audio restriction mode for this camera device. 2193*b7c941bbSAndroid Build Coastguard Worker 2194*b7c941bbSAndroid Build Coastguard Worker Args: 2195*b7c941bbSAndroid Build Coastguard Worker mode: int; the audio restriction mode. See CameraDevice.java for valid 2196*b7c941bbSAndroid Build Coastguard Worker value. 2197*b7c941bbSAndroid Build Coastguard Worker Returns: 2198*b7c941bbSAndroid Build Coastguard Worker Nothing. 2199*b7c941bbSAndroid Build Coastguard Worker """ 2200*b7c941bbSAndroid Build Coastguard Worker cmd = {} 2201*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'setAudioRestriction' 2202*b7c941bbSAndroid Build Coastguard Worker cmd['mode'] = mode 2203*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 2204*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 2205*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'audioRestrictionSet': 2206*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid response for command: %s' % 2207*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR]) 2208*b7c941bbSAndroid Build Coastguard Worker 2209*b7c941bbSAndroid Build Coastguard Worker # pylint: disable=dangerous-default-value 2210*b7c941bbSAndroid Build Coastguard Worker def do_3a(self, 2211*b7c941bbSAndroid Build Coastguard Worker regions_ae=[[0, 0, 1, 1, 1]], 2212*b7c941bbSAndroid Build Coastguard Worker regions_awb=[[0, 0, 1, 1, 1]], 2213*b7c941bbSAndroid Build Coastguard Worker regions_af=[[0, 0, 1, 1, 1]], 2214*b7c941bbSAndroid Build Coastguard Worker do_awb=True, 2215*b7c941bbSAndroid Build Coastguard Worker do_af=True, 2216*b7c941bbSAndroid Build Coastguard Worker lock_ae=False, 2217*b7c941bbSAndroid Build Coastguard Worker lock_awb=False, 2218*b7c941bbSAndroid Build Coastguard Worker get_results=False, 2219*b7c941bbSAndroid Build Coastguard Worker ev_comp=0, 2220*b7c941bbSAndroid Build Coastguard Worker auto_flash=False, 2221*b7c941bbSAndroid Build Coastguard Worker mono_camera=False, 2222*b7c941bbSAndroid Build Coastguard Worker zoom_ratio=None, 2223*b7c941bbSAndroid Build Coastguard Worker out_surfaces=None, 2224*b7c941bbSAndroid Build Coastguard Worker repeat_request=None, 2225*b7c941bbSAndroid Build Coastguard Worker first_surface_for_3a=False, 2226*b7c941bbSAndroid Build Coastguard Worker flash_mode=_FLASH_MODE_OFF): 2227*b7c941bbSAndroid Build Coastguard Worker """Perform a 3A operation on the device. 2228*b7c941bbSAndroid Build Coastguard Worker 2229*b7c941bbSAndroid Build Coastguard Worker Triggers some or all of AE, AWB, and AF, and returns once they have 2230*b7c941bbSAndroid Build Coastguard Worker converged. Uses the vendor 3A that is implemented inside the HAL. 2231*b7c941bbSAndroid Build Coastguard Worker Note: do_awb is always enabled regardless of do_awb flag 2232*b7c941bbSAndroid Build Coastguard Worker 2233*b7c941bbSAndroid Build Coastguard Worker Throws an assertion if 3A fails to converge. 2234*b7c941bbSAndroid Build Coastguard Worker 2235*b7c941bbSAndroid Build Coastguard Worker Args: 2236*b7c941bbSAndroid Build Coastguard Worker regions_ae: List of weighted AE regions. 2237*b7c941bbSAndroid Build Coastguard Worker regions_awb: List of weighted AWB regions. 2238*b7c941bbSAndroid Build Coastguard Worker regions_af: List of weighted AF regions. 2239*b7c941bbSAndroid Build Coastguard Worker do_awb: Wait for AWB to converge. 2240*b7c941bbSAndroid Build Coastguard Worker do_af: Trigger AF and wait for it to converge. 2241*b7c941bbSAndroid Build Coastguard Worker lock_ae: Request AE lock after convergence, and wait for it. 2242*b7c941bbSAndroid Build Coastguard Worker lock_awb: Request AWB lock after convergence, and wait for it. 2243*b7c941bbSAndroid Build Coastguard Worker get_results: Return the 3A results from this function. 2244*b7c941bbSAndroid Build Coastguard Worker ev_comp: An EV compensation value to use when running AE. 2245*b7c941bbSAndroid Build Coastguard Worker auto_flash: AE control boolean to enable auto flash. 2246*b7c941bbSAndroid Build Coastguard Worker mono_camera: Boolean for monochrome camera. 2247*b7c941bbSAndroid Build Coastguard Worker zoom_ratio: Zoom ratio. None if default zoom 2248*b7c941bbSAndroid Build Coastguard Worker out_surfaces: dict; see do_capture() for specifications on out_surfaces. 2249*b7c941bbSAndroid Build Coastguard Worker CameraCaptureSession will only be reused if out_surfaces is specified. 2250*b7c941bbSAndroid Build Coastguard Worker repeat_request: repeating request list. 2251*b7c941bbSAndroid Build Coastguard Worker See do_capture() for specifications on repeat_request. 2252*b7c941bbSAndroid Build Coastguard Worker first_surface_for_3a: Use first surface in output_surfaces for 3A. 2253*b7c941bbSAndroid Build Coastguard Worker Only applicable if out_surfaces contains at least 1 surface. 2254*b7c941bbSAndroid Build Coastguard Worker flash_mode: FLASH_MODE to be used during 3A 2255*b7c941bbSAndroid Build Coastguard Worker 0: OFF 2256*b7c941bbSAndroid Build Coastguard Worker 1: SINGLE 2257*b7c941bbSAndroid Build Coastguard Worker 2: TORCH 2258*b7c941bbSAndroid Build Coastguard Worker 2259*b7c941bbSAndroid Build Coastguard Worker Region format in args: 2260*b7c941bbSAndroid Build Coastguard Worker Arguments are lists of weighted regions; each weighted region is a 2261*b7c941bbSAndroid Build Coastguard Worker list of 5 values, [x, y, w, h, wgt], and each argument is a list of 2262*b7c941bbSAndroid Build Coastguard Worker these 5-value lists. The coordinates are given as normalized 2263*b7c941bbSAndroid Build Coastguard Worker rectangles (x, y, w, h) specifying the region. For example: 2264*b7c941bbSAndroid Build Coastguard Worker [[0.0, 0.0, 1.0, 0.5, 5], [0.0, 0.5, 1.0, 0.5, 10]]. 2265*b7c941bbSAndroid Build Coastguard Worker Weights are non-negative integers. 2266*b7c941bbSAndroid Build Coastguard Worker 2267*b7c941bbSAndroid Build Coastguard Worker Returns: 2268*b7c941bbSAndroid Build Coastguard Worker Five values are returned if get_results is true: 2269*b7c941bbSAndroid Build Coastguard Worker * AE sensitivity; 2270*b7c941bbSAndroid Build Coastguard Worker * AE exposure time; 2271*b7c941bbSAndroid Build Coastguard Worker * AWB gains (list); 2272*b7c941bbSAndroid Build Coastguard Worker * AWB transform (list); 2273*b7c941bbSAndroid Build Coastguard Worker * AF focus position; None if do_af is false 2274*b7c941bbSAndroid Build Coastguard Worker Otherwise, it returns five None values. 2275*b7c941bbSAndroid Build Coastguard Worker """ 2276*b7c941bbSAndroid Build Coastguard Worker logging.debug('Running vendor 3A on device') 2277*b7c941bbSAndroid Build Coastguard Worker cmd = {} 2278*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'do3A' 2279*b7c941bbSAndroid Build Coastguard Worker reuse_session = False 2280*b7c941bbSAndroid Build Coastguard Worker if out_surfaces: 2281*b7c941bbSAndroid Build Coastguard Worker reuse_session = True 2282*b7c941bbSAndroid Build Coastguard Worker if isinstance(out_surfaces, list): 2283*b7c941bbSAndroid Build Coastguard Worker cmd['outputSurfaces'] = out_surfaces 2284*b7c941bbSAndroid Build Coastguard Worker else: 2285*b7c941bbSAndroid Build Coastguard Worker cmd['outputSurfaces'] = [out_surfaces] 2286*b7c941bbSAndroid Build Coastguard Worker if repeat_request is None: 2287*b7c941bbSAndroid Build Coastguard Worker cmd['repeatRequests'] = [] 2288*b7c941bbSAndroid Build Coastguard Worker elif not isinstance(repeat_request, list): 2289*b7c941bbSAndroid Build Coastguard Worker cmd['repeatRequests'] = [repeat_request] 2290*b7c941bbSAndroid Build Coastguard Worker else: 2291*b7c941bbSAndroid Build Coastguard Worker cmd['repeatRequests'] = repeat_request 2292*b7c941bbSAndroid Build Coastguard Worker 2293*b7c941bbSAndroid Build Coastguard Worker cmd['regions'] = { 2294*b7c941bbSAndroid Build Coastguard Worker 'ae': sum(regions_ae, []), 2295*b7c941bbSAndroid Build Coastguard Worker 'awb': sum(regions_awb, []), 2296*b7c941bbSAndroid Build Coastguard Worker 'af': sum(regions_af, []) 2297*b7c941bbSAndroid Build Coastguard Worker } 2298*b7c941bbSAndroid Build Coastguard Worker do_ae = True # Always run AE 2299*b7c941bbSAndroid Build Coastguard Worker cmd['triggers'] = {'ae': do_ae, 'af': do_af} 2300*b7c941bbSAndroid Build Coastguard Worker if lock_ae: 2301*b7c941bbSAndroid Build Coastguard Worker cmd['aeLock'] = True 2302*b7c941bbSAndroid Build Coastguard Worker if lock_awb: 2303*b7c941bbSAndroid Build Coastguard Worker cmd['awbLock'] = True 2304*b7c941bbSAndroid Build Coastguard Worker if ev_comp != 0: 2305*b7c941bbSAndroid Build Coastguard Worker cmd['evComp'] = ev_comp 2306*b7c941bbSAndroid Build Coastguard Worker if flash_mode != 0: 2307*b7c941bbSAndroid Build Coastguard Worker cmd['flashMode'] = flash_mode 2308*b7c941bbSAndroid Build Coastguard Worker if auto_flash: 2309*b7c941bbSAndroid Build Coastguard Worker cmd['autoFlash'] = True 2310*b7c941bbSAndroid Build Coastguard Worker if self._hidden_physical_id: 2311*b7c941bbSAndroid Build Coastguard Worker cmd['physicalId'] = self._hidden_physical_id 2312*b7c941bbSAndroid Build Coastguard Worker if zoom_ratio: 2313*b7c941bbSAndroid Build Coastguard Worker if self.zoom_ratio_within_range(zoom_ratio): 2314*b7c941bbSAndroid Build Coastguard Worker cmd['zoomRatio'] = zoom_ratio 2315*b7c941bbSAndroid Build Coastguard Worker else: 2316*b7c941bbSAndroid Build Coastguard Worker raise AssertionError(f'Zoom ratio {zoom_ratio} out of range') 2317*b7c941bbSAndroid Build Coastguard Worker cmd['reuseSession'] = reuse_session 2318*b7c941bbSAndroid Build Coastguard Worker cmd['firstSurfaceFor3A'] = first_surface_for_3a 2319*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 2320*b7c941bbSAndroid Build Coastguard Worker 2321*b7c941bbSAndroid Build Coastguard Worker # Wait for each specified 3A to converge. 2322*b7c941bbSAndroid Build Coastguard Worker ae_sens = None 2323*b7c941bbSAndroid Build Coastguard Worker ae_exp = None 2324*b7c941bbSAndroid Build Coastguard Worker awb_gains = None 2325*b7c941bbSAndroid Build Coastguard Worker awb_transform = None 2326*b7c941bbSAndroid Build Coastguard Worker af_dist = None 2327*b7c941bbSAndroid Build Coastguard Worker converged = False 2328*b7c941bbSAndroid Build Coastguard Worker while True: 2329*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 2330*b7c941bbSAndroid Build Coastguard Worker vals = data[_STR_VALUE_STR].split() 2331*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] == 'aeResult': 2332*b7c941bbSAndroid Build Coastguard Worker if do_ae: 2333*b7c941bbSAndroid Build Coastguard Worker ae_sens, ae_exp = [int(i) for i in vals] 2334*b7c941bbSAndroid Build Coastguard Worker elif data[_TAG_STR] == 'afResult': 2335*b7c941bbSAndroid Build Coastguard Worker if do_af: 2336*b7c941bbSAndroid Build Coastguard Worker af_dist = float(vals[0]) 2337*b7c941bbSAndroid Build Coastguard Worker elif data[_TAG_STR] == 'awbResult': 2338*b7c941bbSAndroid Build Coastguard Worker awb_gains = [float(f) for f in vals[:4]] 2339*b7c941bbSAndroid Build Coastguard Worker awb_transform = [float(f) for f in vals[4:]] 2340*b7c941bbSAndroid Build Coastguard Worker elif data[_TAG_STR] == '3aConverged': 2341*b7c941bbSAndroid Build Coastguard Worker converged = True 2342*b7c941bbSAndroid Build Coastguard Worker elif data[_TAG_STR] == '3aDone': 2343*b7c941bbSAndroid Build Coastguard Worker break 2344*b7c941bbSAndroid Build Coastguard Worker else: 2345*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 2346*b7c941bbSAndroid Build Coastguard Worker if converged and not get_results: 2347*b7c941bbSAndroid Build Coastguard Worker return None, None, None, None, None 2348*b7c941bbSAndroid Build Coastguard Worker if (do_ae and ae_sens is None or 2349*b7c941bbSAndroid Build Coastguard Worker (not mono_camera and do_awb and awb_gains is None) or 2350*b7c941bbSAndroid Build Coastguard Worker do_af and af_dist is None or not converged): 2351*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('3A failed to converge') 2352*b7c941bbSAndroid Build Coastguard Worker return ae_sens, ae_exp, awb_gains, awb_transform, af_dist 2353*b7c941bbSAndroid Build Coastguard Worker 2354*b7c941bbSAndroid Build Coastguard Worker def calc_camera_fov(self, props): 2355*b7c941bbSAndroid Build Coastguard Worker """Determine the camera field of view from internal params. 2356*b7c941bbSAndroid Build Coastguard Worker 2357*b7c941bbSAndroid Build Coastguard Worker Args: 2358*b7c941bbSAndroid Build Coastguard Worker props: Camera properties object. 2359*b7c941bbSAndroid Build Coastguard Worker 2360*b7c941bbSAndroid Build Coastguard Worker Returns: 2361*b7c941bbSAndroid Build Coastguard Worker camera_fov: string; field of view for camera. 2362*b7c941bbSAndroid Build Coastguard Worker """ 2363*b7c941bbSAndroid Build Coastguard Worker 2364*b7c941bbSAndroid Build Coastguard Worker focal_ls = props['android.lens.info.availableFocalLengths'] 2365*b7c941bbSAndroid Build Coastguard Worker if len(focal_ls) > 1: 2366*b7c941bbSAndroid Build Coastguard Worker logging.debug('Doing capture to determine logical camera focal length') 2367*b7c941bbSAndroid Build Coastguard Worker cap = self.do_capture(capture_request_utils.auto_capture_request()) 2368*b7c941bbSAndroid Build Coastguard Worker focal_l = cap['metadata']['android.lens.focalLength'] 2369*b7c941bbSAndroid Build Coastguard Worker else: 2370*b7c941bbSAndroid Build Coastguard Worker focal_l = focal_ls[0] 2371*b7c941bbSAndroid Build Coastguard Worker 2372*b7c941bbSAndroid Build Coastguard Worker sensor_size = props['android.sensor.info.physicalSize'] 2373*b7c941bbSAndroid Build Coastguard Worker diag = math.sqrt(sensor_size['height']**2 + sensor_size['width']**2) 2374*b7c941bbSAndroid Build Coastguard Worker try: 2375*b7c941bbSAndroid Build Coastguard Worker fov = str(round(2 * math.degrees(math.atan(diag / (2 * focal_l))), 2)) 2376*b7c941bbSAndroid Build Coastguard Worker except ValueError: 2377*b7c941bbSAndroid Build Coastguard Worker fov = str(0) 2378*b7c941bbSAndroid Build Coastguard Worker logging.debug('Calculated FoV: %s', fov) 2379*b7c941bbSAndroid Build Coastguard Worker return fov 2380*b7c941bbSAndroid Build Coastguard Worker 2381*b7c941bbSAndroid Build Coastguard Worker def get_file_name_to_load(self, chart_distance, camera_fov, scene): 2382*b7c941bbSAndroid Build Coastguard Worker """Get the image to load on the tablet depending on fov and chart_distance. 2383*b7c941bbSAndroid Build Coastguard Worker 2384*b7c941bbSAndroid Build Coastguard Worker Args: 2385*b7c941bbSAndroid Build Coastguard Worker chart_distance: float; distance in cm from camera of displayed chart 2386*b7c941bbSAndroid Build Coastguard Worker camera_fov: float; camera field of view. 2387*b7c941bbSAndroid Build Coastguard Worker scene: String; Scene to be used in the test. 2388*b7c941bbSAndroid Build Coastguard Worker 2389*b7c941bbSAndroid Build Coastguard Worker Returns: 2390*b7c941bbSAndroid Build Coastguard Worker file_name: file name to display on the tablet. 2391*b7c941bbSAndroid Build Coastguard Worker 2392*b7c941bbSAndroid Build Coastguard Worker """ 2393*b7c941bbSAndroid Build Coastguard Worker chart_scaling = opencv_processing_utils.calc_chart_scaling( 2394*b7c941bbSAndroid Build Coastguard Worker chart_distance, camera_fov) 2395*b7c941bbSAndroid Build Coastguard Worker if math.isclose( 2396*b7c941bbSAndroid Build Coastguard Worker chart_scaling, 2397*b7c941bbSAndroid Build Coastguard Worker opencv_processing_utils.SCALE_WIDE_IN_22CM_RIG, 2398*b7c941bbSAndroid Build Coastguard Worker abs_tol=SCALING_TO_FILE_ATOL): 2399*b7c941bbSAndroid Build Coastguard Worker file_name = f'{scene}_{opencv_processing_utils.SCALE_WIDE_IN_22CM_RIG}x_scaled.png' 2400*b7c941bbSAndroid Build Coastguard Worker elif math.isclose( 2401*b7c941bbSAndroid Build Coastguard Worker chart_scaling, 2402*b7c941bbSAndroid Build Coastguard Worker opencv_processing_utils.SCALE_TELE_IN_22CM_RIG, 2403*b7c941bbSAndroid Build Coastguard Worker abs_tol=SCALING_TO_FILE_ATOL): 2404*b7c941bbSAndroid Build Coastguard Worker file_name = f'{scene}_{opencv_processing_utils.SCALE_TELE_IN_22CM_RIG}x_scaled.png' 2405*b7c941bbSAndroid Build Coastguard Worker elif math.isclose( 2406*b7c941bbSAndroid Build Coastguard Worker chart_scaling, 2407*b7c941bbSAndroid Build Coastguard Worker opencv_processing_utils.SCALE_TELE25_IN_31CM_RIG, 2408*b7c941bbSAndroid Build Coastguard Worker abs_tol=SCALING_TO_FILE_ATOL): 2409*b7c941bbSAndroid Build Coastguard Worker file_name = f'{scene}_{opencv_processing_utils.SCALE_TELE25_IN_31CM_RIG}x_scaled.png' 2410*b7c941bbSAndroid Build Coastguard Worker elif math.isclose( 2411*b7c941bbSAndroid Build Coastguard Worker chart_scaling, 2412*b7c941bbSAndroid Build Coastguard Worker opencv_processing_utils.SCALE_TELE40_IN_31CM_RIG, 2413*b7c941bbSAndroid Build Coastguard Worker abs_tol=SCALING_TO_FILE_ATOL): 2414*b7c941bbSAndroid Build Coastguard Worker file_name = f'{scene}_{opencv_processing_utils.SCALE_TELE40_IN_31CM_RIG}x_scaled.png' 2415*b7c941bbSAndroid Build Coastguard Worker elif math.isclose( 2416*b7c941bbSAndroid Build Coastguard Worker chart_scaling, 2417*b7c941bbSAndroid Build Coastguard Worker opencv_processing_utils.SCALE_TELE_IN_31CM_RIG, 2418*b7c941bbSAndroid Build Coastguard Worker abs_tol=SCALING_TO_FILE_ATOL): 2419*b7c941bbSAndroid Build Coastguard Worker file_name = f'{scene}_{opencv_processing_utils.SCALE_TELE_IN_31CM_RIG}x_scaled.png' 2420*b7c941bbSAndroid Build Coastguard Worker else: 2421*b7c941bbSAndroid Build Coastguard Worker file_name = f'{scene}.png' 2422*b7c941bbSAndroid Build Coastguard Worker logging.debug('Scene to load: %s', file_name) 2423*b7c941bbSAndroid Build Coastguard Worker return file_name 2424*b7c941bbSAndroid Build Coastguard Worker 2425*b7c941bbSAndroid Build Coastguard Worker def is_stream_combination_supported(self, out_surfaces, settings=None): 2426*b7c941bbSAndroid Build Coastguard Worker """Query whether out_surfaces combination and settings are supported by the camera device. 2427*b7c941bbSAndroid Build Coastguard Worker 2428*b7c941bbSAndroid Build Coastguard Worker This function hooks up to the isSessionConfigurationSupported()/ 2429*b7c941bbSAndroid Build Coastguard Worker isSessionConfigurationWithSettingsSupported() camera API 2430*b7c941bbSAndroid Build Coastguard Worker to query whether a particular stream combination and settings are supported. 2431*b7c941bbSAndroid Build Coastguard Worker 2432*b7c941bbSAndroid Build Coastguard Worker Args: 2433*b7c941bbSAndroid Build Coastguard Worker out_surfaces: dict; see do_capture() for specifications on out_surfaces. 2434*b7c941bbSAndroid Build Coastguard Worker settings: dict; optional capture request settings metadata. 2435*b7c941bbSAndroid Build Coastguard Worker 2436*b7c941bbSAndroid Build Coastguard Worker Returns: 2437*b7c941bbSAndroid Build Coastguard Worker Boolean 2438*b7c941bbSAndroid Build Coastguard Worker """ 2439*b7c941bbSAndroid Build Coastguard Worker cmd = {} 2440*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'isStreamCombinationSupported' 2441*b7c941bbSAndroid Build Coastguard Worker cmd[_CAMERA_ID_STR] = self._camera_id 2442*b7c941bbSAndroid Build Coastguard Worker 2443*b7c941bbSAndroid Build Coastguard Worker if isinstance(out_surfaces, list): 2444*b7c941bbSAndroid Build Coastguard Worker cmd['outputSurfaces'] = out_surfaces 2445*b7c941bbSAndroid Build Coastguard Worker for out_surface in out_surfaces: 2446*b7c941bbSAndroid Build Coastguard Worker if self._hidden_physical_id: 2447*b7c941bbSAndroid Build Coastguard Worker out_surface['physicalCamera'] = self._hidden_physical_id 2448*b7c941bbSAndroid Build Coastguard Worker else: 2449*b7c941bbSAndroid Build Coastguard Worker cmd['outputSurfaces'] = [out_surfaces] 2450*b7c941bbSAndroid Build Coastguard Worker if self._hidden_physical_id: 2451*b7c941bbSAndroid Build Coastguard Worker out_surfaces['physicalCamera'] = self._hidden_physical_id 2452*b7c941bbSAndroid Build Coastguard Worker 2453*b7c941bbSAndroid Build Coastguard Worker if settings: 2454*b7c941bbSAndroid Build Coastguard Worker cmd['settings'] = settings 2455*b7c941bbSAndroid Build Coastguard Worker 2456*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 2457*b7c941bbSAndroid Build Coastguard Worker 2458*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 2459*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'streamCombinationSupport': 2460*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Failed to query stream combination') 2461*b7c941bbSAndroid Build Coastguard Worker 2462*b7c941bbSAndroid Build Coastguard Worker return data[_STR_VALUE_STR] == 'supportedCombination' 2463*b7c941bbSAndroid Build Coastguard Worker 2464*b7c941bbSAndroid Build Coastguard Worker def is_camera_privacy_mode_supported(self): 2465*b7c941bbSAndroid Build Coastguard Worker """Query whether the mobile device supports camera privacy mode. 2466*b7c941bbSAndroid Build Coastguard Worker 2467*b7c941bbSAndroid Build Coastguard Worker This function checks whether the mobile device has FEATURE_CAMERA_TOGGLE 2468*b7c941bbSAndroid Build Coastguard Worker feature support, which indicates the camera device can run in privacy mode. 2469*b7c941bbSAndroid Build Coastguard Worker 2470*b7c941bbSAndroid Build Coastguard Worker Returns: 2471*b7c941bbSAndroid Build Coastguard Worker Boolean 2472*b7c941bbSAndroid Build Coastguard Worker """ 2473*b7c941bbSAndroid Build Coastguard Worker cmd = {} 2474*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'isCameraPrivacyModeSupported' 2475*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 2476*b7c941bbSAndroid Build Coastguard Worker 2477*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 2478*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'cameraPrivacyModeSupport': 2479*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Failed to query camera privacy mode' 2480*b7c941bbSAndroid Build Coastguard Worker ' support') 2481*b7c941bbSAndroid Build Coastguard Worker return data[_STR_VALUE_STR] == 'true' 2482*b7c941bbSAndroid Build Coastguard Worker 2483*b7c941bbSAndroid Build Coastguard Worker def is_primary_camera(self): 2484*b7c941bbSAndroid Build Coastguard Worker """Query whether the camera device is a primary rear/front camera. 2485*b7c941bbSAndroid Build Coastguard Worker 2486*b7c941bbSAndroid Build Coastguard Worker A primary rear/front facing camera is a camera device with the lowest 2487*b7c941bbSAndroid Build Coastguard Worker camera Id for that facing. 2488*b7c941bbSAndroid Build Coastguard Worker 2489*b7c941bbSAndroid Build Coastguard Worker Returns: 2490*b7c941bbSAndroid Build Coastguard Worker Boolean 2491*b7c941bbSAndroid Build Coastguard Worker """ 2492*b7c941bbSAndroid Build Coastguard Worker cmd = {} 2493*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'isPrimaryCamera' 2494*b7c941bbSAndroid Build Coastguard Worker cmd[_CAMERA_ID_STR] = self._camera_id 2495*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 2496*b7c941bbSAndroid Build Coastguard Worker 2497*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 2498*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'primaryCamera': 2499*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Failed to query primary camera') 2500*b7c941bbSAndroid Build Coastguard Worker return data[_STR_VALUE_STR] == 'true' 2501*b7c941bbSAndroid Build Coastguard Worker 2502*b7c941bbSAndroid Build Coastguard Worker def is_performance_class(self): 2503*b7c941bbSAndroid Build Coastguard Worker """Query whether the mobile device is an R or S performance class device. 2504*b7c941bbSAndroid Build Coastguard Worker 2505*b7c941bbSAndroid Build Coastguard Worker Returns: 2506*b7c941bbSAndroid Build Coastguard Worker Boolean 2507*b7c941bbSAndroid Build Coastguard Worker """ 2508*b7c941bbSAndroid Build Coastguard Worker cmd = {} 2509*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'isPerformanceClass' 2510*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 2511*b7c941bbSAndroid Build Coastguard Worker 2512*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 2513*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'performanceClass': 2514*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Failed to query performance class') 2515*b7c941bbSAndroid Build Coastguard Worker return data[_STR_VALUE_STR] == 'true' 2516*b7c941bbSAndroid Build Coastguard Worker 2517*b7c941bbSAndroid Build Coastguard Worker def is_vic_performance_class(self): 2518*b7c941bbSAndroid Build Coastguard Worker """Return whether the mobile device is VIC performance class device. 2519*b7c941bbSAndroid Build Coastguard Worker """ 2520*b7c941bbSAndroid Build Coastguard Worker cmd = {} 2521*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'isVicPerformanceClass' 2522*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 2523*b7c941bbSAndroid Build Coastguard Worker 2524*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 2525*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'vicPerformanceClass': 2526*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Failed to query performance class') 2527*b7c941bbSAndroid Build Coastguard Worker return data[_STR_VALUE_STR] == 'true' 2528*b7c941bbSAndroid Build Coastguard Worker 2529*b7c941bbSAndroid Build Coastguard Worker def measure_camera_launch_ms(self): 2530*b7c941bbSAndroid Build Coastguard Worker """Measure camera launch latency in millisecond, from open to first frame. 2531*b7c941bbSAndroid Build Coastguard Worker 2532*b7c941bbSAndroid Build Coastguard Worker Returns: 2533*b7c941bbSAndroid Build Coastguard Worker Camera launch latency from camera open to receipt of first frame 2534*b7c941bbSAndroid Build Coastguard Worker """ 2535*b7c941bbSAndroid Build Coastguard Worker cmd = {} 2536*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'measureCameraLaunchMs' 2537*b7c941bbSAndroid Build Coastguard Worker cmd[_CAMERA_ID_STR] = self._camera_id 2538*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 2539*b7c941bbSAndroid Build Coastguard Worker 2540*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT_FOR_PERF_MEASURE 2541*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 2542*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 2543*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(self.SOCK_TIMEOUT) 2544*b7c941bbSAndroid Build Coastguard Worker 2545*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'cameraLaunchMs': 2546*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Failed to measure camera launch latency') 2547*b7c941bbSAndroid Build Coastguard Worker return float(data[_STR_VALUE_STR]) 2548*b7c941bbSAndroid Build Coastguard Worker 2549*b7c941bbSAndroid Build Coastguard Worker def measure_camera_1080p_jpeg_capture_ms(self): 2550*b7c941bbSAndroid Build Coastguard Worker """Measure camera 1080P jpeg capture latency in milliseconds. 2551*b7c941bbSAndroid Build Coastguard Worker 2552*b7c941bbSAndroid Build Coastguard Worker Returns: 2553*b7c941bbSAndroid Build Coastguard Worker Camera jpeg capture latency in milliseconds 2554*b7c941bbSAndroid Build Coastguard Worker """ 2555*b7c941bbSAndroid Build Coastguard Worker cmd = {} 2556*b7c941bbSAndroid Build Coastguard Worker cmd[_CMD_NAME_STR] = 'measureCamera1080pJpegCaptureMs' 2557*b7c941bbSAndroid Build Coastguard Worker cmd[_CAMERA_ID_STR] = self._camera_id 2558*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 2559*b7c941bbSAndroid Build Coastguard Worker 2560*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT_FOR_PERF_MEASURE 2561*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 2562*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 2563*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(self.SOCK_TIMEOUT) 2564*b7c941bbSAndroid Build Coastguard Worker 2565*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'camera1080pJpegCaptureMs': 2566*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError( 2567*b7c941bbSAndroid Build Coastguard Worker 'Failed to measure camera 1080p jpeg capture latency') 2568*b7c941bbSAndroid Build Coastguard Worker return float(data[_STR_VALUE_STR]) 2569*b7c941bbSAndroid Build Coastguard Worker 2570*b7c941bbSAndroid Build Coastguard Worker def _camera_id_to_props(self): 2571*b7c941bbSAndroid Build Coastguard Worker """Return the properties of each camera ID.""" 2572*b7c941bbSAndroid Build Coastguard Worker unparsed_ids = self.get_camera_ids().get('cameraIdArray', []) 2573*b7c941bbSAndroid Build Coastguard Worker parsed_ids = parse_camera_ids(unparsed_ids) 2574*b7c941bbSAndroid Build Coastguard Worker id_to_props = {} 2575*b7c941bbSAndroid Build Coastguard Worker for unparsed_id, id_combo in zip(unparsed_ids, parsed_ids): 2576*b7c941bbSAndroid Build Coastguard Worker if id_combo.sub_id is None: 2577*b7c941bbSAndroid Build Coastguard Worker props = self.get_camera_properties_by_id(id_combo.id) 2578*b7c941bbSAndroid Build Coastguard Worker else: 2579*b7c941bbSAndroid Build Coastguard Worker props = self.get_camera_properties_by_id(id_combo.sub_id) 2580*b7c941bbSAndroid Build Coastguard Worker id_to_props[unparsed_id] = props 2581*b7c941bbSAndroid Build Coastguard Worker if not id_to_props: 2582*b7c941bbSAndroid Build Coastguard Worker raise AssertionError('No camera IDs were found.') 2583*b7c941bbSAndroid Build Coastguard Worker return id_to_props 2584*b7c941bbSAndroid Build Coastguard Worker 2585*b7c941bbSAndroid Build Coastguard Worker def has_ultrawide_camera(self, facing): 2586*b7c941bbSAndroid Build Coastguard Worker """Return if device has an ultrawide camera facing the same direction. 2587*b7c941bbSAndroid Build Coastguard Worker 2588*b7c941bbSAndroid Build Coastguard Worker Args: 2589*b7c941bbSAndroid Build Coastguard Worker facing: constant describing the direction the camera device lens faces. 2590*b7c941bbSAndroid Build Coastguard Worker 2591*b7c941bbSAndroid Build Coastguard Worker Returns: 2592*b7c941bbSAndroid Build Coastguard Worker True if the device has an ultrawide camera facing in that direction. 2593*b7c941bbSAndroid Build Coastguard Worker """ 2594*b7c941bbSAndroid Build Coastguard Worker camera_ids = self.get_camera_ids() 2595*b7c941bbSAndroid Build Coastguard Worker primary_rear_camera_id = camera_ids.get('primaryRearCameraId', '') 2596*b7c941bbSAndroid Build Coastguard Worker primary_front_camera_id = camera_ids.get('primaryFrontCameraId', '') 2597*b7c941bbSAndroid Build Coastguard Worker if facing == camera_properties_utils.LENS_FACING['BACK']: 2598*b7c941bbSAndroid Build Coastguard Worker primary_camera_id = primary_rear_camera_id 2599*b7c941bbSAndroid Build Coastguard Worker elif facing == camera_properties_utils.LENS_FACING['FRONT']: 2600*b7c941bbSAndroid Build Coastguard Worker primary_camera_id = primary_front_camera_id 2601*b7c941bbSAndroid Build Coastguard Worker else: 2602*b7c941bbSAndroid Build Coastguard Worker raise NotImplementedError('Cameras not facing either front or back ' 2603*b7c941bbSAndroid Build Coastguard Worker 'are currently unsupported.') 2604*b7c941bbSAndroid Build Coastguard Worker id_to_props = self._camera_id_to_props() 2605*b7c941bbSAndroid Build Coastguard Worker fov_and_facing = collections.namedtuple('FovAndFacing', ['fov', 'facing']) 2606*b7c941bbSAndroid Build Coastguard Worker id_to_fov_facing = { 2607*b7c941bbSAndroid Build Coastguard Worker unparsed_id: fov_and_facing( 2608*b7c941bbSAndroid Build Coastguard Worker self.calc_camera_fov(props), props['android.lens.facing'] 2609*b7c941bbSAndroid Build Coastguard Worker ) 2610*b7c941bbSAndroid Build Coastguard Worker for unparsed_id, props in id_to_props.items() 2611*b7c941bbSAndroid Build Coastguard Worker } 2612*b7c941bbSAndroid Build Coastguard Worker logging.debug('IDs to (FOVs, facing): %s', id_to_fov_facing) 2613*b7c941bbSAndroid Build Coastguard Worker primary_camera_fov, primary_camera_facing = id_to_fov_facing[ 2614*b7c941bbSAndroid Build Coastguard Worker primary_camera_id] 2615*b7c941bbSAndroid Build Coastguard Worker for unparsed_id, fov_facing_combo in id_to_fov_facing.items(): 2616*b7c941bbSAndroid Build Coastguard Worker if (float(fov_facing_combo.fov) > float(primary_camera_fov) and 2617*b7c941bbSAndroid Build Coastguard Worker fov_facing_combo.facing == primary_camera_facing and 2618*b7c941bbSAndroid Build Coastguard Worker unparsed_id != primary_camera_id): 2619*b7c941bbSAndroid Build Coastguard Worker logging.debug('Ultrawide camera found with ID %s and FoV %.3f. ' 2620*b7c941bbSAndroid Build Coastguard Worker 'Primary camera has ID %s and FoV: %.3f.', 2621*b7c941bbSAndroid Build Coastguard Worker unparsed_id, float(fov_facing_combo.fov), 2622*b7c941bbSAndroid Build Coastguard Worker primary_camera_id, float(primary_camera_fov)) 2623*b7c941bbSAndroid Build Coastguard Worker return True 2624*b7c941bbSAndroid Build Coastguard Worker return False 2625*b7c941bbSAndroid Build Coastguard Worker 2626*b7c941bbSAndroid Build Coastguard Worker def get_facing_to_ids(self): 2627*b7c941bbSAndroid Build Coastguard Worker """Returns mapping from lens facing to list of corresponding camera IDs.""" 2628*b7c941bbSAndroid Build Coastguard Worker id_to_props = self._camera_id_to_props() 2629*b7c941bbSAndroid Build Coastguard Worker facing_to_ids = collections.defaultdict(list) 2630*b7c941bbSAndroid Build Coastguard Worker for unparsed_id, props in id_to_props.items(): 2631*b7c941bbSAndroid Build Coastguard Worker facing_to_ids[props['android.lens.facing']].append(unparsed_id) 2632*b7c941bbSAndroid Build Coastguard Worker for ids in facing_to_ids.values(): 2633*b7c941bbSAndroid Build Coastguard Worker ids.sort() 2634*b7c941bbSAndroid Build Coastguard Worker logging.debug('Facing to camera IDs: %s', facing_to_ids) 2635*b7c941bbSAndroid Build Coastguard Worker return facing_to_ids 2636*b7c941bbSAndroid Build Coastguard Worker 2637*b7c941bbSAndroid Build Coastguard Worker def is_low_light_boost_available(self, camera_id, extension=-1): 2638*b7c941bbSAndroid Build Coastguard Worker """Checks if low light boost is available for camera id and extension. 2639*b7c941bbSAndroid Build Coastguard Worker 2640*b7c941bbSAndroid Build Coastguard Worker If the extension is not provided (or -1) then low light boost support is 2641*b7c941bbSAndroid Build Coastguard Worker checked for a camera2 session. 2642*b7c941bbSAndroid Build Coastguard Worker 2643*b7c941bbSAndroid Build Coastguard Worker Args: 2644*b7c941bbSAndroid Build Coastguard Worker camera_id: int; device ID 2645*b7c941bbSAndroid Build Coastguard Worker extension: int; extension type 2646*b7c941bbSAndroid Build Coastguard Worker Returns: 2647*b7c941bbSAndroid Build Coastguard Worker True if low light boost is available and false otherwise. 2648*b7c941bbSAndroid Build Coastguard Worker """ 2649*b7c941bbSAndroid Build Coastguard Worker cmd = { 2650*b7c941bbSAndroid Build Coastguard Worker 'cmdName': 'isLowLightBoostAvailable', 2651*b7c941bbSAndroid Build Coastguard Worker 'cameraId': camera_id, 2652*b7c941bbSAndroid Build Coastguard Worker 'extension': extension 2653*b7c941bbSAndroid Build Coastguard Worker } 2654*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 2655*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT 2656*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 2657*b7c941bbSAndroid Build Coastguard Worker data, _ = self.__read_response_from_socket() 2658*b7c941bbSAndroid Build Coastguard Worker if data['tag'] != 'isLowLightBoostAvailable': 2659*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 2660*b7c941bbSAndroid Build Coastguard Worker return data[_STR_VALUE_STR] == 'true' 2661*b7c941bbSAndroid Build Coastguard Worker 2662*b7c941bbSAndroid Build Coastguard Worker def do_capture_preview_frame(self, 2663*b7c941bbSAndroid Build Coastguard Worker camera_id, 2664*b7c941bbSAndroid Build Coastguard Worker preview_size, 2665*b7c941bbSAndroid Build Coastguard Worker frame_num=0, 2666*b7c941bbSAndroid Build Coastguard Worker extension=-1, 2667*b7c941bbSAndroid Build Coastguard Worker cap_request={}): 2668*b7c941bbSAndroid Build Coastguard Worker """Captures the nth preview frame from the preview stream. 2669*b7c941bbSAndroid Build Coastguard Worker 2670*b7c941bbSAndroid Build Coastguard Worker By default the 0th frame is the first frame. The extension type can also be 2671*b7c941bbSAndroid Build Coastguard Worker provided or -1 to use Camera2 which is the default. 2672*b7c941bbSAndroid Build Coastguard Worker 2673*b7c941bbSAndroid Build Coastguard Worker Args: 2674*b7c941bbSAndroid Build Coastguard Worker camera_id: int; device ID 2675*b7c941bbSAndroid Build Coastguard Worker preview_size: int; preview size 2676*b7c941bbSAndroid Build Coastguard Worker frame_num: int; frame number to capture 2677*b7c941bbSAndroid Build Coastguard Worker extension: int; extension type 2678*b7c941bbSAndroid Build Coastguard Worker cap_request: dict; python dict specifying the key/value pair of capture 2679*b7c941bbSAndroid Build Coastguard Worker request keys, which will be converted to JSON and sent to the device. 2680*b7c941bbSAndroid Build Coastguard Worker Returns: 2681*b7c941bbSAndroid Build Coastguard Worker Single JPEG frame capture as numpy array of bytes 2682*b7c941bbSAndroid Build Coastguard Worker """ 2683*b7c941bbSAndroid Build Coastguard Worker cmd = { 2684*b7c941bbSAndroid Build Coastguard Worker 'cmdName': 'doCapturePreviewFrame', 2685*b7c941bbSAndroid Build Coastguard Worker 'cameraId': camera_id, 2686*b7c941bbSAndroid Build Coastguard Worker 'previewSize': preview_size, 2687*b7c941bbSAndroid Build Coastguard Worker 'frameNum': frame_num, 2688*b7c941bbSAndroid Build Coastguard Worker 'extension': extension, 2689*b7c941bbSAndroid Build Coastguard Worker 'captureRequest': cap_request, 2690*b7c941bbSAndroid Build Coastguard Worker } 2691*b7c941bbSAndroid Build Coastguard Worker self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) 2692*b7c941bbSAndroid Build Coastguard Worker timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT 2693*b7c941bbSAndroid Build Coastguard Worker self.sock.settimeout(timeout) 2694*b7c941bbSAndroid Build Coastguard Worker data, buf = self.__read_response_from_socket() 2695*b7c941bbSAndroid Build Coastguard Worker if data[_TAG_STR] != 'jpegImage': 2696*b7c941bbSAndroid Build Coastguard Worker raise error_util.CameraItsError('Invalid command response') 2697*b7c941bbSAndroid Build Coastguard Worker return buf 2698*b7c941bbSAndroid Build Coastguard Worker 2699*b7c941bbSAndroid Build Coastguard Worker def preview_surface(self, size, hlg10_enabled=False): 2700*b7c941bbSAndroid Build Coastguard Worker """Create a surface dictionary based on size and hdr-ness. 2701*b7c941bbSAndroid Build Coastguard Worker 2702*b7c941bbSAndroid Build Coastguard Worker Args: 2703*b7c941bbSAndroid Build Coastguard Worker size: str, Resolution of an output surface. ex. "1920x1080" 2704*b7c941bbSAndroid Build Coastguard Worker hlg10_enabled: boolean; Whether the output is hlg10 or not. 2705*b7c941bbSAndroid Build Coastguard Worker 2706*b7c941bbSAndroid Build Coastguard Worker Returns: 2707*b7c941bbSAndroid Build Coastguard Worker a dictionary object containing format, size, and hdr-ness. 2708*b7c941bbSAndroid Build Coastguard Worker """ 2709*b7c941bbSAndroid Build Coastguard Worker surface = { 2710*b7c941bbSAndroid Build Coastguard Worker 'format': 'priv', 2711*b7c941bbSAndroid Build Coastguard Worker 'width': int(size.split('x')[0]), 2712*b7c941bbSAndroid Build Coastguard Worker 'height': int(size.split('x')[1]), 2713*b7c941bbSAndroid Build Coastguard Worker 'hlg10': hlg10_enabled 2714*b7c941bbSAndroid Build Coastguard Worker } 2715*b7c941bbSAndroid Build Coastguard Worker if self._hidden_physical_id: 2716*b7c941bbSAndroid Build Coastguard Worker surface['physicalCamera'] = self._hidden_physical_id 2717*b7c941bbSAndroid Build Coastguard Worker return [surface] 2718*b7c941bbSAndroid Build Coastguard Worker 2719*b7c941bbSAndroid Build Coastguard Worker 2720*b7c941bbSAndroid Build Coastguard Workerdef parse_camera_ids(ids): 2721*b7c941bbSAndroid Build Coastguard Worker """Parse the string of camera IDs into array of CameraIdCombo tuples. 2722*b7c941bbSAndroid Build Coastguard Worker 2723*b7c941bbSAndroid Build Coastguard Worker Args: 2724*b7c941bbSAndroid Build Coastguard Worker ids: List of camera ids. 2725*b7c941bbSAndroid Build Coastguard Worker 2726*b7c941bbSAndroid Build Coastguard Worker Returns: 2727*b7c941bbSAndroid Build Coastguard Worker Array of CameraIdCombo 2728*b7c941bbSAndroid Build Coastguard Worker """ 2729*b7c941bbSAndroid Build Coastguard Worker camera_id_combo = collections.namedtuple('CameraIdCombo', ['id', 'sub_id']) 2730*b7c941bbSAndroid Build Coastguard Worker id_combos = [] 2731*b7c941bbSAndroid Build Coastguard Worker for one_id in ids: 2732*b7c941bbSAndroid Build Coastguard Worker one_combo = one_id.split(SUB_CAMERA_SEPARATOR) 2733*b7c941bbSAndroid Build Coastguard Worker if len(one_combo) == 1: 2734*b7c941bbSAndroid Build Coastguard Worker id_combos.append(camera_id_combo(one_combo[0], None)) 2735*b7c941bbSAndroid Build Coastguard Worker elif len(one_combo) == 2: 2736*b7c941bbSAndroid Build Coastguard Worker id_combos.append(camera_id_combo(one_combo[0], one_combo[1])) 2737*b7c941bbSAndroid Build Coastguard Worker else: 2738*b7c941bbSAndroid Build Coastguard Worker raise AssertionError('Camera id parameters must be either ID or ' 2739*b7c941bbSAndroid Build Coastguard Worker f'ID{SUB_CAMERA_SEPARATOR}SUB_ID') 2740*b7c941bbSAndroid Build Coastguard Worker return id_combos 2741*b7c941bbSAndroid Build Coastguard Worker 2742*b7c941bbSAndroid Build Coastguard Worker 2743*b7c941bbSAndroid Build Coastguard Workerdef do_capture_with_latency(cam, req, sync_latency, fmt=None): 2744*b7c941bbSAndroid Build Coastguard Worker """Helper function to take enough frames to allow sync latency. 2745*b7c941bbSAndroid Build Coastguard Worker 2746*b7c941bbSAndroid Build Coastguard Worker Args: 2747*b7c941bbSAndroid Build Coastguard Worker cam: camera object 2748*b7c941bbSAndroid Build Coastguard Worker req: request for camera 2749*b7c941bbSAndroid Build Coastguard Worker sync_latency: integer number of frames 2750*b7c941bbSAndroid Build Coastguard Worker fmt: format for the capture 2751*b7c941bbSAndroid Build Coastguard Worker Returns: 2752*b7c941bbSAndroid Build Coastguard Worker single capture with the unsettled frames discarded 2753*b7c941bbSAndroid Build Coastguard Worker """ 2754*b7c941bbSAndroid Build Coastguard Worker caps = cam.do_capture([req]*(sync_latency+1), fmt) 2755*b7c941bbSAndroid Build Coastguard Worker return caps[-1] 2756*b7c941bbSAndroid Build Coastguard Worker 2757*b7c941bbSAndroid Build Coastguard Worker 2758*b7c941bbSAndroid Build Coastguard Workerdef load_scene(cam, props, scene, tablet, chart_distance, lighting_check=True, 2759*b7c941bbSAndroid Build Coastguard Worker log_path=None): 2760*b7c941bbSAndroid Build Coastguard Worker """Load the scene for the camera based on the FOV. 2761*b7c941bbSAndroid Build Coastguard Worker 2762*b7c941bbSAndroid Build Coastguard Worker Args: 2763*b7c941bbSAndroid Build Coastguard Worker cam: camera object 2764*b7c941bbSAndroid Build Coastguard Worker props: camera properties 2765*b7c941bbSAndroid Build Coastguard Worker scene: scene to be loaded 2766*b7c941bbSAndroid Build Coastguard Worker tablet: tablet to load scene on 2767*b7c941bbSAndroid Build Coastguard Worker chart_distance: distance to tablet 2768*b7c941bbSAndroid Build Coastguard Worker lighting_check: Boolean for lighting check enabled 2769*b7c941bbSAndroid Build Coastguard Worker log_path: [Optional] path to store artifacts 2770*b7c941bbSAndroid Build Coastguard Worker """ 2771*b7c941bbSAndroid Build Coastguard Worker if not tablet: 2772*b7c941bbSAndroid Build Coastguard Worker logging.info('Manual run: no tablet to load scene on.') 2773*b7c941bbSAndroid Build Coastguard Worker return 2774*b7c941bbSAndroid Build Coastguard Worker # Calculate camera_fov, which determines the image/video to load on tablet. 2775*b7c941bbSAndroid Build Coastguard Worker camera_fov = cam.calc_camera_fov(props) 2776*b7c941bbSAndroid Build Coastguard Worker file_name = cam.get_file_name_to_load(chart_distance, camera_fov, scene) 2777*b7c941bbSAndroid Build Coastguard Worker if 'scene' not in file_name: 2778*b7c941bbSAndroid Build Coastguard Worker file_name = f'scene{file_name}' 2779*b7c941bbSAndroid Build Coastguard Worker if scene in VIDEO_SCENES: 2780*b7c941bbSAndroid Build Coastguard Worker root_file_name, _ = os.path.splitext(file_name) 2781*b7c941bbSAndroid Build Coastguard Worker file_name = root_file_name + '.mp4' 2782*b7c941bbSAndroid Build Coastguard Worker logging.debug('Displaying %s on the tablet', file_name) 2783*b7c941bbSAndroid Build Coastguard Worker 2784*b7c941bbSAndroid Build Coastguard Worker # Display the image/video on the tablet using the default media player. 2785*b7c941bbSAndroid Build Coastguard Worker view_file_type = 'image/png' if scene not in VIDEO_SCENES else 'video/mp4' 2786*b7c941bbSAndroid Build Coastguard Worker uri_prefix = 'file://mnt' if scene not in VIDEO_SCENES else '' 2787*b7c941bbSAndroid Build Coastguard Worker tablet.adb.shell( 2788*b7c941bbSAndroid Build Coastguard Worker f'am start -a android.intent.action.VIEW -t {view_file_type} ' 2789*b7c941bbSAndroid Build Coastguard Worker f'-d {uri_prefix}/sdcard/Download/{file_name}') 2790*b7c941bbSAndroid Build Coastguard Worker time.sleep(LOAD_SCENE_DELAY_SEC) 2791*b7c941bbSAndroid Build Coastguard Worker # Tap tablet to remove gallery buttons 2792*b7c941bbSAndroid Build Coastguard Worker tablet.adb.shell( 2793*b7c941bbSAndroid Build Coastguard Worker f'input tap {TAP_COORDINATES[0]} {TAP_COORDINATES[1]}') 2794*b7c941bbSAndroid Build Coastguard Worker rfov_camera_in_rfov_box = ( 2795*b7c941bbSAndroid Build Coastguard Worker math.isclose( 2796*b7c941bbSAndroid Build Coastguard Worker chart_distance, 2797*b7c941bbSAndroid Build Coastguard Worker opencv_processing_utils.CHART_DISTANCE_31CM, rel_tol=0.1) and 2798*b7c941bbSAndroid Build Coastguard Worker opencv_processing_utils.FOV_THRESH_TELE <= float(camera_fov) 2799*b7c941bbSAndroid Build Coastguard Worker <= opencv_processing_utils.FOV_THRESH_UW) 2800*b7c941bbSAndroid Build Coastguard Worker wfov_camera_in_wfov_box = ( 2801*b7c941bbSAndroid Build Coastguard Worker math.isclose( 2802*b7c941bbSAndroid Build Coastguard Worker chart_distance, 2803*b7c941bbSAndroid Build Coastguard Worker opencv_processing_utils.CHART_DISTANCE_22CM, rel_tol=0.1) and 2804*b7c941bbSAndroid Build Coastguard Worker float(camera_fov) > opencv_processing_utils.FOV_THRESH_UW) 2805*b7c941bbSAndroid Build Coastguard Worker if (rfov_camera_in_rfov_box or wfov_camera_in_wfov_box) and lighting_check: 2806*b7c941bbSAndroid Build Coastguard Worker cam.do_3a() 2807*b7c941bbSAndroid Build Coastguard Worker cap = cam.do_capture( 2808*b7c941bbSAndroid Build Coastguard Worker capture_request_utils.auto_capture_request(), cam.CAP_YUV) 2809*b7c941bbSAndroid Build Coastguard Worker y_plane, _, _ = image_processing_utils.convert_capture_to_planes(cap) 2810*b7c941bbSAndroid Build Coastguard Worker validate_lighting(y_plane, scene, log_path=log_path, fov=float(camera_fov)) 2811*b7c941bbSAndroid Build Coastguard Worker 2812*b7c941bbSAndroid Build Coastguard Worker 2813*b7c941bbSAndroid Build Coastguard Workerdef copy_scenes_to_tablet(scene, tablet_id): 2814*b7c941bbSAndroid Build Coastguard Worker """Copies scenes onto the tablet before running the tests. 2815*b7c941bbSAndroid Build Coastguard Worker 2816*b7c941bbSAndroid Build Coastguard Worker Args: 2817*b7c941bbSAndroid Build Coastguard Worker scene: Name of the scene to copy image files. 2818*b7c941bbSAndroid Build Coastguard Worker tablet_id: device id of tablet 2819*b7c941bbSAndroid Build Coastguard Worker """ 2820*b7c941bbSAndroid Build Coastguard Worker logging.info('Copying files to tablet: %s', tablet_id) 2821*b7c941bbSAndroid Build Coastguard Worker scene_path = os.path.join(os.environ['CAMERA_ITS_TOP'], 'tests', scene) 2822*b7c941bbSAndroid Build Coastguard Worker scene_dir = os.listdir(scene_path) 2823*b7c941bbSAndroid Build Coastguard Worker for file_name in scene_dir: 2824*b7c941bbSAndroid Build Coastguard Worker if file_name.endswith('.png') or file_name.endswith('.mp4'): 2825*b7c941bbSAndroid Build Coastguard Worker src_scene_file = os.path.join(scene_path, file_name) 2826*b7c941bbSAndroid Build Coastguard Worker cmd = f'adb -s {tablet_id} push {src_scene_file} {_DST_SCENE_DIR}' 2827*b7c941bbSAndroid Build Coastguard Worker subprocess.Popen(cmd.split()) 2828*b7c941bbSAndroid Build Coastguard Worker time.sleep(_COPY_SCENE_DELAY_SEC) 2829*b7c941bbSAndroid Build Coastguard Worker logging.info('Finished copying files to tablet.') 2830*b7c941bbSAndroid Build Coastguard Worker 2831*b7c941bbSAndroid Build Coastguard Worker 2832*b7c941bbSAndroid Build Coastguard Workerdef validate_lighting(y_plane, scene, state='ON', log_path=None, 2833*b7c941bbSAndroid Build Coastguard Worker tablet_state='ON', fov=None): 2834*b7c941bbSAndroid Build Coastguard Worker """Validates the lighting level in scene corners based on empirical values. 2835*b7c941bbSAndroid Build Coastguard Worker 2836*b7c941bbSAndroid Build Coastguard Worker Args: 2837*b7c941bbSAndroid Build Coastguard Worker y_plane: Y plane of YUV image 2838*b7c941bbSAndroid Build Coastguard Worker scene: scene name 2839*b7c941bbSAndroid Build Coastguard Worker state: string 'ON' or 'OFF' 2840*b7c941bbSAndroid Build Coastguard Worker log_path: [Optional] path to store artifacts 2841*b7c941bbSAndroid Build Coastguard Worker tablet_state: string 'ON' or 'OFF' 2842*b7c941bbSAndroid Build Coastguard Worker fov: [Optional] float, calculated camera FoV 2843*b7c941bbSAndroid Build Coastguard Worker 2844*b7c941bbSAndroid Build Coastguard Worker Returns: 2845*b7c941bbSAndroid Build Coastguard Worker boolean True if lighting validated, else raise AssertionError 2846*b7c941bbSAndroid Build Coastguard Worker """ 2847*b7c941bbSAndroid Build Coastguard Worker logging.debug('Validating lighting levels.') 2848*b7c941bbSAndroid Build Coastguard Worker file_name = f'validate_lighting_{scene}.jpg' 2849*b7c941bbSAndroid Build Coastguard Worker if log_path: 2850*b7c941bbSAndroid Build Coastguard Worker file_name = os.path.join(log_path, f'validate_lighting_{scene}.jpg') 2851*b7c941bbSAndroid Build Coastguard Worker 2852*b7c941bbSAndroid Build Coastguard Worker if tablet_state == 'OFF': 2853*b7c941bbSAndroid Build Coastguard Worker validate_lighting_thresh = _VALIDATE_LIGHTING_THRESH_DARK 2854*b7c941bbSAndroid Build Coastguard Worker else: 2855*b7c941bbSAndroid Build Coastguard Worker validate_lighting_thresh = _VALIDATE_LIGHTING_THRESH 2856*b7c941bbSAndroid Build Coastguard Worker 2857*b7c941bbSAndroid Build Coastguard Worker validate_lighting_regions = _VALIDATE_LIGHTING_REGIONS 2858*b7c941bbSAndroid Build Coastguard Worker if fov and fov > _VALIDATE_LIGHTING_MACRO_FOV_THRESH: 2859*b7c941bbSAndroid Build Coastguard Worker validate_lighting_regions = _VALIDATE_LIGHTING_REGIONS_MODULAR_UW 2860*b7c941bbSAndroid Build Coastguard Worker 2861*b7c941bbSAndroid Build Coastguard Worker # Test patches from each corner. 2862*b7c941bbSAndroid Build Coastguard Worker for location, coordinates in validate_lighting_regions.items(): 2863*b7c941bbSAndroid Build Coastguard Worker patch = image_processing_utils.get_image_patch( 2864*b7c941bbSAndroid Build Coastguard Worker y_plane, coordinates[0], coordinates[1], 2865*b7c941bbSAndroid Build Coastguard Worker _VALIDATE_LIGHTING_PATCH_W, _VALIDATE_LIGHTING_PATCH_H) 2866*b7c941bbSAndroid Build Coastguard Worker y_mean = image_processing_utils.compute_image_means(patch)[0] 2867*b7c941bbSAndroid Build Coastguard Worker logging.debug('%s corner Y mean: %.3f', location, y_mean) 2868*b7c941bbSAndroid Build Coastguard Worker if state == 'ON': 2869*b7c941bbSAndroid Build Coastguard Worker if y_mean > validate_lighting_thresh: 2870*b7c941bbSAndroid Build Coastguard Worker logging.debug('Lights ON in test rig.') 2871*b7c941bbSAndroid Build Coastguard Worker return True 2872*b7c941bbSAndroid Build Coastguard Worker else: 2873*b7c941bbSAndroid Build Coastguard Worker image_processing_utils.write_image(y_plane, file_name) 2874*b7c941bbSAndroid Build Coastguard Worker raise AssertionError('Lights OFF in test rig. Turn ON and retry.') 2875*b7c941bbSAndroid Build Coastguard Worker elif state == 'OFF': 2876*b7c941bbSAndroid Build Coastguard Worker if y_mean < validate_lighting_thresh: 2877*b7c941bbSAndroid Build Coastguard Worker logging.debug('Lights OFF in test rig.') 2878*b7c941bbSAndroid Build Coastguard Worker return True 2879*b7c941bbSAndroid Build Coastguard Worker else: 2880*b7c941bbSAndroid Build Coastguard Worker image_processing_utils.write_image(y_plane, file_name) 2881*b7c941bbSAndroid Build Coastguard Worker raise AssertionError('Lights ON in test rig. Turn OFF and retry.') 2882*b7c941bbSAndroid Build Coastguard Worker else: 2883*b7c941bbSAndroid Build Coastguard Worker raise AssertionError('Invalid lighting state string. ' 2884*b7c941bbSAndroid Build Coastguard Worker "Valid strings: 'ON', 'OFF'.") 2885*b7c941bbSAndroid Build Coastguard Worker 2886*b7c941bbSAndroid Build Coastguard Worker 2887*b7c941bbSAndroid Build Coastguard Workerdef get_build_fingerprint(device_id): 2888*b7c941bbSAndroid Build Coastguard Worker """Return the build fingerprint of the device.""" 2889*b7c941bbSAndroid Build Coastguard Worker cmd = f'adb -s {device_id} shell getprop ro.build.fingerprint' 2890*b7c941bbSAndroid Build Coastguard Worker try: 2891*b7c941bbSAndroid Build Coastguard Worker build_fingerprint = subprocess.check_output(cmd.split()).decode('utf-8').strip() 2892*b7c941bbSAndroid Build Coastguard Worker logging.debug('Build fingerprint: %s', build_fingerprint) 2893*b7c941bbSAndroid Build Coastguard Worker except (subprocess.CalledProcessError, ValueError) as exp_errors: 2894*b7c941bbSAndroid Build Coastguard Worker raise AssertionError('No build_fingerprint.') from exp_errors 2895*b7c941bbSAndroid Build Coastguard Worker return build_fingerprint 2896*b7c941bbSAndroid Build Coastguard Worker 2897*b7c941bbSAndroid Build Coastguard Worker 2898*b7c941bbSAndroid Build Coastguard Workerdef get_build_sdk_version(device_id): 2899*b7c941bbSAndroid Build Coastguard Worker """Return the int build version of the device.""" 2900*b7c941bbSAndroid Build Coastguard Worker cmd = f'adb -s {device_id} shell getprop ro.build.version.sdk' 2901*b7c941bbSAndroid Build Coastguard Worker try: 2902*b7c941bbSAndroid Build Coastguard Worker build_sdk_version = int(subprocess.check_output(cmd.split()).rstrip()) 2903*b7c941bbSAndroid Build Coastguard Worker logging.debug('Build SDK version: %d', build_sdk_version) 2904*b7c941bbSAndroid Build Coastguard Worker except (subprocess.CalledProcessError, ValueError) as exp_errors: 2905*b7c941bbSAndroid Build Coastguard Worker raise AssertionError('No build_sdk_version.') from exp_errors 2906*b7c941bbSAndroid Build Coastguard Worker return build_sdk_version 2907*b7c941bbSAndroid Build Coastguard Worker 2908*b7c941bbSAndroid Build Coastguard Worker 2909*b7c941bbSAndroid Build Coastguard Workerdef get_first_api_level(device_id): 2910*b7c941bbSAndroid Build Coastguard Worker """Return the int value for the first API level of the device.""" 2911*b7c941bbSAndroid Build Coastguard Worker cmd = f'adb -s {device_id} shell getprop ro.product.first_api_level' 2912*b7c941bbSAndroid Build Coastguard Worker try: 2913*b7c941bbSAndroid Build Coastguard Worker first_api_level = int(subprocess.check_output(cmd.split()).rstrip()) 2914*b7c941bbSAndroid Build Coastguard Worker logging.debug('First API level: %d', first_api_level) 2915*b7c941bbSAndroid Build Coastguard Worker except (subprocess.CalledProcessError, ValueError): 2916*b7c941bbSAndroid Build Coastguard Worker logging.error('No first_api_level. Setting to build version.') 2917*b7c941bbSAndroid Build Coastguard Worker first_api_level = get_build_sdk_version(device_id) 2918*b7c941bbSAndroid Build Coastguard Worker return first_api_level 2919*b7c941bbSAndroid Build Coastguard Worker 2920*b7c941bbSAndroid Build Coastguard Worker 2921*b7c941bbSAndroid Build Coastguard Workerdef get_vendor_api_level(device_id): 2922*b7c941bbSAndroid Build Coastguard Worker """Return the int value for the vendor API level of the device.""" 2923*b7c941bbSAndroid Build Coastguard Worker cmd = f'adb -s {device_id} shell getprop ro.vendor.api_level' 2924*b7c941bbSAndroid Build Coastguard Worker try: 2925*b7c941bbSAndroid Build Coastguard Worker vendor_api_level = int(subprocess.check_output(cmd.split()).rstrip()) 2926*b7c941bbSAndroid Build Coastguard Worker logging.debug('First vendor API level: %d', vendor_api_level) 2927*b7c941bbSAndroid Build Coastguard Worker except (subprocess.CalledProcessError, ValueError): 2928*b7c941bbSAndroid Build Coastguard Worker logging.error('No vendor_api_level. Setting to build version.') 2929*b7c941bbSAndroid Build Coastguard Worker vendor_api_level = get_build_sdk_version(device_id) 2930*b7c941bbSAndroid Build Coastguard Worker return vendor_api_level 2931*b7c941bbSAndroid Build Coastguard Worker 2932*b7c941bbSAndroid Build Coastguard Worker 2933*b7c941bbSAndroid Build Coastguard Workerdef get_media_performance_class(device_id): 2934*b7c941bbSAndroid Build Coastguard Worker """Return the int value for the media performance class of the device.""" 2935*b7c941bbSAndroid Build Coastguard Worker cmd = (f'adb -s {device_id} shell ' 2936*b7c941bbSAndroid Build Coastguard Worker 'getprop ro.odm.build.media_performance_class') 2937*b7c941bbSAndroid Build Coastguard Worker try: 2938*b7c941bbSAndroid Build Coastguard Worker media_performance_class = int( 2939*b7c941bbSAndroid Build Coastguard Worker subprocess.check_output(cmd.split()).rstrip()) 2940*b7c941bbSAndroid Build Coastguard Worker logging.debug('Media performance class: %d', media_performance_class) 2941*b7c941bbSAndroid Build Coastguard Worker except (subprocess.CalledProcessError, ValueError): 2942*b7c941bbSAndroid Build Coastguard Worker logging.debug('No media performance class. Setting to 0.') 2943*b7c941bbSAndroid Build Coastguard Worker media_performance_class = 0 2944*b7c941bbSAndroid Build Coastguard Worker return media_performance_class 2945*b7c941bbSAndroid Build Coastguard Worker 2946*b7c941bbSAndroid Build Coastguard Worker 2947*b7c941bbSAndroid Build Coastguard Workerdef raise_mpc_assertion_error(required_mpc, test_name, found_mpc): 2948*b7c941bbSAndroid Build Coastguard Worker raise AssertionError(f'With MPC >= {required_mpc}, {test_name} must be run. ' 2949*b7c941bbSAndroid Build Coastguard Worker f'Found MPC: {found_mpc}') 2950*b7c941bbSAndroid Build Coastguard Worker 2951*b7c941bbSAndroid Build Coastguard Worker 2952*b7c941bbSAndroid Build Coastguard Workerdef stop_video_playback(tablet): 2953*b7c941bbSAndroid Build Coastguard Worker """Force-stop activities used for video playback on the tablet. 2954*b7c941bbSAndroid Build Coastguard Worker 2955*b7c941bbSAndroid Build Coastguard Worker Args: 2956*b7c941bbSAndroid Build Coastguard Worker tablet: a controller object for the ITS tablet. 2957*b7c941bbSAndroid Build Coastguard Worker """ 2958*b7c941bbSAndroid Build Coastguard Worker try: 2959*b7c941bbSAndroid Build Coastguard Worker activities_unencoded = tablet.adb.shell( 2960*b7c941bbSAndroid Build Coastguard Worker ['dumpsys', 'activity', 'recents', '|', 2961*b7c941bbSAndroid Build Coastguard Worker 'grep', '"baseIntent=Intent.*act=android.intent.action"'] 2962*b7c941bbSAndroid Build Coastguard Worker ) 2963*b7c941bbSAndroid Build Coastguard Worker except adb.AdbError as e: 2964*b7c941bbSAndroid Build Coastguard Worker logging.warning('ADB error when finding intent activities: %s. ' 2965*b7c941bbSAndroid Build Coastguard Worker 'Please close the default video player manually.', e) 2966*b7c941bbSAndroid Build Coastguard Worker return 2967*b7c941bbSAndroid Build Coastguard Worker activity_lines = ( 2968*b7c941bbSAndroid Build Coastguard Worker str(activities_unencoded.decode('utf-8')).strip().splitlines() 2969*b7c941bbSAndroid Build Coastguard Worker ) 2970*b7c941bbSAndroid Build Coastguard Worker for activity_line in activity_lines: 2971*b7c941bbSAndroid Build Coastguard Worker activity = activity_line.split('cmp=')[-1].split('/')[0] 2972*b7c941bbSAndroid Build Coastguard Worker try: 2973*b7c941bbSAndroid Build Coastguard Worker tablet.adb.shell(['am', 'force-stop', activity]) 2974*b7c941bbSAndroid Build Coastguard Worker except adb.AdbError as e: 2975*b7c941bbSAndroid Build Coastguard Worker logging.warning('ADB error when killing intent activity %s: %s. ' 2976*b7c941bbSAndroid Build Coastguard Worker 'Please close the default video player manually.', 2977*b7c941bbSAndroid Build Coastguard Worker activity, e) 2978*b7c941bbSAndroid Build Coastguard Worker 2979*b7c941bbSAndroid Build Coastguard Worker 2980*b7c941bbSAndroid Build Coastguard Workerdef raise_not_yet_mandated_error(message, api_level, mandated_api_level): 2981*b7c941bbSAndroid Build Coastguard Worker if api_level >= mandated_api_level: 2982*b7c941bbSAndroid Build Coastguard Worker raise AssertionError( 2983*b7c941bbSAndroid Build Coastguard Worker f'Test is mandated for API level {mandated_api_level} or above. ' 2984*b7c941bbSAndroid Build Coastguard Worker f'Found API level {api_level}.\n\n{message}' 2985*b7c941bbSAndroid Build Coastguard Worker ) 2986*b7c941bbSAndroid Build Coastguard Worker else: 2987*b7c941bbSAndroid Build Coastguard Worker raise AssertionError(f'{NOT_YET_MANDATED_MESSAGE}\n\n{message}') 2988*b7c941bbSAndroid Build Coastguard Worker 2989*b7c941bbSAndroid Build Coastguard Worker 2990*b7c941bbSAndroid Build Coastguard Workerdef pull_file_from_dut(dut, dut_path, log_folder): 2991*b7c941bbSAndroid Build Coastguard Worker """Pulls and returns file from dut and return file name. 2992*b7c941bbSAndroid Build Coastguard Worker 2993*b7c941bbSAndroid Build Coastguard Worker Args: 2994*b7c941bbSAndroid Build Coastguard Worker dut: device under test 2995*b7c941bbSAndroid Build Coastguard Worker dut_path: pull file from this path 2996*b7c941bbSAndroid Build Coastguard Worker log_folder: store pulled file to this folder 2997*b7c941bbSAndroid Build Coastguard Worker 2998*b7c941bbSAndroid Build Coastguard Worker Returns: 2999*b7c941bbSAndroid Build Coastguard Worker filename of file pulled from dut 3000*b7c941bbSAndroid Build Coastguard Worker """ 3001*b7c941bbSAndroid Build Coastguard Worker dut.adb.pull([dut_path, log_folder]) 3002*b7c941bbSAndroid Build Coastguard Worker file_name = (dut_path.split('/')[-1]) 3003*b7c941bbSAndroid Build Coastguard Worker logging.debug('%s pulled from dut', file_name) 3004*b7c941bbSAndroid Build Coastguard Worker return file_name 3005*b7c941bbSAndroid Build Coastguard Worker 3006*b7c941bbSAndroid Build Coastguard Worker 3007*b7c941bbSAndroid Build Coastguard Workerdef remove_tmp_files(log_path, match_pattern): 3008*b7c941bbSAndroid Build Coastguard Worker """Remove temp file with given directory path. 3009*b7c941bbSAndroid Build Coastguard Worker 3010*b7c941bbSAndroid Build Coastguard Worker Args: 3011*b7c941bbSAndroid Build Coastguard Worker log_path: path-like object, path of directory 3012*b7c941bbSAndroid Build Coastguard Worker match_pattern: string, pattern to be matched and removed 3013*b7c941bbSAndroid Build Coastguard Worker 3014*b7c941bbSAndroid Build Coastguard Worker Returns: 3015*b7c941bbSAndroid Build Coastguard Worker List of error messages if encountering error while removing files 3016*b7c941bbSAndroid Build Coastguard Worker """ 3017*b7c941bbSAndroid Build Coastguard Worker temp_files = [] 3018*b7c941bbSAndroid Build Coastguard Worker try: 3019*b7c941bbSAndroid Build Coastguard Worker temp_files = os.listdir(log_path) 3020*b7c941bbSAndroid Build Coastguard Worker except FileNotFoundError: 3021*b7c941bbSAndroid Build Coastguard Worker logging.debug('/tmp directory: %s not found', log_path) 3022*b7c941bbSAndroid Build Coastguard Worker for file in temp_files: 3023*b7c941bbSAndroid Build Coastguard Worker if fnmatch.fnmatch(file, match_pattern): 3024*b7c941bbSAndroid Build Coastguard Worker file_to_remove = os.path.join(log_path, file) 3025*b7c941bbSAndroid Build Coastguard Worker try: 3026*b7c941bbSAndroid Build Coastguard Worker os.remove(file_to_remove) 3027*b7c941bbSAndroid Build Coastguard Worker except FileNotFoundError: 3028*b7c941bbSAndroid Build Coastguard Worker logging.debug('File not found: %s', str(file)) 3029*b7c941bbSAndroid Build Coastguard Worker 3030*b7c941bbSAndroid Build Coastguard Worker 3031*b7c941bbSAndroid Build Coastguard Workerdef remove_frame_files(dir_name, save_files_list=None): 3032*b7c941bbSAndroid Build Coastguard Worker """Removes the generated frame files from test dir. 3033*b7c941bbSAndroid Build Coastguard Worker 3034*b7c941bbSAndroid Build Coastguard Worker Args: 3035*b7c941bbSAndroid Build Coastguard Worker dir_name: test directory name. 3036*b7c941bbSAndroid Build Coastguard Worker save_files_list: list of files not to be removed. Default is empty list. 3037*b7c941bbSAndroid Build Coastguard Worker """ 3038*b7c941bbSAndroid Build Coastguard Worker if os.path.exists(dir_name): 3039*b7c941bbSAndroid Build Coastguard Worker for image in glob.glob('%s/*.png' % dir_name): 3040*b7c941bbSAndroid Build Coastguard Worker if save_files_list is None or image not in save_files_list: 3041*b7c941bbSAndroid Build Coastguard Worker os.remove(image) 3042*b7c941bbSAndroid Build Coastguard Worker 3043*b7c941bbSAndroid Build Coastguard Worker 3044*b7c941bbSAndroid Build Coastguard Workerdef remove_file(file_name_with_path): 3045*b7c941bbSAndroid Build Coastguard Worker """Removes file at given path. 3046*b7c941bbSAndroid Build Coastguard Worker 3047*b7c941bbSAndroid Build Coastguard Worker Args: 3048*b7c941bbSAndroid Build Coastguard Worker file_name_with_path: string, filename with path. 3049*b7c941bbSAndroid Build Coastguard Worker """ 3050*b7c941bbSAndroid Build Coastguard Worker remove_mp4_file(file_name_with_path) 3051*b7c941bbSAndroid Build Coastguard Worker 3052*b7c941bbSAndroid Build Coastguard Worker 3053*b7c941bbSAndroid Build Coastguard Workerdef remove_mp4_file(file_name_with_path): 3054*b7c941bbSAndroid Build Coastguard Worker """Removes the mp4 file at given path. 3055*b7c941bbSAndroid Build Coastguard Worker 3056*b7c941bbSAndroid Build Coastguard Worker Args: 3057*b7c941bbSAndroid Build Coastguard Worker file_name_with_path: string, path to mp4 recording. 3058*b7c941bbSAndroid Build Coastguard Worker """ 3059*b7c941bbSAndroid Build Coastguard Worker try: 3060*b7c941bbSAndroid Build Coastguard Worker os.remove(file_name_with_path) 3061*b7c941bbSAndroid Build Coastguard Worker except FileNotFoundError: 3062*b7c941bbSAndroid Build Coastguard Worker logging.debug('File not found: %s', file_name_with_path) 3063*b7c941bbSAndroid Build Coastguard Worker 3064*b7c941bbSAndroid Build Coastguard Worker 3065*b7c941bbSAndroid Build Coastguard Workerdef check_features_passed( 3066*b7c941bbSAndroid Build Coastguard Worker features_passed, hlg10, is_stabilized): 3067*b7c941bbSAndroid Build Coastguard Worker """Check if the [hlg10, is_stabilized] combination is already tested 3068*b7c941bbSAndroid Build Coastguard Worker to be supported. 3069*b7c941bbSAndroid Build Coastguard Worker 3070*b7c941bbSAndroid Build Coastguard Worker Args: 3071*b7c941bbSAndroid Build Coastguard Worker features_passed: The list of feature combinations already supported 3072*b7c941bbSAndroid Build Coastguard Worker hlg10: boolean; Whether HLG10 is enabled 3073*b7c941bbSAndroid Build Coastguard Worker is_stabilized: boolean; Whether preview stabilizatoin is enabled 3074*b7c941bbSAndroid Build Coastguard Worker 3075*b7c941bbSAndroid Build Coastguard Worker Returns: 3076*b7c941bbSAndroid Build Coastguard Worker Whether the [hlg10, is_stabilized] is already tested to be supported. 3077*b7c941bbSAndroid Build Coastguard Worker """ 3078*b7c941bbSAndroid Build Coastguard Worker feature_mask = 0 3079*b7c941bbSAndroid Build Coastguard Worker if hlg10: feature_mask |= _BIT_HLG10 3080*b7c941bbSAndroid Build Coastguard Worker if is_stabilized: feature_mask |= _BIT_STABILIZATION 3081*b7c941bbSAndroid Build Coastguard Worker tested = False 3082*b7c941bbSAndroid Build Coastguard Worker for tested_feature in features_passed: 3083*b7c941bbSAndroid Build Coastguard Worker # Only test a combination if they aren't already a subset 3084*b7c941bbSAndroid Build Coastguard Worker # of another tested combination. 3085*b7c941bbSAndroid Build Coastguard Worker if (tested_feature | feature_mask) == tested_feature: 3086*b7c941bbSAndroid Build Coastguard Worker tested = True 3087*b7c941bbSAndroid Build Coastguard Worker break 3088*b7c941bbSAndroid Build Coastguard Worker return tested 3089*b7c941bbSAndroid Build Coastguard Worker 3090*b7c941bbSAndroid Build Coastguard Worker 3091*b7c941bbSAndroid Build Coastguard Workerdef mark_features_passed( 3092*b7c941bbSAndroid Build Coastguard Worker features_passed, hlg10, is_stabilized): 3093*b7c941bbSAndroid Build Coastguard Worker """Mark the [hlg10, is_stabilized] combination as tested to pass. 3094*b7c941bbSAndroid Build Coastguard Worker 3095*b7c941bbSAndroid Build Coastguard Worker Args: 3096*b7c941bbSAndroid Build Coastguard Worker features_passed: The list of feature combinations already tested 3097*b7c941bbSAndroid Build Coastguard Worker hlg10: boolean; Whether HLG10 is enabled 3098*b7c941bbSAndroid Build Coastguard Worker is_stabilized: boolean; Whether preview stabilizatoin is enabled 3099*b7c941bbSAndroid Build Coastguard Worker """ 3100*b7c941bbSAndroid Build Coastguard Worker feature_mask = 0 3101*b7c941bbSAndroid Build Coastguard Worker if hlg10: feature_mask |= _BIT_HLG10 3102*b7c941bbSAndroid Build Coastguard Worker if is_stabilized: feature_mask |= _BIT_STABILIZATION 3103*b7c941bbSAndroid Build Coastguard Worker features_passed.append(feature_mask) 3104