mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 740997 - ICS camera support, r=jst,gal,roc
This commit is contained in:
parent
fc2f5cd147
commit
d753b0fbff
@ -165,6 +165,7 @@
|
||||
#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
|
||||
|
@ -174,6 +174,7 @@
|
||||
#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
|
||||
|
@ -273,6 +273,7 @@ MOZ_NATIVE_NSS = @MOZ_NATIVE_NSS@
|
||||
|
||||
MOZ_B2G_RIL = @MOZ_B2G_RIL@
|
||||
MOZ_B2G_BT = @MOZ_B2G_BT@
|
||||
MOZ_B2G_CAMERA = @MOZ_B2G_CAMERA@
|
||||
|
||||
MOZ_SYS_MSG = @MOZ_SYS_MSG@
|
||||
|
||||
|
14
configure.in
14
configure.in
@ -192,7 +192,7 @@ if test -n "$gonkdir" ; then
|
||||
;;
|
||||
esac
|
||||
|
||||
CPPFLAGS="-DANDROID -isystem $gonkdir/bionic/libc/$ARCH_DIR/include -isystem $gonkdir/bionic/libc/include/ -isystem $gonkdir/bionic/libc/kernel/common -isystem $gonkdir/bionic/libc/kernel/$ARCH_DIR -isystem $gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/hardware/libhardware_legacy/include -I$gonkdir/system -I$gonkdir/system/core/include -isystem $gonkdir/bionic -I$gonkdir/frameworks/base/include -I$gonkdir/external/dbus $CPPFLAGS -I$gonkdir/frameworks/base/services/sensorservice"
|
||||
CPPFLAGS="-DANDROID -isystem $gonkdir/bionic/libc/$ARCH_DIR/include -isystem $gonkdir/bionic/libc/include/ -isystem $gonkdir/bionic/libc/kernel/common -isystem $gonkdir/bionic/libc/kernel/$ARCH_DIR -isystem $gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/hardware/libhardware_legacy/include -I$gonkdir/system -I$gonkdir/system/core/include -isystem $gonkdir/bionic -I$gonkdir/frameworks/base/include -I$gonkdir/external/dbus $CPPFLAGS -I$gonkdir/frameworks/base/services/sensorservice -I$gonkdir/frameworks/base/services/camera"
|
||||
CFLAGS="-mandroid -fno-short-enums -fno-exceptions $CFLAGS"
|
||||
CXXFLAGS="-mandroid -fno-short-enums -fno-exceptions $CXXFLAGS $STLPORT_CPPFLAGS"
|
||||
LIBS="$LIBS $STLPORT_LIBS"
|
||||
@ -7351,6 +7351,18 @@ if test -n "$MOZ_SYS_MSG"; then
|
||||
fi
|
||||
AC_SUBST(MOZ_SYS_MSG)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable Camera Interface for B2G (Gonk usually)
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(b2g-camera,
|
||||
[ --enable-b2g-camera Set compile flags necessary for compiling camera API for B2G ],
|
||||
MOZ_B2G_CAMERA=1,
|
||||
MOZ_B2G_CAMERA= )
|
||||
if test -n "$MOZ_B2G_CAMERA"; then
|
||||
AC_DEFINE(MOZ_B2G_CAMERA)
|
||||
fi
|
||||
AC_SUBST(MOZ_B2G_CAMERA)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Support for demangling undefined symbols
|
||||
dnl ========================================================
|
||||
|
@ -70,6 +70,7 @@ DIRS += \
|
||||
ipc \
|
||||
identity \
|
||||
workers \
|
||||
camera \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_B2G_RIL
|
||||
|
@ -50,6 +50,8 @@
|
||||
#include "nsIDOMBluetoothManager.h"
|
||||
#include "BluetoothManager.h"
|
||||
#endif
|
||||
#include "nsIDOMCameraManager.h"
|
||||
#include "DOMCameraManager.h"
|
||||
|
||||
#include "nsIDOMGlobalPropertyInitializer.h"
|
||||
|
||||
@ -112,6 +114,7 @@ NS_INTERFACE_MAP_BEGIN(Navigator)
|
||||
#ifdef MOZ_B2G_BT
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorBluetooth)
|
||||
#endif
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorCamera)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorSystemMessages)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
|
||||
NS_INTERFACE_MAP_END
|
||||
@ -181,6 +184,8 @@ Navigator::Invalidate()
|
||||
}
|
||||
#endif
|
||||
|
||||
mCameraManager = nullptr;
|
||||
|
||||
#ifdef MOZ_SYS_MSG
|
||||
if (mMessagesManager) {
|
||||
mMessagesManager = nullptr;
|
||||
@ -1320,6 +1325,30 @@ Navigator::MozSetMessageHandler(const nsAString& aType,
|
||||
#endif
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// nsNavigator::nsIDOMNavigatorCamera
|
||||
//*****************************************************************************
|
||||
|
||||
NS_IMETHODIMP
|
||||
Navigator::GetMozCameras(nsIDOMCameraManager** aCameraManager)
|
||||
{
|
||||
if (!mCameraManager) {
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mWindow);
|
||||
NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
|
||||
|
||||
if (!win->GetOuterWindow() || win->GetOuterWindow()->GetCurrentInnerWindow() != win) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mCameraManager = nsDOMCameraManager::Create(win->WindowID());
|
||||
}
|
||||
|
||||
nsRefPtr<nsDOMCameraManager> cameraManager = mCameraManager;
|
||||
cameraManager.forget(aCameraManager);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
size_t
|
||||
Navigator::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
|
||||
{
|
||||
@ -1344,12 +1373,19 @@ Navigator::SetWindow(nsPIDOMWindow *aInnerWindow)
|
||||
void
|
||||
Navigator::OnNavigation()
|
||||
{
|
||||
// Inform MediaManager in case there are live streams or pending callbacks.
|
||||
#ifdef MOZ_MEDIA_NAVIGATOR
|
||||
MediaManager *manager = MediaManager::Get();
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mWindow);
|
||||
return manager->OnNavigation(win->WindowID());
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MOZ_MEDIA_NAVIGATOR
|
||||
// Inform MediaManager in case there are live streams or pending callbacks.
|
||||
MediaManager *manager = MediaManager::Get();
|
||||
manager->OnNavigation(win->WindowID());
|
||||
#endif
|
||||
if (mCameraManager) {
|
||||
mCameraManager->OnNavigation(win->WindowID());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -41,6 +41,9 @@ class nsIDOMMozVoicemail;
|
||||
|
||||
#include "nsIDOMNavigatorSystemMessages.h"
|
||||
|
||||
#include "nsIDOMNavigatorCamera.h"
|
||||
#include "DOMCameraManager.h"
|
||||
|
||||
//*****************************************************************************
|
||||
// Navigator: Script "navigator" object
|
||||
//*****************************************************************************
|
||||
@ -82,6 +85,7 @@ class Navigator : public nsIDOMNavigator
|
||||
#ifdef MOZ_B2G_BT
|
||||
, public nsIDOMNavigatorBluetooth
|
||||
#endif
|
||||
, public nsIDOMNavigatorCamera
|
||||
, public nsIDOMNavigatorSystemMessages
|
||||
{
|
||||
public:
|
||||
@ -134,6 +138,7 @@ public:
|
||||
// Helper to initialize mMessagesManager.
|
||||
nsresult EnsureMessagesManager();
|
||||
#endif
|
||||
NS_DECL_NSIDOMNAVIGATORCAMERA
|
||||
|
||||
private:
|
||||
bool IsSmsAllowed() const;
|
||||
@ -155,6 +160,7 @@ private:
|
||||
#ifdef MOZ_B2G_BT
|
||||
nsCOMPtr<nsIDOMBluetoothManager> mBluetooth;
|
||||
#endif
|
||||
nsRefPtr<nsDOMCameraManager> mCameraManager;
|
||||
nsCOMPtr<nsIDOMNavigatorSystemMessages> mMessagesManager;
|
||||
nsWeakPtr mWindow;
|
||||
};
|
||||
|
@ -522,6 +522,10 @@ using mozilla::dom::indexedDB::IDBWrapperCache;
|
||||
|
||||
#include "mozilla/dom/Activity.h"
|
||||
|
||||
#include "DOMCameraManager.h"
|
||||
#include "CameraControl.h"
|
||||
#include "CameraCapabilities.h"
|
||||
|
||||
#include "DOMError.h"
|
||||
#include "DOMRequest.h"
|
||||
#include "nsIOpenWindowEventDetail.h"
|
||||
@ -1668,6 +1672,13 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
#endif
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(CameraManager, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(CameraControl, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(CameraCapabilities, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(DOMError, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
@ -2466,6 +2477,7 @@ nsDOMClassInfo::Init()
|
||||
#ifdef MOZ_B2G_BT
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorBluetooth)
|
||||
#endif
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorCamera)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorSystemMessages)
|
||||
|
||||
DOM_CLASSINFO_MAP_END
|
||||
@ -4457,6 +4469,18 @@ nsDOMClassInfo::Init()
|
||||
DOM_CLASSINFO_MAP_END
|
||||
#endif
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(CameraManager, nsIDOMCameraManager)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMCameraManager)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(CameraControl, nsICameraControl)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsICameraControl)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(CameraCapabilities, nsICameraCapabilities)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsICameraCapabilities)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(DOMError, nsIDOMDOMError)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMError)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
@ -526,6 +526,10 @@ DOMCI_CLASS(BluetoothDevice)
|
||||
DOMCI_CLASS(BluetoothDeviceEvent)
|
||||
#endif
|
||||
|
||||
DOMCI_CLASS(CameraManager)
|
||||
DOMCI_CLASS(CameraControl)
|
||||
DOMCI_CLASS(CameraCapabilities)
|
||||
|
||||
DOMCI_CLASS(DOMError)
|
||||
DOMCI_CLASS(DOMRequest)
|
||||
DOMCI_CLASS(OpenWindowEventDetail)
|
||||
|
44
dom/camera/CameraCapabilities.h
Normal file
44
dom/camera/CameraCapabilities.h
Normal file
@ -0,0 +1,44 @@
|
||||
/* 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_NSCAMERACAPABILITIES_H
|
||||
#define DOM_CAMERA_NSCAMERACAPABILITIES_H
|
||||
|
||||
#include "CameraControl.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
typedef nsresult (*ParseItemAndAddFunc)(JSContext* aCx, JSObject* aArray, PRUint32 aIndex, const char* aStart, char** aEnd);
|
||||
|
||||
class nsCameraCapabilities : public nsICameraCapabilities
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICAMERACAPABILITIES
|
||||
|
||||
nsCameraCapabilities(nsCameraControl* aCamera);
|
||||
|
||||
nsresult ParameterListToNewArray(
|
||||
JSContext* cx,
|
||||
JSObject** aArray,
|
||||
PRUint32 aKey,
|
||||
ParseItemAndAddFunc aParseItemAndAdd
|
||||
);
|
||||
nsresult StringListToNewObject(JSContext* aCx, JS::Value* aArray, PRUint32 aKey);
|
||||
nsresult DimensionListToNewObject(JSContext* aCx, JS::Value* aArray, PRUint32 aKey);
|
||||
|
||||
private:
|
||||
nsCameraCapabilities(const nsCameraCapabilities&) MOZ_DELETE;
|
||||
nsCameraCapabilities& operator=(const nsCameraCapabilities&) MOZ_DELETE;
|
||||
|
||||
protected:
|
||||
/* additional members */
|
||||
~nsCameraCapabilities();
|
||||
nsCOMPtr<nsCameraControl> mCamera;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DOM_CAMERA_NSCAMERACAPABILITIES_H
|
68
dom/camera/CameraCommon.h
Normal file
68
dom/camera/CameraCommon.h
Normal file
@ -0,0 +1,68 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=40: */
|
||||
/* 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_CAMERACOMMON_H
|
||||
#define DOM_CAMERA_CAMERACOMMON_H
|
||||
|
||||
#ifndef __func__
|
||||
#ifdef __FUNCTION__
|
||||
#define __func__ __FUNCTION__
|
||||
#else
|
||||
#define __func__ __FILE__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NAN
|
||||
#define NAN std::numeric_limits<double>::quiet_NaN()
|
||||
#endif
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIDOMCameraManager.h"
|
||||
|
||||
#define DOM_CAMERA_LOG( l, ... ) \
|
||||
do { \
|
||||
if ( DOM_CAMERA_LOG_LEVEL >= (l) ) { \
|
||||
printf_stderr (__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DOM_CAMERA_LOGA( ... ) DOM_CAMERA_LOG( 0, __VA_ARGS__ )
|
||||
|
||||
enum {
|
||||
DOM_CAMERA_LOG_NOTHING,
|
||||
DOM_CAMERA_LOG_ERROR,
|
||||
DOM_CAMERA_LOG_WARNING,
|
||||
DOM_CAMERA_LOG_INFO
|
||||
};
|
||||
|
||||
#define DOM_CAMERA_LOGI( ... ) DOM_CAMERA_LOG( DOM_CAMERA_LOG_INFO, __VA_ARGS__ )
|
||||
#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__ )
|
||||
|
||||
class CameraErrorResult : public nsRunnable
|
||||
{
|
||||
public:
|
||||
CameraErrorResult(nsICameraErrorCallback* onError, const nsString& aErrorMsg)
|
||||
: mOnErrorCb(onError)
|
||||
, mErrorMsg(aErrorMsg)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mOnErrorCb) {
|
||||
mOnErrorCb->HandleEvent(mErrorMsg);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
|
||||
const nsString mErrorMsg;
|
||||
};
|
||||
|
||||
#endif // DOM_CAMERA_CAMERACOMMON_H
|
486
dom/camera/CameraControl.cpp
Normal file
486
dom/camera/CameraControl.cpp
Normal file
@ -0,0 +1,486 @@
|
||||
/* 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 "nsCOMPtr.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsThread.h"
|
||||
#include "DOMCameraManager.h"
|
||||
#include "CameraControl.h"
|
||||
#include "CameraCapabilities.h"
|
||||
#include "CameraControl.h"
|
||||
|
||||
#define DOM_CAMERA_LOG_LEVEL 3
|
||||
#include "CameraCommon.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace dom;
|
||||
|
||||
DOMCI_DATA(CameraControl, nsICameraControl)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsCameraControl)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsICameraControl)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraControl)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(nsCameraControl)
|
||||
NS_IMPL_RELEASE(nsCameraControl)
|
||||
|
||||
// Helpers for string properties.
|
||||
nsresult
|
||||
nsCameraControl::SetHelper(PRUint32 aKey, const nsAString& aValue)
|
||||
{
|
||||
SetParameter(aKey, NS_ConvertUTF16toUTF8(aValue).get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCameraControl::GetHelper(PRUint32 aKey, nsAString& aValue)
|
||||
{
|
||||
const char* value = GetParameterConstChar(aKey);
|
||||
if (!value) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aValue.AssignASCII(value);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Helpers for doubles.
|
||||
nsresult
|
||||
nsCameraControl::SetHelper(PRUint32 aKey, double aValue)
|
||||
{
|
||||
SetParameter(aKey, aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCameraControl::GetHelper(PRUint32 aKey, double* aValue)
|
||||
{
|
||||
MOZ_ASSERT(aValue);
|
||||
*aValue = GetParameterDouble(aKey);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Helper for weighted regions.
|
||||
nsresult
|
||||
nsCameraControl::SetHelper(JSContext* aCx, PRUint32 aKey, const JS::Value& aValue, PRUint32 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;
|
||||
|
||||
JSObject* regions = &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 (PRUint32 i = 0; i < length; ++i) {
|
||||
JS::Value v;
|
||||
|
||||
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);
|
||||
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
|
||||
nsCameraControl::GetHelper(JSContext* aCx, PRUint32 aKey, JS::Value* aValue)
|
||||
{
|
||||
nsTArray<CameraRegion> regionArray;
|
||||
|
||||
GetParameter(aKey, regionArray);
|
||||
|
||||
JSObject* array = JS_NewArrayObject(aCx, 0, nullptr);
|
||||
if (!array) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
PRUint32 length = regionArray.Length();
|
||||
DOM_CAMERA_LOGI("%s:%d : got %d regions\n", __func__, __LINE__, length);
|
||||
|
||||
for (PRUint32 i = 0; i < length; ++i) {
|
||||
CameraRegion* r = ®ionArray[i];
|
||||
JS::Value v;
|
||||
|
||||
JSObject* o = JS_NewObject(aCx, nullptr, nullptr, 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;
|
||||
}
|
||||
|
||||
v = OBJECT_TO_JSVAL(o);
|
||||
if (!JS_SetElement(aCx, array, i, &v)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
*aValue = JS::ObjectValue(*array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute nsICameraCapabilities capabilities; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetCapabilities(nsICameraCapabilities** aCapabilities)
|
||||
{
|
||||
if (!mCapabilities) {
|
||||
mCapabilities = new nsCameraCapabilities(this);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICameraCapabilities> capabilities = mCapabilities;
|
||||
capabilities.forget(aCapabilities);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute DOMString effect; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetEffect(nsAString& aEffect)
|
||||
{
|
||||
return GetHelper(CAMERA_PARAM_EFFECT, aEffect);
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::SetEffect(const nsAString& aEffect)
|
||||
{
|
||||
return SetHelper(CAMERA_PARAM_EFFECT, aEffect);
|
||||
}
|
||||
|
||||
/* attribute DOMString whiteBalanceMode; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetWhiteBalanceMode(nsAString& aWhiteBalanceMode)
|
||||
{
|
||||
return GetHelper(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::SetWhiteBalanceMode(const nsAString& aWhiteBalanceMode)
|
||||
{
|
||||
return SetHelper(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
|
||||
}
|
||||
|
||||
/* attribute DOMString sceneMode; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetSceneMode(nsAString& aSceneMode)
|
||||
{
|
||||
return GetHelper(CAMERA_PARAM_SCENEMODE, aSceneMode);
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::SetSceneMode(const nsAString& aSceneMode)
|
||||
{
|
||||
return SetHelper(CAMERA_PARAM_SCENEMODE, aSceneMode);
|
||||
}
|
||||
|
||||
/* attribute DOMString flashMode; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetFlashMode(nsAString& aFlashMode)
|
||||
{
|
||||
return GetHelper(CAMERA_PARAM_FLASHMODE, aFlashMode);
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::SetFlashMode(const nsAString& aFlashMode)
|
||||
{
|
||||
return SetHelper(CAMERA_PARAM_FLASHMODE, aFlashMode);
|
||||
}
|
||||
|
||||
/* attribute DOMString focusMode; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetFocusMode(nsAString& aFocusMode)
|
||||
{
|
||||
return GetHelper(CAMERA_PARAM_FOCUSMODE, aFocusMode);
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::SetFocusMode(const nsAString& aFocusMode)
|
||||
{
|
||||
return SetHelper(CAMERA_PARAM_FOCUSMODE, aFocusMode);
|
||||
}
|
||||
|
||||
/* attribute double zoom; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetZoom(double* aZoom)
|
||||
{
|
||||
return GetHelper(CAMERA_PARAM_ZOOM, aZoom);
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::SetZoom(double aZoom)
|
||||
{
|
||||
return SetHelper(CAMERA_PARAM_ZOOM, aZoom);
|
||||
}
|
||||
|
||||
/* attribute jsval meteringAreas; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetMeteringAreas(JSContext* cx, JS::Value* aMeteringAreas)
|
||||
{
|
||||
return GetHelper(cx, CAMERA_PARAM_METERINGAREAS, aMeteringAreas);
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::SetMeteringAreas(JSContext* cx, const JS::Value& aMeteringAreas)
|
||||
{
|
||||
return SetHelper(cx, CAMERA_PARAM_METERINGAREAS, aMeteringAreas, mMaxMeteringAreas);
|
||||
}
|
||||
|
||||
/* attribute jsval focusAreas; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetFocusAreas(JSContext* cx, JS::Value* aFocusAreas)
|
||||
{
|
||||
return GetHelper(cx, CAMERA_PARAM_FOCUSAREAS, aFocusAreas);
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::SetFocusAreas(JSContext* cx, const JS::Value& aFocusAreas)
|
||||
{
|
||||
return SetHelper(cx, CAMERA_PARAM_FOCUSAREAS, aFocusAreas, mMaxFocusAreas);
|
||||
}
|
||||
|
||||
/* readonly attribute double focalLength; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetFocalLength(double* aFocalLength)
|
||||
{
|
||||
return GetHelper(CAMERA_PARAM_FOCALLENGTH, aFocalLength);
|
||||
}
|
||||
|
||||
/* readonly attribute double focusDistanceNear; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetFocusDistanceNear(double* aFocusDistanceNear)
|
||||
{
|
||||
return GetHelper(CAMERA_PARAM_FOCUSDISTANCENEAR, aFocusDistanceNear);
|
||||
}
|
||||
|
||||
/* readonly attribute double focusDistanceOptimum; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetFocusDistanceOptimum(double* aFocusDistanceOptimum)
|
||||
{
|
||||
return GetHelper(CAMERA_PARAM_FOCUSDISTANCEOPTIMUM, aFocusDistanceOptimum);
|
||||
}
|
||||
|
||||
/* readonly attribute double focusDistanceFar; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetFocusDistanceFar(double* aFocusDistanceFar)
|
||||
{
|
||||
return GetHelper(CAMERA_PARAM_FOCUSDISTANCEFAR, aFocusDistanceFar);
|
||||
}
|
||||
|
||||
/* void setExposureCompensation (const JS::Value& aCompensation, JSContext* cx); */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::SetExposureCompensation(const JS::Value& aCompensation, JSContext* cx)
|
||||
{
|
||||
if (aCompensation.isNullOrUndefined()) {
|
||||
// use NaN to switch the camera back into auto mode
|
||||
return SetHelper(CAMERA_PARAM_EXPOSURECOMPENSATION, NAN);
|
||||
}
|
||||
|
||||
double compensation;
|
||||
if (!JS_ValueToNumber(cx, aCompensation, &compensation)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return SetHelper(CAMERA_PARAM_EXPOSURECOMPENSATION, compensation);
|
||||
}
|
||||
|
||||
/* readonly attribute double exposureCompensation; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetExposureCompensation(double* aExposureCompensation)
|
||||
{
|
||||
return GetHelper(CAMERA_PARAM_EXPOSURECOMPENSATION, aExposureCompensation);
|
||||
}
|
||||
|
||||
/* attribute nsICameraShutterCallback onShutter; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetOnShutter(nsICameraShutterCallback** aOnShutter)
|
||||
{
|
||||
*aOnShutter = mOnShutterCb;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::SetOnShutter(nsICameraShutterCallback* aOnShutter)
|
||||
{
|
||||
mOnShutterCb = aOnShutter;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void startRecording (in jsval aOptions, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::StartRecording(const JS::Value& aOptions, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
|
||||
{
|
||||
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
|
||||
|
||||
CameraSize size;
|
||||
nsresult rv = size.Init(cx, &aOptions);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIRunnable> startRecordingTask = new StartRecordingTask(this, size, onSuccess, onError);
|
||||
mCameraThread->Dispatch(startRecordingTask, NS_DISPATCH_NORMAL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void stopRecording (); */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::StopRecording()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> stopRecordingTask = new StopRecordingTask(this);
|
||||
mCameraThread->Dispatch(stopRecordingTask, NS_DISPATCH_NORMAL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] void getPreviewStream (in jsval aOptions, in nsICameraPreviewStreamCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::GetPreviewStream(const JS::Value& aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
|
||||
{
|
||||
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
|
||||
|
||||
CameraSize size;
|
||||
nsresult rv = size.Init(cx, &aOptions);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIRunnable> getPreviewStreamTask = new GetPreviewStreamTask(this, size, onSuccess, onError);
|
||||
mCameraThread->Dispatch(getPreviewStreamTask, NS_DISPATCH_NORMAL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void autoFocus (in nsICameraAutoFocusCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
|
||||
NS_IMETHODIMP
|
||||
nsCameraControl::AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
{
|
||||
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
|
||||
|
||||
nsCOMPtr<nsIRunnable> autoFocusTask = new AutoFocusTask(this, onSuccess, onError);
|
||||
mCameraThread->Dispatch(autoFocusTask, NS_DISPATCH_NORMAL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void takePicture (in jsval aOptions, in nsICameraTakePictureCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
|
||||
NS_IMETHODIMP nsCameraControl::TakePicture(const JS::Value& aOptions, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
|
||||
{
|
||||
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
|
||||
|
||||
CameraPictureOptions options;
|
||||
CameraSize size;
|
||||
CameraPosition pos;
|
||||
|
||||
nsresult rv = options.Init(cx, &aOptions);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = size.Init(cx, &options.pictureSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
/**
|
||||
* Default values, until the dictionary parser can handle them.
|
||||
* NaN indicates no value provided.
|
||||
*/
|
||||
pos.latitude = NAN;
|
||||
pos.longitude = NAN;
|
||||
pos.altitude = NAN;
|
||||
pos.timestamp = NAN;
|
||||
rv = pos.Init(cx, &options.position);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIRunnable> takePictureTask = new TakePictureTask(this, size, options.rotation, options.fileFormat, pos, onSuccess, onError);
|
||||
mCameraThread->Dispatch(takePictureTask, NS_DISPATCH_NORMAL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsCameraControl::AutoFocusComplete(bool aSuccess)
|
||||
{
|
||||
/**
|
||||
* Auto focusing can change some of the camera's parameters, so
|
||||
* we need to pull a new set before sending the result to the
|
||||
* main thread.
|
||||
*/
|
||||
PullParametersImpl(nullptr);
|
||||
|
||||
nsCOMPtr<nsIRunnable> autoFocusResult = new AutoFocusResult(aSuccess, mAutoFocusOnSuccessCb);
|
||||
|
||||
nsresult rv = NS_DispatchToMainThread(autoFocusResult);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch autoFocus() onSuccess callback to main thread!");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsCameraControl::TakePictureComplete(PRUint8* aData, PRUint32 aLength)
|
||||
{
|
||||
PRUint8* data = new PRUint8[aLength];
|
||||
|
||||
memcpy(data, aData, aLength);
|
||||
|
||||
/**
|
||||
* TODO: pick up the actual specified picture format for the MIME type;
|
||||
* for now, assume we'll be using JPEGs.
|
||||
*/
|
||||
nsIDOMBlob* blob = new nsDOMMemoryFile(static_cast<void*>(data), static_cast<PRUint64>(aLength), NS_LITERAL_STRING("image/jpeg"));
|
||||
nsCOMPtr<nsIRunnable> takePictureResult = new TakePictureResult(blob, mTakePictureOnSuccessCb);
|
||||
|
||||
nsresult rv = NS_DispatchToMainThread(takePictureResult);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch takePicture() onSuccess callback to main thread!");
|
||||
}
|
||||
}
|
438
dom/camera/CameraControl.h
Normal file
438
dom/camera/CameraControl.h
Normal file
@ -0,0 +1,438 @@
|
||||
/* 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_NSCAMERACONTROL_H
|
||||
#define DOM_CAMERA_NSCAMERACONTROL_H
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsThread.h"
|
||||
#include "nsDOMFile.h"
|
||||
#include "DictionaryHelpers.h"
|
||||
#include "CameraPreview.h"
|
||||
#include "nsIDOMCameraManager.h"
|
||||
|
||||
#define DOM_CAMERA_LOG_LEVEL 3
|
||||
#include "CameraCommon.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace dom;
|
||||
|
||||
class GetPreviewStreamTask;
|
||||
class AutoFocusTask;
|
||||
class TakePictureTask;
|
||||
class StartRecordingTask;
|
||||
class StopRecordingTask;
|
||||
class SetParameterTask;
|
||||
class GetParameterTask;
|
||||
class PushParametersTask;
|
||||
class PullParametersTask;
|
||||
|
||||
// Main camera control.
|
||||
class nsCameraControl : public nsICameraControl
|
||||
{
|
||||
friend class GetPreviewStreamTask;
|
||||
friend class AutoFocusTask;
|
||||
friend class TakePictureTask;
|
||||
friend class StartRecordingTask;
|
||||
friend class StopRecordingTask;
|
||||
friend class SetParameterTask;
|
||||
friend class GetParameterTask;
|
||||
friend class PushParametersTask;
|
||||
friend class PullParametersTask;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICAMERACONTROL
|
||||
|
||||
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_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
|
||||
};
|
||||
virtual const char* GetParameter(const char* aKey) = 0;
|
||||
virtual const char* GetParameterConstChar(PRUint32 aKey) = 0;
|
||||
virtual double GetParameterDouble(PRUint32 aKey) = 0;
|
||||
virtual void GetParameter(PRUint32 aKey, nsTArray<CameraRegion>& aRegions) = 0;
|
||||
virtual void SetParameter(const char* aKey, const char* aValue) = 0;
|
||||
virtual void SetParameter(PRUint32 aKey, const char* aValue) = 0;
|
||||
virtual void SetParameter(PRUint32 aKey, double aValue) = 0;
|
||||
virtual void SetParameter(PRUint32 aKey, const nsTArray<CameraRegion>& aRegions) = 0;
|
||||
virtual void PushParameters() = 0;
|
||||
|
||||
nsCameraControl(PRUint32 aCameraId, nsIThread* aCameraThread)
|
||||
: mCameraId(aCameraId)
|
||||
, mCameraThread(aCameraThread)
|
||||
, mCapabilities(nullptr)
|
||||
, mPreview(nullptr)
|
||||
, mFileFormat()
|
||||
, mMaxMeteringAreas(0)
|
||||
, mMaxFocusAreas(0)
|
||||
, mAutoFocusOnSuccessCb(nullptr)
|
||||
, mAutoFocusOnErrorCb(nullptr)
|
||||
, mTakePictureOnSuccessCb(nullptr)
|
||||
, mTakePictureOnErrorCb(nullptr)
|
||||
, mStartRecordingOnSuccessCb(nullptr)
|
||||
, mStartRecordingOnErrorCb(nullptr)
|
||||
, mOnShutterCb(nullptr)
|
||||
{ }
|
||||
|
||||
void TakePictureComplete(PRUint8 *aData, PRUint32 aLength);
|
||||
void AutoFocusComplete(bool aSuccess);
|
||||
|
||||
protected:
|
||||
virtual ~nsCameraControl() { }
|
||||
|
||||
nsresult SetHelper(PRUint32 aKey, const nsAString& aValue);
|
||||
nsresult GetHelper(PRUint32 aKey, nsAString& aValue);
|
||||
nsresult SetHelper(PRUint32 aKey, double aValue);
|
||||
nsresult GetHelper(PRUint32 aKey, double* aValue);
|
||||
nsresult SetHelper(JSContext* aCx, PRUint32 aKey, const JS::Value& aValue, PRUint32 aLimit);
|
||||
nsresult GetHelper(JSContext* aCx, PRUint32 aKey, JS::Value* aValue);
|
||||
|
||||
virtual nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream) = 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 nsresult PushParametersImpl(PushParametersTask* aPushParameters) = 0;
|
||||
virtual nsresult PullParametersImpl(PullParametersTask* aPullParameters) = 0;
|
||||
|
||||
private:
|
||||
nsCameraControl(const nsCameraControl&) MOZ_DELETE;
|
||||
nsCameraControl& operator=(const nsCameraControl&) MOZ_DELETE;
|
||||
|
||||
protected:
|
||||
/* additional members */
|
||||
PRUint32 mCameraId;
|
||||
nsCOMPtr<nsIThread> mCameraThread;
|
||||
nsCOMPtr<nsICameraCapabilities> mCapabilities;
|
||||
PRUint32 mPreviewWidth;
|
||||
PRUint32 mPreviewHeight;
|
||||
nsCOMPtr<CameraPreview> mPreview;
|
||||
nsString mFileFormat;
|
||||
PRUint32 mMaxMeteringAreas;
|
||||
PRUint32 mMaxFocusAreas;
|
||||
|
||||
nsCOMPtr<nsICameraAutoFocusCallback> mAutoFocusOnSuccessCb;
|
||||
nsCOMPtr<nsICameraErrorCallback> mAutoFocusOnErrorCb;
|
||||
nsCOMPtr<nsICameraTakePictureCallback> mTakePictureOnSuccessCb;
|
||||
nsCOMPtr<nsICameraErrorCallback> mTakePictureOnErrorCb;
|
||||
nsCOMPtr<nsICameraStartRecordingCallback> mStartRecordingOnSuccessCb;
|
||||
nsCOMPtr<nsICameraErrorCallback> mStartRecordingOnErrorCb;
|
||||
nsCOMPtr<nsICameraShutterCallback> mOnShutterCb;
|
||||
};
|
||||
|
||||
// Return the resulting preview stream to JS. Runs on the main thread.
|
||||
class GetPreviewStreamResult : public nsRunnable
|
||||
{
|
||||
public:
|
||||
GetPreviewStreamResult(nsIDOMMediaStream* aStream, nsICameraPreviewStreamCallback* onSuccess)
|
||||
: mStream(aStream)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mOnSuccessCb) {
|
||||
mOnSuccessCb->HandleEvent(mStream);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIDOMMediaStream> mStream;
|
||||
nsCOMPtr<nsICameraPreviewStreamCallback> mOnSuccessCb;
|
||||
};
|
||||
|
||||
// Get the desired preview stream.
|
||||
class GetPreviewStreamTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
GetPreviewStreamTask(nsCameraControl* aCameraControl, CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
: mSize(aSize)
|
||||
, mCameraControl(aCameraControl)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
, mOnErrorCb(onError)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsresult rv = mCameraControl->GetPreviewStreamImpl(this);
|
||||
|
||||
if (NS_FAILED(rv) && mOnErrorCb) {
|
||||
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
CameraSize mSize;
|
||||
nsCOMPtr<nsCameraControl> mCameraControl;
|
||||
nsCOMPtr<nsICameraPreviewStreamCallback> mOnSuccessCb;
|
||||
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
|
||||
};
|
||||
|
||||
// Return the autofocus status to JS. Runs on the main thread.
|
||||
class AutoFocusResult : public nsRunnable
|
||||
{
|
||||
public:
|
||||
AutoFocusResult(bool aSuccess, nsICameraAutoFocusCallback* onSuccess)
|
||||
: mSuccess(aSuccess)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mOnSuccessCb) {
|
||||
mOnSuccessCb->HandleEvent(mSuccess);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool mSuccess;
|
||||
nsCOMPtr<nsICameraAutoFocusCallback> mOnSuccessCb;
|
||||
};
|
||||
|
||||
// Autofocus the camera.
|
||||
class AutoFocusTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
AutoFocusTask(nsCameraControl* aCameraControl, nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
: mCameraControl(aCameraControl)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
, mOnErrorCb(onError)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
nsresult rv = mCameraControl->AutoFocusImpl(this);
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
if (NS_FAILED(rv) && mOnErrorCb) {
|
||||
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsCameraControl> mCameraControl;
|
||||
nsCOMPtr<nsICameraAutoFocusCallback> mOnSuccessCb;
|
||||
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
|
||||
};
|
||||
|
||||
// Return the captured picture to JS. Runs on the main thread.
|
||||
class TakePictureResult : public nsRunnable
|
||||
{
|
||||
public:
|
||||
TakePictureResult(nsIDOMBlob* aImage, nsICameraTakePictureCallback* onSuccess)
|
||||
: mImage(aImage)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mOnSuccessCb) {
|
||||
mOnSuccessCb->HandleEvent(mImage);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIDOMBlob> mImage;
|
||||
nsCOMPtr<nsICameraTakePictureCallback> mOnSuccessCb;
|
||||
};
|
||||
|
||||
// Capture a still image with the camera.
|
||||
class TakePictureTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
TakePictureTask(nsCameraControl* aCameraControl, CameraSize aSize, PRInt32 aRotation, const nsAString& aFileFormat, CameraPosition aPosition, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
: mCameraControl(aCameraControl)
|
||||
, mSize(aSize)
|
||||
, mRotation(aRotation)
|
||||
, mFileFormat(aFileFormat)
|
||||
, mPosition(aPosition)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
, mOnErrorCb(onError)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
nsresult rv = mCameraControl->TakePictureImpl(this);
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
if (NS_FAILED(rv) && mOnErrorCb) {
|
||||
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsCameraControl> mCameraControl;
|
||||
CameraSize mSize;
|
||||
PRInt32 mRotation;
|
||||
nsString mFileFormat;
|
||||
CameraPosition mPosition;
|
||||
nsCOMPtr<nsICameraTakePictureCallback> mOnSuccessCb;
|
||||
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
|
||||
};
|
||||
|
||||
// Return the captured video to JS. Runs on the main thread.
|
||||
class StartRecordingResult : public nsRunnable
|
||||
{
|
||||
public:
|
||||
StartRecordingResult(nsIDOMMediaStream* aStream, nsICameraStartRecordingCallback* onSuccess)
|
||||
: mStream(aStream)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mOnSuccessCb) {
|
||||
mOnSuccessCb->HandleEvent(mStream);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIDOMMediaStream> mStream;
|
||||
nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
|
||||
};
|
||||
|
||||
// Start video recording.
|
||||
class StartRecordingTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
StartRecordingTask(nsCameraControl* aCameraControl, CameraSize aSize, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
: mSize(aSize)
|
||||
, mCameraControl(aCameraControl)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
, mOnErrorCb(onError)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
nsresult rv = mCameraControl->StartRecordingImpl(this);
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
if (NS_FAILED(rv) && mOnErrorCb) {
|
||||
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
CameraSize mSize;
|
||||
nsCOMPtr<nsCameraControl> mCameraControl;
|
||||
nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
|
||||
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
|
||||
};
|
||||
|
||||
// Stop video recording.
|
||||
class StopRecordingTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
StopRecordingTask(nsCameraControl* aCameraControl)
|
||||
: mCameraControl(aCameraControl)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
nsresult rv = mCameraControl->StopRecordingImpl(this);
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsCameraControl> mCameraControl;
|
||||
};
|
||||
|
||||
// Pushes all camera parameters to the camera.
|
||||
class PushParametersTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
PushParametersTask(nsCameraControl* aCameraControl)
|
||||
: mCameraControl(aCameraControl)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
nsresult rv = mCameraControl->PushParametersImpl(this);
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsCameraControl> mCameraControl;
|
||||
};
|
||||
|
||||
// Get all camera parameters from the camera.
|
||||
class PullParametersTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
PullParametersTask(nsCameraControl* aCameraControl)
|
||||
: mCameraControl(aCameraControl)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
nsresult rv = mCameraControl->PullParametersImpl(this);
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsCameraControl> mCameraControl;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DOM_CAMERA_NSCAMERACONTROL_H
|
98
dom/camera/CameraPreview.cpp
Normal file
98
dom/camera/CameraPreview.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
/* 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 "CameraPreview.h"
|
||||
|
||||
#define DOM_CAMERA_LOG_LEVEL 3
|
||||
#include "CameraCommon.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_ISUPPORTS1(CameraPreview, CameraPreview)
|
||||
|
||||
class CameraPreviewListener : public MediaStreamListener
|
||||
{
|
||||
public:
|
||||
CameraPreviewListener(CameraPreview* aPreview) :
|
||||
mPreview(aPreview)
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
~CameraPreviewListener()
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
void NotifyConsumptionChanged(MediaStreamGraph* aGraph, Consumption aConsuming)
|
||||
{
|
||||
const char* state;
|
||||
|
||||
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
|
||||
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);
|
||||
|
||||
switch (aConsuming) {
|
||||
case NOT_CONSUMED:
|
||||
mPreview->Stop();
|
||||
break;
|
||||
|
||||
case CONSUMED:
|
||||
mPreview->Start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<CameraPreview> mPreview;
|
||||
};
|
||||
|
||||
CameraPreview::CameraPreview(PRUint32 aWidth, PRUint32 aHeight)
|
||||
: nsDOMMediaStream()
|
||||
, mWidth(aWidth)
|
||||
, mHeight(aHeight)
|
||||
, mFramesPerSecond(0)
|
||||
, mFrameCount(0)
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s:%d : mWidth=%d, mHeight=%d : this=%p\n", __func__, __LINE__, mWidth, mHeight, this);
|
||||
|
||||
mImageContainer = LayerManager::CreateImageContainer();
|
||||
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
|
||||
mStream = gm->CreateInputStream(this);
|
||||
mInput = GetStream()->AsSourceStream();
|
||||
mInput->AddListener(new CameraPreviewListener(this));
|
||||
}
|
||||
|
||||
void
|
||||
CameraPreview::SetFrameRate(PRUint32 aFramesPerSecond)
|
||||
{
|
||||
mFramesPerSecond = aFramesPerSecond;
|
||||
mInput->AddTrack(TRACK_VIDEO, mFramesPerSecond, 0, new VideoSegment());
|
||||
mInput->AdvanceKnownTracksTime(MEDIA_TIME_MAX);
|
||||
}
|
||||
|
||||
CameraPreview::~CameraPreview()
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
|
||||
/**
|
||||
* We _must_ remember to call RemoveListener on this before destroying this,
|
||||
* else the media framework will trigger a double-free.
|
||||
*/
|
||||
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
58
dom/camera/CameraPreview.h
Normal file
58
dom/camera/CameraPreview.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* 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_CAMERAPREVIEW_H
|
||||
#define DOM_CAMERA_CAMERAPREVIEW_H
|
||||
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "nsDOMMediaStream.h"
|
||||
|
||||
#define DOM_CAMERA_LOG_LEVEL 3
|
||||
#include "CameraCommon.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::layers;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CameraPreview : public nsDOMMediaStream
|
||||
, public MediaStreamListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
CameraPreview(PRUint32 aWidth, PRUint32 aHeight);
|
||||
|
||||
void SetFrameRate(PRUint32 aFramesPerSecond);
|
||||
|
||||
NS_IMETHODIMP
|
||||
GetCurrentTime(double* aCurrentTime) {
|
||||
return nsDOMMediaStream::GetCurrentTime(aCurrentTime);
|
||||
}
|
||||
|
||||
virtual void Start() = 0;
|
||||
virtual void Stop() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~CameraPreview();
|
||||
|
||||
PRUint32 mWidth;
|
||||
PRUint32 mHeight;
|
||||
PRUint32 mFramesPerSecond;
|
||||
SourceMediaStream* mInput;
|
||||
nsRefPtr<mozilla::layers::ImageContainer> mImageContainer;
|
||||
VideoSegment mVideoSegment;
|
||||
PRUint32 mFrameCount;
|
||||
|
||||
enum { TRACK_VIDEO = 1 };
|
||||
|
||||
private:
|
||||
CameraPreview(const CameraPreview&) MOZ_DELETE;
|
||||
CameraPreview& operator=(const CameraPreview&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DOM_CAMERA_CAMERAPREVIEW_H
|
89
dom/camera/DOMCameraManager.cpp
Normal file
89
dom/camera/DOMCameraManager.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
/* 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 "CameraControl.h"
|
||||
#include "DOMCameraManager.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "DictionaryHelpers.h"
|
||||
|
||||
#define DOM_CAMERA_LOG_LEVEL 3
|
||||
#include "CameraCommon.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
DOMCI_DATA(CameraManager, nsIDOMCameraManager)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsDOMCameraManager)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMCameraManager)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraManager)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(nsDOMCameraManager)
|
||||
NS_IMPL_RELEASE(nsDOMCameraManager)
|
||||
|
||||
/**
|
||||
* nsDOMCameraManager::GetListOfCameras
|
||||
* is implementation-specific, and can be found in (e.g.)
|
||||
* GonkCameraManager.cpp and FallbackCameraManager.cpp.
|
||||
*/
|
||||
|
||||
nsDOMCameraManager::nsDOMCameraManager(PRUint64 aWindowId)
|
||||
: mWindowId(aWindowId)
|
||||
{
|
||||
/* member initializers and constructor code */
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
}
|
||||
|
||||
nsDOMCameraManager::~nsDOMCameraManager()
|
||||
{
|
||||
/* destructor code */
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMCameraManager::OnNavigation(PRUint64 aWindowId)
|
||||
{
|
||||
// TODO: implement -- see getUserMedia() implementation
|
||||
}
|
||||
|
||||
// static creator
|
||||
already_AddRefed<nsDOMCameraManager>
|
||||
nsDOMCameraManager::Create(PRUint64 aWindowId)
|
||||
{
|
||||
// TODO: check for permissions here to access cameras
|
||||
|
||||
nsRefPtr<nsDOMCameraManager> cameraManager = new nsDOMCameraManager(aWindowId);
|
||||
return cameraManager.forget();
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] void getCamera ([optional] in jsval aOptions, in nsICameraGetCameraCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
|
||||
NS_IMETHODIMP
|
||||
nsDOMCameraManager::GetCamera(const JS::Value& aOptions, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
|
||||
{
|
||||
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
|
||||
|
||||
PRUint32 cameraId = 0; // back (or forward-facing) camera by default
|
||||
CameraSelector selector;
|
||||
|
||||
nsresult rv = selector.Init(cx, &aOptions);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (selector.camera.EqualsASCII("front")) {
|
||||
cameraId = 1;
|
||||
}
|
||||
|
||||
// reuse the same camera thread to conserve resources
|
||||
if (!mCameraThread) {
|
||||
rv = NS_NewThread(getter_AddRefs(mCameraThread));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
nsCOMPtr<nsIRunnable> getCameraTask = new GetCameraTask(cameraId, onSuccess, onError, mCameraThread);
|
||||
mCameraThread->Dispatch(getCameraTask, NS_DISPATCH_NORMAL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
82
dom/camera/DOMCameraManager.h
Normal file
82
dom/camera/DOMCameraManager.h
Normal file
@ -0,0 +1,82 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=40: */
|
||||
/* 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_DOMCAMERAMANAGER_H
|
||||
#define DOM_CAMERA_DOMCAMERAMANAGER_H
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIDOMCameraManager.h"
|
||||
|
||||
class nsDOMCameraManager : public nsIDOMCameraManager
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMCAMERAMANAGER
|
||||
|
||||
static already_AddRefed<nsDOMCameraManager> Create(PRUint64 aWindowId);
|
||||
|
||||
void OnNavigation(PRUint64 aWindowId);
|
||||
|
||||
private:
|
||||
nsDOMCameraManager();
|
||||
nsDOMCameraManager(PRUint64 aWindowId);
|
||||
nsDOMCameraManager(const nsDOMCameraManager&) MOZ_DELETE;
|
||||
nsDOMCameraManager& operator=(const nsDOMCameraManager&) MOZ_DELETE;
|
||||
~nsDOMCameraManager();
|
||||
|
||||
protected:
|
||||
PRUint64 mWindowId;
|
||||
nsCOMPtr<nsIThread> mCameraThread;
|
||||
};
|
||||
|
||||
|
||||
class GetCameraTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
GetCameraTask(PRUint32 aCameraId, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, nsIThread* aCameraThread)
|
||||
: mCameraId(aCameraId)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
, mOnErrorCb(onError)
|
||||
, mCameraThread(aCameraThread)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run();
|
||||
|
||||
protected:
|
||||
PRUint32 mCameraId;
|
||||
nsCOMPtr<nsICameraGetCameraCallback> mOnSuccessCb;
|
||||
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
|
||||
nsCOMPtr<nsIThread> mCameraThread;
|
||||
};
|
||||
|
||||
class GetCameraResult : public nsRunnable
|
||||
{
|
||||
public:
|
||||
GetCameraResult(nsICameraControl* aCameraControl, nsICameraGetCameraCallback* onSuccess)
|
||||
: mCameraControl(aCameraControl)
|
||||
, mOnSuccessCb(onSuccess)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: window management stuff
|
||||
if (mOnSuccessCb) {
|
||||
mOnSuccessCb->HandleEvent(mCameraControl);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsICameraControl> mCameraControl;
|
||||
nsCOMPtr<nsICameraGetCameraCallback> mOnSuccessCb;
|
||||
};
|
||||
|
||||
#endif // DOM_CAMERA_DOMCAMERAMANAGER_H
|
140
dom/camera/FallbackCameraCapabilities.cpp
Normal file
140
dom/camera/FallbackCameraCapabilities.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
/* 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 "nsDOMClassInfoID.h"
|
||||
#include "CameraControl.h"
|
||||
#include "CameraCapabilities.h"
|
||||
|
||||
#define DOM_CAMERA_LOG_LEVEL 3
|
||||
#include "CameraCommon.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
DOMCI_DATA(CameraCapabilities, nsICameraCapabilities)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsCameraCapabilities)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsICameraCapabilities)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraCapabilities)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(nsCameraCapabilities)
|
||||
NS_IMPL_RELEASE(nsCameraCapabilities)
|
||||
|
||||
nsCameraCapabilities::nsCameraCapabilities(nsCameraControl* aCamera)
|
||||
: mCamera(aCamera)
|
||||
{
|
||||
/* member initializers and constructor code */
|
||||
DOM_CAMERA_LOGI("%s:%d : FALLBACK CAMERA CAPABILITIES\n", __func__, __LINE__);
|
||||
}
|
||||
|
||||
nsCameraCapabilities::~nsCameraCapabilities()
|
||||
{
|
||||
/* destructor code */
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] readonly attribute jsval previewSizes; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetPreviewSizes(JSContext* cx, JS::Value* aPreviewSizes)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] readonly attribute jsval pictureSizes; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetPictureSizes(JSContext* cx, JS::Value* aPictureSizes)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] readonly attribute jsval fileFormats; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetFileFormats(JSContext* cx, JS::Value* aFileFormats)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] readonly attribute jsval whiteBalanceModes; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetWhiteBalanceModes(JSContext* cx, JS::Value* aWhiteBalanceModes)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] readonly attribute jsval sceneModes; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetSceneModes(JSContext* cx, JS::Value* aSceneModes)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] readonly attribute jsval effects; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetEffects(JSContext* cx, JS::Value* aEffects)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] readonly attribute jsval flashModes; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetFlashModes(JSContext* cx, JS::Value* aFlashModes)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] readonly attribute jsval focusModes; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetFocusModes(JSContext* cx, JS::Value* aFocusModes)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] readonly attribute long maxFocusAreas; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetMaxFocusAreas(JSContext* cx, PRInt32* aMaxFocusAreas)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] readonly attribute double minExposureCompensation; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetMinExposureCompensation(JSContext* cx, double* aMinExposureCompensation)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] readonly attribute double maxExposureCompensation; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetMaxExposureCompensation(JSContext* cx, double* aMaxExposureCompensation)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] readonly attribute double stepExposureCompensation; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetStepExposureCompensation(JSContext* cx, double* aStepExposureCompensation)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] readonly attribute long maxMeteringAreas; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetMaxMeteringAreas(JSContext* cx, PRInt32* aMaxMeteringAreas)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] readonly attribute jsval zoomRatios; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetZoomRatios(JSContext* cx, JS::Value* aZoomRatios)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] readonly attribute jsval videoSizes; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetVideoSizes(JSContext* cx, JS::Value* aVideoSizes)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
147
dom/camera/FallbackCameraControl.cpp
Normal file
147
dom/camera/FallbackCameraControl.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
/* 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 "nsDOMClassInfoID.h"
|
||||
#include "DOMCameraManager.h"
|
||||
#include "CameraControl.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
/**
|
||||
* Fallback camera control subclass. Can be used as a template for the
|
||||
* definition of new camera support classes.
|
||||
*/
|
||||
class nsFallbackCameraControl : public nsCameraControl
|
||||
{
|
||||
public:
|
||||
nsFallbackCameraControl(PRUint32 aCameraId, nsIThread* aCameraThread);
|
||||
|
||||
const char* GetParameter(const char* aKey);
|
||||
const char* GetParameterConstChar(PRUint32 aKey);
|
||||
double GetParameterDouble(PRUint32 aKey);
|
||||
void GetParameter(PRUint32 aKey, nsTArray<dom::CameraRegion>& aRegions);
|
||||
void SetParameter(const char* aKey, const char* aValue);
|
||||
void SetParameter(PRUint32 aKey, const char* aValue);
|
||||
void SetParameter(PRUint32 aKey, double aValue);
|
||||
void SetParameter(PRUint32 aKey, const nsTArray<dom::CameraRegion>& aRegions);
|
||||
void PushParameters();
|
||||
|
||||
protected:
|
||||
~nsFallbackCameraControl();
|
||||
|
||||
nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream);
|
||||
nsresult AutoFocusImpl(AutoFocusTask* aAutoFocus);
|
||||
nsresult TakePictureImpl(TakePictureTask* aTakePicture);
|
||||
nsresult StartRecordingImpl(StartRecordingTask* aStartRecording);
|
||||
nsresult StopRecordingImpl(StopRecordingTask* aStopRecording);
|
||||
nsresult PushParametersImpl(PushParametersTask* aPushParameters);
|
||||
nsresult PullParametersImpl(PullParametersTask* aPullParameters);
|
||||
|
||||
private:
|
||||
nsFallbackCameraControl(const nsFallbackCameraControl&) MOZ_DELETE;
|
||||
nsFallbackCameraControl& operator=(const nsFallbackCameraControl&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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(PRUint32 aCameraId, nsIThread* aCameraThread)
|
||||
: nsCameraControl(aCameraId, aCameraThread)
|
||||
{ }
|
||||
|
||||
nsFallbackCameraControl::~nsFallbackCameraControl()
|
||||
{ }
|
||||
|
||||
const char*
|
||||
nsFallbackCameraControl::GetParameter(const char* aKey)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char*
|
||||
nsFallbackCameraControl::GetParameterConstChar(PRUint32 aKey)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
double
|
||||
nsFallbackCameraControl::GetParameterDouble(PRUint32 aKey)
|
||||
{
|
||||
return NAN;
|
||||
}
|
||||
|
||||
void
|
||||
nsFallbackCameraControl::GetParameter(PRUint32 aKey, nsTArray<dom::CameraRegion>& aRegions)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsFallbackCameraControl::SetParameter(const char* aKey, const char* aValue)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsFallbackCameraControl::SetParameter(PRUint32 aKey, const char* aValue)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsFallbackCameraControl::SetParameter(PRUint32 aKey, double aValue)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsFallbackCameraControl::SetParameter(PRUint32 aKey, const nsTArray<dom::CameraRegion>& aRegions)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsFallbackCameraControl::PushParameters()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFallbackCameraControl::GetPreviewStreamImpl(GetPreviewStreamTask* 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(PushParametersTask* aPushParameters)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFallbackCameraControl::PullParametersImpl(PullParametersTask* aPullParameters)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
22
dom/camera/FallbackCameraManager.cpp
Normal file
22
dom/camera/FallbackCameraManager.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
/* 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 "DOMCameraManager.h"
|
||||
|
||||
// From nsDOMCameraManager.
|
||||
|
||||
/* [implicit_jscontext] jsval getListOfCameras (); */
|
||||
NS_IMETHODIMP
|
||||
nsDOMCameraManager::GetListOfCameras(JSContext* cx, JS::Value* _retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMETHODIMP
|
||||
GetCameraTask::Run()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
352
dom/camera/GonkCameraCapabilities.cpp
Normal file
352
dom/camera/GonkCameraCapabilities.cpp
Normal file
@ -0,0 +1,352 @@
|
||||
/* 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "jsapi.h"
|
||||
#include "camera/CameraParameters.h"
|
||||
#include "CameraControl.h"
|
||||
#include "CameraCapabilities.h"
|
||||
|
||||
#define DOM_CAMERA_LOG_LEVEL 3
|
||||
#include "CameraCommon.h"
|
||||
|
||||
using namespace android;
|
||||
using namespace mozilla;
|
||||
|
||||
DOMCI_DATA(CameraCapabilities, nsICameraCapabilities)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsCameraCapabilities)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsICameraCapabilities)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraCapabilities)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(nsCameraCapabilities)
|
||||
NS_IMPL_RELEASE(nsCameraCapabilities)
|
||||
|
||||
|
||||
nsCameraCapabilities::nsCameraCapabilities(nsCameraControl* aCamera)
|
||||
: mCamera(aCamera)
|
||||
{
|
||||
// member initializers and constructor code
|
||||
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
|
||||
nsCameraCapabilities::~nsCameraCapabilities()
|
||||
{
|
||||
// destructor code
|
||||
DOM_CAMERA_LOGI("%s:%d : this=%p, mCamera=%p\n", __func__, __LINE__, this, mCamera.get());
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ParseZoomRatioItemAndAdd(JSContext* aCx, JSObject* aArray, PRUint32 aIndex, const char* aStart, char** aEnd)
|
||||
{
|
||||
if (!*aEnd) {
|
||||
// make 'aEnd' follow the same semantics as strchr().
|
||||
aEnd = nullptr;
|
||||
}
|
||||
|
||||
double d = strtod(aStart, aEnd);
|
||||
jsval v;
|
||||
|
||||
d /= 100;
|
||||
if (!JS_NewNumberValue(aCx, d, &v)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (!JS_SetElement(aCx, aArray, aIndex, &v)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ParseStringItemAndAdd(JSContext* aCx, JSObject* aArray, PRUint32 aIndex, const char* aStart, char** aEnd)
|
||||
{
|
||||
JSString* s;
|
||||
|
||||
if (*aEnd) {
|
||||
s = JS_NewStringCopyN(aCx, aStart, *aEnd - aStart);
|
||||
} else {
|
||||
s = JS_NewStringCopyZ(aCx, aStart);
|
||||
}
|
||||
if (!s) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
jsval v = STRING_TO_JSVAL(s);
|
||||
if (!JS_SetElement(aCx, aArray, aIndex, &v)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ParseDimensionItemAndAdd(JSContext* aCx, JSObject* aArray, PRUint32 aIndex, const char* aStart, char** aEnd)
|
||||
{
|
||||
char* x;
|
||||
|
||||
if (!*aEnd) {
|
||||
// make 'aEnd' follow the same semantics as strchr().
|
||||
aEnd = nullptr;
|
||||
}
|
||||
|
||||
jsval w = INT_TO_JSVAL(strtol(aStart, &x, 10));
|
||||
jsval h = INT_TO_JSVAL(strtol(x + 1, aEnd, 10));
|
||||
|
||||
JSObject* o = JS_NewObject(aCx, nullptr, nullptr, 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;
|
||||
}
|
||||
|
||||
jsval v = OBJECT_TO_JSVAL(o);
|
||||
if (!JS_SetElement(aCx, aArray, aIndex, &v)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCameraCapabilities::ParameterListToNewArray(JSContext* aCx, JSObject** aArray, const char* aKey, ParseItemAndAddFunc aParseItemAndAdd)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
const char* value = mCamera->GetParameter(aKey);
|
||||
if (!value) {
|
||||
// in case we get nonsense data back
|
||||
*aArray = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aArray = JS_NewArrayObject(aCx, 0, nullptr);
|
||||
if (!*aArray) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
const char* p = value;
|
||||
PRUint32 index = 0;
|
||||
nsresult rv;
|
||||
char* q;
|
||||
|
||||
while (p) {
|
||||
q = 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
|
||||
nsCameraCapabilities::StringListToNewObject(JSContext* aCx, JS::Value* aArray, const char* aKey)
|
||||
{
|
||||
JSObject* array;
|
||||
|
||||
nsresult rv = ParameterListToNewArray(aCx, &array, aKey, ParseStringItemAndAdd);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aArray = OBJECT_TO_JSVAL(array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCameraCapabilities::DimensionListToNewObject(JSContext* aCx, JS::Value* aArray, const char* aKey)
|
||||
{
|
||||
JSObject* array;
|
||||
nsresult rv;
|
||||
|
||||
rv = ParameterListToNewArray(aCx, &array, aKey, ParseDimensionItemAndAdd);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aArray = OBJECT_TO_JSVAL(array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute jsval previewSizes; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetPreviewSizes(JSContext* cx, JS::Value* aPreviewSizes)
|
||||
{
|
||||
return DimensionListToNewObject(cx, aPreviewSizes, CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES);
|
||||
}
|
||||
|
||||
/* readonly attribute jsval pictureSizes; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetPictureSizes(JSContext* cx, JS::Value* aPictureSizes)
|
||||
{
|
||||
return DimensionListToNewObject(cx, aPictureSizes, CameraParameters::KEY_SUPPORTED_PICTURE_SIZES);
|
||||
}
|
||||
|
||||
/* readonly attribute jsval fileFormats; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetFileFormats(JSContext* cx, JS::Value* aFileFormats)
|
||||
{
|
||||
return StringListToNewObject(cx, aFileFormats, CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS);
|
||||
}
|
||||
|
||||
/* readonly attribute jsval whiteBalanceModes; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetWhiteBalanceModes(JSContext* cx, JS::Value* aWhiteBalanceModes)
|
||||
{
|
||||
return StringListToNewObject(cx, aWhiteBalanceModes, CameraParameters::KEY_SUPPORTED_WHITE_BALANCE);
|
||||
}
|
||||
|
||||
/* readonly attribute jsval sceneModes; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetSceneModes(JSContext* cx, JS::Value* aSceneModes)
|
||||
{
|
||||
return StringListToNewObject(cx, aSceneModes, CameraParameters::KEY_SUPPORTED_SCENE_MODES);
|
||||
}
|
||||
|
||||
/* readonly attribute jsval effects; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetEffects(JSContext* cx, JS::Value* aEffects)
|
||||
{
|
||||
return StringListToNewObject(cx, aEffects, CameraParameters::KEY_SUPPORTED_EFFECTS);
|
||||
}
|
||||
|
||||
/* readonly attribute jsval flashModes; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetFlashModes(JSContext* cx, JS::Value* aFlashModes)
|
||||
{
|
||||
return StringListToNewObject(cx, aFlashModes, CameraParameters::KEY_SUPPORTED_FLASH_MODES);
|
||||
}
|
||||
|
||||
/* readonly attribute jsval focusModes; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetFocusModes(JSContext* cx, JS::Value* aFocusModes)
|
||||
{
|
||||
return StringListToNewObject(cx, aFocusModes, CameraParameters::KEY_SUPPORTED_FOCUS_MODES);
|
||||
}
|
||||
|
||||
/* readonly attribute long maxFocusAreas; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetMaxFocusAreas(JSContext* cx, PRInt32* aMaxFocusAreas)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
const char* value = mCamera->GetParameter(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS);
|
||||
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
|
||||
nsCameraCapabilities::GetMinExposureCompensation(JSContext* cx, double* aMinExposureCompensation)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
const char* value = mCamera->GetParameter(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION);
|
||||
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
|
||||
nsCameraCapabilities::GetMaxExposureCompensation(JSContext* cx, double* aMaxExposureCompensation)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
const char* value = mCamera->GetParameter(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION);
|
||||
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
|
||||
nsCameraCapabilities::GetStepExposureCompensation(JSContext* cx, double* aStepExposureCompensation)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
const char* value = mCamera->GetParameter(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP);
|
||||
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
|
||||
nsCameraCapabilities::GetMaxMeteringAreas(JSContext* cx, PRInt32* aMaxMeteringAreas)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
const char* value = mCamera->GetParameter(CameraParameters::KEY_MAX_NUM_METERING_AREAS);
|
||||
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
|
||||
nsCameraCapabilities::GetZoomRatios(JSContext* cx, JS::Value* aZoomRatios)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
const char* value = mCamera->GetParameter(CameraParameters::KEY_ZOOM_SUPPORTED);
|
||||
if (!value || strcmp(value, CameraParameters::TRUE) != 0) {
|
||||
// if zoom is not supported, return a null object
|
||||
*aZoomRatios = JSVAL_NULL;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSObject* array;
|
||||
|
||||
nsresult rv = ParameterListToNewArray(cx, &array, CameraParameters::KEY_ZOOM_RATIOS, ParseZoomRatioItemAndAdd);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aZoomRatios = OBJECT_TO_JSVAL(array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute jsval videoSizes; */
|
||||
NS_IMETHODIMP
|
||||
nsCameraCapabilities::GetVideoSizes(JSContext* cx, JS::Value* aVideoSizes)
|
||||
{
|
||||
return DimensionListToNewObject(cx, aVideoSizes, CameraParameters::KEY_SUPPORTED_VIDEO_SIZES);
|
||||
}
|
602
dom/camera/GonkCameraControl.cpp
Normal file
602
dom/camera/GonkCameraControl.cpp
Normal file
@ -0,0 +1,602 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 <string.h>
|
||||
#include "libcameraservice/CameraHardwareInterface.h"
|
||||
#include "camera/CameraParameters.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsMemory.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsThread.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "DOMCameraManager.h"
|
||||
#include "GonkCameraHwMgr.h"
|
||||
#include "CameraCapabilities.h"
|
||||
#include "GonkCameraControl.h"
|
||||
#include "GonkCameraPreview.h"
|
||||
|
||||
#define DOM_CAMERA_LOG_LEVEL 3
|
||||
#include "CameraCommon.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static const char* getKeyText(PRUint32 aKey)
|
||||
{
|
||||
switch (aKey) {
|
||||
case nsCameraControl::CAMERA_PARAM_EFFECT:
|
||||
return CameraParameters::KEY_EFFECT;
|
||||
case nsCameraControl::CAMERA_PARAM_WHITEBALANCE:
|
||||
return CameraParameters::KEY_WHITE_BALANCE;
|
||||
case nsCameraControl::CAMERA_PARAM_SCENEMODE:
|
||||
return CameraParameters::KEY_SCENE_MODE;
|
||||
case nsCameraControl::CAMERA_PARAM_FLASHMODE:
|
||||
return CameraParameters::KEY_FLASH_MODE;
|
||||
case nsCameraControl::CAMERA_PARAM_FOCUSMODE:
|
||||
return CameraParameters::KEY_FOCUS_MODE;
|
||||
case nsCameraControl::CAMERA_PARAM_ZOOM:
|
||||
return CameraParameters::KEY_ZOOM;
|
||||
case nsCameraControl::CAMERA_PARAM_METERINGAREAS:
|
||||
return CameraParameters::KEY_METERING_AREAS;
|
||||
case nsCameraControl::CAMERA_PARAM_FOCUSAREAS:
|
||||
return CameraParameters::KEY_FOCUS_AREAS;
|
||||
case nsCameraControl::CAMERA_PARAM_FOCALLENGTH:
|
||||
return CameraParameters::KEY_FOCAL_LENGTH;
|
||||
case nsCameraControl::CAMERA_PARAM_FOCUSDISTANCENEAR:
|
||||
return CameraParameters::KEY_FOCUS_DISTANCES;
|
||||
case nsCameraControl::CAMERA_PARAM_FOCUSDISTANCEOPTIMUM:
|
||||
return CameraParameters::KEY_FOCUS_DISTANCES;
|
||||
case nsCameraControl::CAMERA_PARAM_FOCUSDISTANCEFAR:
|
||||
return CameraParameters::KEY_FOCUS_DISTANCES;
|
||||
case nsCameraControl::CAMERA_PARAM_EXPOSURECOMPENSATION:
|
||||
return CameraParameters::KEY_EXPOSURE_COMPENSATION;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_PREVIEWSIZES:
|
||||
return CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_VIDEOSIZES:
|
||||
return CameraParameters::KEY_SUPPORTED_VIDEO_SIZES;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_PICTURESIZES:
|
||||
return CameraParameters::KEY_SUPPORTED_PICTURE_SIZES;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_PICTUREFORMATS:
|
||||
return CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_WHITEBALANCES:
|
||||
return CameraParameters::KEY_SUPPORTED_WHITE_BALANCE;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_SCENEMODES:
|
||||
return CameraParameters::KEY_SUPPORTED_SCENE_MODES;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_EFFECTS:
|
||||
return CameraParameters::KEY_SUPPORTED_EFFECTS;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_FLASHMODES:
|
||||
return CameraParameters::KEY_SUPPORTED_FLASH_MODES;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_FOCUSMODES:
|
||||
return CameraParameters::KEY_SUPPORTED_FOCUS_MODES;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS:
|
||||
return CameraParameters::KEY_MAX_NUM_FOCUS_AREAS;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS:
|
||||
return CameraParameters::KEY_MAX_NUM_METERING_AREAS;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION:
|
||||
return CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION:
|
||||
return CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP:
|
||||
return CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_ZOOM:
|
||||
return CameraParameters::KEY_ZOOM_SUPPORTED;
|
||||
case nsCameraControl::CAMERA_PARAM_SUPPORTED_ZOOMRATIOS:
|
||||
return CameraParameters::KEY_ZOOM_RATIOS;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Gonk-specific CameraControl implementation.
|
||||
|
||||
nsGonkCameraControl::nsGonkCameraControl(PRUint32 aCameraId, nsIThread* aCameraThread)
|
||||
: nsCameraControl(aCameraId, aCameraThread)
|
||||
, mHwHandle(0)
|
||||
, mExposureCompensationMin(0.0)
|
||||
, mExposureCompensationStep(0.0)
|
||||
, mDeferConfigUpdate(false)
|
||||
{
|
||||
// Constructor runs on the camera thread--see DOMCameraManager.cpp::GetCameraImpl().
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
mHwHandle = GonkCameraHardware::GetHandle(this, mCameraId);
|
||||
DOM_CAMERA_LOGI("%s:%d : this = %p, mHwHandle = %d\n", __func__, __LINE__, this, mHwHandle);
|
||||
|
||||
// Initialize our camera configuration database.
|
||||
mRwLock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "GonkCameraControl.Parameters.Lock");
|
||||
PullParametersImpl(nullptr);
|
||||
|
||||
// Grab any settings we'll need later.
|
||||
mExposureCompensationMin = mParams.getFloat(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION);
|
||||
mExposureCompensationStep = mParams.getFloat(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP);
|
||||
mMaxMeteringAreas = mParams.getInt(CameraParameters::KEY_MAX_NUM_METERING_AREAS);
|
||||
mMaxFocusAreas = mParams.getInt(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS);
|
||||
|
||||
DOM_CAMERA_LOGI("minimum exposure compensation = %f\n", mExposureCompensationMin);
|
||||
DOM_CAMERA_LOGI("exposure compensation step = %f\n", mExposureCompensationStep);
|
||||
DOM_CAMERA_LOGI("maximum metering areas = %d\n", mMaxMeteringAreas);
|
||||
DOM_CAMERA_LOGI("maximum focus areas = %d\n", mMaxFocusAreas);
|
||||
}
|
||||
|
||||
nsGonkCameraControl::~nsGonkCameraControl()
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s:%d : this = %p, mHwHandle = %d\n", __func__, __LINE__, this, mHwHandle);
|
||||
GonkCameraHardware::ReleaseHandle(mHwHandle);
|
||||
if (mRwLock) {
|
||||
PRRWLock* lock = mRwLock;
|
||||
mRwLock = nullptr;
|
||||
PR_DestroyRWLock(lock);
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
}
|
||||
|
||||
class RwAutoLockRead
|
||||
{
|
||||
public:
|
||||
RwAutoLockRead(PRRWLock* aRwLock)
|
||||
: mRwLock(aRwLock)
|
||||
{
|
||||
PR_RWLock_Rlock(mRwLock);
|
||||
}
|
||||
|
||||
~RwAutoLockRead()
|
||||
{
|
||||
PR_RWLock_Unlock(mRwLock);
|
||||
}
|
||||
|
||||
protected:
|
||||
PRRWLock* mRwLock;
|
||||
};
|
||||
|
||||
class RwAutoLockWrite
|
||||
{
|
||||
public:
|
||||
RwAutoLockWrite(PRRWLock* aRwLock)
|
||||
: mRwLock(aRwLock)
|
||||
{
|
||||
PR_RWLock_Wlock(mRwLock);
|
||||
}
|
||||
|
||||
~RwAutoLockWrite()
|
||||
{
|
||||
PR_RWLock_Unlock(mRwLock);
|
||||
}
|
||||
|
||||
protected:
|
||||
PRRWLock* mRwLock;
|
||||
};
|
||||
|
||||
const char*
|
||||
nsGonkCameraControl::GetParameter(const char* aKey)
|
||||
{
|
||||
RwAutoLockRead lock(mRwLock);
|
||||
return mParams.get(aKey);
|
||||
}
|
||||
|
||||
const char*
|
||||
nsGonkCameraControl::GetParameterConstChar(PRUint32 aKey)
|
||||
{
|
||||
const char* key = getKeyText(aKey);
|
||||
if (!key) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RwAutoLockRead lock(mRwLock);
|
||||
return mParams.get(key);
|
||||
}
|
||||
|
||||
double
|
||||
nsGonkCameraControl::GetParameterDouble(PRUint32 aKey)
|
||||
{
|
||||
double val;
|
||||
int index = 0;
|
||||
double focusDistance[3];
|
||||
const char* s;
|
||||
|
||||
const char* key = getKeyText(aKey);
|
||||
if (!key) {
|
||||
// return 1x when zooming is not supported
|
||||
return aKey == CAMERA_PARAM_ZOOM ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
RwAutoLockRead lock(mRwLock);
|
||||
switch (aKey) {
|
||||
case CAMERA_PARAM_ZOOM:
|
||||
val = mParams.getInt(key);
|
||||
return val / 100;
|
||||
|
||||
/**
|
||||
* 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:
|
||||
s = mParams.get(key);
|
||||
if (sscanf(s, "%lf,%lf,%lf", &focusDistance[0], &focusDistance[1], &focusDistance[2]) == 3) {
|
||||
return focusDistance[index];
|
||||
}
|
||||
return 0.0;
|
||||
|
||||
case CAMERA_PARAM_EXPOSURECOMPENSATION:
|
||||
index = mParams.getInt(key);
|
||||
if (!index) {
|
||||
// NaN indicates automatic exposure compensation
|
||||
return NAN;
|
||||
}
|
||||
val = (index - 1) * mExposureCompensationStep + mExposureCompensationMin;
|
||||
DOM_CAMERA_LOGI("index = %d --> compensation = %f\n", index, val);
|
||||
return val;
|
||||
|
||||
default:
|
||||
return mParams.getFloat(key);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsGonkCameraControl::GetParameter(PRUint32 aKey, nsTArray<CameraRegion>& aRegions)
|
||||
{
|
||||
aRegions.Clear();
|
||||
|
||||
const char* key = getKeyText(aKey);
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
|
||||
RwAutoLockRead lock(mRwLock);
|
||||
|
||||
const char* value = mParams.get(key);
|
||||
DOM_CAMERA_LOGI("key='%s' --> value='%s'\n", key, value);
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char* p = value;
|
||||
PRUint32 count = 1;
|
||||
|
||||
// count the number of regions in the string
|
||||
while ((p = strstr(p, "),("))) {
|
||||
++count;
|
||||
p += 3;
|
||||
}
|
||||
|
||||
aRegions.SetCapacity(count);
|
||||
CameraRegion* r;
|
||||
|
||||
// parse all of the region sets
|
||||
PRUint32 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);
|
||||
goto GetParameter_error;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
GetParameter_error:
|
||||
aRegions.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
nsGonkCameraControl::PushParameters()
|
||||
{
|
||||
if (!mDeferConfigUpdate) {
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
/**
|
||||
* If we're already on the camera thread, call PushParametersImpl()
|
||||
* directly, so that it executes synchronously. Some callers
|
||||
* require this so that changes take effect immediately before
|
||||
* we can proceed.
|
||||
*/
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIRunnable> pushParametersTask = new PushParametersTask(this);
|
||||
mCameraThread->Dispatch(pushParametersTask, NS_DISPATCH_NORMAL);
|
||||
} else {
|
||||
PushParametersImpl(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsGonkCameraControl::SetParameter(const char* aKey, const char* aValue)
|
||||
{
|
||||
{
|
||||
RwAutoLockWrite lock(mRwLock);
|
||||
mParams.set(aKey, aValue);
|
||||
}
|
||||
PushParameters();
|
||||
}
|
||||
|
||||
void
|
||||
nsGonkCameraControl::SetParameter(PRUint32 aKey, const char* aValue)
|
||||
{
|
||||
const char* key = getKeyText(aKey);
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
RwAutoLockWrite lock(mRwLock);
|
||||
mParams.set(key, aValue);
|
||||
}
|
||||
PushParameters();
|
||||
}
|
||||
|
||||
void
|
||||
nsGonkCameraControl::SetParameter(PRUint32 aKey, double aValue)
|
||||
{
|
||||
PRUint32 index;
|
||||
|
||||
const char* key = getKeyText(aKey);
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
RwAutoLockWrite lock(mRwLock);
|
||||
if (aKey == CAMERA_PARAM_EXPOSURECOMPENSATION) {
|
||||
/**
|
||||
* Convert from real value to a Gonk index, round
|
||||
* to the nearest step; index is 1-based.
|
||||
*/
|
||||
index = (aValue - mExposureCompensationMin + mExposureCompensationStep / 2) / mExposureCompensationStep + 1;
|
||||
DOM_CAMERA_LOGI("compensation = %f --> index = %d\n", aValue, index);
|
||||
mParams.set(key, index);
|
||||
} else {
|
||||
mParams.setFloat(key, aValue);
|
||||
}
|
||||
}
|
||||
PushParameters();
|
||||
}
|
||||
|
||||
void
|
||||
nsGonkCameraControl::SetParameter(PRUint32 aKey, const nsTArray<CameraRegion>& aRegions)
|
||||
{
|
||||
const char* key = getKeyText(aKey);
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
|
||||
PRUint32 length = aRegions.Length();
|
||||
|
||||
if (!length) {
|
||||
// This tells the camera driver to revert to automatic regioning.
|
||||
mParams.set(key, "(0,0,0,0,0)");
|
||||
PushParameters();
|
||||
return;
|
||||
}
|
||||
|
||||
nsCString s;
|
||||
|
||||
for (PRUint32 i = 0; i < length; ++i) {
|
||||
const CameraRegion* 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);
|
||||
|
||||
DOM_CAMERA_LOGI("camera region string '%s'\n", s.get());
|
||||
|
||||
{
|
||||
RwAutoLockWrite lock(mRwLock);
|
||||
mParams.set(key, s.get());
|
||||
}
|
||||
PushParameters();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGonkCameraControl::GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream)
|
||||
{
|
||||
nsCOMPtr<CameraPreview> preview = mPreview;
|
||||
nsresult rv;
|
||||
|
||||
if (!preview) {
|
||||
preview = new GonkCameraPreview(mHwHandle, aGetPreviewStream->mSize.width, aGetPreviewStream->mSize.height);
|
||||
if (!preview) {
|
||||
if (aGetPreviewStream->mOnErrorCb) {
|
||||
rv = NS_DispatchToMainThread(new CameraErrorResult(aGetPreviewStream->mOnErrorCb, NS_LITERAL_STRING("OUT_OF_MEMORY")));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
mPreview = preview;
|
||||
return NS_DispatchToMainThread(new GetPreviewStreamResult(preview.get(), aGetPreviewStream->mOnSuccessCb));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGonkCameraControl::AutoFocusImpl(AutoFocusTask* aAutoFocus)
|
||||
{
|
||||
nsCOMPtr<nsICameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb;
|
||||
if (cb) {
|
||||
/**
|
||||
* We already have a callback, so someone has already
|
||||
* called autoFocus() -- cancel it.
|
||||
*/
|
||||
mAutoFocusOnSuccessCb = nullptr;
|
||||
nsCOMPtr<nsICameraErrorCallback> ecb = mAutoFocusOnErrorCb;
|
||||
mAutoFocusOnErrorCb = nullptr;
|
||||
if (ecb) {
|
||||
nsresult rv = NS_DispatchToMainThread(new CameraErrorResult(ecb, NS_LITERAL_STRING("CANCELLED")));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
GonkCameraHardware::CancelAutoFocus(mHwHandle);
|
||||
}
|
||||
|
||||
mAutoFocusOnSuccessCb = aAutoFocus->mOnSuccessCb;
|
||||
mAutoFocusOnErrorCb = aAutoFocus->mOnErrorCb;
|
||||
|
||||
if (GonkCameraHardware::AutoFocus(mHwHandle) != OK) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGonkCameraControl::TakePictureImpl(TakePictureTask* aTakePicture)
|
||||
{
|
||||
nsCOMPtr<nsICameraTakePictureCallback> cb = mTakePictureOnSuccessCb;
|
||||
if (cb) {
|
||||
/**
|
||||
* We already have a callback, so someone has already
|
||||
* called TakePicture() -- cancel it.
|
||||
*/
|
||||
mTakePictureOnSuccessCb = nullptr;
|
||||
nsCOMPtr<nsICameraErrorCallback> ecb = mTakePictureOnErrorCb;
|
||||
mTakePictureOnErrorCb = nullptr;
|
||||
if (ecb) {
|
||||
nsresult rv = NS_DispatchToMainThread(new CameraErrorResult(ecb, NS_LITERAL_STRING("CANCELLED")));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
GonkCameraHardware::CancelTakePicture(mHwHandle);
|
||||
}
|
||||
|
||||
mTakePictureOnSuccessCb = aTakePicture->mOnSuccessCb;
|
||||
mTakePictureOnErrorCb = aTakePicture->mOnErrorCb;
|
||||
|
||||
// batch-update camera configuration
|
||||
mDeferConfigUpdate = true;
|
||||
|
||||
/**
|
||||
* height and width: some drivers are less friendly about getting one of
|
||||
* these set to zero, so if either is not specified, ignore both and go
|
||||
* with current or default settings.
|
||||
*/
|
||||
if (aTakePicture->mSize.width && aTakePicture->mSize.height) {
|
||||
nsCString s;
|
||||
s.AppendPrintf("%dx%d", aTakePicture->mSize.width, aTakePicture->mSize.height);
|
||||
DOM_CAMERA_LOGI("setting picture size to '%s'\n", s.get());
|
||||
SetParameter(CameraParameters::KEY_PICTURE_SIZE, s.get());
|
||||
}
|
||||
|
||||
// Picture format -- need to keep it for the callback.
|
||||
mFileFormat = aTakePicture->mFileFormat;
|
||||
SetParameter(CameraParameters::KEY_PICTURE_FORMAT, NS_ConvertUTF16toUTF8(mFileFormat).get());
|
||||
|
||||
// Convert 'rotation' to a positive value from 0..270 degrees, in steps of 90.
|
||||
PRUint32 r = static_cast<PRUint32>(aTakePicture->mRotation);
|
||||
r %= 360;
|
||||
r += 45;
|
||||
r /= 90;
|
||||
r *= 90;
|
||||
DOM_CAMERA_LOGI("setting picture rotation to %d degrees (mapped from %d)\n", r, aTakePicture->mRotation);
|
||||
SetParameter(CameraParameters::KEY_ROTATION, nsPrintfCString("%u", r).get());
|
||||
|
||||
// Add any specified positional information -- don't care if these fail.
|
||||
if (!isnan(aTakePicture->mPosition.latitude)) {
|
||||
DOM_CAMERA_LOGI("setting picture latitude to %lf\n", aTakePicture->mPosition.latitude);
|
||||
SetParameter(CameraParameters::KEY_GPS_LATITUDE, nsPrintfCString("%lf", aTakePicture->mPosition.latitude).get());
|
||||
}
|
||||
if (!isnan(aTakePicture->mPosition.longitude)) {
|
||||
DOM_CAMERA_LOGI("setting picture longitude to %lf\n", aTakePicture->mPosition.longitude);
|
||||
SetParameter(CameraParameters::KEY_GPS_LONGITUDE, nsPrintfCString("%lf", aTakePicture->mPosition.longitude).get());
|
||||
}
|
||||
if (!isnan(aTakePicture->mPosition.altitude)) {
|
||||
DOM_CAMERA_LOGI("setting picture altitude to %lf\n", aTakePicture->mPosition.altitude);
|
||||
SetParameter(CameraParameters::KEY_GPS_ALTITUDE, nsPrintfCString("%lf", aTakePicture->mPosition.altitude).get());
|
||||
}
|
||||
if (!isnan(aTakePicture->mPosition.timestamp)) {
|
||||
DOM_CAMERA_LOGI("setting picture timestamp to %lf\n", aTakePicture->mPosition.timestamp);
|
||||
SetParameter(CameraParameters::KEY_GPS_TIMESTAMP, nsPrintfCString("%lf", aTakePicture->mPosition.timestamp).get());
|
||||
}
|
||||
|
||||
mDeferConfigUpdate = false;
|
||||
PushParameters();
|
||||
|
||||
if (GonkCameraHardware::TakePicture(mHwHandle) != OK) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGonkCameraControl::PushParametersImpl(PushParametersTask* aPushParameters)
|
||||
{
|
||||
RwAutoLockRead lock(mRwLock);
|
||||
if (GonkCameraHardware::PushParameters(mHwHandle, mParams) != OK) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGonkCameraControl::PullParametersImpl(PullParametersTask* aPullParameters)
|
||||
{
|
||||
RwAutoLockWrite lock(mRwLock);
|
||||
GonkCameraHardware::PullParameters(mHwHandle, mParams);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGonkCameraControl::StartRecordingImpl(StartRecordingTask* aStartRecording)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGonkCameraControl::StopRecordingImpl(StopRecordingTask* aStopRecording)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void
|
||||
nsGonkCameraControl::ReceiveFrame(PRUint8* aData, PRUint32 aLength)
|
||||
{
|
||||
nsCOMPtr<CameraPreview> preview = mPreview;
|
||||
|
||||
if (preview) {
|
||||
GonkCameraPreview* p = static_cast<GonkCameraPreview* >(preview.get());
|
||||
MOZ_ASSERT(p);
|
||||
p->ReceiveFrame(aData, aLength);
|
||||
}
|
||||
}
|
||||
|
||||
// Gonk callback handlers.
|
||||
namespace mozilla {
|
||||
|
||||
void
|
||||
ReceiveImage(nsGonkCameraControl* gc, PRUint8* aData, PRUint32 aLength)
|
||||
{
|
||||
gc->TakePictureComplete(aData, aLength);
|
||||
}
|
||||
|
||||
void
|
||||
AutoFocusComplete(nsGonkCameraControl* gc, bool success)
|
||||
{
|
||||
gc->AutoFocusComplete(success);
|
||||
}
|
||||
|
||||
void
|
||||
ReceiveFrame(nsGonkCameraControl* gc, PRUint8* aData, PRUint32 aLength)
|
||||
{
|
||||
gc->ReceiveFrame(aData, aLength);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
76
dom/camera/GonkCameraControl.h
Normal file
76
dom/camera/GonkCameraControl.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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_GONKCAMERACONTROL_H
|
||||
#define DOM_CAMERA_GONKCAMERACONTROL_H
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "prrwlock.h"
|
||||
#include "CameraControl.h"
|
||||
|
||||
#define DOM_CAMERA_LOG_LEVEL 3
|
||||
#include "CameraCommon.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class nsGonkCameraControl : public nsCameraControl
|
||||
{
|
||||
public:
|
||||
nsGonkCameraControl(PRUint32 aCameraId, nsIThread* aCameraThread);
|
||||
|
||||
const char* GetParameter(const char* aKey);
|
||||
const char* GetParameterConstChar(PRUint32 aKey);
|
||||
double GetParameterDouble(PRUint32 aKey);
|
||||
void GetParameter(PRUint32 aKey, nsTArray<dom::CameraRegion>& aRegions);
|
||||
void SetParameter(const char* aKey, const char* aValue);
|
||||
void SetParameter(PRUint32 aKey, const char* aValue);
|
||||
void SetParameter(PRUint32 aKey, double aValue);
|
||||
void SetParameter(PRUint32 aKey, const nsTArray<dom::CameraRegion>& aRegions);
|
||||
void PushParameters();
|
||||
|
||||
void ReceiveFrame(PRUint8 *aData, PRUint32 aLength);
|
||||
|
||||
protected:
|
||||
~nsGonkCameraControl();
|
||||
|
||||
nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream);
|
||||
nsresult AutoFocusImpl(AutoFocusTask* aAutoFocus);
|
||||
nsresult TakePictureImpl(TakePictureTask* aTakePicture);
|
||||
nsresult StartRecordingImpl(StartRecordingTask* aStartRecording);
|
||||
nsresult StopRecordingImpl(StopRecordingTask* aStopRecording);
|
||||
nsresult PushParametersImpl(PushParametersTask* aPushParameters);
|
||||
nsresult PullParametersImpl(PullParametersTask* aPullParameters);
|
||||
|
||||
PRUint32 mHwHandle;
|
||||
double mExposureCompensationMin;
|
||||
double mExposureCompensationStep;
|
||||
bool mDeferConfigUpdate;
|
||||
PRRWLock* mRwLock;
|
||||
android::CameraParameters mParams;
|
||||
|
||||
private:
|
||||
nsGonkCameraControl(const nsGonkCameraControl&) MOZ_DELETE;
|
||||
nsGonkCameraControl& operator=(const nsGonkCameraControl&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
// camera driver callbacks
|
||||
void ReceiveImage(nsGonkCameraControl* gc, PRUint8* aData, PRUint32 aLength);
|
||||
void AutoFocusComplete(nsGonkCameraControl* gc, bool success);
|
||||
void ReceiveFrame(nsGonkCameraControl* gc, PRUint8* aData, PRUint32 aLength);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DOM_CAMERA_GONKCAMERACONTROL_H
|
435
dom/camera/GonkCameraHwMgr.cpp
Normal file
435
dom/camera/GonkCameraHwMgr.cpp
Normal file
@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 "nsDebug.h"
|
||||
#include "GonkCameraHwMgr.h"
|
||||
#include "GonkNativeWindow.h"
|
||||
|
||||
#define DOM_CAMERA_LOG_LEVEL 3
|
||||
#include "CameraCommon.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#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(GonkCamera* aTarget, PRUint32 aCamera)
|
||||
: mCamera(aCamera)
|
||||
, mFps(30)
|
||||
, mPreviewFormat(PREVIEW_FORMAT_UNKNOWN)
|
||||
, mClosing(false)
|
||||
, mMonitor("GonkCameraHardware.Monitor")
|
||||
, mNumFrames(0)
|
||||
, mTarget(aTarget)
|
||||
, mInitialized(false)
|
||||
{
|
||||
DOM_CAMERA_LOGI( "%s: this = %p (aTarget = %p)\n", __func__, (void* )this, (void* )aTarget );
|
||||
init();
|
||||
}
|
||||
|
||||
// Android data callback
|
||||
void
|
||||
GonkCameraHardware::DataCallback(int32_t aMsgType, const sp<IMemory> &aDataPtr, camera_frame_metadata_t* aMetadata, void* aUser)
|
||||
{
|
||||
GonkCameraHardware* hw = GetHardware((PRUint32)aUser);
|
||||
if (!hw) {
|
||||
DOM_CAMERA_LOGW("%s:aUser = %d resolved to no camera hw\n", __func__, (PRUint32)aUser);
|
||||
return;
|
||||
}
|
||||
if (hw->mClosing) {
|
||||
return;
|
||||
}
|
||||
|
||||
GonkCamera* camera = hw->mTarget;
|
||||
if (camera) {
|
||||
switch (aMsgType) {
|
||||
case CAMERA_MSG_PREVIEW_FRAME:
|
||||
ReceiveFrame(camera, (PRUint8*)aDataPtr->pointer(), aDataPtr->size());
|
||||
break;
|
||||
|
||||
case CAMERA_MSG_COMPRESSED_IMAGE:
|
||||
ReceiveImage(camera, (PRUint8*)aDataPtr->pointer(), aDataPtr->size());
|
||||
break;
|
||||
|
||||
default:
|
||||
DOM_CAMERA_LOGE("Unhandled data callback event %d\n", aMsgType);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
DOM_CAMERA_LOGW("%s: hw = %p (camera = NULL)\n", __func__, hw);
|
||||
}
|
||||
}
|
||||
|
||||
// Android notify callback
|
||||
void
|
||||
GonkCameraHardware::NotifyCallback(int32_t aMsgType, int32_t ext1, int32_t ext2, void* aUser)
|
||||
{
|
||||
bool bSuccess;
|
||||
GonkCameraHardware* hw = GetHardware((PRUint32)aUser);
|
||||
if (!hw) {
|
||||
DOM_CAMERA_LOGW("%s:aUser = %d resolved to no camera hw\n", __func__, (PRUint32)aUser);
|
||||
return;
|
||||
}
|
||||
if (hw->mClosing) {
|
||||
return;
|
||||
}
|
||||
|
||||
GonkCamera* camera = hw->mTarget;
|
||||
if (!camera) {
|
||||
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(camera, bSuccess);
|
||||
break;
|
||||
|
||||
case CAMERA_MSG_SHUTTER:
|
||||
DOM_CAMERA_LOGW("Shutter event not handled yet\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
DOM_CAMERA_LOGE("Unhandled notify callback event %d\n", aMsgType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkCameraHardware::init()
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s: this = %p\n", __func__, (void* )this);
|
||||
|
||||
if (hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t**)&mModule) < 0) {
|
||||
return;
|
||||
}
|
||||
char cameraDeviceName[4];
|
||||
snprintf(cameraDeviceName, sizeof(cameraDeviceName), "%d", mCamera);
|
||||
mHardware = new CameraHardwareInterface(cameraDeviceName);
|
||||
if (mHardware->initialize(&mModule->common) != OK) {
|
||||
mHardware.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
mWindow = new android::GonkNativeWindow();
|
||||
|
||||
if (sHwHandle == 0) {
|
||||
sHwHandle = 1; // don't use 0
|
||||
}
|
||||
mHardware->setCallbacks(GonkCameraHardware::NotifyCallback, GonkCameraHardware::DataCallback, NULL, (void*)sHwHandle);
|
||||
|
||||
// initialize the local camera parameter database
|
||||
mParams = mHardware->getParameters();
|
||||
|
||||
mHardware->setPreviewWindow(mWindow);
|
||||
|
||||
mInitialized = true;
|
||||
}
|
||||
|
||||
GonkCameraHardware::~GonkCameraHardware()
|
||||
{
|
||||
DOM_CAMERA_LOGI( "%s:%d : this = %p\n", __func__, __LINE__, (void*)this );
|
||||
sHw = nullptr;
|
||||
}
|
||||
|
||||
GonkCameraHardware* GonkCameraHardware::sHw = nullptr;
|
||||
PRUint32 GonkCameraHardware::sHwHandle = 0;
|
||||
|
||||
void
|
||||
GonkCameraHardware::ReleaseHandle(PRUint32 aHwHandle)
|
||||
{
|
||||
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||
DOM_CAMERA_LOGI("%s: aHwHandle = %d, hw = %p (sHwHandle = %d)\n", __func__, aHwHandle, (void*)hw, sHwHandle);
|
||||
if (!hw) {
|
||||
return;
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGI("%s: before: sHwHandle = %d\n", __func__, sHwHandle);
|
||||
sHwHandle += 1; // invalidate old handles before deleting
|
||||
hw->mClosing = true;
|
||||
hw->mHardware->disableMsgType(CAMERA_MSG_ALL_MSGS);
|
||||
hw->mHardware->stopPreview();
|
||||
hw->mHardware->release();
|
||||
DOM_CAMERA_LOGI("%s: after: sHwHandle = %d\n", __func__, sHwHandle);
|
||||
delete hw; // destroy the camera hardware instance
|
||||
}
|
||||
|
||||
PRUint32
|
||||
GonkCameraHardware::GetHandle(GonkCamera* aTarget, PRUint32 aCamera)
|
||||
{
|
||||
ReleaseHandle(sHwHandle);
|
||||
|
||||
sHw = new GonkCameraHardware(aTarget, aCamera);
|
||||
|
||||
if (sHw->IsInitialized()) {
|
||||
return sHwHandle;
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGE("failed to initialize camera hardware\n");
|
||||
delete sHw;
|
||||
sHw = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
GonkCameraHardware::GetFps(PRUint32 aHwHandle)
|
||||
{
|
||||
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||
if (!hw) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return hw->mFps;
|
||||
}
|
||||
|
||||
void
|
||||
GonkCameraHardware::GetPreviewSize(PRUint32 aHwHandle, PRUint32* aWidth, PRUint32* aHeight)
|
||||
{
|
||||
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||
if (hw) {
|
||||
*aWidth = hw->mWidth;
|
||||
*aHeight = hw->mHeight;
|
||||
} else {
|
||||
*aWidth = 0;
|
||||
*aHeight = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkCameraHardware::SetPreviewSize(PRUint32 aWidth, PRUint32 aHeight)
|
||||
{
|
||||
Vector<Size> previewSizes;
|
||||
PRUint32 bestWidth = aWidth;
|
||||
PRUint32 bestHeight = aHeight;
|
||||
PRUint32 minSizeDelta = PR_UINT32_MAX;
|
||||
PRUint32 delta;
|
||||
Size size;
|
||||
|
||||
mParams.getSupportedPreviewSizes(previewSizes);
|
||||
|
||||
if (!aWidth && !aHeight) {
|
||||
// no size specified, take the first supported size
|
||||
size = previewSizes[0];
|
||||
bestWidth = size.width;
|
||||
bestHeight = size.height;
|
||||
} else if (aWidth && aHeight) {
|
||||
// both height and width specified, find the supported size closest to requested size
|
||||
for (PRUint32 i = 0; i < previewSizes.size(); i++) {
|
||||
Size size = previewSizes[i];
|
||||
PRUint32 delta = abs((long int)(size.width * size.height - aWidth * aHeight));
|
||||
if (delta < minSizeDelta) {
|
||||
minSizeDelta = delta;
|
||||
bestWidth = size.width;
|
||||
bestHeight = size.height;
|
||||
}
|
||||
}
|
||||
} else if (!aWidth) {
|
||||
// width not specified, find closest height match
|
||||
for (PRUint32 i = 0; i < previewSizes.size(); i++) {
|
||||
size = previewSizes[i];
|
||||
delta = abs((long int)(size.height - aHeight));
|
||||
if (delta < minSizeDelta) {
|
||||
minSizeDelta = delta;
|
||||
bestWidth = size.width;
|
||||
bestHeight = size.height;
|
||||
}
|
||||
}
|
||||
} else if (!aHeight) {
|
||||
// height not specified, find closest width match
|
||||
for (PRUint32 i = 0; i < previewSizes.size(); i++) {
|
||||
size = previewSizes[i];
|
||||
delta = abs((long int)(size.width - aWidth));
|
||||
if (delta < minSizeDelta) {
|
||||
minSizeDelta = delta;
|
||||
bestWidth = size.width;
|
||||
bestHeight = size.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mWidth = bestWidth;
|
||||
mHeight = bestHeight;
|
||||
mParams.setPreviewSize(mWidth, mHeight);
|
||||
}
|
||||
|
||||
void
|
||||
GonkCameraHardware::SetPreviewSize(PRUint32 aHwHandle, PRUint32 aWidth, PRUint32 aHeight)
|
||||
{
|
||||
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||
if (hw) {
|
||||
hw->SetPreviewSize(aWidth, aHeight);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
GonkCameraHardware::AutoFocus(PRUint32 aHwHandle)
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s: aHwHandle = %d\n", __func__, aHwHandle);
|
||||
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||
if (!hw) {
|
||||
return DEAD_OBJECT;
|
||||
}
|
||||
|
||||
hw->mHardware->enableMsgType(CAMERA_MSG_FOCUS);
|
||||
return hw->mHardware->autoFocus();
|
||||
}
|
||||
|
||||
void
|
||||
GonkCameraHardware::CancelAutoFocus(PRUint32 aHwHandle)
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s: aHwHandle = %d\n", __func__, aHwHandle);
|
||||
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||
if (hw) {
|
||||
hw->mHardware->cancelAutoFocus();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
GonkCameraHardware::TakePicture(PRUint32 aHwHandle)
|
||||
{
|
||||
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||
if (!hw) {
|
||||
return DEAD_OBJECT;
|
||||
}
|
||||
|
||||
hw->mHardware->enableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
|
||||
return hw->mHardware->takePicture();
|
||||
}
|
||||
|
||||
void
|
||||
GonkCameraHardware::CancelTakePicture(PRUint32 aHwHandle)
|
||||
{
|
||||
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||
if (hw) {
|
||||
hw->mHardware->cancelPicture();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
GonkCameraHardware::PushParameters(PRUint32 aHwHandle, const CameraParameters& aParams)
|
||||
{
|
||||
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||
if (!hw) {
|
||||
return DEAD_OBJECT;
|
||||
}
|
||||
|
||||
return hw->mHardware->setParameters(aParams);
|
||||
}
|
||||
|
||||
void
|
||||
GonkCameraHardware::PullParameters(PRUint32 aHwHandle, CameraParameters& aParams)
|
||||
{
|
||||
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||
if (hw) {
|
||||
aParams = hw->mHardware->getParameters();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
GonkCameraHardware::StartPreview()
|
||||
{
|
||||
const char* format;
|
||||
|
||||
mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
|
||||
|
||||
DOM_CAMERA_LOGI("Preview formats: %s\n", mParams.get(mParams.KEY_SUPPORTED_PREVIEW_FORMATS));
|
||||
|
||||
// try to set preferred image format and frame rate
|
||||
const char* const PREVIEW_FORMAT = "yuv420p";
|
||||
const char* const BAD_PREVIEW_FORMAT = "yuv420sp";
|
||||
mParams.setPreviewFormat(PREVIEW_FORMAT);
|
||||
mParams.setPreviewFrameRate(mFps);
|
||||
mHardware->setParameters(mParams);
|
||||
|
||||
// check that our settings stuck
|
||||
mParams = mHardware->getParameters();
|
||||
format = mParams.getPreviewFormat();
|
||||
if (strcmp(format, PREVIEW_FORMAT) == 0) {
|
||||
mPreviewFormat = PREVIEW_FORMAT_YUV420P; /* \o/ */
|
||||
} else if (strcmp(format, BAD_PREVIEW_FORMAT) == 0) {
|
||||
mPreviewFormat = PREVIEW_FORMAT_YUV420SP;
|
||||
DOM_CAMERA_LOGA("Camera ignored our request for '%s' preview, will have to convert (from %d)\n", PREVIEW_FORMAT, mPreviewFormat);
|
||||
} else {
|
||||
mPreviewFormat = PREVIEW_FORMAT_UNKNOWN;
|
||||
DOM_CAMERA_LOGE("Camera ignored our request for '%s' preview, returned UNSUPPORTED format '%s'\n", PREVIEW_FORMAT, format);
|
||||
}
|
||||
|
||||
// Check the frame rate and log if the camera ignored our setting
|
||||
PRUint32 fps = mParams.getPreviewFrameRate();
|
||||
if (fps != mFps) {
|
||||
DOM_CAMERA_LOGA("We asked for %d fps but camera returned %d fps, using it", mFps, fps);
|
||||
mFps = fps;
|
||||
}
|
||||
|
||||
return mHardware->startPreview();
|
||||
}
|
||||
|
||||
int
|
||||
GonkCameraHardware::StartPreview(PRUint32 aHwHandle)
|
||||
{
|
||||
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||
DOM_CAMERA_LOGI("%s:%d : aHwHandle = %d, hw = %p\n", __func__, __LINE__, aHwHandle, hw);
|
||||
if (!hw) {
|
||||
return DEAD_OBJECT;
|
||||
}
|
||||
|
||||
return hw->StartPreview();
|
||||
}
|
||||
|
||||
void
|
||||
GonkCameraHardware::StopPreview(PRUint32 aHwHandle)
|
||||
{
|
||||
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||
if (hw) {
|
||||
hw->mHardware->stopPreview();
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32
|
||||
GonkCameraHardware::GetPreviewFormat(PRUint32 aHwHandle)
|
||||
{
|
||||
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||
if (!hw) {
|
||||
return PREVIEW_FORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
return hw->mPreviewFormat;
|
||||
}
|
125
dom/camera/GonkCameraHwMgr.h
Normal file
125
dom/camera/GonkCameraHwMgr.h
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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_GONKCAMERAHWMGR_H
|
||||
#define DOM_CAMERA_GONKCAMERAHWMGR_H
|
||||
|
||||
#include "libcameraservice/CameraHardwareInterface.h"
|
||||
#include "binder/IMemory.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
|
||||
#include "GonkCameraControl.h"
|
||||
|
||||
#define DOM_CAMERA_LOG_LEVEL 3
|
||||
#include "CameraCommon.h"
|
||||
|
||||
// config
|
||||
#define GIHM_TIMING_RECEIVEFRAME 0
|
||||
#define GIHM_TIMING_OVERALL 1
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace android;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
typedef class nsGonkCameraControl GonkCamera;
|
||||
|
||||
class GonkCameraHardware
|
||||
{
|
||||
protected:
|
||||
GonkCameraHardware(GonkCamera* aTarget, PRUint32 aCamera);
|
||||
~GonkCameraHardware();
|
||||
void init();
|
||||
|
||||
static void DataCallback(int32_t aMsgType, const sp<IMemory> &aDataPtr, camera_frame_metadata_t* aMetadata, void* aUser);
|
||||
static void NotifyCallback(int32_t aMsgType, int32_t ext1, int32_t ext2, void* aUser);
|
||||
|
||||
public:
|
||||
static void ReleaseHandle(PRUint32 aHwHandle);
|
||||
static PRUint32 GetHandle(GonkCamera* aTarget, PRUint32 aCamera);
|
||||
static PRUint32 GetFps(PRUint32 aHwHandle);
|
||||
static void GetPreviewSize(PRUint32 aHwHandle, PRUint32* aWidth, PRUint32* aHeight);
|
||||
static void SetPreviewSize(PRUint32 aHwHandle, PRUint32 aWidth, PRUint32 aHeight);
|
||||
static int AutoFocus(PRUint32 aHwHandle);
|
||||
static void CancelAutoFocus(PRUint32 aHwHandle);
|
||||
static int TakePicture(PRUint32 aHwHandle);
|
||||
static void CancelTakePicture(PRUint32 aHwHandle);
|
||||
static int StartPreview(PRUint32 aHwHandle);
|
||||
static void StopPreview(PRUint32 aHwHandle);
|
||||
static int PushParameters(PRUint32 aHwHandle, const CameraParameters& aParams);
|
||||
static void PullParameters(PRUint32 aHwHandle, CameraParameters& aParams);
|
||||
|
||||
enum {
|
||||
PREVIEW_FORMAT_UNKNOWN,
|
||||
PREVIEW_FORMAT_YUV420P,
|
||||
PREVIEW_FORMAT_YUV420SP
|
||||
};
|
||||
// GetPreviewFormat() MUST be called only after StartPreview().
|
||||
static PRUint32 GetPreviewFormat(PRUint32 aHwHandle);
|
||||
|
||||
protected:
|
||||
static GonkCameraHardware* sHw;
|
||||
static PRUint32 sHwHandle;
|
||||
|
||||
static GonkCameraHardware* GetHardware(PRUint32 aHwHandle)
|
||||
{
|
||||
if (aHwHandle == sHwHandle) {
|
||||
/**
|
||||
* In the initial case, sHw will be null and sHwHandle will be 0,
|
||||
* so even if this function is called with aHwHandle = 0, the
|
||||
* result will still be null.
|
||||
*/
|
||||
return sHw;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Instance wrappers to make member function access easier.
|
||||
void SetPreviewSize(PRUint32 aWidth, PRUint32 aHeight);
|
||||
int StartPreview();
|
||||
|
||||
PRUint32 mCamera;
|
||||
PRUint32 mWidth;
|
||||
PRUint32 mHeight;
|
||||
PRUint32 mFps;
|
||||
PRUint32 mPreviewFormat;
|
||||
bool mClosing;
|
||||
mozilla::ReentrantMonitor mMonitor;
|
||||
PRUint32 mNumFrames;
|
||||
sp<CameraHardwareInterface> mHardware;
|
||||
GonkCamera* mTarget;
|
||||
camera_module_t* mModule;
|
||||
sp<ANativeWindow> mWindow;
|
||||
CameraParameters mParams;
|
||||
#if GIHM_TIMING_OVERALL
|
||||
struct timespec mStart;
|
||||
struct timespec mAutoFocusStart;
|
||||
#endif
|
||||
bool mInitialized;
|
||||
|
||||
bool IsInitialized()
|
||||
{
|
||||
return mInitialized;
|
||||
}
|
||||
|
||||
private:
|
||||
GonkCameraHardware(const GonkCameraHardware&) MOZ_DELETE;
|
||||
GonkCameraHardware& operator=(const GonkCameraHardware&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GONK_IMPL_HW_MGR_H
|
107
dom/camera/GonkCameraManager.cpp
Normal file
107
dom/camera/GonkCameraManager.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 "jsapi.h"
|
||||
#include "libcameraservice/CameraHardwareInterface.h"
|
||||
#include "GonkCameraControl.h"
|
||||
#include "DOMCameraManager.h"
|
||||
|
||||
#define DOM_CAMERA_LOG_LEVEL 3
|
||||
#include "CameraCommon.h"
|
||||
|
||||
// From nsDOMCameraManager, but gonk-specific!
|
||||
|
||||
/* [implicit_jscontext] jsval getListOfCameras (); */
|
||||
NS_IMETHODIMP
|
||||
nsDOMCameraManager::GetListOfCameras(JSContext* cx, JS::Value* _retval)
|
||||
{
|
||||
JSObject* a = JS_NewArrayObject(cx, 0, nullptr);
|
||||
camera_module_t* module;
|
||||
PRUint32 index = 0;
|
||||
PRUint32 count;
|
||||
|
||||
if (!a) {
|
||||
DOM_CAMERA_LOGE("getListOfCameras : Could not create array object");
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t**)&module) < 0) {
|
||||
DOM_CAMERA_LOGE("getListOfCameras : Could not load camera HAL module");
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
count = module->get_number_of_cameras();
|
||||
DOM_CAMERA_LOGI("getListOfCameras : get_number_of_cameras() returned %d\n", count);
|
||||
while (count--) {
|
||||
struct camera_info info;
|
||||
int rv = module->get_camera_info(count, &info);
|
||||
if (rv != 0) {
|
||||
DOM_CAMERA_LOGE("getListOfCameras : get_camera_info(%d) failed: %d\n", count, rv);
|
||||
continue;
|
||||
}
|
||||
|
||||
JSString* v;
|
||||
jsval jv;
|
||||
|
||||
switch (info.facing) {
|
||||
case CAMERA_FACING_BACK:
|
||||
v = JS_NewStringCopyZ(cx, "back");
|
||||
index = 0;
|
||||
break;
|
||||
|
||||
case CAMERA_FACING_FRONT:
|
||||
v = JS_NewStringCopyZ(cx, "front");
|
||||
index = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
// TODO: handle extra cameras in getCamera().
|
||||
{
|
||||
static PRUint32 extraIndex = 2;
|
||||
nsCString s;
|
||||
s.AppendPrintf("extra-camera-%d", count);
|
||||
v = JS_NewStringCopyZ(cx, s.get());
|
||||
index = extraIndex++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!v) {
|
||||
DOM_CAMERA_LOGE("getListOfCameras : out of memory populating camera list");
|
||||
delete a;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
jv = STRING_TO_JSVAL(v);
|
||||
if (!JS_SetElement(cx, a, index, &jv)) {
|
||||
DOM_CAMERA_LOGE("getListOfCameras : failed building list of cameras");
|
||||
delete a;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
*_retval = OBJECT_TO_JSVAL(a);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMETHODIMP
|
||||
GetCameraTask::Run()
|
||||
{
|
||||
nsCOMPtr<nsICameraControl> cameraControl = new nsGonkCameraControl(mCameraId, mCameraThread);
|
||||
|
||||
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
return NS_DispatchToMainThread(new GetCameraResult(cameraControl, mOnSuccessCb));
|
||||
}
|
197
dom/camera/GonkCameraPreview.cpp
Normal file
197
dom/camera/GonkCameraPreview.cpp
Normal file
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 "VideoUtils.h"
|
||||
#include "GonkCameraHwMgr.h"
|
||||
#include "GonkCameraPreview.h"
|
||||
|
||||
#define DOM_CAMERA_LOG_LEVEL 2
|
||||
#include "CameraCommon.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
/**
|
||||
* This big macro takes two 32-bit input blocks of interlaced u and
|
||||
* v data (from a yuv420sp frame) in 's0' and 's1', and deinterlaces
|
||||
* them into pairs of contiguous 32-bit blocks, the u plane data in
|
||||
* 'u', and the v plane data in 'v' (i.e. for a yuv420p frame).
|
||||
*
|
||||
* yuv420sp:
|
||||
* [ y-data ][ uv-data ]
|
||||
* [ uv-data ]: [u0][v0][u1][v1][u2][v2]...
|
||||
*
|
||||
* yuv420p:
|
||||
* [ y-data ][ u-data ][ v-data ]
|
||||
* [ u-data ]: [u0][u1][u2]...
|
||||
* [ v-data ]: [v0][v1][v2]...
|
||||
*
|
||||
* Doing this in 32-bit blocks is significantly faster than using
|
||||
* byte-wise operations on ARM. (In some cases, the byte-wise
|
||||
* de-interlacing can be too slow to keep up with the preview frames
|
||||
* coming from the driver.
|
||||
*/
|
||||
#define DEINTERLACE( u, v, s0, s1 ) \
|
||||
u = ( (s0) & 0xFF00UL ) >> 8 | ( (s0) & 0xFF000000UL ) >> 16; \
|
||||
u |= ( (s1) & 0xFF00UL ) << 8 | ( (s1) & 0xFF000000UL ); \
|
||||
v = ( (s0) & 0xFFUL ) | ( (s0) & 0xFF0000UL ) >> 8; \
|
||||
v |= ( (s1) & 0xFFUL ) << 16 | ( (s1) & 0xFF0000UL ) << 8;
|
||||
|
||||
void
|
||||
GonkCameraPreview::ReceiveFrame(PRUint8 *aData, PRUint32 aLength)
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
|
||||
if (mInput->HaveEnoughBuffered(TRACK_VIDEO)) {
|
||||
if (mDiscardedFrameCount == 0) {
|
||||
DOM_CAMERA_LOGI("mInput has enough data buffered, starting to discard\n");
|
||||
}
|
||||
++mDiscardedFrameCount;
|
||||
return;
|
||||
} else if (mDiscardedFrameCount) {
|
||||
DOM_CAMERA_LOGI("mInput needs more data again; discarded %d frames in a row\n", mDiscardedFrameCount);
|
||||
mDiscardedFrameCount = 0;
|
||||
}
|
||||
|
||||
switch (mFormat) {
|
||||
case GonkCameraHardware::PREVIEW_FORMAT_YUV420SP:
|
||||
{
|
||||
// de-interlace the u and v planes
|
||||
uint8_t* y = aData;
|
||||
uint32_t yN = mWidth * mHeight;
|
||||
|
||||
NS_ASSERTION(yN & 0x3 == 0, "Invalid image dimensions!");
|
||||
|
||||
uint32_t uvN = yN / 4;
|
||||
uint32_t* src = (uint32_t*)( y + yN );
|
||||
uint32_t* d = new uint32_t[ uvN / 2 ];
|
||||
uint32_t* u = d;
|
||||
uint32_t* v = u + uvN / 4;
|
||||
|
||||
// we're handling pairs of 32-bit words, so divide by 8
|
||||
NS_ASSERTION(uvN & 0x7 == 0, "Invalid image dimensions!");
|
||||
uvN /= 8;
|
||||
|
||||
while (uvN--) {
|
||||
uint32_t src0 = *src++;
|
||||
uint32_t src1 = *src++;
|
||||
|
||||
uint32_t u0;
|
||||
uint32_t v0;
|
||||
uint32_t u1;
|
||||
uint32_t v1;
|
||||
|
||||
DEINTERLACE( u0, v0, src0, src1 );
|
||||
|
||||
src0 = *src++;
|
||||
src1 = *src++;
|
||||
|
||||
DEINTERLACE( u1, v1, src0, src1 );
|
||||
|
||||
*u++ = u0;
|
||||
*u++ = u1;
|
||||
*v++ = v0;
|
||||
*v++ = v1;
|
||||
}
|
||||
|
||||
memcpy(y + yN, d, yN / 2);
|
||||
delete[] d;
|
||||
}
|
||||
break;
|
||||
|
||||
case GonkCameraHardware::PREVIEW_FORMAT_YUV420P:
|
||||
// no transformating required
|
||||
break;
|
||||
|
||||
default:
|
||||
// in a format we don't handle, get out of here
|
||||
return;
|
||||
}
|
||||
|
||||
Image::Format format = Image::PLANAR_YCBCR;
|
||||
nsRefPtr<Image> image = mImageContainer->CreateImage(&format, 1);
|
||||
image->AddRef();
|
||||
PlanarYCbCrImage* videoImage = static_cast<PlanarYCbCrImage*>(image.get());
|
||||
|
||||
/**
|
||||
* If you change either lumaBpp or chromaBpp, make sure the
|
||||
* assertions below still hold.
|
||||
*/
|
||||
const PRUint8 lumaBpp = 8;
|
||||
const PRUint8 chromaBpp = 4;
|
||||
PlanarYCbCrImage::Data data;
|
||||
data.mYChannel = aData;
|
||||
data.mYSize = gfxIntSize(mWidth, mHeight);
|
||||
|
||||
data.mYStride = mWidth * lumaBpp;
|
||||
NS_ASSERTION(data.mYStride & 0x7 == 0, "Invalid image dimensions!");
|
||||
data.mYStride /= 8;
|
||||
|
||||
data.mCbCrStride = mWidth * chromaBpp;
|
||||
NS_ASSERTION(data.mCbCrStride & 0x7 == 0, "Invalid image dimensions!");
|
||||
data.mCbCrStride /= 8;
|
||||
|
||||
data.mCbChannel = aData + mHeight * data.mYStride;
|
||||
data.mCrChannel = data.mCbChannel + mHeight * data.mCbCrStride / 2;
|
||||
data.mCbCrSize = gfxIntSize(mWidth / 2, mHeight / 2);
|
||||
data.mPicX = 0;
|
||||
data.mPicY = 0;
|
||||
data.mPicSize = gfxIntSize(mWidth, mHeight);
|
||||
data.mStereoMode = mozilla::layers::STEREO_MODE_MONO;
|
||||
videoImage->SetData(data); // copies buffer
|
||||
|
||||
mVideoSegment.AppendFrame(videoImage, 1, gfxIntSize(mWidth, mHeight));
|
||||
mInput->AppendToTrack(TRACK_VIDEO, &mVideoSegment);
|
||||
|
||||
mFrameCount += 1;
|
||||
|
||||
if ((mFrameCount % 10) == 0) {
|
||||
DOM_CAMERA_LOGI("%s:%d : mFrameCount = %d\n", __func__, __LINE__, mFrameCount);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkCameraPreview::Start()
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
|
||||
/**
|
||||
* We set and then immediately get the preview size, in case the camera
|
||||
* driver has decided to ignore our given dimensions. We need to know
|
||||
* the dimensions the driver is using so that, if needed, we can properly
|
||||
* de-interlace the yuv420sp format in ReceiveFrame() above.
|
||||
*/
|
||||
GonkCameraHardware::SetPreviewSize(mHwHandle, mWidth, mHeight);
|
||||
GonkCameraHardware::GetPreviewSize(mHwHandle, &mWidth, &mHeight);
|
||||
SetFrameRate(GonkCameraHardware::GetFps(mHwHandle));
|
||||
|
||||
if (GonkCameraHardware::StartPreview(mHwHandle) == OK) {
|
||||
// GetPreviewFormat() must be called after StartPreview().
|
||||
mFormat = GonkCameraHardware::GetPreviewFormat(mHwHandle);
|
||||
DOM_CAMERA_LOGI("preview stream is (actually!) %d x %d (w x h), %d frames per second, format %d\n", mWidth, mHeight, mFramesPerSecond, mFormat);
|
||||
} else {
|
||||
DOM_CAMERA_LOGE("%s: failed to start preview\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkCameraPreview::Stop()
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
|
||||
GonkCameraHardware::StopPreview(mHwHandle);
|
||||
mInput->EndTrack(TRACK_VIDEO);
|
||||
mInput->Finish();
|
||||
}
|
59
dom/camera/GonkCameraPreview.h
Normal file
59
dom/camera/GonkCameraPreview.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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_GONKCAMERAPREVIEW_H
|
||||
#define DOM_CAMERA_GONKCAMERAPREVIEW_H
|
||||
|
||||
#include "CameraPreview.h"
|
||||
|
||||
#define DOM_CAMERA_LOG_LEVEL 3
|
||||
#include "CameraCommon.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class GonkCameraPreview : public CameraPreview
|
||||
{
|
||||
public:
|
||||
GonkCameraPreview(PRUint32 aHwHandle, PRUint32 aWidth, PRUint32 aHeight)
|
||||
: CameraPreview(aWidth, aHeight)
|
||||
, mHwHandle(aHwHandle)
|
||||
, mDiscardedFrameCount(0)
|
||||
, mFormat(GonkCameraHardware::PREVIEW_FORMAT_UNKNOWN)
|
||||
{ }
|
||||
|
||||
void ReceiveFrame(PRUint8 *aData, PRUint32 aLength);
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
protected:
|
||||
~GonkCameraPreview()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
PRUint32 mHwHandle;
|
||||
PRUint32 mDiscardedFrameCount;
|
||||
PRUint32 mFormat;
|
||||
|
||||
private:
|
||||
GonkCameraPreview(const GonkCameraPreview&) MOZ_DELETE;
|
||||
GonkCameraPreview& operator=(const GonkCameraPreview&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DOM_CAMERA_GONKCAMERAPREVIEW_H
|
475
dom/camera/GonkNativeWindow.cpp
Normal file
475
dom/camera/GonkNativeWindow.cpp
Normal file
@ -0,0 +1,475 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
* Copyright (C) 2012 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 "GonkNativeWindow.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
// enable debug logging by setting to 1
|
||||
#define CNW_DEBUG 0
|
||||
#if CNW_DEBUG
|
||||
#define CNW_LOGD(...) {(void)printf_stderr(__VA_ARGS__);}
|
||||
#else
|
||||
#define CNW_LOGD(...) ((void)0)
|
||||
#endif
|
||||
|
||||
#define CNW_LOGE(...) {(void)printf_stderr(__VA_ARGS__);}
|
||||
|
||||
using namespace android;
|
||||
|
||||
GonkNativeWindow::GonkNativeWindow()
|
||||
{
|
||||
GonkNativeWindow::init();
|
||||
}
|
||||
|
||||
GonkNativeWindow::~GonkNativeWindow()
|
||||
{
|
||||
freeAllBuffersLocked();
|
||||
}
|
||||
|
||||
void GonkNativeWindow::init()
|
||||
{
|
||||
// Initialize the ANativeWindow function pointers.
|
||||
ANativeWindow::setSwapInterval = hook_setSwapInterval;
|
||||
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
|
||||
ANativeWindow::cancelBuffer = hook_cancelBuffer;
|
||||
ANativeWindow::lockBuffer = hook_lockBuffer;
|
||||
ANativeWindow::queueBuffer = hook_queueBuffer;
|
||||
ANativeWindow::query = hook_query;
|
||||
ANativeWindow::perform = hook_perform;
|
||||
|
||||
mDefaultWidth = 0;
|
||||
mDefaultHeight = 0;
|
||||
mPixelFormat = 0;
|
||||
mUsage = 0;
|
||||
mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
|
||||
mBufferCount = MIN_BUFFER_SLOTS;
|
||||
mFrameCounter = 0;
|
||||
}
|
||||
|
||||
|
||||
int GonkNativeWindow::hook_setSwapInterval(ANativeWindow* window, int interval)
|
||||
{
|
||||
GonkNativeWindow* c = getSelf(window);
|
||||
return c->setSwapInterval(interval);
|
||||
}
|
||||
|
||||
int GonkNativeWindow::hook_dequeueBuffer(ANativeWindow* window,
|
||||
ANativeWindowBuffer** buffer)
|
||||
{
|
||||
GonkNativeWindow* c = getSelf(window);
|
||||
return c->dequeueBuffer(buffer);
|
||||
}
|
||||
|
||||
int GonkNativeWindow::hook_cancelBuffer(ANativeWindow* window,
|
||||
ANativeWindowBuffer* buffer)
|
||||
{
|
||||
GonkNativeWindow* c = getSelf(window);
|
||||
return c->cancelBuffer(buffer);
|
||||
}
|
||||
|
||||
int GonkNativeWindow::hook_lockBuffer(ANativeWindow* window,
|
||||
ANativeWindowBuffer* buffer)
|
||||
{
|
||||
GonkNativeWindow* c = getSelf(window);
|
||||
return c->lockBuffer(buffer);
|
||||
}
|
||||
|
||||
int GonkNativeWindow::hook_queueBuffer(ANativeWindow* window,
|
||||
ANativeWindowBuffer* buffer)
|
||||
{
|
||||
GonkNativeWindow* c = getSelf(window);
|
||||
return c->queueBuffer(buffer);
|
||||
}
|
||||
|
||||
int GonkNativeWindow::hook_query(const ANativeWindow* window,
|
||||
int what, int* value)
|
||||
{
|
||||
const GonkNativeWindow* c = getSelf(window);
|
||||
return c->query(what, value);
|
||||
}
|
||||
|
||||
int GonkNativeWindow::hook_perform(ANativeWindow* window, int operation, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, operation);
|
||||
GonkNativeWindow* c = getSelf(window);
|
||||
return c->perform(operation, args);
|
||||
}
|
||||
|
||||
void GonkNativeWindow::freeBufferLocked(int i)
|
||||
{
|
||||
if (mSlots[i].mGraphicBuffer != NULL) {
|
||||
mSlots[i].mGraphicBuffer.clear();
|
||||
mSlots[i].mGraphicBuffer = NULL;
|
||||
}
|
||||
mSlots[i].mBufferState = BufferSlot::FREE;
|
||||
}
|
||||
|
||||
void GonkNativeWindow::freeAllBuffersLocked()
|
||||
{
|
||||
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
|
||||
freeBufferLocked(i);
|
||||
}
|
||||
}
|
||||
|
||||
int GonkNativeWindow::setBufferCount(int bufferCount) {
|
||||
CNW_LOGD("setBufferCount: count=%d", bufferCount);
|
||||
Mutex::Autolock lock(mMutex);
|
||||
|
||||
if (bufferCount > NUM_BUFFER_SLOTS) {
|
||||
CNW_LOGE("setBufferCount: bufferCount larger than slots available");
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
// special-case, nothing to do
|
||||
if (bufferCount == mBufferCount) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (bufferCount < MIN_BUFFER_SLOTS) {
|
||||
CNW_LOGE("setBufferCount: requested buffer count (%d) is less than "
|
||||
"minimum (%d)", bufferCount, MIN_BUFFER_SLOTS);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
// Error out if the user has dequeued buffers
|
||||
for (int i=0 ; i<mBufferCount ; i++) {
|
||||
if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
|
||||
CNW_LOGE("setBufferCount: client owns some buffers");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (bufferCount > mBufferCount) {
|
||||
// easy, we just have more buffers
|
||||
mBufferCount = bufferCount;
|
||||
mDequeueCondition.signal();
|
||||
return OK;
|
||||
}
|
||||
|
||||
// reducing the number of buffers
|
||||
// here we're guaranteed that the client doesn't have dequeued buffers
|
||||
// and will release all of its buffer references.
|
||||
freeAllBuffersLocked();
|
||||
mBufferCount = bufferCount;
|
||||
mDequeueCondition.signal();
|
||||
return OK;
|
||||
}
|
||||
|
||||
int GonkNativeWindow::dequeueBuffer(android_native_buffer_t** buffer)
|
||||
{
|
||||
Mutex::Autolock lock(mMutex);
|
||||
|
||||
int found = -1;
|
||||
int dequeuedCount = 0;
|
||||
bool tryAgain = true;
|
||||
|
||||
CNW_LOGD("dequeueBuffer: E");
|
||||
while (tryAgain) {
|
||||
// look for a free buffer to give to the client
|
||||
found = INVALID_BUFFER_SLOT;
|
||||
dequeuedCount = 0;
|
||||
for (int i = 0; i < mBufferCount; i++) {
|
||||
const int state = mSlots[i].mBufferState;
|
||||
if (state == BufferSlot::DEQUEUED) {
|
||||
dequeuedCount++;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
bool isOlder = mSlots[i].mFrameNumber < mSlots[found].mFrameNumber;
|
||||
if (found < 0 || isOlder) {
|
||||
found = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we're in synchronous mode and didn't find a buffer, we need to
|
||||
// wait for some buffers to be consumed
|
||||
tryAgain = (found == INVALID_BUFFER_SLOT);
|
||||
if (tryAgain) {
|
||||
mDequeueCondition.wait(mMutex);
|
||||
}
|
||||
}
|
||||
|
||||
if (found == INVALID_BUFFER_SLOT) {
|
||||
// This should not happen.
|
||||
CNW_LOGE("dequeueBuffer: no available buffer slots");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
const int buf = found;
|
||||
|
||||
// buffer is now in DEQUEUED
|
||||
mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
|
||||
|
||||
const sp<GraphicBuffer>& gbuf(mSlots[buf].mGraphicBuffer);
|
||||
|
||||
if (gbuf == NULL) {
|
||||
status_t error;
|
||||
sp<GraphicBuffer> graphicBuffer( new GraphicBuffer( mDefaultWidth, mDefaultHeight, mPixelFormat, mUsage));
|
||||
error = graphicBuffer->initCheck();
|
||||
if (error != NO_ERROR) {
|
||||
CNW_LOGE("dequeueBuffer: createGraphicBuffer failed with error %d",error);
|
||||
return error;
|
||||
}
|
||||
mSlots[buf].mGraphicBuffer = graphicBuffer;
|
||||
}
|
||||
*buffer = mSlots[buf].mGraphicBuffer.get();
|
||||
|
||||
CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
|
||||
mSlots[buf].mGraphicBuffer->handle );
|
||||
|
||||
CNW_LOGD("dequeueBuffer: X");
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int GonkNativeWindow::getSlotFromBufferLocked(
|
||||
android_native_buffer_t* buffer) const
|
||||
{
|
||||
if (buffer == NULL) {
|
||||
CNW_LOGE("getSlotFromBufferLocked: encountered NULL buffer");
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
|
||||
if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
CNW_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
int GonkNativeWindow::queueBuffer(ANativeWindowBuffer* buffer)
|
||||
{
|
||||
Mutex::Autolock lock(mMutex);
|
||||
CNW_LOGD("queueBuffer: E");
|
||||
int buf = getSlotFromBufferLocked(buffer);
|
||||
|
||||
if (buf < 0 || buf >= mBufferCount) {
|
||||
CNW_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
|
||||
mBufferCount, buf);
|
||||
return -EINVAL;
|
||||
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
|
||||
CNW_LOGE("queueBuffer: slot %d is not owned by the client "
|
||||
"(state=%d)", buf, mSlots[buf].mBufferState);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int64_t timestamp;
|
||||
if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
|
||||
timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
} else {
|
||||
timestamp = mTimestamp;
|
||||
}
|
||||
|
||||
// Set the state to FREE as there are no operations on the queued buffer
|
||||
// And, so that the buffer can be dequeued when needed.
|
||||
mSlots[buf].mBufferState = BufferSlot::FREE;
|
||||
mSlots[buf].mTimestamp = timestamp;
|
||||
mFrameCounter++;
|
||||
mSlots[buf].mFrameNumber = mFrameCounter;
|
||||
|
||||
mDequeueCondition.signal();
|
||||
CNW_LOGD("queueBuffer: X");
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int GonkNativeWindow::lockBuffer(ANativeWindowBuffer* buffer)
|
||||
{
|
||||
CNW_LOGD("GonkNativeWindow::lockBuffer");
|
||||
Mutex::Autolock lock(mMutex);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int GonkNativeWindow::cancelBuffer(ANativeWindowBuffer* buffer)
|
||||
{
|
||||
Mutex::Autolock lock(mMutex);
|
||||
int buf = getSlotFromBufferLocked(buffer);
|
||||
|
||||
CNW_LOGD("cancelBuffer: slot=%d", buf);
|
||||
if (buf < 0 || buf >= mBufferCount) {
|
||||
CNW_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
|
||||
mBufferCount, buf);
|
||||
return -EINVAL;
|
||||
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
|
||||
CNW_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
|
||||
buf, mSlots[buf].mBufferState);
|
||||
return -EINVAL;
|
||||
}
|
||||
mSlots[buf].mBufferState = BufferSlot::FREE;
|
||||
mSlots[buf].mFrameNumber = 0;
|
||||
mDequeueCondition.signal();
|
||||
return OK;
|
||||
}
|
||||
|
||||
int GonkNativeWindow::perform(int operation, va_list args)
|
||||
{
|
||||
switch (operation) {
|
||||
case NATIVE_WINDOW_CONNECT:
|
||||
// deprecated. must return NO_ERROR.
|
||||
return NO_ERROR;
|
||||
case NATIVE_WINDOW_DISCONNECT:
|
||||
// deprecated. must return NO_ERROR.
|
||||
return NO_ERROR;
|
||||
case NATIVE_WINDOW_SET_USAGE:
|
||||
return dispatchSetUsage(args);
|
||||
case NATIVE_WINDOW_SET_BUFFER_COUNT:
|
||||
return dispatchSetBufferCount(args);
|
||||
case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
|
||||
return dispatchSetBuffersGeometry(args);
|
||||
case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
|
||||
return dispatchSetBuffersTimestamp(args);
|
||||
case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
|
||||
return dispatchSetBuffersDimensions(args);
|
||||
case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
|
||||
return dispatchSetBuffersFormat(args);
|
||||
case NATIVE_WINDOW_SET_CROP:
|
||||
case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
|
||||
case NATIVE_WINDOW_SET_SCALING_MODE:
|
||||
case NATIVE_WINDOW_LOCK:
|
||||
case NATIVE_WINDOW_UNLOCK_AND_POST:
|
||||
case NATIVE_WINDOW_API_CONNECT:
|
||||
case NATIVE_WINDOW_API_DISCONNECT:
|
||||
default:
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
int GonkNativeWindow::query(int what, int* outValue) const
|
||||
{
|
||||
Mutex::Autolock lock(mMutex);
|
||||
|
||||
int value;
|
||||
switch (what) {
|
||||
case NATIVE_WINDOW_WIDTH:
|
||||
value = mDefaultWidth;
|
||||
break;
|
||||
case NATIVE_WINDOW_HEIGHT:
|
||||
value = mDefaultHeight;
|
||||
break;
|
||||
case NATIVE_WINDOW_FORMAT:
|
||||
value = mPixelFormat;
|
||||
break;
|
||||
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
|
||||
value = MIN_UNDEQUEUED_BUFFERS;
|
||||
break;
|
||||
default:
|
||||
return BAD_VALUE;
|
||||
}
|
||||
outValue[0] = value;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int GonkNativeWindow::setSwapInterval(int interval)
|
||||
{
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int GonkNativeWindow::dispatchSetUsage(va_list args)
|
||||
{
|
||||
int usage = va_arg(args, int);
|
||||
return setUsage(usage);
|
||||
}
|
||||
|
||||
int GonkNativeWindow::dispatchSetBufferCount(va_list args)
|
||||
{
|
||||
size_t bufferCount = va_arg(args, size_t);
|
||||
return setBufferCount(bufferCount);
|
||||
}
|
||||
|
||||
int GonkNativeWindow::dispatchSetBuffersGeometry(va_list args)
|
||||
{
|
||||
int w = va_arg(args, int);
|
||||
int h = va_arg(args, int);
|
||||
int f = va_arg(args, int);
|
||||
int err = setBuffersDimensions(w, h);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
return setBuffersFormat(f);
|
||||
}
|
||||
|
||||
int GonkNativeWindow::dispatchSetBuffersDimensions(va_list args)
|
||||
{
|
||||
int w = va_arg(args, int);
|
||||
int h = va_arg(args, int);
|
||||
return setBuffersDimensions(w, h);
|
||||
}
|
||||
|
||||
int GonkNativeWindow::dispatchSetBuffersFormat(va_list args)
|
||||
{
|
||||
int f = va_arg(args, int);
|
||||
return setBuffersFormat(f);
|
||||
}
|
||||
|
||||
int GonkNativeWindow::dispatchSetBuffersTimestamp(va_list args)
|
||||
{
|
||||
int64_t timestamp = va_arg(args, int64_t);
|
||||
return setBuffersTimestamp(timestamp);
|
||||
}
|
||||
|
||||
int GonkNativeWindow::setUsage(uint32_t reqUsage)
|
||||
{
|
||||
CNW_LOGD("GonkNativeWindow::setUsage");
|
||||
Mutex::Autolock lock(mMutex);
|
||||
mUsage = reqUsage;
|
||||
return OK;
|
||||
}
|
||||
|
||||
int GonkNativeWindow::setBuffersDimensions(int w, int h)
|
||||
{
|
||||
CNW_LOGD("GonkNativeWindow::setBuffersDimensions");
|
||||
Mutex::Autolock lock(mMutex);
|
||||
|
||||
if (w<0 || h<0)
|
||||
return BAD_VALUE;
|
||||
|
||||
if ((w && !h) || (!w && h))
|
||||
return BAD_VALUE;
|
||||
|
||||
mDefaultWidth = w;
|
||||
mDefaultHeight = h;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int GonkNativeWindow::setBuffersFormat(int format)
|
||||
{
|
||||
CNW_LOGD("GonkNativeWindow::setBuffersFormat");
|
||||
Mutex::Autolock lock(mMutex);
|
||||
|
||||
if (format<0)
|
||||
return BAD_VALUE;
|
||||
|
||||
mPixelFormat = format;
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int GonkNativeWindow::setBuffersTimestamp(int64_t timestamp)
|
||||
{
|
||||
CNW_LOGD("GonkNativeWindow::setBuffersTimestamp");
|
||||
Mutex::Autolock lock(mMutex);
|
||||
mTimestamp = timestamp;
|
||||
return OK;
|
||||
}
|
192
dom/camera/GonkNativeWindow.h
Normal file
192
dom/camera/GonkNativeWindow.h
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
* Copyright (C) 2012 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_GONKNATIVEWINDOW_H
|
||||
#define DOM_CAMERA_GONKNATIVEWINDOW_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <ui/egl/android_natives.h>
|
||||
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
#include <ui/GraphicBuffer.h>
|
||||
#include <ui/Rect.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class GonkNativeWindow : public EGLNativeBase<ANativeWindow, GonkNativeWindow, RefBase>
|
||||
{
|
||||
public:
|
||||
enum { MIN_UNDEQUEUED_BUFFERS = 2 };
|
||||
enum { MIN_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS };
|
||||
enum { NUM_BUFFER_SLOTS = 32 };
|
||||
|
||||
GonkNativeWindow();
|
||||
~GonkNativeWindow(); // this class cannot be overloaded
|
||||
|
||||
// ANativeWindow hooks
|
||||
static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
|
||||
static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
|
||||
static int hook_lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
|
||||
static int hook_perform(ANativeWindow* window, int operation, ...);
|
||||
static int hook_query(const ANativeWindow* window, int what, int* value);
|
||||
static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
|
||||
static int hook_setSwapInterval(ANativeWindow* window, int interval);
|
||||
|
||||
protected:
|
||||
virtual int cancelBuffer(ANativeWindowBuffer* buffer);
|
||||
virtual int dequeueBuffer(ANativeWindowBuffer** buffer);
|
||||
virtual int lockBuffer(ANativeWindowBuffer* buffer);
|
||||
virtual int perform(int operation, va_list args);
|
||||
virtual int query(int what, int* value) const;
|
||||
virtual int queueBuffer(ANativeWindowBuffer* buffer);
|
||||
virtual int setSwapInterval(int interval);
|
||||
|
||||
virtual int setBufferCount(int bufferCount);
|
||||
virtual int setBuffersDimensions(int w, int h);
|
||||
virtual int setBuffersFormat(int format);
|
||||
virtual int setBuffersTimestamp(int64_t timestamp);
|
||||
virtual int setUsage(uint32_t reqUsage);
|
||||
|
||||
// freeBufferLocked frees the resources (both GraphicBuffer and EGLImage)
|
||||
// for the given slot.
|
||||
void freeBufferLocked(int index);
|
||||
|
||||
// freeAllBuffersLocked frees the resources (both GraphicBuffer and
|
||||
// EGLImage) for all slots.
|
||||
void freeAllBuffersLocked();
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
int dispatchSetBufferCount(va_list args);
|
||||
int dispatchSetBuffersGeometry(va_list args);
|
||||
int dispatchSetBuffersDimensions(va_list args);
|
||||
int dispatchSetBuffersFormat(va_list args);
|
||||
int dispatchSetBuffersTimestamp(va_list args);
|
||||
int dispatchSetUsage(va_list args);
|
||||
|
||||
int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
|
||||
|
||||
private:
|
||||
enum { INVALID_BUFFER_SLOT = -1 };
|
||||
|
||||
struct BufferSlot {
|
||||
|
||||
BufferSlot()
|
||||
: mGraphicBuffer(0),
|
||||
mBufferState(BufferSlot::FREE),
|
||||
mTimestamp(0),
|
||||
mFrameNumber(0){
|
||||
}
|
||||
|
||||
// mGraphicBuffer points to the buffer allocated for this slot or is NULL
|
||||
// if no buffer has been allocated.
|
||||
sp<GraphicBuffer> mGraphicBuffer;
|
||||
|
||||
// BufferState represents the different states in which a buffer slot
|
||||
// can be.
|
||||
enum BufferState {
|
||||
// FREE indicates that the buffer is not currently being used and
|
||||
// will not be used in the future until it gets dequeued and
|
||||
// subsequently queued by the client.
|
||||
FREE = 0,
|
||||
|
||||
// DEQUEUED indicates that the buffer has been dequeued by the
|
||||
// client, but has not yet been queued or canceled. The buffer is
|
||||
// considered 'owned' by the client, and the server should not use
|
||||
// it for anything.
|
||||
//
|
||||
// Note that when in synchronous-mode (mSynchronousMode == true),
|
||||
// the buffer that's currently attached to the texture may be
|
||||
// dequeued by the client. That means that the current buffer can
|
||||
// be in either the DEQUEUED or QUEUED state. In asynchronous mode,
|
||||
// however, the current buffer is always in the QUEUED state.
|
||||
DEQUEUED = 1,
|
||||
|
||||
// QUEUED indicates that the buffer has been queued by the client,
|
||||
// and has not since been made available for the client to dequeue.
|
||||
// Attaching the buffer to the texture does NOT transition the
|
||||
// buffer away from the QUEUED state. However, in Synchronous mode
|
||||
// the current buffer may be dequeued by the client under some
|
||||
// circumstances. See the note about the current buffer in the
|
||||
// documentation for DEQUEUED.
|
||||
QUEUED = 2,
|
||||
};
|
||||
|
||||
// mBufferState is the current state of this buffer slot.
|
||||
BufferState mBufferState;
|
||||
|
||||
// mTimestamp is the current timestamp for this buffer slot. This gets
|
||||
// to set by queueBuffer each time this slot is queued.
|
||||
int64_t mTimestamp;
|
||||
|
||||
// mFrameNumber is the number of the queued frame for this slot.
|
||||
uint64_t mFrameNumber;
|
||||
};
|
||||
|
||||
// mSlots is the array of buffer slots that must be mirrored on the client
|
||||
// side. This allows buffer ownership to be transferred between the client
|
||||
// and server without sending a GraphicBuffer over binder. The entire array
|
||||
// is initialized to NULL at construction time, and buffers are allocated
|
||||
// for a slot when requestBuffer is called with that slot's index.
|
||||
BufferSlot mSlots[NUM_BUFFER_SLOTS];
|
||||
|
||||
// mDequeueCondition condition used for dequeueBuffer in synchronous mode
|
||||
mutable Condition mDequeueCondition;
|
||||
|
||||
// mTimestamp is the timestamp that will be used for the next buffer queue
|
||||
// operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that
|
||||
// a timestamp is auto-generated when queueBuffer is called.
|
||||
int64_t mTimestamp;
|
||||
|
||||
// mDefaultWidth holds the default width of allocated buffers. It is used
|
||||
// in requestBuffers() if a width and height of zero is specified.
|
||||
uint32_t mDefaultWidth;
|
||||
|
||||
// mDefaultHeight holds the default height of allocated buffers. It is used
|
||||
// in requestBuffers() if a width and height of zero is specified.
|
||||
uint32_t mDefaultHeight;
|
||||
|
||||
// mPixelFormat holds the pixel format of allocated buffers. It is used
|
||||
// in requestBuffers() if a format of zero is specified.
|
||||
uint32_t mPixelFormat;
|
||||
|
||||
// usage flag
|
||||
uint32_t mUsage;
|
||||
|
||||
// mBufferCount is the number of buffer slots that the client and server
|
||||
// must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed
|
||||
// by calling setBufferCount or setBufferCountServer
|
||||
int mBufferCount;
|
||||
|
||||
// mMutex is the mutex used to prevent concurrent access to the member
|
||||
// variables. It must be locked whenever the member variables are accessed.
|
||||
mutable Mutex mMutex;
|
||||
|
||||
// mFrameCounter is the free running counter, incremented for every buffer queued
|
||||
uint64_t mFrameCounter;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // DOM_CAMERA_GONKNATIVEWINDOW_H
|
52
dom/camera/Makefile.in
Normal file
52
dom/camera/Makefile.in
Normal file
@ -0,0 +1,52 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = dom
|
||||
LIBRARY_NAME = domcamera_s
|
||||
XPIDL_MODULE = dom_camera
|
||||
LIBXUL_LIBRARY = 1
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
include $(topsrcdir)/dom/dom-config.mk
|
||||
|
||||
CPPSRCS = \
|
||||
DOMCameraManager.cpp \
|
||||
CameraControl.cpp \
|
||||
CameraPreview.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(MOZ_B2G_CAMERA),1)
|
||||
CPPSRCS += \
|
||||
GonkCameraManager.cpp \
|
||||
GonkCameraControl.cpp \
|
||||
GonkCameraHwMgr.cpp \
|
||||
GonkCameraPreview.cpp \
|
||||
GonkNativeWindow.cpp \
|
||||
GonkCameraCapabilities.cpp \
|
||||
$(NULL)
|
||||
else
|
||||
CPPSRCS += \
|
||||
FallbackCameraManager.cpp \
|
||||
FallbackCameraControl.cpp \
|
||||
FallbackCameraCapabilities.cpp \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIDOMNavigatorCamera.idl \
|
||||
nsIDOMCameraManager.idl \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
DOMCameraManager.h \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
341
dom/camera/nsIDOMCameraManager.idl
Normal file
341
dom/camera/nsIDOMCameraManager.idl
Normal file
@ -0,0 +1,341 @@
|
||||
#include "domstubs.idl"
|
||||
|
||||
#include "nsIDOMMediaStream.idl"
|
||||
#include "nsIDOMDOMRequest.idl"
|
||||
|
||||
|
||||
interface nsIDOMBlob;
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
/* Select a camera to use. */
|
||||
dictionary CameraSelector {
|
||||
DOMString camera = "back";
|
||||
};
|
||||
|
||||
[scriptable, uuid(64196840-0d03-4b65-a955-790f43a4b810)]
|
||||
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 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;
|
||||
};
|
||||
|
||||
/*
|
||||
These properties only affect the captured image;
|
||||
invalid property settings are ignored.
|
||||
*/
|
||||
dictionary CameraPictureOptions
|
||||
{
|
||||
/* an object with a combination of 'height' and 'width' properties
|
||||
chosen from nsICameraCapabilities.pictureSizes */
|
||||
jsval pictureSize;
|
||||
|
||||
/* one of the file formats chosen from
|
||||
nsICameraCapabilities.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;
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
jsval position;
|
||||
};
|
||||
|
||||
[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(ac43f123-529c-48d3-84dd-ad206b7aca9b)]
|
||||
interface nsICameraStartRecordingCallback : nsISupports
|
||||
{
|
||||
void handleEvent(in nsIDOMMediaStream stream);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(fb80db71-e315-42f0-9ea9-dd3dd312ed70)]
|
||||
interface nsICameraShutterCallback : nsISupports
|
||||
{
|
||||
void handleEvent();
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(a302c6c9-3776-4d1d-a395-f4105d47c3d3)]
|
||||
interface nsICameraErrorCallback : nsISupports
|
||||
{
|
||||
void handleEvent(in DOMString error);
|
||||
};
|
||||
|
||||
/*
|
||||
attributes here affect the preview, any pictures taken, and/or
|
||||
any video recorded by the camera.
|
||||
*/
|
||||
[scriptable, uuid(3066c884-d2c3-4477-847d-08ea1c2d188a)]
|
||||
interface nsICameraControl : nsISupports
|
||||
{
|
||||
readonly attribute nsICameraCapabilities capabilities;
|
||||
|
||||
/* one of the vales chosen from capabilities.effects;
|
||||
default is "none" */
|
||||
attribute DOMString effect;
|
||||
|
||||
/* one of the values chosen from capabilities.whiteBalanceModes;
|
||||
default is "auto" */
|
||||
attribute DOMString whiteBalanceMode;
|
||||
|
||||
/* one of the valus chosen from capabilities.sceneModes;
|
||||
default is "auto" */
|
||||
attribute DOMString sceneMode;
|
||||
|
||||
/* one of the values chosen from capabilities.flashModes;
|
||||
default is "auto" */
|
||||
attribute DOMString flashMode;
|
||||
|
||||
/* one of the values chosen from capabilities.focusModes;
|
||||
default is "auto", if supported, or "fixed" */
|
||||
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 */
|
||||
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
|
||||
}
|
||||
|
||||
'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.
|
||||
|
||||
this attribute can be set to null to allow the camera to determine
|
||||
where to perform light metering. */
|
||||
[implicit_jscontext]
|
||||
attribute jsval 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.
|
||||
|
||||
this attribute can be set to null to allow the camera to determine
|
||||
where to focus. */
|
||||
[implicit_jscontext]
|
||||
attribute jsval focusAreas;
|
||||
|
||||
/* focal length in millimetres */
|
||||
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.
|
||||
|
||||
'focusDistanceFar' may be infinity. */
|
||||
readonly attribute double focusDistanceNear;
|
||||
readonly attribute double focusDistanceOptimum;
|
||||
readonly attribute double focusDistanceFar;
|
||||
|
||||
/* '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. */
|
||||
[implicit_jscontext]
|
||||
void setExposureCompensation([optional] in jsval compensation);
|
||||
readonly attribute double exposureCompensation;
|
||||
|
||||
/* the function to call on the camera's shutter event, to trigger
|
||||
a shutter sound and/or a visual shutter indicator. */
|
||||
attribute nsICameraShutterCallback onShutter;
|
||||
|
||||
/* tell the camera to attempt to focus the image */
|
||||
void autoFocus(in nsICameraAutoFocusCallback onSuccess, [optional] in nsICameraErrorCallback 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.
|
||||
|
||||
invoking this function will stop the preview stream, which must be
|
||||
manually restarted (e.g. by calling .play() on it). */
|
||||
[implicit_jscontext]
|
||||
void takePicture(in jsval aOptions, in nsICameraTakePictureCallback onSuccess, [optional] in nsICameraErrorCallback onError);
|
||||
|
||||
/* start recording video; 'aOptions' define the frame size of to
|
||||
capture, chosen from capabilities.videoSizes, e.g.:
|
||||
{
|
||||
width: 640,
|
||||
height: 480
|
||||
}
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
void startRecording(in jsval aOptions, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError);
|
||||
|
||||
/* stop precording video. */
|
||||
void stopRecording();
|
||||
|
||||
/* 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,
|
||||
}
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
void getPreviewStream(in jsval aOptions, in nsICameraPreviewStreamCallback onSuccess, [optional] in nsICameraErrorCallback onError);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(a267afbc-d91c-413a-8de5-0b94aecffa3e)]
|
||||
interface nsICameraGetCameraCallback : nsISupports
|
||||
{
|
||||
void handleEvent(in nsICameraControl camera);
|
||||
};
|
||||
|
||||
[scriptable, uuid(671ee624-0336-441a-a24e-26b5319f14fe)]
|
||||
interface nsIDOMCameraManager : nsISupports
|
||||
{
|
||||
/* get a camera instance; options will be used to specify which
|
||||
camera to get from the list returned by getListOfCameras(), e.g.:
|
||||
{
|
||||
camera: front
|
||||
}
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
void getCamera([optional] in jsval aOptions, in nsICameraGetCameraCallback onSuccess, [optional] in nsICameraErrorCallback onError);
|
||||
|
||||
/* return a JSON array of camera identifiers, e.g.
|
||||
[ "front", "back" ]
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
jsval getListOfCameras();
|
||||
};
|
15
dom/camera/nsIDOMNavigatorCamera.idl
Normal file
15
dom/camera/nsIDOMNavigatorCamera.idl
Normal file
@ -0,0 +1,15 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=40: */
|
||||
/* 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 "nsISupports.idl"
|
||||
|
||||
interface nsIDOMCameraManager;
|
||||
|
||||
[scriptable, uuid(bbb2456a-a6c8-42c8-8f52-6de071097e4b)]
|
||||
interface nsIDOMNavigatorCamera : nsISupports
|
||||
{
|
||||
readonly attribute nsIDOMCameraManager mozCameras;
|
||||
};
|
@ -30,6 +30,7 @@ DOM_SRCDIRS = \
|
||||
layout/style \
|
||||
layout/xul/base/src \
|
||||
layout/xul/base/src/tree/src \
|
||||
dom/camera \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_B2G_RIL
|
||||
|
@ -523,7 +523,11 @@ var interfaceNamesInGlobalScope =
|
||||
"ContactTelephone",
|
||||
"ContactEmail",
|
||||
"SVGFitToViewBox",
|
||||
"SVGAElement"
|
||||
"SVGAElement",
|
||||
"NavigatorCamera",
|
||||
"CameraControl",
|
||||
"CameraCapabilities",
|
||||
"CameraManager"
|
||||
]
|
||||
|
||||
for (var i in Components.interfaces) {
|
||||
|
@ -18,7 +18,12 @@ dictionaries = [
|
||||
[ 'GeoPositionOptions', 'nsIDOMGeoGeolocation.idl' ],
|
||||
[ 'DOMFileMetadataParameters', 'nsIDOMLockedFile.idl' ],
|
||||
[ 'XMLHttpRequestParameters', 'nsIXMLHttpRequest.idl' ],
|
||||
[ 'DeviceStorageEnumerationParameters', 'nsIDOMDeviceStorage.idl' ]
|
||||
[ 'DeviceStorageEnumerationParameters', 'nsIDOMDeviceStorage.idl' ],
|
||||
[ 'CameraSize', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'CameraRegion', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'CameraPosition', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'CameraSelector', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'CameraPictureOptions', 'nsIDOMCameraManager.idl' ]
|
||||
]
|
||||
|
||||
# include file names
|
||||
|
@ -121,6 +121,8 @@ ifdef MOZ_B2G_BT #{
|
||||
SHARED_LIBRARY_LIBS += $(DEPTH)/dom/bluetooth/$(LIB_PREFIX)dombluetooth_s.$(LIB_SUFFIX)
|
||||
endif #}
|
||||
|
||||
SHARED_LIBRARY_LIBS += $(DEPTH)/dom/camera/$(LIB_PREFIX)domcamera_s.$(LIB_SUFFIX)
|
||||
|
||||
ifdef MOZ_B2G_RIL #{
|
||||
SHARED_LIBRARY_LIBS += \
|
||||
$(DEPTH)/dom/system/gonk/$(LIB_PREFIX)domsystemgonk_s.$(LIB_SUFFIX) \
|
||||
@ -273,4 +275,6 @@ ifdef MOZ_B2G_BT #{
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/dom/bluetooth
|
||||
endif #}
|
||||
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/dom/camera
|
||||
|
||||
DEFINES += -D_IMPL_NS_LAYOUT
|
||||
|
@ -164,6 +164,7 @@
|
||||
#ifdef MOZ_B2G_BT
|
||||
@BINPATH@/components/dom_bluetooth.xpt
|
||||
#endif
|
||||
@BINPATH@/components/dom_camera.xpt
|
||||
@BINPATH@/components/dom_canvas.xpt
|
||||
@BINPATH@/components/dom_core.xpt
|
||||
@BINPATH@/components/dom_css.xpt
|
||||
|
Loading…
Reference in New Issue
Block a user