Bug 740997 - ICS camera support, r=jst,gal,roc

This commit is contained in:
Mike Habicher 2012-07-30 17:59:05 -04:00
parent fc2f5cd147
commit d753b0fbff
38 changed files with 4808 additions and 7 deletions

View File

@ -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

View File

@ -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

View File

@ -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@

View File

@ -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 ========================================================

View File

@ -70,6 +70,7 @@ DIRS += \
ipc \
identity \
workers \
camera \
$(NULL)
ifdef MOZ_B2G_RIL

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -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)

View 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
View 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

View 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 = &regionArray[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
View 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

View 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);
}

View 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

View 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;
}

View 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

View 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;
}

View 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;
}

View 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;
}

View 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);
}

View 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

View 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

View 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;
}

View 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

View 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));
}

View 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();
}

View 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

View 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;
}

View 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
View 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

View 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();
};

View 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;
};

View File

@ -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

View File

@ -523,7 +523,11 @@ var interfaceNamesInGlobalScope =
"ContactTelephone",
"ContactEmail",
"SVGFitToViewBox",
"SVGAElement"
"SVGAElement",
"NavigatorCamera",
"CameraControl",
"CameraCapabilities",
"CameraManager"
]
for (var i in Components.interfaces) {

View File

@ -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

View File

@ -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

View File

@ -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