diff --git a/dom/camera/CameraCommon.h b/dom/camera/CameraCommon.h index 01bc81cb44fd..ef5c56baf82a 100644 --- a/dom/camera/CameraCommon.h +++ b/dom/camera/CameraCommon.h @@ -77,6 +77,9 @@ enum { CAMERA_PARAM_FOCUSDISTANCEOPTIMUM, CAMERA_PARAM_FOCUSDISTANCEFAR, CAMERA_PARAM_EXPOSURECOMPENSATION, + CAMERA_PARAM_THUMBNAILWIDTH, + CAMERA_PARAM_THUMBNAILHEIGHT, + CAMERA_PARAM_THUMBNAILQUALITY, CAMERA_PARAM_SUPPORTED_PREVIEWSIZES, CAMERA_PARAM_SUPPORTED_VIDEOSIZES, @@ -93,7 +96,8 @@ enum { CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION, CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP, CAMERA_PARAM_SUPPORTED_ZOOM, - CAMERA_PARAM_SUPPORTED_ZOOMRATIOS + CAMERA_PARAM_SUPPORTED_ZOOMRATIOS, + CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES }; #ifdef PR_LOGGING diff --git a/dom/camera/GonkCameraControl.cpp b/dom/camera/GonkCameraControl.cpp index 98a38e1af39e..ed74d64675db 100644 --- a/dom/camera/GonkCameraControl.cpp +++ b/dom/camera/GonkCameraControl.cpp @@ -29,6 +29,7 @@ #include "nsThread.h" #include #include "mozilla/FileUtils.h" +#include "nsAlgorithm.h" #include #include "nsDirectoryServiceDefs.h" // for NS_GetSpecialDirectory #include "nsPrintfCString.h" @@ -72,6 +73,13 @@ static const char* getKeyText(uint32_t aKey) return CameraParameters::KEY_FOCUS_DISTANCES; case CAMERA_PARAM_EXPOSURECOMPENSATION: return CameraParameters::KEY_EXPOSURE_COMPENSATION; + case CAMERA_PARAM_THUMBNAILWIDTH: + return CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH; + case CAMERA_PARAM_THUMBNAILHEIGHT: + return CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT; + case CAMERA_PARAM_THUMBNAILQUALITY: + return CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY; + case CAMERA_PARAM_SUPPORTED_PREVIEWSIZES: return CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES; case CAMERA_PARAM_SUPPORTED_VIDEOSIZES: @@ -104,6 +112,8 @@ static const char* getKeyText(uint32_t aKey) return CameraParameters::KEY_ZOOM_SUPPORTED; case CAMERA_PARAM_SUPPORTED_ZOOMRATIOS: return CameraParameters::KEY_ZOOM_RATIOS; + case CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES: + return CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES; default: return nullptr; } @@ -174,6 +184,8 @@ nsGonkCameraControl::nsGonkCameraControl(uint32_t aCameraId, nsIThread* aCameraT , mDeferConfigUpdate(false) , mWidth(0) , mHeight(0) + , mLastPictureWidth(0) + , mLastPictureHeight(0) , mFormat(PREVIEW_FORMAT_UNKNOWN) , mFps(30) , mDiscardedFrameCount(0) @@ -208,6 +220,7 @@ nsGonkCameraControl::Init() const char* const BAD_PREVIEW_FORMAT = "yuv420sp"; mParams.setPreviewFormat(PREVIEW_FORMAT); mParams.setPreviewFrameRate(mFps); + PushParametersImpl(); // Check that our settings stuck PullParametersImpl(); @@ -402,14 +415,50 @@ nsGonkCameraControl::GetParameter(uint32_t aKey, nsTArray& aRegion r = aRegions.AppendElement(); if (sscanf(p, "(%d,%d,%d,%d,%u)", &r->top, &r->left, &r->bottom, &r->right, &r->weight) != 5) { DOM_CAMERA_LOGE("%s:%d : region tuple has bad format: '%s'\n", __func__, __LINE__, p); - goto GetParameter_error; + aRegions.Clear(); + return; } } return; +} -GetParameter_error: - aRegions.Clear(); +void +nsGonkCameraControl::GetParameter(uint32_t aKey, nsTArray& aSizes) +{ + const char* key = getKeyText(aKey); + if (!key) { + return; + } + + RwAutoLockRead lock(mRwLock); + + const char* value = mParams.get(key); + DOM_CAMERA_LOGI("key='%s' --> value='%s'\n", key, value); + if (!value) { + return; + } + + const char* p = value; + CameraSize* s; + + // The 'value' string is in the format "w1xh1,w2xh2,w3xh3,..." + while (p) { + s = aSizes.AppendElement(); + if (sscanf(p, "%dx%d", &s->width, &s->height) != 2) { + DOM_CAMERA_LOGE("%s:%d : size tuple has bad format: '%s'\n", __func__, __LINE__, p); + aSizes.Clear(); + return; + } + // Look for the next record... + p = strchr(p, ','); + if (p) { + // ...skip the comma too + ++p; + } + } + + return; } nsresult @@ -524,6 +573,20 @@ nsGonkCameraControl::SetParameter(uint32_t aKey, const nsTArray& a PushParameters(); } +void +nsGonkCameraControl::SetParameter(uint32_t aKey, int aValue) +{ + const char* key = getKeyText(aKey); + if (!key) { + return; + } + { + RwAutoLockWrite lock(mRwLock); + mParams.set(key, aValue); + } + PushParameters(); +} + nsresult nsGonkCameraControl::GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream) { @@ -615,6 +678,45 @@ nsGonkCameraControl::AutoFocusImpl(AutoFocusTask* aAutoFocus) return NS_OK; } +void +nsGonkCameraControl::SetupThumbnail(uint32_t aPictureWidth, uint32_t aPictureHeight, uint32_t aPercentQuality) +{ + /** + * Use the smallest non-0x0 thumbnail size that matches + * the aspect ratio of our parameters... + */ + uint32_t smallestArea = UINT_MAX; + uint32_t smallestIndex = UINT_MAX; + nsAutoTArray thumbnailSizes; + GetParameter(CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES, thumbnailSizes); + + for (uint32_t i = 0; i < thumbnailSizes.Length(); ++i) { + uint32_t area = thumbnailSizes[i].width * thumbnailSizes[i].height; + if (area != 0 + && area < smallestArea + && thumbnailSizes[i].width * aPictureHeight / thumbnailSizes[i].height == aPictureWidth + ) { + smallestArea = area; + smallestIndex = i; + } + } + + aPercentQuality = clamped(aPercentQuality, 1, 100); + SetParameter(CAMERA_PARAM_THUMBNAILQUALITY, static_cast(aPercentQuality)); + + if (smallestIndex != UINT_MAX) { + uint32_t w = thumbnailSizes[smallestIndex].width; + uint32_t h = thumbnailSizes[smallestIndex].height; + DOM_CAMERA_LOGI("Using thumbnail size: %ux%u, quality: %u %%\n", w, h, aPercentQuality); + if (w > INT_MAX || h > INT_MAX) { + DOM_CAMERA_LOGE("Thumbnail dimension is too big, will use defaults\n"); + return; + } + SetParameter(CAMERA_PARAM_THUMBNAILWIDTH, static_cast(w)); + SetParameter(CAMERA_PARAM_THUMBNAILHEIGHT, static_cast(h)); + } +} + nsresult nsGonkCameraControl::TakePictureImpl(TakePictureTask* aTakePicture) { @@ -641,16 +743,24 @@ nsGonkCameraControl::TakePictureImpl(TakePictureTask* aTakePicture) // batch-update camera configuration mDeferConfigUpdate = true; - /** - * height and width: some drivers are less friendly about getting one of - * these set to zero, so if either is not specified, ignore both and go - * with current or default settings. - */ - if (aTakePicture->mSize.width && aTakePicture->mSize.height) { - nsCString s; - s.AppendPrintf("%dx%d", aTakePicture->mSize.width, aTakePicture->mSize.height); - DOM_CAMERA_LOGI("setting picture size to '%s'\n", s.get()); - SetParameter(CameraParameters::KEY_PICTURE_SIZE, s.get()); + if (aTakePicture->mSize.width != mLastPictureWidth || aTakePicture->mSize.height != mLastPictureHeight) { + /** + * height and width: some drivers are less friendly about getting one of + * these set to zero, so if either is not specified, ignore both and go + * with current or default settings. + */ + if (aTakePicture->mSize.width && aTakePicture->mSize.height) { + nsCString s; + s.AppendPrintf("%ux%u", aTakePicture->mSize.width, aTakePicture->mSize.height); + DOM_CAMERA_LOGI("setting picture size to '%s'\n", s.get()); + SetParameter(CameraParameters::KEY_PICTURE_SIZE, s.get()); + + // Choose an appropriate thumbnail size and quality (from 1..100) + SetupThumbnail(aTakePicture->mSize.width, aTakePicture->mSize.height, 60); + } + + mLastPictureWidth = aTakePicture->mSize.width; + mLastPictureHeight = aTakePicture->mSize.height; } // Picture format -- need to keep it for the callback. diff --git a/dom/camera/GonkCameraControl.h b/dom/camera/GonkCameraControl.h index 836e01b1bfe5..ca3ded4b4496 100644 --- a/dom/camera/GonkCameraControl.h +++ b/dom/camera/GonkCameraControl.h @@ -47,10 +47,12 @@ public: const char* GetParameterConstChar(uint32_t aKey); double GetParameterDouble(uint32_t aKey); void GetParameter(uint32_t aKey, nsTArray& aRegions); + void GetParameter(uint32_t aKey, nsTArray& aSizes); void SetParameter(const char* aKey, const char* aValue); void SetParameter(uint32_t aKey, const char* aValue); void SetParameter(uint32_t aKey, double aValue); void SetParameter(uint32_t aKey, const nsTArray& aRegions); + void SetParameter(uint32_t aKey, int aValue); nsresult GetVideoSizes(nsTArray& aVideoSizes); nsresult PushParameters(); @@ -79,6 +81,7 @@ protected: already_AddRefed GetGonkRecorderProfileManager(); void SetPreviewSize(uint32_t aWidth, uint32_t aHeight); + void SetupThumbnail(uint32_t aPictureWidth, uint32_t aPictureHeight, uint32_t aPercentQuality); uint32_t mHwHandle; double mExposureCompensationMin; @@ -88,6 +91,8 @@ protected: android::CameraParameters mParams; uint32_t mWidth; uint32_t mHeight; + uint32_t mLastPictureWidth; + uint32_t mLastPictureHeight; enum { PREVIEW_FORMAT_UNKNOWN,