netwerk/protocol/device/AndroidCaptureProvider.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "base/basictypes.h"
     7 #include "AndroidCaptureProvider.h"
     8 #include "nsXULAppAPI.h"
     9 #include "AndroidBridge.h"
    10 #include "nsStreamUtils.h"
    11 #include "nsThreadUtils.h"
    12 #include "nsMemory.h"
    13 #include "RawStructs.h"
    15 // The maximum number of frames we keep in our queue. Don't live in the past.
    16 #define MAX_FRAMES_QUEUED 10
    18 using namespace mozilla::net;
    20 NS_IMPL_ISUPPORTS(AndroidCameraInputStream, nsIInputStream, nsIAsyncInputStream)
    22 AndroidCameraInputStream::AndroidCameraInputStream() :
    23   mWidth(0), mHeight(0), mCamera(0), mHeaderSent(false), mClosed(true), mFrameSize(0),
    24   mMonitor("AndroidCamera.Monitor")
    25 {
    26   mAvailable = sizeof(RawVideoHeader);
    27   mFrameQueue = new nsDeque();
    28 }
    30 AndroidCameraInputStream::~AndroidCameraInputStream() {
    31   // clear the frame queue
    32   while (mFrameQueue->GetSize() > 0) {
    33     nsMemory::Free(mFrameQueue->PopFront());
    34   }
    35   delete mFrameQueue;
    36 }
    38 NS_IMETHODIMP
    39 AndroidCameraInputStream::Init(nsACString& aContentType, nsCaptureParams* aParams)
    40 {
    41   if (XRE_GetProcessType() != GeckoProcessType_Default)
    42     return NS_ERROR_NOT_IMPLEMENTED;
    44   mContentType = aContentType;
    45   mWidth = aParams->width;
    46   mHeight = aParams->height;
    47   mCamera = aParams->camera;
    49   CameraStreamImpl *impl = CameraStreamImpl::GetInstance(0);
    50   if (!impl)
    51     return NS_ERROR_OUT_OF_MEMORY;
    52   if (impl->Init(mContentType, mCamera, mWidth, mHeight, this)) {
    53     mWidth = impl->GetWidth();
    54     mHeight = impl->GetHeight();
    55     mClosed = false;
    56   }
    57   return NS_OK;
    58 }
    60 void AndroidCameraInputStream::ReceiveFrame(char* frame, uint32_t length) {
    61   {
    62     mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor);
    63     if (mFrameQueue->GetSize() > MAX_FRAMES_QUEUED) {
    64       nsMemory::Free(mFrameQueue->PopFront());
    65       mAvailable -= mFrameSize;
    66     }
    67   }
    69   mFrameSize = sizeof(RawPacketHeader) + length;
    71   char* fullFrame = (char*)nsMemory::Alloc(mFrameSize);
    73   if (!fullFrame)
    74     return;
    76   RawPacketHeader* header = (RawPacketHeader*) fullFrame;
    77   header->packetID = 0xFF;
    78   header->codecID = 0x595556; // "YUV"
    80   // we copy the Y plane, and de-interlace the CrCb
    82   uint32_t yFrameSize = mWidth * mHeight;
    83   uint32_t uvFrameSize = yFrameSize / 4;
    85   memcpy(fullFrame + sizeof(RawPacketHeader), frame, yFrameSize);
    87   char* uFrame = fullFrame + yFrameSize;
    88   char* vFrame = fullFrame + yFrameSize + uvFrameSize;
    89   char* yFrame = frame + yFrameSize;
    90   for (uint32_t i = 0; i < uvFrameSize; i++) {
    91     uFrame[i] = yFrame[2 * i + 1];
    92     vFrame[i] = yFrame[2 * i];
    93   }
    95   {
    96     mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor);
    97     mAvailable += mFrameSize;
    98     mFrameQueue->Push((void*)fullFrame);
    99   }
   101   NotifyListeners();
   102 }
   104 NS_IMETHODIMP
   105 AndroidCameraInputStream::Available(uint64_t *aAvailable)
   106 {
   107   mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor);
   109   *aAvailable = mAvailable;
   111   return NS_OK;
   112 }
   114 NS_IMETHODIMP AndroidCameraInputStream::IsNonBlocking(bool *aNonBlock) {
   115   *aNonBlock = true;
   116   return NS_OK;
   117 }
   119 NS_IMETHODIMP AndroidCameraInputStream::Read(char *aBuffer, uint32_t aCount, uint32_t *aRead) {
   120   return ReadSegments(NS_CopySegmentToBuffer, aBuffer, aCount, aRead);
   121 }
   123 NS_IMETHODIMP AndroidCameraInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, uint32_t aCount, uint32_t *aRead) {
   124   *aRead = 0;
   126   nsresult rv;
   128   if (mAvailable == 0)
   129     return NS_BASE_STREAM_WOULD_BLOCK;
   131   if (aCount > mAvailable)
   132     aCount = mAvailable;
   134   if (!mHeaderSent) {
   135     CameraStreamImpl *impl = CameraStreamImpl::GetInstance(0);
   136     RawVideoHeader header;
   137     header.headerPacketID = 0;
   138     header.codecID = 0x595556; // "YUV"
   139     header.majorVersion = 0;
   140     header.minorVersion = 1;
   141     header.options = 1 | 1 << 1; // color, 4:2:2
   143     header.alphaChannelBpp = 0;
   144     header.lumaChannelBpp = 8;
   145     header.chromaChannelBpp = 4;
   146     header.colorspace = 1;
   148     header.frameWidth = mWidth;
   149     header.frameHeight = mHeight;
   150     header.aspectNumerator = 1;
   151     header.aspectDenominator = 1;
   153     header.framerateNumerator = impl->GetFps();
   154     header.framerateDenominator = 1;
   156     rv = aWriter(this, aClosure, (const char*)&header, 0, sizeof(RawVideoHeader), aRead);
   158     if (NS_FAILED(rv))
   159       return NS_OK;
   161     mHeaderSent = true;
   162     aCount -= sizeof(RawVideoHeader);
   163     mAvailable -= sizeof(RawVideoHeader);
   164   }
   166   {
   167     mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor);
   168     while ((mAvailable > 0) && (aCount >= mFrameSize)) {
   169       uint32_t readThisTime = 0;
   171       char* frame = (char*)mFrameQueue->PopFront();
   172       rv = aWriter(this, aClosure, (const char*)frame, *aRead, mFrameSize, &readThisTime);
   174       if (readThisTime != mFrameSize) {
   175         mFrameQueue->PushFront((void*)frame);
   176         return NS_OK;
   177       }
   179       // RawReader does a copy when calling VideoData::Create()
   180       nsMemory::Free(frame);
   182       if (NS_FAILED(rv))
   183         return NS_OK;
   185       aCount -= readThisTime;
   186       mAvailable -= readThisTime;
   187       *aRead += readThisTime;
   188     }
   189   }
   190   return NS_OK;
   191 }
   193 NS_IMETHODIMP AndroidCameraInputStream::Close() {
   194   return CloseWithStatus(NS_OK);
   195 }
   198 /**
   199  * must be called on the main (java) thread
   200  */
   201 void AndroidCameraInputStream::doClose() {
   202   NS_ASSERTION(!mClosed, "Camera is already closed");
   204   CameraStreamImpl *impl = CameraStreamImpl::GetInstance(0);
   205   impl->Close();
   206   mClosed = true;
   207 }
   210 void AndroidCameraInputStream::NotifyListeners() {
   211   mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor);
   213   if (mCallback && (mAvailable > sizeof(RawVideoHeader))) {
   214     nsCOMPtr<nsIInputStreamCallback> callback;
   215     if (mCallbackTarget) {
   216       callback = NS_NewInputStreamReadyEvent(mCallback, mCallbackTarget);
   217     } else {
   218       callback = mCallback;
   219     }
   221     NS_ASSERTION(callback, "Shouldn't fail to make the callback!");
   223     // Null the callback first because OnInputStreamReady may reenter AsyncWait
   224     mCallback = nullptr;
   225     mCallbackTarget = nullptr;
   227     callback->OnInputStreamReady(this);
   228   }
   229 }
   231 NS_IMETHODIMP AndroidCameraInputStream::AsyncWait(nsIInputStreamCallback *aCallback, uint32_t aFlags, uint32_t aRequestedCount, nsIEventTarget *aTarget)
   232 {
   233   if (aFlags != 0)
   234     return NS_ERROR_NOT_IMPLEMENTED;
   236   if (mCallback || mCallbackTarget)
   237     return NS_ERROR_UNEXPECTED;
   239   mCallbackTarget = aTarget;
   240   mCallback = aCallback;
   242   // What we are being asked for may be present already
   243   NotifyListeners();
   244   return NS_OK;
   245 }
   248 NS_IMETHODIMP AndroidCameraInputStream::CloseWithStatus(nsresult status)
   249 {
   250   AndroidCameraInputStream::doClose();
   251   return NS_OK;
   252 }
   254 /**
   255  * AndroidCaptureProvider implementation
   256  */
   258 NS_IMPL_ISUPPORTS0(AndroidCaptureProvider)
   260 AndroidCaptureProvider* AndroidCaptureProvider::sInstance = nullptr;
   262 AndroidCaptureProvider::AndroidCaptureProvider() {
   263 }
   265 AndroidCaptureProvider::~AndroidCaptureProvider() {
   266   AndroidCaptureProvider::sInstance = nullptr;
   267 }
   269 nsresult AndroidCaptureProvider::Init(nsACString& aContentType,
   270                         nsCaptureParams* aParams,
   271                         nsIInputStream** aStream) {
   273   NS_ENSURE_ARG_POINTER(aParams);
   275   NS_ASSERTION(aParams->frameLimit == 0 || aParams->timeLimit == 0,
   276     "Cannot set both a frame limit and a time limit!");
   278   nsRefPtr<AndroidCameraInputStream> stream;
   280   if (aContentType.EqualsLiteral("video/x-raw-yuv")) {
   281     stream = new AndroidCameraInputStream();
   282     if (stream) {
   283       nsresult rv = stream->Init(aContentType, aParams);
   284       if (NS_FAILED(rv))
   285         return rv;
   286     }
   287     else
   288       return NS_ERROR_OUT_OF_MEMORY;
   289   } else {
   290     NS_NOTREACHED("Should not have asked Android for this type!");
   291   }
   292   return CallQueryInterface(stream, aStream);
   293 }
   295 already_AddRefed<AndroidCaptureProvider> GetAndroidCaptureProvider() {
   296   if (!AndroidCaptureProvider::sInstance) {
   297     AndroidCaptureProvider::sInstance = new AndroidCaptureProvider();
   298   }
   299   nsRefPtr<AndroidCaptureProvider> ret = AndroidCaptureProvider::sInstance;
   300   return ret.forget();
   301 }

mercurial