diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /netwerk/protocol/device | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | uxp-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz |
Add m-esr52 at 52.6.0
Diffstat (limited to 'netwerk/protocol/device')
-rw-r--r-- | netwerk/protocol/device/AndroidCaptureProvider.cpp | 301 | ||||
-rw-r--r-- | netwerk/protocol/device/AndroidCaptureProvider.h | 68 | ||||
-rw-r--r-- | netwerk/protocol/device/CameraStreamImpl.cpp | 114 | ||||
-rw-r--r-- | netwerk/protocol/device/CameraStreamImpl.h | 71 | ||||
-rw-r--r-- | netwerk/protocol/device/RawStructs.h | 60 | ||||
-rw-r--r-- | netwerk/protocol/device/moz.build | 27 | ||||
-rw-r--r-- | netwerk/protocol/device/nsDeviceCaptureProvider.h | 31 | ||||
-rw-r--r-- | netwerk/protocol/device/nsDeviceChannel.cpp | 154 | ||||
-rw-r--r-- | netwerk/protocol/device/nsDeviceChannel.h | 26 | ||||
-rw-r--r-- | netwerk/protocol/device/nsDeviceProtocolHandler.cpp | 93 | ||||
-rw-r--r-- | netwerk/protocol/device/nsDeviceProtocolHandler.h | 34 |
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 |