dom/camera/GonkCameraParameters.cpp

changeset 0
6474c204b198
     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 +

mercurial