Bug 1036637 - disable HDR on low-memory devices, r=dhylands

This commit is contained in:
Mike Habicher 2014-07-13 11:50:48 -04:00
parent 5983261f67
commit a6cf3a0bdf
7 changed files with 312 additions and 36 deletions

View File

@ -22,6 +22,11 @@ StaticAutoPtr<nsCString> CameraPreferences::sPrefGonkParameters;
nsresult CameraPreferences::sPrefCameraControlMethodErrorOverride = NS_OK;
nsresult CameraPreferences::sPrefCameraControlAsyncErrorOverride = NS_OK;
uint32_t CameraPreferences::sPrefCameraControlLowMemoryThresholdMB = 0;
bool CameraPreferences::sPrefCameraParametersIsLowMemory = false;
#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
/* static */
nsresult
CameraPreferences::UpdatePref(const char* aPref, nsresult& aVal)
@ -33,6 +38,19 @@ CameraPreferences::UpdatePref(const char* aPref, nsresult& aVal)
}
return rv;
}
#endif
/* static */
nsresult
CameraPreferences::UpdatePref(const char* aPref, uint32_t& aVal)
{
uint32_t val;
nsresult rv = Preferences::GetUint(aPref, &val);
if (NS_SUCCEEDED(rv)) {
aVal = val;
}
return rv;
}
/* static */
nsresult
@ -46,6 +64,18 @@ CameraPreferences::UpdatePref(const char* aPref, nsACString& aVal)
return rv;
}
/* static */
nsresult
CameraPreferences::UpdatePref(const char* aPref, bool& aVal)
{
bool val;
nsresult rv = Preferences::GetBool(aPref, &val);
if (NS_SUCCEEDED(rv)) {
aVal = val;
}
return rv;
}
/* static */
CameraPreferences::Pref CameraPreferences::sPrefs[] = {
{
@ -67,14 +97,24 @@ CameraPreferences::Pref CameraPreferences::sPrefs[] = {
#endif
{
"camera.control.test.method.error",
kPrefValueIsNSResult,
kPrefValueIsNsResult,
{ &sPrefCameraControlMethodErrorOverride }
},
{
"camera.control.test.async.error",
kPrefValueIsNSResult,
kPrefValueIsNsResult,
{ &sPrefCameraControlAsyncErrorOverride }
},
{
"camera.control.test.is_low_memory",
kPrefValueIsBoolean,
{ &sPrefCameraParametersIsLowMemory }
},
{
"camera.control.low_memory_thresholdMB",
kPrefValueIsUint32,
{ &sPrefCameraControlLowMemoryThresholdMB }
},
};
/* static */
@ -104,7 +144,8 @@ CameraPreferences::PreferenceChanged(const char* aPref, void* aClosure)
Pref& p = sPrefs[i];
nsresult rv;
switch (p.mValueType) {
case kPrefValueIsNSResult:
case kPrefValueIsNsResult:
#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
{
nsresult& v = *p.mValue.mAsNsResult;
rv = UpdatePref(aPref, v);
@ -113,6 +154,17 @@ CameraPreferences::PreferenceChanged(const char* aPref, void* aClosure)
}
}
break;
#endif
case kPrefValueIsUint32:
{
uint32_t& v = *p.mValue.mAsUint32;
rv = UpdatePref(aPref, v);
if (NS_SUCCEEDED(rv)) {
DOM_CAMERA_LOGI("Preference '%s' has changed, %u\n", aPref, v);
}
}
break;
case kPrefValueIsCString:
{
@ -124,6 +176,17 @@ CameraPreferences::PreferenceChanged(const char* aPref, void* aClosure)
}
break;
case kPrefValueIsBoolean:
{
bool& v = *p.mValue.mAsBoolean;
rv = UpdatePref(aPref, v);
if (NS_SUCCEEDED(rv)) {
DOM_CAMERA_LOGI("Preference '%s' has changed, %s\n",
aPref, v ? "true" : "false");
}
}
break;
default:
MOZ_ASSERT_UNREACHABLE("Unhandled preference value type!");
return;
@ -211,6 +274,7 @@ CameraPreferences::GetPref(const char* aPref, nsACString& aVal)
return true;
}
#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
/* static */
bool
CameraPreferences::GetPref(const char* aPref, nsresult& aVal)
@ -223,14 +287,14 @@ CameraPreferences::GetPref(const char* aPref, nsresult& aVal)
DOM_CAMERA_LOGW("Preference '%s' is not tracked by CameraPreferences\n", aPref);
return false;
}
if (sPrefs[i].mValueType != kPrefValueIsNSResult) {
if (sPrefs[i].mValueType != kPrefValueIsNsResult) {
DOM_CAMERA_LOGW("Preference '%s' is not an nsresult type\n", aPref);
return false;
}
nsresult v = *sPrefs[i].mValue.mAsNsResult;
if (v == NS_OK) {
DOM_CAMERA_LOGI("Preference '%s' is not set\n", aPref);
DOM_CAMERA_LOGW("Preference '%s' is not set\n", aPref);
return false;
}
@ -238,3 +302,50 @@ CameraPreferences::GetPref(const char* aPref, nsresult& aVal)
aVal = v;
return true;
}
#endif
/* static */
bool
CameraPreferences::GetPref(const char* aPref, uint32_t& aVal)
{
MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
MonitorAutoLock mon(*sPrefMonitor);
uint32_t i = PrefToIndex(aPref);
if (i == kPrefNotFound || i >= ArrayLength(sPrefs)) {
DOM_CAMERA_LOGW("Preference '%s' is not tracked by CameraPreferences\n", aPref);
return false;
}
if (sPrefs[i].mValueType != kPrefValueIsUint32) {
DOM_CAMERA_LOGW("Preference '%s' is not a uint32_t type\n", aPref);
return false;
}
uint32_t v = *sPrefs[i].mValue.mAsUint32;
DOM_CAMERA_LOGI("Preference '%s', got %u\n", aPref, v);
aVal = v;
return true;
}
/* static */
bool
CameraPreferences::GetPref(const char* aPref, bool& aVal)
{
MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
MonitorAutoLock mon(*sPrefMonitor);
uint32_t i = PrefToIndex(aPref);
if (i == kPrefNotFound || i >= ArrayLength(sPrefs)) {
DOM_CAMERA_LOGW("Preference '%s' is not tracked by CameraPreferences\n", aPref);
return false;
}
if (sPrefs[i].mValueType != kPrefValueIsBoolean) {
DOM_CAMERA_LOGW("Preference '%s' is not a boolean type\n", aPref);
return false;
}
bool v = *sPrefs[i].mValue.mAsBoolean;
DOM_CAMERA_LOGI("Preference '%s', got %s\n", aPref, v ? "true" : "false");
aVal = v;
return true;
}

View File

@ -8,6 +8,13 @@
#include "nsString.h"
#if defined(MOZ_HAVE_CXX11_STRONG_ENUMS) || defined(MOZ_HAVE_CXX11_ENUM_TYPE)
// Older compilers that don't support strongly-typed enums
// just typedef uint32_t to nsresult, which results in conflicting
// overloaded members in CameraPreferences.
#define CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
#endif
namespace mozilla {
template<class T> class StaticAutoPtr;
@ -19,19 +26,29 @@ public:
static void Shutdown();
static bool GetPref(const char* aPref, nsACString& aVal);
#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
static bool GetPref(const char* aPref, nsresult& aVal);
#endif
static bool GetPref(const char* aPref, uint32_t& aVal);
static bool GetPref(const char* aPref, bool& aVal);
protected:
static const uint32_t kPrefNotFound = UINT32_MAX;
static uint32_t PrefToIndex(const char* aPref);
static void PreferenceChanged(const char* aPref, void* aClosure);
#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
static nsresult UpdatePref(const char* aPref, nsresult& aVar);
#endif
static nsresult UpdatePref(const char* aPref, uint32_t& aVar);
static nsresult UpdatePref(const char* aPref, nsACString& aVar);
static nsresult UpdatePref(const char* aPref, bool& aVar);
enum PrefValueType {
kPrefValueIsNSResult,
kPrefValueIsCString
kPrefValueIsNsResult,
kPrefValueIsUint32,
kPrefValueIsCString,
kPrefValueIsBoolean
};
struct Pref {
const char* const mPref;
@ -45,6 +62,8 @@ protected:
void* mAsVoid;
StaticAutoPtr<nsCString>* mAsCString;
nsresult* mAsNsResult;
uint32_t* mAsUint32;
bool* mAsBoolean;
} mValue;
};
static Pref sPrefs[];
@ -56,6 +75,10 @@ protected:
static nsresult sPrefCameraControlMethodErrorOverride;
static nsresult sPrefCameraControlAsyncErrorOverride;
static uint32_t sPrefCameraControlLowMemoryThresholdMB;
static bool sPrefCameraParametersIsLowMemory;
private:
// static class only
CameraPreferences();

View File

@ -16,12 +16,40 @@
#include "GonkCameraParameters.h"
#include "camera/CameraParameters.h"
#include "CameraPreferences.h"
#include "ICameraControl.h"
#include "CameraCommon.h"
#include "mozilla/Hal.h"
using namespace mozilla;
using namespace android;
/* static */ bool
GonkCameraParameters::IsLowMemoryPlatform()
{
bool testIsLowMem = false;
CameraPreferences::GetPref("camera.control.test.is_low_memory", testIsLowMem);
if (testIsLowMem) {
NS_WARNING("Forcing low-memory platform camera preferences");
return true;
}
uint32_t lowMemoryThresholdBytes = 0;
CameraPreferences::GetPref("camera.control.low_memory_thresholdMB",
lowMemoryThresholdBytes);
lowMemoryThresholdBytes *= 1024 * 1024;
if (lowMemoryThresholdBytes) {
uint32_t totalMemoryBytes = hal::GetTotalSystemMemory();
if (totalMemoryBytes < lowMemoryThresholdBytes) {
DOM_CAMERA_LOGI("Low-memory platform with %d bytes of RAM (threshold: <%d bytes)\n",
totalMemoryBytes, lowMemoryThresholdBytes);
return true;
}
}
return false;
}
/* static */ const char*
GonkCameraParameters::Parameters::GetTextKey(uint32_t aKey)
{
@ -246,7 +274,7 @@ GonkCameraParameters::Initialize()
nsString s;
nsTArray<nsCString> isoModes;
GetListAsArray(CAMERA_PARAM_SUPPORTED_ISOMODES, isoModes);
for (uint32_t i = 0; i < isoModes.Length(); ++i) {
for (nsTArray<nsCString>::size_type i = 0; i < isoModes.Length(); ++i) {
rv = MapIsoFromGonk(isoModes[i].get(), s);
if (NS_FAILED(rv)) {
DOM_CAMERA_LOGW("Unrecognized ISO mode value '%s'\n", isoModes[i].get());
@ -256,6 +284,17 @@ GonkCameraParameters::Initialize()
mIsoModeMap.Put(s, new nsCString(isoModes[i]));
}
GetListAsArray(CAMERA_PARAM_SUPPORTED_SCENEMODES, mSceneModes);
if (IsLowMemoryPlatform()) {
bool hdrRemoved = false;
while (mSceneModes.RemoveElement(NS_LITERAL_STRING("hdr"))) {
hdrRemoved = true;
}
if (hdrRemoved) {
DOM_CAMERA_LOGI("Disabling HDR support due to low memory\n");
}
}
mInitialized = true;
return NS_OK;
}
@ -264,16 +303,26 @@ GonkCameraParameters::Initialize()
nsresult
GonkCameraParameters::SetTranslated(uint32_t aKey, const nsAString& aValue)
{
if (aKey == CAMERA_PARAM_ISOMODE) {
nsAutoCString v;
nsresult rv = MapIsoToGonk(aValue, v);
if (NS_FAILED(rv)) {
return rv;
}
return SetImpl(aKey, v.get());
}
switch (aKey) {
case CAMERA_PARAM_ISOMODE:
{
nsAutoCString v;
nsresult rv = MapIsoToGonk(aValue, v);
if (NS_FAILED(rv)) {
return rv;
}
return SetImpl(aKey, v.get());
}
return SetImpl(aKey, NS_ConvertUTF16toUTF8(aValue).get());
case CAMERA_PARAM_SCENEMODE:
if (mSceneModes.IndexOf(aValue) == nsTArray<nsString>::NoIndex) {
return NS_ERROR_INVALID_ARG;
}
// fallthrough
default:
return SetImpl(aKey, NS_ConvertUTF16toUTF8(aValue).get());
}
}
nsresult
@ -620,7 +669,7 @@ GonkCameraParameters::SetTranslated(uint32_t aKey, const double& aValue)
nsresult
GonkCameraParameters::GetTranslated(uint32_t aKey, double& aValue)
{
double val;
double val = 0.0; // initialize to keep the compiler happy [-Wmaybe-uninitialized]
int index = 0;
double focusDistance[3];
const char* s;
@ -840,12 +889,18 @@ GonkCameraParameters::GetListAsArray(uint32_t aKey, nsTArray<T>& aArray)
nsresult
GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<nsString>& aValues)
{
if (aKey == CAMERA_PARAM_SUPPORTED_ISOMODES) {
aValues = mIsoModes;
return NS_OK;
}
switch (aKey) {
case CAMERA_PARAM_SUPPORTED_ISOMODES:
aValues = mIsoModes;
return NS_OK;
return GetListAsArray(aKey, aValues);
case CAMERA_PARAM_SUPPORTED_SCENEMODES:
aValues = mSceneModes;
return NS_OK;
default:
return GetListAsArray(aKey, aValues);
}
}
nsresult

View File

@ -101,6 +101,7 @@ protected:
int32_t mExposureCompensationMaxIndex;
nsTArray<int> mZoomRatios;
nsTArray<nsString> mIsoModes;
nsTArray<nsString> mSceneModes;
nsClassHashtable<nsStringHashKey, nsCString> mIsoModeMap;
// This subclass of android::CameraParameters just gives
@ -224,6 +225,10 @@ protected:
// Call once to initialize local cached values used in translating other
// arguments between Gecko and Gonk. Always returns NS_OK.
nsresult Initialize();
// Returns true if we're a memory-constrained platform that requires
// certain features to be disabled; returns false otherwise.
static bool IsLowMemoryPlatform();
};
} // namespace mozilla

View File

@ -35,6 +35,7 @@ var CameraTest = (function() {
const PREF_TEST_ENABLED = "camera.control.test.enabled";
const PREF_TEST_HARDWARE = "camera.control.test.hardware";
const PREF_TEST_EXTRA_PARAMETERS = "camera.control.test.hardware.gonk.parameters";
const PREF_TEST_FAKE_LOW_MEMORY = "camera.control.test.is_low_memory";
var oldTestEnabled;
var oldTestHw;
var testMode;
@ -53,6 +54,20 @@ var CameraTest = (function() {
SpecialPowers.pushPrefEnv({'clear': [[PREF_TEST_EXTRA_PARAMETERS]]}, callback);
}
function testHardwareSetFakeLowMemoryPlatform(callback) {
SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_FAKE_LOW_MEMORY, true]]}, function() {
var setParams = SpecialPowers.getBoolPref(PREF_TEST_FAKE_LOW_MEMORY);
ise(setParams, true, "Fake low memory platform");
if (callback) {
callback(setParams);
}
});
}
function testHardwareClearFakeLowMemoryPlatform(callback) {
SpecialPowers.pushPrefEnv({'clear': [[PREF_TEST_FAKE_LOW_MEMORY]]}, callback);
}
function testHardwareSet(test, callback) {
SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_HARDWARE, test]]}, function() {
var setTest = SpecialPowers.getCharPref(PREF_TEST_HARDWARE);
@ -88,6 +103,8 @@ var CameraTest = (function() {
set: testHardwareSet,
setFakeParameters: testHardwareSetFakeParameters,
clearFakeParameters: testHardwareClearFakeParameters,
setFakeLowMemoryPlatform: testHardwareSetFakeLowMemoryPlatform,
clearFakeLowMemoryPlatform: testHardwareClearFakeLowMemoryPlatform,
done: testHardwareDone
};
if (callback) {
@ -122,8 +139,16 @@ var CameraTest = (function() {
next();
}
}
function cleanUpExtraParameters() {
function cleanUpLowMemoryPlatform() {
var next = cleanUpTest;
if (testMode) {
testMode.clearFakeLowMemoryPlatform(next);
} else {
next();
}
}
function cleanUpExtraParameters() {
var next = cleanUpLowMemoryPlatform;
if (testMode) {
testMode.clearFakeParameters(next);
} else {

View File

@ -114,6 +114,61 @@ var tests = [
next();
}
},
{
key: "fake-high-memory-platform",
prep: function setupFakeHighMemoryPlatform(test) {
test.setFakeParameters("scene-mode-values=none,snow,beach,hdr,nothdr", function () {
run();
});
},
test: function testFakeHighMemoryPlatform(cam, cap) {
ok(cap.sceneModes.length == 5, "scene modes length = " + cap.zoomRatios.length);
// make sure expected values are present and can be set
[ "none", "snow", "beach", "hdr", "nothdr" ].forEach(function(mode) {
ok(cap.sceneModes.indexOf(mode) != -1, "Scene mode '" + mode + "' is present");
cam.sceneMode = mode;
ok(cam.sceneMode == mode, "Scene mode '" + cam.sceneMode + "' is set");
});
next();
}
},
{
key: "fake-low-memory-platform",
prep: function setupFakeLowMemoryPlatform(test) {
test.setFakeLowMemoryPlatform(function() {
test.setFakeParameters("scene-mode-values=none,hdr,snow,beach,hdr,nothdr", function () {
run();
});
});
},
test: function testFakeLowMemoryPlatform(cam, cap) {
ok(cap.sceneModes.length == 4, "scene modes length = " + cap.zoomRatios.length);
// make sure expected values are present and can be set
[ "none", "snow", "beach", "nothdr" ].forEach(function(mode) {
ok(cap.sceneModes.indexOf(mode) != -1, "Scene mode '" + mode + "' is present");
cam.sceneMode = mode;
ok(cam.sceneMode == mode, "Scene mode '" + cam.sceneMode + "' is set");
});
// make sure unsupported values have been removed, and can't be set
var sceneMode = cam.sceneMode;
[ "hdr" ].forEach(function(mode) {
ok(cap.sceneModes.indexOf(mode) == -1, "Scene mode '" + mode + "' is not present");
try {
cam.sceneMode = mode;
} catch(e) {
}
ok(cam.sceneMode != mode, "Scene mode '" + cam.sceneMode + "' is still set, '"
+ mode + "' rejected");
});
ok(cam.sceneMode == sceneMode, "Scene mode '" + cam.sceneMode + "' is still set");
next();
}
},
{
key: "fake-iso",
prep: function setupFakeIso(test) {
@ -129,20 +184,14 @@ var tests = [
ok(cap.isoModes.length == 7, "ISO modes length = " + cap.isoModes.length);
// make sure we're not leaking any unexpected values formats
ok(cap.isoModes.indexOf("ISO_HJR") == -1, "ISO mode 'ISO_HJR' does not appear");
ok(cap.isoModes.indexOf("_HJR") == -1, "ISO mode '_HJR' does not appear");
ok(cap.isoModes.indexOf("HJR") == -1, "ISO mode 'HJR' does not appear");
ok(cap.isoModes.indexOf("ISO100") == -1, "ISO mode 'ISO100' does not appear");
ok(cap.isoModes.indexOf("ISO200") == -1, "ISO mode 'ISO200' does not appear");
ok(cap.isoModes.indexOf("ISO800") == -1, "ISO mode 'ISO800' does not appear");
[ "ISO_HJR", "_HJR", "HJR", "ISO100", "ISO200", "ISO800" ].forEach(function(iso) {
ok(cap.isoModes.indexOf(iso) == -1, "ISO mode '" + iso + "' does not appear");
});
// make sure any weird values are dropped entirely
ok(cap.isoModes.indexOf("foo") == -1, "Unknown ISO mode 'foo' is ignored");
ok(cap.isoModes.indexOf("ISObar") == -1, "Unknown ISO mode 'ISObar' is ignored");
ok(cap.isoModes.indexOf("bar") == -1, "Unknown ISO mode 'bar' is ignored");
ok(cap.isoModes.indexOf("ISO150moz") == -1, "Unknown ISO mode 'ISO150moz' is ignored");
ok(cap.isoModes.indexOf("150moz") == -1, "Unknown ISO mode '150moz' is ignored");
ok(cap.isoModes.indexOf("150") == -1, "Unknown ISO mode '150' is ignored");
[ "foo", "ISObar", "bar", "ISO150moz", "150moz", "150" ].forEach(function(iso) {
ok(cap.isoModes.indexOf(iso) == -1, "Unknown ISO mode '" + iso + "' is ignored");
});
// make sure expected values are present
[ "auto", "hjr", "100", "200", "400", "800", "1600" ].forEach(function(iso) {

View File

@ -4273,3 +4273,11 @@ pref("beacon.enabled", true);
// Camera prefs
pref("camera.control.autofocus_moving_callback.enabled", true);
pref("camera.control.face_detection.enabled", true);
#ifdef MOZ_WIDGET_GONK
// Empirically, this is the value returned by hal::GetTotalSystemMemory()
// when Flame's memory is limited to 512MiB. If the camera stack determines
// it is running on a low memory platform, features that can be reliably
// supported will be disabled. This threshold can be adjusted to suit other
// platforms; and set to 0 to disable the low-memory check altogether.
pref("camera.control.low_memory_thresholdMB", 404);
#endif