Bug 1014877 - Uncouple preview and video-recording frame sizes. r=aosmond, a=bajaj
authorMike Habicher <mikeh@mozilla.com>
Tue, 16 Sep 2014 15:36:48 -0400
changeset 225312 f5170efd106107d34889154eb80075a684bfbc37
parent 225311 02494f813b0db66ff2c9ebcb82cb866cd13a84ac
child 225313 70c0f06356c1725e384423fb0d6f879823a6a06b
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaosmond, bajaj
bugs1014877
milestone34.0a2
Bug 1014877 - Uncouple preview and video-recording frame sizes. r=aosmond, a=bajaj
dom/camera/GonkCameraControl.cpp
dom/camera/GonkCameraControl.h
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -64,16 +64,17 @@ nsGonkCameraControl::nsGonkCameraControl
   : CameraControlImpl(aCameraId)
   , mLastPictureSize({0, 0})
   , mLastThumbnailSize({0, 0})
   , mPreviewFps(30)
   , mResumePreviewAfterTakingPicture(false) // XXXmikeh - see bug 950102
   , mFlashSupported(false)
   , mLuminanceSupported(false)
   , mAutoFlashModeOverridden(false)
+  , mSeparateVideoAndPreviewSizesSupported(false)
   , mDeferConfigUpdate(0)
   , mMediaProfiles(nullptr)
   , mRecorder(nullptr)
   , mRecorderMonitor("GonkCameraControl::mRecorder.Monitor")
   , mProfileManager(nullptr)
   , mRecorderProfile(nullptr)
   , mVideoFile(nullptr)
   , mReentrantMonitor("GonkCameraControl::OnTakePicture.Monitor")
@@ -162,17 +163,16 @@ nsGonkCameraControl::Initialize()
   int areas;
   mParams.Get(CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS, areas);
   mCurrentConfiguration.mMaxMeteringAreas = areas != -1 ? areas : 0;
   mParams.Get(CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS, areas);
   mCurrentConfiguration.mMaxFocusAreas = areas != -1 ? areas : 0;
 
   mParams.Get(CAMERA_PARAM_PICTURE_SIZE, mLastPictureSize);
   mParams.Get(CAMERA_PARAM_PREVIEWSIZE, mCurrentConfiguration.mPreviewSize);
-  mParams.Get(CAMERA_PARAM_VIDEOSIZE, mLastRecorderSize);
 
   nsString luminance; // check for support
   mParams.Get(CAMERA_PARAM_LUMINANCE, luminance);
   mLuminanceSupported = !luminance.IsEmpty();
 
   nsString flashMode;
   mParams.Get(CAMERA_PARAM_FLASHMODE, flashMode);
   mFlashSupported = !flashMode.IsEmpty();
@@ -186,27 +186,37 @@ nsGonkCameraControl::Initialize()
     mLastPictureSize.width, mLastPictureSize.height);
   DOM_CAMERA_LOGI(" - default picture file format:   %s\n",
     NS_ConvertUTF16toUTF8(mFileFormat).get());
   DOM_CAMERA_LOGI(" - default picture quality:       %f\n", quality);
   DOM_CAMERA_LOGI(" - default thumbnail size:        %u x %u\n",
     mLastThumbnailSize.width, mLastThumbnailSize.height);
   DOM_CAMERA_LOGI(" - default preview size:          %u x %u\n",
     mCurrentConfiguration.mPreviewSize.width, mCurrentConfiguration.mPreviewSize.height);
-  DOM_CAMERA_LOGI(" - default video recorder size:   %u x %u\n",
-    mLastRecorderSize.width, mLastRecorderSize.height);
   DOM_CAMERA_LOGI(" - luminance reporting:           %ssupported\n",
     mLuminanceSupported ? "" : "NOT ");
   if (mFlashSupported) {
     DOM_CAMERA_LOGI(" - flash:                         supported, default mode '%s'\n",
       NS_ConvertUTF16toUTF8(flashMode).get());
   } else {
     DOM_CAMERA_LOGI(" - flash:                         NOT supported\n");
   }
 
+  nsAutoTArray<Size, 16> sizes;
+  mParams.Get(CAMERA_PARAM_SUPPORTED_VIDEOSIZES, sizes);
+  if (sizes.Length() > 0) {
+    mSeparateVideoAndPreviewSizesSupported = true;
+    DOM_CAMERA_LOGI(" - support for separate preview and video sizes\n");
+    mParams.Get(CAMERA_PARAM_VIDEOSIZE, mLastRecorderSize);
+    DOM_CAMERA_LOGI(" - default video recorder size:   %u x %u\n",
+      mLastRecorderSize.width, mLastRecorderSize.height);
+  } else {
+    mLastRecorderSize = mCurrentConfiguration.mPreviewSize;
+  }
+
   return NS_OK;
 }
 
 nsGonkCameraControl::~nsGonkCameraControl()
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p, mCameraHw = %p\n", __func__, __LINE__, this, mCameraHw.get());
 
   StopImpl();
@@ -246,19 +256,16 @@ nsGonkCameraControl::SetConfigurationInt
     rv = Set(CAMERA_PARAM_RECORDINGHINT, aConfig.mMode == kVideoMode);
     if (NS_FAILED(rv)) {
       DOM_CAMERA_LOGE("Failed to set recording hint (0x%x)\n", rv);
     }
   }
 
   mCurrentConfiguration.mMode = aConfig.mMode;
   mCurrentConfiguration.mRecorderProfile = aConfig.mRecorderProfile;
-  if (aConfig.mMode == kVideoMode) {
-    mCurrentConfiguration.mPreviewSize = mLastRecorderSize;
-  }
 
   OnConfigurationChange();
   return NS_OK;
 }
 
 nsresult
 nsGonkCameraControl::SetConfigurationImpl(const Configuration& aConfig)
 {
@@ -311,32 +318,16 @@ nsGonkCameraControl::SetPictureConfigura
   DOM_CAMERA_LOGI("picture mode preview: wanted %ux%u, got %ux%u (%u fps)\n",
     aConfig.mPreviewSize.width, aConfig.mPreviewSize.height,
     mCurrentConfiguration.mPreviewSize.width, mCurrentConfiguration.mPreviewSize.height,
     mPreviewFps);
 
   return NS_OK;
 }
 
-nsresult
-nsGonkCameraControl::SetVideoConfiguration(const Configuration& aConfig)
-{
-  DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
-
-  nsresult rv = SetupVideoMode(aConfig.mRecorderProfile);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  DOM_CAMERA_LOGI("video mode preview: profile '%s', got %ux%u (%u fps)\n",
-    NS_ConvertUTF16toUTF8(aConfig.mRecorderProfile).get(),
-    mLastRecorderSize.width, mLastRecorderSize.height,
-    mPreviewFps);
-
-  return rv;
-}
-
 // Parameter management.
 nsresult
 nsGonkCameraControl::PushParameters()
 {
   uint32_t dcu = mDeferConfigUpdate;
   if (dcu > 0) {
     DOM_CAMERA_LOGI("Defering config update (nest level %u)\n", dcu);
     return NS_OK;
@@ -395,22 +386,18 @@ nsGonkCameraControl::SetAndPush(uint32_t
   }
   return PushParameters();
 }
 
 // Array-of-Size parameter accessor.
 nsresult
 nsGonkCameraControl::Get(uint32_t aKey, nsTArray<Size>& aSizes)
 {
-  if (aKey == CAMERA_PARAM_SUPPORTED_VIDEOSIZES) {
-    nsresult rv = mParams.Get(aKey, aSizes);
-    if (aSizes.Length() != 0) {
-      return rv;
-    }
-    DOM_CAMERA_LOGI("Camera doesn't support video independent of the preview\n");
+  if (aKey == CAMERA_PARAM_SUPPORTED_VIDEOSIZES &&
+      !mSeparateVideoAndPreviewSizesSupported) {
     aKey = CAMERA_PARAM_SUPPORTED_PREVIEWSIZES;
   }
 
   return mParams.Get(aKey, aSizes);
 }
 
 // Array-of-doubles parameter accessor.
 nsresult
@@ -1285,31 +1272,40 @@ nsGonkCameraControl::SetPreviewSize(cons
   Size best;
   rv  = GetSupportedSize(aSize, previewSizes, best);
   if (NS_FAILED(rv)) {
     DOM_CAMERA_LOGE("Failed to find a supported preview size, requested size %dx%d",
         aSize.width, aSize.height);
     return rv;
   }
 
-  // Some camera drivers will ignore our preview size if it's larger
-  // than the currently set video recording size, so we need to set
-  // the video size here as well, just in case.
-  if (best.width > mLastRecorderSize.width || best.height > mLastRecorderSize.height) {
-    SetVideoSize(best);
+  if (mSeparateVideoAndPreviewSizesSupported) {
+    // Some camera drivers will ignore our preview size if it's larger
+    // than the currently set video recording size, so we need to set
+    // the video size here as well, just in case.
+    if (best.width > mLastRecorderSize.width || best.height > mLastRecorderSize.height) {
+      SetVideoSize(best);
+    }
+  } else {
+    mLastRecorderSize = best;
   }
   mCurrentConfiguration.mPreviewSize = best;
   return Set(CAMERA_PARAM_PREVIEWSIZE, best);
 }
 
 nsresult
 nsGonkCameraControl::SetVideoSize(const Size& aSize)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
 
+  if (!mSeparateVideoAndPreviewSizesSupported) {
+    DOM_CAMERA_LOGE("Camera does not support setting separate video size\n");
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+  
   nsTArray<Size> videoSizes;
   nsresult rv = Get(CAMERA_PARAM_SUPPORTED_VIDEOSIZES, videoSizes);
   if (NS_FAILED(rv)) {
     DOM_CAMERA_LOGE("Camera failed to return any video sizes (0x%x)\n", rv);
     return rv;
   }
 
   Size best;
@@ -1371,25 +1367,24 @@ nsGonkCameraControl::GetSupportedSize(co
         rv = NS_OK;
       }
     }
   }
   return rv;
 }
 
 nsresult
-nsGonkCameraControl::SetupVideoMode(const nsAString& aProfile)
+nsGonkCameraControl::SetVideoConfiguration(const Configuration& aConfig)
 {
   DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
 
   // read preferences for camcorder
   mMediaProfiles = MediaProfiles::getInstance();
 
-  nsAutoCString profile = NS_ConvertUTF16toUTF8(aProfile);
-  // XXXkhuey are we leaking?
+  nsAutoCString profile = NS_ConvertUTF16toUTF8(aConfig.mRecorderProfile);
   mRecorderProfile = GetGonkRecorderProfileManager().take()->Get(profile.get());
   if (!mRecorderProfile) {
     DOM_CAMERA_LOGE("Recorder profile '%s' is not supported\n", profile.get());
     return NS_ERROR_INVALID_ARG;
   }
 
   const GonkRecorderVideoProfile* video = mRecorderProfile->GetGonkVideoProfile();
   int width = video->GetWidth();
@@ -1404,31 +1399,43 @@ nsGonkCameraControl::SetupVideoMode(cons
   PullParametersImpl();
 
   Size size;
   size.width = static_cast<uint32_t>(width);
   size.height = static_cast<uint32_t>(height);
 
   {
     ICameraControlParameterSetAutoEnter set(this);
+    nsresult rv;
 
-    // The camera interface allows for hardware to provide two video
-    //  streams, a low resolution preview and a potentially high resolution
-    //  stream for encoding. For now we don't use this and set preview and video
-    //  size to the same thing.
-    nsresult rv = SetVideoSize(size);
-    if (NS_FAILED(rv)) {
-      DOM_CAMERA_LOGE("Failed to set video mode video size (0x%x)\n", rv);
-      return rv;
-    }
+    if (mSeparateVideoAndPreviewSizesSupported) {
+      // The camera supports two video streams: a low(er) resolution preview
+      // stream and and a potentially high(er) resolution stream for encoding. 
+      rv = SetVideoSize(size);
+      if (NS_FAILED(rv)) {
+        DOM_CAMERA_LOGE("Failed to set video mode video size (0x%x)\n", rv);
+        return rv;
+      }
 
-    rv = SetPreviewSize(size);
-    if (NS_FAILED(rv)) {
-      DOM_CAMERA_LOGE("Failed to set video mode preview size (0x%x)\n", rv);
-      return rv;
+      // The video size must be set first, before the preview size, because
+      // some platforms have a dependency between the two.
+      rv = SetPreviewSize(aConfig.mPreviewSize);
+      if (NS_FAILED(rv)) {
+        DOM_CAMERA_LOGE("Failed to set video mode preview size (0x%x)\n", rv);
+        return rv;
+      }
+    } else {
+      // The camera only supports a single video stream: in this case, we set
+      // the preview size to be the desired video recording size, and ignore
+      // the specified preview size.
+      rv = SetPreviewSize(size);
+      if (NS_FAILED(rv)) {
+        DOM_CAMERA_LOGE("Failed to set video mode preview size (0x%x)\n", rv);
+        return rv;
+      }
     }
 
     rv = Set(CAMERA_PARAM_PREVIEWFRAMERATE, fps);
     if (NS_FAILED(rv)) {
       DOM_CAMERA_LOGE("Failed to set video mode frame rate (0x%x)\n", rv);
       return rv;
     }
   }
--- a/dom/camera/GonkCameraControl.h
+++ b/dom/camera/GonkCameraControl.h
@@ -121,17 +121,16 @@ protected:
   virtual nsresult PushParametersImpl() MOZ_OVERRIDE;
   virtual nsresult PullParametersImpl() MOZ_OVERRIDE;
   virtual already_AddRefed<RecorderProfileManager> GetRecorderProfileManagerImpl() MOZ_OVERRIDE;
   already_AddRefed<GonkRecorderProfileManager> GetGonkRecorderProfileManager();
 
   nsresult SetupRecording(int aFd, int aRotation, uint64_t aMaxFileSizeBytes,
                           uint64_t aMaxVideoLengthMs);
   nsresult SetupRecordingFlash(bool aAutoEnableLowLightTorch);
-  nsresult SetupVideoMode(const nsAString& aProfile);
   nsresult SetPreviewSize(const Size& aSize);
   nsresult SetVideoSize(const Size& aSize);
   nsresult PausePreview();
   nsresult GetSupportedSize(const Size& aSize, const nsTArray<Size>& supportedSizes, Size& best);
 
   friend class SetPictureSize;
   friend class SetThumbnailSize;
   nsresult SetPictureSize(const Size& aSize);
@@ -147,16 +146,17 @@ protected:
   Size                      mLastPictureSize;
   Size                      mLastThumbnailSize;
   Size                      mLastRecorderSize;
   uint32_t                  mPreviewFps;
   bool                      mResumePreviewAfterTakingPicture;
   bool                      mFlashSupported;
   bool                      mLuminanceSupported;
   bool                      mAutoFlashModeOverridden;
+  bool                      mSeparateVideoAndPreviewSizesSupported;
   Atomic<uint32_t>          mDeferConfigUpdate;
   GonkCameraParameters      mParams;
 
   nsRefPtr<mozilla::layers::ImageContainer> mImageContainer;
 
   android::MediaProfiles*   mMediaProfiles;
   nsRefPtr<android::GonkRecorder> mRecorder;
   // Touching mRecorder happens inside this monitor because the destructor