summaryrefslogtreecommitdiff
path: root/netwerk/protocol/device
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /netwerk/protocol/device
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloaduxp-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
Add m-esr52 at 52.6.0
Diffstat (limited to 'netwerk/protocol/device')
-rw-r--r--netwerk/protocol/device/AndroidCaptureProvider.cpp301
-rw-r--r--netwerk/protocol/device/AndroidCaptureProvider.h68
-rw-r--r--netwerk/protocol/device/CameraStreamImpl.cpp114
-rw-r--r--netwerk/protocol/device/CameraStreamImpl.h71
-rw-r--r--netwerk/protocol/device/RawStructs.h60
-rw-r--r--netwerk/protocol/device/moz.build27
-rw-r--r--netwerk/protocol/device/nsDeviceCaptureProvider.h31
-rw-r--r--netwerk/protocol/device/nsDeviceChannel.cpp154
-rw-r--r--netwerk/protocol/device/nsDeviceChannel.h26
-rw-r--r--netwerk/protocol/device/nsDeviceProtocolHandler.cpp93
-rw-r--r--netwerk/protocol/device/nsDeviceProtocolHandler.h34
11 files changed, 979 insertions, 0 deletions
diff --git a/netwerk/protocol/device/AndroidCaptureProvider.cpp b/netwerk/protocol/device/AndroidCaptureProvider.cpp
new file mode 100644
index 0000000000..e697660850
--- /dev/null
+++ b/netwerk/protocol/device/AndroidCaptureProvider.cpp
@@ -0,0 +1,301 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "base/basictypes.h"
+#include "AndroidCaptureProvider.h"
+#include "nsXULAppAPI.h"
+#include "nsStreamUtils.h"
+#include "nsThreadUtils.h"
+#include "nsMemory.h"
+#include "RawStructs.h"
+
+// The maximum number of frames we keep in our queue. Don't live in the past.
+#define MAX_FRAMES_QUEUED 10
+
+using namespace mozilla::net;
+
+NS_IMPL_ISUPPORTS(AndroidCameraInputStream, nsIInputStream, nsIAsyncInputStream)
+
+AndroidCameraInputStream::AndroidCameraInputStream() :
+ mWidth(0), mHeight(0), mCamera(0), mHeaderSent(false), mClosed(true), mFrameSize(0),
+ mMonitor("AndroidCamera.Monitor")
+{
+ mAvailable = sizeof(RawVideoHeader);
+ mFrameQueue = new nsDeque();
+}
+
+AndroidCameraInputStream::~AndroidCameraInputStream() {
+ // clear the frame queue
+ while (mFrameQueue->GetSize() > 0) {
+ free(mFrameQueue->PopFront());
+ }
+ delete mFrameQueue;
+}
+
+NS_IMETHODIMP
+AndroidCameraInputStream::Init(nsACString& aContentType, nsCaptureParams* aParams)
+{
+ if (!XRE_IsParentProcess())
+ return NS_ERROR_NOT_IMPLEMENTED;
+
+ mContentType = aContentType;
+ mWidth = aParams->width;
+ mHeight = aParams->height;
+ mCamera = aParams->camera;
+
+ CameraStreamImpl *impl = CameraStreamImpl::GetInstance(0);
+ if (!impl)
+ return NS_ERROR_OUT_OF_MEMORY;
+ if (impl->Init(mContentType, mCamera, mWidth, mHeight, this)) {
+ mWidth = impl->GetWidth();
+ mHeight = impl->GetHeight();
+ mClosed = false;
+ }
+ return NS_OK;
+}
+
+void AndroidCameraInputStream::ReceiveFrame(char* frame, uint32_t length) {
+ {
+ mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor);
+ if (mFrameQueue->GetSize() > MAX_FRAMES_QUEUED) {
+ free(mFrameQueue->PopFront());
+ mAvailable -= mFrameSize;
+ }
+ }
+
+ mFrameSize = sizeof(RawPacketHeader) + length;
+
+ char* fullFrame = (char*)moz_xmalloc(mFrameSize);
+
+ if (!fullFrame)
+ return;
+
+ RawPacketHeader* header = (RawPacketHeader*) fullFrame;
+ header->packetID = 0xFF;
+ header->codecID = 0x595556; // "YUV"
+
+ // we copy the Y plane, and de-interlace the CrCb
+
+ uint32_t yFrameSize = mWidth * mHeight;
+ uint32_t uvFrameSize = yFrameSize / 4;
+
+ memcpy(fullFrame + sizeof(RawPacketHeader), frame, yFrameSize);
+
+ char* uFrame = fullFrame + yFrameSize;
+ char* vFrame = fullFrame + yFrameSize + uvFrameSize;
+ char* yFrame = frame + yFrameSize;
+ for (uint32_t i = 0; i < uvFrameSize; i++) {
+ uFrame[i] = yFrame[2 * i + 1];
+ vFrame[i] = yFrame[2 * i];
+ }
+
+ {
+ mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor);
+ mAvailable += mFrameSize;
+ mFrameQueue->Push((void*)fullFrame);
+ }
+
+ NotifyListeners();
+}
+
+NS_IMETHODIMP
+AndroidCameraInputStream::Available(uint64_t *aAvailable)
+{
+ mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor);
+
+ *aAvailable = mAvailable;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP AndroidCameraInputStream::IsNonBlocking(bool *aNonBlock) {
+ *aNonBlock = true;
+ return NS_OK;
+}
+
+NS_IMETHODIMP AndroidCameraInputStream::Read(char *aBuffer, uint32_t aCount, uint32_t *aRead) {
+ return ReadSegments(NS_CopySegmentToBuffer, aBuffer, aCount, aRead);
+}
+
+NS_IMETHODIMP AndroidCameraInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, uint32_t aCount, uint32_t *aRead) {
+ *aRead = 0;
+
+ nsresult rv;
+
+ if (mAvailable == 0)
+ return NS_BASE_STREAM_WOULD_BLOCK;
+
+ if (aCount > mAvailable)
+ aCount = mAvailable;
+
+ if (!mHeaderSent) {
+ CameraStreamImpl *impl = CameraStreamImpl::GetInstance(0);
+ RawVideoHeader header;
+ header.headerPacketID = 0;
+ header.codecID = 0x595556; // "YUV"
+ header.majorVersion = 0;
+ header.minorVersion = 1;
+ header.options = 1 | 1 << 1; // color, 4:2:2
+
+ header.alphaChannelBpp = 0;
+ header.lumaChannelBpp = 8;
+ header.chromaChannelBpp = 4;
+ header.colorspace = 1;
+
+ header.frameWidth = mWidth;
+ header.frameHeight = mHeight;
+ header.aspectNumerator = 1;
+ header.aspectDenominator = 1;
+
+ header.framerateNumerator = impl->GetFps();
+ header.framerateDenominator = 1;
+
+ rv = aWriter(this, aClosure, (const char*)&header, 0, sizeof(RawVideoHeader), aRead);
+
+ if (NS_FAILED(rv))
+ return NS_OK;
+
+ mHeaderSent = true;
+ aCount -= sizeof(RawVideoHeader);
+ mAvailable -= sizeof(RawVideoHeader);
+ }
+
+ {
+ mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor);
+ while ((mAvailable > 0) && (aCount >= mFrameSize)) {
+ uint32_t readThisTime = 0;
+
+ char* frame = (char*)mFrameQueue->PopFront();
+ rv = aWriter(this, aClosure, (const char*)frame, *aRead, mFrameSize, &readThisTime);
+
+ if (readThisTime != mFrameSize) {
+ mFrameQueue->PushFront((void*)frame);
+ return NS_OK;
+ }
+
+ // RawReader does a copy when calling VideoData::Create()
+ free(frame);
+
+ if (NS_FAILED(rv))
+ return NS_OK;
+
+ aCount -= readThisTime;
+ mAvailable -= readThisTime;
+ *aRead += readThisTime;
+ }
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP AndroidCameraInputStream::Close() {
+ return CloseWithStatus(NS_OK);
+}
+
+
+/**
+ * must be called on the main (java) thread
+ */
+void AndroidCameraInputStream::doClose() {
+ NS_ASSERTION(!mClosed, "Camera is already closed");
+
+ CameraStreamImpl *impl = CameraStreamImpl::GetInstance(0);
+ impl->Close();
+ mClosed = true;
+}
+
+
+void AndroidCameraInputStream::NotifyListeners() {
+ mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor);
+
+ if (mCallback && (mAvailable > sizeof(RawVideoHeader))) {
+ nsCOMPtr<nsIInputStreamCallback> callback;
+ if (mCallbackTarget) {
+ callback = NS_NewInputStreamReadyEvent(mCallback, mCallbackTarget);
+ } else {
+ callback = mCallback;
+ }
+
+ NS_ASSERTION(callback, "Shouldn't fail to make the callback!");
+
+ // Null the callback first because OnInputStreamReady may reenter AsyncWait
+ mCallback = nullptr;
+ mCallbackTarget = nullptr;
+
+ callback->OnInputStreamReady(this);
+ }
+}
+
+NS_IMETHODIMP AndroidCameraInputStream::AsyncWait(nsIInputStreamCallback *aCallback, uint32_t aFlags, uint32_t aRequestedCount, nsIEventTarget *aTarget)
+{
+ if (aFlags != 0)
+ return NS_ERROR_NOT_IMPLEMENTED;
+
+ if (mCallback || mCallbackTarget)
+ return NS_ERROR_UNEXPECTED;
+
+ mCallbackTarget = aTarget;
+ mCallback = aCallback;
+
+ // What we are being asked for may be present already
+ NotifyListeners();
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP AndroidCameraInputStream::CloseWithStatus(nsresult status)
+{
+ AndroidCameraInputStream::doClose();
+ return NS_OK;
+}
+
+/**
+ * AndroidCaptureProvider implementation
+ */
+
+NS_IMPL_ISUPPORTS0(AndroidCaptureProvider)
+
+AndroidCaptureProvider* AndroidCaptureProvider::sInstance = nullptr;
+
+AndroidCaptureProvider::AndroidCaptureProvider() {
+}
+
+AndroidCaptureProvider::~AndroidCaptureProvider() {
+ AndroidCaptureProvider::sInstance = nullptr;
+}
+
+nsresult AndroidCaptureProvider::Init(nsACString& aContentType,
+ nsCaptureParams* aParams,
+ nsIInputStream** aStream) {
+
+ NS_ENSURE_ARG_POINTER(aParams);
+
+ NS_ASSERTION(aParams->frameLimit == 0 || aParams->timeLimit == 0,
+ "Cannot set both a frame limit and a time limit!");
+
+ RefPtr<AndroidCameraInputStream> stream;
+
+ if (aContentType.EqualsLiteral("video/x-raw-yuv")) {
+ stream = new AndroidCameraInputStream();
+ if (stream) {
+ nsresult rv = stream->Init(aContentType, aParams);
+ if (NS_FAILED(rv))
+ return rv;
+ }
+ else
+ return NS_ERROR_OUT_OF_MEMORY;
+ } else {
+ NS_NOTREACHED("Should not have asked Android for this type!");
+ }
+ stream.forget(aStream);
+ return NS_OK;
+}
+
+already_AddRefed<AndroidCaptureProvider> GetAndroidCaptureProvider() {
+ if (!AndroidCaptureProvider::sInstance) {
+ AndroidCaptureProvider::sInstance = new AndroidCaptureProvider();
+ }
+ RefPtr<AndroidCaptureProvider> ret = AndroidCaptureProvider::sInstance;
+ return ret.forget();
+}
diff --git a/netwerk/protocol/device/AndroidCaptureProvider.h b/netwerk/protocol/device/AndroidCaptureProvider.h
new file mode 100644
index 0000000000..dd99ea5411
--- /dev/null
+++ b/netwerk/protocol/device/AndroidCaptureProvider.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 AndroidDeviceCaptureProvide_h_
+#define AndroidDeviceCaptureProvide_h_
+
+#include "nsDeviceCaptureProvider.h"
+#include "nsIAsyncInputStream.h"
+#include "nsCOMPtr.h"
+#include "nsAutoPtr.h"
+#include "nsString.h"
+#include "mozilla/net/CameraStreamImpl.h"
+#include "nsIEventTarget.h"
+#include "nsDeque.h"
+#include "mozilla/ReentrantMonitor.h"
+
+class AndroidCaptureProvider final : public nsDeviceCaptureProvider {
+ private:
+ ~AndroidCaptureProvider();
+
+ public:
+ AndroidCaptureProvider();
+
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ MOZ_MUST_USE nsresult Init(nsACString& aContentType, nsCaptureParams* aParams, nsIInputStream** aStream) override;
+ static AndroidCaptureProvider* sInstance;
+};
+
+class AndroidCameraInputStream final : public nsIAsyncInputStream, mozilla::net::CameraStreamImpl::FrameCallback {
+ private:
+ ~AndroidCameraInputStream();
+
+ public:
+ AndroidCameraInputStream();
+
+ NS_IMETHODIMP Init(nsACString& aContentType, nsCaptureParams* aParams);
+
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIINPUTSTREAM
+ NS_DECL_NSIASYNCINPUTSTREAM
+
+ void ReceiveFrame(char* frame, uint32_t length) override;
+
+ protected:
+ void NotifyListeners();
+ void doClose();
+
+ uint32_t mAvailable;
+ nsCString mContentType;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mCamera;
+ bool mHeaderSent;
+ bool mClosed;
+ nsDeque *mFrameQueue;
+ uint32_t mFrameSize;
+ mozilla::ReentrantMonitor mMonitor;
+
+ nsCOMPtr<nsIInputStreamCallback> mCallback;
+ nsCOMPtr<nsIEventTarget> mCallbackTarget;
+};
+
+already_AddRefed<AndroidCaptureProvider> GetAndroidCaptureProvider();
+
+#endif
diff --git a/netwerk/protocol/device/CameraStreamImpl.cpp b/netwerk/protocol/device/CameraStreamImpl.cpp
new file mode 100644
index 0000000000..f4a2cf4a4f
--- /dev/null
+++ b/netwerk/protocol/device/CameraStreamImpl.cpp
@@ -0,0 +1,114 @@
+/* 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 "CameraStreamImpl.h"
+#include "GeneratedJNINatives.h"
+#include "nsCRTGlue.h"
+#include "nsThreadUtils.h"
+#include "nsXULAppAPI.h"
+#include "mozilla/Monitor.h"
+
+using namespace mozilla;
+
+namespace mozilla {
+namespace net {
+
+static CameraStreamImpl* mCamera0 = nullptr;
+static CameraStreamImpl* mCamera1 = nullptr;
+
+class CameraStreamImpl::Callback
+ : public java::GeckoAppShell::CameraCallback::Natives<Callback>
+{
+public:
+ static void OnFrameData(int32_t aCamera, jni::ByteArray::Param aData)
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ CameraStreamImpl* impl = GetInstance(uint32_t(aCamera));
+ if (impl) {
+ impl->TransmitFrame(aData);
+ }
+ }
+};
+
+/**
+ * CameraStreamImpl
+ */
+
+void CameraStreamImpl::TransmitFrame(jni::ByteArray::Param aData) {
+ if (!mCallback) {
+ return;
+ }
+
+ JNIEnv* const env = jni::GetGeckoThreadEnv();
+ const size_t length = size_t(env->GetArrayLength(aData.Get()));
+
+ if (!length) {
+ return;
+ }
+
+ jbyte* const data = env->GetByteArrayElements(aData.Get(), nullptr);
+ mCallback->ReceiveFrame(reinterpret_cast<char*>(data), length);
+ env->ReleaseByteArrayElements(aData.Get(), data, JNI_ABORT);
+}
+
+CameraStreamImpl* CameraStreamImpl::GetInstance(uint32_t aCamera) {
+ CameraStreamImpl* res = nullptr;
+ switch(aCamera) {
+ case 0:
+ if (mCamera0)
+ res = mCamera0;
+ else
+ res = mCamera0 = new CameraStreamImpl(aCamera);
+ break;
+ case 1:
+ if (mCamera1)
+ res = mCamera1;
+ else
+ res = mCamera1 = new CameraStreamImpl(aCamera);
+ break;
+ }
+ return res;
+}
+
+
+CameraStreamImpl::CameraStreamImpl(uint32_t aCamera) :
+ mInit(false), mCamera(aCamera)
+{
+ NS_WARNING("CameraStreamImpl::CameraStreamImpl()");
+ mWidth = 0;
+ mHeight = 0;
+ mFps = 0;
+}
+
+CameraStreamImpl::~CameraStreamImpl()
+{
+ NS_WARNING("CameraStreamImpl::~CameraStreamImpl()");
+}
+
+bool CameraStreamImpl::Init(const nsCString& contentType, const uint32_t& camera, const uint32_t& width, const uint32_t& height, FrameCallback* aCallback)
+{
+ mCallback = aCallback;
+ mWidth = width;
+ mHeight = height;
+
+ Callback::Init();
+ jni::IntArray::LocalRef retArray = java::GeckoAppShell::InitCamera(
+ contentType, int32_t(camera), int32_t(width), int32_t(height));
+ nsTArray<int32_t> ret = retArray->GetElements();
+
+ mWidth = uint32_t(ret[1]);
+ mHeight = uint32_t(ret[2]);
+ mFps = uint32_t(ret[3]);
+
+ return !!ret[0];
+}
+
+void CameraStreamImpl::Close() {
+ java::GeckoAppShell::CloseCamera();
+ mCallback = nullptr;
+}
+
+} // namespace net
+} // namespace mozilla
diff --git a/netwerk/protocol/device/CameraStreamImpl.h b/netwerk/protocol/device/CameraStreamImpl.h
new file mode 100644
index 0000000000..93037caf66
--- /dev/null
+++ b/netwerk/protocol/device/CameraStreamImpl.h
@@ -0,0 +1,71 @@
+/* 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 __CAMERASTREAMIMPL_H__
+#define __CAMERASTREAMIMPL_H__
+
+#include "mozilla/jni/Refs.h"
+
+#include "nsString.h"
+
+/**
+ * This singleton class handles communication with the Android camera
+ * through JNI. It is used by the IPDL parent or directly from the chrome process
+ */
+
+namespace mozilla {
+namespace net {
+
+class CameraStreamImpl {
+public:
+ class FrameCallback {
+ public:
+ virtual void ReceiveFrame(char* frame, uint32_t length) = 0;
+ };
+
+ /**
+ * instance bound to a given camera
+ */
+ static CameraStreamImpl* GetInstance(uint32_t aCamera);
+
+ bool initNeeded() {
+ return !mInit;
+ }
+
+ FrameCallback* GetFrameCallback() {
+ return mCallback;
+ }
+
+ MOZ_MUST_USE bool Init(const nsCString& contentType, const uint32_t& camera, const uint32_t& width, const uint32_t& height, FrameCallback* callback);
+ void Close();
+
+ uint32_t GetWidth() { return mWidth; }
+ uint32_t GetHeight() { return mHeight; }
+ uint32_t GetFps() { return mFps; }
+
+ void takePicture(const nsAString& aFileName);
+
+private:
+ class Callback;
+
+ CameraStreamImpl(uint32_t aCamera);
+ CameraStreamImpl(const CameraStreamImpl&);
+ CameraStreamImpl& operator=(const CameraStreamImpl&);
+
+ ~CameraStreamImpl();
+
+ void TransmitFrame(jni::ByteArray::Param aData);
+
+ bool mInit;
+ uint32_t mCamera;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mFps;
+ FrameCallback* mCallback;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif
diff --git a/netwerk/protocol/device/RawStructs.h b/netwerk/protocol/device/RawStructs.h
new file mode 100644
index 0000000000..61777877ea
--- /dev/null
+++ b/netwerk/protocol/device/RawStructs.h
@@ -0,0 +1,60 @@
+/* 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/. */
+
+#if !defined(RawStructs_h_)
+#define RawStructs_h_
+
+static const uint32_t RAW_ID = 0x595556;
+
+struct nsRawVideo_PRUint24 {
+ operator uint32_t() const { return value[2] << 16 | value[1] << 8 | value[0]; }
+ nsRawVideo_PRUint24& operator= (const uint32_t& rhs)
+ { value[2] = (rhs & 0x00FF0000) >> 16;
+ value[1] = (rhs & 0x0000FF00) >> 8;
+ value[0] = (rhs & 0x000000FF);
+ return *this; }
+private:
+ uint8_t value[3];
+};
+
+struct RawPacketHeader {
+ typedef nsRawVideo_PRUint24 PRUint24;
+ uint8_t packetID;
+ PRUint24 codecID;
+};
+
+// This is Arc's draft from wiki.xiph.org/OggYUV
+struct RawVideoHeader {
+ typedef nsRawVideo_PRUint24 PRUint24;
+ uint8_t headerPacketID; // Header Packet ID (always 0)
+ PRUint24 codecID; // Codec identifier (always "YUV")
+ uint8_t majorVersion; // Version Major (breaks backwards compat)
+ uint8_t minorVersion; // Version Minor (preserves backwards compat)
+ uint16_t options; // Bit 1: Color (false = B/W)
+ // Bits 2-4: Chroma Pixel Shape
+ // Bit 5: 50% horizontal offset for Cr samples
+ // Bit 6: 50% vertical ...
+ // Bits 7-8: Chroma Blending
+ // Bit 9: Packed (false = Planar)
+ // Bit 10: Cr Staggered Horizontally
+ // Bit 11: Cr Staggered Vertically
+ // Bit 12: Unused (format is always little endian)
+ // Bit 13: Interlaced (false = Progressive)
+ // Bits 14-16: Interlace options (undefined)
+
+ uint8_t alphaChannelBpp;
+ uint8_t lumaChannelBpp;
+ uint8_t chromaChannelBpp;
+ uint8_t colorspace;
+
+ PRUint24 frameWidth;
+ PRUint24 frameHeight;
+ PRUint24 aspectNumerator;
+ PRUint24 aspectDenominator;
+
+ uint32_t framerateNumerator;
+ uint32_t framerateDenominator;
+};
+
+#endif // RawStructs_h_
diff --git a/netwerk/protocol/device/moz.build b/netwerk/protocol/device/moz.build
new file mode 100644
index 0000000000..a186722204
--- /dev/null
+++ b/netwerk/protocol/device/moz.build
@@ -0,0 +1,27 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
+ EXPORTS.mozilla.net += [
+ 'CameraStreamImpl.h',
+ ]
+ UNIFIED_SOURCES += [
+ 'AndroidCaptureProvider.cpp',
+ 'CameraStreamImpl.cpp',
+ ]
+
+UNIFIED_SOURCES += [
+ 'nsDeviceChannel.cpp',
+ 'nsDeviceProtocolHandler.cpp',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
+
+LOCAL_INCLUDES += [
+ '/netwerk/base/',
+]
diff --git a/netwerk/protocol/device/nsDeviceCaptureProvider.h b/netwerk/protocol/device/nsDeviceCaptureProvider.h
new file mode 100644
index 0000000000..024f6689d6
--- /dev/null
+++ b/netwerk/protocol/device/nsDeviceCaptureProvider.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 nsDeviceCaptureProvider_h_
+#define nsDeviceCaptureProvider_h_
+
+#include "nsIInputStream.h"
+
+struct nsCaptureParams {
+ bool captureAudio;
+ bool captureVideo;
+ uint32_t frameRate;
+ uint32_t frameLimit;
+ uint32_t timeLimit;
+ uint32_t width;
+ uint32_t height;
+ uint32_t bpp;
+ uint32_t camera;
+};
+
+class nsDeviceCaptureProvider : public nsISupports
+{
+public:
+ virtual MOZ_MUST_USE nsresult Init(nsACString& aContentType,
+ nsCaptureParams* aParams,
+ nsIInputStream** aStream) = 0;
+};
+
+#endif
diff --git a/netwerk/protocol/device/nsDeviceChannel.cpp b/netwerk/protocol/device/nsDeviceChannel.cpp
new file mode 100644
index 0000000000..6c5788a568
--- /dev/null
+++ b/netwerk/protocol/device/nsDeviceChannel.cpp
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "plstr.h"
+#include "nsDeviceChannel.h"
+#include "nsDeviceCaptureProvider.h"
+
+#ifdef MOZ_WIDGET_ANDROID
+#include "mozilla/Preferences.h"
+#include "AndroidCaptureProvider.h"
+#endif
+
+using namespace mozilla;
+
+// Copied from image/decoders/icon/nsIconURI.cpp
+// takes a string like ?size=32&contentType=text/html and returns a new string
+// containing just the attribute values. i.e you could pass in this string with
+// an attribute name of "size=", this will return 32
+// Assumption: attribute pairs are separated by &
+void extractAttributeValue(const char* searchString, const char* attributeName, nsCString& result)
+{
+ result.Truncate();
+
+ if (!searchString || !attributeName)
+ return;
+
+ uint32_t attributeNameSize = strlen(attributeName);
+ const char *startOfAttribute = PL_strcasestr(searchString, attributeName);
+ if (!startOfAttribute ||
+ !( *(startOfAttribute-1) == '?' || *(startOfAttribute-1) == '&') )
+ return;
+
+ startOfAttribute += attributeNameSize; // Skip the attributeName
+ if (!*startOfAttribute)
+ return;
+
+ const char *endOfAttribute = strchr(startOfAttribute, '&');
+ if (endOfAttribute) {
+ result.Assign(Substring(startOfAttribute, endOfAttribute));
+ } else {
+ result.Assign(startOfAttribute);
+ }
+}
+
+NS_IMPL_ISUPPORTS_INHERITED(nsDeviceChannel,
+ nsBaseChannel,
+ nsIChannel)
+
+// nsDeviceChannel methods
+nsDeviceChannel::nsDeviceChannel()
+{
+ SetContentType(NS_LITERAL_CSTRING("image/png"));
+}
+
+nsDeviceChannel::~nsDeviceChannel()
+{
+}
+
+nsresult
+nsDeviceChannel::Init(nsIURI* aUri)
+{
+ nsBaseChannel::Init();
+ nsBaseChannel::SetURI(aUri);
+ return NS_OK;
+}
+
+nsresult
+nsDeviceChannel::OpenContentStream(bool aAsync,
+ nsIInputStream** aStream,
+ nsIChannel** aChannel)
+{
+ if (!aAsync)
+ return NS_ERROR_NOT_IMPLEMENTED;
+
+ nsCOMPtr<nsIURI> uri = nsBaseChannel::URI();
+ *aStream = nullptr;
+ *aChannel = nullptr;
+ NS_NAMED_LITERAL_CSTRING(width, "width=");
+ NS_NAMED_LITERAL_CSTRING(height, "height=");
+
+ nsAutoCString spec;
+ nsresult rv = uri->GetSpec(spec);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoCString type;
+
+ RefPtr<nsDeviceCaptureProvider> capture;
+ nsCaptureParams captureParams;
+ captureParams.camera = 0;
+ if (kNotFound != spec.Find(NS_LITERAL_CSTRING("type=image/png"),
+ true,
+ 0,
+ -1)) {
+ type.AssignLiteral("image/png");
+ SetContentType(type);
+ captureParams.captureAudio = false;
+ captureParams.captureVideo = true;
+ captureParams.timeLimit = 0;
+ captureParams.frameLimit = 1;
+ nsAutoCString buffer;
+ extractAttributeValue(spec.get(), "width=", buffer);
+ nsresult err;
+ captureParams.width = buffer.ToInteger(&err);
+ if (!captureParams.width)
+ captureParams.width = 640;
+ extractAttributeValue(spec.get(), "height=", buffer);
+ captureParams.height = buffer.ToInteger(&err);
+ if (!captureParams.height)
+ captureParams.height = 480;
+ extractAttributeValue(spec.get(), "camera=", buffer);
+ captureParams.camera = buffer.ToInteger(&err);
+ captureParams.bpp = 32;
+#ifdef MOZ_WIDGET_ANDROID
+ capture = GetAndroidCaptureProvider();
+#endif
+ } else if (kNotFound != spec.Find(NS_LITERAL_CSTRING("type=video/x-raw-yuv"),
+ true,
+ 0,
+ -1)) {
+ type.AssignLiteral("video/x-raw-yuv");
+ SetContentType(type);
+ captureParams.captureAudio = false;
+ captureParams.captureVideo = true;
+ nsAutoCString buffer;
+ extractAttributeValue(spec.get(), "width=", buffer);
+ nsresult err;
+ captureParams.width = buffer.ToInteger(&err);
+ if (!captureParams.width)
+ captureParams.width = 640;
+ extractAttributeValue(spec.get(), "height=", buffer);
+ captureParams.height = buffer.ToInteger(&err);
+ if (!captureParams.height)
+ captureParams.height = 480;
+ extractAttributeValue(spec.get(), "camera=", buffer);
+ captureParams.camera = buffer.ToInteger(&err);
+ captureParams.bpp = 32;
+ captureParams.timeLimit = 0;
+ captureParams.frameLimit = 60000;
+#ifdef MOZ_WIDGET_ANDROID
+ // only enable if "device.camera.enabled" is true.
+ if (Preferences::GetBool("device.camera.enabled", false) == true)
+ capture = GetAndroidCaptureProvider();
+#endif
+ } else {
+ return NS_ERROR_NOT_IMPLEMENTED;
+ }
+
+ if (!capture)
+ return NS_ERROR_FAILURE;
+
+ return capture->Init(type, &captureParams, aStream);
+}
diff --git a/netwerk/protocol/device/nsDeviceChannel.h b/netwerk/protocol/device/nsDeviceChannel.h
new file mode 100644
index 0000000000..8c3e447931
--- /dev/null
+++ b/netwerk/protocol/device/nsDeviceChannel.h
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 nsDeviceChannel_h_
+#define nsDeviceChannel_h_
+
+#include "nsBaseChannel.h"
+
+class nsDeviceChannel : public nsBaseChannel
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+
+ nsDeviceChannel();
+
+ MOZ_MUST_USE nsresult Init(nsIURI* uri);
+ MOZ_MUST_USE nsresult OpenContentStream(bool aAsync,
+ nsIInputStream **aStream,
+ nsIChannel **aChannel) override;
+
+protected:
+ ~nsDeviceChannel();
+};
+#endif
diff --git a/netwerk/protocol/device/nsDeviceProtocolHandler.cpp b/netwerk/protocol/device/nsDeviceProtocolHandler.cpp
new file mode 100644
index 0000000000..26c5f33dff
--- /dev/null
+++ b/netwerk/protocol/device/nsDeviceProtocolHandler.cpp
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "nsDeviceProtocolHandler.h"
+#include "nsDeviceChannel.h"
+#include "nsAutoPtr.h"
+#include "nsSimpleURI.h"
+
+namespace mozilla {
+namespace net {
+
+//-----------------------------------------------------------------------------
+NS_IMPL_ISUPPORTS(nsDeviceProtocolHandler,
+ nsIProtocolHandler)
+
+nsresult
+nsDeviceProtocolHandler::Init(){
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDeviceProtocolHandler::GetScheme(nsACString &aResult)
+{
+ aResult.AssignLiteral("moz-device");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDeviceProtocolHandler::GetDefaultPort(int32_t *aResult)
+{
+ *aResult = -1; // no port for moz_device: URLs
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDeviceProtocolHandler::GetProtocolFlags(uint32_t *aResult)
+{
+ *aResult = URI_NORELATIVE | URI_NOAUTH | URI_DANGEROUS_TO_LOAD;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDeviceProtocolHandler::NewURI(const nsACString &spec,
+ const char *originCharset,
+ nsIURI *baseURI,
+ nsIURI **result)
+{
+ RefPtr<nsSimpleURI> uri = new nsSimpleURI();
+
+ nsresult rv = uri->SetSpec(spec);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uri.forget(result);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDeviceProtocolHandler::NewChannel2(nsIURI* aURI,
+ nsILoadInfo* aLoadInfo,
+ nsIChannel** aResult)
+{
+ RefPtr<nsDeviceChannel> channel = new nsDeviceChannel();
+ nsresult rv = channel->Init(aURI);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // set the loadInfo on the new channel
+ rv = channel->SetLoadInfo(aLoadInfo);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ channel.forget(aResult);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDeviceProtocolHandler::NewChannel(nsIURI* aURI, nsIChannel **aResult)
+{
+ return NewChannel2(aURI, nullptr, aResult);
+}
+
+NS_IMETHODIMP
+nsDeviceProtocolHandler::AllowPort(int32_t port,
+ const char *scheme,
+ bool *aResult)
+{
+ // don't override anything.
+ *aResult = false;
+ return NS_OK;
+}
+
+} // namespace net
+} // namespace mozilla
diff --git a/netwerk/protocol/device/nsDeviceProtocolHandler.h b/netwerk/protocol/device/nsDeviceProtocolHandler.h
new file mode 100644
index 0000000000..dee9b4f8f0
--- /dev/null
+++ b/netwerk/protocol/device/nsDeviceProtocolHandler.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 nsDeviceProtocolHandler_h_
+#define nsDeviceProtocolHandler_h_
+
+#include "nsIProtocolHandler.h"
+#include "mozilla/Attributes.h"
+
+namespace mozilla {
+namespace net {
+
+// {6b0ffe9e-d114-486b-aeb7-da62e7273ed5}
+#define NS_DEVICEPROTOCOLHANDLER_CID \
+{ 0x60ffe9e, 0xd114, 0x486b, \
+ {0xae, 0xb7, 0xda, 0x62, 0xe7, 0x27, 0x3e, 0xd5} }
+
+class nsDeviceProtocolHandler final : public nsIProtocolHandler {
+ ~nsDeviceProtocolHandler() {}
+
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIPROTOCOLHANDLER
+
+ nsDeviceProtocolHandler() {}
+
+ MOZ_MUST_USE nsresult Init();
+};
+
+} // namespace net
+} // namespace mozilla
+#endif