mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Bug 909542 - refactor CameraControl API, r=dhylands,jst,jesup,onecyrenus
This commit is contained in:
parent
2b49e82edb
commit
557d8c2d5c
@ -167,7 +167,6 @@
|
||||
#ifdef MOZ_B2G_BT
|
||||
@BINPATH@/components/dom_bluetooth.xpt
|
||||
#endif
|
||||
@BINPATH@/components/dom_camera.xpt
|
||||
@BINPATH@/components/dom_canvas.xpt
|
||||
@BINPATH@/components/dom_contacts.xpt
|
||||
@BINPATH@/components/dom_alarm.xpt
|
||||
|
@ -197,7 +197,6 @@
|
||||
#ifdef MOZ_B2G_BT
|
||||
@BINPATH@/components/dom_bluetooth.xpt
|
||||
#endif
|
||||
@BINPATH@/components/dom_camera.xpt
|
||||
@BINPATH@/components/dom_canvas.xpt
|
||||
@BINPATH@/components/dom_alarm.xpt
|
||||
@BINPATH@/components/dom_core.xpt
|
||||
|
@ -42,7 +42,7 @@ GetUserMediaLog()
|
||||
#define LOG(args) PR_LOG(GetUserMediaLog(), PR_LOG_DEBUG, args)
|
||||
|
||||
namespace mozilla {
|
||||
#ifndef MOZ_B2G_CAMERA
|
||||
|
||||
MediaEngineWebRTC::MediaEngineWebRTC(MediaEnginePrefs &aPrefs)
|
||||
: mMutex("mozilla::MediaEngineWebRTC")
|
||||
, mVideoEngine(nullptr)
|
||||
@ -51,27 +51,26 @@ MediaEngineWebRTC::MediaEngineWebRTC(MediaEnginePrefs &aPrefs)
|
||||
, mAudioEngineInit(false)
|
||||
, mHasTabVideoSource(false)
|
||||
{
|
||||
#ifndef MOZ_B2G_CAMERA
|
||||
nsCOMPtr<nsIComponentRegistrar> compMgr;
|
||||
NS_GetComponentRegistrar(getter_AddRefs(compMgr));
|
||||
if (compMgr) {
|
||||
compMgr->IsContractIDRegistered(NS_TABSOURCESERVICE_CONTRACTID, &mHasTabVideoSource);
|
||||
}
|
||||
#else
|
||||
AsyncLatencyLogger::Get()->AddRef();
|
||||
#endif
|
||||
if (aPrefs.mLoadAdapt) {
|
||||
mLoadMonitor = new LoadMonitor();
|
||||
mLoadMonitor->Init(mLoadMonitor);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >* aVSources)
|
||||
{
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mCameraManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* We still enumerate every time, in case a new device was plugged in since
|
||||
@ -83,14 +82,14 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSourc
|
||||
*/
|
||||
int num = 0;
|
||||
nsresult result;
|
||||
result = mCameraManager->GetNumberOfCameras(num);
|
||||
result = ICameraControl::GetNumberOfCameras(num);
|
||||
if (num <= 0 || result != NS_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num; i++) {
|
||||
nsCString cameraName;
|
||||
result = mCameraManager->GetCameraName(i, cameraName);
|
||||
result = ICameraControl::GetCameraName(i, cameraName);
|
||||
if (result != NS_OK) {
|
||||
continue;
|
||||
}
|
||||
@ -101,7 +100,7 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSourc
|
||||
// We've already seen this device, just append.
|
||||
aVSources->AppendElement(vSource.get());
|
||||
} else {
|
||||
vSource = new MediaEngineWebRTCVideoSource(mCameraManager, i, mWindowId);
|
||||
vSource = new MediaEngineWebRTCVideoSource(i);
|
||||
mVideoSources.Put(uuid, vSource); // Hashtable takes ownership.
|
||||
aVSources->AppendElement(vSource);
|
||||
}
|
||||
|
@ -46,9 +46,8 @@
|
||||
#include "webrtc/video_engine/include/vie_render.h"
|
||||
#include "webrtc/video_engine/include/vie_capture.h"
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
#include "CameraPreviewMediaStream.h"
|
||||
#include "DOMCameraManager.h"
|
||||
#include "GonkCameraControl.h"
|
||||
#include "CameraControlListener.h"
|
||||
#include "ICameraControl.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "prprf.h"
|
||||
@ -73,7 +72,7 @@ class GetCameraNameRunnable;
|
||||
* mSources, mImageContainer, mSources, mState, mImage, mLastCapture
|
||||
*
|
||||
* MainThread:
|
||||
* mDOMCameraControl, mCaptureIndex, mCameraThread, mWindowId, mCameraManager,
|
||||
* mCaptureIndex, mWindowId,
|
||||
* mNativeCameraControl, mPreviewStream, mState, mLastCapture, mWidth, mHeight
|
||||
*
|
||||
* Where mWidth, mHeight, mImage are protected by mMonitor
|
||||
@ -83,24 +82,15 @@ class GetCameraNameRunnable;
|
||||
class MediaEngineWebRTCVideoSource : public MediaEngineVideoSource
|
||||
, public nsRunnable
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
, public nsICameraGetCameraCallback
|
||||
, public nsICameraPreviewStreamCallback
|
||||
, public nsICameraTakePictureCallback
|
||||
, public nsICameraReleaseCallback
|
||||
, public nsICameraErrorCallback
|
||||
, public CameraPreviewFrameCallback
|
||||
, public CameraControlListener
|
||||
#else
|
||||
, public webrtc::ExternalRenderer
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
MediaEngineWebRTCVideoSource(nsDOMCameraManager* aCameraManager,
|
||||
int aIndex, uint64_t aWindowId)
|
||||
: mCameraManager(aCameraManager)
|
||||
, mNativeCameraControl(nullptr)
|
||||
, mPreviewStream(nullptr)
|
||||
, mWindowId(aWindowId)
|
||||
MediaEngineWebRTCVideoSource(int aIndex)
|
||||
: mCameraControl(nullptr)
|
||||
, mCallbackMonitor("WebRTCCamera.CallbackMonitor")
|
||||
, mCaptureIndex(aIndex)
|
||||
, mMonitor("WebRTCCamera.Monitor")
|
||||
@ -111,7 +101,6 @@ public:
|
||||
, mSnapshotPath(nullptr)
|
||||
{
|
||||
mState = kReleased;
|
||||
NS_NewNamedThread("CameraThread", getter_AddRefs(mCameraThread));
|
||||
Init();
|
||||
}
|
||||
#else
|
||||
@ -167,20 +156,17 @@ public:
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
NS_DECL_NSICAMERAGETCAMERACALLBACK
|
||||
NS_DECL_NSICAMERAPREVIEWSTREAMCALLBACK
|
||||
NS_DECL_NSICAMERATAKEPICTURECALLBACK
|
||||
NS_DECL_NSICAMERARELEASECALLBACK
|
||||
NS_DECL_NSICAMERAERRORCALLBACK
|
||||
void OnHardwareStateChange(HardwareState aState);
|
||||
void OnConfigurationChange(const CameraListenerConfiguration& aConfiguration);
|
||||
bool OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight);
|
||||
void OnError(CameraErrorContext aContext, const nsACString& aError);
|
||||
void OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType);
|
||||
|
||||
void AllocImpl();
|
||||
void DeallocImpl();
|
||||
void StartImpl(webrtc::CaptureCapability aCapability);
|
||||
void StopImpl();
|
||||
void SnapshotImpl();
|
||||
|
||||
virtual void OnNewFrame(const gfxIntSize& aIntrinsicSize, layers::Image* aImage);
|
||||
|
||||
#endif
|
||||
|
||||
// This runnable is for creating a temporary file on the main thread.
|
||||
@ -212,20 +198,8 @@ private:
|
||||
|
||||
// Engine variables.
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
// MediaEngine hold this DOM object, and the MediaEngine is hold by Navigator
|
||||
// Their life time is always much longer than this object. Use a raw-pointer
|
||||
// here should be safe.
|
||||
// We need raw pointer here since such DOM-object should not addref/release on
|
||||
// any thread other than main thread, but we must use this object for now. To
|
||||
// avoid any bad thing do to addref/release DOM-object on other thread, we use
|
||||
// raw-pointer for now.
|
||||
nsDOMCameraManager* mCameraManager;
|
||||
nsRefPtr<nsDOMCameraControl> mDOMCameraControl;
|
||||
nsRefPtr<nsGonkCameraControl> mNativeCameraControl;
|
||||
nsRefPtr<DOMCameraPreview> mPreviewStream;
|
||||
uint64_t mWindowId;
|
||||
nsRefPtr<ICameraControl> mCameraControl;
|
||||
mozilla::ReentrantMonitor mCallbackMonitor; // Monitor for camera callback handling
|
||||
nsRefPtr<nsIThread> mCameraThread;
|
||||
nsRefPtr<nsIDOMFile> mLastCapture;
|
||||
#else
|
||||
webrtc::VideoEngine* mVideoEngine; // Weak reference, don't free.
|
||||
@ -351,24 +325,7 @@ private:
|
||||
class MediaEngineWebRTC : public MediaEngine
|
||||
{
|
||||
public:
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
MediaEngineWebRTC(nsDOMCameraManager* aCameraManager, uint64_t aWindowId)
|
||||
: mMutex("mozilla::MediaEngineWebRTC")
|
||||
, mVideoEngine(nullptr)
|
||||
, mVoiceEngine(nullptr)
|
||||
, mVideoEngineInit(false)
|
||||
, mAudioEngineInit(false)
|
||||
, mCameraManager(aCameraManager)
|
||||
, mWindowId(aWindowId)
|
||||
, mHasTabVideoSource(false)
|
||||
{
|
||||
AsyncLatencyLogger::Get(true)->AddRef();
|
||||
mLoadMonitor = new LoadMonitor();
|
||||
mLoadMonitor->Init(mLoadMonitor);
|
||||
}
|
||||
#else
|
||||
MediaEngineWebRTC(MediaEnginePrefs &aPrefs);
|
||||
#endif
|
||||
~MediaEngineWebRTC() {
|
||||
Shutdown();
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
@ -400,19 +357,7 @@ private:
|
||||
nsRefPtrHashtable<nsStringHashKey, MediaEngineWebRTCVideoSource > mVideoSources;
|
||||
nsRefPtrHashtable<nsStringHashKey, MediaEngineWebRTCAudioSource > mAudioSources;
|
||||
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
// MediaEngine hold this DOM object, and the MediaEngine is hold by Navigator
|
||||
// Their life time is always much longer than this object. Use a raw-pointer
|
||||
// here should be safe.
|
||||
// We need raw pointer here since such DOM-object should not addref/release on
|
||||
// any thread other than main thread, but we must use this object for now. To
|
||||
// avoid any bad thing do to addref/release DOM-object on other thread, we use
|
||||
// raw-pointer for now.
|
||||
nsDOMCameraManager* mCameraManager;
|
||||
uint64_t mWindowId;
|
||||
#endif
|
||||
|
||||
nsRefPtr<LoadMonitor> mLoadMonitor;
|
||||
nsRefPtr<LoadMonitor> mLoadMonitor;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -312,7 +312,9 @@ nsresult
|
||||
MediaEngineWebRTCVideoSource::Start(SourceMediaStream* aStream, TrackID aID)
|
||||
{
|
||||
LOG((__FUNCTION__));
|
||||
#ifndef MOZ_B2G_CAMERA
|
||||
int error = 0;
|
||||
#endif
|
||||
if (!mInitDone || !aStream) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -413,7 +415,7 @@ MediaEngineWebRTCVideoSource::Init()
|
||||
{
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
nsAutoCString deviceName;
|
||||
mCameraManager->GetCameraName(mCaptureIndex, deviceName);
|
||||
ICameraControl::GetCameraName(mCaptureIndex, deviceName);
|
||||
CopyUTF8toUTF16(deviceName, mDeviceName);
|
||||
CopyUTF8toUTF16(deviceName, mUniqueId);
|
||||
#else
|
||||
@ -492,125 +494,95 @@ void
|
||||
MediaEngineWebRTCVideoSource::AllocImpl() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mDOMCameraControl = new nsDOMCameraControl(mCaptureIndex,
|
||||
mCameraThread,
|
||||
this,
|
||||
this,
|
||||
nsGlobalWindow::GetInnerWindowWithId(mWindowId));
|
||||
mCameraManager->Register(mDOMCameraControl);
|
||||
mCameraControl = ICameraControl::Create(mCaptureIndex, nullptr);
|
||||
mCameraControl->AddListener(this);
|
||||
}
|
||||
|
||||
void
|
||||
MediaEngineWebRTCVideoSource::DeallocImpl() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mNativeCameraControl->ReleaseHardware(this, this);
|
||||
mNativeCameraControl = nullptr;
|
||||
mCameraControl->ReleaseHardware();
|
||||
mCameraControl = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
MediaEngineWebRTCVideoSource::StartImpl(webrtc::CaptureCapability aCapability) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
idl::CameraSize size;
|
||||
size.width = aCapability.width;
|
||||
size.height = aCapability.height;
|
||||
mNativeCameraControl->GetPreviewStream(size, this, this);
|
||||
ICameraControl::Configuration config;
|
||||
config.mMode = ICameraControl::kPictureMode;
|
||||
config.mPreviewSize.width = aCapability.width;
|
||||
config.mPreviewSize.height = aCapability.height;
|
||||
mCameraControl->SetConfiguration(config);
|
||||
mCameraControl->Set(CAMERA_PARAM_PICTURESIZE, config.mPreviewSize);
|
||||
}
|
||||
|
||||
void
|
||||
MediaEngineWebRTCVideoSource::StopImpl() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mNativeCameraControl->StopPreview();
|
||||
mPreviewStream = nullptr;
|
||||
mCameraControl->StopPreview();
|
||||
}
|
||||
|
||||
void
|
||||
MediaEngineWebRTCVideoSource::SnapshotImpl() {
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
idl::CameraSize size;
|
||||
size.width = mCapability.width;
|
||||
size.height = mCapability.height;
|
||||
|
||||
idl::CameraPosition cameraPosition;
|
||||
cameraPosition.latitude = NAN;
|
||||
cameraPosition.longitude = NAN;
|
||||
cameraPosition.altitude = NAN;
|
||||
cameraPosition.timestamp = NAN;
|
||||
|
||||
mNativeCameraControl->TakePicture(size, 0, NS_LITERAL_STRING("jpeg"), cameraPosition, PR_Now() / 1000000, this, this);
|
||||
mCameraControl->TakePicture();
|
||||
}
|
||||
|
||||
// nsICameraGetCameraCallback
|
||||
nsresult
|
||||
MediaEngineWebRTCVideoSource::HandleEvent(nsISupports* /* unused */) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
void
|
||||
MediaEngineWebRTCVideoSource::OnHardwareStateChange(HardwareState aState)
|
||||
{
|
||||
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
|
||||
mNativeCameraControl = static_cast<nsGonkCameraControl*>(mDOMCameraControl->GetNativeCameraControl().get());
|
||||
mState = kAllocated;
|
||||
if (aState == CameraControlListener::kHardwareOpen) {
|
||||
mState = kAllocated;
|
||||
} else {
|
||||
mState = kReleased;
|
||||
mCameraControl->RemoveListener(this);
|
||||
}
|
||||
mCallbackMonitor.Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsICameraPreviewStreamCallback
|
||||
nsresult
|
||||
MediaEngineWebRTCVideoSource::HandleEvent(nsIDOMMediaStream* stream) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
void
|
||||
MediaEngineWebRTCVideoSource::OnConfigurationChange(const CameraListenerConfiguration& aConfiguration)
|
||||
{
|
||||
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
|
||||
mPreviewStream = static_cast<DOMCameraPreview*>(stream);
|
||||
mPreviewStream->Start();
|
||||
CameraPreviewMediaStream* cameraStream = static_cast<CameraPreviewMediaStream*>(mPreviewStream->GetStream());
|
||||
cameraStream->SetFrameCallback(this);
|
||||
mState = kStarted;
|
||||
mCallbackMonitor.Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsICameraTakePictureCallback
|
||||
nsresult
|
||||
MediaEngineWebRTCVideoSource::HandleEvent(nsIDOMBlob* picture) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
|
||||
mLastCapture = static_cast<nsIDOMFile*>(picture);
|
||||
mCallbackMonitor.Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsICameraReleaseCallback
|
||||
nsresult
|
||||
MediaEngineWebRTCVideoSource::HandleEvent() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
|
||||
mState = kReleased;
|
||||
mCallbackMonitor.Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsICameraErrorCallback
|
||||
nsresult
|
||||
MediaEngineWebRTCVideoSource::HandleEvent(const nsAString& error) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
|
||||
mCallbackMonitor.Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//Except this one. This callback should called on camera preview thread.
|
||||
void
|
||||
MediaEngineWebRTCVideoSource::OnNewFrame(const gfxIntSize& aIntrinsicSize, layers::Image* aImage) {
|
||||
MediaEngineWebRTCVideoSource::OnError(CameraErrorContext aContext, const nsACString& aError)
|
||||
{
|
||||
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
|
||||
mCallbackMonitor.Notify();
|
||||
}
|
||||
|
||||
void
|
||||
MediaEngineWebRTCVideoSource::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
|
||||
{
|
||||
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
|
||||
mLastCapture =
|
||||
static_cast<nsIDOMFile*>(new nsDOMMemoryFile(static_cast<void*>(aData),
|
||||
static_cast<uint64_t>(aLength),
|
||||
aMimeType));
|
||||
mCallbackMonitor.Notify();
|
||||
}
|
||||
|
||||
bool
|
||||
MediaEngineWebRTCVideoSource::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight) {
|
||||
MonitorAutoLock enter(mMonitor);
|
||||
if (mState == kStopped) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
mImage = aImage;
|
||||
if (mWidth != aIntrinsicSize.width || mHeight != aIntrinsicSize.height) {
|
||||
mWidth = aIntrinsicSize.width;
|
||||
mHeight = aIntrinsicSize.height;
|
||||
if (mWidth != static_cast<int>(aWidth) || mHeight != static_cast<int>(aHeight)) {
|
||||
mWidth = aWidth;
|
||||
mHeight = aHeight;
|
||||
LOG(("Video FrameSizeChange: %ux%u", mWidth, mHeight));
|
||||
}
|
||||
return true; // return true because we're accepting the frame
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -160,7 +160,6 @@
|
||||
#include "FMRadio.h"
|
||||
#endif
|
||||
|
||||
#include "nsIDOMCameraManager.h"
|
||||
#include "nsIDOMGlobalObjectConstructor.h"
|
||||
#include "nsIDOMLockedFile.h"
|
||||
#include "nsDebug.h"
|
||||
@ -470,9 +469,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
#endif
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(CameraCapabilities, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(LockedFile, nsEventTargetSH,
|
||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(CSSFontFeatureValuesRule, nsDOMGenericSH,
|
||||
@ -1176,10 +1172,6 @@ nsDOMClassInfo::Init()
|
||||
|
||||
#endif
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(CameraCapabilities, nsICameraCapabilities)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsICameraCapabilities)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(LockedFile, nsIDOMLockedFile)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMLockedFile)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
@ -103,8 +103,6 @@ DOMCI_CLASS(CSSPageRule)
|
||||
DOMCI_CLASS(MozIccManager)
|
||||
#endif
|
||||
|
||||
DOMCI_CLASS(CameraCapabilities)
|
||||
|
||||
DOMCI_CLASS(LockedFile)
|
||||
|
||||
DOMCI_CLASS(CSSFontFeatureValuesRule)
|
||||
|
@ -180,6 +180,11 @@ DOMInterfaces = {
|
||||
'headerFile': 'BluetoothManager.h'
|
||||
},
|
||||
|
||||
'CameraCapabilities': {
|
||||
'nativeType': 'mozilla::dom::CameraCapabilities',
|
||||
'headerFile': 'DOMCameraCapabilities.h'
|
||||
},
|
||||
|
||||
'CameraControl': {
|
||||
'nativeType': 'mozilla::nsDOMCameraControl',
|
||||
'headerFile': 'DOMCameraControl.h',
|
||||
@ -1967,15 +1972,3 @@ addExternalIface('XPathExpression')
|
||||
addExternalIface('XPathNSResolver')
|
||||
addExternalIface('XULCommandDispatcher')
|
||||
addExternalIface('DataTransfer', notflattened=True)
|
||||
addExternalIface('GetCameraCallback', nativeType='nsICameraGetCameraCallback', headerFile='nsIDOMCameraManager.h')
|
||||
addExternalIface('CameraErrorCallback', nativeType='nsICameraErrorCallback', headerFile='nsIDOMCameraManager.h')
|
||||
addExternalIface('CameraCapabilities', nativeType='nsICameraCapabilities', headerFile='nsIDOMCameraManager.h')
|
||||
addExternalIface('CameraAutoFocusCallback', nativeType='nsICameraAutoFocusCallback', headerFile='nsIDOMCameraManager.h')
|
||||
addExternalIface('CameraShutterCallback', nativeType='nsICameraShutterCallback', headerFile='nsIDOMCameraManager.h')
|
||||
addExternalIface('CameraClosedCallback', nativeType='nsICameraClosedCallback', headerFile='nsIDOMCameraManager.h')
|
||||
addExternalIface('CameraTakePictureCallback', nativeType='nsICameraTakePictureCallback', headerFile='nsIDOMCameraManager.h')
|
||||
addExternalIface('CameraReleaseCallback', nativeType='nsICameraReleaseCallback', headerFile='nsIDOMCameraManager.h')
|
||||
addExternalIface('CameraStartRecordingCallback', nativeType='nsICameraStartRecordingCallback', headerFile='nsIDOMCameraManager.h')
|
||||
addExternalIface('CameraPreviewStateChange', nativeType='nsICameraPreviewStateChange', headerFile='nsIDOMCameraManager.h')
|
||||
addExternalIface('CameraPreviewStreamCallback', nativeType='nsICameraPreviewStreamCallback', headerFile='nsIDOMCameraManager.h')
|
||||
addExternalIface('CameraRecorderStateChange', nativeType='nsICameraRecorderStateChange', headerFile='nsIDOMCameraManager.h')
|
||||
|
49
dom/camera/AutoRwLock.h
Normal file
49
dom/camera/AutoRwLock.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef RWLOCK_AUTO_ENTER_H
|
||||
#define RWLOCK_AUTO_ENTER_H
|
||||
|
||||
#include "prrwlock.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
class RwLockAutoEnterRead
|
||||
{
|
||||
public:
|
||||
RwLockAutoEnterRead(PRRWLock* aRwLock)
|
||||
: mRwLock(aRwLock)
|
||||
{
|
||||
MOZ_ASSERT(mRwLock);
|
||||
PR_RWLock_Rlock(mRwLock);
|
||||
}
|
||||
|
||||
~RwLockAutoEnterRead()
|
||||
{
|
||||
PR_RWLock_Unlock(mRwLock);
|
||||
}
|
||||
|
||||
protected:
|
||||
PRRWLock* mRwLock;
|
||||
};
|
||||
|
||||
class RwLockAutoEnterWrite
|
||||
{
|
||||
public:
|
||||
RwLockAutoEnterWrite(PRRWLock* aRwLock)
|
||||
: mRwLock(aRwLock)
|
||||
{
|
||||
MOZ_ASSERT(mRwLock);
|
||||
PR_RWLock_Wlock(mRwLock);
|
||||
}
|
||||
|
||||
~RwLockAutoEnterWrite()
|
||||
{
|
||||
PR_RWLock_Unlock(mRwLock);
|
||||
}
|
||||
|
||||
protected:
|
||||
PRRWLock* mRwLock;
|
||||
};
|
||||
|
||||
#endif // RWLOCK_AUTO_ENTER_H
|
@ -19,7 +19,6 @@
|
||||
#define NAN std::numeric_limits<double>::quiet_NaN()
|
||||
#endif
|
||||
|
||||
#include "nsIDOMCameraManager.h"
|
||||
#include "prlog.h"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
@ -62,44 +61,6 @@ enum {
|
||||
#define DOM_CAMERA_LOGW( ... ) DOM_CAMERA_LOG( DOM_CAMERA_LOG_WARNING, __VA_ARGS__ )
|
||||
#define DOM_CAMERA_LOGE( ... ) DOM_CAMERA_LOG( DOM_CAMERA_LOG_ERROR, __VA_ARGS__ )
|
||||
|
||||
enum {
|
||||
CAMERA_PARAM_EFFECT,
|
||||
CAMERA_PARAM_WHITEBALANCE,
|
||||
CAMERA_PARAM_SCENEMODE,
|
||||
CAMERA_PARAM_FLASHMODE,
|
||||
CAMERA_PARAM_FOCUSMODE,
|
||||
CAMERA_PARAM_ZOOM,
|
||||
CAMERA_PARAM_METERINGAREAS,
|
||||
CAMERA_PARAM_FOCUSAREAS,
|
||||
CAMERA_PARAM_FOCALLENGTH,
|
||||
CAMERA_PARAM_FOCUSDISTANCENEAR,
|
||||
CAMERA_PARAM_FOCUSDISTANCEOPTIMUM,
|
||||
CAMERA_PARAM_FOCUSDISTANCEFAR,
|
||||
CAMERA_PARAM_EXPOSURECOMPENSATION,
|
||||
CAMERA_PARAM_PICTURESIZE,
|
||||
CAMERA_PARAM_THUMBNAILSIZE,
|
||||
CAMERA_PARAM_THUMBNAILQUALITY,
|
||||
CAMERA_PARAM_SENSORANGLE,
|
||||
|
||||
CAMERA_PARAM_SUPPORTED_PREVIEWSIZES,
|
||||
CAMERA_PARAM_SUPPORTED_VIDEOSIZES,
|
||||
CAMERA_PARAM_SUPPORTED_PICTURESIZES,
|
||||
CAMERA_PARAM_SUPPORTED_PICTUREFORMATS,
|
||||
CAMERA_PARAM_SUPPORTED_WHITEBALANCES,
|
||||
CAMERA_PARAM_SUPPORTED_SCENEMODES,
|
||||
CAMERA_PARAM_SUPPORTED_EFFECTS,
|
||||
CAMERA_PARAM_SUPPORTED_FLASHMODES,
|
||||
CAMERA_PARAM_SUPPORTED_FOCUSMODES,
|
||||
CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS,
|
||||
CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS,
|
||||
CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION,
|
||||
CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION,
|
||||
CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP,
|
||||
CAMERA_PARAM_SUPPORTED_ZOOM,
|
||||
CAMERA_PARAM_SUPPORTED_ZOOMRATIOS,
|
||||
CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES
|
||||
};
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
|
||||
static inline void nsLogAddRefCamera(const char *file, uint32_t line, void* p, uint32_t count, const char *clazz, uint32_t size)
|
||||
|
@ -2,278 +2,51 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "CameraControlImpl.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "DOMCameraPreview.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsIWeakReferenceUtils.h"
|
||||
#include "CameraRecorderProfiles.h"
|
||||
#include "CameraControlImpl.h"
|
||||
#include "CameraCommon.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "DeviceStorageFileDescriptor.h"
|
||||
#include "CameraControlListener.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::idl;
|
||||
|
||||
CameraControlImpl::CameraControlImpl(uint32_t aCameraId, nsIThread* aCameraThread, uint64_t aWindowId)
|
||||
nsWeakPtr CameraControlImpl::sCameraThread;
|
||||
|
||||
CameraControlImpl::CameraControlImpl(uint32_t aCameraId)
|
||||
: mCameraId(aCameraId)
|
||||
, mCameraThread(aCameraThread)
|
||||
, mWindowId(aWindowId)
|
||||
, mFileFormat()
|
||||
, mMaxMeteringAreas(0)
|
||||
, mMaxFocusAreas(0)
|
||||
, mPreviewState(PREVIEW_STOPPED)
|
||||
, mDOMPreview(nullptr)
|
||||
, mAutoFocusOnSuccessCb(nullptr)
|
||||
, mAutoFocusOnErrorCb(nullptr)
|
||||
, mTakePictureOnSuccessCb(nullptr)
|
||||
, mTakePictureOnErrorCb(nullptr)
|
||||
, mOnShutterCb(nullptr)
|
||||
, mOnClosedCb(nullptr)
|
||||
, mOnRecorderStateChangeCb(nullptr)
|
||||
, mOnPreviewStateChangeCb(nullptr)
|
||||
, mPreviewState(CameraControlListener::kPreviewStopped)
|
||||
, mHardwareState(CameraControlListener::kHardwareClosed)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
|
||||
// reuse the same camera thread to conserve resources
|
||||
nsCOMPtr<nsIThread> ct = do_QueryReferent(sCameraThread);
|
||||
if (ct) {
|
||||
mCameraThread = ct.forget();
|
||||
} else {
|
||||
nsresult rv = NS_NewNamedThread("CameraThread", getter_AddRefs(mCameraThread));
|
||||
unused << rv; // swallow rv to suppress a compiler warning when the macro
|
||||
// is #defined to nothing (i.e. in non-DEBUG builds).
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
// keep a weak reference to the new thread
|
||||
sCameraThread = do_GetWeakReference(mCameraThread);
|
||||
}
|
||||
|
||||
mListenerLock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "CameraControlImpl.Listeners.Lock");
|
||||
}
|
||||
|
||||
CameraControlImpl::~CameraControlImpl()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
// Helpers for string properties.
|
||||
nsresult
|
||||
CameraControlImpl::Set(uint32_t aKey, const nsAString& aValue)
|
||||
{
|
||||
SetParameter(aKey, NS_ConvertUTF16toUTF8(aValue).get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Get(uint32_t aKey, nsAString& aValue)
|
||||
{
|
||||
const char* value = GetParameterConstChar(aKey);
|
||||
if (!value) {
|
||||
return NS_ERROR_FAILURE;
|
||||
if (mListenerLock) {
|
||||
PR_DestroyRWLock(mListenerLock);
|
||||
mListenerLock = nullptr;
|
||||
}
|
||||
|
||||
aValue.AssignASCII(value);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Helpers for doubles.
|
||||
nsresult
|
||||
CameraControlImpl::Set(uint32_t aKey, double aValue)
|
||||
{
|
||||
SetParameter(aKey, aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Get(uint32_t aKey, double* aValue)
|
||||
{
|
||||
MOZ_ASSERT(aValue);
|
||||
*aValue = GetParameterDouble(aKey);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Helper for weighted regions.
|
||||
nsresult
|
||||
CameraControlImpl::Set(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit)
|
||||
{
|
||||
if (aLimit == 0) {
|
||||
DOM_CAMERA_LOGI("%s:%d : aLimit = 0, nothing to do\n", __func__, __LINE__);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!aValue.isObject()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
uint32_t length = 0;
|
||||
|
||||
JS::Rooted<JSObject*> regions(aCx, &aValue.toObject());
|
||||
if (!JS_GetArrayLength(aCx, regions, &length)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGI("%s:%d : got %d regions (limited to %d)\n", __func__, __LINE__, length, aLimit);
|
||||
if (length > aLimit) {
|
||||
length = aLimit;
|
||||
}
|
||||
|
||||
nsTArray<CameraRegion> regionArray;
|
||||
regionArray.SetCapacity(length);
|
||||
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
JS::Rooted<JS::Value> v(aCx);
|
||||
|
||||
if (!JS_GetElement(aCx, regions, i, &v)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
CameraRegion* r = regionArray.AppendElement();
|
||||
/**
|
||||
* These are the default values. We can remove these when the xpidl
|
||||
* dictionary parser gains the ability to grok default values.
|
||||
*/
|
||||
r->top = -1000;
|
||||
r->left = -1000;
|
||||
r->bottom = 1000;
|
||||
r->right = 1000;
|
||||
r->weight = 1000;
|
||||
|
||||
nsresult rv = r->Init(aCx, v.address());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
DOM_CAMERA_LOGI("region %d: top=%d, left=%d, bottom=%d, right=%d, weight=%d\n",
|
||||
i,
|
||||
r->top,
|
||||
r->left,
|
||||
r->bottom,
|
||||
r->right,
|
||||
r->weight
|
||||
);
|
||||
}
|
||||
SetParameter(aKey, regionArray);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue)
|
||||
{
|
||||
nsTArray<CameraRegion> regionArray;
|
||||
|
||||
GetParameter(aKey, regionArray);
|
||||
|
||||
JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0));
|
||||
if (!array) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
uint32_t length = regionArray.Length();
|
||||
DOM_CAMERA_LOGI("%s:%d : got %d regions\n", __func__, __LINE__, length);
|
||||
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
CameraRegion* r = ®ionArray[i];
|
||||
JS::Rooted<JS::Value> v(aCx);
|
||||
|
||||
JS::Rooted<JSObject*> o(aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr()));
|
||||
if (!o) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGI("top=%d\n", r->top);
|
||||
v = INT_TO_JSVAL(r->top);
|
||||
if (!JS_SetProperty(aCx, o, "top", v)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
DOM_CAMERA_LOGI("left=%d\n", r->left);
|
||||
v = INT_TO_JSVAL(r->left);
|
||||
if (!JS_SetProperty(aCx, o, "left", v)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
DOM_CAMERA_LOGI("bottom=%d\n", r->bottom);
|
||||
v = INT_TO_JSVAL(r->bottom);
|
||||
if (!JS_SetProperty(aCx, o, "bottom", v)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
DOM_CAMERA_LOGI("right=%d\n", r->right);
|
||||
v = INT_TO_JSVAL(r->right);
|
||||
if (!JS_SetProperty(aCx, o, "right", v)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
DOM_CAMERA_LOGI("weight=%d\n", r->weight);
|
||||
v = INT_TO_JSVAL(r->weight);
|
||||
if (!JS_SetProperty(aCx, o, "weight", v)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!JS_SetElement(aCx, array, i, o)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
*aValue = JS::ObjectValue(*array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Set(nsICameraShutterCallback* aOnShutter)
|
||||
{
|
||||
mOnShutterCb = new nsMainThreadPtrHolder<nsICameraShutterCallback>(aOnShutter);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Get(nsICameraShutterCallback** aOnShutter)
|
||||
{
|
||||
*aOnShutter = mOnShutterCb;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Set(nsICameraClosedCallback* aOnClosed)
|
||||
{
|
||||
mOnClosedCb = new nsMainThreadPtrHolder<nsICameraClosedCallback>(aOnClosed);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Get(nsICameraClosedCallback** aOnClosed)
|
||||
{
|
||||
*aOnClosed = mOnClosedCb;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Set(nsICameraRecorderStateChange* aOnRecorderStateChange)
|
||||
{
|
||||
mOnRecorderStateChangeCb = new nsMainThreadPtrHolder<nsICameraRecorderStateChange>(aOnRecorderStateChange);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Get(nsICameraRecorderStateChange** aOnRecorderStateChange)
|
||||
{
|
||||
*aOnRecorderStateChange = mOnRecorderStateChangeCb;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Set(nsICameraPreviewStateChange* aOnPreviewStateChange)
|
||||
{
|
||||
mOnPreviewStateChangeCb = new nsMainThreadPtrHolder<nsICameraPreviewStateChange>(aOnPreviewStateChange);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Get(nsICameraPreviewStateChange** aOnPreviewStateChange)
|
||||
{
|
||||
*aOnPreviewStateChange = mOnPreviewStateChangeCb;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Set(uint32_t aKey, const idl::CameraSize& aSize)
|
||||
{
|
||||
SetParameter(aKey, aSize);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Get(uint32_t aKey, idl::CameraSize& aSize)
|
||||
{
|
||||
GetParameter(aKey, aSize);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Get(uint32_t aKey, int32_t* aValue)
|
||||
{
|
||||
MOZ_ASSERT(aValue);
|
||||
*aValue = GetParameterInt32(aKey);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<RecorderProfileManager>
|
||||
@ -286,238 +59,518 @@ void
|
||||
CameraControlImpl::Shutdown()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
mAutoFocusOnSuccessCb = nullptr;
|
||||
mAutoFocusOnErrorCb = nullptr;
|
||||
mTakePictureOnSuccessCb = nullptr;
|
||||
mTakePictureOnErrorCb = nullptr;
|
||||
mOnShutterCb = nullptr;
|
||||
mOnClosedCb = nullptr;
|
||||
mOnRecorderStateChangeCb = nullptr;
|
||||
mOnPreviewStateChangeCb = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CameraControlImpl::OnShutterInternal()
|
||||
CameraControlImpl::OnHardwareStateChange(CameraControlListener::HardwareState aNewState)
|
||||
{
|
||||
DOM_CAMERA_LOGI("** SNAP **\n");
|
||||
if (mOnShutterCb.get()) {
|
||||
mOnShutterCb->HandleEvent();
|
||||
// This callback can run on threads other than the Main Thread and
|
||||
// the Camera Thread. On Gonk, it may be called from the camera's
|
||||
// local binder thread, should the mediaserver process die.
|
||||
RwLockAutoEnterRead lock(mListenerLock);
|
||||
|
||||
if (aNewState == mHardwareState) {
|
||||
DOM_CAMERA_LOGI("OnHardwareStateChange: state did not change from %d\n", mHardwareState);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
const char* state[] = { "open", "closed", "failed" };
|
||||
MOZ_ASSERT(aNewState >= 0);
|
||||
if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) {
|
||||
DOM_CAMERA_LOGI("New hardware state is '%s'\n", state[aNewState]);
|
||||
} else {
|
||||
DOM_CAMERA_LOGE("OnHardwareStateChange: got invalid HardwareState value %d\n", aNewState);
|
||||
}
|
||||
#endif
|
||||
|
||||
mHardwareState = aNewState;
|
||||
|
||||
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
|
||||
CameraControlListener* l = mListeners[i];
|
||||
l->OnHardwareStateChange(mHardwareState);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CameraControlImpl::OnConfigurationChange()
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
|
||||
RwLockAutoEnterRead lock(mListenerLock);
|
||||
|
||||
DOM_CAMERA_LOGI("OnConfigurationChange : %d listeners\n", mListeners.Length());
|
||||
|
||||
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
|
||||
CameraControlListener* l = mListeners[i];
|
||||
l->OnConfigurationChange(mCurrentConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CameraControlImpl::OnAutoFocusComplete(bool aAutoFocusSucceeded)
|
||||
{
|
||||
// This callback can run on threads other than the Main Thread and
|
||||
// the Camera Thread. On Gonk, it is called from the camera
|
||||
// library's auto focus thread.
|
||||
RwLockAutoEnterRead lock(mListenerLock);
|
||||
|
||||
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
|
||||
CameraControlListener* l = mListeners[i];
|
||||
l->OnAutoFocusComplete(aAutoFocusSucceeded);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CameraControlImpl::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
|
||||
{
|
||||
// This callback can run on threads other than the Main Thread and
|
||||
// the Camera Thread. On Gonk, it is called from the camera
|
||||
// library's snapshot thread.
|
||||
RwLockAutoEnterRead lock(mListenerLock);
|
||||
|
||||
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
|
||||
CameraControlListener* l = mListeners[i];
|
||||
l->OnTakePictureComplete(aData, aLength, aMimeType);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CameraControlImpl::OnShutter()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> onShutter = NS_NewRunnableMethod(this, &CameraControlImpl::OnShutterInternal);
|
||||
nsresult rv = NS_DispatchToMainThread(onShutter);
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGW("Failed to dispatch onShutter event to main thread (%d)\n", rv);
|
||||
// This callback can run on threads other than the Main Thread and
|
||||
// the Camera Thread. On Gonk, it is called from the camera driver's
|
||||
// preview thread.
|
||||
RwLockAutoEnterRead lock(mListenerLock);
|
||||
|
||||
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
|
||||
CameraControlListener* l = mListeners[i];
|
||||
l->OnShutter();
|
||||
}
|
||||
}
|
||||
|
||||
class OnClosedTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
OnClosedTask(nsMainThreadPtrHandle<nsICameraClosedCallback> onClosed, uint64_t aWindowId)
|
||||
: mOnClosedCb(onClosed)
|
||||
, mWindowId(aWindowId)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
virtual ~OnClosedTask()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mOnClosedCb.get() && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
|
||||
mOnClosedCb->HandleEvent();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsMainThreadPtrHandle<nsICameraClosedCallback> mOnClosedCb;
|
||||
uint64_t mWindowId;
|
||||
};
|
||||
|
||||
void
|
||||
CameraControlImpl::OnClosed()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> onClosed = new OnClosedTask(mOnClosedCb, mWindowId);
|
||||
nsresult rv = NS_DispatchToMainThread(onClosed);
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGW("Failed to dispatch onClosed event to main thread (%d)\n", rv);
|
||||
// This callback can run on threads other than the Main Thread and
|
||||
// the Camera Thread.
|
||||
RwLockAutoEnterRead lock(mListenerLock);
|
||||
|
||||
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
|
||||
CameraControlListener* l = mListeners[i];
|
||||
l->OnHardwareStateChange(CameraControlListener::kHardwareClosed);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CameraControlImpl::OnRecorderStateChange(const nsString& aStateMsg, int32_t aStatus, int32_t aTrackNumber)
|
||||
CameraControlImpl::OnRecorderStateChange(CameraControlListener::RecorderState aState,
|
||||
int32_t aStatus, int32_t aTrackNumber)
|
||||
{
|
||||
DOM_CAMERA_LOGI("OnRecorderStateChange: '%s'\n", NS_ConvertUTF16toUTF8(aStateMsg).get());
|
||||
// This callback can run on threads other than the Main Thread and
|
||||
// the Camera Thread. On Gonk, it is called from the media encoder
|
||||
// thread.
|
||||
RwLockAutoEnterRead lock(mListenerLock);
|
||||
|
||||
nsCOMPtr<nsIRunnable> onRecorderStateChange = new CameraRecorderStateChange(mOnRecorderStateChangeCb, aStateMsg, aStatus, aTrackNumber, mWindowId);
|
||||
nsresult rv = NS_DispatchToMainThread(onRecorderStateChange);
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGE("Failed to dispatch onRecorderStateChange event to main thread (%d)\n", rv);
|
||||
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
|
||||
CameraControlListener* l = mListeners[i];
|
||||
l->OnRecorderStateChange(aState, aStatus, aTrackNumber);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CameraControlImpl::OnPreviewStateChange(PreviewState aNewState)
|
||||
CameraControlImpl::OnPreviewStateChange(CameraControlListener::PreviewState aNewState)
|
||||
{
|
||||
// This callback runs on the Main Thread and the Camera Thread, and
|
||||
// may run on the local binder thread, should the mediaserver
|
||||
// process die.
|
||||
RwLockAutoEnterRead lock(mListenerLock);
|
||||
|
||||
if (aNewState == mPreviewState) {
|
||||
DOM_CAMERA_LOGI("OnPreviewStateChange: state did not change from %d\n", mPreviewState);
|
||||
return;
|
||||
}
|
||||
|
||||
nsString msg;
|
||||
switch (aNewState) {
|
||||
case PREVIEW_STOPPED:
|
||||
msg = NS_LITERAL_STRING("stopped");
|
||||
break;
|
||||
|
||||
case PREVIEW_STARTED:
|
||||
msg = NS_LITERAL_STRING("started");
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("Preview state can only be PREVIEW_STOPPED or _STARTED!");
|
||||
#ifdef PR_LOGGING
|
||||
const char* state[] = { "stopped", "paused", "started" };
|
||||
MOZ_ASSERT(aNewState >= 0);
|
||||
if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) {
|
||||
DOM_CAMERA_LOGI("New preview state is '%s'\n", state[aNewState]);
|
||||
} else {
|
||||
DOM_CAMERA_LOGE("OnPreviewStateChange: got unknown PreviewState value %d\n", aNewState);
|
||||
}
|
||||
#endif
|
||||
|
||||
// const nsString& aStateMsg)
|
||||
DOM_CAMERA_LOGI("OnPreviewStateChange: '%s'\n", NS_ConvertUTF16toUTF8(msg).get());
|
||||
mPreviewState = aNewState;
|
||||
|
||||
nsCOMPtr<nsIRunnable> onPreviewStateChange = new CameraPreviewStateChange(mOnPreviewStateChangeCb, msg, mWindowId);
|
||||
nsresult rv = NS_DispatchToMainThread(onPreviewStateChange);
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGE("Failed to dispatch onPreviewStateChange event to main thread (%d)\n", rv);
|
||||
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
|
||||
CameraControlListener* l = mListeners[i];
|
||||
l->OnPreviewStateChange(mPreviewState);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::GetPreviewStream(CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
bool
|
||||
CameraControlImpl::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> getPreviewStreamTask = new GetPreviewStreamTask(this, aSize, onSuccess, onError);
|
||||
return mCameraThread->Dispatch(getPreviewStreamTask, NS_DISPATCH_NORMAL);
|
||||
// This function runs on neither the Main Thread nor the Camera Thread.
|
||||
// On Gonk, it is called from the camera driver's preview thread.
|
||||
RwLockAutoEnterRead lock(mListenerLock);
|
||||
|
||||
DOM_CAMERA_LOGI("OnNewPreviewFrame: we have %d preview frame listener(s)\n",
|
||||
mListeners.Length());
|
||||
|
||||
bool consumed = false;
|
||||
|
||||
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
|
||||
CameraControlListener* l = mListeners[i];
|
||||
consumed = l->OnNewPreviewFrame(aImage, aWidth, aHeight) || consumed;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
void
|
||||
CameraControlImpl::OnError(CameraControlListener::CameraErrorContext aContext,
|
||||
CameraControlListener::CameraError aError)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
bool cancel = false;
|
||||
// This callback can run on threads other than the Main Thread and
|
||||
// the Camera Thread.
|
||||
RwLockAutoEnterRead lock(mListenerLock);
|
||||
|
||||
nsCOMPtr<nsICameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb.get();
|
||||
if (cb) {
|
||||
/**
|
||||
* We already have a callback, so someone has already
|
||||
* called autoFocus() -- cancel it.
|
||||
*/
|
||||
mAutoFocusOnSuccessCb = nullptr;
|
||||
mAutoFocusOnErrorCb = nullptr;
|
||||
cancel = true;
|
||||
#ifdef PR_LOGGING
|
||||
const char* error[] = { "camera-service-failed", "unknown" };
|
||||
if (static_cast<unsigned int>(aError) < sizeof(error) / sizeof(error[0])) {
|
||||
DOM_CAMERA_LOGW("CameraControlImpl::OnError : aContext=%u, msg='%s'\n",
|
||||
aContext, error[aError]);
|
||||
} else {
|
||||
DOM_CAMERA_LOGE("CameraControlImpl::OnError : aContext=%u, unknown error=%d\n",
|
||||
aContext, aError);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
|
||||
CameraControlListener* l = mListeners[i];
|
||||
l->OnError(aContext, aError);
|
||||
}
|
||||
}
|
||||
|
||||
// Camera control asynchronous message; these are dispatched from
|
||||
// the Main Thread to the Camera Thread, where they are consumed.
|
||||
|
||||
class CameraControlImpl::ControlMessage : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ControlMessage(CameraControlImpl* aCameraControl,
|
||||
CameraControlListener::CameraErrorContext aContext)
|
||||
: mCameraControl(aCameraControl)
|
||||
, mContext(aContext)
|
||||
{
|
||||
MOZ_COUNT_CTOR(CameraControlImpl::ControlMessage);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> autoFocusTask = new AutoFocusTask(this, cancel, onSuccess, onError);
|
||||
return mCameraThread->Dispatch(autoFocusTask, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::TakePicture(const CameraSize& aSize, int32_t aRotation, const nsAString& aFileFormat, CameraPosition aPosition, uint64_t aDateTime, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
bool cancel = false;
|
||||
|
||||
nsCOMPtr<nsICameraTakePictureCallback> cb = mTakePictureOnSuccessCb.get();
|
||||
if (cb) {
|
||||
/**
|
||||
* We already have a callback, so someone has already
|
||||
* called takePicture() -- cancel it.
|
||||
*/
|
||||
mTakePictureOnSuccessCb = nullptr;
|
||||
mTakePictureOnErrorCb = nullptr;
|
||||
cancel = true;
|
||||
virtual ~ControlMessage()
|
||||
{
|
||||
MOZ_COUNT_DTOR(CameraControlImpl::ControlMessage);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> takePictureTask = new TakePictureTask(this, cancel, aSize, aRotation, aFileFormat, aPosition, aDateTime, onSuccess, onError);
|
||||
return mCameraThread->Dispatch(takePictureTask, NS_DISPATCH_NORMAL);
|
||||
virtual nsresult RunImpl() = 0;
|
||||
|
||||
NS_IMETHOD
|
||||
Run() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(mCameraControl);
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mCameraControl->mCameraThread);
|
||||
|
||||
nsresult rv = RunImpl();
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGW("Camera control API failed at %d with 0x%x\n", mContext, rv);
|
||||
// XXXmikeh - do we want to report a more specific error code?
|
||||
mCameraControl->OnError(mContext, CameraControlListener::kErrorApiFailed);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsRefPtr<CameraControlImpl> mCameraControl;
|
||||
CameraControlListener::CameraErrorContext mContext;
|
||||
};
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::SetConfiguration(const Configuration& aConfig)
|
||||
{
|
||||
class Message : public ControlMessage
|
||||
{
|
||||
public:
|
||||
Message(CameraControlImpl* aCameraControl,
|
||||
CameraControlListener::CameraErrorContext aContext,
|
||||
const Configuration& aConfig)
|
||||
: ControlMessage(aCameraControl, aContext)
|
||||
, mConfig(aConfig)
|
||||
{ }
|
||||
|
||||
nsresult
|
||||
RunImpl() MOZ_OVERRIDE
|
||||
{
|
||||
return mCameraControl->SetConfigurationImpl(mConfig);
|
||||
}
|
||||
|
||||
protected:
|
||||
Configuration mConfig;
|
||||
};
|
||||
|
||||
return mCameraThread->Dispatch(
|
||||
new Message(this, CameraControlListener::kInSetConfiguration, aConfig), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::StartRecording(CameraStartRecordingOptions* aOptions, DeviceStorageFileDescriptor* aFileDescriptor, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
CameraControlImpl::AutoFocus(bool aCancelExistingCall)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> startRecordingTask = new StartRecordingTask(this, *aOptions, aFileDescriptor, onSuccess, onError, mWindowId);
|
||||
return mCameraThread->Dispatch(startRecordingTask, NS_DISPATCH_NORMAL);
|
||||
class Message : public ControlMessage
|
||||
{
|
||||
public:
|
||||
Message(CameraControlImpl* aCameraControl,
|
||||
CameraControlListener::CameraErrorContext aContext,
|
||||
bool aCancelExistingCall)
|
||||
: ControlMessage(aCameraControl, aContext)
|
||||
, mCancelExistingCall(aCancelExistingCall)
|
||||
{ }
|
||||
|
||||
nsresult
|
||||
RunImpl() MOZ_OVERRIDE
|
||||
{
|
||||
return mCameraControl->AutoFocusImpl(mCancelExistingCall);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool mCancelExistingCall;
|
||||
};
|
||||
|
||||
return mCameraThread->Dispatch(
|
||||
new Message(this, CameraControlListener::kInAutoFocus, aCancelExistingCall), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::TakePicture()
|
||||
{
|
||||
class Message : public ControlMessage
|
||||
{
|
||||
public:
|
||||
Message(CameraControlImpl* aCameraControl,
|
||||
CameraControlListener::CameraErrorContext aContext)
|
||||
: ControlMessage(aCameraControl, aContext)
|
||||
{ }
|
||||
|
||||
nsresult
|
||||
RunImpl() MOZ_OVERRIDE
|
||||
{
|
||||
return mCameraControl->TakePictureImpl();
|
||||
}
|
||||
};
|
||||
|
||||
return mCameraThread->Dispatch(
|
||||
new Message(this, CameraControlListener::kInTakePicture), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
|
||||
const StartRecordingOptions* aOptions)
|
||||
{
|
||||
class Message : public ControlMessage
|
||||
{
|
||||
public:
|
||||
Message(CameraControlImpl* aCameraControl,
|
||||
CameraControlListener::CameraErrorContext aContext,
|
||||
const StartRecordingOptions* aOptions,
|
||||
DeviceStorageFileDescriptor* aFileDescriptor)
|
||||
: ControlMessage(aCameraControl, aContext)
|
||||
, mOptionsPassed(false)
|
||||
, mFileDescriptor(aFileDescriptor)
|
||||
{
|
||||
if (aOptions) {
|
||||
mOptions = *aOptions;
|
||||
mOptionsPassed = true;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
RunImpl() MOZ_OVERRIDE
|
||||
{
|
||||
return mCameraControl->StartRecordingImpl(mFileDescriptor,
|
||||
mOptionsPassed ? &mOptions : nullptr);
|
||||
}
|
||||
|
||||
protected:
|
||||
StartRecordingOptions mOptions;
|
||||
bool mOptionsPassed;
|
||||
nsRefPtr<DeviceStorageFileDescriptor> mFileDescriptor;
|
||||
};
|
||||
|
||||
|
||||
return mCameraThread->Dispatch(new Message(this, CameraControlListener::kInStartRecording,
|
||||
aOptions, aFileDescriptor), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::StopRecording()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> stopRecordingTask = new StopRecordingTask(this);
|
||||
return mCameraThread->Dispatch(stopRecordingTask, NS_DISPATCH_NORMAL);
|
||||
class Message : public ControlMessage
|
||||
{
|
||||
public:
|
||||
Message(CameraControlImpl* aCameraControl,
|
||||
CameraControlListener::CameraErrorContext aContext)
|
||||
: ControlMessage(aCameraControl, aContext)
|
||||
{ }
|
||||
|
||||
nsresult
|
||||
RunImpl() MOZ_OVERRIDE
|
||||
{
|
||||
return mCameraControl->StopRecordingImpl();
|
||||
}
|
||||
};
|
||||
|
||||
return mCameraThread->Dispatch(
|
||||
new Message(this, CameraControlListener::kInStopRecording), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::StartPreview(DOMCameraPreview* aDOMPreview)
|
||||
CameraControlImpl::StartPreview()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> startPreviewTask = new StartPreviewTask(this, aDOMPreview);
|
||||
return mCameraThread->Dispatch(startPreviewTask, NS_DISPATCH_NORMAL);
|
||||
class Message : public ControlMessage
|
||||
{
|
||||
public:
|
||||
Message(CameraControlImpl* aCameraControl,
|
||||
CameraControlListener::CameraErrorContext aContext)
|
||||
: ControlMessage(aCameraControl, aContext)
|
||||
{ }
|
||||
|
||||
nsresult
|
||||
RunImpl() MOZ_OVERRIDE
|
||||
{
|
||||
return mCameraControl->StartPreviewImpl();
|
||||
}
|
||||
};
|
||||
|
||||
return mCameraThread->Dispatch(
|
||||
new Message(this, CameraControlListener::kInStartPreview), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::StopPreview()
|
||||
{
|
||||
class Message : public ControlMessage
|
||||
{
|
||||
public:
|
||||
Message(CameraControlImpl* aCameraControl,
|
||||
CameraControlListener::CameraErrorContext aContext)
|
||||
: ControlMessage(aCameraControl, aContext)
|
||||
{ }
|
||||
|
||||
nsresult
|
||||
RunImpl() MOZ_OVERRIDE
|
||||
{
|
||||
return mCameraControl->StopPreviewImpl();
|
||||
}
|
||||
};
|
||||
|
||||
return mCameraThread->Dispatch(
|
||||
new Message(this, CameraControlListener::kInStopPreview), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::ReleaseHardware()
|
||||
{
|
||||
class Message : public ControlMessage
|
||||
{
|
||||
public:
|
||||
Message(CameraControlImpl* aCameraControl,
|
||||
CameraControlListener::CameraErrorContext aContext)
|
||||
: ControlMessage(aCameraControl, aContext)
|
||||
{ }
|
||||
|
||||
nsresult
|
||||
RunImpl() MOZ_OVERRIDE
|
||||
{
|
||||
return mCameraControl->ReleaseHardwareImpl();
|
||||
}
|
||||
};
|
||||
|
||||
return mCameraThread->Dispatch(
|
||||
new Message(this, CameraControlListener::kInReleaseHardware), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
class CameraControlImpl::ListenerMessage : public CameraControlImpl::ControlMessage
|
||||
{
|
||||
public:
|
||||
ListenerMessage(CameraControlImpl* aCameraControl,
|
||||
CameraControlListener* aListener)
|
||||
: ControlMessage(aCameraControl, CameraControlListener::kInUnspecified)
|
||||
, mListener(aListener)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
nsRefPtr<CameraControlListener> mListener;
|
||||
};
|
||||
|
||||
void
|
||||
CameraControlImpl::AddListenerImpl(already_AddRefed<CameraControlListener> aListener)
|
||||
{
|
||||
RwLockAutoEnterWrite lock(mListenerLock);
|
||||
|
||||
CameraControlListener* l = *mListeners.AppendElement() = aListener;
|
||||
|
||||
// Update the newly-added listener's state
|
||||
l->OnConfigurationChange(mCurrentConfiguration);
|
||||
l->OnHardwareStateChange(mHardwareState);
|
||||
l->OnPreviewStateChange(mPreviewState);
|
||||
}
|
||||
|
||||
void
|
||||
CameraControlImpl::StopPreview()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> stopPreviewTask = new StopPreviewTask(this);
|
||||
mCameraThread->Dispatch(stopPreviewTask, NS_DISPATCH_NORMAL);
|
||||
CameraControlImpl::AddListener(CameraControlListener* aListener)
|
||||
{
|
||||
class Message : public ListenerMessage
|
||||
{
|
||||
public:
|
||||
Message(CameraControlImpl* aCameraControl,
|
||||
CameraControlListener* aListener)
|
||||
: ListenerMessage(aCameraControl, aListener)
|
||||
{ }
|
||||
|
||||
nsresult
|
||||
RunImpl() MOZ_OVERRIDE
|
||||
{
|
||||
mCameraControl->AddListenerImpl(mListener.forget());
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
mCameraThread->Dispatch(new Message(this, aListener), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::GetPreviewStreamVideoMode(CameraRecorderOptions* aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
void
|
||||
CameraControlImpl::RemoveListenerImpl(CameraControlListener* aListener)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> getPreviewStreamVideoModeTask = new GetPreviewStreamVideoModeTask(this, *aOptions, onSuccess, onError);
|
||||
return mCameraThread->Dispatch(getPreviewStreamVideoModeTask, NS_DISPATCH_NORMAL);
|
||||
RwLockAutoEnterWrite lock(mListenerLock);
|
||||
|
||||
nsRefPtr<CameraControlListener> l(aListener);
|
||||
mListeners.RemoveElement(l);
|
||||
// XXXmikeh - do we want to notify the listener that it has been removed?
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::ReleaseHardware(nsICameraReleaseCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> releaseHardwareTask = new ReleaseHardwareTask(this, onSuccess, onError);
|
||||
return mCameraThread->Dispatch(releaseHardwareTask, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
bool
|
||||
CameraControlImpl::ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder)
|
||||
{
|
||||
if (!mDOMPreview) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mDOMPreview->ReceiveFrame(aBuffer, aFormat, aBuilder);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GetPreviewStreamResult::Run()
|
||||
{
|
||||
/**
|
||||
* The camera preview stream object is DOM-facing, and as such
|
||||
* must be a cycle-collection participant created on the main
|
||||
* thread.
|
||||
*/
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsICameraPreviewStreamCallback> onSuccess = mOnSuccessCb.get();
|
||||
nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
|
||||
if (onSuccess && nsDOMCameraManager::IsWindowStillActive(mWindowId) && window) {
|
||||
nsCOMPtr<nsIDOMMediaStream> stream =
|
||||
new DOMCameraPreview(window, mCameraControl, mWidth, mHeight,
|
||||
mFramesPerSecond);
|
||||
onSuccess->HandleEvent(stream);
|
||||
}
|
||||
return NS_OK;
|
||||
void
|
||||
CameraControlImpl::RemoveListener(CameraControlListener* aListener)
|
||||
{
|
||||
class Message : public ListenerMessage
|
||||
{
|
||||
public:
|
||||
Message(CameraControlImpl* aCameraControl, CameraControlListener* aListener)
|
||||
: ListenerMessage(aCameraControl, aListener)
|
||||
{ }
|
||||
|
||||
nsresult
|
||||
RunImpl() MOZ_OVERRIDE
|
||||
{
|
||||
mCameraControl->RemoveListenerImpl(mListener);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
mCameraThread->Dispatch(new Message(this, aListener), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
@ -5,746 +5,119 @@
|
||||
#ifndef DOM_CAMERA_CAMERACONTROLIMPL_H
|
||||
#define DOM_CAMERA_CAMERACONTROLIMPL_H
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "nsWeakPtr.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsDOMFile.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "DictionaryHelpers.h"
|
||||
#include "AutoRwLock.h"
|
||||
#include "nsIDOMDeviceStorage.h"
|
||||
#include "DOMCameraManager.h"
|
||||
#include "DOMCameraPreview.h"
|
||||
#include "ICameraControl.h"
|
||||
#include "CameraCommon.h"
|
||||
#include "DeviceStorage.h"
|
||||
#include "DeviceStorageFileDescriptor.h"
|
||||
#include "CameraControlListener.h"
|
||||
|
||||
class DeviceStorageFileDescriptor;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class GetPreviewStreamTask;
|
||||
class StartPreviewTask;
|
||||
class StopPreviewTask;
|
||||
class AutoFocusTask;
|
||||
class TakePictureTask;
|
||||
class StartRecordingTask;
|
||||
class StopRecordingTask;
|
||||
class SetParameterTask;
|
||||
class GetParameterTask;
|
||||
class GetPreviewStreamVideoModeTask;
|
||||
class ReleaseHardwareTask;
|
||||
namespace layers {
|
||||
class Image;
|
||||
}
|
||||
|
||||
class DOMCameraPreview;
|
||||
class RecorderProfileManager;
|
||||
|
||||
class CameraControlImpl : public ICameraControl
|
||||
{
|
||||
friend class GetPreviewStreamTask;
|
||||
friend class StartPreviewTask;
|
||||
friend class StopPreviewTask;
|
||||
friend class AutoFocusTask;
|
||||
friend class TakePictureTask;
|
||||
friend class StartRecordingTask;
|
||||
friend class StopRecordingTask;
|
||||
friend class SetParameterTask;
|
||||
friend class GetParameterTask;
|
||||
friend class GetPreviewStreamVideoModeTask;
|
||||
friend class ReleaseHardwareTask;
|
||||
|
||||
public:
|
||||
CameraControlImpl(uint32_t aCameraId, nsIThread* aCameraThread, uint64_t aWindowId);
|
||||
CameraControlImpl(uint32_t aCameraId);
|
||||
virtual void AddListener(CameraControlListener* aListener) MOZ_OVERRIDE;
|
||||
virtual void RemoveListener(CameraControlListener* aListener) MOZ_OVERRIDE;
|
||||
|
||||
nsresult GetPreviewStream(idl::CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError);
|
||||
nsresult StartPreview(DOMCameraPreview* aDOMPreview);
|
||||
void StopPreview();
|
||||
nsresult AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError);
|
||||
nsresult TakePicture(const idl::CameraSize& aSize, int32_t aRotation, const nsAString& aFileFormat, idl::CameraPosition aPosition, uint64_t aDateTime, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError);
|
||||
nsresult StartRecording(idl::CameraStartRecordingOptions* aOptions, DeviceStorageFileDescriptor *aDSFileDescriptor, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError);
|
||||
nsresult StopRecording();
|
||||
nsresult GetPreviewStreamVideoMode(idl::CameraRecorderOptions* aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError);
|
||||
nsresult ReleaseHardware(nsICameraReleaseCallback* onSuccess, nsICameraErrorCallback* onError);
|
||||
|
||||
nsresult Set(uint32_t aKey, const nsAString& aValue);
|
||||
nsresult Get(uint32_t aKey, nsAString& aValue);
|
||||
nsresult Set(uint32_t aKey, double aValue);
|
||||
nsresult Get(uint32_t aKey, double* aValue);
|
||||
nsresult Set(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit);
|
||||
nsresult Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue);
|
||||
nsresult Set(nsICameraShutterCallback* aOnShutter);
|
||||
nsresult Get(nsICameraShutterCallback** aOnShutter);
|
||||
nsresult Set(nsICameraClosedCallback* aOnClosed);
|
||||
nsresult Get(nsICameraClosedCallback** aOnClosed);
|
||||
nsresult Set(nsICameraRecorderStateChange* aOnRecorderStateChange);
|
||||
nsresult Get(nsICameraRecorderStateChange** aOnRecorderStateChange);
|
||||
nsresult Set(nsICameraPreviewStateChange* aOnPreviewStateChange);
|
||||
nsresult Get(nsICameraPreviewStateChange** aOnPreviewStateChange);
|
||||
nsresult Set(uint32_t aKey, const idl::CameraSize& aSize);
|
||||
nsresult Get(uint32_t aKey, idl::CameraSize& aSize);
|
||||
nsresult Get(uint32_t aKey, int32_t* aValue);
|
||||
|
||||
nsresult SetFocusAreas(JSContext* aCx, const JS::Value& aValue)
|
||||
{
|
||||
return Set(aCx, CAMERA_PARAM_FOCUSAREAS, aValue, mMaxFocusAreas);
|
||||
}
|
||||
|
||||
nsresult SetMeteringAreas(JSContext* aCx, const JS::Value& aValue)
|
||||
{
|
||||
return Set(aCx, CAMERA_PARAM_METERINGAREAS, aValue, mMaxMeteringAreas);
|
||||
}
|
||||
virtual nsresult SetConfiguration(const Configuration& aConfig) MOZ_OVERRIDE;
|
||||
virtual nsresult StartPreview() MOZ_OVERRIDE;
|
||||
virtual nsresult StopPreview() MOZ_OVERRIDE;
|
||||
virtual nsresult AutoFocus(bool aCancelExistingCall) MOZ_OVERRIDE;
|
||||
virtual nsresult TakePicture() MOZ_OVERRIDE;
|
||||
virtual nsresult StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
|
||||
const StartRecordingOptions* aOptions) MOZ_OVERRIDE;
|
||||
virtual nsresult StopRecording() MOZ_OVERRIDE;
|
||||
virtual nsresult ReleaseHardware() MOZ_OVERRIDE;
|
||||
|
||||
already_AddRefed<RecorderProfileManager> GetRecorderProfileManager();
|
||||
uint32_t GetCameraId() { return mCameraId; }
|
||||
|
||||
virtual const char* GetParameter(const char* aKey) = 0;
|
||||
virtual const char* GetParameterConstChar(uint32_t aKey) = 0;
|
||||
virtual double GetParameterDouble(uint32_t aKey) = 0;
|
||||
virtual int32_t GetParameterInt32(uint32_t aKey) = 0;
|
||||
virtual void GetParameter(uint32_t aKey, nsTArray<idl::CameraRegion>& aRegions) = 0;
|
||||
virtual void GetParameter(uint32_t aKey, idl::CameraSize& aSize) = 0;
|
||||
virtual void SetParameter(const char* aKey, const char* aValue) = 0;
|
||||
virtual void SetParameter(uint32_t aKey, const char* aValue) = 0;
|
||||
virtual void SetParameter(uint32_t aKey, double aValue) = 0;
|
||||
virtual void SetParameter(uint32_t aKey, const nsTArray<idl::CameraRegion>& aRegions) = 0;
|
||||
virtual void SetParameter(uint32_t aKey, const idl::CameraSize& aSize) = 0;
|
||||
virtual nsresult GetVideoSizes(nsTArray<idl::CameraSize>& aVideoSizes) = 0;
|
||||
virtual nsresult PushParameters() = 0;
|
||||
virtual void Shutdown();
|
||||
virtual void Shutdown() MOZ_OVERRIDE;
|
||||
|
||||
bool ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder);
|
||||
void OnShutter();
|
||||
void OnClosed();
|
||||
void OnRecorderStateChange(const nsString& aStateMsg, int32_t aStatus, int32_t aTrackNumber);
|
||||
|
||||
enum PreviewState {
|
||||
PREVIEW_STOPPED,
|
||||
PREVIEW_STARTED
|
||||
};
|
||||
void OnPreviewStateChange(PreviewState aNewState);
|
||||
|
||||
uint64_t GetWindowId()
|
||||
{
|
||||
return mWindowId;
|
||||
}
|
||||
void OnError(CameraControlListener::CameraErrorContext aContext,
|
||||
CameraControlListener::CameraError aError);
|
||||
|
||||
protected:
|
||||
// Event handlers.
|
||||
void OnAutoFocusComplete(bool aAutoFocusSucceeded);
|
||||
void OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType);
|
||||
|
||||
bool OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight);
|
||||
void OnRecorderStateChange(CameraControlListener::RecorderState aState,
|
||||
int32_t aStatus, int32_t aTrackNumber);
|
||||
void OnPreviewStateChange(CameraControlListener::PreviewState aState);
|
||||
void OnHardwareStateChange(CameraControlListener::HardwareState aState);
|
||||
void OnConfigurationChange();
|
||||
|
||||
// When we create a new CameraThread, we keep a static reference to it so
|
||||
// that multiple CameraControl instances can find and reuse it; but we
|
||||
// don't want that reference to keep the thread object around unnecessarily,
|
||||
// so we make it a weak reference. The strong dynamic references will keep
|
||||
// the thread object alive as needed.
|
||||
static nsWeakPtr sCameraThread;
|
||||
nsCOMPtr<nsIThread> mCameraThread;
|
||||
|
||||
virtual ~CameraControlImpl();
|
||||
|
||||
virtual nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream) = 0;
|
||||
virtual nsresult StartPreviewImpl(StartPreviewTask* aStartPreview) = 0;
|
||||
virtual nsresult StopPreviewImpl(StopPreviewTask* aStopPreview) = 0;
|
||||
virtual nsresult AutoFocusImpl(AutoFocusTask* aAutoFocus) = 0;
|
||||
virtual nsresult TakePictureImpl(TakePictureTask* aTakePicture) = 0;
|
||||
virtual nsresult StartRecordingImpl(StartRecordingTask* aStartRecording) = 0;
|
||||
virtual nsresult StopRecordingImpl(StopRecordingTask* aStopRecording) = 0;
|
||||
virtual void BeginBatchParameterSet() MOZ_OVERRIDE { }
|
||||
virtual void EndBatchParameterSet() MOZ_OVERRIDE { }
|
||||
|
||||
// Manage camera event listeners.
|
||||
void AddListenerImpl(already_AddRefed<CameraControlListener> aListener);
|
||||
void RemoveListenerImpl(CameraControlListener* aListener);
|
||||
nsTArray<nsRefPtr<CameraControlListener> > mListeners;
|
||||
PRRWLock* mListenerLock;
|
||||
|
||||
class ControlMessage;
|
||||
class ListenerMessage;
|
||||
|
||||
virtual nsresult SetConfigurationImpl(const Configuration& aConfig) = 0;
|
||||
virtual nsresult StartPreviewImpl() = 0;
|
||||
virtual nsresult StopPreviewImpl() = 0;
|
||||
virtual nsresult AutoFocusImpl(bool aCancelExistingCall) = 0;
|
||||
virtual nsresult TakePictureImpl() = 0;
|
||||
virtual nsresult StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescriptor,
|
||||
const StartRecordingOptions* aOptions) = 0;
|
||||
virtual nsresult StopRecordingImpl() = 0;
|
||||
virtual nsresult PushParametersImpl() = 0;
|
||||
virtual nsresult PullParametersImpl() = 0;
|
||||
virtual nsresult GetPreviewStreamVideoModeImpl(GetPreviewStreamVideoModeTask* aGetPreviewStreamVideoMode) = 0;
|
||||
virtual nsresult ReleaseHardwareImpl(ReleaseHardwareTask* aReleaseHardware) = 0;
|
||||
virtual nsresult ReleaseHardwareImpl() = 0;
|
||||
virtual already_AddRefed<RecorderProfileManager> GetRecorderProfileManagerImpl() = 0;
|
||||
|
||||
void OnShutterInternal();
|
||||
void OnClosedInternal();
|
||||
|
||||
uint32_t mCameraId;
|
||||
nsCOMPtr<nsIThread> mCameraThread;
|
||||
uint64_t mWindowId;
|
||||
nsString mFileFormat;
|
||||
uint32_t mMaxMeteringAreas;
|
||||
uint32_t mMaxFocusAreas;
|
||||
PreviewState mPreviewState;
|
||||
uint32_t mCameraId;
|
||||
|
||||
/**
|
||||
* 'mDOMPreview' is a raw pointer to the object that will receive incoming
|
||||
* preview frames. This is guaranteed to be valid, or null.
|
||||
*
|
||||
* It is set by a call to StartPreview(), and set to null on StopPreview().
|
||||
* It is up to the caller to ensure that the object will not disappear
|
||||
* out from under this pointer--usually by calling NS_ADDREF().
|
||||
*/
|
||||
DOMCameraPreview* mDOMPreview;
|
||||
CameraControlListener::CameraListenerConfiguration mCurrentConfiguration;
|
||||
|
||||
nsMainThreadPtrHandle<nsICameraAutoFocusCallback> mAutoFocusOnSuccessCb;
|
||||
nsMainThreadPtrHandle<nsICameraErrorCallback> mAutoFocusOnErrorCb;
|
||||
nsMainThreadPtrHandle<nsICameraTakePictureCallback> mTakePictureOnSuccessCb;
|
||||
nsMainThreadPtrHandle<nsICameraErrorCallback> mTakePictureOnErrorCb;
|
||||
nsMainThreadPtrHandle<nsICameraShutterCallback> mOnShutterCb;
|
||||
nsMainThreadPtrHandle<nsICameraClosedCallback> mOnClosedCb;
|
||||
nsMainThreadPtrHandle<nsICameraRecorderStateChange> mOnRecorderStateChangeCb;
|
||||
nsMainThreadPtrHandle<nsICameraPreviewStateChange> mOnPreviewStateChangeCb;
|
||||
CameraControlListener::PreviewState mPreviewState;
|
||||
CameraControlListener::HardwareState mHardwareState;
|
||||
|
||||
private:
|
||||
CameraControlImpl(const CameraControlImpl&) MOZ_DELETE;
|
||||
CameraControlImpl& operator=(const CameraControlImpl&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
// Error result runnable
|
||||
class CameraErrorResult : public nsRunnable
|
||||
{
|
||||
public:
|
||||
CameraErrorResult(nsMainThreadPtrHandle<nsICameraErrorCallback> onError, const nsString& aErrorMsg, uint64_t aWindowId)
|
||||
: mOnErrorCb(onError)
|
||||
, mErrorMsg(aErrorMsg)
|
||||
, mWindowId(aWindowId)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mOnErrorCb.get() && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
|
||||
mOnErrorCb->HandleEvent(mErrorMsg);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsMainThreadPtrHandle<nsICameraErrorCallback> mOnErrorCb;
|
||||
const nsString mErrorMsg;
|
||||
uint64_t mWindowId;
|
||||
};
|
||||
|
||||
// Return the resulting preview stream to JS. Runs on the main thread.
|
||||
class GetPreviewStreamResult : public nsRunnable
|
||||
{
|
||||
public:
|
||||
GetPreviewStreamResult(CameraControlImpl* aCameraControl, uint32_t aWidth, uint32_t aHeight, uint32_t aFramesPerSecond, nsMainThreadPtrHandle<nsICameraPreviewStreamCallback>& onSuccess, uint64_t aWindowId)
|
||||
: mCameraControl(aCameraControl)
|
||||
, mWidth(aWidth)
|
||||
, mHeight(aHeight)
|
||||
, mFramesPerSecond(aFramesPerSecond)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
, mWindowId(aWindowId)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
virtual ~GetPreviewStreamResult()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
// Run() method is implementation specific.
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
nsRefPtr<CameraControlImpl> mCameraControl;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
uint32_t mFramesPerSecond;
|
||||
nsMainThreadPtrHandle<nsICameraPreviewStreamCallback> mOnSuccessCb;
|
||||
uint64_t mWindowId;
|
||||
};
|
||||
|
||||
// Get the desired preview stream.
|
||||
class GetPreviewStreamTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
GetPreviewStreamTask(CameraControlImpl* aCameraControl, idl::CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
: mSize(aSize)
|
||||
, mCameraControl(aCameraControl)
|
||||
, mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraPreviewStreamCallback>(onSuccess))
|
||||
, mOnErrorCb(new nsMainThreadPtrHolder<nsICameraErrorCallback>(onError))
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
virtual ~GetPreviewStreamTask()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||
{
|
||||
nsresult rv = mCameraControl->GetPreviewStreamImpl(this);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
nsCOMPtr<nsIRunnable> cameraErrorResult = new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE"), mCameraControl->GetWindowId());
|
||||
rv = NS_DispatchToMainThread(cameraErrorResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
idl::CameraSize mSize;
|
||||
nsRefPtr<CameraControlImpl> mCameraControl;
|
||||
nsMainThreadPtrHandle<nsICameraPreviewStreamCallback> mOnSuccessCb;
|
||||
nsMainThreadPtrHandle<nsICameraErrorCallback> mOnErrorCb;
|
||||
};
|
||||
|
||||
// Return the autofocus status to JS. Runs on the main thread.
|
||||
class AutoFocusResult : public nsRunnable
|
||||
{
|
||||
public:
|
||||
AutoFocusResult(bool aSuccess, nsMainThreadPtrHandle<nsICameraAutoFocusCallback> onSuccess, uint64_t aWindowId)
|
||||
: mSuccess(aSuccess)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
, mWindowId(aWindowId)
|
||||
{ }
|
||||
|
||||
virtual ~AutoFocusResult() { }
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mOnSuccessCb.get() && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
|
||||
mOnSuccessCb->HandleEvent(mSuccess);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool mSuccess;
|
||||
nsMainThreadPtrHandle<nsICameraAutoFocusCallback> mOnSuccessCb;
|
||||
uint64_t mWindowId;
|
||||
};
|
||||
|
||||
// Autofocus the camera.
|
||||
class AutoFocusTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
AutoFocusTask(CameraControlImpl* aCameraControl, bool aCancel, nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
: mCameraControl(aCameraControl)
|
||||
, mCancel(aCancel)
|
||||
, mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraAutoFocusCallback>(onSuccess))
|
||||
, mOnErrorCb(new nsMainThreadPtrHolder<nsICameraErrorCallback>(onError))
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
virtual ~AutoFocusTask()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
nsresult rv = mCameraControl->AutoFocusImpl(this);
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
nsCOMPtr<nsIRunnable> cameraErrorResult = new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE"), mCameraControl->GetWindowId());
|
||||
rv = NS_DispatchToMainThread(cameraErrorResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsRefPtr<CameraControlImpl> mCameraControl;
|
||||
bool mCancel;
|
||||
nsMainThreadPtrHandle<nsICameraAutoFocusCallback> mOnSuccessCb;
|
||||
nsMainThreadPtrHandle<nsICameraErrorCallback> mOnErrorCb;
|
||||
};
|
||||
|
||||
// Return the captured picture to JS. Runs on the main thread.
|
||||
class TakePictureResult : public nsRunnable
|
||||
{
|
||||
public:
|
||||
TakePictureResult(uint8_t* aData, uint64_t aLength, const nsAString& aMimeType, nsMainThreadPtrHandle<nsICameraTakePictureCallback> onSuccess, uint64_t aWindowId)
|
||||
: mData(aData)
|
||||
, mLength(aLength)
|
||||
, mMimeType(aMimeType)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
, mWindowId(aWindowId)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
virtual ~TakePictureResult()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
if (mOnSuccessCb.get() && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
|
||||
nsCOMPtr<nsIDOMBlob> image = new nsDOMMemoryFile(static_cast<void*>(mData), static_cast<uint64_t>(mLength), mMimeType);
|
||||
mOnSuccessCb->HandleEvent(image);
|
||||
} else {
|
||||
delete[] mData;
|
||||
}
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t* mData;
|
||||
uint64_t mLength;
|
||||
nsString mMimeType;
|
||||
nsMainThreadPtrHandle<nsICameraTakePictureCallback> mOnSuccessCb;
|
||||
uint64_t mWindowId;
|
||||
};
|
||||
|
||||
// Capture a still image with the camera.
|
||||
class TakePictureTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
TakePictureTask(CameraControlImpl* aCameraControl, bool aCancel, const idl::CameraSize& aSize, int32_t aRotation, const nsAString& aFileFormat, idl::CameraPosition aPosition, uint64_t aDateTime, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
: mCameraControl(aCameraControl)
|
||||
, mCancel(aCancel)
|
||||
, mSize(aSize)
|
||||
, mRotation(aRotation)
|
||||
, mFileFormat(aFileFormat)
|
||||
, mPosition(aPosition)
|
||||
, mDateTime(aDateTime)
|
||||
, mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraTakePictureCallback>(onSuccess))
|
||||
, mOnErrorCb(new nsMainThreadPtrHolder<nsICameraErrorCallback>(onError))
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
virtual ~TakePictureTask()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
nsresult rv = mCameraControl->TakePictureImpl(this);
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
nsCOMPtr<nsIRunnable> cameraErrorResult = new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE"), mCameraControl->GetWindowId());
|
||||
rv = NS_DispatchToMainThread(cameraErrorResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsRefPtr<CameraControlImpl> mCameraControl;
|
||||
bool mCancel;
|
||||
idl::CameraSize mSize;
|
||||
int32_t mRotation;
|
||||
nsString mFileFormat;
|
||||
idl::CameraPosition mPosition;
|
||||
uint64_t mDateTime;
|
||||
nsMainThreadPtrHandle<nsICameraTakePictureCallback> mOnSuccessCb;
|
||||
nsMainThreadPtrHandle<nsICameraErrorCallback> mOnErrorCb;
|
||||
};
|
||||
|
||||
// Return the result of starting recording. Runs on the main thread.
|
||||
class StartRecordingResult : public nsRunnable
|
||||
{
|
||||
public:
|
||||
StartRecordingResult(nsMainThreadPtrHandle<nsICameraStartRecordingCallback> onSuccess, uint64_t aWindowId)
|
||||
: mOnSuccessCb(onSuccess)
|
||||
, mWindowId(aWindowId)
|
||||
{ }
|
||||
|
||||
virtual ~StartRecordingResult() { }
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mOnSuccessCb.get() && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
|
||||
mOnSuccessCb->HandleEvent();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsMainThreadPtrHandle<nsICameraStartRecordingCallback> mOnSuccessCb;
|
||||
uint64_t mWindowId;
|
||||
};
|
||||
|
||||
// Start video recording.
|
||||
class StartRecordingTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
StartRecordingTask(CameraControlImpl* aCameraControl,
|
||||
idl::CameraStartRecordingOptions aOptions,
|
||||
DeviceStorageFileDescriptor *aDSFileDescriptor,
|
||||
nsICameraStartRecordingCallback* onSuccess,
|
||||
nsICameraErrorCallback* onError,
|
||||
uint64_t aWindowId)
|
||||
: mCameraControl(aCameraControl)
|
||||
, mOptions(aOptions)
|
||||
, mDSFileDescriptor(aDSFileDescriptor)
|
||||
, mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraStartRecordingCallback>(onSuccess))
|
||||
, mOnErrorCb(new nsMainThreadPtrHolder<nsICameraErrorCallback>(onError))
|
||||
, mWindowId(aWindowId)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
virtual ~StartRecordingTask()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
nsresult rv = mCameraControl->StartRecordingImpl(this);
|
||||
DOM_CAMERA_LOGT("%s:%d : result %d\n", __func__, __LINE__, rv);
|
||||
|
||||
// dispatch the callback
|
||||
nsCOMPtr<nsIRunnable> startRecordingResult;
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
startRecordingResult = new StartRecordingResult(mOnSuccessCb, mWindowId);
|
||||
} else {
|
||||
startRecordingResult = new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE"), mWindowId);
|
||||
}
|
||||
rv = NS_DispatchToMainThread(startRecordingResult);
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGE("Failed to dispatch start recording result to main thread (%d)!", rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsRefPtr<CameraControlImpl> mCameraControl;
|
||||
idl::CameraStartRecordingOptions mOptions;
|
||||
nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
|
||||
nsMainThreadPtrHandle<nsICameraStartRecordingCallback> mOnSuccessCb;
|
||||
nsMainThreadPtrHandle<nsICameraErrorCallback> mOnErrorCb;
|
||||
uint64_t mWindowId;
|
||||
};
|
||||
|
||||
// Stop video recording.
|
||||
class StopRecordingTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
StopRecordingTask(CameraControlImpl* aCameraControl)
|
||||
: mCameraControl(aCameraControl)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
virtual ~StopRecordingTask()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
nsresult rv = mCameraControl->StopRecordingImpl(this);
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<CameraControlImpl> mCameraControl;
|
||||
};
|
||||
|
||||
// Start the preview.
|
||||
class StartPreviewTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
StartPreviewTask(CameraControlImpl* aCameraControl, DOMCameraPreview* aDOMPreview)
|
||||
: mCameraControl(aCameraControl)
|
||||
, mDOMPreview(aDOMPreview)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
virtual ~StartPreviewTask()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
nsresult rv = mCameraControl->StartPreviewImpl(this);
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<CameraControlImpl> mCameraControl;
|
||||
DOMCameraPreview* mDOMPreview; // DOMCameraPreview NS_ADDREFs itself for us
|
||||
};
|
||||
|
||||
// Stop the preview.
|
||||
class StopPreviewTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
StopPreviewTask(CameraControlImpl* aCameraControl)
|
||||
: mCameraControl(aCameraControl)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
virtual ~StopPreviewTask()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
mCameraControl->StopPreviewImpl(this);
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<CameraControlImpl> mCameraControl;
|
||||
};
|
||||
|
||||
// Get the video mode preview stream.
|
||||
class GetPreviewStreamVideoModeTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
GetPreviewStreamVideoModeTask(CameraControlImpl* aCameraControl, idl::CameraRecorderOptions aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
: mCameraControl(aCameraControl)
|
||||
, mOptions(aOptions)
|
||||
, mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraPreviewStreamCallback>(onSuccess))
|
||||
, mOnErrorCb(new nsMainThreadPtrHolder<nsICameraErrorCallback>(onError))
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s:%d -- BEFORE IMPL\n", __func__, __LINE__);
|
||||
nsresult rv = mCameraControl->GetPreviewStreamVideoModeImpl(this);
|
||||
DOM_CAMERA_LOGI("%s:%d -- AFTER IMPL : rv = %d\n", __func__, __LINE__, rv);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
nsCOMPtr<nsIRunnable> cameraErrorResult = new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE"), mCameraControl->GetWindowId());
|
||||
rv = NS_DispatchToMainThread(cameraErrorResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<CameraControlImpl> mCameraControl;
|
||||
idl::CameraRecorderOptions mOptions;
|
||||
nsMainThreadPtrHandle<nsICameraPreviewStreamCallback> mOnSuccessCb;
|
||||
nsMainThreadPtrHandle<nsICameraErrorCallback> mOnErrorCb;
|
||||
};
|
||||
|
||||
// Return the result of releasing the camera hardware. Runs on the main thread.
|
||||
class ReleaseHardwareResult : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ReleaseHardwareResult(nsMainThreadPtrHandle<nsICameraReleaseCallback> onSuccess, uint64_t aWindowId)
|
||||
: mOnSuccessCb(onSuccess)
|
||||
, mWindowId(aWindowId)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
virtual ~ReleaseHardwareResult()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mOnSuccessCb.get() && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
|
||||
mOnSuccessCb->HandleEvent();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsMainThreadPtrHandle<nsICameraReleaseCallback> mOnSuccessCb;
|
||||
uint64_t mWindowId;
|
||||
};
|
||||
|
||||
// Release the camera hardware.
|
||||
class ReleaseHardwareTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ReleaseHardwareTask(CameraControlImpl* aCameraControl, nsICameraReleaseCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
: mCameraControl(aCameraControl)
|
||||
, mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraReleaseCallback>(onSuccess))
|
||||
, mOnErrorCb(new nsMainThreadPtrHolder<nsICameraErrorCallback>(onError))
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
virtual ~ReleaseHardwareTask()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
nsresult rv = mCameraControl->ReleaseHardwareImpl(this);
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
nsCOMPtr<nsIRunnable> cameraErrorResult = new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE"), mCameraControl->GetWindowId());
|
||||
rv = NS_DispatchToMainThread(cameraErrorResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsRefPtr<CameraControlImpl> mCameraControl;
|
||||
nsMainThreadPtrHandle<nsICameraReleaseCallback> mOnSuccessCb;
|
||||
nsMainThreadPtrHandle<nsICameraErrorCallback> mOnErrorCb;
|
||||
};
|
||||
|
||||
// Report that the video recorder state has changed.
|
||||
class CameraRecorderStateChange : public nsRunnable
|
||||
{
|
||||
public:
|
||||
CameraRecorderStateChange(nsMainThreadPtrHandle<nsICameraRecorderStateChange> onStateChange, const nsString& aStateMsg, int32_t aStatus, int32_t aTrackNumber, uint64_t aWindowId)
|
||||
: mOnStateChangeCb(onStateChange)
|
||||
, mStateMsg(aStateMsg)
|
||||
, mStatus(aStatus)
|
||||
, mTrackNumber(aTrackNumber)
|
||||
, mWindowId(aWindowId)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mOnStateChangeCb.get() && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
|
||||
// For now, just pass the state message and swallow mStatus and mTrackNumber
|
||||
mOnStateChangeCb->HandleStateChange(mStateMsg);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsMainThreadPtrHandle<nsICameraRecorderStateChange> mOnStateChangeCb;
|
||||
const nsString mStateMsg;
|
||||
int32_t mStatus;
|
||||
int32_t mTrackNumber;
|
||||
uint64_t mWindowId;
|
||||
};
|
||||
|
||||
// Report that the preview stream state has changed.
|
||||
class CameraPreviewStateChange : public nsRunnable
|
||||
{
|
||||
public:
|
||||
CameraPreviewStateChange(nsMainThreadPtrHandle<nsICameraPreviewStateChange> onStateChange, const nsString& aStateMsg, uint64_t aWindowId)
|
||||
: mOnStateChangeCb(onStateChange)
|
||||
, mStateMsg(aStateMsg)
|
||||
, mWindowId(aWindowId)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mOnStateChangeCb.get() && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
|
||||
mOnStateChangeCb->HandleStateChange(mStateMsg);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsMainThreadPtrHandle<nsICameraPreviewStateChange> mOnStateChangeCb;
|
||||
const nsString mStateMsg;
|
||||
uint64_t mWindowId;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DOM_CAMERA_CAMERACONTROLIMPL_H
|
||||
|
100
dom/camera/CameraControlListener.h
Normal file
100
dom/camera/CameraControlListener.h
Normal file
@ -0,0 +1,100 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef DOM_CAMERA_CAMERACONTROLLISTENER_H
|
||||
#define DOM_CAMERA_CAMERACONTROLLISTENER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ICameraControl.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace layers {
|
||||
class Image;
|
||||
}
|
||||
|
||||
class CameraControlListener
|
||||
{
|
||||
public:
|
||||
virtual ~CameraControlListener() { }
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CameraControlListener);
|
||||
|
||||
enum HardwareState
|
||||
{
|
||||
kHardwareOpen,
|
||||
kHardwareClosed
|
||||
};
|
||||
virtual void OnHardwareStateChange(HardwareState aState) { }
|
||||
|
||||
enum PreviewState
|
||||
{
|
||||
kPreviewStopped,
|
||||
kPreviewPaused,
|
||||
kPreviewStarted
|
||||
};
|
||||
virtual void OnPreviewStateChange(PreviewState aState) { }
|
||||
|
||||
enum RecorderState
|
||||
{
|
||||
kRecorderStopped,
|
||||
kRecorderStarted,
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
kFileSizeLimitReached,
|
||||
kVideoLengthLimitReached,
|
||||
kTrackCompleted,
|
||||
kTrackFailed,
|
||||
kMediaRecorderFailed,
|
||||
kMediaServerFailed
|
||||
#endif
|
||||
};
|
||||
enum { kNoTrackNumber = -1 };
|
||||
virtual void OnRecorderStateChange(RecorderState aState, int32_t aStatus, int32_t aTrackNum) { }
|
||||
|
||||
virtual void OnShutter() { }
|
||||
virtual bool OnNewPreviewFrame(layers::Image* aFrame, uint32_t aWidth, uint32_t aHeight)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
class CameraListenerConfiguration : public ICameraControl::Configuration
|
||||
{
|
||||
public:
|
||||
uint32_t mMaxMeteringAreas;
|
||||
uint32_t mMaxFocusAreas;
|
||||
};
|
||||
virtual void OnConfigurationChange(const CameraListenerConfiguration& aConfiguration) { }
|
||||
|
||||
virtual void OnAutoFocusComplete(bool aAutoFocusSucceeded) { }
|
||||
virtual void OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType) { }
|
||||
|
||||
enum CameraErrorContext
|
||||
{
|
||||
kInGetCamera,
|
||||
kInAutoFocus,
|
||||
kInTakePicture,
|
||||
kInStartRecording,
|
||||
kInStopRecording,
|
||||
kInSetConfiguration,
|
||||
kInReleaseHardware,
|
||||
kInStartPreview,
|
||||
kInStopPreview,
|
||||
kInUnspecified
|
||||
};
|
||||
enum CameraError
|
||||
{
|
||||
kErrorApiFailed,
|
||||
kErrorInitFailed,
|
||||
kErrorInvalidConfiguration,
|
||||
kErrorServiceFailed,
|
||||
kErrorSetPictureSizeFailed,
|
||||
kErrorSetThumbnailSizeFailed,
|
||||
kErrorUnknown
|
||||
};
|
||||
virtual void OnError(CameraErrorContext aContext, CameraError aError) { }
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DOM_CAMERA_CAMERACONTROLLISTENER_H
|
@ -2,8 +2,8 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "CameraRecorderProfiles.h"
|
||||
#include "jsapi.h"
|
||||
#include "CameraCommon.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -10,10 +10,8 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "jsapi.h"
|
||||
#include "DictionaryHelpers.h"
|
||||
#include "CameraCommon.h"
|
||||
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CameraControlImpl;
|
||||
|
@ -1,424 +1,282 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include "base/basictypes.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "jsapi.h"
|
||||
#include "CameraRecorderProfiles.h"
|
||||
#include "DOMCameraControl.h"
|
||||
#include "DOMCameraCapabilities.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/dom/CameraManagerBinding.h"
|
||||
#include "mozilla/dom/CameraCapabilitiesBinding.h"
|
||||
#include "CameraCommon.h"
|
||||
#include "ICameraControl.h"
|
||||
#include "CameraRecorderProfiles.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
DOMCI_DATA(CameraCapabilities, nsICameraCapabilities)
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(CameraCapabilities)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(DOMCameraCapabilities)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CameraCapabilities)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
|
||||
tmp->mRecorderProfiles = JS::UndefinedValue();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CameraCapabilities)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CameraCapabilities)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mRecorderProfiles)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraCapabilities)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraCapabilities)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CameraCapabilities)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsICameraCapabilities)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraCapabilities)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(DOMCameraCapabilities)
|
||||
NS_IMPL_RELEASE(DOMCameraCapabilities)
|
||||
|
||||
static nsresult
|
||||
ParseZoomRatioItemAndAdd(JSContext* aCx, JS::Handle<JSObject*> aArray,
|
||||
uint32_t aIndex, const char* aStart, char** aEnd)
|
||||
CameraCapabilities::CameraCapabilities(nsPIDOMWindow* aWindow)
|
||||
: mRecorderProfiles(JS::UndefinedValue())
|
||||
, mWindow(aWindow)
|
||||
{
|
||||
if (!*aEnd) {
|
||||
// make 'aEnd' follow the same semantics as strchr().
|
||||
aEnd = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* The by-100 divisor is Gonk-specific. For now, assume other platforms
|
||||
* return actual fractional multipliers.
|
||||
*/
|
||||
double d = strtod(aStart, aEnd);
|
||||
#if MOZ_WIDGET_GONK
|
||||
d /= 100;
|
||||
#endif
|
||||
|
||||
if (!JS_SetElement(aCx, aArray, aIndex, d)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
MOZ_COUNT_CTOR(CameraCapabilities);
|
||||
mozilla::HoldJSObjects(this);
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ParseStringItemAndAdd(JSContext* aCx, JS::Handle<JSObject*> aArray,
|
||||
uint32_t aIndex, const char* aStart, char** aEnd)
|
||||
CameraCapabilities::~CameraCapabilities()
|
||||
{
|
||||
JS::Rooted<JSString*> s(aCx);
|
||||
|
||||
if (*aEnd) {
|
||||
s = JS_NewStringCopyN(aCx, aStart, *aEnd - aStart);
|
||||
} else {
|
||||
s = JS_NewStringCopyZ(aCx, aStart);
|
||||
}
|
||||
if (!s) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (!JS_SetElement(aCx, aArray, aIndex, s)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
mRecorderProfiles = JS::UndefinedValue();
|
||||
mozilla::DropJSObjects(this);
|
||||
MOZ_COUNT_DTOR(CameraCapabilities);
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ParseDimensionItemAndAdd(JSContext* aCx, JS::Handle<JSObject*> aArray,
|
||||
uint32_t aIndex, const char* aStart, char** aEnd)
|
||||
JSObject*
|
||||
CameraCapabilities::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
{
|
||||
char* x;
|
||||
|
||||
if (!*aEnd) {
|
||||
// make 'aEnd' follow the same semantics as strchr().
|
||||
aEnd = nullptr;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> w(aCx, INT_TO_JSVAL(strtol(aStart, &x, 10)));
|
||||
JS::Rooted<JS::Value> h(aCx, INT_TO_JSVAL(strtol(x + 1, aEnd, 10)));
|
||||
|
||||
JS::Rooted<JSObject*> o(aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr()));
|
||||
if (!o) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (!JS_SetProperty(aCx, o, "width", w)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (!JS_SetProperty(aCx, o, "height", h)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!JS_SetElement(aCx, aArray, aIndex, o)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return CameraCapabilitiesBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
#define LOG_IF_ERROR(rv, param) \
|
||||
do { \
|
||||
if (NS_FAILED(rv)) { \
|
||||
DOM_CAMERA_LOGW("Error %x trying to get " #param "\n", \
|
||||
(rv)); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
nsresult
|
||||
DOMCameraCapabilities::ParameterListToNewArray(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aArray,
|
||||
uint32_t aKey,
|
||||
ParseItemAndAddFunc aParseItemAndAdd)
|
||||
CameraCapabilities::TranslateToDictionary(ICameraControl* aCameraControl,
|
||||
uint32_t aKey, nsTArray<CameraSize>& aSizes)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
const char* value = mCamera->GetParameterConstChar(aKey);
|
||||
if (!value) {
|
||||
// in case we get nonsense data back
|
||||
aArray.set(nullptr);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aArray.set(JS_NewArrayObject(aCx, 0));
|
||||
if (!aArray) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
const char* p = value;
|
||||
uint32_t index = 0;
|
||||
nsresult rv;
|
||||
char* q;
|
||||
nsTArray<ICameraControl::Size> sizes;
|
||||
|
||||
while (p) {
|
||||
/**
|
||||
* In C's string.h, strchr() is declared as returning 'char*'; in C++'s
|
||||
* cstring, it is declared as returning 'const char*', _except_ in MSVC,
|
||||
* where the C version is declared to return const like the C++ version.
|
||||
*
|
||||
* Unfortunately, for both cases, strtod() and strtol() take a 'char**' as
|
||||
* the end-of-conversion pointer, so we need to cast away strchr()'s
|
||||
* const-ness here to make the MSVC build everything happy.
|
||||
*/
|
||||
q = const_cast<char*>(strchr(p, ','));
|
||||
if (q != p) { // skip consecutive delimiters, just in case
|
||||
rv = aParseItemAndAdd(aCx, aArray, index, p, &q);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
++index;
|
||||
}
|
||||
p = q;
|
||||
if (p) {
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
return JS_FreezeObject(aCx, aArray) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DOMCameraCapabilities::StringListToNewObject(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aArray,
|
||||
uint32_t aKey)
|
||||
{
|
||||
JS::Rooted<JSObject*> array(aCx);
|
||||
|
||||
nsresult rv = ParameterListToNewArray(aCx, &array, aKey, ParseStringItemAndAdd);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aArray.setObjectOrNull(array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DOMCameraCapabilities::DimensionListToNewObject(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aArray,
|
||||
uint32_t aKey)
|
||||
{
|
||||
JS::Rooted<JSObject*> array(aCx);
|
||||
|
||||
nsresult rv = ParameterListToNewArray(aCx, &array, aKey, ParseDimensionItemAndAdd);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aArray.setObjectOrNull(array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute jsval previewSizes; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetPreviewSizes(JSContext* cx,
|
||||
JS::MutableHandle<JS::Value> aPreviewSizes)
|
||||
{
|
||||
return DimensionListToNewObject(cx, aPreviewSizes, CAMERA_PARAM_SUPPORTED_PREVIEWSIZES);
|
||||
}
|
||||
|
||||
/* readonly attribute jsval pictureSizes; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetPictureSizes(JSContext* cx,
|
||||
JS::MutableHandle<JS::Value> aPictureSizes)
|
||||
{
|
||||
return DimensionListToNewObject(cx, aPictureSizes, CAMERA_PARAM_SUPPORTED_PICTURESIZES);
|
||||
}
|
||||
|
||||
/* readonly attribute jsval thumbnailSizes; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetThumbnailSizes(JSContext* cx,
|
||||
JS::MutableHandle<JS::Value> aThumbnailSizes)
|
||||
{
|
||||
return DimensionListToNewObject(cx, aThumbnailSizes, CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES);
|
||||
}
|
||||
|
||||
/* readonly attribute jsval fileFormats; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetFileFormats(JSContext* cx,
|
||||
JS::MutableHandle<JS::Value> aFileFormats)
|
||||
{
|
||||
return StringListToNewObject(cx, aFileFormats, CAMERA_PARAM_SUPPORTED_PICTUREFORMATS);
|
||||
}
|
||||
|
||||
/* readonly attribute jsval whiteBalanceModes; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetWhiteBalanceModes(JSContext* cx,
|
||||
JS::MutableHandle<JS::Value> aWhiteBalanceModes)
|
||||
{
|
||||
return StringListToNewObject(cx, aWhiteBalanceModes, CAMERA_PARAM_SUPPORTED_WHITEBALANCES);
|
||||
}
|
||||
|
||||
/* readonly attribute jsval sceneModes; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetSceneModes(JSContext* cx,
|
||||
JS::MutableHandle<JS::Value> aSceneModes)
|
||||
{
|
||||
return StringListToNewObject(cx, aSceneModes, CAMERA_PARAM_SUPPORTED_SCENEMODES);
|
||||
}
|
||||
|
||||
/* readonly attribute jsval effects; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetEffects(JSContext* cx,
|
||||
JS::MutableHandle<JS::Value> aEffects)
|
||||
{
|
||||
return StringListToNewObject(cx, aEffects, CAMERA_PARAM_SUPPORTED_EFFECTS);
|
||||
}
|
||||
|
||||
/* readonly attribute jsval flashModes; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetFlashModes(JSContext* cx,
|
||||
JS::MutableHandle<JS::Value> aFlashModes)
|
||||
{
|
||||
return StringListToNewObject(cx, aFlashModes, CAMERA_PARAM_SUPPORTED_FLASHMODES);
|
||||
}
|
||||
|
||||
/* readonly attribute jsval focusModes; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetFocusModes(JSContext* cx,
|
||||
JS::MutableHandle<JS::Value> aFocusModes)
|
||||
{
|
||||
return StringListToNewObject(cx, aFocusModes, CAMERA_PARAM_SUPPORTED_FOCUSMODES);
|
||||
}
|
||||
|
||||
/* readonly attribute long maxFocusAreas; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetMaxFocusAreas(JSContext* cx, int32_t* aMaxFocusAreas)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS);
|
||||
if (!value) {
|
||||
// in case we get nonsense data back
|
||||
*aMaxFocusAreas = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aMaxFocusAreas = atoi(value);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute double minExposureCompensation; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetMinExposureCompensation(JSContext* cx, double* aMinExposureCompensation)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION);
|
||||
if (!value) {
|
||||
// in case we get nonsense data back
|
||||
*aMinExposureCompensation = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aMinExposureCompensation = atof(value);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute double maxExposureCompensation; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetMaxExposureCompensation(JSContext* cx, double* aMaxExposureCompensation)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION);
|
||||
if (!value) {
|
||||
// in case we get nonsense data back
|
||||
*aMaxExposureCompensation = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aMaxExposureCompensation = atof(value);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute double stepExposureCompensation; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetStepExposureCompensation(JSContext* cx, double* aStepExposureCompensation)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP);
|
||||
if (!value) {
|
||||
// in case we get nonsense data back
|
||||
*aStepExposureCompensation = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aStepExposureCompensation = atof(value);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute long maxMeteringAreas; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetMaxMeteringAreas(JSContext* cx, int32_t* aMaxMeteringAreas)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS);
|
||||
if (!value) {
|
||||
// in case we get nonsense data back
|
||||
*aMaxMeteringAreas = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aMaxMeteringAreas = atoi(value);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute jsval zoomRatios; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetZoomRatios(JSContext* cx, JS::MutableHandle<JS::Value> aZoomRatios)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_ZOOM);
|
||||
if (!value || strcmp(value, "true") != 0) {
|
||||
// if zoom is not supported, return a null object
|
||||
aZoomRatios.setNull();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> array(cx);
|
||||
|
||||
nsresult rv = ParameterListToNewArray(cx, &array, CAMERA_PARAM_SUPPORTED_ZOOMRATIOS, ParseZoomRatioItemAndAdd);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aZoomRatios.setObjectOrNull(array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute jsval videoSizes; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetVideoSizes(JSContext* cx, JS::MutableHandle<JS::Value> aVideoSizes)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
nsTArray<mozilla::idl::CameraSize> sizes;
|
||||
nsresult rv = mCamera->GetVideoSizes(sizes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (sizes.Length() == 0) {
|
||||
// video recording not supported, return null
|
||||
aVideoSizes.setNull();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> array(cx, JS_NewArrayObject(cx, 0));
|
||||
if (!array) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
rv = aCameraControl->Get(aKey, sizes);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
aSizes.Clear();
|
||||
aSizes.SetCapacity(sizes.Length());
|
||||
for (uint32_t i = 0; i < sizes.Length(); ++i) {
|
||||
JS::Rooted<JSObject*> o(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
|
||||
JS::Rooted<JS::Value> v(cx, INT_TO_JSVAL(sizes[i].width));
|
||||
if (!JS_SetProperty(cx, o, "width", v)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
v = INT_TO_JSVAL(sizes[i].height);
|
||||
if (!JS_SetProperty(cx, o, "height", v)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!JS_SetElement(cx, array, i, o)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
CameraSize* s = aSizes.AppendElement();
|
||||
s->mWidth = sizes[i].width;
|
||||
s->mHeight = sizes[i].height;
|
||||
}
|
||||
|
||||
aVideoSizes.setObject(*array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute jsval recorderProfiles; */
|
||||
NS_IMETHODIMP
|
||||
DOMCameraCapabilities::GetRecorderProfiles(JSContext* cx, JS::MutableHandle<JS::Value> aRecorderProfiles)
|
||||
nsresult
|
||||
CameraCapabilities::Populate(ICameraControl* aCameraControl)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
NS_ENSURE_TRUE(aCameraControl, NS_ERROR_INVALID_ARG);
|
||||
|
||||
nsRefPtr<RecorderProfileManager> profileMgr = mCamera->GetRecorderProfileManager();
|
||||
if (!profileMgr) {
|
||||
aRecorderProfiles.setNull();
|
||||
return NS_OK;
|
||||
nsresult rv;
|
||||
|
||||
rv = TranslateToDictionary(aCameraControl, CAMERA_PARAM_SUPPORTED_PREVIEWSIZES, mPreviewSizes);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_PREVIEWSIZES);
|
||||
|
||||
rv = TranslateToDictionary(aCameraControl, CAMERA_PARAM_SUPPORTED_PICTURESIZES, mPictureSizes);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_PICTURESIZES);
|
||||
|
||||
rv = TranslateToDictionary(aCameraControl, CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES, mThumbnailSizes);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES);
|
||||
|
||||
rv = TranslateToDictionary(aCameraControl, CAMERA_PARAM_SUPPORTED_VIDEOSIZES, mVideoSizes);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_VIDEOSIZES);
|
||||
|
||||
rv = aCameraControl->Get(CAMERA_PARAM_SUPPORTED_PICTUREFORMATS, mFileFormats);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_PICTUREFORMATS);
|
||||
|
||||
rv = aCameraControl->Get(CAMERA_PARAM_SUPPORTED_WHITEBALANCES, mWhiteBalanceModes);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_WHITEBALANCES);
|
||||
|
||||
rv = aCameraControl->Get(CAMERA_PARAM_SUPPORTED_SCENEMODES, mSceneModes);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_SCENEMODES);
|
||||
|
||||
rv = aCameraControl->Get(CAMERA_PARAM_SUPPORTED_EFFECTS, mEffects);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_EFFECTS);
|
||||
|
||||
rv = aCameraControl->Get(CAMERA_PARAM_SUPPORTED_FLASHMODES, mFlashModes);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_FLASHMODES);
|
||||
|
||||
rv = aCameraControl->Get(CAMERA_PARAM_SUPPORTED_FOCUSMODES, mFocusModes);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_FOCUSMODES);
|
||||
|
||||
rv = aCameraControl->Get(CAMERA_PARAM_SUPPORTED_ZOOMRATIOS, mZoomRatios);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_ZOOMRATIOS);
|
||||
|
||||
int32_t areas;
|
||||
rv = aCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS, areas);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS);
|
||||
mMaxFocusAreas = areas < 0 ? 0 : areas;
|
||||
|
||||
rv = aCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS, areas);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS);
|
||||
mMaxMeteringAreas = areas < 0 ? 0 : areas;
|
||||
|
||||
rv = aCameraControl->Get(CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION, mMinExposureCompensation);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION);
|
||||
|
||||
rv = aCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION, mMaxExposureCompensation);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION);
|
||||
|
||||
rv = aCameraControl->Get(CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP, mExposureCompensationStep);
|
||||
LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP);
|
||||
|
||||
mRecorderProfileManager = aCameraControl->GetRecorderProfileManager();
|
||||
if (!mRecorderProfileManager) {
|
||||
DOM_CAMERA_LOGW("Unable to get recorder profile manager\n");
|
||||
} else {
|
||||
AutoJSContext js;
|
||||
|
||||
JS::Rooted<JSObject*> o(js);
|
||||
nsresult rv = mRecorderProfileManager->GetJsObject(js, o.address());
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGE("Failed to JS-objectify profile manager (%d)\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
mRecorderProfiles = JS::ObjectValue(*o);
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> o(cx);
|
||||
nsresult rv = profileMgr->GetJsObject(cx, o.address());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aRecorderProfiles.setObject(*o);
|
||||
// For now, always return success, since the presence or absence of capabilities
|
||||
// indicates whether or not they are supported.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
CameraCapabilities::GetPreviewSizes(nsTArray<dom::CameraSize>& retval) const
|
||||
{
|
||||
retval = mPreviewSizes;
|
||||
}
|
||||
|
||||
void
|
||||
CameraCapabilities::GetPictureSizes(nsTArray<dom::CameraSize>& retval) const
|
||||
{
|
||||
retval = mPictureSizes;
|
||||
}
|
||||
|
||||
void
|
||||
CameraCapabilities::GetThumbnailSizes(nsTArray<dom::CameraSize>& retval) const
|
||||
{
|
||||
retval = mThumbnailSizes;
|
||||
}
|
||||
|
||||
void
|
||||
CameraCapabilities::GetVideoSizes(nsTArray<dom::CameraSize>& retval) const
|
||||
{
|
||||
retval = mVideoSizes;
|
||||
}
|
||||
|
||||
void
|
||||
CameraCapabilities::GetFileFormats(nsTArray<nsString>& retval) const
|
||||
{
|
||||
retval = mFileFormats;
|
||||
}
|
||||
|
||||
void
|
||||
CameraCapabilities::GetWhiteBalanceModes(nsTArray<nsString>& retval) const
|
||||
{
|
||||
retval = mWhiteBalanceModes;
|
||||
}
|
||||
|
||||
void
|
||||
CameraCapabilities::GetSceneModes(nsTArray<nsString>& retval) const
|
||||
{
|
||||
retval = mSceneModes;
|
||||
}
|
||||
|
||||
void
|
||||
CameraCapabilities::GetEffects(nsTArray<nsString>& retval) const
|
||||
{
|
||||
retval = mEffects;
|
||||
}
|
||||
|
||||
void
|
||||
CameraCapabilities::GetFlashModes(nsTArray<nsString>& retval) const
|
||||
{
|
||||
retval = mFlashModes;
|
||||
}
|
||||
|
||||
void
|
||||
CameraCapabilities::GetFocusModes(nsTArray<nsString>& retval) const
|
||||
{
|
||||
retval = mFocusModes;
|
||||
}
|
||||
|
||||
void
|
||||
CameraCapabilities::GetZoomRatios(nsTArray<double>& retval) const
|
||||
{
|
||||
retval = mZoomRatios;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CameraCapabilities::MaxFocusAreas() const
|
||||
{
|
||||
return mMaxFocusAreas;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CameraCapabilities::MaxMeteringAreas() const
|
||||
{
|
||||
return mMaxMeteringAreas;
|
||||
}
|
||||
|
||||
double
|
||||
CameraCapabilities::MinExposureCompensation() const
|
||||
{
|
||||
return mMinExposureCompensation;
|
||||
}
|
||||
|
||||
double
|
||||
CameraCapabilities::MaxExposureCompensation() const
|
||||
{
|
||||
return mMaxExposureCompensation;
|
||||
}
|
||||
|
||||
double
|
||||
CameraCapabilities::ExposureCompensationStep() const
|
||||
{
|
||||
return mExposureCompensationStep;
|
||||
}
|
||||
|
||||
JS::Value
|
||||
CameraCapabilities::RecorderProfiles(JSContext* aCx) const
|
||||
{
|
||||
return mRecorderProfiles;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -1,59 +1,96 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef DOM_CAMERA_DOMCAMERACAPABILITIES_H
|
||||
#define DOM_CAMERA_DOMCAMERACAPABILITIES_H
|
||||
#ifndef mozilla_dom_CameraCapabilities_h__
|
||||
#define mozilla_dom_CameraCapabilities_h__
|
||||
|
||||
#include "ICameraControl.h"
|
||||
#include "nsString.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "CameraCommon.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/CameraManagerBinding.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
struct JSContext;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
typedef nsresult (*ParseItemAndAddFunc)(JSContext* aCx, JS::Handle<JSObject*> aArray,
|
||||
uint32_t aIndex, const char* aStart, char** aEnd);
|
||||
class ICameraControl;
|
||||
class RecorderProfileManager;
|
||||
|
||||
class DOMCameraCapabilities MOZ_FINAL : public nsICameraCapabilities
|
||||
namespace dom {
|
||||
|
||||
class CameraCapabilities MOZ_FINAL : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICAMERACAPABILITIES
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CameraCapabilities)
|
||||
|
||||
DOMCameraCapabilities(ICameraControl* aCamera)
|
||||
: mCamera(aCamera)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
CameraCapabilities(nsPIDOMWindow* aWindow);
|
||||
~CameraCapabilities();
|
||||
|
||||
nsresult ParameterListToNewArray(
|
||||
JSContext* cx,
|
||||
JS::MutableHandle<JSObject*> aArray,
|
||||
uint32_t aKey,
|
||||
ParseItemAndAddFunc aParseItemAndAdd
|
||||
);
|
||||
nsresult StringListToNewObject(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aArray,
|
||||
uint32_t aKey);
|
||||
nsresult DimensionListToNewObject(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aArray,
|
||||
uint32_t aKey);
|
||||
nsresult Populate(ICameraControl* aCameraControl);
|
||||
|
||||
private:
|
||||
DOMCameraCapabilities(const DOMCameraCapabilities&) MOZ_DELETE;
|
||||
DOMCameraCapabilities& operator=(const DOMCameraCapabilities&) MOZ_DELETE;
|
||||
nsPIDOMWindow* GetParentObject() const { return mWindow; }
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
||||
void GetPreviewSizes(nsTArray<CameraSize>& aRetVal) const;
|
||||
void GetPictureSizes(nsTArray<CameraSize>& aRetVal) const;
|
||||
void GetThumbnailSizes(nsTArray<CameraSize>& aRetVal) const;
|
||||
void GetVideoSizes(nsTArray<CameraSize>& aRetVal) const;
|
||||
void GetFileFormats(nsTArray<nsString>& aRetVal) const;
|
||||
void GetWhiteBalanceModes(nsTArray<nsString>& aRetVal) const;
|
||||
void GetSceneModes(nsTArray<nsString>& aRetVal) const;
|
||||
void GetEffects(nsTArray<nsString>& aRetVal) const;
|
||||
void GetFlashModes(nsTArray<nsString>& aRetVal) const;
|
||||
void GetFocusModes(nsTArray<nsString>& aRetVal) const;
|
||||
void GetZoomRatios(nsTArray<double>& aRetVal) const;
|
||||
uint32_t MaxFocusAreas() const;
|
||||
uint32_t MaxMeteringAreas() const;
|
||||
double MinExposureCompensation() const;
|
||||
double MaxExposureCompensation() const;
|
||||
double ExposureCompensationStep() const;
|
||||
JS::Value RecorderProfiles(JSContext* cx) const;
|
||||
|
||||
protected:
|
||||
/* additional members */
|
||||
~DOMCameraCapabilities()
|
||||
{
|
||||
// destructor code
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p, mCamera=%p\n", __func__, __LINE__, this, mCamera.get());
|
||||
}
|
||||
nsresult TranslateToDictionary(ICameraControl* aCameraControl,
|
||||
uint32_t aKey, nsTArray<CameraSize>& aSizes);
|
||||
|
||||
nsRefPtr<ICameraControl> mCamera;
|
||||
nsTArray<CameraSize> mPreviewSizes;
|
||||
nsTArray<CameraSize> mPictureSizes;
|
||||
nsTArray<CameraSize> mThumbnailSizes;
|
||||
nsTArray<CameraSize> mVideoSizes;
|
||||
|
||||
nsTArray<nsString> mFileFormats;
|
||||
nsTArray<nsString> mWhiteBalanceModes;
|
||||
nsTArray<nsString> mSceneModes;
|
||||
nsTArray<nsString> mEffects;
|
||||
nsTArray<nsString> mFlashModes;
|
||||
nsTArray<nsString> mFocusModes;
|
||||
|
||||
nsTArray<double> mZoomRatios;
|
||||
|
||||
uint32_t mMaxFocusAreas;
|
||||
uint32_t mMaxMeteringAreas;
|
||||
|
||||
double mMinExposureCompensation;
|
||||
double mMaxExposureCompensation;
|
||||
double mExposureCompensationStep;
|
||||
|
||||
nsRefPtr<RecorderProfileManager> mRecorderProfileManager;
|
||||
JS::Heap<JS::Value> mRecorderProfiles;
|
||||
|
||||
nsRefPtr<nsPIDOMWindow> mWindow;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DOM_CAMERA_DOMCAMERACAPABILITIES_H
|
||||
#endif // mozilla_dom_CameraCapabilities_h__
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,51 +8,50 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "DictionaryHelpers.h"
|
||||
#include "mozilla/dom/CameraControlBinding.h"
|
||||
#include "ICameraControl.h"
|
||||
#include "DOMCameraPreview.h"
|
||||
#include "nsIDOMCameraManager.h"
|
||||
#include "CameraCommon.h"
|
||||
#include "DOMMediaStream.h"
|
||||
#include "AudioChannelAgent.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsHashPropertyBag.h"
|
||||
#include "DeviceStorage.h"
|
||||
#include "DOMCameraControlListener.h"
|
||||
|
||||
class nsDOMDeviceStorage;
|
||||
class nsPIDOMWindow;
|
||||
class nsIDOMBlob;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class CameraPictureOptions;
|
||||
template<typename T> class Optional;
|
||||
class CameraCapabilities;
|
||||
class CameraPictureOptions;
|
||||
class CameraStartRecordingOptions;
|
||||
template<typename T> class Optional;
|
||||
}
|
||||
class ErrorResult;
|
||||
class StartRecordingHelper;
|
||||
|
||||
// Main camera control.
|
||||
class nsDOMCameraControl MOZ_FINAL : public nsIDOMEventListener,
|
||||
public nsWrapperCache
|
||||
class nsDOMCameraControl MOZ_FINAL : public DOMMediaStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMCameraControl)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsDOMCameraControl, DOMMediaStream)
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThread,
|
||||
nsICameraGetCameraCallback* onSuccess,
|
||||
nsICameraErrorCallback* onError, nsPIDOMWindow* aWindow);
|
||||
nsresult Result(nsresult aResult,
|
||||
const nsMainThreadPtrHandle<nsICameraGetCameraCallback>& onSuccess,
|
||||
const nsMainThreadPtrHandle<nsICameraErrorCallback>& onError,
|
||||
uint64_t aWindowId);
|
||||
nsDOMCameraControl(uint32_t aCameraId,
|
||||
const dom::CameraConfiguration& aInitialConfig,
|
||||
dom::GetCameraCallback* aOnSuccess,
|
||||
dom::CameraErrorCallback* aOnError,
|
||||
nsPIDOMWindow* aWindow);
|
||||
nsRefPtr<ICameraControl> GetNativeCameraControl();
|
||||
|
||||
void Shutdown();
|
||||
|
||||
nsPIDOMWindow* GetParentObject() const { return mWindow; }
|
||||
|
||||
// WebIDL
|
||||
nsICameraCapabilities* Capabilities();
|
||||
// Attributes.
|
||||
void GetEffect(nsString& aEffect, ErrorResult& aRv);
|
||||
void SetEffect(const nsAString& aEffect, ErrorResult& aRv);
|
||||
void GetWhiteBalanceMode(nsString& aMode, ErrorResult& aRv);
|
||||
@ -80,48 +79,130 @@ public:
|
||||
void SetExposureCompensation(const dom::Optional<double>& aCompensation, ErrorResult& aRv);
|
||||
double GetExposureCompensation(ErrorResult& aRv);
|
||||
int32_t SensorAngle();
|
||||
already_AddRefed<nsICameraShutterCallback> GetOnShutter(ErrorResult& aRv);
|
||||
void SetOnShutter(nsICameraShutterCallback* aCb, ErrorResult& aRv);
|
||||
already_AddRefed<nsICameraClosedCallback> GetOnClosed(ErrorResult& aRv);
|
||||
void SetOnClosed(nsICameraClosedCallback* aCb, ErrorResult& aRv);
|
||||
already_AddRefed<nsICameraRecorderStateChange> GetOnRecorderStateChange(ErrorResult& aRv);
|
||||
void SetOnRecorderStateChange(nsICameraRecorderStateChange* aCb, ErrorResult& aRv);
|
||||
void AutoFocus(nsICameraAutoFocusCallback* aOnSuccess, const dom::Optional<nsICameraErrorCallback*>& aOnErro, ErrorResult& aRvr);
|
||||
void TakePicture(JSContext* aCx, const dom::CameraPictureOptions& aOptions,
|
||||
nsICameraTakePictureCallback* onSuccess,
|
||||
const dom::Optional<nsICameraErrorCallback* >& onError,
|
||||
already_AddRefed<dom::CameraCapabilities> Capabilities();
|
||||
|
||||
// Unsolicited event handlers.
|
||||
already_AddRefed<dom::CameraShutterCallback> GetOnShutter();
|
||||
void SetOnShutter(dom::CameraShutterCallback* aCb);
|
||||
already_AddRefed<dom::CameraClosedCallback> GetOnClosed();
|
||||
void SetOnClosed(dom::CameraClosedCallback* aCb);
|
||||
already_AddRefed<dom::CameraRecorderStateChange> GetOnRecorderStateChange();
|
||||
void SetOnRecorderStateChange(dom::CameraRecorderStateChange* aCb);
|
||||
already_AddRefed<dom::CameraPreviewStateChange> GetOnPreviewStateChange();
|
||||
void SetOnPreviewStateChange(dom::CameraPreviewStateChange* aCb);
|
||||
|
||||
// Methods.
|
||||
void SetConfiguration(const dom::CameraConfiguration& aConfiguration,
|
||||
const dom::Optional<dom::OwningNonNull<dom::CameraSetConfigurationCallback> >& aOnSuccess,
|
||||
const dom::Optional<dom::OwningNonNull<dom::CameraErrorCallback> >& aOnError,
|
||||
ErrorResult& aRv);
|
||||
void AutoFocus(dom::CameraAutoFocusCallback& aOnSuccess,
|
||||
const dom::Optional<dom::OwningNonNull<dom::CameraErrorCallback> >& aOnError,
|
||||
ErrorResult& aRv);
|
||||
void TakePicture(const dom::CameraPictureOptions& aOptions,
|
||||
dom::CameraTakePictureCallback& aOnSuccess,
|
||||
const dom::Optional<dom::OwningNonNull<dom::CameraErrorCallback> >& aOnError,
|
||||
ErrorResult& aRv);
|
||||
already_AddRefed<nsICameraPreviewStateChange> GetOnPreviewStateChange() const;
|
||||
void SetOnPreviewStateChange(nsICameraPreviewStateChange* aOnStateChange);
|
||||
void GetPreviewStreamVideoMode(JSContext* cx, JS::Handle<JS::Value> aOptions, nsICameraPreviewStreamCallback* onSuccess, const dom::Optional<nsICameraErrorCallback* >& onError, ErrorResult& aRv);
|
||||
void StartRecording(JSContext* cx, JS::Handle<JS::Value> aOptions, nsDOMDeviceStorage& storageArea, const nsAString& filename, nsICameraStartRecordingCallback* onSuccess, const dom::Optional<nsICameraErrorCallback* >& onError, ErrorResult& aRv);
|
||||
void StartRecording(const dom::CameraStartRecordingOptions& aOptions,
|
||||
nsDOMDeviceStorage& storageArea,
|
||||
const nsAString& filename,
|
||||
dom::CameraStartRecordingCallback& aOnSuccess,
|
||||
const dom::Optional<dom::OwningNonNull<dom::CameraErrorCallback> >& aOnError,
|
||||
ErrorResult& aRv);
|
||||
void StopRecording(ErrorResult& aRv);
|
||||
void GetPreviewStream(JSContext* cx, JS::Handle<JS::Value> aOptions, nsICameraPreviewStreamCallback* onSuccess, const dom::Optional<nsICameraErrorCallback* >& onError, ErrorResult& aRv);
|
||||
void ResumePreview(ErrorResult& aRv);
|
||||
void ReleaseHardware(const dom::Optional<nsICameraReleaseCallback* >& onSuccess, const dom::Optional<nsICameraErrorCallback* >& onError, ErrorResult& aRv);
|
||||
void ReleaseHardware(const dom::Optional<dom::OwningNonNull<dom::CameraReleaseCallback> >& aOnSuccess,
|
||||
const dom::Optional<dom::OwningNonNull<dom::CameraErrorCallback> >& aOnError,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
virtual ~nsDOMCameraControl();
|
||||
|
||||
class DOMCameraConfiguration : public dom::CameraConfiguration
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(DOMCameraConfiguration)
|
||||
|
||||
DOMCameraConfiguration();
|
||||
DOMCameraConfiguration(const dom::CameraConfiguration& aConfiguration);
|
||||
|
||||
// Additional configuration options that aren't exposed to the DOM
|
||||
uint32_t mMaxFocusAreas;
|
||||
uint32_t mMaxMeteringAreas;
|
||||
|
||||
protected:
|
||||
~DOMCameraConfiguration();
|
||||
};
|
||||
|
||||
friend class DOMCameraControlListener;
|
||||
friend class mozilla::StartRecordingHelper;
|
||||
|
||||
void OnCreatedFileDescriptor(bool aSucceeded);
|
||||
|
||||
void OnAutoFocusComplete(bool aAutoFocusSucceeded);
|
||||
void OnTakePictureComplete(nsIDOMBlob* aPicture);
|
||||
|
||||
void OnHardwareStateChange(DOMCameraControlListener::HardwareState aState);
|
||||
void OnPreviewStateChange(DOMCameraControlListener::PreviewState aState);
|
||||
void OnRecorderStateChange(CameraControlListener::RecorderState aState, int32_t aStatus, int32_t aTrackNum);
|
||||
void OnConfigurationChange(DOMCameraConfiguration* aConfiguration);
|
||||
void OnShutter();
|
||||
void OnError(CameraControlListener::CameraErrorContext aContext, const nsAString& mError);
|
||||
|
||||
bool IsWindowStillActive();
|
||||
|
||||
nsresult NotifyRecordingStatusChange(const nsString& aMsg);
|
||||
|
||||
nsRefPtr<ICameraControl> mCameraControl; // non-DOM camera control
|
||||
|
||||
// An agent used to join audio channel service.
|
||||
nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent;
|
||||
|
||||
nsresult Set(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit);
|
||||
nsresult Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue);
|
||||
|
||||
nsRefPtr<DOMCameraConfiguration> mCurrentConfiguration;
|
||||
nsRefPtr<dom::CameraCapabilities> mCapabilities;
|
||||
|
||||
// solicited camera control event handlers
|
||||
nsCOMPtr<dom::GetCameraCallback> mGetCameraOnSuccessCb;
|
||||
nsCOMPtr<dom::CameraErrorCallback> mGetCameraOnErrorCb;
|
||||
nsCOMPtr<dom::CameraAutoFocusCallback> mAutoFocusOnSuccessCb;
|
||||
nsCOMPtr<dom::CameraErrorCallback> mAutoFocusOnErrorCb;
|
||||
nsCOMPtr<dom::CameraTakePictureCallback> mTakePictureOnSuccessCb;
|
||||
nsCOMPtr<dom::CameraErrorCallback> mTakePictureOnErrorCb;
|
||||
nsCOMPtr<dom::CameraStartRecordingCallback> mStartRecordingOnSuccessCb;
|
||||
nsCOMPtr<dom::CameraErrorCallback> mStartRecordingOnErrorCb;
|
||||
nsCOMPtr<dom::CameraReleaseCallback> mReleaseOnSuccessCb;
|
||||
nsCOMPtr<dom::CameraErrorCallback> mReleaseOnErrorCb;
|
||||
nsCOMPtr<dom::CameraSetConfigurationCallback> mSetConfigurationOnSuccessCb;
|
||||
nsCOMPtr<dom::CameraErrorCallback> mSetConfigurationOnErrorCb;
|
||||
|
||||
// unsolicited event handlers
|
||||
nsCOMPtr<dom::CameraShutterCallback> mOnShutterCb;
|
||||
nsCOMPtr<dom::CameraClosedCallback> mOnClosedCb;
|
||||
nsCOMPtr<dom::CameraRecorderStateChange> mOnRecorderStateChangeCb;
|
||||
nsCOMPtr<dom::CameraPreviewStateChange> mOnPreviewStateChangeCb;
|
||||
|
||||
// Camera event listener; we only need this weak reference so that
|
||||
// we can remove the listener from the camera when we're done
|
||||
// with it.
|
||||
DOMCameraControlListener* mListener;
|
||||
|
||||
// our viewfinder stream
|
||||
CameraPreviewMediaStream* mInput;
|
||||
|
||||
// set once when this object is created
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
|
||||
dom::CameraStartRecordingOptions mOptions;
|
||||
nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
|
||||
|
||||
private:
|
||||
nsDOMCameraControl(const nsDOMCameraControl&) MOZ_DELETE;
|
||||
nsDOMCameraControl& operator=(const nsDOMCameraControl&) MOZ_DELETE;
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
nsresult NotifyRecordingStatusChange(const nsString& aMsg);
|
||||
|
||||
mozilla::idl::CameraStartRecordingOptions mOptions;
|
||||
nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
|
||||
nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
|
||||
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
|
||||
|
||||
protected:
|
||||
/* additional members */
|
||||
nsRefPtr<ICameraControl> mCameraControl; // non-DOM camera control
|
||||
nsCOMPtr<nsICameraCapabilities> mDOMCapabilities;
|
||||
// An agent used to join audio channel service.
|
||||
nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent;
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
329
dom/camera/DOMCameraControlListener.cpp
Normal file
329
dom/camera/DOMCameraControlListener.cpp
Normal file
@ -0,0 +1,329 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DOMCameraControlListener.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsDOMFile.h"
|
||||
#include "CameraCommon.h"
|
||||
#include "DOMCameraControl.h"
|
||||
#include "CameraPreviewMediaStream.h"
|
||||
#include "mozilla/dom/CameraManagerBinding.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
// Boilerplate callback runnable
|
||||
class DOMCameraControlListener::DOMCallback : public nsRunnable
|
||||
{
|
||||
public:
|
||||
DOMCallback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl)
|
||||
: mDOMCameraControl(aDOMCameraControl)
|
||||
{ }
|
||||
virtual ~DOMCallback() { }
|
||||
|
||||
virtual void RunCallback(nsDOMCameraControl* aDOMCameraControl) = 0;
|
||||
|
||||
NS_IMETHOD
|
||||
Run() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsRefPtr<nsDOMCameraControl> camera = mDOMCameraControl.get();
|
||||
if (camera) {
|
||||
RunCallback(camera);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsMainThreadPtrHandle<nsDOMCameraControl> mDOMCameraControl;
|
||||
};
|
||||
|
||||
// Specific callback handlers
|
||||
void
|
||||
DOMCameraControlListener::OnHardwareStateChange(HardwareState aState)
|
||||
{
|
||||
class Callback : public DOMCallback
|
||||
{
|
||||
public:
|
||||
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
|
||||
HardwareState aState)
|
||||
: DOMCallback(aDOMCameraControl)
|
||||
, mState(aState)
|
||||
{ }
|
||||
|
||||
void
|
||||
RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
|
||||
{
|
||||
aDOMCameraControl->OnHardwareStateChange(mState);
|
||||
}
|
||||
|
||||
protected:
|
||||
HardwareState mState;
|
||||
};
|
||||
|
||||
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState));
|
||||
}
|
||||
|
||||
void
|
||||
DOMCameraControlListener::OnPreviewStateChange(PreviewState aState)
|
||||
{
|
||||
class Callback : public DOMCallback
|
||||
{
|
||||
public:
|
||||
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
|
||||
PreviewState aState)
|
||||
: DOMCallback(aDOMCameraControl)
|
||||
, mState(aState)
|
||||
{ }
|
||||
|
||||
void
|
||||
RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
|
||||
{
|
||||
aDOMCameraControl->OnPreviewStateChange(mState);
|
||||
}
|
||||
|
||||
protected:
|
||||
PreviewState mState;
|
||||
};
|
||||
|
||||
switch (aState) {
|
||||
case kPreviewStopped:
|
||||
// Clear the current frame right away, without dispatching a
|
||||
// runnable. This is an ugly coupling between the camera's
|
||||
// SurfaceTextureClient and the MediaStream/ImageContainer,
|
||||
// but without it, the preview can fail to start.
|
||||
DOM_CAMERA_LOGI("Preview stopped, clearing current frame\n");
|
||||
mStream->ClearCurrentFrame();
|
||||
break;
|
||||
|
||||
case kPreviewPaused:
|
||||
// In the paused state, we still want to reflect the change
|
||||
// in preview state, but we don't want to clear the current
|
||||
// frame as above, since doing so seems to cause genlock
|
||||
// problems when we restart the preview. See bug 957749.
|
||||
DOM_CAMERA_LOGI("Preview paused\n");
|
||||
break;
|
||||
|
||||
case kPreviewStarted:
|
||||
DOM_CAMERA_LOGI("Preview started\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
DOM_CAMERA_LOGE("Unknown preview state %d\n", aState);
|
||||
MOZ_ASSUME_UNREACHABLE("Invalid preview state");
|
||||
return;
|
||||
}
|
||||
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState));
|
||||
}
|
||||
|
||||
void
|
||||
DOMCameraControlListener::OnRecorderStateChange(RecorderState aState,
|
||||
int32_t aStatus, int32_t aTrackNum)
|
||||
{
|
||||
class Callback : public DOMCallback
|
||||
{
|
||||
public:
|
||||
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
|
||||
RecorderState aState,
|
||||
int32_t aStatus,
|
||||
int32_t aTrackNum)
|
||||
: DOMCallback(aDOMCameraControl)
|
||||
, mState(aState)
|
||||
, mStatus(aStatus)
|
||||
, mTrackNum(aTrackNum)
|
||||
{ }
|
||||
|
||||
void
|
||||
RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
|
||||
{
|
||||
aDOMCameraControl->OnRecorderStateChange(mState, mStatus, mTrackNum);
|
||||
}
|
||||
|
||||
protected:
|
||||
RecorderState mState;
|
||||
int32_t mStatus;
|
||||
int32_t mTrackNum;
|
||||
};
|
||||
|
||||
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState, aStatus, aTrackNum));
|
||||
}
|
||||
|
||||
void
|
||||
DOMCameraControlListener::OnConfigurationChange(const CameraListenerConfiguration& aConfiguration)
|
||||
{
|
||||
class Callback : public DOMCallback
|
||||
{
|
||||
public:
|
||||
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
|
||||
const CameraListenerConfiguration& aConfiguration)
|
||||
: DOMCallback(aDOMCameraControl)
|
||||
, mConfiguration(aConfiguration)
|
||||
{ }
|
||||
|
||||
void
|
||||
RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
|
||||
{
|
||||
nsRefPtr<nsDOMCameraControl::DOMCameraConfiguration> config =
|
||||
new nsDOMCameraControl::DOMCameraConfiguration();
|
||||
|
||||
switch (mConfiguration.mMode) {
|
||||
case ICameraControl::kVideoMode:
|
||||
config->mMode = CameraMode::Video;
|
||||
break;
|
||||
|
||||
case ICameraControl::kPictureMode:
|
||||
config->mMode = CameraMode::Picture;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("Unanticipated camera mode!");
|
||||
}
|
||||
|
||||
// Map CameraControl parameters to their DOM-facing equivalents
|
||||
config->mRecorderProfile = mConfiguration.mRecorderProfile;
|
||||
config->mPreviewSize.mWidth = mConfiguration.mPreviewSize.width;
|
||||
config->mPreviewSize.mHeight = mConfiguration.mPreviewSize.height;
|
||||
config->mMaxMeteringAreas = mConfiguration.mMaxMeteringAreas;
|
||||
config->mMaxFocusAreas = mConfiguration.mMaxFocusAreas;
|
||||
|
||||
aDOMCameraControl->OnConfigurationChange(config);
|
||||
}
|
||||
|
||||
protected:
|
||||
const CameraListenerConfiguration mConfiguration;
|
||||
};
|
||||
|
||||
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aConfiguration));
|
||||
}
|
||||
|
||||
void
|
||||
DOMCameraControlListener::OnShutter()
|
||||
{
|
||||
class Callback : public DOMCallback
|
||||
{
|
||||
public:
|
||||
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl)
|
||||
: DOMCallback(aDOMCameraControl)
|
||||
{ }
|
||||
|
||||
void
|
||||
RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
|
||||
{
|
||||
aDOMCameraControl->OnShutter();
|
||||
}
|
||||
};
|
||||
|
||||
NS_DispatchToMainThread(new Callback(mDOMCameraControl));
|
||||
}
|
||||
|
||||
bool
|
||||
DOMCameraControlListener::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight)
|
||||
{
|
||||
DOM_CAMERA_LOGI("OnNewPreviewFrame: got %d x %d frame\n", aWidth, aHeight);
|
||||
|
||||
mStream->SetCurrentFrame(gfxIntSize(aWidth, aHeight), aImage);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DOMCameraControlListener::OnAutoFocusComplete(bool aAutoFocusSucceeded)
|
||||
{
|
||||
class Callback : public DOMCallback
|
||||
{
|
||||
public:
|
||||
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
|
||||
bool aAutoFocusSucceeded)
|
||||
: DOMCallback(aDOMCameraControl)
|
||||
, mAutoFocusSucceeded(aAutoFocusSucceeded)
|
||||
{ }
|
||||
|
||||
void
|
||||
RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
|
||||
{
|
||||
aDOMCameraControl->OnAutoFocusComplete(mAutoFocusSucceeded);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool mAutoFocusSucceeded;
|
||||
};
|
||||
|
||||
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aAutoFocusSucceeded));
|
||||
}
|
||||
|
||||
void
|
||||
DOMCameraControlListener::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
|
||||
{
|
||||
class Callback : public DOMCallback
|
||||
{
|
||||
public:
|
||||
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
|
||||
uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
|
||||
: DOMCallback(aDOMCameraControl)
|
||||
, mData(aData)
|
||||
, mLength(aLength)
|
||||
, mMimeType(aMimeType)
|
||||
{ }
|
||||
|
||||
void
|
||||
RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
|
||||
{
|
||||
nsCOMPtr<nsIDOMBlob> picture = new nsDOMMemoryFile(static_cast<void*>(mData),
|
||||
static_cast<uint64_t>(mLength),
|
||||
mMimeType);
|
||||
aDOMCameraControl->OnTakePictureComplete(picture);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t* mData;
|
||||
uint32_t mLength;
|
||||
nsString mMimeType;
|
||||
};
|
||||
|
||||
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aData, aLength, aMimeType));
|
||||
}
|
||||
|
||||
void
|
||||
DOMCameraControlListener::OnError(CameraErrorContext aContext, CameraError aError)
|
||||
{
|
||||
class Callback : public DOMCallback
|
||||
{
|
||||
public:
|
||||
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
|
||||
CameraErrorContext aContext,
|
||||
CameraError aError)
|
||||
: DOMCallback(aDOMCameraControl)
|
||||
, mContext(aContext)
|
||||
, mError(aError)
|
||||
{ }
|
||||
|
||||
void
|
||||
RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
|
||||
{
|
||||
nsString error;
|
||||
|
||||
switch (mError) {
|
||||
case kErrorServiceFailed:
|
||||
error = NS_LITERAL_STRING("ErrorServiceFailed");
|
||||
break;
|
||||
|
||||
case kErrorApiFailed:
|
||||
// XXXmikeh legacy error placeholder
|
||||
error = NS_LITERAL_STRING("FAILURE");
|
||||
break;
|
||||
|
||||
default:
|
||||
error = NS_LITERAL_STRING("ErrorUnknown");
|
||||
break;
|
||||
}
|
||||
aDOMCameraControl->OnError(mContext, error);
|
||||
}
|
||||
|
||||
protected:
|
||||
CameraErrorContext mContext;
|
||||
CameraError mError;
|
||||
};
|
||||
|
||||
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aContext, aError));
|
||||
}
|
48
dom/camera/DOMCameraControlListener.h
Normal file
48
dom/camera/DOMCameraControlListener.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef DOM_CAMERA_DOMCAMERACONTROLLISTENER_H
|
||||
#define DOM_CAMERA_DOMCAMERACONTROLLISTENER_H
|
||||
|
||||
#include "nsProxyRelease.h"
|
||||
#include "CameraControlListener.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class nsDOMCameraControl;
|
||||
class CameraPreviewMediaStream;
|
||||
|
||||
class DOMCameraControlListener : public CameraControlListener
|
||||
{
|
||||
protected:
|
||||
nsMainThreadPtrHandle<nsDOMCameraControl> mDOMCameraControl;
|
||||
CameraPreviewMediaStream* mStream;
|
||||
|
||||
class DOMCallback;
|
||||
|
||||
public:
|
||||
DOMCameraControlListener(nsDOMCameraControl* aDOMCameraControl, CameraPreviewMediaStream* aStream)
|
||||
: mDOMCameraControl(new nsMainThreadPtrHolder<nsDOMCameraControl>(aDOMCameraControl))
|
||||
, mStream(aStream)
|
||||
{ }
|
||||
|
||||
void OnAutoFocusComplete(bool aAutoFocusSucceeded);
|
||||
void OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType);
|
||||
|
||||
void OnHardwareStateChange(HardwareState aState);
|
||||
void OnPreviewStateChange(PreviewState aState);
|
||||
void OnRecorderStateChange(RecorderState aState, int32_t aStatus, int32_t aTrackNum);
|
||||
void OnConfigurationChange(const CameraListenerConfiguration& aConfiguration);
|
||||
void OnShutter();
|
||||
bool OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight);
|
||||
void OnError(CameraErrorContext aContext, CameraError aError);
|
||||
|
||||
private:
|
||||
DOMCameraControlListener(const DOMCameraControlListener&) MOZ_DELETE;
|
||||
DOMCameraControlListener& operator=(const DOMCameraControlListener&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DOM_CAMERA_DOMCAMERACONTROLLISTENER_H
|
@ -2,16 +2,18 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DOMCameraManager.h"
|
||||
#include "nsDebug.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsObserverService.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "DOMCameraControl.h"
|
||||
#include "DOMCameraManager.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "DictionaryHelpers.h"
|
||||
#include "CameraCommon.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/CameraManagerBinding.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -22,6 +24,7 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMCameraManager, mWindow)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCameraManager)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
@ -38,37 +41,35 @@ PRLogModuleInfo*
|
||||
GetCameraLog()
|
||||
{
|
||||
static PRLogModuleInfo *sLog;
|
||||
if (!sLog)
|
||||
if (!sLog) {
|
||||
sLog = PR_NewLogModule("Camera");
|
||||
}
|
||||
return sLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* nsDOMCameraManager::GetListOfCameras
|
||||
* is implementation-specific, and can be found in (e.g.)
|
||||
* GonkCameraManager.cpp and FallbackCameraManager.cpp.
|
||||
*/
|
||||
|
||||
WindowTable* nsDOMCameraManager::sActiveWindows = nullptr;
|
||||
|
||||
nsDOMCameraManager::nsDOMCameraManager(nsPIDOMWindow* aWindow)
|
||||
: mWindowId(aWindow->WindowID())
|
||||
, mCameraThread(nullptr)
|
||||
, mWindow(aWindow)
|
||||
{
|
||||
/* member initializers and constructor code */
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p, windowId=%llx\n", __func__, __LINE__, this, mWindowId);
|
||||
MOZ_COUNT_CTOR(nsDOMCameraManager);
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
nsDOMCameraManager::~nsDOMCameraManager()
|
||||
{
|
||||
/* destructor code */
|
||||
MOZ_COUNT_DTOR(nsDOMCameraManager);
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->RemoveObserver(this, "xpcom-shutdown");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMCameraManager::GetListOfCameras(nsTArray<nsString>& aList, ErrorResult& aRv)
|
||||
{
|
||||
aRv = ICameraControl::GetListOfCameras(aList);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -106,30 +107,28 @@ nsDOMCameraManager::CreateInstance(nsPIDOMWindow* aWindow)
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMCameraManager::GetCamera(const CameraSelector& aOptions,
|
||||
nsICameraGetCameraCallback* onSuccess,
|
||||
const Optional<nsICameraErrorCallback*>& onError,
|
||||
nsDOMCameraManager::GetCamera(const nsAString& aCamera,
|
||||
const CameraConfiguration& aInitialConfig,
|
||||
GetCameraCallback& aOnSuccess,
|
||||
const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
uint32_t cameraId = 0; // back (or forward-facing) camera by default
|
||||
if (aOptions.mCamera.EqualsLiteral("front")) {
|
||||
if (aCamera.EqualsLiteral("front")) {
|
||||
cameraId = 1;
|
||||
}
|
||||
|
||||
// reuse the same camera thread to conserve resources
|
||||
if (!mCameraThread) {
|
||||
aRv = NS_NewThread(getter_AddRefs(mCameraThread));
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<CameraErrorCallback> errorCallback = nullptr;
|
||||
if (aOnError.WasPassed()) {
|
||||
errorCallback = &aOnError.Value();
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
// Creating this object will trigger the onSuccess handler
|
||||
// Creating this object will trigger the aOnSuccess callback
|
||||
// (or the aOnError one, if it fails).
|
||||
nsRefPtr<nsDOMCameraControl> cameraControl =
|
||||
new nsDOMCameraControl(cameraId, mCameraThread,
|
||||
onSuccess, onError.WasPassed() ? onError.Value() : nullptr, mWindow);
|
||||
new nsDOMCameraControl(cameraId, aInitialConfig, &aOnSuccess, errorCallback, mWindow);
|
||||
|
||||
Register(cameraControl);
|
||||
}
|
||||
|
@ -10,24 +10,24 @@
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsIDOMCameraManager.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
class ErrorResult;
|
||||
class nsDOMCameraControl;
|
||||
namespace dom {
|
||||
class CameraSelector;
|
||||
}
|
||||
class nsDOMCameraControl;
|
||||
namespace dom {
|
||||
class CameraConfiguration;
|
||||
class GetCameraCallback;
|
||||
class CameraErrorCallback;
|
||||
}
|
||||
}
|
||||
|
||||
typedef nsTArray<nsRefPtr<mozilla::nsDOMCameraControl> > CameraControls;
|
||||
@ -52,13 +52,11 @@ public:
|
||||
void Register(mozilla::nsDOMCameraControl* aDOMCameraControl);
|
||||
void OnNavigation(uint64_t aWindowId);
|
||||
|
||||
nsresult GetNumberOfCameras(int32_t& aDeviceCount);
|
||||
nsresult GetCameraName(uint32_t aDeviceNum, nsCString& aDeviceName);
|
||||
|
||||
// WebIDL
|
||||
void GetCamera(const mozilla::dom::CameraSelector& aOptions,
|
||||
nsICameraGetCameraCallback* aCallback,
|
||||
const mozilla::dom::Optional<nsICameraErrorCallback*>& ErrorCallback,
|
||||
void GetCamera(const nsAString& aCamera,
|
||||
const mozilla::dom::CameraConfiguration& aOptions,
|
||||
mozilla::dom::GetCameraCallback& aOnSuccess,
|
||||
const mozilla::dom::Optional<mozilla::dom::OwningNonNull<mozilla::dom::CameraErrorCallback> >& aOnError,
|
||||
mozilla::ErrorResult& aRv);
|
||||
void GetListOfCameras(nsTArray<nsString>& aList, mozilla::ErrorResult& aRv);
|
||||
|
||||
@ -79,32 +77,12 @@ private:
|
||||
|
||||
protected:
|
||||
uint64_t mWindowId;
|
||||
nsCOMPtr<nsIThread> mCameraThread;
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
/**
|
||||
* 'mActiveWindows' is only ever accessed while in the main thread,
|
||||
* 'sActiveWindows' is only ever accessed while in the Main Thread,
|
||||
* so it is not otherwise protected.
|
||||
*/
|
||||
static ::WindowTable* sActiveWindows;
|
||||
};
|
||||
|
||||
class GetCameraTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
GetCameraTask(uint32_t aCameraId, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, nsIThread* aCameraThread)
|
||||
: mCameraId(aCameraId)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
, mOnErrorCb(onError)
|
||||
, mCameraThread(aCameraThread)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
uint32_t mCameraId;
|
||||
nsCOMPtr<nsICameraGetCameraCallback> mOnSuccessCb;
|
||||
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
|
||||
nsCOMPtr<nsIThread> mCameraThread;
|
||||
};
|
||||
|
||||
#endif // DOM_CAMERA_DOMCAMERAMANAGER_H
|
||||
|
@ -1,304 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "Layers.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "DOMCameraPreview.h"
|
||||
#include "CameraCommon.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::layers;
|
||||
|
||||
/**
|
||||
* 'PreviewControl' is a helper class that dispatches preview control
|
||||
* events from the main thread.
|
||||
*
|
||||
* NS_NewRunnableMethod() can't be used because it AddRef()s the method's
|
||||
* object, which can't be done off the main thread for cycle collection
|
||||
* participants.
|
||||
*
|
||||
* Before using this class, 'aDOMPreview' must be appropriately AddRef()ed.
|
||||
*/
|
||||
class PreviewControl : public nsRunnable
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
START,
|
||||
STOP,
|
||||
STARTED,
|
||||
STOPPED
|
||||
};
|
||||
PreviewControl(DOMCameraPreview* aDOMPreview, uint32_t aControl)
|
||||
: mDOMPreview(aDOMPreview)
|
||||
, mControl(aControl)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "PreviewControl not run on main thread");
|
||||
|
||||
switch (mControl) {
|
||||
case START:
|
||||
mDOMPreview->Start();
|
||||
break;
|
||||
|
||||
case STOP:
|
||||
mDOMPreview->StopPreview();
|
||||
break;
|
||||
|
||||
case STARTED:
|
||||
mDOMPreview->SetStateStarted();
|
||||
break;
|
||||
|
||||
case STOPPED:
|
||||
mDOMPreview->SetStateStopped();
|
||||
break;
|
||||
|
||||
default:
|
||||
DOM_CAMERA_LOGE("PreviewControl: invalid control %d\n", mControl);
|
||||
break;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* This must be a raw pointer because this class is not created on the
|
||||
* main thread, and DOMCameraPreview is not threadsafe. Prior to
|
||||
* issuing a preview control event, the caller must ensure that
|
||||
* mDOMPreview will not disappear.
|
||||
*/
|
||||
DOMCameraPreview* mDOMPreview;
|
||||
uint32_t mControl;
|
||||
};
|
||||
|
||||
class DOMCameraPreviewListener : public MediaStreamListener
|
||||
{
|
||||
public:
|
||||
DOMCameraPreviewListener(DOMCameraPreview* aDOMPreview) :
|
||||
mDOMPreview(aDOMPreview)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
~DOMCameraPreviewListener()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
void NotifyConsumptionChanged(MediaStreamGraph* aGraph, Consumption aConsuming)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
const char* state;
|
||||
|
||||
switch (aConsuming) {
|
||||
case NOT_CONSUMED:
|
||||
state = "not consuming";
|
||||
break;
|
||||
|
||||
case CONSUMED:
|
||||
state = "consuming";
|
||||
break;
|
||||
|
||||
default:
|
||||
state = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGA("camera viewfinder is %s\n", state);
|
||||
#endif
|
||||
nsCOMPtr<nsIRunnable> previewControl;
|
||||
|
||||
switch (aConsuming) {
|
||||
case NOT_CONSUMED:
|
||||
previewControl = new PreviewControl(mDOMPreview, PreviewControl::STOP);
|
||||
break;
|
||||
|
||||
case CONSUMED:
|
||||
previewControl = new PreviewControl(mDOMPreview, PreviewControl::START);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = NS_DispatchToMainThread(previewControl);
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGE("Failed to dispatch preview control (%d)!\n", rv);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// Raw pointer; if we exist, 'mDOMPreview' exists as well
|
||||
DOMCameraPreview* mDOMPreview;
|
||||
};
|
||||
|
||||
DOMCameraPreview::DOMCameraPreview(nsGlobalWindow* aWindow,
|
||||
ICameraControl* aCameraControl,
|
||||
uint32_t aWidth, uint32_t aHeight,
|
||||
uint32_t aFrameRate)
|
||||
: DOMMediaStream()
|
||||
, mState(STOPPED)
|
||||
, mWidth(aWidth)
|
||||
, mHeight(aHeight)
|
||||
, mFramesPerSecond(aFrameRate)
|
||||
, mFrameCount(0)
|
||||
, mCameraControl(aCameraControl)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p : mWidth=%d, mHeight=%d, mFramesPerSecond=%d\n", __func__, __LINE__, this, mWidth, mHeight, mFramesPerSecond);
|
||||
|
||||
mImageContainer = LayerManager::CreateImageContainer();
|
||||
mWindow = aWindow;
|
||||
mInput = new CameraPreviewMediaStream(this);
|
||||
mStream = mInput;
|
||||
|
||||
mListener = new DOMCameraPreviewListener(this);
|
||||
mInput->AddListener(mListener);
|
||||
|
||||
if (aWindow->GetExtantDoc()) {
|
||||
CombineWithPrincipal(aWindow->GetExtantDoc()->NodePrincipal());
|
||||
}
|
||||
}
|
||||
|
||||
DOMCameraPreview::~DOMCameraPreview()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p, mListener=%p\n", __func__, __LINE__, this, mListener);
|
||||
mInput->RemoveListener(mListener);
|
||||
}
|
||||
|
||||
bool
|
||||
DOMCameraPreview::HaveEnoughBuffered()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DOMCameraPreview::ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
if (!aBuffer || !aBuilder) {
|
||||
return false;
|
||||
}
|
||||
if (mState != STARTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<Image> image = mImageContainer->CreateImage(aFormat);
|
||||
aBuilder(image, aBuffer, mWidth, mHeight);
|
||||
|
||||
mInput->SetCurrentFrame(gfxIntSize(mWidth, mHeight), image);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DOMCameraPreview::Start()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Start() not called from main thread");
|
||||
if (mState != STOPPED) {
|
||||
return;
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGI("Starting preview stream\n");
|
||||
|
||||
/**
|
||||
* Add a reference to ourselves to make sure we stay alive while
|
||||
* the preview is running, as the CameraControlImpl object holds a
|
||||
* weak reference to us.
|
||||
*
|
||||
* This reference is removed in SetStateStopped().
|
||||
*/
|
||||
NS_ADDREF_THIS();
|
||||
DOM_CAMERA_SETSTATE(STARTING);
|
||||
mCameraControl->StartPreview(this);
|
||||
}
|
||||
|
||||
void
|
||||
DOMCameraPreview::SetStateStarted()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "SetStateStarted() not called from main thread");
|
||||
|
||||
DOM_CAMERA_SETSTATE(STARTED);
|
||||
DOM_CAMERA_LOGI("Preview stream started\n");
|
||||
}
|
||||
|
||||
void
|
||||
DOMCameraPreview::Started()
|
||||
{
|
||||
if (mState != STARTING) {
|
||||
return;
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGI("Dispatching preview stream started\n");
|
||||
nsCOMPtr<nsIRunnable> started = new PreviewControl(this, PreviewControl::STARTED);
|
||||
nsresult rv = NS_DispatchToMainThread(started);
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGE("failed to set statrted state (%d), POTENTIAL MEMORY LEAK!\n", rv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DOMCameraPreview::StopPreview()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "StopPreview() not called from main thread");
|
||||
if (mState != STARTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGI("Stopping preview stream\n");
|
||||
DOM_CAMERA_SETSTATE(STOPPING);
|
||||
mCameraControl->StopPreview();
|
||||
//mInput->EndTrack(TRACK_VIDEO);
|
||||
//mInput->Finish();
|
||||
}
|
||||
|
||||
void
|
||||
DOMCameraPreview::SetStateStopped()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "SetStateStopped() not called from main thread");
|
||||
|
||||
// see bug 809259 and bug 817367.
|
||||
if (mState != STOPPING) {
|
||||
//mInput->EndTrack(TRACK_VIDEO);
|
||||
//mInput->Finish();
|
||||
}
|
||||
DOM_CAMERA_SETSTATE(STOPPED);
|
||||
DOM_CAMERA_LOGI("Preview stream stopped\n");
|
||||
|
||||
/**
|
||||
* Only remove the reference added in Start() once the preview
|
||||
* has stopped completely.
|
||||
*/
|
||||
NS_RELEASE_THIS();
|
||||
}
|
||||
|
||||
void
|
||||
DOMCameraPreview::Stopped(bool aForced)
|
||||
{
|
||||
if (mState != STOPPING && !aForced) {
|
||||
return;
|
||||
}
|
||||
|
||||
mInput->ClearCurrentFrame();
|
||||
|
||||
DOM_CAMERA_LOGI("Dispatching preview stream stopped\n");
|
||||
nsCOMPtr<nsIRunnable> stopped = new PreviewControl(this, PreviewControl::STOPPED);
|
||||
nsresult rv = NS_DispatchToMainThread(stopped);
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGE("failed to decrement reference count (%d), MEMORY LEAK!\n", rv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DOMCameraPreview::Error()
|
||||
{
|
||||
DOM_CAMERA_LOGE("Error occurred changing preview state!\n");
|
||||
Stopped(true);
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef DOM_CAMERA_DOMCAMERAPREVIEW_H
|
||||
#define DOM_CAMERA_DOMCAMERAPREVIEW_H
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "ICameraControl.h"
|
||||
#include "DOMMediaStream.h"
|
||||
#include "CameraPreviewMediaStream.h"
|
||||
#include "CameraCommon.h"
|
||||
|
||||
class nsGlobalWindow;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
typedef void (*FrameBuilder)(mozilla::layers::Image* aImage, void* aBuffer, uint32_t aWidth, uint32_t aHeight);
|
||||
|
||||
/**
|
||||
* DOMCameraPreview is only exposed to the DOM as an nsDOMMediaStream,
|
||||
* which is a cycle-collection participant already, and we don't
|
||||
* add any traceable fields here, so we don't need to declare any
|
||||
* more cycle-collection goop.
|
||||
*/
|
||||
class DOMCameraPreview : public DOMMediaStream
|
||||
{
|
||||
protected:
|
||||
enum { TRACK_VIDEO = 1 };
|
||||
|
||||
public:
|
||||
DOMCameraPreview(nsGlobalWindow* aWindow, ICameraControl* aCameraControl,
|
||||
uint32_t aWidth, uint32_t aHeight, uint32_t aFramesPerSecond = 30);
|
||||
|
||||
bool ReceiveFrame(void* aBuffer, ImageFormat aFormat, mozilla::FrameBuilder aBuilder);
|
||||
bool HaveEnoughBuffered();
|
||||
|
||||
void Start(); // called by the MediaStreamListener to start preview
|
||||
void Started(); // called by the CameraControl when preview is started
|
||||
void StopPreview(); // called by the MediaStreamListener to stop preview
|
||||
void Stopped(bool aForced = false);
|
||||
// called by the CameraControl when preview is stopped
|
||||
void Error(); // something went wrong, NS_RELEASE needed
|
||||
|
||||
void SetStateStarted();
|
||||
void SetStateStopped();
|
||||
|
||||
protected:
|
||||
virtual ~DOMCameraPreview();
|
||||
|
||||
enum {
|
||||
STOPPED,
|
||||
STARTING,
|
||||
STARTED,
|
||||
STOPPING
|
||||
};
|
||||
uint32_t mState;
|
||||
|
||||
// Helper function, used in conjunction with the macro below, to make
|
||||
// it easy to track state changes, which must happen only on the main
|
||||
// thread.
|
||||
void
|
||||
SetState(uint32_t aNewState, const char* aFileOrFunc, int aLine)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
const char* states[] = { "stopped", "starting", "started", "stopping" };
|
||||
MOZ_ASSERT(mState < sizeof(states) / sizeof(states[0]));
|
||||
MOZ_ASSERT(aNewState < sizeof(states) / sizeof(states[0]));
|
||||
DOM_CAMERA_LOGI("SetState: (this=%p) '%s' --> '%s' : %s:%d\n", this, states[mState], states[aNewState], aFileOrFunc, aLine);
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(NS_IsMainThread(), "Preview state set OFF OF main thread!");
|
||||
mState = aNewState;
|
||||
}
|
||||
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
uint32_t mFramesPerSecond;
|
||||
CameraPreviewMediaStream* mInput;
|
||||
nsRefPtr<mozilla::layers::ImageContainer> mImageContainer;
|
||||
VideoSegment mVideoSegment;
|
||||
uint32_t mFrameCount;
|
||||
nsRefPtr<ICameraControl> mCameraControl;
|
||||
|
||||
// Raw pointer; AddListener() keeps the reference for us
|
||||
MediaStreamListener* mListener;
|
||||
|
||||
private:
|
||||
DOMCameraPreview(const DOMCameraPreview&) MOZ_DELETE;
|
||||
DOMCameraPreview& operator=(const DOMCameraPreview&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#define DOM_CAMERA_SETSTATE(newState) SetState((newState), __func__, __LINE__)
|
||||
|
||||
#endif // DOM_CAMERA_DOMCAMERAPREVIEW_H
|
@ -2,9 +2,8 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsDOMClassInfoID.h"
|
||||
#include "DOMCameraControl.h"
|
||||
#include "DOMCameraCapabilities.h"
|
||||
#include "DOMCameraControl.h"
|
||||
#include "CameraCommon.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -2,215 +2,74 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DOMCameraControl.h"
|
||||
#include "CameraControlImpl.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
namespace mozilla {
|
||||
class RecorderProfileManager;
|
||||
class RecorderProfileManager;
|
||||
|
||||
namespace layers {
|
||||
class GraphicBufferLocked;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallback camera control subclass. Can be used as a template for the
|
||||
* Fallback camera control subclass. Can be used as a template for the
|
||||
* definition of new camera support classes.
|
||||
*/
|
||||
class nsFallbackCameraControl : public CameraControlImpl
|
||||
class FallbackCameraControl : public CameraControlImpl
|
||||
{
|
||||
public:
|
||||
nsFallbackCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsDOMCameraControl* aDOMCameraControl, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, uint64_t aWindowId);
|
||||
FallbackCameraControl(uint32_t aCameraId) : CameraControlImpl(aCameraId) { }
|
||||
|
||||
const char* GetParameter(const char* aKey);
|
||||
const char* GetParameterConstChar(uint32_t aKey);
|
||||
double GetParameterDouble(uint32_t aKey);
|
||||
int32_t GetParameterInt32(uint32_t aKey);
|
||||
void GetParameter(uint32_t aKey, nsTArray<idl::CameraRegion>& aRegions);
|
||||
void GetParameter(uint32_t aKey, idl::CameraSize& aSize);
|
||||
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<idl::CameraRegion>& aRegions);
|
||||
void SetParameter(uint32_t aKey, const idl::CameraSize& aSize);
|
||||
nsresult GetVideoSizes(nsTArray<idl::CameraSize>& aVideoSizes);
|
||||
nsresult PushParameters();
|
||||
void OnAutoFocusComplete(bool aSuccess);
|
||||
void OnTakePictureComplete(uint8_t* aData, uint32_t aLength) { }
|
||||
void OnTakePictureError() { }
|
||||
void OnNewPreviewFrame(layers::GraphicBufferLocked* aBuffer) { }
|
||||
void OnRecorderEvent(int msg, int ext1, int ext2) { }
|
||||
void OnError(CameraControlListener::CameraErrorContext aWhere,
|
||||
CameraControlListener::CameraError aError) { }
|
||||
|
||||
virtual nsresult Set(uint32_t aKey, const nsAString& aValue) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult Get(uint32_t aKey, nsAString& aValue) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult Set(uint32_t aKey, double aValue) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult Get(uint32_t aKey, double& aValue) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult Set(uint32_t aKey, int32_t aValue) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult Get(uint32_t aKey, int32_t& aValue) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult Set(uint32_t aKey, int64_t aValue) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult Get(uint32_t aKey, int64_t& aValue) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult Set(uint32_t aKey, const Size& aValue) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult Get(uint32_t aKey, Size& aValue) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult Set(uint32_t aKey, const nsTArray<Region>& aRegions) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult Get(uint32_t aKey, nsTArray<Region>& aRegions) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
|
||||
virtual nsresult SetLocation(const Position& aLocation) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
|
||||
virtual nsresult Get(uint32_t aKey, nsTArray<Size>& aSizes) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult Get(uint32_t aKey, nsTArray<nsString>& aValues) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult Get(uint32_t aKey, nsTArray<double>& aValues) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
|
||||
|
||||
nsresult PushParameters() { return NS_ERROR_FAILURE; }
|
||||
nsresult PullParameters() { return NS_ERROR_FAILURE; }
|
||||
|
||||
protected:
|
||||
~nsFallbackCameraControl();
|
||||
~FallbackCameraControl();
|
||||
|
||||
nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream);
|
||||
nsresult StartPreviewImpl(StartPreviewTask* aStartPreview);
|
||||
nsresult StopPreviewImpl(StopPreviewTask* aStopPreview);
|
||||
nsresult AutoFocusImpl(AutoFocusTask* aAutoFocus);
|
||||
nsresult TakePictureImpl(TakePictureTask* aTakePicture);
|
||||
nsresult StartRecordingImpl(StartRecordingTask* aStartRecording);
|
||||
nsresult StopRecordingImpl(StopRecordingTask* aStopRecording);
|
||||
nsresult PushParametersImpl();
|
||||
nsresult PullParametersImpl();
|
||||
already_AddRefed<RecorderProfileManager> GetRecorderProfileManagerImpl();
|
||||
virtual nsresult StartPreviewImpl() { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult StopPreviewImpl() { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult AutoFocusImpl(bool aCancelExistingCall) { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult TakePictureImpl() { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescriptor,
|
||||
const StartRecordingOptions* aOptions = nullptr)
|
||||
{ return NS_ERROR_FAILURE; }
|
||||
virtual nsresult StopRecordingImpl() { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult PushParametersImpl() { return NS_ERROR_FAILURE; }
|
||||
virtual nsresult PullParametersImpl() { return NS_ERROR_FAILURE; }
|
||||
virtual already_AddRefed<RecorderProfileManager> GetRecorderProfileManagerImpl() { return nullptr; }
|
||||
|
||||
private:
|
||||
nsFallbackCameraControl(const nsFallbackCameraControl&) MOZ_DELETE;
|
||||
nsFallbackCameraControl& operator=(const nsFallbackCameraControl&) MOZ_DELETE;
|
||||
FallbackCameraControl(const FallbackCameraControl&) MOZ_DELETE;
|
||||
FallbackCameraControl& operator=(const FallbackCameraControl&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stub implementation of the DOM-facing camera control constructor.
|
||||
*
|
||||
* This should never get called--it exists to keep the linker happy; if
|
||||
* implemented, it should construct (e.g.) nsFallbackCameraControl and
|
||||
* store a reference in the 'mCameraControl' member (which is why it is
|
||||
* defined here).
|
||||
*/
|
||||
nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, nsPIDOMWindow* aWindow) :
|
||||
mWindow(aWindow)
|
||||
{
|
||||
MOZ_ASSERT(aWindow, "shouldn't be created with null window!");
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stub implemetations of the fallback camera control.
|
||||
*
|
||||
* None of these should ever get called--they exist to keep the linker happy,
|
||||
* and may be used as templates for new camera support classes.
|
||||
*/
|
||||
nsFallbackCameraControl::nsFallbackCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsDOMCameraControl* aDOMCameraControl, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, uint64_t aWindowId)
|
||||
: CameraControlImpl(aCameraId, aCameraThread, aWindowId)
|
||||
{
|
||||
}
|
||||
|
||||
nsFallbackCameraControl::~nsFallbackCameraControl()
|
||||
{
|
||||
}
|
||||
|
||||
const char*
|
||||
nsFallbackCameraControl::GetParameter(const char* aKey)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char*
|
||||
nsFallbackCameraControl::GetParameterConstChar(uint32_t aKey)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
double
|
||||
nsFallbackCameraControl::GetParameterDouble(uint32_t aKey)
|
||||
{
|
||||
return NAN;
|
||||
}
|
||||
|
||||
int32_t
|
||||
nsFallbackCameraControl::GetParameterInt32(uint32_t aKey)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nsFallbackCameraControl::GetParameter(uint32_t aKey, nsTArray<idl::CameraRegion>& aRegions)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsFallbackCameraControl::GetParameter(uint32_t aKey, idl::CameraSize& aSize)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsFallbackCameraControl::SetParameter(const char* aKey, const char* aValue)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsFallbackCameraControl::SetParameter(uint32_t aKey, const char* aValue)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsFallbackCameraControl::SetParameter(uint32_t aKey, double aValue)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsFallbackCameraControl::SetParameter(uint32_t aKey, const nsTArray<idl::CameraRegion>& aRegions)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsFallbackCameraControl::SetParameter(uint32_t aKey, const idl::CameraSize& aSize)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFallbackCameraControl::PushParameters()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFallbackCameraControl::GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFallbackCameraControl::StartPreviewImpl(StartPreviewTask* aGetPreviewStream)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFallbackCameraControl::StopPreviewImpl(StopPreviewTask* aGetPreviewStream)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFallbackCameraControl::AutoFocusImpl(AutoFocusTask* aAutoFocus)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFallbackCameraControl::TakePictureImpl(TakePictureTask* aTakePicture)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFallbackCameraControl::StartRecordingImpl(StartRecordingTask* aStartRecording)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFallbackCameraControl::StopRecordingImpl(StopRecordingTask* aStopRecording)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFallbackCameraControl::PushParametersImpl()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFallbackCameraControl::PullParametersImpl()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFallbackCameraControl::GetVideoSizes(nsTArray<idl::CameraSize>& aVideoSizes)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
already_AddRefed<RecorderProfileManager>
|
||||
nsFallbackCameraControl::GetRecorderProfileManagerImpl()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -2,27 +2,31 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DOMCameraManager.h"
|
||||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "ICameraControl.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
// From nsDOMCameraManager.
|
||||
// From ICameraControl.
|
||||
nsresult
|
||||
nsDOMCameraManager::GetNumberOfCameras(int32_t& aDeviceCount)
|
||||
ICameraControl::GetNumberOfCameras(int32_t& aDeviceCount)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
nsresult
|
||||
nsDOMCameraManager::GetCameraName(uint32_t aDeviceNum, nsCString& aDeviceName)
|
||||
ICameraControl::GetCameraName(uint32_t aDeviceNum, nsCString& aDeviceName)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMCameraManager::GetListOfCameras(nsTArray<nsString>& aList, ErrorResult& aRv)
|
||||
nsresult
|
||||
ICameraControl::GetListOfCameras(nsTArray<nsString>& aList)
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
already_AddRefed<ICameraControl>
|
||||
ICameraControl::Create(uint32_t aCameraId, const Configuration* aInitialConfig)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Mozilla Foundation
|
||||
* Copyright (C) 2012-2013 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -18,26 +18,26 @@
|
||||
#define DOM_CAMERA_GONKCAMERACONTROL_H
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "prrwlock.h"
|
||||
#include <media/MediaProfiles.h>
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "DeviceStorage.h"
|
||||
#include "nsIDOMCameraManager.h"
|
||||
#include "DOMCameraControl.h"
|
||||
#include "CameraControlImpl.h"
|
||||
#include "CameraCommon.h"
|
||||
#include "GonkRecorder.h"
|
||||
#include "GonkCameraHwMgr.h"
|
||||
#include "GonkCameraParameters.h"
|
||||
|
||||
namespace android {
|
||||
class GonkCameraHardware;
|
||||
class MediaProfiles;
|
||||
class GonkRecorder;
|
||||
class GonkCameraHardware;
|
||||
class MediaProfiles;
|
||||
class GonkRecorder;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace layers {
|
||||
class GraphicBufferLocked;
|
||||
class GraphicBufferLocked;
|
||||
class ImageContainer;
|
||||
}
|
||||
|
||||
class GonkRecorderProfile;
|
||||
@ -46,89 +46,111 @@ class GonkRecorderProfileManager;
|
||||
class nsGonkCameraControl : public CameraControlImpl
|
||||
{
|
||||
public:
|
||||
nsGonkCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsDOMCameraControl* aDOMCameraControl, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, uint64_t aWindowId);
|
||||
void DispatchInit(nsDOMCameraControl* aDOMCameraControl, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, uint64_t aWindowId);
|
||||
nsresult Init();
|
||||
nsGonkCameraControl(uint32_t aCameraId);
|
||||
nsresult Init(const Configuration* aInitialConfig);
|
||||
nsresult InitImpl();
|
||||
|
||||
void OnAutoFocusComplete(bool aSuccess);
|
||||
void OnTakePictureComplete(uint8_t* aData, uint32_t aLength);
|
||||
void OnTakePictureError();
|
||||
void OnNewPreviewFrame(layers::GraphicBufferLocked* aBuffer);
|
||||
void OnRecorderEvent(int msg, int ext1, int ext2);
|
||||
void OnError(CameraControlListener::CameraErrorContext aWhere,
|
||||
CameraControlListener::CameraError aError);
|
||||
|
||||
virtual nsresult Set(uint32_t aKey, const nsAString& aValue) MOZ_OVERRIDE;
|
||||
virtual nsresult Get(uint32_t aKey, nsAString& aValue) MOZ_OVERRIDE;
|
||||
virtual nsresult Set(uint32_t aKey, double aValue) MOZ_OVERRIDE;
|
||||
virtual nsresult Get(uint32_t aKey, double& aValue) MOZ_OVERRIDE;
|
||||
virtual nsresult Set(uint32_t aKey, int32_t aValue) MOZ_OVERRIDE;
|
||||
virtual nsresult Get(uint32_t aKey, int32_t& aValue) MOZ_OVERRIDE;
|
||||
virtual nsresult Set(uint32_t aKey, int64_t aValue) MOZ_OVERRIDE;
|
||||
virtual nsresult Get(uint32_t aKey, int64_t& aValue) MOZ_OVERRIDE;
|
||||
virtual nsresult Set(uint32_t aKey, const Size& aValue) MOZ_OVERRIDE;
|
||||
virtual nsresult Get(uint32_t aKey, Size& aValue) MOZ_OVERRIDE;
|
||||
virtual nsresult Set(uint32_t aKey, const nsTArray<Region>& aRegions) MOZ_OVERRIDE;
|
||||
virtual nsresult Get(uint32_t aKey, nsTArray<Region>& aRegions) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult SetLocation(const Position& aLocation) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Get(uint32_t aKey, nsTArray<Size>& aSizes) MOZ_OVERRIDE;
|
||||
virtual nsresult Get(uint32_t aKey, nsTArray<nsString>& aValues) MOZ_OVERRIDE;
|
||||
virtual nsresult Get(uint32_t aKey, nsTArray<double>& aValues) MOZ_OVERRIDE;
|
||||
|
||||
const char* GetParameter(const char* aKey);
|
||||
const char* GetParameterConstChar(uint32_t aKey);
|
||||
double GetParameterDouble(uint32_t aKey);
|
||||
int32_t GetParameterInt32(uint32_t aKey);
|
||||
void GetParameter(uint32_t aKey, nsTArray<idl::CameraRegion>& aRegions);
|
||||
void GetParameter(uint32_t aKey, nsTArray<idl::CameraSize>& aSizes);
|
||||
void GetParameter(uint32_t aKey, idl::CameraSize& aSize);
|
||||
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<idl::CameraRegion>& aRegions);
|
||||
void SetParameter(uint32_t aKey, int aValue);
|
||||
void SetParameter(uint32_t aKey, const idl::CameraSize& aSize);
|
||||
nsresult GetVideoSizes(nsTArray<idl::CameraSize>& aVideoSizes);
|
||||
nsresult PushParameters();
|
||||
|
||||
void AutoFocusComplete(bool aSuccess);
|
||||
void TakePictureComplete(uint8_t* aData, uint32_t aLength);
|
||||
void TakePictureError();
|
||||
void HandleRecorderEvent(int msg, int ext1, int ext2);
|
||||
nsresult PullParameters();
|
||||
|
||||
protected:
|
||||
~nsGonkCameraControl();
|
||||
|
||||
nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream);
|
||||
nsresult StartPreviewImpl(StartPreviewTask* aStartPreview);
|
||||
nsresult StopPreviewImpl(StopPreviewTask* aStopPreview);
|
||||
nsresult StopPreviewInternal(bool aForced = false);
|
||||
nsresult AutoFocusImpl(AutoFocusTask* aAutoFocus);
|
||||
nsresult TakePictureImpl(TakePictureTask* aTakePicture);
|
||||
nsresult StartRecordingImpl(StartRecordingTask* aStartRecording);
|
||||
nsresult StopRecordingImpl(StopRecordingTask* aStopRecording);
|
||||
nsresult PushParametersImpl();
|
||||
nsresult PullParametersImpl();
|
||||
nsresult GetPreviewStreamVideoModeImpl(GetPreviewStreamVideoModeTask* aGetPreviewStreamVideoMode);
|
||||
nsresult ReleaseHardwareImpl(ReleaseHardwareTask* aReleaseHardware);
|
||||
already_AddRefed<RecorderProfileManager> GetRecorderProfileManagerImpl();
|
||||
using CameraControlImpl::OnNewPreviewFrame;
|
||||
using CameraControlImpl::OnAutoFocusComplete;
|
||||
using CameraControlImpl::OnTakePictureComplete;
|
||||
using CameraControlImpl::OnConfigurationChange;
|
||||
using CameraControlImpl::OnError;
|
||||
|
||||
virtual void BeginBatchParameterSet() MOZ_OVERRIDE;
|
||||
virtual void EndBatchParameterSet() MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult SetConfigurationImpl(const Configuration& aConfig) MOZ_OVERRIDE;
|
||||
nsresult SetConfigurationInternal(const Configuration& aConfig);
|
||||
nsresult SetPictureConfiguration(const Configuration& aConfig);
|
||||
nsresult SetVideoConfiguration(const Configuration& aConfig);
|
||||
|
||||
template<class T> nsresult SetAndPush(uint32_t aKey, const T& aValue);
|
||||
|
||||
virtual nsresult StartPreviewImpl() MOZ_OVERRIDE;
|
||||
virtual nsresult StopPreviewImpl() MOZ_OVERRIDE;
|
||||
virtual nsresult AutoFocusImpl(bool aCancelExistingCall) MOZ_OVERRIDE;
|
||||
virtual nsresult TakePictureImpl() MOZ_OVERRIDE;
|
||||
virtual nsresult StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescriptor,
|
||||
const StartRecordingOptions* aOptions = nullptr) MOZ_OVERRIDE;
|
||||
virtual nsresult StopRecordingImpl() MOZ_OVERRIDE;
|
||||
virtual nsresult PushParametersImpl() MOZ_OVERRIDE;
|
||||
virtual nsresult PullParametersImpl() MOZ_OVERRIDE;
|
||||
virtual nsresult ReleaseHardwareImpl() MOZ_OVERRIDE;
|
||||
virtual already_AddRefed<RecorderProfileManager> GetRecorderProfileManagerImpl() MOZ_OVERRIDE;
|
||||
already_AddRefed<GonkRecorderProfileManager> GetGonkRecorderProfileManager();
|
||||
|
||||
nsresult SetupRecording(int aFd, int aRotation, int64_t aMaxFileSizeBytes, int64_t aMaxVideoLengthMs);
|
||||
nsresult SetupVideoMode(const nsAString& aProfile);
|
||||
void SetPreviewSize(uint32_t aWidth, uint32_t aHeight);
|
||||
void SetThumbnailSize(uint32_t aWidth, uint32_t aHeight);
|
||||
void UpdateThumbnailSize();
|
||||
void SetPictureSize(uint32_t aWidth, uint32_t aHeight);
|
||||
nsresult SetPreviewSize(const Size& aSize);
|
||||
|
||||
friend class SetPictureSize;
|
||||
friend class SetThumbnailSize;
|
||||
nsresult SetPictureSize(const Size& aSize);
|
||||
nsresult SetPictureSizeImpl(const Size& aSize);
|
||||
nsresult SetThumbnailSize(const Size& aSize);
|
||||
nsresult UpdateThumbnailSize();
|
||||
nsresult SetThumbnailSizeImpl(const Size& aSize);
|
||||
|
||||
int32_t RationalizeRotation(int32_t aRotation);
|
||||
|
||||
android::sp<android::GonkCameraHardware> mCameraHw;
|
||||
double mExposureCompensationMin;
|
||||
double mExposureCompensationStep;
|
||||
bool mDeferConfigUpdate;
|
||||
PRRWLock* mRwLock;
|
||||
android::CameraParameters mParams;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
uint32_t mLastPictureWidth;
|
||||
uint32_t mLastPictureHeight;
|
||||
uint32_t mLastThumbnailWidth;
|
||||
uint32_t mLastThumbnailHeight;
|
||||
|
||||
enum {
|
||||
PREVIEW_FORMAT_UNKNOWN,
|
||||
PREVIEW_FORMAT_YUV420P,
|
||||
PREVIEW_FORMAT_YUV420SP
|
||||
};
|
||||
uint32_t mFormat;
|
||||
Size mLastPictureSize;
|
||||
Size mLastThumbnailSize;
|
||||
Size mLastRecorderSize;
|
||||
uint32_t mPreviewFps;
|
||||
bool mResumePreviewAfterTakingPicture;
|
||||
|
||||
uint32_t mFps;
|
||||
uint32_t mDiscardedFrameCount;
|
||||
Atomic<uint32_t> mDeferConfigUpdate;
|
||||
GonkCameraParameters mParams;
|
||||
|
||||
nsRefPtr<mozilla::layers::ImageContainer> mImageContainer;
|
||||
|
||||
android::MediaProfiles* mMediaProfiles;
|
||||
nsRefPtr<android::GonkRecorder> mRecorder;
|
||||
|
||||
// camcorder profile settings for the desired quality level
|
||||
// Camcorder profile settings for the desired quality level
|
||||
nsRefPtr<GonkRecorderProfileManager> mProfileManager;
|
||||
nsRefPtr<GonkRecorderProfile> mRecorderProfile;
|
||||
|
||||
nsRefPtr<DeviceStorageFile> mVideoFile;
|
||||
nsString mFileFormat;
|
||||
|
||||
// Guards against calling StartPreviewImpl() while in OnTakePictureComplete().
|
||||
ReentrantMonitor mReentrantMonitor;
|
||||
|
||||
private:
|
||||
nsGonkCameraControl(const nsGonkCameraControl&) MOZ_DELETE;
|
||||
@ -136,12 +158,14 @@ private:
|
||||
};
|
||||
|
||||
// camera driver callbacks
|
||||
void ReceiveImage(nsGonkCameraControl* gc, uint8_t* aData, uint32_t aLength);
|
||||
void ReceiveImageError(nsGonkCameraControl* gc);
|
||||
void AutoFocusComplete(nsGonkCameraControl* gc, bool aSuccess);
|
||||
void ReceiveFrame(nsGonkCameraControl* gc, layers::GraphicBufferLocked* aBuffer);
|
||||
void OnTakePictureComplete(nsGonkCameraControl* gc, uint8_t* aData, uint32_t aLength);
|
||||
void OnTakePictureError(nsGonkCameraControl* gc);
|
||||
void OnAutoFocusComplete(nsGonkCameraControl* gc, bool aSuccess);
|
||||
void OnNewPreviewFrame(nsGonkCameraControl* gc, layers::GraphicBufferLocked* aBuffer);
|
||||
void OnShutter(nsGonkCameraControl* gc);
|
||||
void OnClosed(nsGonkCameraControl* gc);
|
||||
void OnError(nsGonkCameraControl* gc, CameraControlListener::CameraError aError,
|
||||
int32_t aArg1, int32_t aArg2);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Mozilla Foundation
|
||||
* Copyright (C) 2012-2013 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -14,13 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "GonkCameraHwMgr.h"
|
||||
|
||||
#include <binder/IPCThreadState.h>
|
||||
#include <sys/system_properties.h>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "nsDebug.h"
|
||||
#include "GonkCameraControl.h"
|
||||
#include "GonkCameraHwMgr.h"
|
||||
#include "GonkNativeWindow.h"
|
||||
#include "CameraCommon.h"
|
||||
|
||||
@ -28,39 +29,16 @@ using namespace mozilla;
|
||||
using namespace mozilla::layers;
|
||||
using namespace android;
|
||||
|
||||
#if GIHM_TIMING_RECEIVEFRAME
|
||||
#define INCLUDE_TIME_H 1
|
||||
#endif
|
||||
#if GIHM_TIMING_OVERALL
|
||||
#define INCLUDE_TIME_H 1
|
||||
#endif
|
||||
|
||||
#if INCLUDE_TIME_H
|
||||
#include <time.h>
|
||||
|
||||
static __inline void timespecSubtract(struct timespec* a, struct timespec* b)
|
||||
{
|
||||
// a = b - a
|
||||
if (b->tv_nsec < a->tv_nsec) {
|
||||
b->tv_nsec += 1000000000;
|
||||
b->tv_sec -= 1;
|
||||
}
|
||||
a->tv_nsec = b->tv_nsec - a->tv_nsec;
|
||||
a->tv_sec = b->tv_sec - a->tv_sec;
|
||||
}
|
||||
#endif
|
||||
|
||||
GonkCameraHardware::GonkCameraHardware(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId, const sp<Camera>& aCamera)
|
||||
: mCameraId(aCameraId)
|
||||
, mClosing(false)
|
||||
, mMonitor("GonkCameraHardware.Monitor")
|
||||
, mNumFrames(0)
|
||||
, mCamera(aCamera)
|
||||
, mTarget(aTarget)
|
||||
, mInitialized(false)
|
||||
, mSensorOrientation(0)
|
||||
{
|
||||
DOM_CAMERA_LOGT( "%s:%d : this=%p (aTarget=%p)\n", __func__, __LINE__, (void*)this, (void*)aTarget );
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p (aTarget=%p)\n", __func__, __LINE__, (void*)this, (void*)aTarget);
|
||||
Init();
|
||||
}
|
||||
|
||||
@ -75,7 +53,7 @@ GonkCameraHardware::OnNewFrame()
|
||||
DOM_CAMERA_LOGW("received null frame");
|
||||
return;
|
||||
}
|
||||
ReceiveFrame(mTarget, buffer);
|
||||
OnNewPreviewFrame(mTarget, buffer);
|
||||
}
|
||||
|
||||
// Android data callback
|
||||
@ -93,9 +71,9 @@ GonkCameraHardware::postData(int32_t aMsgType, const sp<IMemory>& aDataPtr, came
|
||||
|
||||
case CAMERA_MSG_COMPRESSED_IMAGE:
|
||||
if (aDataPtr != nullptr) {
|
||||
ReceiveImage(mTarget, (uint8_t*)aDataPtr->pointer(), aDataPtr->size());
|
||||
OnTakePictureComplete(mTarget, static_cast<uint8_t*>(aDataPtr->pointer()), aDataPtr->size());
|
||||
} else {
|
||||
ReceiveImageError(mTarget);
|
||||
OnTakePictureError(mTarget);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -109,27 +87,23 @@ GonkCameraHardware::postData(int32_t aMsgType, const sp<IMemory>& aDataPtr, came
|
||||
void
|
||||
GonkCameraHardware::notify(int32_t aMsgType, int32_t ext1, int32_t ext2)
|
||||
{
|
||||
bool bSuccess;
|
||||
if (mClosing) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aMsgType) {
|
||||
case CAMERA_MSG_FOCUS:
|
||||
if (ext1) {
|
||||
DOM_CAMERA_LOGI("Autofocus complete");
|
||||
bSuccess = true;
|
||||
} else {
|
||||
DOM_CAMERA_LOGW("Autofocus failed");
|
||||
bSuccess = false;
|
||||
}
|
||||
AutoFocusComplete(mTarget, bSuccess);
|
||||
OnAutoFocusComplete(mTarget, !!ext1);
|
||||
break;
|
||||
|
||||
case CAMERA_MSG_SHUTTER:
|
||||
OnShutter(mTarget);
|
||||
break;
|
||||
|
||||
case CAMERA_MSG_ERROR:
|
||||
OnError(mTarget, CameraControlListener::kErrorServiceFailed, ext1, ext2);
|
||||
break;
|
||||
|
||||
default:
|
||||
DOM_CAMERA_LOGE("Unhandled notify callback event %d\n", aMsgType);
|
||||
break;
|
||||
@ -295,6 +269,13 @@ GonkCameraHardware::CancelTakePicture()
|
||||
DOM_CAMERA_LOGW("%s: android::Camera do not provide this capability\n", __func__);
|
||||
}
|
||||
|
||||
int
|
||||
GonkCameraHardware::PushParameters(const GonkCameraParameters& aParams)
|
||||
{
|
||||
const String8 s = aParams.Flatten();
|
||||
return mCamera->setParameters(s);
|
||||
}
|
||||
|
||||
int
|
||||
GonkCameraHardware::PushParameters(const CameraParameters& aParams)
|
||||
{
|
||||
@ -302,6 +283,13 @@ GonkCameraHardware::PushParameters(const CameraParameters& aParams)
|
||||
return mCamera->setParameters(s);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkCameraHardware::PullParameters(GonkCameraParameters& aParams)
|
||||
{
|
||||
const String8 s = mCamera->getParameters();
|
||||
return aParams.Unflatten(s);
|
||||
}
|
||||
|
||||
void
|
||||
GonkCameraHardware::PullParameters(CameraParameters& aParams)
|
||||
{
|
||||
|
@ -27,15 +27,12 @@
|
||||
|
||||
#include "GonkCameraListener.h"
|
||||
#include "GonkNativeWindow.h"
|
||||
#include "GonkCameraParameters.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
|
||||
// config
|
||||
#define GIHM_TIMING_RECEIVEFRAME 0
|
||||
#define GIHM_TIMING_OVERALL 1
|
||||
|
||||
|
||||
namespace mozilla {
|
||||
class nsGonkCameraControl;
|
||||
class GonkCameraParameters;
|
||||
}
|
||||
|
||||
namespace android {
|
||||
@ -86,7 +83,9 @@ public:
|
||||
void CancelTakePicture();
|
||||
int StartPreview();
|
||||
void StopPreview();
|
||||
int PushParameters(const mozilla::GonkCameraParameters& aParams);
|
||||
int PushParameters(const CameraParameters& aParams);
|
||||
nsresult PullParameters(mozilla::GonkCameraParameters& aParams);
|
||||
void PullParameters(CameraParameters& aParams);
|
||||
int StartRecording();
|
||||
int StopRecording();
|
||||
@ -98,15 +97,10 @@ protected:
|
||||
|
||||
uint32_t mCameraId;
|
||||
bool mClosing;
|
||||
mozilla::ReentrantMonitor mMonitor;
|
||||
uint32_t mNumFrames;
|
||||
sp<Camera> mCamera;
|
||||
mozilla::nsGonkCameraControl* mTarget;
|
||||
sp<GonkNativeWindow> mNativeWindow;
|
||||
#if GIHM_TIMING_OVERALL
|
||||
struct timespec mStart;
|
||||
struct timespec mAutoFocusStart;
|
||||
#endif
|
||||
sp<GonkCameraListener> mListener;
|
||||
bool mInitialized;
|
||||
int mRawSensorOrientation;
|
||||
|
@ -16,35 +16,36 @@
|
||||
|
||||
#include <camera/Camera.h>
|
||||
|
||||
#include "GonkCameraControl.h"
|
||||
#include "DOMCameraManager.h"
|
||||
#include "CameraCommon.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "GonkCameraControl.h"
|
||||
#include "ICameraControl.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
// From nsDOMCameraManager, but gonk-specific!
|
||||
// From ICameraControl, gonk-specific management functions
|
||||
nsresult
|
||||
nsDOMCameraManager::GetNumberOfCameras(int32_t& aDeviceCount)
|
||||
ICameraControl::GetNumberOfCameras(int32_t& aDeviceCount)
|
||||
{
|
||||
aDeviceCount = android::Camera::getNumberOfCameras();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMCameraManager::GetCameraName(uint32_t aDeviceNum, nsCString& aDeviceName)
|
||||
ICameraControl::GetCameraName(uint32_t aDeviceNum, nsCString& aDeviceName)
|
||||
{
|
||||
int32_t count = android::Camera::getNumberOfCameras();
|
||||
int32_t deviceNum = static_cast<int32_t>(aDeviceNum);
|
||||
|
||||
DOM_CAMERA_LOGI("GetCameraName : getNumberOfCameras() returned %d\n", count);
|
||||
if (aDeviceNum > count) {
|
||||
DOM_CAMERA_LOGE("GetCameraName : invalid device number");
|
||||
if (deviceNum < 0 || deviceNum > count) {
|
||||
DOM_CAMERA_LOGE("GetCameraName : invalid device number (%u)\n", aDeviceNum);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
android::CameraInfo info;
|
||||
int rv = android::Camera::getCameraInfo(aDeviceNum, &info);
|
||||
int rv = android::Camera::getCameraInfo(deviceNum, &info);
|
||||
if (rv != 0) {
|
||||
DOM_CAMERA_LOGE("GetCameraName : get_camera_info(%d) failed: %d\n", aDeviceNum, rv);
|
||||
DOM_CAMERA_LOGE("GetCameraName : get_camera_info(%d) failed: %d\n", deviceNum, rv);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
@ -59,27 +60,27 @@ nsDOMCameraManager::GetCameraName(uint32_t aDeviceNum, nsCString& aDeviceName)
|
||||
|
||||
default:
|
||||
aDeviceName.Assign("extra-camera-");
|
||||
aDeviceName.AppendInt(aDeviceNum);
|
||||
aDeviceName.AppendInt(deviceNum);
|
||||
break;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMCameraManager::GetListOfCameras(nsTArray<nsString>& aList, ErrorResult& aRv)
|
||||
nsresult
|
||||
ICameraControl::GetListOfCameras(nsTArray<nsString>& aList)
|
||||
{
|
||||
int32_t count = android::Camera::getNumberOfCameras();
|
||||
if (count <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGI("getListOfCameras : getNumberOfCameras() returned %d\n", count);
|
||||
if (count <= 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Allocate 2 extra slots to reserve space for 'front' and 'back' cameras
|
||||
// at the front of the array--we will collapse any empty slots below.
|
||||
aList.SetLength(2);
|
||||
uint32_t extraIdx = 2;
|
||||
bool gotFront = false, gotBack = false;
|
||||
bool gotFront = false;
|
||||
bool gotBack = false;
|
||||
while (count--) {
|
||||
nsCString cameraName;
|
||||
nsresult result = GetCameraName(count, cameraName);
|
||||
@ -104,8 +105,28 @@ nsDOMCameraManager::GetListOfCameras(nsTArray<nsString>& aList, ErrorResult& aRv
|
||||
if (!gotFront) {
|
||||
aList.RemoveElementAt(1);
|
||||
}
|
||||
|
||||
|
||||
if (!gotBack) {
|
||||
aList.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// implementation-specific camera factory
|
||||
already_AddRefed<ICameraControl>
|
||||
ICameraControl::Create(uint32_t aCameraId, const Configuration* aInitialConfig)
|
||||
{
|
||||
if (aInitialConfig) {
|
||||
DOM_CAMERA_LOGI("Creating camera %d control, initial mode '%s'\n",
|
||||
aCameraId, aInitialConfig->mMode == kVideoMode ? "video" : "picture");
|
||||
} else {
|
||||
DOM_CAMERA_LOGI("Creating camera %d control, no intial configuration\n", aCameraId);
|
||||
}
|
||||
|
||||
nsRefPtr<nsGonkCameraControl> control = new nsGonkCameraControl(aCameraId);
|
||||
nsresult rv = control->Init(aInitialConfig);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
return control.forget();
|
||||
}
|
||||
|
620
dom/camera/GonkCameraParameters.cpp
Normal file
620
dom/camera/GonkCameraParameters.cpp
Normal file
@ -0,0 +1,620 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "GonkCameraParameters.h"
|
||||
#include "camera/CameraParameters.h"
|
||||
#include "ICameraControl.h"
|
||||
#include "CameraCommon.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace android;
|
||||
|
||||
/* static */ const char*
|
||||
GonkCameraParameters::Parameters::GetTextKey(uint32_t aKey)
|
||||
{
|
||||
switch (aKey) {
|
||||
case CAMERA_PARAM_PREVIEWSIZE:
|
||||
return KEY_PREVIEW_SIZE;
|
||||
case CAMERA_PARAM_PREVIEWFORMAT:
|
||||
return KEY_PREVIEW_FORMAT;
|
||||
case CAMERA_PARAM_PREVIEWFRAMERATE:
|
||||
return KEY_PREVIEW_FRAME_RATE;
|
||||
case CAMERA_PARAM_EFFECT:
|
||||
return KEY_EFFECT;
|
||||
case CAMERA_PARAM_WHITEBALANCE:
|
||||
return KEY_WHITE_BALANCE;
|
||||
case CAMERA_PARAM_SCENEMODE:
|
||||
return KEY_SCENE_MODE;
|
||||
case CAMERA_PARAM_FLASHMODE:
|
||||
return KEY_FLASH_MODE;
|
||||
case CAMERA_PARAM_FOCUSMODE:
|
||||
return KEY_FOCUS_MODE;
|
||||
case CAMERA_PARAM_ZOOM:
|
||||
return KEY_ZOOM;
|
||||
case CAMERA_PARAM_METERINGAREAS:
|
||||
return KEY_METERING_AREAS;
|
||||
case CAMERA_PARAM_FOCUSAREAS:
|
||||
return KEY_FOCUS_AREAS;
|
||||
case CAMERA_PARAM_FOCALLENGTH:
|
||||
return KEY_FOCAL_LENGTH;
|
||||
case CAMERA_PARAM_FOCUSDISTANCENEAR:
|
||||
return KEY_FOCUS_DISTANCES;
|
||||
case CAMERA_PARAM_FOCUSDISTANCEOPTIMUM:
|
||||
return KEY_FOCUS_DISTANCES;
|
||||
case CAMERA_PARAM_FOCUSDISTANCEFAR:
|
||||
return KEY_FOCUS_DISTANCES;
|
||||
case CAMERA_PARAM_EXPOSURECOMPENSATION:
|
||||
return KEY_EXPOSURE_COMPENSATION;
|
||||
case CAMERA_PARAM_PICTURESIZE:
|
||||
return KEY_PICTURE_SIZE;
|
||||
case CAMERA_PARAM_THUMBNAILQUALITY:
|
||||
return KEY_JPEG_THUMBNAIL_QUALITY;
|
||||
case CAMERA_PARAM_PICTURE_SIZE:
|
||||
return KEY_PICTURE_SIZE;
|
||||
case CAMERA_PARAM_PICTURE_FILEFORMAT:
|
||||
return KEY_PICTURE_FORMAT;
|
||||
case CAMERA_PARAM_PICTURE_ROTATION:
|
||||
return KEY_ROTATION;
|
||||
case CAMERA_PARAM_PICTURE_DATETIME:
|
||||
// Not every platform defines a KEY_EXIF_DATETIME;
|
||||
// for those that don't, we use the raw string key, and if the platform
|
||||
// doesn't support it, it will be ignored.
|
||||
//
|
||||
// See bug 832494.
|
||||
return "exif-datetime";
|
||||
case CAMERA_PARAM_VIDEOSIZE:
|
||||
return KEY_VIDEO_SIZE;
|
||||
|
||||
case CAMERA_PARAM_SUPPORTED_PREVIEWSIZES:
|
||||
return KEY_SUPPORTED_PREVIEW_SIZES;
|
||||
case CAMERA_PARAM_SUPPORTED_PICTURESIZES:
|
||||
return KEY_SUPPORTED_PICTURE_SIZES;
|
||||
case CAMERA_PARAM_SUPPORTED_VIDEOSIZES:
|
||||
return KEY_SUPPORTED_VIDEO_SIZES;
|
||||
case CAMERA_PARAM_SUPPORTED_PICTUREFORMATS:
|
||||
return KEY_SUPPORTED_PICTURE_FORMATS;
|
||||
case CAMERA_PARAM_SUPPORTED_WHITEBALANCES:
|
||||
return KEY_SUPPORTED_WHITE_BALANCE;
|
||||
case CAMERA_PARAM_SUPPORTED_SCENEMODES:
|
||||
return KEY_SUPPORTED_SCENE_MODES;
|
||||
case CAMERA_PARAM_SUPPORTED_EFFECTS:
|
||||
return KEY_SUPPORTED_EFFECTS;
|
||||
case CAMERA_PARAM_SUPPORTED_FLASHMODES:
|
||||
return KEY_SUPPORTED_FLASH_MODES;
|
||||
case CAMERA_PARAM_SUPPORTED_FOCUSMODES:
|
||||
return KEY_SUPPORTED_FOCUS_MODES;
|
||||
case CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS:
|
||||
return KEY_MAX_NUM_FOCUS_AREAS;
|
||||
case CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS:
|
||||
return KEY_MAX_NUM_METERING_AREAS;
|
||||
case CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION:
|
||||
return KEY_MIN_EXPOSURE_COMPENSATION;
|
||||
case CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION:
|
||||
return KEY_MAX_EXPOSURE_COMPENSATION;
|
||||
case CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP:
|
||||
return KEY_EXPOSURE_COMPENSATION_STEP;
|
||||
case CAMERA_PARAM_SUPPORTED_ZOOM:
|
||||
return KEY_ZOOM_SUPPORTED;
|
||||
case CAMERA_PARAM_SUPPORTED_ZOOMRATIOS:
|
||||
return KEY_ZOOM_RATIOS;
|
||||
case CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES:
|
||||
return KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES;
|
||||
default:
|
||||
DOM_CAMERA_LOGE("Unhandled camera parameter value %u\n", aKey);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
GonkCameraParameters::GonkCameraParameters()
|
||||
: mLock(PR_NewRWLock(PR_RWLOCK_RANK_NONE, "GonkCameraParameters.Lock"))
|
||||
, mDirty(false)
|
||||
, mInitialized(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(GonkCameraParameters);
|
||||
if (!mLock) {
|
||||
MOZ_CRASH("OOM getting new PRRWLock");
|
||||
}
|
||||
}
|
||||
|
||||
GonkCameraParameters::~GonkCameraParameters()
|
||||
{
|
||||
MOZ_COUNT_DTOR(GonkCameraParameters);
|
||||
if (mLock) {
|
||||
PR_DestroyRWLock(mLock);
|
||||
mLock = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Any members that need to be initialized on the first parameter pull
|
||||
// need to get handled in here.
|
||||
nsresult
|
||||
GonkCameraParameters::Initialize()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = GetImpl(CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION, mExposureCompensationMin);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = GetImpl(CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP, mExposureCompensationStep);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mInitialized = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Handle nsAStrings
|
||||
nsresult
|
||||
GonkCameraParameters::SetTranslated(uint32_t aKey, const nsAString& aValue)
|
||||
{
|
||||
return SetImpl(aKey, NS_ConvertUTF16toUTF8(aValue).get());
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkCameraParameters::GetTranslated(uint32_t aKey, nsAString& aValue)
|
||||
{
|
||||
const char* val;
|
||||
nsresult rv = GetImpl(aKey, val);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
aValue.AssignASCII(val);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Handle ICameraControl::Sizes
|
||||
nsresult
|
||||
GonkCameraParameters::SetTranslated(uint32_t aKey, const ICameraControl::Size& aSize)
|
||||
{
|
||||
if (aSize.width > INT_MAX || aSize.height > INT_MAX) {
|
||||
// AOSP can only handle signed ints.
|
||||
DOM_CAMERA_LOGE("Camera parameter aKey=%d out of bounds (width=%u, height=%u)\n",
|
||||
aSize.width, aSize.height);
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
switch (aKey) {
|
||||
case CAMERA_PARAM_THUMBNAILSIZE:
|
||||
// This is a special case--for some reason the thumbnail size
|
||||
// is accessed as two separate values instead of a tuple.
|
||||
// XXXmikeh - make this restore the original values on error
|
||||
rv = SetImpl(Parameters::KEY_JPEG_THUMBNAIL_WIDTH, static_cast<int>(aSize.width));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = SetImpl(Parameters::KEY_JPEG_THUMBNAIL_HEIGHT, static_cast<int>(aSize.height));
|
||||
}
|
||||
break;
|
||||
|
||||
case CAMERA_PARAM_VIDEOSIZE:
|
||||
// "record-size" is probably deprecated in later ICS;
|
||||
// might need to set "video-size" instead of "record-size";
|
||||
// for the time being, set both. See bug 795332.
|
||||
rv = SetImpl("record-size", nsPrintfCString("%ux%u", aSize.width, aSize.height).get());
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
// intentional fallthrough
|
||||
|
||||
default:
|
||||
rv = SetImpl(aKey, nsPrintfCString("%ux%u", aSize.width, aSize.height).get());
|
||||
break;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGE("Camera parameter aKey=%d failed to set (0x%x)\n", aKey, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkCameraParameters::GetTranslated(uint32_t aKey, ICameraControl::Size& aSize)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (aKey == CAMERA_PARAM_THUMBNAILSIZE) {
|
||||
int width;
|
||||
int height;
|
||||
|
||||
rv = GetImpl(Parameters::KEY_JPEG_THUMBNAIL_WIDTH, width);
|
||||
if (NS_FAILED(rv) || width < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = GetImpl(Parameters::KEY_JPEG_THUMBNAIL_HEIGHT, height);
|
||||
if (NS_FAILED(rv) || height < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aSize.width = static_cast<uint32_t>(width);
|
||||
aSize.height = static_cast<uint32_t>(height);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const char* value;
|
||||
rv = GetImpl(aKey, value);
|
||||
if (NS_FAILED(rv) || !value || *value == '\0') {
|
||||
DOM_CAMERA_LOGW("Camera parameter aKey=%d not available (0x%x)\n", aKey, rv);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
if (sscanf(value, "%ux%u", &aSize.width, &aSize.height) != 2) {
|
||||
DOM_CAMERA_LOGE("Camera parameter aKey=%d size tuple '%s' is invalid\n", aKey, value);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Handle arrays of ICameraControl::Regions
|
||||
nsresult
|
||||
GonkCameraParameters::SetTranslated(uint32_t aKey, const nsTArray<ICameraControl::Region>& aRegions)
|
||||
{
|
||||
uint32_t length = aRegions.Length();
|
||||
|
||||
if (!length) {
|
||||
// This tells the camera driver to revert to automatic regioning.
|
||||
return SetImpl(aKey, "(0,0,0,0,0)");
|
||||
}
|
||||
|
||||
nsCString s;
|
||||
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
const ICameraControl::Region* r = &aRegions[i];
|
||||
s.AppendPrintf("(%d,%d,%d,%d,%d),", r->top, r->left, r->bottom, r->right, r->weight);
|
||||
}
|
||||
|
||||
// remove the trailing comma
|
||||
s.Trim(",", false, true, true);
|
||||
|
||||
return SetImpl(aKey, s.get());
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<ICameraControl::Region>& aRegions)
|
||||
{
|
||||
aRegions.Clear();
|
||||
|
||||
const char* value;
|
||||
nsresult rv = GetImpl(aKey, value);
|
||||
if (NS_FAILED(rv) || !value || *value == '\0') {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
const char* p = value;
|
||||
uint32_t count = 1;
|
||||
|
||||
// count the number of regions in the string
|
||||
while ((p = strstr(p, "),("))) {
|
||||
++count;
|
||||
p += 3;
|
||||
}
|
||||
|
||||
aRegions.SetCapacity(count);
|
||||
ICameraControl::Region* r;
|
||||
|
||||
// parse all of the region sets
|
||||
uint32_t i;
|
||||
for (i = 0, p = value; p && i < count; ++i, p = strchr(p + 1, '(')) {
|
||||
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);
|
||||
aRegions.Clear();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Handle ICameraControl::Positions
|
||||
nsresult
|
||||
GonkCameraParameters::SetTranslated(uint32_t aKey, const ICameraControl::Position& aPosition)
|
||||
{
|
||||
MOZ_ASSERT(aKey == CAMERA_PARAM_PICTURE_LOCATION);
|
||||
|
||||
// Add any specified location information -- we don't care if these fail.
|
||||
if (!isnan(aPosition.latitude)) {
|
||||
DOM_CAMERA_LOGI("setting picture latitude to %lf\n", aPosition.latitude);
|
||||
SetImpl(Parameters::KEY_GPS_LATITUDE, nsPrintfCString("%lf", aPosition.latitude).get());
|
||||
}
|
||||
if (!isnan(aPosition.longitude)) {
|
||||
DOM_CAMERA_LOGI("setting picture longitude to %lf\n", aPosition.longitude);
|
||||
SetImpl(Parameters::KEY_GPS_LONGITUDE, nsPrintfCString("%lf", aPosition.longitude).get());
|
||||
}
|
||||
if (!isnan(aPosition.altitude)) {
|
||||
DOM_CAMERA_LOGI("setting picture altitude to %lf\n", aPosition.altitude);
|
||||
SetImpl(Parameters::KEY_GPS_ALTITUDE, nsPrintfCString("%lf", aPosition.altitude).get());
|
||||
}
|
||||
if (!isnan(aPosition.timestamp)) {
|
||||
DOM_CAMERA_LOGI("setting picture timestamp to %lf\n", aPosition.timestamp);
|
||||
SetImpl(Parameters::KEY_GPS_TIMESTAMP, nsPrintfCString("%lf", aPosition.timestamp).get());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Handle int64_ts
|
||||
nsresult
|
||||
GonkCameraParameters::SetTranslated(uint32_t aKey, const int64_t& aValue)
|
||||
{
|
||||
if (aKey == CAMERA_PARAM_PICTURE_DATETIME) {
|
||||
// Add the non-GPS timestamp. The EXIF date/time field is formatted as
|
||||
// "YYYY:MM:DD HH:MM:SS", without room for a time-zone; as such, the time
|
||||
// is meant to be stored as a local time. Since we are given seconds from
|
||||
// Epoch GMT, we use localtime_r() to handle the conversion.
|
||||
time_t time = aValue;
|
||||
if (time != aValue) {
|
||||
DOM_CAMERA_LOGE("picture date/time '%llu' is too far in the future\n", aValue);
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
struct tm t;
|
||||
if (!localtime_r(&time, &t)) {
|
||||
DOM_CAMERA_LOGE("picture date/time couldn't be converted to local time: (%d) %s\n", errno, strerror(errno));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
char dateTime[20];
|
||||
if (!strftime(dateTime, sizeof(dateTime), "%Y:%m:%d %T", &t)) {
|
||||
DOM_CAMERA_LOGE("picture date/time couldn't be converted to string\n");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGI("setting picture date/time to %s\n", dateTime);
|
||||
|
||||
return SetImpl(CAMERA_PARAM_PICTURE_DATETIME, dateTime);
|
||||
}
|
||||
|
||||
// You can't actually pass 64-bit parameters to Gonk. :(
|
||||
int32_t v = static_cast<int32_t>(aValue);
|
||||
if (static_cast<int64_t>(v) != aValue) {
|
||||
return NS_ERROR_INVALID_ARG;;
|
||||
}
|
||||
return SetImpl(aKey, v);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkCameraParameters::GetTranslated(uint32_t aKey, int64_t& aValue)
|
||||
{
|
||||
int val;
|
||||
nsresult rv = GetImpl(aKey, val);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
aValue = val;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Handle doubles
|
||||
nsresult
|
||||
GonkCameraParameters::SetTranslated(uint32_t aKey, const double& aValue)
|
||||
{
|
||||
if (aKey == CAMERA_PARAM_EXPOSURECOMPENSATION) {
|
||||
/**
|
||||
* Convert from real value to a Gonk index, round
|
||||
* to the nearest step; index is 1-based.
|
||||
*/
|
||||
int index =
|
||||
(aValue - mExposureCompensationMin + mExposureCompensationStep / 2) /
|
||||
mExposureCompensationStep + 1;
|
||||
DOM_CAMERA_LOGI("Exposure compensation = %f --> index = %d\n", aValue, index);
|
||||
return SetImpl(CAMERA_PARAM_EXPOSURECOMPENSATION, index);
|
||||
}
|
||||
|
||||
return SetImpl(aKey, aValue);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkCameraParameters::GetTranslated(uint32_t aKey, double& aValue)
|
||||
{
|
||||
double val;
|
||||
int index = 0;
|
||||
double focusDistance[3];
|
||||
const char* s;
|
||||
nsresult rv;
|
||||
|
||||
switch (aKey) {
|
||||
case CAMERA_PARAM_ZOOM:
|
||||
rv = GetImpl(CAMERA_PARAM_ZOOM, val);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
val /= 100.0;
|
||||
} else {
|
||||
// return 1x when zooming is not supported
|
||||
val = 1.0;
|
||||
}
|
||||
break;
|
||||
|
||||
/**
|
||||
* The gonk camera parameters API only exposes one focus distance property
|
||||
* that contains "Near,Optimum,Far" distances, in metres, where 'Far' may
|
||||
* be 'Infinity'.
|
||||
*/
|
||||
case CAMERA_PARAM_FOCUSDISTANCEFAR:
|
||||
++index;
|
||||
// intentional fallthrough
|
||||
|
||||
case CAMERA_PARAM_FOCUSDISTANCEOPTIMUM:
|
||||
++index;
|
||||
// intentional fallthrough
|
||||
|
||||
case CAMERA_PARAM_FOCUSDISTANCENEAR:
|
||||
rv = GetImpl(aKey, s);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (sscanf(s, "%lf,%lf,%lf", &focusDistance[0], &focusDistance[1], &focusDistance[2]) == 3) {
|
||||
val = focusDistance[index];
|
||||
} else {
|
||||
val = 0.0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CAMERA_PARAM_EXPOSURECOMPENSATION:
|
||||
rv = GetImpl(aKey, index);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (!index) {
|
||||
// NaN indicates automatic exposure compensation
|
||||
val = NAN;
|
||||
} else {
|
||||
val = (index - 1) * mExposureCompensationStep + mExposureCompensationMin;
|
||||
DOM_CAMERA_LOGI("index = %d --> compensation = %f\n", index, val);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = GetImpl(aKey, val);
|
||||
break;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aValue = val;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Handle ints
|
||||
nsresult
|
||||
GonkCameraParameters::SetTranslated(uint32_t aKey, const int& aValue)
|
||||
{
|
||||
return SetImpl(aKey, aValue);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkCameraParameters::GetTranslated(uint32_t aKey, int& aValue)
|
||||
{
|
||||
return GetImpl(aKey, aValue);
|
||||
}
|
||||
|
||||
// Handle uint32_ts -- Gonk only speaks int
|
||||
nsresult
|
||||
GonkCameraParameters::SetTranslated(uint32_t aKey, const uint32_t& aValue)
|
||||
{
|
||||
if (aValue > INT_MAX) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
int val = static_cast<int>(aValue);
|
||||
return SetImpl(aKey, val);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkCameraParameters::GetTranslated(uint32_t aKey, uint32_t& aValue)
|
||||
{
|
||||
int val;
|
||||
nsresult rv = GetImpl(aKey, val);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (val < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aValue = val;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ParseItem(const char* aStart, const char* aEnd, ICameraControl::Size* aItem)
|
||||
{
|
||||
if (sscanf(aStart, "%ux%u", &aItem->width, &aItem->height) == 2) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGE("Size tuple has bad format: '%s'\n", __func__, __LINE__, aStart);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ParseItem(const char* aStart, const char* aEnd, nsAString* aItem)
|
||||
{
|
||||
if (aEnd) {
|
||||
aItem->AssignASCII(aStart, aEnd - aStart);
|
||||
} else {
|
||||
aItem->AssignASCII(aStart);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ParseItem(const char* aStart, const char* aEnd, double* aItem)
|
||||
{
|
||||
if (sscanf(aStart, "%lf", aItem) == 1) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
template<class T> nsresult
|
||||
GonkCameraParameters::GetListAsArray(uint32_t aKey, nsTArray<T>& aArray)
|
||||
{
|
||||
const char* p;
|
||||
nsresult rv = GetImpl(aKey, p);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (!p) {
|
||||
DOM_CAMERA_LOGW("Camera parameter %d not available (value is null)\n", aKey);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
if (*p == '\0') {
|
||||
DOM_CAMERA_LOGW("Camera parameter %d not available (value is empty string)\n", aKey);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
aArray.Clear();
|
||||
const char* comma;
|
||||
|
||||
while (p) {
|
||||
T* v = aArray.AppendElement();
|
||||
if (!v) {
|
||||
aArray.Clear();
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
comma = strchr(p, ',');
|
||||
if (comma != p) {
|
||||
rv = ParseItem(p, comma, v);
|
||||
if (NS_FAILED(rv)) {
|
||||
aArray.Clear();
|
||||
return rv;
|
||||
}
|
||||
p = comma;
|
||||
}
|
||||
if (p) {
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<nsString>& aValues)
|
||||
{
|
||||
return GetListAsArray(aKey, aValues);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<double>& aValues)
|
||||
{
|
||||
return GetListAsArray(aKey, aValues);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<ICameraControl::Size>& aSizes)
|
||||
{
|
||||
return GetListAsArray(aKey, aSizes);
|
||||
}
|
||||
|
184
dom/camera/GonkCameraParameters.h
Normal file
184
dom/camera/GonkCameraParameters.h
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef DOM_CAMERA_GONKCAMERAPARAMETERS_H
|
||||
#define DOM_CAMERA_GONKCAMERAPARAMETERS_H
|
||||
|
||||
#include <math.h>
|
||||
#include "camera/CameraParameters.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsString.h"
|
||||
#include "AutoRwLock.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "ICameraControl.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class GonkCameraParameters
|
||||
{
|
||||
public:
|
||||
GonkCameraParameters();
|
||||
virtual ~GonkCameraParameters();
|
||||
|
||||
// IMPORTANT: This class is read and written by multiple threads --
|
||||
// ALL public methods must hold mLock, for either reading or writing,
|
||||
// for the life of their operation. Not doing so was the cause of
|
||||
// bug 928856, which was -painful- to track down.
|
||||
template<class T> nsresult
|
||||
Set(uint32_t aKey, const T& aValue)
|
||||
{
|
||||
RwLockAutoEnterWrite lock(mLock);
|
||||
nsresult rv = SetTranslated(aKey, aValue);
|
||||
mDirty = mDirty || NS_SUCCEEDED(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
template<class T> nsresult
|
||||
Get(uint32_t aKey, T& aValue)
|
||||
{
|
||||
RwLockAutoEnterRead lock(mLock);
|
||||
return GetTranslated(aKey, aValue);
|
||||
}
|
||||
|
||||
bool
|
||||
TestAndClearDirtyFlag()
|
||||
{
|
||||
bool dirty;
|
||||
|
||||
RwLockAutoEnterWrite lock(mLock);
|
||||
dirty = mDirty;
|
||||
mDirty = false;
|
||||
return dirty;
|
||||
}
|
||||
|
||||
android::String8
|
||||
Flatten() const
|
||||
{
|
||||
RwLockAutoEnterRead lock(mLock);
|
||||
return mParams.flatten();
|
||||
}
|
||||
|
||||
nsresult
|
||||
Unflatten(const android::String8& aFlatParameters)
|
||||
{
|
||||
RwLockAutoEnterWrite lock(mLock);
|
||||
mParams.unflatten(aFlatParameters);
|
||||
if (mInitialized) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// We call Initialize() once when the parameter set is first loaded,
|
||||
// to set up any constant values this class requires internally,
|
||||
// e.g. the exposure compensation step and limits.
|
||||
return Initialize();
|
||||
}
|
||||
|
||||
protected:
|
||||
PRRWLock* mLock;
|
||||
bool mDirty;
|
||||
bool mInitialized;
|
||||
|
||||
// Required internal properties
|
||||
double mExposureCompensationMin;
|
||||
double mExposureCompensationStep;
|
||||
|
||||
// This subclass of android::CameraParameters just gives
|
||||
// all of the AOSP getters and setters the same signature.
|
||||
class Parameters : public android::CameraParameters
|
||||
{
|
||||
public:
|
||||
using android::CameraParameters::set;
|
||||
|
||||
void set(const char* aKey, float aValue) { setFloat(aKey, aValue); }
|
||||
void set(const char* aKey, double aValue) { setFloat(aKey, aValue); }
|
||||
void get(const char* aKey, float& aRet) { aRet = getFloat(aKey); }
|
||||
void get(const char* aKey, double& aRet) { aRet = getFloat(aKey); }
|
||||
void get(const char* aKey, const char*& aRet) { aRet = android::CameraParameters::get(aKey); }
|
||||
void get(const char* aKey, int& aRet) { aRet = getInt(aKey); }
|
||||
|
||||
static const char* GetTextKey(uint32_t aKey);
|
||||
};
|
||||
|
||||
Parameters mParams;
|
||||
|
||||
// The *Impl() templates handle converting the parameter keys from
|
||||
// their enum values to string types, if necessary. These are the
|
||||
// bottom layer accessors to mParams.
|
||||
template<typename T> nsresult
|
||||
SetImpl(uint32_t aKey, const T& aValue)
|
||||
{
|
||||
const char* key = Parameters::GetTextKey(aKey);
|
||||
NS_ENSURE_TRUE(key, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
mParams.set(key, aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template<typename T> nsresult
|
||||
GetImpl(uint32_t aKey, T& aValue)
|
||||
{
|
||||
const char* key = Parameters::GetTextKey(aKey);
|
||||
NS_ENSURE_TRUE(key, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
mParams.get(key, aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template<class T> nsresult
|
||||
SetImpl(const char* aKey, const T& aValue)
|
||||
{
|
||||
mParams.set(aKey, aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template<class T> nsresult
|
||||
GetImpl(const char* aKey, T& aValue)
|
||||
{
|
||||
mParams.get(aKey, aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// The *Translated() functions allow us to handle special cases;
|
||||
// for example, where the thumbnail size setting is exposed as an
|
||||
// ICameraControl::Size object, but is handled by the AOSP layer
|
||||
// as two separate parameters.
|
||||
nsresult SetTranslated(uint32_t aKey, const nsAString& aValue);
|
||||
nsresult GetTranslated(uint32_t aKey, nsAString& aValue);
|
||||
nsresult SetTranslated(uint32_t aKey, const ICameraControl::Size& aSize);
|
||||
nsresult GetTranslated(uint32_t aKey, ICameraControl::Size& aSize);
|
||||
nsresult GetTranslated(uint32_t aKey, nsTArray<ICameraControl::Size>& aSizes);
|
||||
nsresult SetTranslated(uint32_t aKey, const nsTArray<ICameraControl::Region>& aRegions);
|
||||
nsresult GetTranslated(uint32_t aKey, nsTArray<ICameraControl::Region>& aRegions);
|
||||
nsresult SetTranslated(uint32_t aKey, const ICameraControl::Position& aPosition);
|
||||
nsresult SetTranslated(uint32_t aKey, const int64_t& aValue);
|
||||
nsresult GetTranslated(uint32_t aKey, int64_t& aValue);
|
||||
nsresult SetTranslated(uint32_t aKey, const double& aValue);
|
||||
nsresult GetTranslated(uint32_t aKey, double& aValue);
|
||||
nsresult SetTranslated(uint32_t aKey, const int& aValue);
|
||||
nsresult GetTranslated(uint32_t aKey, int& aValue);
|
||||
nsresult SetTranslated(uint32_t aKey, const uint32_t& aValue);
|
||||
nsresult GetTranslated(uint32_t aKey, uint32_t& aValue);
|
||||
nsresult GetTranslated(uint32_t aKey, nsTArray<nsString>& aValues);
|
||||
nsresult GetTranslated(uint32_t aKey, nsTArray<double>& aValues);
|
||||
|
||||
template<class T> nsresult GetListAsArray(uint32_t aKey, nsTArray<T>& aArray);
|
||||
|
||||
nsresult Initialize();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DOM_CAMERA_GONKCAMERAPARAMETERS_H
|
@ -158,8 +158,7 @@ GonkCameraSource::GonkCameraSource(
|
||||
Size videoSize,
|
||||
int32_t frameRate,
|
||||
bool storeMetaDataInVideoBuffers)
|
||||
: mCameraHw(aCameraHw),
|
||||
mCameraFlags(0),
|
||||
: mCameraFlags(0),
|
||||
mNumInputBuffers(0),
|
||||
mVideoFrameRate(-1),
|
||||
mNumFramesReceived(0),
|
||||
@ -171,7 +170,8 @@ GonkCameraSource::GonkCameraSource(
|
||||
mNumFramesDropped(0),
|
||||
mNumGlitches(0),
|
||||
mGlitchDurationThresholdUs(200000),
|
||||
mCollectStats(false) {
|
||||
mCollectStats(false),
|
||||
mCameraHw(aCameraHw) {
|
||||
mVideoSize.width = -1;
|
||||
mVideoSize.height = -1;
|
||||
|
||||
|
@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "GonkRecorderProfiles.h"
|
||||
#include <media/MediaProfiles.h>
|
||||
#include "GonkRecorder.h"
|
||||
#include "CameraControlImpl.h"
|
||||
#include "GonkRecorderProfiles.h"
|
||||
#include "CameraCommon.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <media/MediaProfiles.h>
|
||||
#include "CameraRecorderProfiles.h"
|
||||
#include "ICameraControl.h"
|
||||
|
||||
#ifndef CHECK_SETARG
|
||||
#define CHECK_SETARG(x) \
|
||||
@ -86,7 +87,7 @@ public:
|
||||
* supported by the camera hardware. (Just because it appears in a recorder
|
||||
* profile doesn't mean the hardware can handle it.)
|
||||
*/
|
||||
void SetSupportedResolutions(const nsTArray<idl::CameraSize>& aSizes)
|
||||
void SetSupportedResolutions(const nsTArray<ICameraControl::Size>& aSizes)
|
||||
{ mSupportedSizes = aSizes; }
|
||||
|
||||
/**
|
||||
@ -104,7 +105,7 @@ public:
|
||||
protected:
|
||||
virtual ~GonkRecorderProfileManager();
|
||||
|
||||
nsTArray<idl::CameraSize> mSupportedSizes;
|
||||
nsTArray<ICameraControl::Size> mSupportedSizes;
|
||||
};
|
||||
|
||||
}; // namespace mozilla
|
||||
|
@ -5,69 +5,185 @@
|
||||
#ifndef DOM_CAMERA_ICAMERACONTROL_H
|
||||
#define DOM_CAMERA_ICAMERACONTROL_H
|
||||
|
||||
#include "nsIFile.h"
|
||||
#include "nsIDOMCameraManager.h"
|
||||
#include "DictionaryHelpers.h"
|
||||
#include "CameraCommon.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
class DeviceStorageFileDescriptor;
|
||||
|
||||
class nsIFile;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class DOMCameraPreview;
|
||||
class CameraControlListener;
|
||||
class RecorderProfileManager;
|
||||
|
||||
// XXXmikeh - In some future patch this should move into the ICameraControl
|
||||
// class as well, and the names updated to the 'k'-style;
|
||||
// e.g. kParamPreviewSize, etc.
|
||||
enum {
|
||||
// current settings
|
||||
CAMERA_PARAM_PREVIEWSIZE,
|
||||
CAMERA_PARAM_PREVIEWFORMAT,
|
||||
CAMERA_PARAM_PREVIEWFRAMERATE,
|
||||
CAMERA_PARAM_VIDEOSIZE,
|
||||
CAMERA_PARAM_PICTURE_SIZE,
|
||||
CAMERA_PARAM_PICTURE_FILEFORMAT,
|
||||
CAMERA_PARAM_PICTURE_ROTATION,
|
||||
CAMERA_PARAM_PICTURE_LOCATION,
|
||||
CAMERA_PARAM_PICTURE_DATETIME,
|
||||
CAMERA_PARAM_EFFECT,
|
||||
CAMERA_PARAM_WHITEBALANCE,
|
||||
CAMERA_PARAM_SCENEMODE,
|
||||
CAMERA_PARAM_FLASHMODE,
|
||||
CAMERA_PARAM_FOCUSMODE,
|
||||
CAMERA_PARAM_ZOOM,
|
||||
CAMERA_PARAM_METERINGAREAS,
|
||||
CAMERA_PARAM_FOCUSAREAS,
|
||||
CAMERA_PARAM_FOCALLENGTH,
|
||||
CAMERA_PARAM_FOCUSDISTANCENEAR,
|
||||
CAMERA_PARAM_FOCUSDISTANCEOPTIMUM,
|
||||
CAMERA_PARAM_FOCUSDISTANCEFAR,
|
||||
CAMERA_PARAM_EXPOSURECOMPENSATION,
|
||||
CAMERA_PARAM_PICTURESIZE,
|
||||
CAMERA_PARAM_THUMBNAILSIZE,
|
||||
CAMERA_PARAM_THUMBNAILQUALITY,
|
||||
CAMERA_PARAM_SENSORANGLE,
|
||||
|
||||
// supported features
|
||||
CAMERA_PARAM_SUPPORTED_PREVIEWSIZES,
|
||||
CAMERA_PARAM_SUPPORTED_PICTURESIZES,
|
||||
CAMERA_PARAM_SUPPORTED_VIDEOSIZES,
|
||||
CAMERA_PARAM_SUPPORTED_PICTUREFORMATS,
|
||||
CAMERA_PARAM_SUPPORTED_WHITEBALANCES,
|
||||
CAMERA_PARAM_SUPPORTED_SCENEMODES,
|
||||
CAMERA_PARAM_SUPPORTED_EFFECTS,
|
||||
CAMERA_PARAM_SUPPORTED_FLASHMODES,
|
||||
CAMERA_PARAM_SUPPORTED_FOCUSMODES,
|
||||
CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS,
|
||||
CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS,
|
||||
CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION,
|
||||
CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION,
|
||||
CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP,
|
||||
CAMERA_PARAM_SUPPORTED_ZOOM,
|
||||
CAMERA_PARAM_SUPPORTED_ZOOMRATIOS,
|
||||
CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES
|
||||
};
|
||||
|
||||
class ICameraControl
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ICameraControl)
|
||||
|
||||
virtual nsresult GetPreviewStream(idl::CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
|
||||
virtual nsresult StartPreview(DOMCameraPreview* aDOMPreview) = 0;
|
||||
virtual void StopPreview() = 0;
|
||||
virtual nsresult AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
|
||||
virtual nsresult TakePicture(const idl::CameraSize& aSize, int32_t aRotation, const nsAString& aFileFormat, idl::CameraPosition aPosition, uint64_t aDateTime, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
|
||||
virtual nsresult StartRecording(idl::CameraStartRecordingOptions* aOptions, DeviceStorageFileDescriptor *aFileDescriptor, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
|
||||
static nsresult GetNumberOfCameras(int32_t& aDeviceCount);
|
||||
static nsresult GetCameraName(uint32_t aDeviceNum, nsCString& aDeviceName);
|
||||
static nsresult GetListOfCameras(nsTArray<nsString>& aList);
|
||||
|
||||
enum Mode {
|
||||
kUnspecifiedMode,
|
||||
kPictureMode,
|
||||
kVideoMode,
|
||||
};
|
||||
|
||||
struct Size {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
};
|
||||
|
||||
struct Region {
|
||||
int32_t top;
|
||||
int32_t left;
|
||||
int32_t bottom;
|
||||
int32_t right;
|
||||
uint32_t weight;
|
||||
};
|
||||
|
||||
struct Position {
|
||||
double latitude;
|
||||
double longitude;
|
||||
double altitude;
|
||||
double timestamp;
|
||||
};
|
||||
|
||||
struct StartRecordingOptions {
|
||||
uint32_t rotation;
|
||||
uint32_t maxFileSizeBytes;
|
||||
uint32_t maxVideoLengthMs;
|
||||
};
|
||||
|
||||
struct Configuration {
|
||||
Mode mMode;
|
||||
Size mPreviewSize;
|
||||
nsString mRecorderProfile;
|
||||
};
|
||||
static already_AddRefed<ICameraControl> Create(uint32_t aCameraId,
|
||||
const Configuration* aInitialConfig);
|
||||
virtual nsresult SetConfiguration(const Configuration& aConfig) = 0;
|
||||
|
||||
virtual void AddListener(CameraControlListener* aListener) = 0;
|
||||
virtual void RemoveListener(CameraControlListener* aListener) = 0;
|
||||
|
||||
virtual nsresult StartPreview() = 0;
|
||||
virtual nsresult StopPreview() = 0;
|
||||
virtual nsresult AutoFocus(bool aCancelExistingCall) = 0;
|
||||
virtual nsresult TakePicture() = 0;
|
||||
virtual nsresult StartRecording(DeviceStorageFileDescriptor *aFileDescriptor,
|
||||
const StartRecordingOptions* aOptions = nullptr) = 0;
|
||||
virtual nsresult StopRecording() = 0;
|
||||
virtual nsresult GetPreviewStreamVideoMode(idl::CameraRecorderOptions* aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
|
||||
virtual nsresult ReleaseHardware(nsICameraReleaseCallback* onSuccess, nsICameraErrorCallback* onError) = 0;
|
||||
virtual nsresult ReleaseHardware() = 0;
|
||||
|
||||
virtual nsresult Set(uint32_t aKey, const nsAString& aValue) = 0;
|
||||
virtual nsresult Get(uint32_t aKey, nsAString& aValue) = 0;
|
||||
virtual nsresult Set(uint32_t aKey, double aValue) = 0;
|
||||
virtual nsresult Get(uint32_t aKey, double* aValue) = 0;
|
||||
virtual nsresult Set(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit) = 0;
|
||||
virtual nsresult Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue) = 0;
|
||||
virtual nsresult Set(nsICameraShutterCallback* aOnShutter) = 0;
|
||||
virtual nsresult Get(nsICameraShutterCallback** aOnShutter) = 0;
|
||||
virtual nsresult Set(nsICameraClosedCallback* aOnClosed) = 0;
|
||||
virtual nsresult Get(nsICameraClosedCallback** aOnClosed) = 0;
|
||||
virtual nsresult Set(nsICameraRecorderStateChange* aOnRecorderStateChange) = 0;
|
||||
virtual nsresult Get(nsICameraRecorderStateChange** aOnRecorderStateChange) = 0;
|
||||
virtual nsresult Set(nsICameraPreviewStateChange* aOnPreviewStateChange) = 0;
|
||||
virtual nsresult Get(nsICameraPreviewStateChange** aOnPreviewStateChange) = 0;
|
||||
virtual nsresult Set(uint32_t aKey, const idl::CameraSize& aSize) = 0;
|
||||
virtual nsresult Get(uint32_t aKey, idl::CameraSize& aSize) = 0;
|
||||
virtual nsresult Get(uint32_t aKey, int32_t* aValue) = 0;
|
||||
virtual nsresult SetFocusAreas(JSContext* aCx, const JS::Value& aValue) = 0;
|
||||
virtual nsresult SetMeteringAreas(JSContext* aCx, const JS::Value& aValue) = 0;
|
||||
virtual nsresult GetVideoSizes(nsTArray<idl::CameraSize>& aVideoSizes) = 0;
|
||||
virtual nsresult Get(uint32_t aKey, double& aValue) = 0;
|
||||
virtual nsresult Set(uint32_t aKey, int32_t aValue) = 0;
|
||||
virtual nsresult Get(uint32_t aKey, int32_t& aValue) = 0;
|
||||
virtual nsresult Set(uint32_t aKey, int64_t aValue) = 0;
|
||||
virtual nsresult Get(uint32_t aKey, int64_t& aValue) = 0;
|
||||
virtual nsresult Set(uint32_t aKey, const Size& aValue) = 0;
|
||||
virtual nsresult Get(uint32_t aKey, Size& aValue) = 0;
|
||||
virtual nsresult Set(uint32_t aKey, const nsTArray<Region>& aRegions) = 0;
|
||||
virtual nsresult Get(uint32_t aKey, nsTArray<Region>& aRegions) = 0;
|
||||
|
||||
virtual nsresult SetLocation(const Position& aLocation) = 0;
|
||||
|
||||
virtual nsresult Get(uint32_t aKey, nsTArray<Size>& aSizes) = 0;
|
||||
virtual nsresult Get(uint32_t aKey, nsTArray<nsString>& aValues) = 0;
|
||||
virtual nsresult Get(uint32_t aKey, nsTArray<double>& aValues) = 0;
|
||||
|
||||
virtual already_AddRefed<RecorderProfileManager> GetRecorderProfileManager() = 0;
|
||||
virtual uint32_t GetCameraId() = 0;
|
||||
|
||||
virtual const char* GetParameter(const char* aKey) = 0;
|
||||
virtual const char* GetParameterConstChar(uint32_t aKey) = 0;
|
||||
virtual double GetParameterDouble(uint32_t aKey) = 0;
|
||||
virtual void GetParameter(uint32_t aKey, nsTArray<idl::CameraRegion>& aRegions) = 0;
|
||||
virtual void SetParameter(const char* aKey, const char* aValue) = 0;
|
||||
virtual void SetParameter(uint32_t aKey, const char* aValue) = 0;
|
||||
virtual void SetParameter(uint32_t aKey, double aValue) = 0;
|
||||
virtual void SetParameter(uint32_t aKey, const nsTArray<idl::CameraRegion>& aRegions) = 0;
|
||||
|
||||
virtual void Shutdown() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~ICameraControl() { }
|
||||
|
||||
friend class ICameraControlParameterSetAutoEnter;
|
||||
|
||||
virtual void BeginBatchParameterSet() = 0;
|
||||
virtual void EndBatchParameterSet() = 0;
|
||||
};
|
||||
|
||||
// Helper class to make it easy to update a batch of camera parameters;
|
||||
// the parameters are applied atomically when this object goes out of
|
||||
// scope.
|
||||
class ICameraControlParameterSetAutoEnter
|
||||
{
|
||||
public:
|
||||
ICameraControlParameterSetAutoEnter(ICameraControl* aCameraControl)
|
||||
: mCameraControl(aCameraControl)
|
||||
{
|
||||
mCameraControl->BeginBatchParameterSet();
|
||||
}
|
||||
virtual ~ICameraControlParameterSetAutoEnter()
|
||||
{
|
||||
mCameraControl->EndBatchParameterSet();
|
||||
}
|
||||
|
||||
protected:
|
||||
nsRefPtr<ICameraControl> mCameraControl;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -4,15 +4,9 @@
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIDOMCameraManager.idl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
TEST_DIRS += ['test']
|
||||
|
||||
XPIDL_MODULE = 'dom_camera'
|
||||
|
||||
EXPORTS += [
|
||||
'CameraCommon.h',
|
||||
'CameraPreviewMediaStream.h',
|
||||
@ -26,8 +20,8 @@ SOURCES += [
|
||||
'CameraRecorderProfiles.cpp',
|
||||
'DOMCameraCapabilities.cpp',
|
||||
'DOMCameraControl.cpp',
|
||||
'DOMCameraControlListener.cpp',
|
||||
'DOMCameraManager.cpp',
|
||||
'DOMCameraPreview.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_B2G_CAMERA']:
|
||||
@ -35,6 +29,7 @@ if CONFIG['MOZ_B2G_CAMERA']:
|
||||
'GonkCameraControl.cpp',
|
||||
'GonkCameraHwMgr.cpp',
|
||||
'GonkCameraManager.cpp',
|
||||
'GonkCameraParameters.cpp',
|
||||
'GonkCameraSource.cpp',
|
||||
'GonkRecorder.cpp',
|
||||
'GonkRecorderProfiles.cpp',
|
||||
|
@ -1,229 +0,0 @@
|
||||
#include "domstubs.idl"
|
||||
|
||||
#include "nsIDOMMediaStream.idl"
|
||||
#include "nsIDOMDOMRequest.idl"
|
||||
|
||||
|
||||
interface nsIDOMBlob;
|
||||
interface nsIDOMDeviceStorage;
|
||||
|
||||
/* Used to set the dimensions of a captured picture,
|
||||
a preview stream, a video capture stream, etc. */
|
||||
dictionary CameraSize {
|
||||
unsigned long width;
|
||||
unsigned long height;
|
||||
};
|
||||
|
||||
/* Camera regions are used to set focus and metering areas;
|
||||
the coordinates are referenced to the sensor:
|
||||
(-1000, -1000) is the top left corner
|
||||
(1000, 1000) is the bottom left corner
|
||||
The weight of the region can range from 0 to 1000. */
|
||||
dictionary CameraRegion {
|
||||
long top;
|
||||
long left;
|
||||
long bottom;
|
||||
long right;
|
||||
unsigned long weight;
|
||||
};
|
||||
|
||||
/* The position information to record in the image header.
|
||||
'NaN' indicates the information is not available. */
|
||||
dictionary CameraPosition {
|
||||
double latitude;
|
||||
double longitude;
|
||||
double altitude;
|
||||
double timestamp;
|
||||
};
|
||||
|
||||
[scriptable, uuid(0711a4af-73c2-481d-85bc-0ba3ec36c004)]
|
||||
interface nsICameraCapabilities : nsISupports
|
||||
{
|
||||
/* an array of objects with 'height' and 'width' properties
|
||||
supported for the preview stream */
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval previewSizes;
|
||||
|
||||
/* an array of objects with 'height' and 'width' properties
|
||||
supported for picture taking */
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval pictureSizes;
|
||||
|
||||
/* an array of objects with 'height' and 'width' properties
|
||||
supported for thumbnail sizes in taken pictures */
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval thumbnailSizes;
|
||||
|
||||
/* an array of strings, e.g. [ "jpeg", "rgb565" ] */
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval fileFormats;
|
||||
|
||||
/* an array of strings, e.g. [ "auto", "fluorescent", etc. ] */
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval whiteBalanceModes;
|
||||
|
||||
/* an array of strings, e.g. [ "auto", "night", "beach", etc. ] */
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval sceneModes;
|
||||
|
||||
/* an array of strings, e.g. [ "normal", "sepia", "mono", etc. ] */
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval effects;
|
||||
|
||||
/* an array of strings, e.g. [ "auto", "off", "on", etc. ] */
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval flashModes;
|
||||
|
||||
/* an array of strings, e.g. [ "auto", "fixed", "macro", etc. ] */
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval focusModes;
|
||||
|
||||
/* the maximum number of focus areas supported by the camera */
|
||||
[implicit_jscontext]
|
||||
readonly attribute long maxFocusAreas;
|
||||
|
||||
/* the minimum supported exposure compensation value */
|
||||
[implicit_jscontext]
|
||||
readonly attribute double minExposureCompensation;
|
||||
|
||||
/* the maximum supported exposure compensation value */
|
||||
[implicit_jscontext]
|
||||
readonly attribute double maxExposureCompensation;
|
||||
|
||||
/* exposure compensation minimum step-size */
|
||||
[implicit_jscontext]
|
||||
readonly attribute double stepExposureCompensation;
|
||||
|
||||
/* the maximum number of metering areas supported by the camera */
|
||||
[implicit_jscontext]
|
||||
readonly attribute long maxMeteringAreas;
|
||||
|
||||
/* an array of doubles, e.g. [ 1.0, 1.2, 1.5, 2.0, 3.0, etc. ],
|
||||
or null if zooming is not supported */
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval zoomRatios;
|
||||
|
||||
/* an array of objects with 'height' and 'width' properties
|
||||
supported for video recording */
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval videoSizes;
|
||||
|
||||
/* an object with attributes for each of the supported recorder
|
||||
profiles, e.g. recorderProfiles.cif, recorderProfiles.qvga,
|
||||
etc. */
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval recorderProfiles;
|
||||
};
|
||||
|
||||
/* These properties affect the video recording preview, e.g.
|
||||
{
|
||||
profile: "1080p",
|
||||
rotation: 0
|
||||
}
|
||||
|
||||
'profile' is one of the profiles returned by
|
||||
nsICameraCapabilities.recorderProfiles'; if this profile is missing,
|
||||
an arbitrary profile will be chosen.
|
||||
|
||||
'rotation' is the degrees clockwise to rotate the preview; if
|
||||
this option is not supported, it will be ignored; if this option
|
||||
is missing, the default is 0.
|
||||
*/
|
||||
dictionary CameraRecorderOptions
|
||||
{
|
||||
DOMString profile;
|
||||
long rotation;
|
||||
};
|
||||
|
||||
/* These properties affect the actual video recording, e.g.
|
||||
{
|
||||
rotation: 0,
|
||||
maxFileSizeBytes: 1024 * 1024,
|
||||
maxVideoLengthMs: 0
|
||||
}
|
||||
|
||||
'rotation' is the degrees clockwise to rotate the recorded video; if
|
||||
this options is not supported, it will be ignored; if this option is
|
||||
missing, the default is 0.
|
||||
|
||||
'maxFileSizeBytes' is the maximum size in bytes to which the recorded
|
||||
video file will be allowed to grow.
|
||||
|
||||
'maxVideoLengthMs' is the maximum length in milliseconds to which the
|
||||
recorded video will be allowed to grow.
|
||||
|
||||
if either 'maxFileSizeBytes' or 'maxVideoLengthMs' is missing, zero,
|
||||
or negative, that limit will be disabled.
|
||||
*/
|
||||
dictionary CameraStartRecordingOptions
|
||||
{
|
||||
long rotation;
|
||||
long long maxFileSizeBytes;
|
||||
long long maxVideoLengthMs;
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(0444a687-4bc9-462c-8246-5423f0fe46a4)]
|
||||
interface nsICameraPreviewStreamCallback : nsISupports
|
||||
{
|
||||
void handleEvent(in nsIDOMMediaStream stream);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(6baa4ac7-9c25-4c48-9bb0-5193b38b9b0a)]
|
||||
interface nsICameraAutoFocusCallback : nsISupports
|
||||
{
|
||||
void handleEvent(in boolean success);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(17af779e-cb6f-4ca5-890c-06468ff82e4f)]
|
||||
interface nsICameraTakePictureCallback : nsISupports
|
||||
{
|
||||
void handleEvent(in nsIDOMBlob picture);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(89a762f8-581b-410a-ad86-e2bd2113ad82)]
|
||||
interface nsICameraStartRecordingCallback : nsISupports
|
||||
{
|
||||
void handleEvent();
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(fb80db71-e315-42f0-9ea9-dd3dd312ed70)]
|
||||
interface nsICameraShutterCallback : nsISupports
|
||||
{
|
||||
void handleEvent();
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(0ef0f01e-ce74-4741-9bba-54376adfb7a2)]
|
||||
interface nsICameraClosedCallback : nsISupports
|
||||
{
|
||||
void handleEvent();
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(550d675a-257d-4713-8b3d-0da53eba68fc)]
|
||||
interface nsICameraRecorderStateChange : nsISupports
|
||||
{
|
||||
void handleStateChange(in DOMString newState);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(d1634592-43fd-4117-a2b2-419aec841cc4)]
|
||||
interface nsICameraPreviewStateChange : nsISupports
|
||||
{
|
||||
void handleStateChange(in DOMString newState);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(f84d607b-554c-413d-8810-cf848642765a)]
|
||||
interface nsICameraReleaseCallback : nsISupports
|
||||
{
|
||||
void handleEvent();
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(a302c6c9-3776-4d1d-a395-f4105d47c3d3)]
|
||||
interface nsICameraErrorCallback : nsISupports
|
||||
{
|
||||
void handleEvent(in DOMString error);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(16de7703-dc43-4766-99c5-ff30a9ab92d7)]
|
||||
interface nsICameraGetCameraCallback : nsISupports
|
||||
{
|
||||
void handleEvent(in nsISupports camera);
|
||||
};
|
@ -1,3 +1,4 @@
|
||||
[DEFAULT]
|
||||
|
||||
[test_camera.html]
|
||||
[test_camera_2.html]
|
||||
|
@ -1,7 +1,7 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for mozCameras</title>
|
||||
<title>Test for mozCameras.getCamera() with separate .setConfiguration() call</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
@ -11,8 +11,14 @@
|
||||
<img src="#" alt="This image is going to load" id="testimage"/>
|
||||
<script class="testbody" type="text/javascript;version=1.7">
|
||||
|
||||
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||
var options = {
|
||||
camera: navigator.mozCameras.getListOfCameras()[0]
|
||||
mode: 'picture',
|
||||
recorderProfile: 'cif',
|
||||
previewSize: {
|
||||
width: 352,
|
||||
height: 288
|
||||
}
|
||||
};
|
||||
|
||||
var config = {
|
||||
@ -24,6 +30,9 @@ var config = {
|
||||
|
||||
function onError(e) {
|
||||
ok(false, "Error" + JSON.stringify(e));
|
||||
Camera.cameraObj.release();
|
||||
Camera.cameraObj = null;
|
||||
Camera.viewfinder.mozSrcObject = null;
|
||||
}
|
||||
|
||||
var capabilities = [ 'previewSizes', 'pictureSizes', 'fileFormats', 'maxFocusAreas', 'minExposureCompensation',
|
||||
@ -96,7 +105,9 @@ var Camera = {
|
||||
Camera._testsCompleted++;
|
||||
if(Camera._testsCompleted == Camera._tests.length) {
|
||||
ok(true, "test finishing");
|
||||
Camera.cameraObj.release();
|
||||
Camera.cameraObj.release(function() {
|
||||
Camera.cameraObj = null;
|
||||
}, onError);
|
||||
Camera.viewfinder.mozSrcObject = null;
|
||||
SimpleTest.finish();
|
||||
} else {
|
||||
@ -114,27 +125,16 @@ var Camera = {
|
||||
Camera._shutter + " times");
|
||||
|
||||
},
|
||||
streamReady: function onStreamReady (stream) {
|
||||
Camera.viewfinder.mozSrcObject = stream;
|
||||
Camera.viewfinder.play();
|
||||
ok(true, "on Stream is ready and playing");
|
||||
Camera.cameraObj.onPreviewStateChange = function(state) {
|
||||
if (state === 'started') {
|
||||
Camera.cameraObj.onPreviewStateChange = null;
|
||||
Camera.onReady();
|
||||
}
|
||||
};
|
||||
|
||||
//window.setTimeout(Camera.onReady, 500);
|
||||
},
|
||||
onReady: function onReady() {
|
||||
var camcap = Camera.cameraObj.capabilities;
|
||||
var tests = {};
|
||||
for (var prop in capabilities) {
|
||||
prop = capabilities[prop];
|
||||
ok(camcap[prop] || isFinite(camcap[prop]) || camcap[prop] == null, "Camera Capability: " +
|
||||
prop + " is exposed, value = " +JSON.stringify(camcap[prop]));
|
||||
}
|
||||
prop + " is exposed, value = " + JSON.stringify(camcap[prop]));
|
||||
}
|
||||
ok(camcap.maxMeteringAreas >= 0, "maxMeteringAreas = " + camcap.maxMeteringAreas);
|
||||
ok(camcap.maxFocusAreas >= 0, "maxFocusAreas = " + camcap.maxFocusAreas);
|
||||
for (var prop in camcap) {
|
||||
if(camcap[prop] && camcap[prop].length > 1) {
|
||||
tests[prop] = camcap[prop];
|
||||
@ -165,24 +165,34 @@ var Camera = {
|
||||
Camera.setFlashMode(test.flashMode);
|
||||
config.fileFormat = test.fileFormat;
|
||||
config.pictureSize = test.pictureSize;
|
||||
ok(true, JSON.stringify(config.pictureSize));
|
||||
ok(true, "testing picture size " + JSON.stringify(config.pictureSize));
|
||||
Camera.cameraObj.takePicture(config, this.takePictureSuccess.bind(this), onError);
|
||||
},
|
||||
onConfigChange: function onConfigChange(config) {
|
||||
ok(config.mode === options.mode, "configuration mode = " + config.mode);
|
||||
ok(config.recorderProfile === options.recorderProfile, "recorder profile = " + config.recorderProfile);
|
||||
ok(config.previewSize.width === options.previewSize.width &&
|
||||
config.previewSize.height === options.previewSize.height,
|
||||
"preview size (w x h) = " + config.previewSize.width + " x " + config.previewSize.height);
|
||||
},
|
||||
setUp: function setup_tests() {
|
||||
function onSuccess(camera) {
|
||||
Camera.cameraObj = camera;
|
||||
var size = {
|
||||
profile: 'cif',
|
||||
rotation: 0,
|
||||
width: 352,
|
||||
height: 288
|
||||
Camera.viewfinder.mozSrcObject = camera;
|
||||
Camera.viewfinder.play();
|
||||
Camera.cameraObj.onPreviewStateChange = function(state) {
|
||||
if (state === 'started') {
|
||||
ok(true, "viewfinder is ready and playing");
|
||||
Camera.cameraObj.onPreviewStateChange = null;
|
||||
Camera.onReady();
|
||||
}
|
||||
};
|
||||
SimpleTest.expectAssertions(34);
|
||||
SimpleTest.expectAssertions(0);
|
||||
ok(true, "Camera Control object has been successfully initialized");
|
||||
Camera.cameraObj.getPreviewStream(size, Camera.streamReady);
|
||||
Camera.cameraObj.setConfiguration(options, Camera.onConfigChange, onError);
|
||||
Camera.cameraObj.onShutter = Camera.shutter;
|
||||
};
|
||||
navigator.mozCameras.getCamera(options, onSuccess, onError);
|
||||
navigator.mozCameras.getCamera(whichCamera, null, onSuccess, onError);
|
||||
}
|
||||
}
|
||||
|
||||
|
205
dom/camera/test/test_camera_2.html
Normal file
205
dom/camera/test/test_camera_2.html
Normal file
@ -0,0 +1,205 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for mozCameras.getCamera() using an initial configuration</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<video id="viewfinder" |width = "200" height = "200| autoplay></video>
|
||||
<img src="#" alt="This image is going to load" id="testimage"/>
|
||||
<script class="testbody" type="text/javascript;version=1.7">
|
||||
|
||||
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||
var options = {
|
||||
mode: 'picture',
|
||||
recorderProfile: 'cif',
|
||||
previewSize: {
|
||||
width: 352,
|
||||
height: 288
|
||||
}
|
||||
};
|
||||
|
||||
var config = {
|
||||
dateTime: Date.now() / 1000,
|
||||
pictureSize: null,
|
||||
fileFormat: 'jpeg',
|
||||
rotation: 90
|
||||
};
|
||||
|
||||
function onError(e) {
|
||||
ok(false, "Error" + JSON.stringify(e));
|
||||
Camera.cameraObj.release();
|
||||
Camera.cameraObj = null;
|
||||
Camera.viewfinder.mozSrcObject = null;
|
||||
}
|
||||
|
||||
var capabilities = [ 'previewSizes', 'pictureSizes', 'fileFormats', 'maxFocusAreas', 'minExposureCompensation',
|
||||
'maxExposureCompensation', 'stepExposureCompensation', 'maxMeteringAreas', 'videoSizes',
|
||||
'recorderProfiles'];
|
||||
|
||||
var Camera = {
|
||||
cameraObj: null,
|
||||
_recording: false,
|
||||
_currentTest: null,
|
||||
_autoFocusSupported: 0,
|
||||
_manuallyFocused: false,
|
||||
_flashmodes: null,
|
||||
_pictureSizes: null,
|
||||
_previewSizes: null,
|
||||
_whiteBalanceModes: null,
|
||||
_zoomRatios: null,
|
||||
_sceneModes: null,
|
||||
_focusModes: null,
|
||||
_testsCompleted: 0,
|
||||
_shutter: 0,
|
||||
_config: {
|
||||
dateTime: Date.now() / 1000,
|
||||
pictureSize: null,
|
||||
fileFormat: 'jpeg',
|
||||
rotation: 90
|
||||
},
|
||||
_tests: null,
|
||||
get viewfinder() {
|
||||
return document.getElementById('viewfinder');
|
||||
},
|
||||
setFlashMode: function camera_setFlash(mode) {
|
||||
this.cameraObj.flashMode = mode;
|
||||
},
|
||||
setFocus: function camera_setfocus(mode) {
|
||||
this.cameraObj.focus = mode;
|
||||
},
|
||||
getFileFormats: function camera_formats() {
|
||||
this._fileFormats = this.cameraObj.capabilities.fileFormats;
|
||||
},
|
||||
getFlashModes: function camera_getFlash() {
|
||||
this._flashmodes = this.cameraObj.capabilities.flashModes;
|
||||
},
|
||||
getFocusModes: function camera_getFocus() {
|
||||
this._focusModes = this.cameraObj.capabilities.focusModes;
|
||||
},
|
||||
getSceneModes: function camera_getScene() {
|
||||
this._sceneModes = this.cameraObj.capabilities.sceneModes;
|
||||
},
|
||||
getZoomRatios: function camera_getZoom() {
|
||||
this._zoomRatios = this.cameraObj.capabilities.zoomRatios;
|
||||
},
|
||||
getWhiteBalance: function camera_white() {
|
||||
this._whitebalanceModes = this.cameraObj.capabilities.whiteBalanceModes;
|
||||
},
|
||||
getPictureSizes: function camera_sizes() {
|
||||
this._pictureSizes = this.cameraObj.capabilities.pictureSizes;
|
||||
},
|
||||
getPreviewSizes: function camera_preview() {
|
||||
this._previewSizes = this.cameraObj.capabilities.previewSizes;
|
||||
},
|
||||
takePictureSuccess: function taken_foto(blob) {
|
||||
var img = new Image();
|
||||
var test = this._currentTest;
|
||||
img.onload = function Imgsize() {
|
||||
ok(this.width == test.pictureSize.width, "The image taken has the width " +
|
||||
this.width + " pictureSize width = " + test.pictureSize.width);
|
||||
ok(this.height == test.pictureSize.height, "The image taken has the height " +
|
||||
this.height + " picturesize height = " + test.pictureSize.height);
|
||||
Camera._testsCompleted++;
|
||||
if(Camera._testsCompleted == Camera._tests.length) {
|
||||
ok(true, "test finishing");
|
||||
Camera.cameraObj.release(function() {
|
||||
Camera.cameraObj = null;
|
||||
}, onError);
|
||||
Camera.viewfinder.mozSrcObject = null;
|
||||
SimpleTest.finish();
|
||||
} else {
|
||||
Camera.runTests();
|
||||
}
|
||||
}
|
||||
ok(blob.size > 100 , "Blob Size Gathered = " + blob.size);
|
||||
ok("image/" + test.fileFormat == blob.type, "Blob Type = " + blob.type);
|
||||
img.src = window.URL.createObjectURL(blob);
|
||||
},
|
||||
shutter: function onShutter () {
|
||||
Camera._shutter++;
|
||||
|
||||
ok(Camera._shutter == (Camera._testsCompleted + 1), "on Shutter has been called " +
|
||||
Camera._shutter + " times");
|
||||
|
||||
},
|
||||
onReady: function onReady() {
|
||||
var camcap = Camera.cameraObj.capabilities;
|
||||
var tests = {};
|
||||
for (var prop in capabilities) {
|
||||
prop = capabilities[prop];
|
||||
ok(camcap[prop] || isFinite(camcap[prop]) || camcap[prop] == null, "Camera Capability: " +
|
||||
prop + " is exposed, value = " + JSON.stringify(camcap[prop]));
|
||||
}
|
||||
for (var prop in camcap) {
|
||||
if(camcap[prop] && camcap[prop].length > 1) {
|
||||
tests[prop] = camcap[prop];
|
||||
}
|
||||
}
|
||||
Camera.getPictureSizes();
|
||||
Camera.getPreviewSizes();
|
||||
Camera.getFileFormats();
|
||||
Camera.getFocusModes();
|
||||
ok(Camera._previewSizes.length > 0, "previewSizes length = " + Camera._previewSizes.length);
|
||||
ok(Camera._pictureSizes.length > 0, "picturesizes length = " + Camera._pictureSizes.length);
|
||||
ok(Camera._fileFormats.length > 0, "file formats length = " + Camera._fileFormats.length);
|
||||
Camera._tests = new Array();
|
||||
for (var i in Camera._pictureSizes) {
|
||||
for (var l in Camera._fileFormats) {
|
||||
var config = {
|
||||
pictureSize: Camera._pictureSizes[i],
|
||||
fileFormat: Camera._fileFormats[l]
|
||||
};
|
||||
Camera._tests.push(config);
|
||||
}
|
||||
}
|
||||
Camera.runTests();
|
||||
},
|
||||
runTests: function run_tests() {
|
||||
var test = this._tests[this._testsCompleted];
|
||||
this._currentTest = test;
|
||||
Camera.setFlashMode(test.flashMode);
|
||||
config.fileFormat = test.fileFormat;
|
||||
config.pictureSize = test.pictureSize;
|
||||
ok(true, "testing picture size " + JSON.stringify(config.pictureSize));
|
||||
Camera.cameraObj.takePicture(config, this.takePictureSuccess.bind(this), onError);
|
||||
},
|
||||
setUp: function setup_tests() {
|
||||
function onSuccess(camera, config) {
|
||||
ok(true, "Camera Control object has been successfully initialized");
|
||||
ok(config.mode === options.mode, "configuration mode = " + config.mode);
|
||||
ok(config.recorderProfile === options.recorderProfile, "recorder profile = " + config.recorderProfile);
|
||||
ok(config.previewSize.width === options.previewSize.width &&
|
||||
config.previewSize.height === options.previewSize.height,
|
||||
"preview size (w x h) = " + config.previewSize.width + " x " + config.previewSize.height);
|
||||
Camera.cameraObj = camera;
|
||||
Camera.viewfinder.mozSrcObject = camera;
|
||||
Camera.viewfinder.play();
|
||||
Camera.cameraObj.onPreviewStateChange = function(state) {
|
||||
if (state === 'started') {
|
||||
ok(true, "viewfinder is ready and playing");
|
||||
Camera.cameraObj.onPreviewStateChange = null;
|
||||
Camera.onReady();
|
||||
}
|
||||
};
|
||||
SimpleTest.expectAssertions(0);
|
||||
Camera.cameraObj.onShutter = Camera.shutter;
|
||||
};
|
||||
navigator.mozCameras.getCamera(whichCamera, options, onSuccess, onError);
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
window.addEventListener('beforeunload', function() {
|
||||
Camera.viewfinder.mozSrcObject = null;
|
||||
});
|
||||
|
||||
Camera.setUp();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1496,11 +1496,7 @@ MediaManager::GetBackend(uint64_t aWindowId)
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mBackend) {
|
||||
#if defined(MOZ_WEBRTC)
|
||||
#ifndef MOZ_B2G_CAMERA
|
||||
mBackend = new MediaEngineWebRTC(mPrefs);
|
||||
#else
|
||||
mBackend = new MediaEngineWebRTC(mCameraManager, aWindowId);
|
||||
#endif
|
||||
#else
|
||||
mBackend = new MediaEngineDefault();
|
||||
#endif
|
||||
|
33
dom/webidl/CameraCapabilities.webidl
Normal file
33
dom/webidl/CameraCapabilities.webidl
Normal file
@ -0,0 +1,33 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
interface CameraCapabilities
|
||||
{
|
||||
[Constant, Cached] readonly attribute sequence<CameraSize> previewSizes;
|
||||
[Constant, Cached] readonly attribute sequence<CameraSize> pictureSizes;
|
||||
[Constant, Cached] readonly attribute sequence<CameraSize> thumbnailSizes;
|
||||
[Constant, Cached] readonly attribute sequence<CameraSize> videoSizes;
|
||||
|
||||
[Constant, Cached] readonly attribute sequence<DOMString> fileFormats;
|
||||
|
||||
[Constant, Cached] readonly attribute sequence<DOMString> whiteBalanceModes;
|
||||
[Constant, Cached] readonly attribute sequence<DOMString> sceneModes;
|
||||
[Constant, Cached] readonly attribute sequence<DOMString> effects;
|
||||
[Constant, Cached] readonly attribute sequence<DOMString> flashModes;
|
||||
[Constant, Cached] readonly attribute sequence<DOMString> focusModes;
|
||||
|
||||
[Constant, Cached] readonly attribute sequence<double> zoomRatios;
|
||||
|
||||
[Constant, Cached] readonly attribute unsigned long maxFocusAreas;
|
||||
[Constant, Cached] readonly attribute unsigned long maxMeteringAreas;
|
||||
|
||||
[Constant, Cached] readonly attribute double minExposureCompensation;
|
||||
[Constant, Cached] readonly attribute double maxExposureCompensation;
|
||||
[Constant, Cached] readonly attribute double exposureCompensationStep;
|
||||
|
||||
[Constant, Cached] readonly attribute any recorderProfiles;
|
||||
};
|
@ -5,213 +5,328 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
interface CameraCapabilities;
|
||||
interface GetCameraCallback;
|
||||
interface CameraErrorCallback;
|
||||
interface CameraShutterCallback;
|
||||
interface CameraClosedCallback;
|
||||
interface CameraRecorderStateChange;
|
||||
interface CameraAutoFocusCallback;
|
||||
interface CameraTakePictureCallback;
|
||||
interface CameraPreviewStateChange;
|
||||
interface CameraPreviewStreamCallback;
|
||||
interface CameraStartRecordingCallback;
|
||||
interface CameraReleaseCallback;
|
||||
/* Camera regions are used to set focus and metering areas;
|
||||
the coordinates are referenced to the sensor:
|
||||
(-1000, -1000) is the top-left corner
|
||||
(1000, 1000) is the bottom-right corner
|
||||
The weight of the region can range from 0 to 1000. */
|
||||
dictionary CameraRegion
|
||||
{
|
||||
long top = -1000;
|
||||
long left = -1000;
|
||||
long bottom = 1000;
|
||||
long right = 1000;
|
||||
unsigned long weight = 1000;
|
||||
};
|
||||
|
||||
/* The position information to record in the image header.
|
||||
'NaN' indicates the information is not available. */
|
||||
dictionary CameraPosition
|
||||
{
|
||||
unrestricted double latitude = NaN;
|
||||
unrestricted double longitude = NaN;
|
||||
unrestricted double altitude = NaN;
|
||||
unrestricted double timestamp = NaN;
|
||||
};
|
||||
|
||||
/*
|
||||
Options for takePicture().
|
||||
*/
|
||||
dictionary CameraPictureOptions
|
||||
{
|
||||
/* an object with a combination of 'height' and 'width' properties
|
||||
chosen from CameraCapabilities.pictureSizes */
|
||||
CameraSize pictureSize = null;
|
||||
|
||||
/* one of the file formats chosen from
|
||||
CameraCapabilities.fileFormats */
|
||||
DOMString fileFormat = "";
|
||||
|
||||
/* the rotation of the image in degrees, from 0 to 270 in
|
||||
steps of 90; this doesn't affect the image, only the
|
||||
rotation recorded in the image header.*/
|
||||
long rotation = 0;
|
||||
|
||||
/* an object containing any or all of 'latitude', 'longitude',
|
||||
'altitude', and 'timestamp', used to record when and where
|
||||
the image was taken. e.g.
|
||||
{
|
||||
latitude: 43.647118,
|
||||
longitude: -79.3943,
|
||||
altitude: 500
|
||||
// timestamp not specified, in this case, and
|
||||
// won't be included in the image header
|
||||
}
|
||||
|
||||
can be null in the case where position information isn't
|
||||
available/desired.
|
||||
|
||||
'altitude' is in metres; 'timestamp' is UTC, in seconds from
|
||||
January 1, 1970.
|
||||
*/
|
||||
CameraPosition position = null;
|
||||
|
||||
/* the number of seconds from January 1, 1970 UTC. This can be
|
||||
different from the positional timestamp (above). */
|
||||
// XXXbz this should really accept a date too, no?
|
||||
long long dateTime = 0;
|
||||
};
|
||||
|
||||
/* These properties affect the video recording preview, e.g.
|
||||
{
|
||||
profile: "1080p",
|
||||
rotation: 0
|
||||
}
|
||||
|
||||
'profile' is one of the profiles returned by
|
||||
CameraCapabilities.recorderProfiles'; if this profile is missing,
|
||||
an arbitrary profile will be chosen.
|
||||
|
||||
'rotation' is the degrees clockwise to rotate the preview; if
|
||||
this option is not supported, it will be ignored; if this option
|
||||
is missing, the default is 0.
|
||||
*/
|
||||
dictionary CameraRecorderOptions
|
||||
{
|
||||
DOMString profile;
|
||||
long rotation;
|
||||
};
|
||||
|
||||
/* These properties affect the actual video recording, e.g.
|
||||
{
|
||||
rotation: 0,
|
||||
maxFileSizeBytes: 1024 * 1024,
|
||||
maxVideoLengthMs: 0
|
||||
}
|
||||
|
||||
'rotation' is the degrees clockwise to rotate the recorded video; if
|
||||
this options is not supported, it will be ignored; if this option is
|
||||
missing, the default is 0.
|
||||
|
||||
'maxFileSizeBytes' is the maximum size in bytes to which the recorded
|
||||
video file will be allowed to grow.
|
||||
|
||||
'maxVideoLengthMs' is the maximum length in milliseconds to which the
|
||||
recorded video will be allowed to grow.
|
||||
|
||||
if either 'maxFileSizeBytes' or 'maxVideoLengthMs' is missing, zero,
|
||||
or negative, that limit will be disabled.
|
||||
*/
|
||||
dictionary CameraStartRecordingOptions
|
||||
{
|
||||
long rotation = 0;
|
||||
long long maxFileSizeBytes = 0;
|
||||
long long maxVideoLengthMs = 0;
|
||||
};
|
||||
|
||||
callback CameraSetConfigurationCallback = void (CameraConfiguration configuration);
|
||||
callback CameraAutoFocusCallback = void (boolean focused);
|
||||
callback CameraTakePictureCallback = void (Blob picture);
|
||||
callback CameraStartRecordingCallback = void ();
|
||||
callback CameraShutterCallback = void ();
|
||||
callback CameraClosedCallback = void ();
|
||||
callback CameraReleaseCallback = void ();
|
||||
callback CameraRecorderStateChange = void (DOMString newState);
|
||||
callback CameraPreviewStateChange = void (DOMString newState);
|
||||
|
||||
/*
|
||||
attributes here affect the preview, any pictures taken, and/or
|
||||
any video recorded by the camera.
|
||||
*/
|
||||
interface CameraControl {
|
||||
readonly attribute CameraCapabilities capabilities;
|
||||
interface CameraControl : MediaStream
|
||||
{
|
||||
[Constant, Cached]
|
||||
readonly attribute CameraCapabilities capabilities;
|
||||
|
||||
/* one of the values chosen from capabilities.effects;
|
||||
default is "none" */
|
||||
[Throws]
|
||||
attribute DOMString effect;
|
||||
/* one of the values chosen from capabilities.effects;
|
||||
default is "none" */
|
||||
[Throws]
|
||||
attribute DOMString effect;
|
||||
|
||||
/* one of the values chosen from capabilities.whiteBalanceModes;
|
||||
default is "auto" */
|
||||
[Throws]
|
||||
attribute DOMString whiteBalanceMode;
|
||||
/* one of the values chosen from capabilities.whiteBalanceModes;
|
||||
default is "auto" */
|
||||
[Throws]
|
||||
attribute DOMString whiteBalanceMode;
|
||||
|
||||
/* one of the values chosen from capabilities.sceneModes;
|
||||
default is "auto" */
|
||||
[Throws]
|
||||
attribute DOMString sceneMode;
|
||||
/* one of the values chosen from capabilities.sceneModes;
|
||||
default is "auto" */
|
||||
[Throws]
|
||||
attribute DOMString sceneMode;
|
||||
|
||||
/* one of the values chosen from capabilities.flashModes;
|
||||
default is "auto" */
|
||||
[Throws]
|
||||
attribute DOMString flashMode;
|
||||
/* one of the values chosen from capabilities.flashModes;
|
||||
default is "auto" */
|
||||
[Throws]
|
||||
attribute DOMString flashMode;
|
||||
|
||||
/* one of the values chosen from capabilities.focusModes;
|
||||
default is "auto", if supported, or "fixed" */
|
||||
[Throws]
|
||||
attribute DOMString focusMode;
|
||||
/* one of the values chosen from capabilities.focusModes;
|
||||
default is "auto", if supported, or "fixed" */
|
||||
[Throws]
|
||||
attribute DOMString focusMode;
|
||||
|
||||
/* one of the values chosen from capabilities.zoomRatios; other
|
||||
values will be rounded to the nearest supported value;
|
||||
default is 1.0 */
|
||||
[Throws]
|
||||
attribute double zoom;
|
||||
/* one of the values chosen from capabilities.zoomRatios; other
|
||||
values will be rounded to the nearest supported value;
|
||||
default is 1.0 */
|
||||
[Throws]
|
||||
attribute double zoom;
|
||||
|
||||
/* an array of one or more objects that define where the
|
||||
camera will perform light metering, each defining the properties:
|
||||
{
|
||||
top: -1000,
|
||||
left: -1000,
|
||||
bottom: 1000,
|
||||
right: 1000,
|
||||
weight: 1000
|
||||
}
|
||||
/* an array of one or more objects that define where the
|
||||
camera will perform light metering, each defining the properties:
|
||||
{
|
||||
top: -1000,
|
||||
left: -1000,
|
||||
bottom: 1000,
|
||||
right: 1000,
|
||||
weight: 1000
|
||||
}
|
||||
|
||||
'top', 'left', 'bottom', and 'right' all range from -1000 at
|
||||
the top-/leftmost of the sensor to 1000 at the bottom-/rightmost
|
||||
of the sensor.
|
||||
'top', 'left', 'bottom', and 'right' all range from -1000 at
|
||||
the top-/leftmost of the sensor to 1000 at the bottom-/rightmost
|
||||
of the sensor.
|
||||
|
||||
objects missing one or more of these properties will be ignored;
|
||||
if the array contains more than capabilities.maxMeteringAreas,
|
||||
extra areas will be ignored.
|
||||
objects missing one or more of these properties will be ignored;
|
||||
if the array contains more than capabilities.maxMeteringAreas,
|
||||
extra areas will be ignored.
|
||||
|
||||
this attribute can be set to null to allow the camera to determine
|
||||
where to perform light metering. */
|
||||
[Throws]
|
||||
attribute any meteringAreas;
|
||||
this attribute can be set to null to allow the camera to determine
|
||||
where to perform light metering. */
|
||||
[Throws]
|
||||
attribute any meteringAreas;
|
||||
|
||||
/* an array of one or more objects that define where the camera will
|
||||
perform auto-focusing, with the same definition as meteringAreas.
|
||||
/* an array of one or more objects that define where the camera will
|
||||
perform auto-focusing, with the same definition as meteringAreas.
|
||||
|
||||
if the array contains more than capabilities.maxFocusAreas, extra
|
||||
areas will be ignored.
|
||||
if the array contains more than capabilities.maxFocusAreas, extra
|
||||
areas will be ignored.
|
||||
|
||||
this attribute can be set to null to allow the camera to determine
|
||||
where to focus. */
|
||||
[Throws]
|
||||
attribute any focusAreas;
|
||||
this attribute can be set to null to allow the camera to determine
|
||||
where to focus. */
|
||||
[Throws]
|
||||
attribute any focusAreas;
|
||||
|
||||
/* focal length in millimetres */
|
||||
[Throws]
|
||||
readonly attribute double focalLength;
|
||||
/* focal length in millimetres */
|
||||
[Throws]
|
||||
readonly attribute double focalLength;
|
||||
|
||||
/* the distances in metres to where the image subject appears to be
|
||||
in focus. 'focusDistanceOptimum' is where the subject will appear
|
||||
sharpest; the difference between 'focusDistanceFar' and
|
||||
'focusDistanceNear' is the image's depth of field.
|
||||
/* the distances in metres to where the image subject appears to be
|
||||
in focus. 'focusDistanceOptimum' is where the subject will appear
|
||||
sharpest; the difference between 'focusDistanceFar' and
|
||||
'focusDistanceNear' is the image's depth of field.
|
||||
|
||||
'focusDistanceFar' may be infinity. */
|
||||
[Throws]
|
||||
readonly attribute double focusDistanceNear;
|
||||
[Throws]
|
||||
readonly attribute double focusDistanceOptimum;
|
||||
[Throws]
|
||||
readonly attribute unrestricted double focusDistanceFar;
|
||||
'focusDistanceFar' may be infinity. */
|
||||
[Throws]
|
||||
readonly attribute double focusDistanceNear;
|
||||
[Throws]
|
||||
readonly attribute double focusDistanceOptimum;
|
||||
[Throws]
|
||||
readonly attribute unrestricted double focusDistanceFar;
|
||||
|
||||
/* 'compensation' is optional, and if missing, will
|
||||
set the camera to use automatic exposure compensation.
|
||||
/* 'compensation' is optional, and if missing, will
|
||||
set the camera to use automatic exposure compensation.
|
||||
|
||||
acceptable values must range from minExposureCompensation
|
||||
to maxExposureCompensation in steps of stepExposureCompensation;
|
||||
invalid values will be rounded to the nearest valid value. */
|
||||
[Throws]
|
||||
void setExposureCompensation(optional double compensation);
|
||||
[Throws]
|
||||
readonly attribute unrestricted double exposureCompensation;
|
||||
acceptable values must range from minExposureCompensation
|
||||
to maxExposureCompensation in steps of stepExposureCompensation;
|
||||
invalid values will be rounded to the nearest valid value. */
|
||||
[Throws]
|
||||
void setExposureCompensation(optional double compensation);
|
||||
[Throws]
|
||||
readonly attribute unrestricted double exposureCompensation;
|
||||
|
||||
/* the function to call on the camera's shutter event, to trigger
|
||||
a shutter sound and/or a visual shutter indicator. */
|
||||
[Throws]
|
||||
attribute CameraShutterCallback? onShutter;
|
||||
/* the function to call on the camera's shutter event, to trigger
|
||||
a shutter sound and/or a visual shutter indicator. */
|
||||
attribute CameraShutterCallback? onShutter;
|
||||
|
||||
/* the function to call when the camera hardware is closed
|
||||
by the underlying framework, e.g. when another app makes a more
|
||||
recent call to get the camera. */
|
||||
[Throws]
|
||||
attribute CameraClosedCallback? onClosed;
|
||||
/* the function to call when the camera hardware is closed
|
||||
by the underlying framework, e.g. when another app makes a more
|
||||
recent call to get the camera. */
|
||||
attribute CameraClosedCallback? onClosed;
|
||||
|
||||
/* the function to call when the recorder changes state, either because
|
||||
the recording process encountered an error, or because one of the
|
||||
recording limits (see CameraStartRecordingOptions) was reached. */
|
||||
[Throws]
|
||||
attribute CameraRecorderStateChange? onRecorderStateChange;
|
||||
attribute CameraPreviewStateChange? onPreviewStateChange;
|
||||
/* the function to call when the recorder changes state, either because
|
||||
the recording process encountered an error, or because one of the
|
||||
recording limits (see CameraStartRecordingOptions) was reached. */
|
||||
attribute CameraRecorderStateChange? onRecorderStateChange;
|
||||
|
||||
/* the size of the picture to be returned by a call to takePicture();
|
||||
an object with 'height' and 'width' properties that corresponds to
|
||||
one of the options returned by capabilities.pictureSizes. */
|
||||
[Throws]
|
||||
attribute any pictureSize;
|
||||
/* the function to call when the viewfinder stops or starts,
|
||||
useful for synchronizing other UI elements. */
|
||||
attribute CameraPreviewStateChange? onPreviewStateChange;
|
||||
|
||||
/* the size of the thumbnail to be included in the picture returned
|
||||
by a call to takePicture(), assuming the chose fileFormat supports
|
||||
one; an object with 'height' and 'width' properties that corresponds
|
||||
to one of the options returned by capabilities.pictureSizes.
|
||||
|
||||
this setting should be considered a hint: the implementation will
|
||||
respect it when possible, and override it if necessary. */
|
||||
[Throws]
|
||||
attribute any thumbnailSize;
|
||||
/* the size of the picture to be returned by a call to takePicture();
|
||||
an object with 'height' and 'width' properties that corresponds to
|
||||
one of the options returned by capabilities.pictureSizes. */
|
||||
[Throws]
|
||||
attribute any pictureSize;
|
||||
|
||||
/* the angle, in degrees, that the image sensor is mounted relative
|
||||
to the display; e.g. if 'sensorAngle' is 270 degrees (or -90 degrees),
|
||||
then the preview stream needs to be rotated +90 degrees to have the
|
||||
same orientation as the real world. */
|
||||
readonly attribute long sensorAngle;
|
||||
/* the size of the thumbnail to be included in the picture returned
|
||||
by a call to takePicture(), assuming the chosen fileFormat supports
|
||||
one; an object with 'height' and 'width' properties that corresponds
|
||||
to one of the options returned by capabilities.pictureSizes.
|
||||
|
||||
/* tell the camera to attempt to focus the image */
|
||||
[Throws]
|
||||
void autoFocus(CameraAutoFocusCallback onSuccess, optional CameraErrorCallback onError);
|
||||
this setting should be considered a hint: the implementation will
|
||||
respect it when possible, and override it if necessary. */
|
||||
[Throws]
|
||||
attribute any thumbnailSize;
|
||||
|
||||
/* capture an image and return it as a blob to the 'onSuccess' callback;
|
||||
if the camera supports it, this may be invoked while the camera is
|
||||
already recording video.
|
||||
/* the angle, in degrees, that the image sensor is mounted relative
|
||||
to the display; e.g. if 'sensorAngle' is 270 degrees (or -90 degrees),
|
||||
then the preview stream needs to be rotated +90 degrees to have the
|
||||
same orientation as the real world. */
|
||||
readonly attribute long sensorAngle;
|
||||
|
||||
invoking this function will stop the preview stream, which must be
|
||||
manually restarted (e.g. by calling .play() on it). */
|
||||
[Throws]
|
||||
void takePicture(CameraPictureOptions aOptions,
|
||||
CameraTakePictureCallback onSuccess,
|
||||
optional CameraErrorCallback onError);
|
||||
/* tell the camera to attempt to focus the image */
|
||||
[Throws]
|
||||
void autoFocus(CameraAutoFocusCallback onSuccess, optional CameraErrorCallback onError);
|
||||
|
||||
/* get a media stream to be used as a camera viewfinder in video mode;
|
||||
'aOptions' is an CameraRecorderOptions object. */
|
||||
[Throws]
|
||||
void getPreviewStreamVideoMode(any aOptions, CameraPreviewStreamCallback onSuccess, optional CameraErrorCallback onError);
|
||||
/* capture an image and return it as a blob to the 'onSuccess' callback;
|
||||
if the camera supports it, this may be invoked while the camera is
|
||||
already recording video.
|
||||
|
||||
/* start recording video; 'aOptions' is a
|
||||
CameraStartRecordingOptions object. */
|
||||
[Throws]
|
||||
void startRecording(any aOptions, DeviceStorage storageArea, DOMString filename, CameraStartRecordingCallback onSuccess, optional CameraErrorCallback onError);
|
||||
invoking this function will stop the preview stream, which must be
|
||||
manually restarted (e.g. by calling .play() on it). */
|
||||
[Throws]
|
||||
void takePicture(CameraPictureOptions aOptions,
|
||||
CameraTakePictureCallback onSuccess,
|
||||
optional CameraErrorCallback onError);
|
||||
|
||||
/* stop precording video. */
|
||||
[Throws]
|
||||
void stopRecording();
|
||||
/* start recording video; 'aOptions' is a
|
||||
CameraStartRecordingOptions object. */
|
||||
[Throws]
|
||||
void startRecording(CameraStartRecordingOptions aOptions,
|
||||
DeviceStorage storageArea,
|
||||
DOMString filename,
|
||||
CameraStartRecordingCallback onSuccess,
|
||||
optional CameraErrorCallback onError);
|
||||
|
||||
/* get a media stream to be used as a camera viewfinder; the options
|
||||
define the desired frame size of the preview, chosen from
|
||||
capabilities.previewSizes, e.g.:
|
||||
{
|
||||
height: 640,
|
||||
width: 480,
|
||||
}
|
||||
*/
|
||||
[Throws]
|
||||
void getPreviewStream(any aOptions, CameraPreviewStreamCallback onSuccess, optional CameraErrorCallback onError);
|
||||
/* stop precording video. */
|
||||
[Throws]
|
||||
void stopRecording();
|
||||
|
||||
/* call in or after the takePicture() onSuccess callback to
|
||||
resume the camera preview stream. */
|
||||
[Throws]
|
||||
void resumePreview();
|
||||
/* call in or after the takePicture() onSuccess callback to
|
||||
resume the camera preview stream. */
|
||||
[Throws]
|
||||
void resumePreview();
|
||||
|
||||
/* release the camera so that other applications can use it; you should
|
||||
probably call this whenever the camera is not longer in the foreground
|
||||
(depending on your usage model).
|
||||
/* release the camera so that other applications can use it; you should
|
||||
probably call this whenever the camera is not longer in the foreground
|
||||
(depending on your usage model).
|
||||
|
||||
the callbacks are optional, unless you really need to know when
|
||||
the hardware is ultimately released.
|
||||
the callbacks are optional, unless you really need to know when
|
||||
the hardware is ultimately released.
|
||||
|
||||
once this is called, the camera control object is to be considered
|
||||
defunct; a new instance will need to be created to access the camera. */
|
||||
[Throws]
|
||||
void release(optional CameraReleaseCallback onSuccess, optional CameraErrorCallback onError);
|
||||
once this is called, the camera control object is to be considered
|
||||
defunct; a new instance will need to be created to access the camera. */
|
||||
[Throws]
|
||||
void release(optional CameraReleaseCallback onSuccess,
|
||||
optional CameraErrorCallback onError);
|
||||
|
||||
/* changes the camera configuration on the fly;
|
||||
'configuration' is of type CameraConfiguration.
|
||||
|
||||
XXXmikeh the 'configuration' argument needs to be optional, else
|
||||
the WebIDL compiler throws: "WebIDL.WebIDLError: error: Dictionary
|
||||
argument or union argument containing a dictionary not followed by
|
||||
a required argument must be optional"
|
||||
*/
|
||||
[Throws]
|
||||
void setConfiguration(optional CameraConfiguration configuration,
|
||||
optional CameraSetConfigurationCallback onSuccess,
|
||||
optional CameraErrorCallback onError);
|
||||
};
|
||||
|
@ -5,70 +5,43 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
dictionary CameraPictureOptions {
|
||||
enum CameraMode { "picture", "video" };
|
||||
|
||||
/* an object with a combination of 'height' and 'width' properties
|
||||
chosen from nsICameraCapabilities.pictureSizes */
|
||||
// XXXbz this should be a CameraSize dictionary, but we don't have that yet.
|
||||
any pictureSize = null;
|
||||
/* Used for the dimensions of a captured picture,
|
||||
a preview stream, a video capture stream, etc. */
|
||||
dictionary CameraSize
|
||||
{
|
||||
unsigned long width = 0;
|
||||
unsigned long height = 0;
|
||||
};
|
||||
|
||||
/* one of the file formats chosen from
|
||||
nsICameraCapabilities.fileFormats */
|
||||
DOMString fileFormat = "";
|
||||
/* Pre-emptive camera configuration options. */
|
||||
dictionary CameraConfiguration
|
||||
{
|
||||
CameraMode mode = "picture";
|
||||
CameraSize previewSize = null;
|
||||
DOMString recorderProfile = "cif"; // or some other recording profile
|
||||
// supported by the CameraControl
|
||||
};
|
||||
|
||||
/* the rotation of the image in degrees, from 0 to 270 in
|
||||
steps of 90; this doesn't affect the image, only the
|
||||
rotation recorded in the image header.*/
|
||||
long rotation = 0;
|
||||
callback CameraErrorCallback = void (DOMString error);
|
||||
|
||||
/* an object containing any or all of 'latitude', 'longitude',
|
||||
'altitude', and 'timestamp', used to record when and where
|
||||
the image was taken. e.g.
|
||||
{
|
||||
latitude: 43.647118,
|
||||
longitude: -79.3943,
|
||||
altitude: 500
|
||||
// timestamp not specified, in this case, and
|
||||
// won't be included in the image header
|
||||
}
|
||||
callback GetCameraCallback = void (CameraControl camera,
|
||||
CameraConfiguration configuration);
|
||||
|
||||
can be null in the case where position information isn't
|
||||
available/desired.
|
||||
|
||||
'altitude' is in metres; 'timestamp' is UTC, in seconds from
|
||||
January 1, 1970.
|
||||
interface CameraManager
|
||||
{
|
||||
/* get a camera instance; 'camera' is one of the camera
|
||||
identifiers returned by getListOfCameras() below.
|
||||
*/
|
||||
any position = null;
|
||||
|
||||
/* the number of seconds from January 1, 1970 UTC. This can be
|
||||
different from the positional timestamp (above). */
|
||||
// XXXbz this should really accept a date too, no?
|
||||
long long dateTime = 0;
|
||||
};
|
||||
|
||||
// If we start using CameraPictureOptions here, remove it from DummyBinding.
|
||||
|
||||
interface GetCameraCallback;
|
||||
interface CameraErrorCallback;
|
||||
|
||||
/* Select a camera to use. */
|
||||
dictionary CameraSelector {
|
||||
DOMString camera = "back";
|
||||
};
|
||||
|
||||
interface CameraManager {
|
||||
/* get a camera instance; options will be used to specify which
|
||||
camera to get from the list returned by getListOfCameras(), e.g.:
|
||||
{
|
||||
camera: "front"
|
||||
}
|
||||
*/
|
||||
[Throws]
|
||||
void getCamera(CameraSelector options, GetCameraCallback callback,
|
||||
void getCamera(DOMString camera,
|
||||
CameraConfiguration initialConfiguration,
|
||||
GetCameraCallback callback,
|
||||
optional CameraErrorCallback errorCallback);
|
||||
|
||||
/* return an array of camera identifiers, e.g.
|
||||
[ "front", "back" ]
|
||||
/* return an array of camera identifiers, e.g.
|
||||
[ "front", "back" ]
|
||||
*/
|
||||
[Throws]
|
||||
sequence<DOMString> getListOfCameras();
|
||||
|
@ -41,6 +41,7 @@ WEBIDL_FILES = [
|
||||
'BrowserElementDictionaries.webidl',
|
||||
'CallEvent.webidl',
|
||||
'CallsList.webidl',
|
||||
'CameraCapabilities.webidl',
|
||||
'CameraControl.webidl',
|
||||
'CameraManager.webidl',
|
||||
'CanvasRenderingContext2D.webidl',
|
||||
|
@ -4,11 +4,6 @@
|
||||
|
||||
# Dictionary interface name, interface file name
|
||||
dictionaries = [
|
||||
[ 'CameraSize', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'CameraRegion', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'CameraPosition', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'CameraSelector', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'CameraRecordingOptions', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'SmsThreadListItem', 'nsIMobileMessageCallback.idl' ],
|
||||
[ 'MmsAttachment', 'nsIDOMMozMmsMessage.idl' ]
|
||||
]
|
||||
|
@ -135,7 +135,6 @@
|
||||
@BINPATH@/components/dom.xpt
|
||||
@BINPATH@/components/dom_apps.xpt
|
||||
@BINPATH@/components/dom_base.xpt
|
||||
@BINPATH@/components/dom_camera.xpt
|
||||
@BINPATH@/components/dom_canvas.xpt
|
||||
@BINPATH@/components/dom_core.xpt
|
||||
@BINPATH@/components/dom_css.xpt
|
||||
|
@ -460,7 +460,6 @@
|
||||
"dom/apps/tests/test_packaged_app_update.html": "debug-only timeout",
|
||||
"dom/apps/tests/test_uninstall_errors.html": "debug-only timeout",
|
||||
"dom/bindings/test/test_exceptions_from_jsimplemented.html": "debug-only failure; bug 926547",
|
||||
"dom/camera/test/test_camera.html": "debug-only failure; no assertions when 34 were expected",
|
||||
"dom/contacts/tests/test_contacts_basics.html": "debug-only failure",
|
||||
"dom/contacts/tests/test_contacts_getall.html": "debug-only failure",
|
||||
"dom/datastore/tests/test_arrays.html": "debug-only failure; time out",
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
* Copyright (C) 2012 Mozilla Foundation
|
||||
* Copyright (C) 2012-2013 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -37,12 +37,12 @@ using namespace mozilla::gfx;
|
||||
using namespace mozilla::layers;
|
||||
|
||||
GonkNativeWindow::GonkNativeWindow() :
|
||||
mAbandoned(false),
|
||||
mDefaultWidth(1),
|
||||
mDefaultHeight(1),
|
||||
mPixelFormat(PIXEL_FORMAT_RGBA_8888),
|
||||
mBufferCount(MIN_BUFFER_SLOTS + 1),
|
||||
mConnectedApi(NO_CONNECTED_API),
|
||||
mAbandoned(false),
|
||||
mFrameCounter(0),
|
||||
mGeneration(0),
|
||||
mNewFrameCallback(nullptr) {
|
||||
@ -108,6 +108,7 @@ void GonkNativeWindow::releaseBufferFreeListUnlocked(nsTArray<SurfaceDescriptor>
|
||||
void GonkNativeWindow::clearRenderingStateBuffersLocked()
|
||||
{
|
||||
++mGeneration;
|
||||
CNW_LOGD("clearRenderingStateBuffersLocked: mGeneration=%d\n", mGeneration);
|
||||
|
||||
for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
|
||||
if (mSlots[i].mGraphicBuffer != NULL) {
|
||||
@ -244,22 +245,33 @@ status_t GonkNativeWindow::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
|
||||
renderingCount = 0;
|
||||
for (int i = 0; i < mBufferCount; i++) {
|
||||
const int state = mSlots[i].mBufferState;
|
||||
if (state == BufferSlot::DEQUEUED) {
|
||||
dequeuedCount++;
|
||||
}
|
||||
else if (state == BufferSlot::RENDERING) {
|
||||
renderingCount++;
|
||||
}
|
||||
else if (state == BufferSlot::FREE) {
|
||||
/* We return the oldest of the free buffers to avoid
|
||||
* stalling the producer if possible. This is because
|
||||
* the consumer may still have pending reads of the
|
||||
* buffers in flight.
|
||||
*/
|
||||
if (found < 0 ||
|
||||
mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
|
||||
found = i;
|
||||
}
|
||||
switch (state) {
|
||||
case BufferSlot::DEQUEUED:
|
||||
CNW_LOGD("dequeueBuffer: slot %d is DEQUEUED\n", i);
|
||||
dequeuedCount++;
|
||||
break;
|
||||
|
||||
case BufferSlot::RENDERING:
|
||||
CNW_LOGD("dequeueBuffer: slot %d is RENDERING\n", i);
|
||||
renderingCount++;
|
||||
break;
|
||||
|
||||
case BufferSlot::FREE:
|
||||
CNW_LOGD("dequeueBuffer: slot %d is FREE\n", i);
|
||||
/* We return the oldest of the free buffers to avoid
|
||||
* stalling the producer if possible. This is because
|
||||
* the consumer may still have pending reads of the
|
||||
* buffers in flight.
|
||||
*/
|
||||
if (found < 0 ||
|
||||
mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
|
||||
found = i;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
CNW_LOGD("dequeueBuffer: slot %d is %d\n", i, state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -330,10 +342,10 @@ status_t GonkNativeWindow::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
|
||||
// after trying to create the surface descriptor below.
|
||||
//
|
||||
// So we don't need mMutex locked, which would otherwise run the risk
|
||||
// of a deadlock on calling AllocSurfaceDescriptorGralloc().
|
||||
// of a deadlock on calling AllocSurfaceDescriptorGralloc().
|
||||
|
||||
SurfaceDescriptor desc;
|
||||
ImageBridgeChild* ibc;
|
||||
ImageBridgeChild* ibc = nullptr;
|
||||
sp<GraphicBuffer> graphicBuffer;
|
||||
if (alloc) {
|
||||
usage |= GraphicBuffer::USAGE_HW_TEXTURE;
|
||||
@ -437,6 +449,7 @@ status_t GonkNativeWindow::queueBuffer(int buf, int64_t timestamp,
|
||||
{
|
||||
Mutex::Autolock lock(mMutex);
|
||||
CNW_LOGD("queueBuffer: E");
|
||||
CNW_LOGD("queueBuffer: buf=%d", buf);
|
||||
|
||||
if (mAbandoned) {
|
||||
CNW_LOGE("queueBuffer: GonkNativeWindow has been abandoned!");
|
||||
@ -498,6 +511,7 @@ GonkNativeWindow::getCurrentBuffer()
|
||||
|
||||
Fifo::iterator front(mQueue.begin());
|
||||
int buf = *front;
|
||||
CNW_LOGD("getCurrentBuffer: buf=%d", buf);
|
||||
|
||||
mSlots[buf].mBufferState = BufferSlot::RENDERING;
|
||||
|
||||
@ -524,7 +538,7 @@ GonkNativeWindow::returnBuffer(uint32_t aIndex, uint32_t aGeneration)
|
||||
aGeneration, mGeneration);
|
||||
return false;
|
||||
}
|
||||
if (aIndex >= mBufferCount) {
|
||||
if (static_cast<int>(aIndex) >= mBufferCount) {
|
||||
CNW_LOGE("returnBuffer: slot index out of range [0, %d]: %d",
|
||||
mBufferCount, aIndex);
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user