Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / dom / camera / GonkCameraParameters.cpp
blob6e5581ebf3f1da50262bcedb252f9581c281777b
1 /*
2 * Copyright (C) 2013-2014 Mozilla Foundation
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "GonkCameraParameters.h"
18 #include "camera/CameraParameters.h"
19 #include "CameraPreferences.h"
20 #include "ICameraControl.h"
21 #include "CameraCommon.h"
22 #include "mozilla/Hal.h"
24 using namespace mozilla;
25 using namespace android;
27 /* static */ bool
28 GonkCameraParameters::IsLowMemoryPlatform()
30 bool testIsLowMem = false;
31 CameraPreferences::GetPref("camera.control.test.is_low_memory", testIsLowMem);
32 if (testIsLowMem) {
33 NS_WARNING("Forcing low-memory platform camera preferences");
34 return true;
37 uint32_t lowMemoryThresholdBytes = 0;
38 CameraPreferences::GetPref("camera.control.low_memory_thresholdMB",
39 lowMemoryThresholdBytes);
40 lowMemoryThresholdBytes *= 1024 * 1024;
41 if (lowMemoryThresholdBytes) {
42 uint32_t totalMemoryBytes = hal::GetTotalSystemMemory();
43 if (totalMemoryBytes < lowMemoryThresholdBytes) {
44 DOM_CAMERA_LOGI("Low-memory platform with %d bytes of RAM (threshold: <%d bytes)\n",
45 totalMemoryBytes, lowMemoryThresholdBytes);
46 return true;
50 return false;
53 /* static */ const char*
54 GonkCameraParameters::Parameters::GetTextKey(uint32_t aKey)
56 switch (aKey) {
57 case CAMERA_PARAM_PREVIEWSIZE:
58 return KEY_PREVIEW_SIZE;
59 case CAMERA_PARAM_PREVIEWFORMAT:
60 return KEY_PREVIEW_FORMAT;
61 case CAMERA_PARAM_PREVIEWFRAMERATE:
62 return KEY_PREVIEW_FRAME_RATE;
63 case CAMERA_PARAM_EFFECT:
64 return KEY_EFFECT;
65 case CAMERA_PARAM_WHITEBALANCE:
66 return KEY_WHITE_BALANCE;
67 case CAMERA_PARAM_SCENEMODE:
68 return KEY_SCENE_MODE;
69 case CAMERA_PARAM_FLASHMODE:
70 return KEY_FLASH_MODE;
71 case CAMERA_PARAM_FOCUSMODE:
72 return KEY_FOCUS_MODE;
73 case CAMERA_PARAM_ZOOM:
74 return KEY_ZOOM;
75 case CAMERA_PARAM_METERINGAREAS:
76 return KEY_METERING_AREAS;
77 case CAMERA_PARAM_FOCUSAREAS:
78 return KEY_FOCUS_AREAS;
79 case CAMERA_PARAM_FOCALLENGTH:
80 return KEY_FOCAL_LENGTH;
81 case CAMERA_PARAM_FOCUSDISTANCENEAR:
82 return KEY_FOCUS_DISTANCES;
83 case CAMERA_PARAM_FOCUSDISTANCEOPTIMUM:
84 return KEY_FOCUS_DISTANCES;
85 case CAMERA_PARAM_FOCUSDISTANCEFAR:
86 return KEY_FOCUS_DISTANCES;
87 case CAMERA_PARAM_EXPOSURECOMPENSATION:
88 return KEY_EXPOSURE_COMPENSATION;
89 case CAMERA_PARAM_THUMBNAILQUALITY:
90 return KEY_JPEG_THUMBNAIL_QUALITY;
91 case CAMERA_PARAM_PICTURE_SIZE:
92 return KEY_PICTURE_SIZE;
93 case CAMERA_PARAM_PICTURE_FILEFORMAT:
94 return KEY_PICTURE_FORMAT;
95 case CAMERA_PARAM_PICTURE_ROTATION:
96 return KEY_ROTATION;
97 case CAMERA_PARAM_PICTURE_DATETIME:
98 // Not every platform defines a KEY_EXIF_DATETIME;
99 // for those that don't, we use the raw string key, and if the platform
100 // doesn't support it, it will be ignored.
102 // See bug 832494.
103 return "exif-datetime";
104 case CAMERA_PARAM_VIDEOSIZE:
105 return KEY_VIDEO_SIZE;
106 case CAMERA_PARAM_ISOMODE:
107 // Not every platform defines KEY_ISO_MODE;
108 // for those that don't, we use the raw string key.
109 return "iso";
110 case CAMERA_PARAM_LUMINANCE:
111 return "luminance-condition";
112 case CAMERA_PARAM_SCENEMODE_HDR_RETURNNORMALPICTURE:
113 // Not every platform defines KEY_QC_HDR_NEED_1X;
114 // for those that don't, we use the raw string key.
115 return "hdr-need-1x";
116 case CAMERA_PARAM_RECORDINGHINT:
117 return KEY_RECORDING_HINT;
118 case CAMERA_PARAM_PICTURE_QUALITY:
119 return KEY_JPEG_QUALITY;
121 case CAMERA_PARAM_SUPPORTED_PREVIEWSIZES:
122 return KEY_SUPPORTED_PREVIEW_SIZES;
123 case CAMERA_PARAM_SUPPORTED_PICTURESIZES:
124 return KEY_SUPPORTED_PICTURE_SIZES;
125 case CAMERA_PARAM_SUPPORTED_VIDEOSIZES:
126 return KEY_SUPPORTED_VIDEO_SIZES;
127 case CAMERA_PARAM_SUPPORTED_PICTUREFORMATS:
128 return KEY_SUPPORTED_PICTURE_FORMATS;
129 case CAMERA_PARAM_SUPPORTED_WHITEBALANCES:
130 return KEY_SUPPORTED_WHITE_BALANCE;
131 case CAMERA_PARAM_SUPPORTED_SCENEMODES:
132 return KEY_SUPPORTED_SCENE_MODES;
133 case CAMERA_PARAM_SUPPORTED_EFFECTS:
134 return KEY_SUPPORTED_EFFECTS;
135 case CAMERA_PARAM_SUPPORTED_FLASHMODES:
136 return KEY_SUPPORTED_FLASH_MODES;
137 case CAMERA_PARAM_SUPPORTED_FOCUSMODES:
138 return KEY_SUPPORTED_FOCUS_MODES;
139 case CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS:
140 return KEY_MAX_NUM_FOCUS_AREAS;
141 case CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS:
142 return KEY_MAX_NUM_METERING_AREAS;
143 case CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION:
144 return KEY_MIN_EXPOSURE_COMPENSATION;
145 case CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION:
146 return KEY_MAX_EXPOSURE_COMPENSATION;
147 case CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP:
148 return KEY_EXPOSURE_COMPENSATION_STEP;
149 case CAMERA_PARAM_SUPPORTED_ZOOM:
150 return KEY_ZOOM_SUPPORTED;
151 case CAMERA_PARAM_SUPPORTED_ZOOMRATIOS:
152 return KEY_ZOOM_RATIOS;
153 case CAMERA_PARAM_SUPPORTED_MAXDETECTEDFACES:
154 return KEY_MAX_NUM_DETECTED_FACES_HW;
155 case CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES:
156 return KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES;
157 case CAMERA_PARAM_SUPPORTED_ISOMODES:
158 // Not every platform defines KEY_SUPPORTED_ISO_MODES;
159 // for those that don't, we use the raw string key.
160 return "iso-values";
161 default:
162 DOM_CAMERA_LOGE("Unhandled camera parameter value %u\n", aKey);
163 return nullptr;
167 GonkCameraParameters::GonkCameraParameters()
168 : mLock(PR_NewRWLock(PR_RWLOCK_RANK_NONE, "GonkCameraParameters.Lock"))
169 , mDirty(false)
170 , mInitialized(false)
171 , mExposureCompensationStep(0.0)
173 MOZ_COUNT_CTOR(GonkCameraParameters);
174 if (!mLock) {
175 MOZ_CRASH("Out of memory getting new PRRWLock");
179 GonkCameraParameters::~GonkCameraParameters()
181 MOZ_COUNT_DTOR(GonkCameraParameters);
182 mIsoModeMap.Clear();
183 MOZ_ASSERT(mLock, "mLock missing in ~GonkCameraParameters()");
184 if (mLock) {
185 PR_DestroyRWLock(mLock);
186 mLock = nullptr;
190 nsresult
191 GonkCameraParameters::MapIsoToGonk(const nsAString& aIso, nsACString& aIsoOut)
193 nsCString* s;
194 if (mIsoModeMap.Get(aIso, &s)) {
195 if (!s) {
196 DOM_CAMERA_LOGE("ISO mode '%s' maps to null Gonk ISO value\n",
197 NS_LossyConvertUTF16toASCII(aIso).get());
198 return NS_ERROR_FAILURE;
201 aIsoOut = *s;
202 return NS_OK;
205 return NS_ERROR_INVALID_ARG;
208 nsresult
209 GonkCameraParameters::MapIsoFromGonk(const char* aIso, nsAString& aIsoOut)
211 if (strcmp(aIso, "ISO_HJR") == 0) {
212 aIsoOut.AssignASCII("hjr");
213 } else if (strcmp(aIso, "auto") == 0) {
214 aIsoOut.AssignASCII("auto");
215 } else {
216 unsigned int iso;
217 char ignored;
218 // Some camera libraries return ISO modes as "ISO100", others as "100".
219 if (sscanf(aIso, "ISO%u%c", &iso, &ignored) != 1 &&
220 sscanf(aIso, "%u%c", &iso, &ignored) != 1) {
221 return NS_ERROR_INVALID_ARG;
223 aIsoOut.Truncate(0);
224 aIsoOut.AppendInt(iso);
227 return NS_OK;
230 // Any members that need to be initialized on the first parameter pull
231 // need to get handled in here.
232 nsresult
233 GonkCameraParameters::Initialize()
235 nsresult rv;
237 rv = GetImpl(Parameters::KEY_EXPOSURE_COMPENSATION_STEP, mExposureCompensationStep);
238 if (NS_FAILED(rv)) {
239 NS_WARNING("Failed to initialize exposure compensation step size");
240 mExposureCompensationStep = 0.0;
242 rv = GetImpl(Parameters::KEY_MIN_EXPOSURE_COMPENSATION, mExposureCompensationMinIndex);
243 if (NS_FAILED(rv)) {
244 NS_WARNING("Failed to initialize minimum exposure compensation index");
245 mExposureCompensationMinIndex = 0;
247 rv = GetImpl(Parameters::KEY_MAX_EXPOSURE_COMPENSATION, mExposureCompensationMaxIndex);
248 if (NS_FAILED(rv)) {
249 NS_WARNING("Failed to initialize maximum exposure compensation index");
250 mExposureCompensationMaxIndex = 0;
253 rv = GetListAsArray(CAMERA_PARAM_SUPPORTED_ZOOMRATIOS, mZoomRatios);
254 if (NS_FAILED(rv)) {
255 // zoom is not supported
256 mZoomRatios.Clear();
258 for (uint32_t i = 1; i < mZoomRatios.Length(); ++i) {
259 // Make sure the camera gave us a properly sorted zoom ratio list!
260 if (mZoomRatios[i] < mZoomRatios[i - 1]) {
261 NS_WARNING("Zoom ratios list is out of order, discarding");
262 DOM_CAMERA_LOGE("zoom[%d]=%fx < zoom[%d]=%fx is out of order\n",
263 i, mZoomRatios[i] / 100.0, i - 1, mZoomRatios[i - 1] / 100.0);
264 mZoomRatios.Clear();
265 break;
268 if (mZoomRatios.Length() == 0) {
269 // Always report that we support at least 1.0x zoom.
270 *mZoomRatios.AppendElement() = 100;
273 // The return code from GetListAsArray() doesn't matter. If it fails,
274 // the isoModes array will be empty, and the subsequent loop won't
275 // execute.
276 nsString s;
277 nsTArray<nsCString> isoModes;
278 GetListAsArray(CAMERA_PARAM_SUPPORTED_ISOMODES, isoModes);
279 for (nsTArray<nsCString>::size_type i = 0; i < isoModes.Length(); ++i) {
280 rv = MapIsoFromGonk(isoModes[i].get(), s);
281 if (NS_FAILED(rv)) {
282 DOM_CAMERA_LOGW("Unrecognized ISO mode value '%s'\n", isoModes[i].get());
283 continue;
285 *mIsoModes.AppendElement() = s;
286 mIsoModeMap.Put(s, new nsCString(isoModes[i]));
289 GetListAsArray(CAMERA_PARAM_SUPPORTED_SCENEMODES, mSceneModes);
290 if (IsLowMemoryPlatform()) {
291 bool hdrRemoved = false;
292 while (mSceneModes.RemoveElement(NS_LITERAL_STRING("hdr"))) {
293 hdrRemoved = true;
295 if (hdrRemoved) {
296 DOM_CAMERA_LOGI("Disabling HDR support due to low memory\n");
300 mInitialized = true;
301 return NS_OK;
304 // Handle nsAStrings
305 nsresult
306 GonkCameraParameters::SetTranslated(uint32_t aKey, const nsAString& aValue)
308 switch (aKey) {
309 case CAMERA_PARAM_ISOMODE:
311 nsAutoCString v;
312 nsresult rv = MapIsoToGonk(aValue, v);
313 if (NS_FAILED(rv)) {
314 return rv;
316 return SetImpl(aKey, v.get());
319 case CAMERA_PARAM_SCENEMODE:
320 if (mSceneModes.IndexOf(aValue) == nsTArray<nsString>::NoIndex) {
321 return NS_ERROR_INVALID_ARG;
323 // fallthrough
325 default:
326 return SetImpl(aKey, NS_ConvertUTF16toUTF8(aValue).get());
330 nsresult
331 GonkCameraParameters::GetTranslated(uint32_t aKey, nsAString& aValue)
333 const char* val;
334 nsresult rv = GetImpl(aKey, val);
335 if (NS_FAILED(rv)) {
336 return rv;
338 if (aKey == CAMERA_PARAM_ISOMODE) {
339 rv = MapIsoFromGonk(val, aValue);
340 } else if(val) {
341 aValue.AssignASCII(val);
342 } else {
343 aValue.Truncate(0);
345 return rv;
348 // Handle ICameraControl::Sizes
349 nsresult
350 GonkCameraParameters::SetTranslated(uint32_t aKey, const ICameraControl::Size& aSize)
352 if (aSize.width > INT_MAX || aSize.height > INT_MAX) {
353 // AOSP can only handle signed ints.
354 DOM_CAMERA_LOGE("Camera parameter aKey=%d out of bounds (width=%u, height=%u)\n",
355 aSize.width, aSize.height);
356 return NS_ERROR_INVALID_ARG;
359 nsresult rv;
361 switch (aKey) {
362 case CAMERA_PARAM_THUMBNAILSIZE:
363 // This is a special case--for some reason the thumbnail size
364 // is accessed as two separate values instead of a tuple.
365 // XXXmikeh - make this restore the original values on error
366 rv = SetImpl(Parameters::KEY_JPEG_THUMBNAIL_WIDTH, static_cast<int>(aSize.width));
367 if (NS_SUCCEEDED(rv)) {
368 rv = SetImpl(Parameters::KEY_JPEG_THUMBNAIL_HEIGHT, static_cast<int>(aSize.height));
370 break;
372 case CAMERA_PARAM_VIDEOSIZE:
373 // "record-size" is probably deprecated in later ICS;
374 // might need to set "video-size" instead of "record-size";
375 // for the time being, set both. See bug 795332.
376 rv = SetImpl("record-size", nsPrintfCString("%ux%u", aSize.width, aSize.height).get());
377 if (NS_FAILED(rv)) {
378 break;
380 // intentional fallthrough
382 default:
383 rv = SetImpl(aKey, nsPrintfCString("%ux%u", aSize.width, aSize.height).get());
384 break;
387 if (NS_FAILED(rv)) {
388 DOM_CAMERA_LOGE("Camera parameter aKey=%d failed to set (0x%x)\n", aKey, rv);
390 return rv;
393 nsresult
394 GonkCameraParameters::GetTranslated(uint32_t aKey, ICameraControl::Size& aSize)
396 nsresult rv;
398 if (aKey == CAMERA_PARAM_THUMBNAILSIZE) {
399 int width;
400 int height;
402 rv = GetImpl(Parameters::KEY_JPEG_THUMBNAIL_WIDTH, width);
403 if (NS_FAILED(rv)) {
404 return rv;
406 if (width < 0) {
407 return NS_ERROR_NOT_AVAILABLE;
409 rv = GetImpl(Parameters::KEY_JPEG_THUMBNAIL_HEIGHT, height);
410 if (NS_FAILED(rv)) {
411 return rv;
413 if (height < 0) {
414 return NS_ERROR_NOT_AVAILABLE;
417 aSize.width = static_cast<uint32_t>(width);
418 aSize.height = static_cast<uint32_t>(height);
419 return NS_OK;
422 const char* value;
423 rv = GetImpl(aKey, value);
424 if (NS_FAILED(rv)) {
425 return rv;
427 if (!value || *value == '\0') {
428 DOM_CAMERA_LOGW("Camera parameter aKey=%d not available\n", aKey);
429 return NS_ERROR_NOT_AVAILABLE;
431 if (sscanf(value, "%ux%u", &aSize.width, &aSize.height) != 2) {
432 DOM_CAMERA_LOGE("Camera parameter aKey=%d size tuple '%s' is invalid\n", aKey, value);
433 return NS_ERROR_NOT_AVAILABLE;
436 return NS_OK;
439 // Handle arrays of ICameraControl::Regions
440 nsresult
441 GonkCameraParameters::SetTranslated(uint32_t aKey, const nsTArray<ICameraControl::Region>& aRegions)
443 uint32_t length = aRegions.Length();
445 if (!length) {
446 // This tells the camera driver to revert to automatic regioning.
447 return SetImpl(aKey, "(0,0,0,0,0)");
450 nsCString s;
452 for (uint32_t i = 0; i < length; ++i) {
453 const ICameraControl::Region* r = &aRegions[i];
454 s.AppendPrintf("(%d,%d,%d,%d,%d),", r->left, r->top, r->right, r->bottom, r->weight);
457 // remove the trailing comma
458 s.Trim(",", false, true, true);
460 return SetImpl(aKey, s.get());
463 nsresult
464 GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<ICameraControl::Region>& aRegions)
466 aRegions.Clear();
468 const char* value;
469 nsresult rv = GetImpl(aKey, value);
470 if (NS_FAILED(rv)) {
471 return rv;
473 if (!value || *value == '\0') {
474 DOM_CAMERA_LOGW("Camera parameter aKey=%d not available\n", aKey);
475 return NS_ERROR_NOT_AVAILABLE;
478 const char* p = value;
479 uint32_t count = 1;
481 // count the number of regions in the string
482 while ((p = strstr(p, "),("))) {
483 ++count;
484 p += 3;
487 aRegions.SetCapacity(count);
488 ICameraControl::Region* r;
490 // parse all of the region sets
491 uint32_t i;
492 for (i = 0, p = value; p && i < count; ++i, p = strchr(p + 1, '(')) {
493 r = aRegions.AppendElement();
494 if (sscanf(p, "(%d,%d,%d,%d,%u)", &r->left, &r->top, &r->right, &r->bottom, &r->weight) != 5) {
495 DOM_CAMERA_LOGE("Camera parameter aKey=%d region tuple has bad format: '%s'\n", aKey, p);
496 aRegions.Clear();
497 return NS_ERROR_NOT_AVAILABLE;
501 return NS_OK;
504 // Handle ICameraControl::Positions
505 nsresult
506 GonkCameraParameters::SetTranslated(uint32_t aKey, const ICameraControl::Position& aPosition)
508 MOZ_ASSERT(aKey == CAMERA_PARAM_PICTURE_LOCATION);
510 // Add any specified location information -- we don't care if these fail.
511 if (!isnan(aPosition.latitude)) {
512 DOM_CAMERA_LOGI("setting picture latitude to %lf\n", aPosition.latitude);
513 SetImpl(Parameters::KEY_GPS_LATITUDE, nsPrintfCString("%lf", aPosition.latitude).get());
515 if (!isnan(aPosition.longitude)) {
516 DOM_CAMERA_LOGI("setting picture longitude to %lf\n", aPosition.longitude);
517 SetImpl(Parameters::KEY_GPS_LONGITUDE, nsPrintfCString("%lf", aPosition.longitude).get());
519 if (!isnan(aPosition.altitude)) {
520 DOM_CAMERA_LOGI("setting picture altitude to %lf\n", aPosition.altitude);
521 SetImpl(Parameters::KEY_GPS_ALTITUDE, nsPrintfCString("%lf", aPosition.altitude).get());
523 if (!isnan(aPosition.timestamp)) {
524 DOM_CAMERA_LOGI("setting picture timestamp to %lf\n", aPosition.timestamp);
525 SetImpl(Parameters::KEY_GPS_TIMESTAMP, nsPrintfCString("%lf", aPosition.timestamp).get());
528 return NS_OK;
531 // Handle int64_ts
532 nsresult
533 GonkCameraParameters::SetTranslated(uint32_t aKey, const int64_t& aValue)
535 switch (aKey) {
536 case CAMERA_PARAM_PICTURE_DATETIME:
538 // Add the non-GPS timestamp. The EXIF date/time field is formatted as
539 // "YYYY:MM:DD HH:MM:SS", without room for a time-zone; as such, the time
540 // is meant to be stored as a local time. Since we are given seconds from
541 // Epoch GMT, we use localtime_r() to handle the conversion.
542 time_t time = aValue;
543 if (time != aValue) {
544 DOM_CAMERA_LOGE("picture date/time '%llu' is too far in the future\n", aValue);
545 return NS_ERROR_INVALID_ARG;
548 struct tm t;
549 if (!localtime_r(&time, &t)) {
550 DOM_CAMERA_LOGE("picture date/time couldn't be converted to local time: (%d) %s\n", errno, strerror(errno));
551 return NS_ERROR_FAILURE;
554 char dateTime[20];
555 if (!strftime(dateTime, sizeof(dateTime), "%Y:%m:%d %T", &t)) {
556 DOM_CAMERA_LOGE("picture date/time couldn't be converted to string\n");
557 return NS_ERROR_FAILURE;
560 DOM_CAMERA_LOGI("setting picture date/time to %s\n", dateTime);
562 return SetImpl(CAMERA_PARAM_PICTURE_DATETIME, dateTime);
565 case CAMERA_PARAM_ISOMODE:
567 if (aValue > INT32_MAX) {
568 DOM_CAMERA_LOGW("Can't set ISO mode = %lld, too big\n", aValue);
569 return NS_ERROR_INVALID_ARG;
572 nsString s;
573 s.AppendInt(aValue);
574 return SetTranslated(CAMERA_PARAM_ISOMODE, s);
578 // You can't actually pass 64-bit parameters to Gonk. :(
579 int32_t v = static_cast<int32_t>(aValue);
580 if (static_cast<int64_t>(v) != aValue) {
581 return NS_ERROR_INVALID_ARG;;
583 return SetImpl(aKey, v);
586 nsresult
587 GonkCameraParameters::GetTranslated(uint32_t aKey, int64_t& aValue)
589 int val;
590 nsresult rv = GetImpl(aKey, val);
591 if (NS_FAILED(rv)) {
592 return rv;
594 aValue = val;
595 return NS_OK;
598 // Handle doubles
599 nsresult
600 GonkCameraParameters::SetTranslated(uint32_t aKey, const double& aValue)
602 int index;
603 int value;
605 switch (aKey) {
606 case CAMERA_PARAM_EXPOSURECOMPENSATION:
607 if (mExposureCompensationStep == 0.0) {
608 DOM_CAMERA_LOGE("Exposure compensation not supported, can't set EV=%f\n", aValue);
609 return NS_ERROR_NOT_AVAILABLE;
613 * Convert from real value to a Gonk index, round
614 * to the nearest step; index is 1-based.
617 double i = round(aValue / mExposureCompensationStep);
618 if (i < mExposureCompensationMinIndex) {
619 index = mExposureCompensationMinIndex;
620 } else if (i > mExposureCompensationMaxIndex) {
621 index = mExposureCompensationMaxIndex;
622 } else {
623 index = i;
626 DOM_CAMERA_LOGI("Exposure compensation = %f --> index = %d\n", aValue, index);
627 return SetImpl(CAMERA_PARAM_EXPOSURECOMPENSATION, index);
629 case CAMERA_PARAM_ZOOM:
632 * Convert from a real zoom multipler (e.g. 2.5x) to
633 * the index of the nearest supported value.
635 value = aValue * 100.0;
637 if (value <= mZoomRatios[0]) {
638 index = 0;
639 } else if (value >= mZoomRatios.LastElement()) {
640 index = mZoomRatios.Length() - 1;
641 } else {
642 // mZoomRatios is sorted, so we can binary search it
643 int bottom = 0;
644 int top = mZoomRatios.Length() - 1;
646 while (top >= bottom) {
647 index = (top + bottom) / 2;
648 if (value == mZoomRatios[index]) {
649 // exact match
650 break;
652 if (value > mZoomRatios[index] && value < mZoomRatios[index + 1]) {
653 // the specified zoom value lies in this interval
654 break;
656 if (value > mZoomRatios[index]) {
657 bottom = index + 1;
658 } else {
659 top = index - 1;
663 DOM_CAMERA_LOGI("Zoom = %fx --> index = %d\n", aValue, index);
665 return SetImpl(CAMERA_PARAM_ZOOM, index);
667 case CAMERA_PARAM_PICTURE_QUALITY:
669 // Convert aValue [0.0..1.0] to nearest index in the range [1..100].
670 index = (aValue + 0.005) * 99.0 + 1.0;
671 if (aValue < 0.0) {
672 index = 1;
673 } else if (aValue > 1.0) {
674 index = 100;
676 DOM_CAMERA_LOGI("Picture quality = %f --> index = %d\n", aValue, index);
678 return SetImpl(CAMERA_PARAM_PICTURE_QUALITY, index);
681 return SetImpl(aKey, aValue);
684 nsresult
685 GonkCameraParameters::GetTranslated(uint32_t aKey, double& aValue)
687 double val = 0.0; // initialize to keep the compiler happy [-Wmaybe-uninitialized]
688 int index = 0;
689 double focusDistance[3];
690 const char* s;
691 nsresult rv;
693 switch (aKey) {
694 case CAMERA_PARAM_ZOOM:
695 rv = GetImpl(aKey, index);
696 if (NS_SUCCEEDED(rv) && index >= 0) {
697 val = mZoomRatios[index] / 100.0;
698 } else {
699 // return 1x when zooming is not supported
700 val = 1.0;
701 rv = NS_OK;
703 break;
706 * The gonk camera parameters API only exposes one focus distance property
707 * that contains "Near,Optimum,Far" distances, in metres, where 'Far' may
708 * be 'Infinity'.
710 case CAMERA_PARAM_FOCUSDISTANCEFAR:
711 ++index;
712 // intentional fallthrough
714 case CAMERA_PARAM_FOCUSDISTANCEOPTIMUM:
715 ++index;
716 // intentional fallthrough
718 case CAMERA_PARAM_FOCUSDISTANCENEAR:
719 rv = GetImpl(aKey, s);
720 if (NS_SUCCEEDED(rv)) {
721 if (sscanf(s, "%lf,%lf,%lf", &focusDistance[0], &focusDistance[1], &focusDistance[2]) == 3) {
722 val = focusDistance[index];
723 } else {
724 val = 0.0;
727 break;
729 case CAMERA_PARAM_EXPOSURECOMPENSATION:
730 case CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION:
731 case CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION:
732 if (mExposureCompensationStep == 0.0) {
733 DOM_CAMERA_LOGE("Exposure compensation not supported, can't get EV\n");
734 return NS_ERROR_NOT_AVAILABLE;
736 rv = GetImpl(aKey, index);
737 if (NS_SUCCEEDED(rv)) {
738 val = index * mExposureCompensationStep;
739 DOM_CAMERA_LOGI("exposure compensation (aKey=%d): index=%d --> EV=%f\n", aKey, index, val);
741 break;
743 case CAMERA_PARAM_PICTURE_QUALITY:
744 // Convert index [1..100] to a quality value [0.0..1.0].
745 rv = GetImpl(aKey, index);
746 if (index < 2) {
747 val = 0.0;
748 } else if (index > 99) {
749 val = 1.0;
750 } else {
751 val = static_cast<double>(index - 1) / 99.0;
753 DOM_CAMERA_LOGI("index = %d --> picture quality = %f\n", index, val);
754 break;
756 default:
757 rv = GetImpl(aKey, val);
758 break;
761 if (NS_SUCCEEDED(rv)) {
762 aValue = val;
764 return rv;
767 // Handle ints
768 nsresult
769 GonkCameraParameters::SetTranslated(uint32_t aKey, const int& aValue)
771 return SetImpl(aKey, aValue);
774 nsresult
775 GonkCameraParameters::GetTranslated(uint32_t aKey, int& aValue)
777 return GetImpl(aKey, aValue);
780 // Handle uint32_ts -- Gonk only speaks int
781 nsresult
782 GonkCameraParameters::SetTranslated(uint32_t aKey, const uint32_t& aValue)
784 if (aValue > INT_MAX) {
785 return NS_ERROR_INVALID_ARG;
788 int val = static_cast<int>(aValue);
789 return SetImpl(aKey, val);
792 nsresult
793 GonkCameraParameters::GetTranslated(uint32_t aKey, uint32_t& aValue)
795 int val;
796 nsresult rv = GetImpl(aKey, val);
797 if (NS_FAILED(rv)) {
798 return rv;
800 if (val < 0) {
801 return NS_ERROR_NOT_AVAILABLE;
804 aValue = val;
805 return NS_OK;
808 // Handle bools
809 nsresult
810 GonkCameraParameters::SetTranslated(uint32_t aKey, const bool& aValue)
812 return SetImpl(aKey, aValue);
815 nsresult
816 GonkCameraParameters::GetTranslated(uint32_t aKey, bool& aValue)
818 return GetImpl(aKey, aValue);
821 nsresult
822 ParseItem(const char* aStart, const char* aEnd, ICameraControl::Size* aItem)
824 if (sscanf(aStart, "%ux%u", &aItem->width, &aItem->height) == 2) {
825 return NS_OK;
828 DOM_CAMERA_LOGE("Size tuple has bad format: '%s'\n", aStart);
829 return NS_ERROR_NOT_AVAILABLE;
832 nsresult
833 ParseItem(const char* aStart, const char* aEnd, nsAString* aItem)
835 if (aEnd) {
836 aItem->AssignASCII(aStart, aEnd - aStart);
837 } else {
838 aItem->AssignASCII(aStart);
840 return NS_OK;
843 nsresult
844 ParseItem(const char* aStart, const char* aEnd, nsACString* aItem)
846 if (aEnd) {
847 aItem->AssignASCII(aStart, aEnd - aStart);
848 } else {
849 aItem->AssignASCII(aStart);
851 return NS_OK;
854 nsresult
855 ParseItem(const char* aStart, const char* aEnd, double* aItem)
857 if (sscanf(aStart, "%lf", aItem) == 1) {
858 return NS_OK;
861 return NS_ERROR_NOT_AVAILABLE;
864 nsresult
865 ParseItem(const char* aStart, const char* aEnd, int* aItem)
867 if (sscanf(aStart, "%d", aItem) == 1) {
868 return NS_OK;
871 return NS_ERROR_NOT_AVAILABLE;
874 template<class T> nsresult
875 GonkCameraParameters::GetListAsArray(uint32_t aKey, nsTArray<T>& aArray)
877 const char* p;
878 nsresult rv = GetImpl(aKey, p);
879 if (NS_FAILED(rv)) {
880 return rv;
883 aArray.Clear();
885 // If there is no value available, just return the empty array.
886 if (!p) {
887 DOM_CAMERA_LOGI("Camera parameter %d not available (value is null)\n", aKey);
888 return NS_OK;
890 if (*p == '\0') {
891 DOM_CAMERA_LOGI("Camera parameter %d not available (value is empty string)\n", aKey);
892 return NS_OK;
895 const char* comma;
897 while (p) {
898 // nsTArray::AppendElement() is infallible
899 T* v = aArray.AppendElement();
900 comma = strchr(p, ',');
901 if (comma != p) {
902 rv = ParseItem(p, comma, v);
903 if (NS_FAILED(rv)) {
904 aArray.Clear();
905 return rv;
907 p = comma;
909 if (p) {
910 ++p;
914 return NS_OK;
917 nsresult
918 GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<nsString>& aValues)
920 switch (aKey) {
921 case CAMERA_PARAM_SUPPORTED_ISOMODES:
922 aValues = mIsoModes;
923 return NS_OK;
925 case CAMERA_PARAM_SUPPORTED_SCENEMODES:
926 aValues = mSceneModes;
927 return NS_OK;
929 default:
930 return GetListAsArray(aKey, aValues);
934 nsresult
935 GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<double>& aValues)
937 if (aKey == CAMERA_PARAM_SUPPORTED_ZOOMRATIOS) {
938 aValues.Clear();
939 for (uint32_t i = 0; i < mZoomRatios.Length(); ++i) {
940 *aValues.AppendElement() = mZoomRatios[i] / 100.0;
942 return NS_OK;
945 return GetListAsArray(aKey, aValues);
948 nsresult
949 GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<ICameraControl::Size>& aSizes)
951 return GetListAsArray(aKey, aSizes);