1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/camera/GonkCameraParameters.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,834 @@ 1.4 +/* 1.5 + * Copyright (C) 2013-2014 Mozilla Foundation 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * Unless required by applicable law or agreed to in writing, software 1.14 + * distributed under the License is distributed on an "AS IS" BASIS, 1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.16 + * See the License for the specific language governing permissions and 1.17 + * limitations under the License. 1.18 + */ 1.19 + 1.20 +#include "GonkCameraParameters.h" 1.21 +#include "camera/CameraParameters.h" 1.22 +#include "ICameraControl.h" 1.23 +#include "CameraCommon.h" 1.24 + 1.25 +using namespace mozilla; 1.26 +using namespace android; 1.27 + 1.28 +/* static */ const char* 1.29 +GonkCameraParameters::Parameters::GetTextKey(uint32_t aKey) 1.30 +{ 1.31 + switch (aKey) { 1.32 + case CAMERA_PARAM_PREVIEWSIZE: 1.33 + return KEY_PREVIEW_SIZE; 1.34 + case CAMERA_PARAM_PREVIEWFORMAT: 1.35 + return KEY_PREVIEW_FORMAT; 1.36 + case CAMERA_PARAM_PREVIEWFRAMERATE: 1.37 + return KEY_PREVIEW_FRAME_RATE; 1.38 + case CAMERA_PARAM_EFFECT: 1.39 + return KEY_EFFECT; 1.40 + case CAMERA_PARAM_WHITEBALANCE: 1.41 + return KEY_WHITE_BALANCE; 1.42 + case CAMERA_PARAM_SCENEMODE: 1.43 + return KEY_SCENE_MODE; 1.44 + case CAMERA_PARAM_FLASHMODE: 1.45 + return KEY_FLASH_MODE; 1.46 + case CAMERA_PARAM_FOCUSMODE: 1.47 + return KEY_FOCUS_MODE; 1.48 + case CAMERA_PARAM_ZOOM: 1.49 + return KEY_ZOOM; 1.50 + case CAMERA_PARAM_METERINGAREAS: 1.51 + return KEY_METERING_AREAS; 1.52 + case CAMERA_PARAM_FOCUSAREAS: 1.53 + return KEY_FOCUS_AREAS; 1.54 + case CAMERA_PARAM_FOCALLENGTH: 1.55 + return KEY_FOCAL_LENGTH; 1.56 + case CAMERA_PARAM_FOCUSDISTANCENEAR: 1.57 + return KEY_FOCUS_DISTANCES; 1.58 + case CAMERA_PARAM_FOCUSDISTANCEOPTIMUM: 1.59 + return KEY_FOCUS_DISTANCES; 1.60 + case CAMERA_PARAM_FOCUSDISTANCEFAR: 1.61 + return KEY_FOCUS_DISTANCES; 1.62 + case CAMERA_PARAM_EXPOSURECOMPENSATION: 1.63 + return KEY_EXPOSURE_COMPENSATION; 1.64 + case CAMERA_PARAM_THUMBNAILQUALITY: 1.65 + return KEY_JPEG_THUMBNAIL_QUALITY; 1.66 + case CAMERA_PARAM_PICTURE_SIZE: 1.67 + return KEY_PICTURE_SIZE; 1.68 + case CAMERA_PARAM_PICTURE_FILEFORMAT: 1.69 + return KEY_PICTURE_FORMAT; 1.70 + case CAMERA_PARAM_PICTURE_ROTATION: 1.71 + return KEY_ROTATION; 1.72 + case CAMERA_PARAM_PICTURE_DATETIME: 1.73 + // Not every platform defines a KEY_EXIF_DATETIME; 1.74 + // for those that don't, we use the raw string key, and if the platform 1.75 + // doesn't support it, it will be ignored. 1.76 + // 1.77 + // See bug 832494. 1.78 + return "exif-datetime"; 1.79 + case CAMERA_PARAM_VIDEOSIZE: 1.80 + return KEY_VIDEO_SIZE; 1.81 + case CAMERA_PARAM_ISOMODE: 1.82 + // Not every platform defines KEY_ISO_MODE; 1.83 + // for those that don't, we use the raw string key. 1.84 + return "iso"; 1.85 + case CAMERA_PARAM_LUMINANCE: 1.86 + return "luminance-condition"; 1.87 + case CAMERA_PARAM_SCENEMODE_HDR_RETURNNORMALPICTURE: 1.88 + // Not every platform defines KEY_QC_HDR_NEED_1X; 1.89 + // for those that don't, we use the raw string key. 1.90 + return "hdr-need-1x"; 1.91 + 1.92 + case CAMERA_PARAM_SUPPORTED_PREVIEWSIZES: 1.93 + return KEY_SUPPORTED_PREVIEW_SIZES; 1.94 + case CAMERA_PARAM_SUPPORTED_PICTURESIZES: 1.95 + return KEY_SUPPORTED_PICTURE_SIZES; 1.96 + case CAMERA_PARAM_SUPPORTED_VIDEOSIZES: 1.97 + return KEY_SUPPORTED_VIDEO_SIZES; 1.98 + case CAMERA_PARAM_SUPPORTED_PICTUREFORMATS: 1.99 + return KEY_SUPPORTED_PICTURE_FORMATS; 1.100 + case CAMERA_PARAM_SUPPORTED_WHITEBALANCES: 1.101 + return KEY_SUPPORTED_WHITE_BALANCE; 1.102 + case CAMERA_PARAM_SUPPORTED_SCENEMODES: 1.103 + return KEY_SUPPORTED_SCENE_MODES; 1.104 + case CAMERA_PARAM_SUPPORTED_EFFECTS: 1.105 + return KEY_SUPPORTED_EFFECTS; 1.106 + case CAMERA_PARAM_SUPPORTED_FLASHMODES: 1.107 + return KEY_SUPPORTED_FLASH_MODES; 1.108 + case CAMERA_PARAM_SUPPORTED_FOCUSMODES: 1.109 + return KEY_SUPPORTED_FOCUS_MODES; 1.110 + case CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS: 1.111 + return KEY_MAX_NUM_FOCUS_AREAS; 1.112 + case CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS: 1.113 + return KEY_MAX_NUM_METERING_AREAS; 1.114 + case CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION: 1.115 + return KEY_MIN_EXPOSURE_COMPENSATION; 1.116 + case CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION: 1.117 + return KEY_MAX_EXPOSURE_COMPENSATION; 1.118 + case CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP: 1.119 + return KEY_EXPOSURE_COMPENSATION_STEP; 1.120 + case CAMERA_PARAM_SUPPORTED_ZOOM: 1.121 + return KEY_ZOOM_SUPPORTED; 1.122 + case CAMERA_PARAM_SUPPORTED_ZOOMRATIOS: 1.123 + return KEY_ZOOM_RATIOS; 1.124 + case CAMERA_PARAM_SUPPORTED_MAXDETECTEDFACES: 1.125 + return KEY_MAX_NUM_DETECTED_FACES_HW; 1.126 + case CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES: 1.127 + return KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES; 1.128 + case CAMERA_PARAM_SUPPORTED_ISOMODES: 1.129 + // Not every platform defines KEY_SUPPORTED_ISO_MODES; 1.130 + // for those that don't, we use the raw string key. 1.131 + return "iso-values"; 1.132 + default: 1.133 + DOM_CAMERA_LOGE("Unhandled camera parameter value %u\n", aKey); 1.134 + return nullptr; 1.135 + } 1.136 +} 1.137 + 1.138 +GonkCameraParameters::GonkCameraParameters() 1.139 + : mLock(PR_NewRWLock(PR_RWLOCK_RANK_NONE, "GonkCameraParameters.Lock")) 1.140 + , mDirty(false) 1.141 + , mInitialized(false) 1.142 +{ 1.143 + MOZ_COUNT_CTOR(GonkCameraParameters); 1.144 + if (!mLock) { 1.145 + MOZ_CRASH("OOM getting new PRRWLock"); 1.146 + } 1.147 +} 1.148 + 1.149 +GonkCameraParameters::~GonkCameraParameters() 1.150 +{ 1.151 + MOZ_COUNT_DTOR(GonkCameraParameters); 1.152 + if (mLock) { 1.153 + PR_DestroyRWLock(mLock); 1.154 + mLock = nullptr; 1.155 + } 1.156 +} 1.157 + 1.158 +nsresult 1.159 +GonkCameraParameters::MapIsoToGonk(const nsAString& aIso, nsACString& aIsoOut) 1.160 +{ 1.161 + if (aIso.EqualsASCII("hjr")) { 1.162 + aIsoOut = "ISO_HJR"; 1.163 + } else if (aIso.EqualsASCII("auto")) { 1.164 + aIsoOut = "auto"; 1.165 + } else { 1.166 + nsAutoCString v = NS_LossyConvertUTF16toASCII(aIso); 1.167 + unsigned int iso; 1.168 + if (sscanf(v.get(), "%u", &iso) != 1) { 1.169 + return NS_ERROR_FAILURE; 1.170 + } 1.171 + aIsoOut = nsPrintfCString("ISO%u", iso); 1.172 + } 1.173 + 1.174 + return NS_OK; 1.175 +} 1.176 + 1.177 +nsresult 1.178 +GonkCameraParameters::MapIsoFromGonk(const char* aIso, nsAString& aIsoOut) 1.179 +{ 1.180 + if (strcmp(aIso, "ISO_HJR") == 0) { 1.181 + aIsoOut.AssignASCII("hjr"); 1.182 + } else if (strcmp(aIso, "auto") == 0) { 1.183 + aIsoOut.AssignASCII("auto"); 1.184 + } else { 1.185 + unsigned int iso; 1.186 + if (sscanf(aIso, "ISO%u", &iso) != 1) { 1.187 + return NS_ERROR_FAILURE; 1.188 + } 1.189 + aIsoOut.AppendInt(iso); 1.190 + } 1.191 + 1.192 + return NS_OK; 1.193 +} 1.194 + 1.195 +// Any members that need to be initialized on the first parameter pull 1.196 +// need to get handled in here. 1.197 +nsresult 1.198 +GonkCameraParameters::Initialize() 1.199 +{ 1.200 + nsresult rv; 1.201 + 1.202 + rv = GetImpl(CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION, mExposureCompensationMin); 1.203 + if (NS_FAILED(rv)) { 1.204 + NS_WARNING("Failed to initialize minimum exposure compensation"); 1.205 + mExposureCompensationMin = 0; 1.206 + } 1.207 + rv = GetImpl(CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP, mExposureCompensationStep); 1.208 + if (NS_FAILED(rv)) { 1.209 + NS_WARNING("Failed to initialize exposure compensation step size"); 1.210 + mExposureCompensationStep = 0; 1.211 + } 1.212 + 1.213 + rv = GetListAsArray(CAMERA_PARAM_SUPPORTED_ZOOMRATIOS, mZoomRatios); 1.214 + if (NS_FAILED(rv)) { 1.215 + // zoom is not supported 1.216 + mZoomRatios.Clear(); 1.217 + } 1.218 + for (uint32_t i = 1; i < mZoomRatios.Length(); ++i) { 1.219 + // Make sure the camera gave us a properly sorted zoom ratio list! 1.220 + if (mZoomRatios[i] < mZoomRatios[i - 1]) { 1.221 + NS_WARNING("Zoom ratios list is out of order, discarding"); 1.222 + DOM_CAMERA_LOGE("zoom[%d]=%fx < zoom[%d]=%fx is out of order\n", 1.223 + i, mZoomRatios[i] / 100.0, i - 1, mZoomRatios[i - 1] / 100.0); 1.224 + mZoomRatios.Clear(); 1.225 + break; 1.226 + } 1.227 + } 1.228 + if (mZoomRatios.Length() == 0) { 1.229 + // Always report that we support at least 1.0x zoom. 1.230 + *mZoomRatios.AppendElement() = 100; 1.231 + } 1.232 + 1.233 + // The return code from GetListAsArray() doesn't matter. If it fails, 1.234 + // the isoModes array will be empty, and the subsequent loop won't 1.235 + // execute. 1.236 + nsTArray<nsCString> isoModes; 1.237 + GetListAsArray(CAMERA_PARAM_SUPPORTED_ISOMODES, isoModes); 1.238 + for (uint32_t i = 0; i < isoModes.Length(); ++i) { 1.239 + nsString v; 1.240 + rv = MapIsoFromGonk(isoModes[i].get(), v); 1.241 + if (NS_SUCCEEDED(rv)) { 1.242 + *mIsoModes.AppendElement() = v; 1.243 + } 1.244 + } 1.245 + 1.246 + mInitialized = true; 1.247 + return NS_OK; 1.248 +} 1.249 + 1.250 +// Handle nsAStrings 1.251 +nsresult 1.252 +GonkCameraParameters::SetTranslated(uint32_t aKey, const nsAString& aValue) 1.253 +{ 1.254 + if (aKey == CAMERA_PARAM_ISOMODE) { 1.255 + nsAutoCString v; 1.256 + nsresult rv = MapIsoToGonk(aValue, v); 1.257 + if (NS_FAILED(rv)) { 1.258 + return rv; 1.259 + } 1.260 + return SetImpl(aKey, v.get()); 1.261 + } 1.262 + 1.263 + return SetImpl(aKey, NS_ConvertUTF16toUTF8(aValue).get()); 1.264 +} 1.265 + 1.266 +nsresult 1.267 +GonkCameraParameters::GetTranslated(uint32_t aKey, nsAString& aValue) 1.268 +{ 1.269 + const char* val; 1.270 + nsresult rv = GetImpl(aKey, val); 1.271 + if (NS_FAILED(rv)) { 1.272 + return rv; 1.273 + } 1.274 + if (aKey == CAMERA_PARAM_ISOMODE) { 1.275 + rv = MapIsoFromGonk(val, aValue); 1.276 + } else if(val) { 1.277 + aValue.AssignASCII(val); 1.278 + } else { 1.279 + aValue.Truncate(0); 1.280 + } 1.281 + return rv; 1.282 +} 1.283 + 1.284 +// Handle ICameraControl::Sizes 1.285 +nsresult 1.286 +GonkCameraParameters::SetTranslated(uint32_t aKey, const ICameraControl::Size& aSize) 1.287 +{ 1.288 + if (aSize.width > INT_MAX || aSize.height > INT_MAX) { 1.289 + // AOSP can only handle signed ints. 1.290 + DOM_CAMERA_LOGE("Camera parameter aKey=%d out of bounds (width=%u, height=%u)\n", 1.291 + aSize.width, aSize.height); 1.292 + return NS_ERROR_INVALID_ARG; 1.293 + } 1.294 + 1.295 + nsresult rv; 1.296 + 1.297 + switch (aKey) { 1.298 + case CAMERA_PARAM_THUMBNAILSIZE: 1.299 + // This is a special case--for some reason the thumbnail size 1.300 + // is accessed as two separate values instead of a tuple. 1.301 + // XXXmikeh - make this restore the original values on error 1.302 + rv = SetImpl(Parameters::KEY_JPEG_THUMBNAIL_WIDTH, static_cast<int>(aSize.width)); 1.303 + if (NS_SUCCEEDED(rv)) { 1.304 + rv = SetImpl(Parameters::KEY_JPEG_THUMBNAIL_HEIGHT, static_cast<int>(aSize.height)); 1.305 + } 1.306 + break; 1.307 + 1.308 + case CAMERA_PARAM_VIDEOSIZE: 1.309 + // "record-size" is probably deprecated in later ICS; 1.310 + // might need to set "video-size" instead of "record-size"; 1.311 + // for the time being, set both. See bug 795332. 1.312 + rv = SetImpl("record-size", nsPrintfCString("%ux%u", aSize.width, aSize.height).get()); 1.313 + if (NS_FAILED(rv)) { 1.314 + break; 1.315 + } 1.316 + // intentional fallthrough 1.317 + 1.318 + default: 1.319 + rv = SetImpl(aKey, nsPrintfCString("%ux%u", aSize.width, aSize.height).get()); 1.320 + break; 1.321 + } 1.322 + 1.323 + if (NS_FAILED(rv)) { 1.324 + DOM_CAMERA_LOGE("Camera parameter aKey=%d failed to set (0x%x)\n", aKey, rv); 1.325 + } 1.326 + return rv; 1.327 +} 1.328 + 1.329 +nsresult 1.330 +GonkCameraParameters::GetTranslated(uint32_t aKey, ICameraControl::Size& aSize) 1.331 +{ 1.332 + nsresult rv; 1.333 + 1.334 + if (aKey == CAMERA_PARAM_THUMBNAILSIZE) { 1.335 + int width; 1.336 + int height; 1.337 + 1.338 + rv = GetImpl(Parameters::KEY_JPEG_THUMBNAIL_WIDTH, width); 1.339 + if (NS_FAILED(rv) || width < 0) { 1.340 + return NS_ERROR_FAILURE; 1.341 + } 1.342 + rv = GetImpl(Parameters::KEY_JPEG_THUMBNAIL_HEIGHT, height); 1.343 + if (NS_FAILED(rv) || height < 0) { 1.344 + return NS_ERROR_FAILURE; 1.345 + } 1.346 + 1.347 + aSize.width = static_cast<uint32_t>(width); 1.348 + aSize.height = static_cast<uint32_t>(height); 1.349 + return NS_OK; 1.350 + } 1.351 + 1.352 + const char* value; 1.353 + rv = GetImpl(aKey, value); 1.354 + if (NS_FAILED(rv) || !value || *value == '\0') { 1.355 + DOM_CAMERA_LOGW("Camera parameter aKey=%d not available (0x%x)\n", aKey, rv); 1.356 + return NS_ERROR_NOT_AVAILABLE; 1.357 + } 1.358 + if (sscanf(value, "%ux%u", &aSize.width, &aSize.height) != 2) { 1.359 + DOM_CAMERA_LOGE("Camera parameter aKey=%d size tuple '%s' is invalid\n", aKey, value); 1.360 + return NS_ERROR_FAILURE; 1.361 + } 1.362 + return NS_OK; 1.363 +} 1.364 + 1.365 +// Handle arrays of ICameraControl::Regions 1.366 +nsresult 1.367 +GonkCameraParameters::SetTranslated(uint32_t aKey, const nsTArray<ICameraControl::Region>& aRegions) 1.368 +{ 1.369 + uint32_t length = aRegions.Length(); 1.370 + 1.371 + if (!length) { 1.372 + // This tells the camera driver to revert to automatic regioning. 1.373 + return SetImpl(aKey, "(0,0,0,0,0)"); 1.374 + } 1.375 + 1.376 + nsCString s; 1.377 + 1.378 + for (uint32_t i = 0; i < length; ++i) { 1.379 + const ICameraControl::Region* r = &aRegions[i]; 1.380 + s.AppendPrintf("(%d,%d,%d,%d,%d),", r->top, r->left, r->bottom, r->right, r->weight); 1.381 + } 1.382 + 1.383 + // remove the trailing comma 1.384 + s.Trim(",", false, true, true); 1.385 + 1.386 + return SetImpl(aKey, s.get()); 1.387 +} 1.388 + 1.389 +nsresult 1.390 +GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<ICameraControl::Region>& aRegions) 1.391 +{ 1.392 + aRegions.Clear(); 1.393 + 1.394 + const char* value; 1.395 + nsresult rv = GetImpl(aKey, value); 1.396 + if (NS_FAILED(rv) || !value || *value == '\0') { 1.397 + return NS_ERROR_FAILURE; 1.398 + } 1.399 + 1.400 + const char* p = value; 1.401 + uint32_t count = 1; 1.402 + 1.403 + // count the number of regions in the string 1.404 + while ((p = strstr(p, "),("))) { 1.405 + ++count; 1.406 + p += 3; 1.407 + } 1.408 + 1.409 + aRegions.SetCapacity(count); 1.410 + ICameraControl::Region* r; 1.411 + 1.412 + // parse all of the region sets 1.413 + uint32_t i; 1.414 + for (i = 0, p = value; p && i < count; ++i, p = strchr(p + 1, '(')) { 1.415 + r = aRegions.AppendElement(); 1.416 + if (sscanf(p, "(%d,%d,%d,%d,%u)", &r->top, &r->left, &r->bottom, &r->right, &r->weight) != 5) { 1.417 + DOM_CAMERA_LOGE("%s:%d : region tuple has bad format: '%s'\n", __func__, __LINE__, p); 1.418 + aRegions.Clear(); 1.419 + return NS_ERROR_FAILURE; 1.420 + } 1.421 + } 1.422 + 1.423 + return NS_OK; 1.424 +} 1.425 + 1.426 +// Handle ICameraControl::Positions 1.427 +nsresult 1.428 +GonkCameraParameters::SetTranslated(uint32_t aKey, const ICameraControl::Position& aPosition) 1.429 +{ 1.430 + MOZ_ASSERT(aKey == CAMERA_PARAM_PICTURE_LOCATION); 1.431 + 1.432 + // Add any specified location information -- we don't care if these fail. 1.433 + if (!isnan(aPosition.latitude)) { 1.434 + DOM_CAMERA_LOGI("setting picture latitude to %lf\n", aPosition.latitude); 1.435 + SetImpl(Parameters::KEY_GPS_LATITUDE, nsPrintfCString("%lf", aPosition.latitude).get()); 1.436 + } 1.437 + if (!isnan(aPosition.longitude)) { 1.438 + DOM_CAMERA_LOGI("setting picture longitude to %lf\n", aPosition.longitude); 1.439 + SetImpl(Parameters::KEY_GPS_LONGITUDE, nsPrintfCString("%lf", aPosition.longitude).get()); 1.440 + } 1.441 + if (!isnan(aPosition.altitude)) { 1.442 + DOM_CAMERA_LOGI("setting picture altitude to %lf\n", aPosition.altitude); 1.443 + SetImpl(Parameters::KEY_GPS_ALTITUDE, nsPrintfCString("%lf", aPosition.altitude).get()); 1.444 + } 1.445 + if (!isnan(aPosition.timestamp)) { 1.446 + DOM_CAMERA_LOGI("setting picture timestamp to %lf\n", aPosition.timestamp); 1.447 + SetImpl(Parameters::KEY_GPS_TIMESTAMP, nsPrintfCString("%lf", aPosition.timestamp).get()); 1.448 + } 1.449 + return NS_OK; 1.450 +} 1.451 + 1.452 +// Handle int64_ts 1.453 +nsresult 1.454 +GonkCameraParameters::SetTranslated(uint32_t aKey, const int64_t& aValue) 1.455 +{ 1.456 + switch (aKey) { 1.457 + case CAMERA_PARAM_PICTURE_DATETIME: 1.458 + { 1.459 + // Add the non-GPS timestamp. The EXIF date/time field is formatted as 1.460 + // "YYYY:MM:DD HH:MM:SS", without room for a time-zone; as such, the time 1.461 + // is meant to be stored as a local time. Since we are given seconds from 1.462 + // Epoch GMT, we use localtime_r() to handle the conversion. 1.463 + time_t time = aValue; 1.464 + if (time != aValue) { 1.465 + DOM_CAMERA_LOGE("picture date/time '%llu' is too far in the future\n", aValue); 1.466 + return NS_ERROR_INVALID_ARG; 1.467 + } 1.468 + 1.469 + struct tm t; 1.470 + if (!localtime_r(&time, &t)) { 1.471 + DOM_CAMERA_LOGE("picture date/time couldn't be converted to local time: (%d) %s\n", errno, strerror(errno)); 1.472 + return NS_ERROR_FAILURE; 1.473 + } 1.474 + 1.475 + char dateTime[20]; 1.476 + if (!strftime(dateTime, sizeof(dateTime), "%Y:%m:%d %T", &t)) { 1.477 + DOM_CAMERA_LOGE("picture date/time couldn't be converted to string\n"); 1.478 + return NS_ERROR_FAILURE; 1.479 + } 1.480 + 1.481 + DOM_CAMERA_LOGI("setting picture date/time to %s\n", dateTime); 1.482 + 1.483 + return SetImpl(CAMERA_PARAM_PICTURE_DATETIME, dateTime); 1.484 + } 1.485 + 1.486 + case CAMERA_PARAM_ISOMODE: 1.487 + { 1.488 + if (aValue > INT32_MAX) { 1.489 + DOM_CAMERA_LOGW("Can't set ISO mode = %lld, too big\n", aValue); 1.490 + return NS_ERROR_INVALID_ARG; 1.491 + } 1.492 + 1.493 + nsString s; 1.494 + s.AppendInt(aValue); 1.495 + return SetTranslated(CAMERA_PARAM_ISOMODE, s); 1.496 + } 1.497 + } 1.498 + 1.499 + // You can't actually pass 64-bit parameters to Gonk. :( 1.500 + int32_t v = static_cast<int32_t>(aValue); 1.501 + if (static_cast<int64_t>(v) != aValue) { 1.502 + return NS_ERROR_INVALID_ARG;; 1.503 + } 1.504 + return SetImpl(aKey, v); 1.505 +} 1.506 + 1.507 +nsresult 1.508 +GonkCameraParameters::GetTranslated(uint32_t aKey, int64_t& aValue) 1.509 +{ 1.510 + int val; 1.511 + nsresult rv = GetImpl(aKey, val); 1.512 + if (NS_FAILED(rv)) { 1.513 + return rv; 1.514 + } 1.515 + aValue = val; 1.516 + return NS_OK; 1.517 +} 1.518 + 1.519 +// Handle doubles 1.520 +nsresult 1.521 +GonkCameraParameters::SetTranslated(uint32_t aKey, const double& aValue) 1.522 +{ 1.523 + int index; 1.524 + int value; 1.525 + 1.526 + switch (aKey) { 1.527 + case CAMERA_PARAM_EXPOSURECOMPENSATION: 1.528 + if (mExposureCompensationStep == 0) { 1.529 + DOM_CAMERA_LOGE("Exposure compensation not supported, can't set %f\n", aValue); 1.530 + return NS_ERROR_NOT_AVAILABLE; 1.531 + } 1.532 + 1.533 + /** 1.534 + * Convert from real value to a Gonk index, round 1.535 + * to the nearest step; index is 1-based. 1.536 + */ 1.537 + index = 1.538 + (aValue - mExposureCompensationMin + mExposureCompensationStep / 2) / 1.539 + mExposureCompensationStep + 1; 1.540 + DOM_CAMERA_LOGI("Exposure compensation = %f --> index = %d\n", aValue, index); 1.541 + return SetImpl(CAMERA_PARAM_EXPOSURECOMPENSATION, index); 1.542 + 1.543 + case CAMERA_PARAM_ZOOM: 1.544 + { 1.545 + /** 1.546 + * Convert from a real zoom multipler (e.g. 2.5x) to 1.547 + * the index of the nearest supported value. 1.548 + */ 1.549 + value = aValue * 100.0; 1.550 + 1.551 + if (value <= mZoomRatios[0]) { 1.552 + index = 0; 1.553 + } else if (value >= mZoomRatios.LastElement()) { 1.554 + index = mZoomRatios.Length() - 1; 1.555 + } else { 1.556 + // mZoomRatios is sorted, so we can binary search it 1.557 + int bottom = 0; 1.558 + int top = mZoomRatios.Length() - 1; 1.559 + 1.560 + while (top >= bottom) { 1.561 + index = (top + bottom) / 2; 1.562 + if (value == mZoomRatios[index]) { 1.563 + // exact match 1.564 + break; 1.565 + } 1.566 + if (value > mZoomRatios[index] && value < mZoomRatios[index + 1]) { 1.567 + // the specified zoom value lies in this interval 1.568 + break; 1.569 + } 1.570 + if (value > mZoomRatios[index]) { 1.571 + bottom = index + 1; 1.572 + } else { 1.573 + top = index - 1; 1.574 + } 1.575 + } 1.576 + } 1.577 + DOM_CAMERA_LOGI("Zoom = %fx --> index = %d\n", aValue, index); 1.578 + } 1.579 + return SetImpl(CAMERA_PARAM_ZOOM, index); 1.580 + } 1.581 + 1.582 + return SetImpl(aKey, aValue); 1.583 +} 1.584 + 1.585 +nsresult 1.586 +GonkCameraParameters::GetTranslated(uint32_t aKey, double& aValue) 1.587 +{ 1.588 + double val; 1.589 + int index = 0; 1.590 + double focusDistance[3]; 1.591 + const char* s; 1.592 + nsresult rv; 1.593 + 1.594 + switch (aKey) { 1.595 + case CAMERA_PARAM_ZOOM: 1.596 + rv = GetImpl(aKey, index); 1.597 + if (NS_SUCCEEDED(rv) && index >= 0) { 1.598 + val = mZoomRatios[index] / 100.0; 1.599 + } else { 1.600 + // return 1x when zooming is not supported 1.601 + val = 1.0; 1.602 + rv = NS_OK; 1.603 + } 1.604 + break; 1.605 + 1.606 + /** 1.607 + * The gonk camera parameters API only exposes one focus distance property 1.608 + * that contains "Near,Optimum,Far" distances, in metres, where 'Far' may 1.609 + * be 'Infinity'. 1.610 + */ 1.611 + case CAMERA_PARAM_FOCUSDISTANCEFAR: 1.612 + ++index; 1.613 + // intentional fallthrough 1.614 + 1.615 + case CAMERA_PARAM_FOCUSDISTANCEOPTIMUM: 1.616 + ++index; 1.617 + // intentional fallthrough 1.618 + 1.619 + case CAMERA_PARAM_FOCUSDISTANCENEAR: 1.620 + rv = GetImpl(aKey, s); 1.621 + if (NS_SUCCEEDED(rv)) { 1.622 + if (sscanf(s, "%lf,%lf,%lf", &focusDistance[0], &focusDistance[1], &focusDistance[2]) == 3) { 1.623 + val = focusDistance[index]; 1.624 + } else { 1.625 + val = 0.0; 1.626 + } 1.627 + } 1.628 + break; 1.629 + 1.630 + case CAMERA_PARAM_EXPOSURECOMPENSATION: 1.631 + rv = GetImpl(aKey, index); 1.632 + if (NS_SUCCEEDED(rv)) { 1.633 + if (!index) { 1.634 + // NaN indicates automatic exposure compensation 1.635 + val = NAN; 1.636 + } else { 1.637 + val = (index - 1) * mExposureCompensationStep + mExposureCompensationMin; 1.638 + DOM_CAMERA_LOGI("index = %d --> compensation = %f\n", index, val); 1.639 + } 1.640 + } 1.641 + break; 1.642 + 1.643 + default: 1.644 + rv = GetImpl(aKey, val); 1.645 + break; 1.646 + } 1.647 + 1.648 + if (NS_SUCCEEDED(rv)) { 1.649 + aValue = val; 1.650 + } 1.651 + return rv; 1.652 +} 1.653 + 1.654 +// Handle ints 1.655 +nsresult 1.656 +GonkCameraParameters::SetTranslated(uint32_t aKey, const int& aValue) 1.657 +{ 1.658 + return SetImpl(aKey, aValue); 1.659 +} 1.660 + 1.661 +nsresult 1.662 +GonkCameraParameters::GetTranslated(uint32_t aKey, int& aValue) 1.663 +{ 1.664 + return GetImpl(aKey, aValue); 1.665 +} 1.666 + 1.667 +// Handle uint32_ts -- Gonk only speaks int 1.668 +nsresult 1.669 +GonkCameraParameters::SetTranslated(uint32_t aKey, const uint32_t& aValue) 1.670 +{ 1.671 + if (aValue > INT_MAX) { 1.672 + return NS_ERROR_INVALID_ARG; 1.673 + } 1.674 + 1.675 + int val = static_cast<int>(aValue); 1.676 + return SetImpl(aKey, val); 1.677 +} 1.678 + 1.679 +nsresult 1.680 +GonkCameraParameters::GetTranslated(uint32_t aKey, uint32_t& aValue) 1.681 +{ 1.682 + int val; 1.683 + nsresult rv = GetImpl(aKey, val); 1.684 + if (NS_FAILED(rv)) { 1.685 + return rv; 1.686 + } 1.687 + if (val < 0) { 1.688 + return NS_ERROR_FAILURE; 1.689 + } 1.690 + 1.691 + aValue = val; 1.692 + return NS_OK; 1.693 +} 1.694 + 1.695 +// Handle bools 1.696 +nsresult 1.697 +GonkCameraParameters::SetTranslated(uint32_t aKey, const bool& aValue) 1.698 +{ 1.699 + return SetImpl(aKey, aValue); 1.700 +} 1.701 + 1.702 +nsresult 1.703 +GonkCameraParameters::GetTranslated(uint32_t aKey, bool& aValue) 1.704 +{ 1.705 + return GetImpl(aKey, aValue); 1.706 +} 1.707 + 1.708 +nsresult 1.709 +ParseItem(const char* aStart, const char* aEnd, ICameraControl::Size* aItem) 1.710 +{ 1.711 + if (sscanf(aStart, "%ux%u", &aItem->width, &aItem->height) == 2) { 1.712 + return NS_OK; 1.713 + } 1.714 + 1.715 + DOM_CAMERA_LOGE("Size tuple has bad format: '%s'\n", __func__, __LINE__, aStart); 1.716 + return NS_ERROR_FAILURE; 1.717 +} 1.718 + 1.719 +nsresult 1.720 +ParseItem(const char* aStart, const char* aEnd, nsAString* aItem) 1.721 +{ 1.722 + if (aEnd) { 1.723 + aItem->AssignASCII(aStart, aEnd - aStart); 1.724 + } else { 1.725 + aItem->AssignASCII(aStart); 1.726 + } 1.727 + return NS_OK; 1.728 +} 1.729 + 1.730 +nsresult 1.731 +ParseItem(const char* aStart, const char* aEnd, nsACString* aItem) 1.732 +{ 1.733 + if (aEnd) { 1.734 + aItem->AssignASCII(aStart, aEnd - aStart); 1.735 + } else { 1.736 + aItem->AssignASCII(aStart); 1.737 + } 1.738 + return NS_OK; 1.739 +} 1.740 + 1.741 +nsresult 1.742 +ParseItem(const char* aStart, const char* aEnd, double* aItem) 1.743 +{ 1.744 + if (sscanf(aStart, "%lf", aItem) == 1) { 1.745 + return NS_OK; 1.746 + } 1.747 + 1.748 + return NS_ERROR_FAILURE; 1.749 +} 1.750 + 1.751 +nsresult 1.752 +ParseItem(const char* aStart, const char* aEnd, int* aItem) 1.753 +{ 1.754 + if (sscanf(aStart, "%d", aItem) == 1) { 1.755 + return NS_OK; 1.756 + } 1.757 + 1.758 + return NS_ERROR_FAILURE; 1.759 +} 1.760 + 1.761 +template<class T> nsresult 1.762 +GonkCameraParameters::GetListAsArray(uint32_t aKey, nsTArray<T>& aArray) 1.763 +{ 1.764 + const char* p; 1.765 + nsresult rv = GetImpl(aKey, p); 1.766 + if (NS_FAILED(rv)) { 1.767 + return rv; 1.768 + } 1.769 + 1.770 + aArray.Clear(); 1.771 + 1.772 + // If there is no value available, just return the empty array. 1.773 + if (!p) { 1.774 + DOM_CAMERA_LOGI("Camera parameter %d not available (value is null)\n", aKey); 1.775 + return NS_OK; 1.776 + } 1.777 + if (*p == '\0') { 1.778 + DOM_CAMERA_LOGI("Camera parameter %d not available (value is empty string)\n", aKey); 1.779 + return NS_OK; 1.780 + } 1.781 + 1.782 + const char* comma; 1.783 + 1.784 + while (p) { 1.785 + T* v = aArray.AppendElement(); 1.786 + if (!v) { 1.787 + aArray.Clear(); 1.788 + return NS_ERROR_OUT_OF_MEMORY; 1.789 + } 1.790 + comma = strchr(p, ','); 1.791 + if (comma != p) { 1.792 + rv = ParseItem(p, comma, v); 1.793 + if (NS_FAILED(rv)) { 1.794 + aArray.Clear(); 1.795 + return rv; 1.796 + } 1.797 + p = comma; 1.798 + } 1.799 + if (p) { 1.800 + ++p; 1.801 + } 1.802 + } 1.803 + 1.804 + return NS_OK; 1.805 +} 1.806 + 1.807 +nsresult 1.808 +GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<nsString>& aValues) 1.809 +{ 1.810 + if (aKey == CAMERA_PARAM_SUPPORTED_ISOMODES) { 1.811 + aValues = mIsoModes; 1.812 + return NS_OK; 1.813 + } 1.814 + 1.815 + return GetListAsArray(aKey, aValues); 1.816 +} 1.817 + 1.818 +nsresult 1.819 +GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<double>& aValues) 1.820 +{ 1.821 + if (aKey == CAMERA_PARAM_SUPPORTED_ZOOMRATIOS) { 1.822 + aValues.Clear(); 1.823 + for (uint32_t i = 0; i < mZoomRatios.Length(); ++i) { 1.824 + *aValues.AppendElement() = mZoomRatios[i] / 100.0; 1.825 + } 1.826 + return NS_OK; 1.827 + } 1.828 + 1.829 + return GetListAsArray(aKey, aValues); 1.830 +} 1.831 + 1.832 +nsresult 1.833 +GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<ICameraControl::Size>& aSizes) 1.834 +{ 1.835 + return GetListAsArray(aKey, aSizes); 1.836 +} 1.837 +