dom/camera/TestGonkCameraHardware.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/camera/TestGonkCameraHardware.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,503 @@
     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 "TestGonkCameraHardware.h"
    1.21 +
    1.22 +#include "mozilla/Preferences.h"
    1.23 +#include "nsThreadUtils.h"
    1.24 +
    1.25 +using namespace android;
    1.26 +using namespace mozilla;
    1.27 +
    1.28 +TestGonkCameraHardware::TestGonkCameraHardware(nsGonkCameraControl* aTarget,
    1.29 +                                               uint32_t aCameraId,
    1.30 +                                               const sp<Camera>& aCamera)
    1.31 +  : GonkCameraHardware(aTarget, aCameraId, aCamera)
    1.32 +{
    1.33 +  DOM_CAMERA_LOGA("v===== Created TestGonkCameraHardware =====v\n");
    1.34 +  DOM_CAMERA_LOGT("%s:%d : this=%p (aTarget=%p)\n",
    1.35 +    __func__, __LINE__, this, aTarget);
    1.36 +  MOZ_COUNT_CTOR(TestGonkCameraHardware);
    1.37 +}
    1.38 +
    1.39 +TestGonkCameraHardware::~TestGonkCameraHardware()
    1.40 +{
    1.41 +  MOZ_COUNT_DTOR(TestGonkCameraHardware);
    1.42 +  DOM_CAMERA_LOGA("^===== Destroyed TestGonkCameraHardware =====^\n");
    1.43 +}
    1.44 +
    1.45 +nsresult
    1.46 +TestGonkCameraHardware::Init()
    1.47 +{
    1.48 +  if (IsTestCase("init-failure")) {
    1.49 +    return NS_ERROR_FAILURE;
    1.50 +  }
    1.51 +
    1.52 +  return GonkCameraHardware::Init();
    1.53 +}
    1.54 +
    1.55 +const nsCString
    1.56 +TestGonkCameraHardware::TestCase()
    1.57 +{
    1.58 +  const nsCString test = Preferences::GetCString("camera.control.test.hardware");
    1.59 +  return test;
    1.60 +}
    1.61 +
    1.62 +const nsCString
    1.63 +TestGonkCameraHardware::GetExtraParameters()
    1.64 +{
    1.65 +  /**
    1.66 +   * The contents of this pref are appended to the flattened string of
    1.67 +   * parameters stuffed into GonkCameraParameters by the camera library.
    1.68 +   * It consists of semicolon-delimited key=value pairs, e.g.
    1.69 +   *
    1.70 +   *   focus-mode=auto;flash-mode=auto;preview-size=1024x768
    1.71 +   *
    1.72 +   * The unflattening process breaks this string up on semicolon boundaries
    1.73 +   * and sets an entry in a hashtable of strings with the token before
    1.74 +   * the equals sign as the key, and the token after as the value. Because
    1.75 +   * the string is parsed in order, key=value pairs occuring later in the
    1.76 +   * string will replace value pairs appearing earlier, making it easy to
    1.77 +   * inject fake, testable values into the parameters table.
    1.78 +   *
    1.79 +   * One constraint of this approach is that neither the key nor the value
    1.80 +   * may contain equals signs or semicolons. We don't enforce that here
    1.81 +   * so that we can also test correct handling of improperly-formatted values.
    1.82 +   */
    1.83 +  const nsCString parameters = Preferences::GetCString("camera.control.test.hardware.gonk.parameters");
    1.84 +  DOM_CAMERA_LOGA("TestGonkCameraHardware : extra-parameters '%s'\n",
    1.85 +    parameters.get());
    1.86 +  return parameters;
    1.87 +}
    1.88 +
    1.89 +bool
    1.90 +TestGonkCameraHardware::IsTestCaseInternal(const char* aTest, const char* aFile, int aLine)
    1.91 +{
    1.92 +  if (TestCase().EqualsASCII(aTest)) {
    1.93 +    DOM_CAMERA_LOGA("TestGonkCameraHardware : test-case '%s' (%s:%d)\n",
    1.94 +      aTest, aFile, aLine);
    1.95 +    return true;
    1.96 +  }
    1.97 +
    1.98 +  return false;
    1.99 +}
   1.100 +
   1.101 +int
   1.102 +TestGonkCameraHardware::TestCaseError(int aDefaultError)
   1.103 +{
   1.104 +  // for now, just return the default error
   1.105 +  return aDefaultError;
   1.106 +}
   1.107 +
   1.108 +int
   1.109 +TestGonkCameraHardware::AutoFocus()
   1.110 +{
   1.111 +  class AutoFocusFailure : public nsRunnable
   1.112 +  {
   1.113 +  public:
   1.114 +    AutoFocusFailure(nsGonkCameraControl* aTarget)
   1.115 +      : mTarget(aTarget)
   1.116 +    { }
   1.117 +
   1.118 +    NS_IMETHODIMP
   1.119 +    Run()
   1.120 +    {
   1.121 +      OnAutoFocusComplete(mTarget, false);
   1.122 +      return NS_OK;
   1.123 +    }
   1.124 +
   1.125 +  protected:
   1.126 +    nsGonkCameraControl* mTarget;
   1.127 +  };
   1.128 +
   1.129 +  if (IsTestCase("auto-focus-failure")) {
   1.130 +    return TestCaseError(UNKNOWN_ERROR);
   1.131 +  }
   1.132 +  if (IsTestCase("auto-focus-process-failure")) {
   1.133 +    nsresult rv = NS_DispatchToCurrentThread(new AutoFocusFailure(mTarget));
   1.134 +    if (NS_SUCCEEDED(rv)) {
   1.135 +      return OK;
   1.136 +    }
   1.137 +    DOM_CAMERA_LOGE("Failed to dispatch AutoFocusFailure runnable (0x%08x)\n", rv);
   1.138 +    return UNKNOWN_ERROR;
   1.139 +  }
   1.140 +
   1.141 +  return GonkCameraHardware::AutoFocus();
   1.142 +}
   1.143 +
   1.144 +// These classes have to be external to StartFaceDetection(), at least
   1.145 +// until we pick up gcc 4.5, which supports local classes as template
   1.146 +// arguments.
   1.147 +class FaceDetected : public nsRunnable
   1.148 +{
   1.149 +public:
   1.150 +  FaceDetected(nsGonkCameraControl* aTarget)
   1.151 +    : mTarget(aTarget)
   1.152 +  { }
   1.153 +
   1.154 +  ~FaceDetected()
   1.155 +  {
   1.156 +    ReleaseFacesArray();
   1.157 +  }
   1.158 +
   1.159 +  NS_IMETHODIMP
   1.160 +  Run()
   1.161 +  {
   1.162 +    InitMetaData();
   1.163 +    OnFacesDetected(mTarget, &mMetaData);
   1.164 +    return NS_OK;
   1.165 +  }
   1.166 +
   1.167 +protected:
   1.168 +  virtual nsresult InitMetaData() = 0;
   1.169 +
   1.170 +  nsresult
   1.171 +  AllocateFacesArray(uint32_t num)
   1.172 +  {
   1.173 +    mMetaData.faces = new camera_face_t[num];
   1.174 +    return NS_OK;
   1.175 +  }
   1.176 +
   1.177 +  nsresult
   1.178 +  ReleaseFacesArray()
   1.179 +  {
   1.180 +    delete [] mMetaData.faces;
   1.181 +    mMetaData.faces = nullptr;
   1.182 +    return NS_OK;
   1.183 +  }
   1.184 +
   1.185 +  nsRefPtr<nsGonkCameraControl> mTarget;
   1.186 +  camera_frame_metadata_t mMetaData;
   1.187 +};
   1.188 +
   1.189 +class OneFaceDetected : public FaceDetected
   1.190 +{
   1.191 +public:
   1.192 +  OneFaceDetected(nsGonkCameraControl* aTarget)
   1.193 +    : FaceDetected(aTarget)
   1.194 +  { }
   1.195 +
   1.196 +  nsresult
   1.197 +  InitMetaData() MOZ_OVERRIDE
   1.198 +  {
   1.199 +    mMetaData.number_of_faces = 1;
   1.200 +    AllocateFacesArray(1);
   1.201 +    mMetaData.faces[0].id = 1;
   1.202 +    mMetaData.faces[0].score = 2;
   1.203 +    mMetaData.faces[0].rect[0] = 3;
   1.204 +    mMetaData.faces[0].rect[1] = 4;
   1.205 +    mMetaData.faces[0].rect[2] = 5;
   1.206 +    mMetaData.faces[0].rect[3] = 6;
   1.207 +    mMetaData.faces[0].left_eye[0] = 7;
   1.208 +    mMetaData.faces[0].left_eye[1] = 8;
   1.209 +    mMetaData.faces[0].right_eye[0] = 9;
   1.210 +    mMetaData.faces[0].right_eye[1] = 10;
   1.211 +    mMetaData.faces[0].mouth[0] = 11;
   1.212 +    mMetaData.faces[0].mouth[1] = 12;
   1.213 +
   1.214 +    return NS_OK;
   1.215 +  }
   1.216 +};
   1.217 +
   1.218 +class TwoFacesDetected : public FaceDetected
   1.219 +{
   1.220 +public:
   1.221 +  TwoFacesDetected(nsGonkCameraControl* aTarget)
   1.222 +    : FaceDetected(aTarget)
   1.223 +  { }
   1.224 +
   1.225 +  nsresult
   1.226 +  InitMetaData() MOZ_OVERRIDE
   1.227 +  {
   1.228 +    mMetaData.number_of_faces = 2;
   1.229 +    AllocateFacesArray(2);
   1.230 +    mMetaData.faces[0].id = 1;
   1.231 +    mMetaData.faces[0].score = 2;
   1.232 +    mMetaData.faces[0].rect[0] = 3;
   1.233 +    mMetaData.faces[0].rect[1] = 4;
   1.234 +    mMetaData.faces[0].rect[2] = 5;
   1.235 +    mMetaData.faces[0].rect[3] = 6;
   1.236 +    mMetaData.faces[0].left_eye[0] = 7;
   1.237 +    mMetaData.faces[0].left_eye[1] = 8;
   1.238 +    mMetaData.faces[0].right_eye[0] = 9;
   1.239 +    mMetaData.faces[0].right_eye[1] = 10;
   1.240 +    mMetaData.faces[0].mouth[0] = 11;
   1.241 +    mMetaData.faces[0].mouth[1] = 12;
   1.242 +    mMetaData.faces[1].id = 13;
   1.243 +    mMetaData.faces[1].score = 14;
   1.244 +    mMetaData.faces[1].rect[0] = 15;
   1.245 +    mMetaData.faces[1].rect[1] = 16;
   1.246 +    mMetaData.faces[1].rect[2] = 17;
   1.247 +    mMetaData.faces[1].rect[3] = 18;
   1.248 +    mMetaData.faces[1].left_eye[0] = 19;
   1.249 +    mMetaData.faces[1].left_eye[1] = 20;
   1.250 +    mMetaData.faces[1].right_eye[0] = 21;
   1.251 +    mMetaData.faces[1].right_eye[1] = 22;
   1.252 +    mMetaData.faces[1].mouth[0] = 23;
   1.253 +    mMetaData.faces[1].mouth[1] = 24;
   1.254 +
   1.255 +    return NS_OK;
   1.256 +  }
   1.257 +};
   1.258 +
   1.259 +class OneFaceNoFeaturesDetected : public FaceDetected
   1.260 +{
   1.261 +public:
   1.262 +  OneFaceNoFeaturesDetected(nsGonkCameraControl* aTarget)
   1.263 +    : FaceDetected(aTarget)
   1.264 +  { }
   1.265 +
   1.266 +  nsresult
   1.267 +  InitMetaData() MOZ_OVERRIDE
   1.268 +  {
   1.269 +    mMetaData.number_of_faces = 1;
   1.270 +    AllocateFacesArray(1);
   1.271 +    mMetaData.faces[0].id = 1;
   1.272 +    // Test clamping 'score' to 100.
   1.273 +    mMetaData.faces[0].score = 1000;
   1.274 +    mMetaData.faces[0].rect[0] = 3;
   1.275 +    mMetaData.faces[0].rect[1] = 4;
   1.276 +    mMetaData.faces[0].rect[2] = 5;
   1.277 +    mMetaData.faces[0].rect[3] = 6;
   1.278 +    // Nullable values set to 'not-supported' specific values
   1.279 +    mMetaData.faces[0].left_eye[0] = -2000;
   1.280 +    mMetaData.faces[0].left_eye[1] = -2000;
   1.281 +    // Test other 'not-supported' values as well. We treat
   1.282 +    // anything outside the range [-1000, 1000] as invalid.
   1.283 +    mMetaData.faces[0].right_eye[0] = 1001;
   1.284 +    mMetaData.faces[0].right_eye[1] = -1001;
   1.285 +    mMetaData.faces[0].mouth[0] = -2000;
   1.286 +    mMetaData.faces[0].mouth[1] = 2000;
   1.287 +
   1.288 +    return NS_OK;
   1.289 +  }
   1.290 +};
   1.291 +
   1.292 +class NoFacesDetected : public FaceDetected
   1.293 +{
   1.294 +public:
   1.295 +  NoFacesDetected(nsGonkCameraControl* aTarget)
   1.296 +    : FaceDetected(aTarget)
   1.297 +  { }
   1.298 +
   1.299 +  nsresult
   1.300 +  InitMetaData() MOZ_OVERRIDE
   1.301 +  {
   1.302 +    mMetaData.number_of_faces = 0;
   1.303 +    mMetaData.faces = nullptr;
   1.304 +
   1.305 +    return NS_OK;
   1.306 +  }
   1.307 +};
   1.308 +
   1.309 +int
   1.310 +TestGonkCameraHardware::StartFaceDetection()
   1.311 +{
   1.312 +  nsRefPtr<FaceDetected> faceDetected;
   1.313 +
   1.314 +  if (IsTestCase("face-detection-detected-one-face")) {
   1.315 +    faceDetected = new OneFaceDetected(mTarget);
   1.316 +  } else if (IsTestCase("face-detection-detected-two-faces")) {
   1.317 +    faceDetected = new TwoFacesDetected(mTarget);
   1.318 +  } else if (IsTestCase("face-detection-detected-one-face-no-features")) {
   1.319 +    faceDetected = new OneFaceNoFeaturesDetected(mTarget);
   1.320 +  } else if (IsTestCase("face-detection-no-faces-detected")) {
   1.321 +    faceDetected = new NoFacesDetected(mTarget);
   1.322 +  }
   1.323 +
   1.324 +  if (!faceDetected) {
   1.325 +    return GonkCameraHardware::StartFaceDetection();
   1.326 +  }
   1.327 +
   1.328 +  nsresult rv = NS_DispatchToCurrentThread(faceDetected);
   1.329 +  if (NS_FAILED(rv)) {
   1.330 +    DOM_CAMERA_LOGE("Failed to dispatch FaceDetected runnable (0x%08x)\n", rv);
   1.331 +    return UNKNOWN_ERROR;
   1.332 +  }
   1.333 +
   1.334 +  return OK;
   1.335 +}
   1.336 +
   1.337 +int
   1.338 +TestGonkCameraHardware::StopFaceDetection()
   1.339 +{
   1.340 +  if (IsTestCase("face-detection-detected-one-face") ||
   1.341 +      IsTestCase("face-detection-detected-two-faces") ||
   1.342 +      IsTestCase("face-detection-detected-one-face-no-features") ||
   1.343 +      IsTestCase("face-detection-no-faces-detected"))
   1.344 +  {
   1.345 +    return OK;
   1.346 +  }
   1.347 +
   1.348 +  return GonkCameraHardware::StopFaceDetection();
   1.349 +}
   1.350 +
   1.351 +int
   1.352 +TestGonkCameraHardware::TakePicture()
   1.353 +{
   1.354 +  class TakePictureFailure : public nsRunnable
   1.355 +  {
   1.356 +  public:
   1.357 +    TakePictureFailure(nsGonkCameraControl* aTarget)
   1.358 +      : mTarget(aTarget)
   1.359 +    { }
   1.360 +
   1.361 +    NS_IMETHODIMP
   1.362 +    Run()
   1.363 +    {
   1.364 +      OnTakePictureError(mTarget);
   1.365 +      return NS_OK;
   1.366 +    }
   1.367 +
   1.368 +  protected:
   1.369 +    nsGonkCameraControl* mTarget;
   1.370 +  };
   1.371 +
   1.372 +  if (IsTestCase("take-picture-failure")) {
   1.373 +    return TestCaseError(UNKNOWN_ERROR);
   1.374 +  }
   1.375 +  if (IsTestCase("take-picture-process-failure")) {
   1.376 +    nsresult rv = NS_DispatchToCurrentThread(new TakePictureFailure(mTarget));
   1.377 +    if (NS_SUCCEEDED(rv)) {
   1.378 +      return OK;
   1.379 +    }
   1.380 +    DOM_CAMERA_LOGE("Failed to dispatch TakePictureFailure runnable (0x%08x)\n", rv);
   1.381 +    return UNKNOWN_ERROR;
   1.382 +  }
   1.383 +
   1.384 +  return GonkCameraHardware::TakePicture();
   1.385 +}
   1.386 +
   1.387 +int
   1.388 +TestGonkCameraHardware::StartPreview()
   1.389 +{
   1.390 +  if (IsTestCase("start-preview-failure")) {
   1.391 +    return TestCaseError(UNKNOWN_ERROR);
   1.392 +  }
   1.393 +
   1.394 +  return GonkCameraHardware::StartPreview();
   1.395 +}
   1.396 +
   1.397 +int
   1.398 +TestGonkCameraHardware::StartAutoFocusMoving(bool aIsMoving)
   1.399 +{
   1.400 +  class AutoFocusMoving : public nsRunnable
   1.401 +  {
   1.402 +  public:
   1.403 +    AutoFocusMoving(nsGonkCameraControl* aTarget, bool aIsMoving)
   1.404 +      : mTarget(aTarget)
   1.405 +      , mIsMoving(aIsMoving)
   1.406 +    { }
   1.407 +
   1.408 +    NS_IMETHODIMP
   1.409 +    Run()
   1.410 +    {
   1.411 +      OnAutoFocusMoving(mTarget, mIsMoving);
   1.412 +      return NS_OK;
   1.413 +    }
   1.414 +
   1.415 +  protected:
   1.416 +    nsGonkCameraControl* mTarget;
   1.417 +    bool mIsMoving;
   1.418 +  };
   1.419 +
   1.420 +  nsresult rv = NS_DispatchToCurrentThread(new AutoFocusMoving(mTarget, aIsMoving));
   1.421 +  if (NS_SUCCEEDED(rv)) {
   1.422 +    return OK;
   1.423 +  }
   1.424 +  DOM_CAMERA_LOGE("Failed to dispatch AutoFocusMoving runnable (0x%08x)\n", rv);
   1.425 +  return UNKNOWN_ERROR;
   1.426 +}
   1.427 +
   1.428 +int
   1.429 +TestGonkCameraHardware::PushParameters(const GonkCameraParameters& aParams)
   1.430 +{
   1.431 +  if (IsTestCase("push-parameters-failure")) {
   1.432 +    return TestCaseError(UNKNOWN_ERROR);
   1.433 +  }
   1.434 +
   1.435 +  nsString focusMode;
   1.436 +  GonkCameraParameters& params = const_cast<GonkCameraParameters&>(aParams);
   1.437 +  params.Get(CAMERA_PARAM_FOCUSMODE, focusMode);
   1.438 +  if (focusMode.EqualsASCII("continuous-picture") ||
   1.439 +      focusMode.EqualsASCII("continuous-video"))
   1.440 +  {
   1.441 +    if (IsTestCase("autofocus-moving-true")) {
   1.442 +      return StartAutoFocusMoving(true);
   1.443 +    } else if (IsTestCase("autofocus-moving-false")) {
   1.444 +      return StartAutoFocusMoving(false);
   1.445 +    }
   1.446 +  }
   1.447 +
   1.448 +  return GonkCameraHardware::PushParameters(aParams);
   1.449 +}
   1.450 +
   1.451 +nsresult
   1.452 +TestGonkCameraHardware::PullParameters(GonkCameraParameters& aParams)
   1.453 +{
   1.454 +  if (IsTestCase("pull-parameters-failure")) {
   1.455 +    return static_cast<nsresult>(TestCaseError(UNKNOWN_ERROR));
   1.456 +  }
   1.457 +
   1.458 +  String8 s = mCamera->getParameters();
   1.459 +  nsCString extra = GetExtraParameters();
   1.460 +  if (!extra.IsEmpty()) {
   1.461 +    s += ";";
   1.462 +    s += extra.get();
   1.463 +  }
   1.464 +
   1.465 +  return aParams.Unflatten(s);
   1.466 +}
   1.467 +
   1.468 +int
   1.469 +TestGonkCameraHardware::StartRecording()
   1.470 +{
   1.471 +  if (IsTestCase("start-recording-failure")) {
   1.472 +    return TestCaseError(UNKNOWN_ERROR);
   1.473 +  }
   1.474 +
   1.475 +  return GonkCameraHardware::StartRecording();
   1.476 +}
   1.477 +
   1.478 +int
   1.479 +TestGonkCameraHardware::StopRecording()
   1.480 +{
   1.481 +  if (IsTestCase("stop-recording-failure")) {
   1.482 +    return TestCaseError(UNKNOWN_ERROR);
   1.483 +  }
   1.484 +
   1.485 +  return GonkCameraHardware::StopRecording();
   1.486 +}
   1.487 +
   1.488 +int
   1.489 +TestGonkCameraHardware::SetListener(const sp<GonkCameraListener>& aListener)
   1.490 +{
   1.491 +  if (IsTestCase("set-listener-failure")) {
   1.492 +    return TestCaseError(UNKNOWN_ERROR);
   1.493 +  }
   1.494 +
   1.495 +  return GonkCameraHardware::SetListener(aListener);
   1.496 +}
   1.497 +
   1.498 +int
   1.499 +TestGonkCameraHardware::StoreMetaDataInBuffers(bool aEnabled)
   1.500 +{
   1.501 +  if (IsTestCase("store-metadata-in-buffers-failure")) {
   1.502 +    return TestCaseError(UNKNOWN_ERROR);
   1.503 +  }
   1.504 +
   1.505 +  return GonkCameraHardware::StoreMetaDataInBuffers(aEnabled);
   1.506 +}

mercurial