|
1 /* |
|
2 * Copyright (C) 2013-2014 Mozilla Foundation |
|
3 * |
|
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 |
|
7 * |
|
8 * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 * |
|
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. |
|
15 */ |
|
16 |
|
17 #include "GonkCameraParameters.h" |
|
18 #include "camera/CameraParameters.h" |
|
19 #include "ICameraControl.h" |
|
20 #include "CameraCommon.h" |
|
21 |
|
22 using namespace mozilla; |
|
23 using namespace android; |
|
24 |
|
25 /* static */ const char* |
|
26 GonkCameraParameters::Parameters::GetTextKey(uint32_t aKey) |
|
27 { |
|
28 switch (aKey) { |
|
29 case CAMERA_PARAM_PREVIEWSIZE: |
|
30 return KEY_PREVIEW_SIZE; |
|
31 case CAMERA_PARAM_PREVIEWFORMAT: |
|
32 return KEY_PREVIEW_FORMAT; |
|
33 case CAMERA_PARAM_PREVIEWFRAMERATE: |
|
34 return KEY_PREVIEW_FRAME_RATE; |
|
35 case CAMERA_PARAM_EFFECT: |
|
36 return KEY_EFFECT; |
|
37 case CAMERA_PARAM_WHITEBALANCE: |
|
38 return KEY_WHITE_BALANCE; |
|
39 case CAMERA_PARAM_SCENEMODE: |
|
40 return KEY_SCENE_MODE; |
|
41 case CAMERA_PARAM_FLASHMODE: |
|
42 return KEY_FLASH_MODE; |
|
43 case CAMERA_PARAM_FOCUSMODE: |
|
44 return KEY_FOCUS_MODE; |
|
45 case CAMERA_PARAM_ZOOM: |
|
46 return KEY_ZOOM; |
|
47 case CAMERA_PARAM_METERINGAREAS: |
|
48 return KEY_METERING_AREAS; |
|
49 case CAMERA_PARAM_FOCUSAREAS: |
|
50 return KEY_FOCUS_AREAS; |
|
51 case CAMERA_PARAM_FOCALLENGTH: |
|
52 return KEY_FOCAL_LENGTH; |
|
53 case CAMERA_PARAM_FOCUSDISTANCENEAR: |
|
54 return KEY_FOCUS_DISTANCES; |
|
55 case CAMERA_PARAM_FOCUSDISTANCEOPTIMUM: |
|
56 return KEY_FOCUS_DISTANCES; |
|
57 case CAMERA_PARAM_FOCUSDISTANCEFAR: |
|
58 return KEY_FOCUS_DISTANCES; |
|
59 case CAMERA_PARAM_EXPOSURECOMPENSATION: |
|
60 return KEY_EXPOSURE_COMPENSATION; |
|
61 case CAMERA_PARAM_THUMBNAILQUALITY: |
|
62 return KEY_JPEG_THUMBNAIL_QUALITY; |
|
63 case CAMERA_PARAM_PICTURE_SIZE: |
|
64 return KEY_PICTURE_SIZE; |
|
65 case CAMERA_PARAM_PICTURE_FILEFORMAT: |
|
66 return KEY_PICTURE_FORMAT; |
|
67 case CAMERA_PARAM_PICTURE_ROTATION: |
|
68 return KEY_ROTATION; |
|
69 case CAMERA_PARAM_PICTURE_DATETIME: |
|
70 // Not every platform defines a KEY_EXIF_DATETIME; |
|
71 // for those that don't, we use the raw string key, and if the platform |
|
72 // doesn't support it, it will be ignored. |
|
73 // |
|
74 // See bug 832494. |
|
75 return "exif-datetime"; |
|
76 case CAMERA_PARAM_VIDEOSIZE: |
|
77 return KEY_VIDEO_SIZE; |
|
78 case CAMERA_PARAM_ISOMODE: |
|
79 // Not every platform defines KEY_ISO_MODE; |
|
80 // for those that don't, we use the raw string key. |
|
81 return "iso"; |
|
82 case CAMERA_PARAM_LUMINANCE: |
|
83 return "luminance-condition"; |
|
84 case CAMERA_PARAM_SCENEMODE_HDR_RETURNNORMALPICTURE: |
|
85 // Not every platform defines KEY_QC_HDR_NEED_1X; |
|
86 // for those that don't, we use the raw string key. |
|
87 return "hdr-need-1x"; |
|
88 |
|
89 case CAMERA_PARAM_SUPPORTED_PREVIEWSIZES: |
|
90 return KEY_SUPPORTED_PREVIEW_SIZES; |
|
91 case CAMERA_PARAM_SUPPORTED_PICTURESIZES: |
|
92 return KEY_SUPPORTED_PICTURE_SIZES; |
|
93 case CAMERA_PARAM_SUPPORTED_VIDEOSIZES: |
|
94 return KEY_SUPPORTED_VIDEO_SIZES; |
|
95 case CAMERA_PARAM_SUPPORTED_PICTUREFORMATS: |
|
96 return KEY_SUPPORTED_PICTURE_FORMATS; |
|
97 case CAMERA_PARAM_SUPPORTED_WHITEBALANCES: |
|
98 return KEY_SUPPORTED_WHITE_BALANCE; |
|
99 case CAMERA_PARAM_SUPPORTED_SCENEMODES: |
|
100 return KEY_SUPPORTED_SCENE_MODES; |
|
101 case CAMERA_PARAM_SUPPORTED_EFFECTS: |
|
102 return KEY_SUPPORTED_EFFECTS; |
|
103 case CAMERA_PARAM_SUPPORTED_FLASHMODES: |
|
104 return KEY_SUPPORTED_FLASH_MODES; |
|
105 case CAMERA_PARAM_SUPPORTED_FOCUSMODES: |
|
106 return KEY_SUPPORTED_FOCUS_MODES; |
|
107 case CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS: |
|
108 return KEY_MAX_NUM_FOCUS_AREAS; |
|
109 case CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS: |
|
110 return KEY_MAX_NUM_METERING_AREAS; |
|
111 case CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION: |
|
112 return KEY_MIN_EXPOSURE_COMPENSATION; |
|
113 case CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION: |
|
114 return KEY_MAX_EXPOSURE_COMPENSATION; |
|
115 case CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP: |
|
116 return KEY_EXPOSURE_COMPENSATION_STEP; |
|
117 case CAMERA_PARAM_SUPPORTED_ZOOM: |
|
118 return KEY_ZOOM_SUPPORTED; |
|
119 case CAMERA_PARAM_SUPPORTED_ZOOMRATIOS: |
|
120 return KEY_ZOOM_RATIOS; |
|
121 case CAMERA_PARAM_SUPPORTED_MAXDETECTEDFACES: |
|
122 return KEY_MAX_NUM_DETECTED_FACES_HW; |
|
123 case CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES: |
|
124 return KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES; |
|
125 case CAMERA_PARAM_SUPPORTED_ISOMODES: |
|
126 // Not every platform defines KEY_SUPPORTED_ISO_MODES; |
|
127 // for those that don't, we use the raw string key. |
|
128 return "iso-values"; |
|
129 default: |
|
130 DOM_CAMERA_LOGE("Unhandled camera parameter value %u\n", aKey); |
|
131 return nullptr; |
|
132 } |
|
133 } |
|
134 |
|
135 GonkCameraParameters::GonkCameraParameters() |
|
136 : mLock(PR_NewRWLock(PR_RWLOCK_RANK_NONE, "GonkCameraParameters.Lock")) |
|
137 , mDirty(false) |
|
138 , mInitialized(false) |
|
139 { |
|
140 MOZ_COUNT_CTOR(GonkCameraParameters); |
|
141 if (!mLock) { |
|
142 MOZ_CRASH("OOM getting new PRRWLock"); |
|
143 } |
|
144 } |
|
145 |
|
146 GonkCameraParameters::~GonkCameraParameters() |
|
147 { |
|
148 MOZ_COUNT_DTOR(GonkCameraParameters); |
|
149 if (mLock) { |
|
150 PR_DestroyRWLock(mLock); |
|
151 mLock = nullptr; |
|
152 } |
|
153 } |
|
154 |
|
155 nsresult |
|
156 GonkCameraParameters::MapIsoToGonk(const nsAString& aIso, nsACString& aIsoOut) |
|
157 { |
|
158 if (aIso.EqualsASCII("hjr")) { |
|
159 aIsoOut = "ISO_HJR"; |
|
160 } else if (aIso.EqualsASCII("auto")) { |
|
161 aIsoOut = "auto"; |
|
162 } else { |
|
163 nsAutoCString v = NS_LossyConvertUTF16toASCII(aIso); |
|
164 unsigned int iso; |
|
165 if (sscanf(v.get(), "%u", &iso) != 1) { |
|
166 return NS_ERROR_FAILURE; |
|
167 } |
|
168 aIsoOut = nsPrintfCString("ISO%u", iso); |
|
169 } |
|
170 |
|
171 return NS_OK; |
|
172 } |
|
173 |
|
174 nsresult |
|
175 GonkCameraParameters::MapIsoFromGonk(const char* aIso, nsAString& aIsoOut) |
|
176 { |
|
177 if (strcmp(aIso, "ISO_HJR") == 0) { |
|
178 aIsoOut.AssignASCII("hjr"); |
|
179 } else if (strcmp(aIso, "auto") == 0) { |
|
180 aIsoOut.AssignASCII("auto"); |
|
181 } else { |
|
182 unsigned int iso; |
|
183 if (sscanf(aIso, "ISO%u", &iso) != 1) { |
|
184 return NS_ERROR_FAILURE; |
|
185 } |
|
186 aIsoOut.AppendInt(iso); |
|
187 } |
|
188 |
|
189 return NS_OK; |
|
190 } |
|
191 |
|
192 // Any members that need to be initialized on the first parameter pull |
|
193 // need to get handled in here. |
|
194 nsresult |
|
195 GonkCameraParameters::Initialize() |
|
196 { |
|
197 nsresult rv; |
|
198 |
|
199 rv = GetImpl(CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION, mExposureCompensationMin); |
|
200 if (NS_FAILED(rv)) { |
|
201 NS_WARNING("Failed to initialize minimum exposure compensation"); |
|
202 mExposureCompensationMin = 0; |
|
203 } |
|
204 rv = GetImpl(CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP, mExposureCompensationStep); |
|
205 if (NS_FAILED(rv)) { |
|
206 NS_WARNING("Failed to initialize exposure compensation step size"); |
|
207 mExposureCompensationStep = 0; |
|
208 } |
|
209 |
|
210 rv = GetListAsArray(CAMERA_PARAM_SUPPORTED_ZOOMRATIOS, mZoomRatios); |
|
211 if (NS_FAILED(rv)) { |
|
212 // zoom is not supported |
|
213 mZoomRatios.Clear(); |
|
214 } |
|
215 for (uint32_t i = 1; i < mZoomRatios.Length(); ++i) { |
|
216 // Make sure the camera gave us a properly sorted zoom ratio list! |
|
217 if (mZoomRatios[i] < mZoomRatios[i - 1]) { |
|
218 NS_WARNING("Zoom ratios list is out of order, discarding"); |
|
219 DOM_CAMERA_LOGE("zoom[%d]=%fx < zoom[%d]=%fx is out of order\n", |
|
220 i, mZoomRatios[i] / 100.0, i - 1, mZoomRatios[i - 1] / 100.0); |
|
221 mZoomRatios.Clear(); |
|
222 break; |
|
223 } |
|
224 } |
|
225 if (mZoomRatios.Length() == 0) { |
|
226 // Always report that we support at least 1.0x zoom. |
|
227 *mZoomRatios.AppendElement() = 100; |
|
228 } |
|
229 |
|
230 // The return code from GetListAsArray() doesn't matter. If it fails, |
|
231 // the isoModes array will be empty, and the subsequent loop won't |
|
232 // execute. |
|
233 nsTArray<nsCString> isoModes; |
|
234 GetListAsArray(CAMERA_PARAM_SUPPORTED_ISOMODES, isoModes); |
|
235 for (uint32_t i = 0; i < isoModes.Length(); ++i) { |
|
236 nsString v; |
|
237 rv = MapIsoFromGonk(isoModes[i].get(), v); |
|
238 if (NS_SUCCEEDED(rv)) { |
|
239 *mIsoModes.AppendElement() = v; |
|
240 } |
|
241 } |
|
242 |
|
243 mInitialized = true; |
|
244 return NS_OK; |
|
245 } |
|
246 |
|
247 // Handle nsAStrings |
|
248 nsresult |
|
249 GonkCameraParameters::SetTranslated(uint32_t aKey, const nsAString& aValue) |
|
250 { |
|
251 if (aKey == CAMERA_PARAM_ISOMODE) { |
|
252 nsAutoCString v; |
|
253 nsresult rv = MapIsoToGonk(aValue, v); |
|
254 if (NS_FAILED(rv)) { |
|
255 return rv; |
|
256 } |
|
257 return SetImpl(aKey, v.get()); |
|
258 } |
|
259 |
|
260 return SetImpl(aKey, NS_ConvertUTF16toUTF8(aValue).get()); |
|
261 } |
|
262 |
|
263 nsresult |
|
264 GonkCameraParameters::GetTranslated(uint32_t aKey, nsAString& aValue) |
|
265 { |
|
266 const char* val; |
|
267 nsresult rv = GetImpl(aKey, val); |
|
268 if (NS_FAILED(rv)) { |
|
269 return rv; |
|
270 } |
|
271 if (aKey == CAMERA_PARAM_ISOMODE) { |
|
272 rv = MapIsoFromGonk(val, aValue); |
|
273 } else if(val) { |
|
274 aValue.AssignASCII(val); |
|
275 } else { |
|
276 aValue.Truncate(0); |
|
277 } |
|
278 return rv; |
|
279 } |
|
280 |
|
281 // Handle ICameraControl::Sizes |
|
282 nsresult |
|
283 GonkCameraParameters::SetTranslated(uint32_t aKey, const ICameraControl::Size& aSize) |
|
284 { |
|
285 if (aSize.width > INT_MAX || aSize.height > INT_MAX) { |
|
286 // AOSP can only handle signed ints. |
|
287 DOM_CAMERA_LOGE("Camera parameter aKey=%d out of bounds (width=%u, height=%u)\n", |
|
288 aSize.width, aSize.height); |
|
289 return NS_ERROR_INVALID_ARG; |
|
290 } |
|
291 |
|
292 nsresult rv; |
|
293 |
|
294 switch (aKey) { |
|
295 case CAMERA_PARAM_THUMBNAILSIZE: |
|
296 // This is a special case--for some reason the thumbnail size |
|
297 // is accessed as two separate values instead of a tuple. |
|
298 // XXXmikeh - make this restore the original values on error |
|
299 rv = SetImpl(Parameters::KEY_JPEG_THUMBNAIL_WIDTH, static_cast<int>(aSize.width)); |
|
300 if (NS_SUCCEEDED(rv)) { |
|
301 rv = SetImpl(Parameters::KEY_JPEG_THUMBNAIL_HEIGHT, static_cast<int>(aSize.height)); |
|
302 } |
|
303 break; |
|
304 |
|
305 case CAMERA_PARAM_VIDEOSIZE: |
|
306 // "record-size" is probably deprecated in later ICS; |
|
307 // might need to set "video-size" instead of "record-size"; |
|
308 // for the time being, set both. See bug 795332. |
|
309 rv = SetImpl("record-size", nsPrintfCString("%ux%u", aSize.width, aSize.height).get()); |
|
310 if (NS_FAILED(rv)) { |
|
311 break; |
|
312 } |
|
313 // intentional fallthrough |
|
314 |
|
315 default: |
|
316 rv = SetImpl(aKey, nsPrintfCString("%ux%u", aSize.width, aSize.height).get()); |
|
317 break; |
|
318 } |
|
319 |
|
320 if (NS_FAILED(rv)) { |
|
321 DOM_CAMERA_LOGE("Camera parameter aKey=%d failed to set (0x%x)\n", aKey, rv); |
|
322 } |
|
323 return rv; |
|
324 } |
|
325 |
|
326 nsresult |
|
327 GonkCameraParameters::GetTranslated(uint32_t aKey, ICameraControl::Size& aSize) |
|
328 { |
|
329 nsresult rv; |
|
330 |
|
331 if (aKey == CAMERA_PARAM_THUMBNAILSIZE) { |
|
332 int width; |
|
333 int height; |
|
334 |
|
335 rv = GetImpl(Parameters::KEY_JPEG_THUMBNAIL_WIDTH, width); |
|
336 if (NS_FAILED(rv) || width < 0) { |
|
337 return NS_ERROR_FAILURE; |
|
338 } |
|
339 rv = GetImpl(Parameters::KEY_JPEG_THUMBNAIL_HEIGHT, height); |
|
340 if (NS_FAILED(rv) || height < 0) { |
|
341 return NS_ERROR_FAILURE; |
|
342 } |
|
343 |
|
344 aSize.width = static_cast<uint32_t>(width); |
|
345 aSize.height = static_cast<uint32_t>(height); |
|
346 return NS_OK; |
|
347 } |
|
348 |
|
349 const char* value; |
|
350 rv = GetImpl(aKey, value); |
|
351 if (NS_FAILED(rv) || !value || *value == '\0') { |
|
352 DOM_CAMERA_LOGW("Camera parameter aKey=%d not available (0x%x)\n", aKey, rv); |
|
353 return NS_ERROR_NOT_AVAILABLE; |
|
354 } |
|
355 if (sscanf(value, "%ux%u", &aSize.width, &aSize.height) != 2) { |
|
356 DOM_CAMERA_LOGE("Camera parameter aKey=%d size tuple '%s' is invalid\n", aKey, value); |
|
357 return NS_ERROR_FAILURE; |
|
358 } |
|
359 return NS_OK; |
|
360 } |
|
361 |
|
362 // Handle arrays of ICameraControl::Regions |
|
363 nsresult |
|
364 GonkCameraParameters::SetTranslated(uint32_t aKey, const nsTArray<ICameraControl::Region>& aRegions) |
|
365 { |
|
366 uint32_t length = aRegions.Length(); |
|
367 |
|
368 if (!length) { |
|
369 // This tells the camera driver to revert to automatic regioning. |
|
370 return SetImpl(aKey, "(0,0,0,0,0)"); |
|
371 } |
|
372 |
|
373 nsCString s; |
|
374 |
|
375 for (uint32_t i = 0; i < length; ++i) { |
|
376 const ICameraControl::Region* r = &aRegions[i]; |
|
377 s.AppendPrintf("(%d,%d,%d,%d,%d),", r->top, r->left, r->bottom, r->right, r->weight); |
|
378 } |
|
379 |
|
380 // remove the trailing comma |
|
381 s.Trim(",", false, true, true); |
|
382 |
|
383 return SetImpl(aKey, s.get()); |
|
384 } |
|
385 |
|
386 nsresult |
|
387 GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<ICameraControl::Region>& aRegions) |
|
388 { |
|
389 aRegions.Clear(); |
|
390 |
|
391 const char* value; |
|
392 nsresult rv = GetImpl(aKey, value); |
|
393 if (NS_FAILED(rv) || !value || *value == '\0') { |
|
394 return NS_ERROR_FAILURE; |
|
395 } |
|
396 |
|
397 const char* p = value; |
|
398 uint32_t count = 1; |
|
399 |
|
400 // count the number of regions in the string |
|
401 while ((p = strstr(p, "),("))) { |
|
402 ++count; |
|
403 p += 3; |
|
404 } |
|
405 |
|
406 aRegions.SetCapacity(count); |
|
407 ICameraControl::Region* r; |
|
408 |
|
409 // parse all of the region sets |
|
410 uint32_t i; |
|
411 for (i = 0, p = value; p && i < count; ++i, p = strchr(p + 1, '(')) { |
|
412 r = aRegions.AppendElement(); |
|
413 if (sscanf(p, "(%d,%d,%d,%d,%u)", &r->top, &r->left, &r->bottom, &r->right, &r->weight) != 5) { |
|
414 DOM_CAMERA_LOGE("%s:%d : region tuple has bad format: '%s'\n", __func__, __LINE__, p); |
|
415 aRegions.Clear(); |
|
416 return NS_ERROR_FAILURE; |
|
417 } |
|
418 } |
|
419 |
|
420 return NS_OK; |
|
421 } |
|
422 |
|
423 // Handle ICameraControl::Positions |
|
424 nsresult |
|
425 GonkCameraParameters::SetTranslated(uint32_t aKey, const ICameraControl::Position& aPosition) |
|
426 { |
|
427 MOZ_ASSERT(aKey == CAMERA_PARAM_PICTURE_LOCATION); |
|
428 |
|
429 // Add any specified location information -- we don't care if these fail. |
|
430 if (!isnan(aPosition.latitude)) { |
|
431 DOM_CAMERA_LOGI("setting picture latitude to %lf\n", aPosition.latitude); |
|
432 SetImpl(Parameters::KEY_GPS_LATITUDE, nsPrintfCString("%lf", aPosition.latitude).get()); |
|
433 } |
|
434 if (!isnan(aPosition.longitude)) { |
|
435 DOM_CAMERA_LOGI("setting picture longitude to %lf\n", aPosition.longitude); |
|
436 SetImpl(Parameters::KEY_GPS_LONGITUDE, nsPrintfCString("%lf", aPosition.longitude).get()); |
|
437 } |
|
438 if (!isnan(aPosition.altitude)) { |
|
439 DOM_CAMERA_LOGI("setting picture altitude to %lf\n", aPosition.altitude); |
|
440 SetImpl(Parameters::KEY_GPS_ALTITUDE, nsPrintfCString("%lf", aPosition.altitude).get()); |
|
441 } |
|
442 if (!isnan(aPosition.timestamp)) { |
|
443 DOM_CAMERA_LOGI("setting picture timestamp to %lf\n", aPosition.timestamp); |
|
444 SetImpl(Parameters::KEY_GPS_TIMESTAMP, nsPrintfCString("%lf", aPosition.timestamp).get()); |
|
445 } |
|
446 return NS_OK; |
|
447 } |
|
448 |
|
449 // Handle int64_ts |
|
450 nsresult |
|
451 GonkCameraParameters::SetTranslated(uint32_t aKey, const int64_t& aValue) |
|
452 { |
|
453 switch (aKey) { |
|
454 case CAMERA_PARAM_PICTURE_DATETIME: |
|
455 { |
|
456 // Add the non-GPS timestamp. The EXIF date/time field is formatted as |
|
457 // "YYYY:MM:DD HH:MM:SS", without room for a time-zone; as such, the time |
|
458 // is meant to be stored as a local time. Since we are given seconds from |
|
459 // Epoch GMT, we use localtime_r() to handle the conversion. |
|
460 time_t time = aValue; |
|
461 if (time != aValue) { |
|
462 DOM_CAMERA_LOGE("picture date/time '%llu' is too far in the future\n", aValue); |
|
463 return NS_ERROR_INVALID_ARG; |
|
464 } |
|
465 |
|
466 struct tm t; |
|
467 if (!localtime_r(&time, &t)) { |
|
468 DOM_CAMERA_LOGE("picture date/time couldn't be converted to local time: (%d) %s\n", errno, strerror(errno)); |
|
469 return NS_ERROR_FAILURE; |
|
470 } |
|
471 |
|
472 char dateTime[20]; |
|
473 if (!strftime(dateTime, sizeof(dateTime), "%Y:%m:%d %T", &t)) { |
|
474 DOM_CAMERA_LOGE("picture date/time couldn't be converted to string\n"); |
|
475 return NS_ERROR_FAILURE; |
|
476 } |
|
477 |
|
478 DOM_CAMERA_LOGI("setting picture date/time to %s\n", dateTime); |
|
479 |
|
480 return SetImpl(CAMERA_PARAM_PICTURE_DATETIME, dateTime); |
|
481 } |
|
482 |
|
483 case CAMERA_PARAM_ISOMODE: |
|
484 { |
|
485 if (aValue > INT32_MAX) { |
|
486 DOM_CAMERA_LOGW("Can't set ISO mode = %lld, too big\n", aValue); |
|
487 return NS_ERROR_INVALID_ARG; |
|
488 } |
|
489 |
|
490 nsString s; |
|
491 s.AppendInt(aValue); |
|
492 return SetTranslated(CAMERA_PARAM_ISOMODE, s); |
|
493 } |
|
494 } |
|
495 |
|
496 // You can't actually pass 64-bit parameters to Gonk. :( |
|
497 int32_t v = static_cast<int32_t>(aValue); |
|
498 if (static_cast<int64_t>(v) != aValue) { |
|
499 return NS_ERROR_INVALID_ARG;; |
|
500 } |
|
501 return SetImpl(aKey, v); |
|
502 } |
|
503 |
|
504 nsresult |
|
505 GonkCameraParameters::GetTranslated(uint32_t aKey, int64_t& aValue) |
|
506 { |
|
507 int val; |
|
508 nsresult rv = GetImpl(aKey, val); |
|
509 if (NS_FAILED(rv)) { |
|
510 return rv; |
|
511 } |
|
512 aValue = val; |
|
513 return NS_OK; |
|
514 } |
|
515 |
|
516 // Handle doubles |
|
517 nsresult |
|
518 GonkCameraParameters::SetTranslated(uint32_t aKey, const double& aValue) |
|
519 { |
|
520 int index; |
|
521 int value; |
|
522 |
|
523 switch (aKey) { |
|
524 case CAMERA_PARAM_EXPOSURECOMPENSATION: |
|
525 if (mExposureCompensationStep == 0) { |
|
526 DOM_CAMERA_LOGE("Exposure compensation not supported, can't set %f\n", aValue); |
|
527 return NS_ERROR_NOT_AVAILABLE; |
|
528 } |
|
529 |
|
530 /** |
|
531 * Convert from real value to a Gonk index, round |
|
532 * to the nearest step; index is 1-based. |
|
533 */ |
|
534 index = |
|
535 (aValue - mExposureCompensationMin + mExposureCompensationStep / 2) / |
|
536 mExposureCompensationStep + 1; |
|
537 DOM_CAMERA_LOGI("Exposure compensation = %f --> index = %d\n", aValue, index); |
|
538 return SetImpl(CAMERA_PARAM_EXPOSURECOMPENSATION, index); |
|
539 |
|
540 case CAMERA_PARAM_ZOOM: |
|
541 { |
|
542 /** |
|
543 * Convert from a real zoom multipler (e.g. 2.5x) to |
|
544 * the index of the nearest supported value. |
|
545 */ |
|
546 value = aValue * 100.0; |
|
547 |
|
548 if (value <= mZoomRatios[0]) { |
|
549 index = 0; |
|
550 } else if (value >= mZoomRatios.LastElement()) { |
|
551 index = mZoomRatios.Length() - 1; |
|
552 } else { |
|
553 // mZoomRatios is sorted, so we can binary search it |
|
554 int bottom = 0; |
|
555 int top = mZoomRatios.Length() - 1; |
|
556 |
|
557 while (top >= bottom) { |
|
558 index = (top + bottom) / 2; |
|
559 if (value == mZoomRatios[index]) { |
|
560 // exact match |
|
561 break; |
|
562 } |
|
563 if (value > mZoomRatios[index] && value < mZoomRatios[index + 1]) { |
|
564 // the specified zoom value lies in this interval |
|
565 break; |
|
566 } |
|
567 if (value > mZoomRatios[index]) { |
|
568 bottom = index + 1; |
|
569 } else { |
|
570 top = index - 1; |
|
571 } |
|
572 } |
|
573 } |
|
574 DOM_CAMERA_LOGI("Zoom = %fx --> index = %d\n", aValue, index); |
|
575 } |
|
576 return SetImpl(CAMERA_PARAM_ZOOM, index); |
|
577 } |
|
578 |
|
579 return SetImpl(aKey, aValue); |
|
580 } |
|
581 |
|
582 nsresult |
|
583 GonkCameraParameters::GetTranslated(uint32_t aKey, double& aValue) |
|
584 { |
|
585 double val; |
|
586 int index = 0; |
|
587 double focusDistance[3]; |
|
588 const char* s; |
|
589 nsresult rv; |
|
590 |
|
591 switch (aKey) { |
|
592 case CAMERA_PARAM_ZOOM: |
|
593 rv = GetImpl(aKey, index); |
|
594 if (NS_SUCCEEDED(rv) && index >= 0) { |
|
595 val = mZoomRatios[index] / 100.0; |
|
596 } else { |
|
597 // return 1x when zooming is not supported |
|
598 val = 1.0; |
|
599 rv = NS_OK; |
|
600 } |
|
601 break; |
|
602 |
|
603 /** |
|
604 * The gonk camera parameters API only exposes one focus distance property |
|
605 * that contains "Near,Optimum,Far" distances, in metres, where 'Far' may |
|
606 * be 'Infinity'. |
|
607 */ |
|
608 case CAMERA_PARAM_FOCUSDISTANCEFAR: |
|
609 ++index; |
|
610 // intentional fallthrough |
|
611 |
|
612 case CAMERA_PARAM_FOCUSDISTANCEOPTIMUM: |
|
613 ++index; |
|
614 // intentional fallthrough |
|
615 |
|
616 case CAMERA_PARAM_FOCUSDISTANCENEAR: |
|
617 rv = GetImpl(aKey, s); |
|
618 if (NS_SUCCEEDED(rv)) { |
|
619 if (sscanf(s, "%lf,%lf,%lf", &focusDistance[0], &focusDistance[1], &focusDistance[2]) == 3) { |
|
620 val = focusDistance[index]; |
|
621 } else { |
|
622 val = 0.0; |
|
623 } |
|
624 } |
|
625 break; |
|
626 |
|
627 case CAMERA_PARAM_EXPOSURECOMPENSATION: |
|
628 rv = GetImpl(aKey, index); |
|
629 if (NS_SUCCEEDED(rv)) { |
|
630 if (!index) { |
|
631 // NaN indicates automatic exposure compensation |
|
632 val = NAN; |
|
633 } else { |
|
634 val = (index - 1) * mExposureCompensationStep + mExposureCompensationMin; |
|
635 DOM_CAMERA_LOGI("index = %d --> compensation = %f\n", index, val); |
|
636 } |
|
637 } |
|
638 break; |
|
639 |
|
640 default: |
|
641 rv = GetImpl(aKey, val); |
|
642 break; |
|
643 } |
|
644 |
|
645 if (NS_SUCCEEDED(rv)) { |
|
646 aValue = val; |
|
647 } |
|
648 return rv; |
|
649 } |
|
650 |
|
651 // Handle ints |
|
652 nsresult |
|
653 GonkCameraParameters::SetTranslated(uint32_t aKey, const int& aValue) |
|
654 { |
|
655 return SetImpl(aKey, aValue); |
|
656 } |
|
657 |
|
658 nsresult |
|
659 GonkCameraParameters::GetTranslated(uint32_t aKey, int& aValue) |
|
660 { |
|
661 return GetImpl(aKey, aValue); |
|
662 } |
|
663 |
|
664 // Handle uint32_ts -- Gonk only speaks int |
|
665 nsresult |
|
666 GonkCameraParameters::SetTranslated(uint32_t aKey, const uint32_t& aValue) |
|
667 { |
|
668 if (aValue > INT_MAX) { |
|
669 return NS_ERROR_INVALID_ARG; |
|
670 } |
|
671 |
|
672 int val = static_cast<int>(aValue); |
|
673 return SetImpl(aKey, val); |
|
674 } |
|
675 |
|
676 nsresult |
|
677 GonkCameraParameters::GetTranslated(uint32_t aKey, uint32_t& aValue) |
|
678 { |
|
679 int val; |
|
680 nsresult rv = GetImpl(aKey, val); |
|
681 if (NS_FAILED(rv)) { |
|
682 return rv; |
|
683 } |
|
684 if (val < 0) { |
|
685 return NS_ERROR_FAILURE; |
|
686 } |
|
687 |
|
688 aValue = val; |
|
689 return NS_OK; |
|
690 } |
|
691 |
|
692 // Handle bools |
|
693 nsresult |
|
694 GonkCameraParameters::SetTranslated(uint32_t aKey, const bool& aValue) |
|
695 { |
|
696 return SetImpl(aKey, aValue); |
|
697 } |
|
698 |
|
699 nsresult |
|
700 GonkCameraParameters::GetTranslated(uint32_t aKey, bool& aValue) |
|
701 { |
|
702 return GetImpl(aKey, aValue); |
|
703 } |
|
704 |
|
705 nsresult |
|
706 ParseItem(const char* aStart, const char* aEnd, ICameraControl::Size* aItem) |
|
707 { |
|
708 if (sscanf(aStart, "%ux%u", &aItem->width, &aItem->height) == 2) { |
|
709 return NS_OK; |
|
710 } |
|
711 |
|
712 DOM_CAMERA_LOGE("Size tuple has bad format: '%s'\n", __func__, __LINE__, aStart); |
|
713 return NS_ERROR_FAILURE; |
|
714 } |
|
715 |
|
716 nsresult |
|
717 ParseItem(const char* aStart, const char* aEnd, nsAString* aItem) |
|
718 { |
|
719 if (aEnd) { |
|
720 aItem->AssignASCII(aStart, aEnd - aStart); |
|
721 } else { |
|
722 aItem->AssignASCII(aStart); |
|
723 } |
|
724 return NS_OK; |
|
725 } |
|
726 |
|
727 nsresult |
|
728 ParseItem(const char* aStart, const char* aEnd, nsACString* aItem) |
|
729 { |
|
730 if (aEnd) { |
|
731 aItem->AssignASCII(aStart, aEnd - aStart); |
|
732 } else { |
|
733 aItem->AssignASCII(aStart); |
|
734 } |
|
735 return NS_OK; |
|
736 } |
|
737 |
|
738 nsresult |
|
739 ParseItem(const char* aStart, const char* aEnd, double* aItem) |
|
740 { |
|
741 if (sscanf(aStart, "%lf", aItem) == 1) { |
|
742 return NS_OK; |
|
743 } |
|
744 |
|
745 return NS_ERROR_FAILURE; |
|
746 } |
|
747 |
|
748 nsresult |
|
749 ParseItem(const char* aStart, const char* aEnd, int* aItem) |
|
750 { |
|
751 if (sscanf(aStart, "%d", aItem) == 1) { |
|
752 return NS_OK; |
|
753 } |
|
754 |
|
755 return NS_ERROR_FAILURE; |
|
756 } |
|
757 |
|
758 template<class T> nsresult |
|
759 GonkCameraParameters::GetListAsArray(uint32_t aKey, nsTArray<T>& aArray) |
|
760 { |
|
761 const char* p; |
|
762 nsresult rv = GetImpl(aKey, p); |
|
763 if (NS_FAILED(rv)) { |
|
764 return rv; |
|
765 } |
|
766 |
|
767 aArray.Clear(); |
|
768 |
|
769 // If there is no value available, just return the empty array. |
|
770 if (!p) { |
|
771 DOM_CAMERA_LOGI("Camera parameter %d not available (value is null)\n", aKey); |
|
772 return NS_OK; |
|
773 } |
|
774 if (*p == '\0') { |
|
775 DOM_CAMERA_LOGI("Camera parameter %d not available (value is empty string)\n", aKey); |
|
776 return NS_OK; |
|
777 } |
|
778 |
|
779 const char* comma; |
|
780 |
|
781 while (p) { |
|
782 T* v = aArray.AppendElement(); |
|
783 if (!v) { |
|
784 aArray.Clear(); |
|
785 return NS_ERROR_OUT_OF_MEMORY; |
|
786 } |
|
787 comma = strchr(p, ','); |
|
788 if (comma != p) { |
|
789 rv = ParseItem(p, comma, v); |
|
790 if (NS_FAILED(rv)) { |
|
791 aArray.Clear(); |
|
792 return rv; |
|
793 } |
|
794 p = comma; |
|
795 } |
|
796 if (p) { |
|
797 ++p; |
|
798 } |
|
799 } |
|
800 |
|
801 return NS_OK; |
|
802 } |
|
803 |
|
804 nsresult |
|
805 GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<nsString>& aValues) |
|
806 { |
|
807 if (aKey == CAMERA_PARAM_SUPPORTED_ISOMODES) { |
|
808 aValues = mIsoModes; |
|
809 return NS_OK; |
|
810 } |
|
811 |
|
812 return GetListAsArray(aKey, aValues); |
|
813 } |
|
814 |
|
815 nsresult |
|
816 GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<double>& aValues) |
|
817 { |
|
818 if (aKey == CAMERA_PARAM_SUPPORTED_ZOOMRATIOS) { |
|
819 aValues.Clear(); |
|
820 for (uint32_t i = 0; i < mZoomRatios.Length(); ++i) { |
|
821 *aValues.AppendElement() = mZoomRatios[i] / 100.0; |
|
822 } |
|
823 return NS_OK; |
|
824 } |
|
825 |
|
826 return GetListAsArray(aKey, aValues); |
|
827 } |
|
828 |
|
829 nsresult |
|
830 GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<ICameraControl::Size>& aSizes) |
|
831 { |
|
832 return GetListAsArray(aKey, aSizes); |
|
833 } |
|
834 |