import changes from `dev' branch of rmottola/Arctic-Fox:

- missing part of  Bug 1165772: P1. (7311039be4)
- missing gstreamer stuff (54a80d69b2)
- Bug 1214208: Do not use MP3Decoder on B2G. r=alfredo (0a19e7946e)
- Bug 1194014 - Remove redundant includes. r=jya (ccc3753113)
- Bug 1039639 - Add support for Flac on Firefox OS. r=cajbir (7d76197e07)
- Bug 875573 - Add video/x-m4v mime type. r=kentuckyfriedtakahe (6ec8af93e6)
- cleanup (6fb3d5dd26)
- Bug 1180621 - [FxOS] Enable VP9 codec for the Android version after KK. r=sotaro (58f7c2b657)
- Bug 1187247: [MSE] P2. Enable WebM in MediaSource. r=jya (2df0ee1f7a)
- Bug 1187247: [MSE] P1. Continue parsing MediaSegment if buffer starts with SimpleBlock/Block. r=kinetik (574475ed6f)
- Bug 1217170: P1. Rename functions to explicitly reflect what they are doing. r=kentuckyfriedtakahe (70c81a8179)
- Bug 1070216 - Split DOMMediaStream::InitStreamCommon into three. r=roc (1bda71cc88)
- Bug 1215582 - Rename Blacklist to Block list in GStreamerFormatReader. r=gerald (4f08077f5e)
- Bug 1170958 - Destroy track-locked MediaInputPorts when the track ends. r=roc (ff3922a2d6)
- Bug 1070216 - constify DOMMediaStream::Get[Audio/Video]Tracks(). r=roc (ba09f6f191)
- Bug 1070216 - Guard against adding a track owned by one MSG to a stream owned by another. r=padenot (a80deb8b30)
- Bug 1070216 - Implement MediaStream constructors. r=smaug,jib,padenot (3403ef2599)
- Bug 1070216 - Guard against a null MediaInputPort in DOMMediaStream::FindPlaybackDOMTrack(). r=roc (453a9ffbc1)
- Bug 1212783 - Expose TrackPort in DOMMediaStream.h r=roc (fb61c79ae7)
- Bug 1219711 - Ensure MediaStreamTrack.enabled propagates across peer connections. r=jesup (d9d1e54dae)
- Bug 1129051 - Fix double free in Camera Control Listener. Fix webrtc memory leak. r=aosmond (3e9b3bccfd)
- Bug 1152260 - Generate focused event for drivers that do not notify us when using continuous auto focus. r=mikeh (6c7bd42fdc)
- Bug 1175656 - Implement generation of recording posters in Gecko. r=dhylands,bz (51b2c66dc7)
- Bug 1187364 - Part 1. Add ability for camera to pause/resume recording. r=dhylands,bz (c54c735e37)
- Bug 1187364 - Part 2. Ensure that recording is resumed with a key frame. r=mchiang (c1c6048982)
- Bug 1187364 - Part 3. Fix missing end comment in WebIDL. r=me,bz (7faf106cc1)
- Bug 1212783 - Add a MediaStreamTrack to DOMCameraControl. r=aosmond (91e11efd3a)
- Bug 1124338 - Fix possible camera cached parameters invalidation from underlying driver modification. r=aosmond (dea67dc155)
- Bug 1196330 - Do not restart preview if configuration is unchanged. r=dhylands (097644f5d9)
- Bug 1215372 - Filter empty camera face detected events at gonk layer. r=dhylands (733efe50eb)
- Bug 1179726 - Prefer lower resolutions than 4kuhd as the default video recording profile. r=dhylands (27c71273dc)
- Bug 1222122 - Add picture size to verified parameters when reconfiguring the camera. r=dhylands (8c1fac6a4a)
- Bug 1141267 - register CameraThread with profiler, r=aosmond (299592a024)
- Bug 1008483 - removes the RW lock in CameraControlImpl and replaces it with a standard mutex. r=aosmond (45936cb90d)
- Bug 1008483 - Part 2. Readd missing nsPrintfCString.h include which has broken some local builds. r=me (9dd84b0f19)
- Bug 1191731 - Update poster API to allow application control over when poster is saved. r=bz, r=dhylands (73f9e7e0f4)
- Bug 1155648 - Fix documentation for DOMMediaStream::OnTracksAvailable. r=jesup (702828c304)
- Bug 1217170: [MSE] P2. Enable WebM/MSE on systems with no MP4/H264 support. r=kentuckyfriedtakahe (0b814b0708)
- Bug 1213177: Enable WebM on machines where H264 HW decoding is disabled. r=kentuckyfriedtakahe (e64da2ea24)
- add back some sps telemetry (52c2c64f5b)
- missing bit of Bug 1195073: [MSE/webm] P1 (9c45e82c3d)
- Bug 1150305 - sourcebuffer.buffered returns the same object if not changed. r=roc, r=bz, r=jya (6005d56c0c)
- Bug 1215447 - move flag setting from SeekStarted() to Seek(). r=roc. (a646b744c1)
- Bug 1119936 - Audio from FM Radio or Music app ceases to play when switching between front/back camera. r=roc (1a60aa7d69)
- Bug 1186806 - Part 1: Replace nsBaseHashtable::EnumerateRead() with iterators in HTMLFormControlsCollection. r=khuey (ccb8cb180a)
- Bug 1186806 - Part 2: Use NS_IMPL_CYCLE_COLLECTION_TRAVERSE instead of manual traversal in HTMLFormElement. r=khuey (57e6eabf1b)
- Bug 1186806 - Part 3: Replace nsBaseHashtable::EnumerateRead() with iterators in HTMLMediaElement. r=khuey (243ef6e83b)
- Bug 1186806 - Part 4: Replace nsBaseHashtable::EnumerateRead() with iterators in HTMLPropertiesCollection. r=khuey (499bdef85f)
- Bug 1163958 - Reduce the allocation in MediaStreamGraph - patch 3 CLOSED TREE (a557661df1)
- Bug 1219330 - Prevent the creation of TextureClient after shutdown. r=mattwoodrow (a6c047d54f)
- Bug 1205559: Make TextureChild/TextureClient thread-safe. r=nical (307c089631)
- missing bit of 1219330 (0e351ea419)
- nsRefPtr -> RefPtr (07ba248e69)
- Bug 1215023. Part 1 - make MediaDecoder::mOwner a const member. We will check mShuttingDown before calling functions of mOwner. r=kinetik. (da7f201815)
- Bug 1215023. Part 2 - remove null check of mOwner. We check mShuttingDown to know whether it is valid to call functions of mOwner. r=kinetik. (8d28a04bbe)
- Bug 1220558. Part 2 - remove unused members. r=jya. (d3a9ed8c68)
- Bug 1223599 - Remove the throttling argument from AbstractMediaDecoder::NotifyDataArrived(). r=jya. (320323ff1d)
- Bug 1194606 - Make MediaDecoderStateMachine capable of requesting different kind (decoded/raw) of media data. r=jya (1e2b6a5c44)
- Bug 1197075: P3. Decode frames ahead of MDSM requesting them. r=edwin This makes the media.*-decode-ahead pref performs more according to its name. We decode audio and video in advance so a MediaDataPromise can be resolved almost instantly. Default is 2. (b3f56447c4)
- Bug 1189964 - Fix bustage. r=bustage CLOSED TREE (afaa49b4b5)
- Bug 1212149 - e10s support for opening notification settings. r=wchen (f0e7778fb6)
- Bug 1215644 - Use child process volume service cache for available and storage status requests. r=dhylands (dfd49f2ef3)
- bug 1215552 - nsHttpConnectionMgr::PostEvent shouldnt manually ref count r=hurley (5e2f1886e6)
- Bug 1219392 - Capitalize mozilla::unused to avoid conflicts. r=froydnj (0c8bb7f15a)
- bug 1217834 - buzzfeed packet loss r=dragana (e9a60b605f)
- Bug 1168033 - Add a comment to nsHttpConnectionMgr.cpp explaining the assignment of attemptedOptimisticPipeline. r=mcmanus (2451996350)
- bug 1189645 - remove spdy telem r=hurley (cda90abbdb)
- Bug 1148268 - fixed misspelling attribute mActorDestoryed. r=dhyland. (3615d68765)
- Bug 1216031 - Make MediaDecoder::mVideoFrameContainer const. r=kinetik. (a3feb9d6bc)
- missing bits of  Bug 1165515 - Part 13-2 (009e32281f)
- Bug 1131473 - crash in -[NativeMenuItemTarget menuItemHit:]. r=spohl (ea2da6441c)
- Bug 1216416 - Fix -Wimplicit-fallthrough warnings in widget/cocoa. r=spohl (faaa390b20)
- Bug 1181977 - Firefox app menu contains only "Quit" in certain edgecases. r=spohl (0b9d912961)
This commit is contained in:
2022-12-06 13:48:22 +08:00
parent 6b21bacef6
commit 86a3aa0b54
329 changed files with 3290 additions and 2125 deletions
+400 -66
View File
@@ -27,17 +27,22 @@
#include <media/mediaplayer.h>
#include <media/MediaProfiles.h>
#include "GrallocImages.h"
#include "imgIEncoder.h"
#include "libyuv.h"
#include "nsNetUtil.h" // for NS_ReadInputStreamToBuffer
#endif
#include "nsNetCID.h" // for NS_STREAMTRANSPORTSERVICE_CONTRACTID
#include "nsAutoPtr.h" // for nsAutoArrayPtr
#include "nsCOMPtr.h"
#include "nsMemory.h"
#include "nsThread.h"
#include "nsITimer.h"
#include "mozilla/FileUtils.h"
#include "mozilla/Services.h"
#include "mozilla/unused.h"
#include "mozilla/ipc/FileDescriptorUtils.h"
#include "nsAlgorithm.h"
#include "nsPrintfCString.h"
#include "AutoRwLock.h"
#include "GonkCameraHwMgr.h"
#include "GonkRecorderProfiles.h"
#include "CameraCommon.h"
@@ -45,6 +50,7 @@
#include "DeviceStorageFileDescriptor.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::layers;
using namespace mozilla::gfx;
using namespace mozilla::ipc;
@@ -59,6 +65,9 @@ using namespace android;
} \
} while(0)
static const unsigned long kAutoFocusCompleteTimeoutMs = 1000;
static const int32_t kAutoFocusCompleteTimeoutLimit = 3;
// Construct nsGonkCameraControl on the main thread.
nsGonkCameraControl::nsGonkCameraControl(uint32_t aCameraId)
: mCameraId(aCameraId)
@@ -75,11 +84,20 @@ nsGonkCameraControl::nsGonkCameraControl(uint32_t aCameraId)
#endif
, mRecorderMonitor("GonkCameraControl::mRecorder.Monitor")
, mVideoFile(nullptr)
, mCapturePoster(false)
, mAutoFocusPending(false)
, mAutoFocusCompleteExpired(0)
, mPrevFacesDetected(0)
, mReentrantMonitor("GonkCameraControl::OnTakePicture.Monitor")
{
// Constructor runs on the main thread...
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
mImageContainer = LayerManager::CreateImageContainer();
mAutoFocusCompleteTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
if (NS_WARN_IF(!mAutoFocusCompleteTimer)) {
mAutoFocusCompleteExpired = kAutoFocusCompleteTimeoutLimit;
}
}
nsresult
@@ -122,13 +140,19 @@ nsGonkCameraControl::StartInternal(const Configuration* aInitialConfig)
case NS_ERROR_ALREADY_INITIALIZED:
case NS_OK:
break;
default:
return rv;
}
if (aInitialConfig) {
rv = SetConfigurationInternal(*aInitialConfig);
Configuration config;
rv = ValidateConfiguration(*aInitialConfig, config);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = SetConfigurationInternal(config);
if (NS_WARN_IF(NS_FAILED(rv))) {
// The initial configuration failed, close up the hardware
StopInternal();
@@ -166,9 +190,11 @@ nsGonkCameraControl::Initialize()
DOM_CAMERA_LOGI("Initializing camera %d (this=%p, mCameraHw=%p)\n", mCameraId, this, mCameraHw.get());
mCurrentConfiguration.mRecorderProfile.Truncate();
mRequestedPreviewSize.width = UINT32_MAX;
mRequestedPreviewSize.height = UINT32_MAX;
// Initialize our camera configuration database.
PullParametersImpl();
mCameraHw->PullParameters(mParams);
// Set preferred preview frame format.
mParams.Set(CAMERA_PARAM_PREVIEWFORMAT, NS_LITERAL_STRING("yuv420sp"));
@@ -261,7 +287,7 @@ nsGonkCameraControl::Initialize()
DOM_CAMERA_LOGI(" - metering mode: '%s'\n",
NS_ConvertUTF16toUTF8(mode).get());
}
return NS_OK;
}
@@ -304,9 +330,19 @@ nsGonkCameraControl::ValidateConfiguration(const Configuration& aConfig, Configu
return NS_ERROR_INVALID_ARG;
}
if (mCurrentConfiguration.mMode == aConfig.mMode &&
mCurrentConfiguration.mRecorderProfile.Equals(profile->GetName()) &&
mRequestedPreviewSize.Equals(aConfig.mPreviewSize) &&
mCurrentConfiguration.mPictureSize.Equals(aValidatedConfig.mPictureSize))
{
DOM_CAMERA_LOGI("Camera configuration is unchanged\n");
return NS_ERROR_ALREADY_INITIALIZED;
}
aValidatedConfig.mMode = aConfig.mMode;
aValidatedConfig.mPreviewSize = aConfig.mPreviewSize;
aValidatedConfig.mRecorderProfile = profile->GetName();
mRequestedPreviewSize = aConfig.mPreviewSize;
return NS_OK;
}
@@ -315,53 +351,46 @@ nsGonkCameraControl::SetConfigurationInternal(const Configuration& aConfig)
{
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
// Ensure sanity of all provided parameters and determine defaults if
// none are provided when given a new configuration
Configuration config;
nsresult rv = ValidateConfiguration(aConfig, config);
ICameraControlParameterSetAutoEnter set(this);
nsresult rv;
switch (aConfig.mMode) {
case kPictureMode:
rv = SetPictureConfiguration(aConfig);
break;
case kVideoMode:
rv = SetVideoConfiguration(aConfig);
break;
default:
MOZ_ASSERT_UNREACHABLE("Unanticipated camera mode in SetConfigurationInternal()");
rv = NS_ERROR_FAILURE;
break;
}
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
if (NS_WARN_IF(NS_FAILED(rv))) {
mRequestedPreviewSize.width = UINT32_MAX;
mRequestedPreviewSize.height = UINT32_MAX;
return rv;
}
{
ICameraControlParameterSetAutoEnter set(this);
rv = Set(CAMERA_PARAM_RECORDINGHINT, aConfig.mMode == kVideoMode);
if (NS_FAILED(rv)) {
DOM_CAMERA_LOGE("Failed to set recording hint (0x%x)\n", rv);
}
switch (config.mMode) {
case kPictureMode:
rv = SetPictureConfiguration(config);
break;
mCurrentConfiguration.mMode = aConfig.mMode;
mCurrentConfiguration.mRecorderProfile = aConfig.mRecorderProfile;
case kVideoMode:
rv = SetVideoConfiguration(config);
break;
default:
MOZ_ASSERT_UNREACHABLE("Unanticipated camera mode in SetConfigurationInternal()");
rv = NS_ERROR_FAILURE;
break;
}
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = Set(CAMERA_PARAM_RECORDINGHINT, config.mMode == kVideoMode);
if (NS_FAILED(rv)) {
DOM_CAMERA_LOGE("Failed to set recording hint (0x%x)\n", rv);
}
mCurrentConfiguration.mMode = config.mMode;
mCurrentConfiguration.mRecorderProfile = config.mRecorderProfile;
if (config.mMode == kPictureMode) {
mCurrentConfiguration.mPictureSize = config.mPictureSize;
} else /* if config.mMode == kVideoMode */ {
// The following is best-effort; we don't currently support taking
// pictures while in video mode, but we should at least return
// sane values to OnConfigurationChange() handlers...
SetPictureSizeImpl(config.mPictureSize);
}
if (aConfig.mMode == kPictureMode) {
mCurrentConfiguration.mPictureSize = aConfig.mPictureSize;
} else /* if config.mMode == kVideoMode */ {
// The following is best-effort; we don't currently support taking
// pictures while in video mode, but we should at least return
// sane values to OnConfigurationChange() handlers...
SetPictureSizeImpl(aConfig.mPictureSize);
}
return NS_OK;
}
@@ -377,8 +406,19 @@ nsGonkCameraControl::SetConfigurationImpl(const Configuration& aConfig)
return NS_ERROR_INVALID_ARG;
}
Configuration config;
nsresult rv = ValidateConfiguration(aConfig, config);
if (rv == NS_ERROR_ALREADY_INITIALIZED) {
// Configuration did not change, so no need to stop/start the preview
// or push parameters to the camera hardware
OnConfigurationChange();
return NS_OK;
} else if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// Stop any currently running preview
nsresult rv = PausePreview();
rv = PausePreview();
if (NS_FAILED(rv)) {
DOM_CAMERA_LOGW("PausePreview() in SetConfigurationImpl() failed (0x%x)\n", rv);
if (rv == NS_ERROR_NOT_INITIALIZED) {
@@ -389,7 +429,7 @@ nsGonkCameraControl::SetConfigurationImpl(const Configuration& aConfig)
}
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
rv = SetConfigurationInternal(aConfig);
rv = SetConfigurationInternal(config);
if (NS_WARN_IF(NS_FAILED(rv))) {
StopPreviewImpl();
return rv;
@@ -813,6 +853,12 @@ nsGonkCameraControl::AutoFocusImpl()
if (mCameraHw->AutoFocus() != OK) {
return NS_ERROR_FAILURE;
}
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mAutoFocusPending = true;
if (mAutoFocusCompleteTimer) {
mAutoFocusCompleteTimer->Cancel();
}
return NS_OK;
}
@@ -1110,7 +1156,13 @@ nsGonkCameraControl::PullParametersImpl()
DOM_CAMERA_LOGI("Pulling camera parameters\n");
RETURN_IF_NO_CAMERA_HW();
return mCameraHw->PullParameters(mParams);
nsresult rv = mCameraHw->PullParameters(mParams);
mParams.Get(CAMERA_PARAM_THUMBNAILSIZE, mLastThumbnailSize);
mParams.Get(CAMERA_PARAM_PICTURE_SIZE, mCurrentConfiguration.mPictureSize);
mParams.Get(CAMERA_PARAM_PREVIEWSIZE, mCurrentConfiguration.mPreviewSize);
mParams.Get(CAMERA_PARAM_VIDEOSIZE, mLastRecorderSize);
return rv;
}
nsresult
@@ -1229,6 +1281,7 @@ nsGonkCameraControl::StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescri
#endif
OnRecorderStateChange(CameraControlListener::kRecorderStarted);
mCapturePoster = aOptions->createPoster;
return NS_OK;
}
@@ -1273,6 +1326,9 @@ nsGonkCameraControl::StopRecordingImpl()
return NS_OK;
}
#endif
if (mCapturePoster.exchange(false)) {
OnPoster(nullptr, 0);
}
OnRecorderStateChange(CameraControlListener::kRecorderStopped);
{
@@ -1290,6 +1346,48 @@ nsGonkCameraControl::StopRecordingImpl()
return NS_DispatchToMainThread(new RecordingComplete(mVideoFile.forget()));
}
nsresult
nsGonkCameraControl::PauseRecordingImpl()
{
ReentrantMonitorAutoEnter mon(mRecorderMonitor);
#ifdef MOZ_WIDGET_GONK
if (!mRecorder) {
return NS_ERROR_NOT_AVAILABLE;
}
int err = mRecorder->pause();
switch (err) {
case OK:
break;
case INVALID_OPERATION:
return NS_ERROR_NOT_IMPLEMENTED;
default:
return NS_ERROR_FAILURE;
}
#endif
OnRecorderStateChange(CameraControlListener::kRecorderPaused);
return NS_OK;
}
nsresult
nsGonkCameraControl::ResumeRecordingImpl()
{
ReentrantMonitorAutoEnter mon(mRecorderMonitor);
#ifdef MOZ_WIDGET_GONK
if (!mRecorder) {
return NS_ERROR_NOT_AVAILABLE;
}
if (mRecorder->resume() != OK) {
return NS_ERROR_FAILURE;
}
#endif
OnRecorderStateChange(CameraControlListener::kRecorderResumed);
return NS_OK;
}
nsresult
nsGonkCameraControl::ResumeContinuousFocusImpl()
{
@@ -1307,30 +1405,118 @@ nsGonkCameraControl::ResumeContinuousFocusImpl()
return NS_OK;
}
class AutoFocusMovingTimerCallback : public nsITimerCallback
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
AutoFocusMovingTimerCallback(nsGonkCameraControl* aCameraControl)
: mCameraControl(aCameraControl)
{ }
NS_IMETHODIMP
Notify(nsITimer* aTimer)
{
mCameraControl->OnAutoFocusComplete(true, true);
return NS_OK;
}
protected:
virtual ~AutoFocusMovingTimerCallback()
{ }
RefPtr<nsGonkCameraControl> mCameraControl;
};
NS_IMPL_ISUPPORTS(AutoFocusMovingTimerCallback, nsITimerCallback);
void
nsGonkCameraControl::OnAutoFocusComplete(bool aSuccess)
nsGonkCameraControl::OnAutoFocusMoving(bool aIsMoving)
{
CameraControlImpl::OnAutoFocusMoving(aIsMoving);
if (!aIsMoving) {
/* Some drivers do not signal us with the status of the continuous auto focus
operation, only the moving signal which comes first. As a result we need to
arm a timer to detect the driver behaviour and if necessary generate the
signal ourselves to update the application state. */
int32_t expiredCount = 0;
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mAutoFocusCompleteTimer) {
mAutoFocusCompleteTimer->Cancel();
if (!mAutoFocusPending) {
RefPtr<nsITimerCallback> timerCb = new AutoFocusMovingTimerCallback(this);
nsresult rv = mAutoFocusCompleteTimer->InitWithCallback(timerCb,
kAutoFocusCompleteTimeoutMs,
nsITimer::TYPE_ONE_SHOT);
NS_WARN_IF(NS_FAILED(rv));
}
return;
}
if (!mAutoFocusPending) {
expiredCount = mAutoFocusCompleteExpired;
}
}
if (expiredCount == kAutoFocusCompleteTimeoutLimit) {
OnAutoFocusComplete(true, true);
}
}
}
void
nsGonkCameraControl::OnAutoFocusComplete(bool aSuccess, bool aExpired)
{
class AutoFocusComplete : public nsRunnable
{
public:
AutoFocusComplete(nsGonkCameraControl* aCameraControl, bool aSuccess)
AutoFocusComplete(nsGonkCameraControl* aCameraControl, bool aSuccess, bool aExpired)
: mCameraControl(aCameraControl)
, mSuccess(aSuccess)
, mExpired(aExpired)
{ }
NS_IMETHODIMP
Run() override
{
mCameraControl->OnAutoFocusComplete(mSuccess);
mCameraControl->OnAutoFocusComplete(mSuccess, mExpired);
return NS_OK;
}
protected:
RefPtr<nsGonkCameraControl> mCameraControl;
bool mSuccess;
bool mExpired;
};
if (NS_GetCurrentThread() == mCameraThread) {
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mAutoFocusPending) {
mAutoFocusPending = false;
} else if (mAutoFocusCompleteTimer) {
if (aExpired) {
NS_WARNING("Camera timed out waiting for OnAutoFocusComplete");
++mAutoFocusCompleteExpired;
} else {
mAutoFocusCompleteTimer->Cancel();
--mAutoFocusCompleteExpired;
}
if (mAutoFocusCompleteExpired == kAutoFocusCompleteTimeoutLimit ||
mAutoFocusCompleteExpired == -kAutoFocusCompleteTimeoutLimit)
{
mAutoFocusCompleteTimer = nullptr;
}
}
}
/**
* Auto focusing can change some of the camera's parameters, so
* we need to pull a new set before notifying any clients.
@@ -1344,7 +1530,7 @@ nsGonkCameraControl::OnAutoFocusComplete(bool aSuccess)
* Because the callback needs to call PullParametersImpl(),
* we need to dispatch this callback through the Camera Thread.
*/
mCameraThread->Dispatch(new AutoFocusComplete(this, aSuccess), NS_DISPATCH_NORMAL);
mCameraThread->Dispatch(new AutoFocusComplete(this, aSuccess, aExpired), NS_DISPATCH_NORMAL);
}
bool
@@ -1372,6 +1558,11 @@ nsGonkCameraControl::OnFacesDetected(camera_frame_metadata_t* aMetaData)
nsTArray<Face> faces;
uint32_t numFaces = aMetaData->number_of_faces;
if (numFaces == 0 && mPrevFacesDetected == 0) {
return;
}
mPrevFacesDetected = numFaces;
DOM_CAMERA_LOGI("Camera detected %d face(s)", numFaces);
faces.SetCapacity(numFaces);
@@ -1429,14 +1620,10 @@ nsGonkCameraControl::OnTakePictureComplete(uint8_t* aData, uint32_t aLength)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
uint8_t* data = new uint8_t[aLength];
memcpy(data, aData, aLength);
nsString s(NS_LITERAL_STRING("image/"));
s.Append(mFileFormat);
DOM_CAMERA_LOGI("Got picture, type '%s', %u bytes\n", NS_ConvertUTF16toUTF8(s).get(), aLength);
OnTakePictureComplete(data, aLength, s);
OnTakePictureComplete(aData, aLength, s);
if (mResumePreviewAfterTakingPicture) {
nsresult rv = StartPreview();
@@ -1911,11 +2098,13 @@ nsGonkCameraControl::SetupRecording(int aFd, int aRotation,
NS_ERROR_INVALID_ARG);
// adjust rotation by camera sensor offset
int r = aRotation;
r += mCameraHw->GetSensorOrientation();
r = RationalizeRotation(r);
DOM_CAMERA_LOGI("setting video rotation to %d degrees (mapped from %d)\n", r, aRotation);
snprintf(buffer, SIZE, "video-param-rotation-angle-degrees=%d", r);
mVideoRotation = aRotation;
mVideoRotation += mCameraHw->GetSensorOrientation();
mVideoRotation = RationalizeRotation(mVideoRotation);
DOM_CAMERA_LOGI("setting video rotation to %d degrees (mapped from %d)\n",
mVideoRotation, aRotation);
snprintf(buffer, SIZE, "video-param-rotation-angle-degrees=%d",
mVideoRotation);
CHECK_SETARG_RETURN(mRecorder->setParameters(String8(buffer)),
NS_ERROR_INVALID_ARG);
@@ -1983,6 +2172,7 @@ nsGonkCameraControl::LoadRecorderProfiles()
nsTArray<RecorderProfile>::size_type bestIndexMatch = 0;
int bestAreaMatch = 0;
uint32_t bestPriorityMatch = UINT32_MAX;
// Limit profiles to those video sizes supported by the camera hardware...
for (nsTArray<RecorderProfile>::size_type i = 0; i < profiles.Length(); ++i) {
@@ -1997,17 +2187,22 @@ nsGonkCameraControl::LoadRecorderProfiles()
if (static_cast<uint32_t>(width) == sizes[n].width &&
static_cast<uint32_t>(height) == sizes[n].height) {
mRecorderProfiles.Put(profiles[i]->GetName(), profiles[i]);
// "Best" or default profile is the one with the lowest priority
// value and largest area.
int area = width * height;
if (area > bestAreaMatch) {
uint32_t priority = profiles[i]->GetPriority();
if (bestPriorityMatch > priority ||
(bestPriorityMatch == priority && area > bestAreaMatch)) {
bestIndexMatch = i;
bestAreaMatch = area;
bestPriorityMatch = priority;
}
break;
}
}
}
// Default profile is the one with the largest area.
if (bestAreaMatch > 0) {
nsAutoString name;
name.AssignASCII("default");
@@ -2058,6 +2253,137 @@ nsGonkCameraControl::OnRateLimitPreview(bool aLimit)
CameraControlImpl::OnRateLimitPreview(aLimit);
}
void
nsGonkCameraControl::CreatePoster(Image* aImage, uint32_t aWidth, uint32_t aHeight, int32_t aRotation)
{
class PosterRunnable : public nsRunnable {
public:
PosterRunnable(nsGonkCameraControl* aTarget, Image* aImage,
uint32_t aWidth, uint32_t aHeight, int32_t aRotation)
: mTarget(aTarget)
, mImage(aImage)
, mWidth(aWidth)
, mHeight(aHeight)
, mRotation(aRotation)
, mDst(nullptr)
, mDstLength(0)
{ }
virtual ~PosterRunnable()
{
mTarget->OnPoster(mDst, mDstLength);
}
NS_IMETHODIMP Run() override
{
#ifdef MOZ_WIDGET_GONK
// NV21 (yuv420sp) is 12 bits / pixel
size_t srcLength = (mWidth * mHeight * 3 + 1) / 2;
// ARGB is 32 bits / pixel
size_t tmpLength = mWidth * mHeight * sizeof(uint32_t);
nsAutoArrayPtr<uint8_t> tmp;
tmp = new uint8_t[tmpLength];
GrallocImage* nativeImage = static_cast<GrallocImage*>(mImage.get());
android::sp<GraphicBuffer> graphicBuffer = nativeImage->GetGraphicBuffer();
void* graphicSrc = nullptr;
graphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_MASK, &graphicSrc);
uint32_t stride = mWidth * 4;
int err = libyuv::ConvertToARGB(static_cast<uint8_t*>(graphicSrc),
srcLength, tmp, stride, 0, 0,
mWidth, mHeight, mWidth, mHeight,
libyuv::kRotate0, libyuv::FOURCC_NV21);
graphicBuffer->unlock();
graphicSrc = nullptr;
graphicBuffer.clear();
nativeImage = nullptr;
mImage = nullptr;
if (NS_WARN_IF(err < 0)) {
DOM_CAMERA_LOGE("CreatePoster: to ARGB failed (%d)\n", err);
return NS_OK;
}
nsCOMPtr<imgIEncoder> encoder =
do_CreateInstance("@mozilla.org/image/encoder;2?type=image/jpeg");
if (NS_WARN_IF(!encoder)) {
DOM_CAMERA_LOGE("CreatePoster: no JPEG encoder\n");
return NS_OK;
}
nsString opt;
nsresult rv = encoder->InitFromData(tmp, tmpLength, mWidth,
mHeight, stride,
imgIEncoder::INPUT_FORMAT_HOSTARGB,
opt);
if (NS_WARN_IF(NS_FAILED(rv))) {
DOM_CAMERA_LOGE("CreatePoster: encoder init failed (0x%x)\n",
rv);
return NS_OK;
}
nsCOMPtr<nsIInputStream> stream = do_QueryInterface(encoder);
if (NS_WARN_IF(!stream)) {
DOM_CAMERA_LOGE("CreatePoster: to input stream failed\n");
return NS_OK;
}
uint64_t length = 0;
rv = stream->Available(&length);
if (NS_WARN_IF(NS_FAILED(rv))) {
DOM_CAMERA_LOGE("CreatePoster: get length failed (0x%x)\n",
rv);
return NS_OK;
}
rv = NS_ReadInputStreamToBuffer(stream, &mDst, length);
if (NS_WARN_IF(NS_FAILED(rv))) {
DOM_CAMERA_LOGE("CreatePoster: read failed (0x%x)\n", rv);
mDst = nullptr;
return NS_OK;
}
mDstLength = length;
#endif
return NS_OK;
}
private:
RefPtr<nsGonkCameraControl> mTarget;
RefPtr<Image> mImage;
int32_t mWidth;
int32_t mHeight;
int32_t mRotation;
void* mDst;
size_t mDstLength;
};
nsCOMPtr<nsIRunnable> event = new PosterRunnable(this, aImage,
aWidth,
aHeight,
aRotation);
nsCOMPtr<nsIEventTarget> target
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
MOZ_ASSERT(target);
target->Dispatch(event, NS_DISPATCH_NORMAL);
}
void
nsGonkCameraControl::OnPoster(void* aData, uint32_t aLength)
{
RefPtr<BlobImpl> blobImpl;
if (aData) {
blobImpl = new BlobImplMemory(aData, aLength, NS_LITERAL_STRING("image/jpeg"));
}
CameraControlImpl::OnPoster(blobImpl);
}
void
nsGonkCameraControl::OnNewPreviewFrame(layers::TextureClient* aBuffer)
{
@@ -2072,6 +2398,14 @@ nsGonkCameraControl::OnNewPreviewFrame(layers::TextureClient* aBuffer)
mCurrentConfiguration.mPreviewSize.height);
videoImage->SetData(data);
if (mCapturePoster.exchange(false)) {
CreatePoster(frame,
mCurrentConfiguration.mPreviewSize.width,
mCurrentConfiguration.mPreviewSize.height,
mVideoRotation);
return;
}
OnNewPreviewFrame(frame, mCurrentConfiguration.mPreviewSize.width,
mCurrentConfiguration.mPreviewSize.height);
#endif
@@ -2107,7 +2441,7 @@ OnTakePictureError(nsGonkCameraControl* gc)
void
OnAutoFocusComplete(nsGonkCameraControl* gc, bool aSuccess)
{
gc->OnAutoFocusComplete(aSuccess);
gc->OnAutoFocusComplete(aSuccess, false);
}
void