LCOV - code coverage report
Current view: top level - dom/media - CanvasCaptureMediaStream.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 124 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 34 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; 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 file,
       4             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "CanvasCaptureMediaStream.h"
       7             : 
       8             : #include "DOMMediaStream.h"
       9             : #include "ImageContainer.h"
      10             : #include "MediaStreamGraph.h"
      11             : #include "MediaStreamListener.h"
      12             : #include "gfxPlatform.h"
      13             : #include "mozilla/Atomics.h"
      14             : #include "mozilla/dom/CanvasCaptureMediaStreamBinding.h"
      15             : #include "mozilla/gfx/2D.h"
      16             : #include "nsContentUtils.h"
      17             : 
      18             : using namespace mozilla::layers;
      19             : using namespace mozilla::gfx;
      20             : 
      21             : namespace mozilla {
      22             : namespace dom {
      23             : 
      24             : class OutputStreamDriver::StreamListener : public MediaStreamListener
      25             : {
      26             : public:
      27           0 :   explicit StreamListener(OutputStreamDriver* aDriver,
      28             :                           TrackID aTrackId,
      29             :                           PrincipalHandle aPrincipalHandle,
      30             :                           SourceMediaStream* aSourceStream)
      31           0 :     : mEnded(false)
      32             :     , mSourceStream(aSourceStream)
      33             :     , mTrackId(aTrackId)
      34             :     , mPrincipalHandle(aPrincipalHandle)
      35           0 :     , mMutex("CanvasCaptureMediaStream OutputStreamDriver::StreamListener")
      36             :   {
      37           0 :     MOZ_ASSERT(mSourceStream);
      38           0 :   }
      39             : 
      40           0 :   void EndStream() {
      41           0 :     mEnded = true;
      42           0 :   }
      43             : 
      44           0 :   void SetImage(const RefPtr<layers::Image>& aImage, const TimeStamp& aTime)
      45             :   {
      46           0 :     MutexAutoLock lock(mMutex);
      47           0 :     mImage = aImage;
      48           0 :     mImageTime = aTime;
      49           0 :   }
      50             : 
      51           0 :   void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) override
      52             :   {
      53             :     // Called on the MediaStreamGraph thread.
      54           0 :     MOZ_ASSERT(mSourceStream);
      55           0 :     StreamTime delta = aDesiredTime - mSourceStream->GetEndOfAppendedData(mTrackId);
      56           0 :     if (delta > 0) {
      57           0 :       MutexAutoLock lock(mMutex);
      58             : 
      59           0 :       RefPtr<Image> image = mImage;
      60           0 :       IntSize size = image ? image->GetSize() : IntSize(0, 0);
      61           0 :       VideoSegment segment;
      62           0 :       segment.AppendFrame(image.forget(), delta, size, mPrincipalHandle, false,
      63           0 :                           mImageTime);
      64             : 
      65           0 :       mSourceStream->AppendToTrack(mTrackId, &segment);
      66             :     }
      67             : 
      68           0 :     if (mEnded) {
      69           0 :       mSourceStream->EndAllTrackAndFinish();
      70             :     }
      71           0 :   }
      72             : 
      73             : protected:
      74           0 :   ~StreamListener() { }
      75             : 
      76             : private:
      77             :   Atomic<bool> mEnded;
      78             :   const RefPtr<SourceMediaStream> mSourceStream;
      79             :   const TrackID mTrackId;
      80             :   const PrincipalHandle mPrincipalHandle;
      81             : 
      82             :   Mutex mMutex;
      83             :   // The below members are protected by mMutex.
      84             :   RefPtr<layers::Image> mImage;
      85             :   TimeStamp mImageTime;
      86             : };
      87             : 
      88           0 : OutputStreamDriver::OutputStreamDriver(SourceMediaStream* aSourceStream,
      89             :                                        const TrackID& aTrackId,
      90           0 :                                        const PrincipalHandle& aPrincipalHandle)
      91             :   : FrameCaptureListener()
      92             :   , mSourceStream(aSourceStream)
      93             :   , mStreamListener(new StreamListener(this, aTrackId, aPrincipalHandle,
      94           0 :                                        aSourceStream))
      95             : {
      96           0 :   MOZ_ASSERT(NS_IsMainThread());
      97           0 :   MOZ_ASSERT(mSourceStream);
      98           0 :   mSourceStream->AddListener(mStreamListener);
      99           0 :   mSourceStream->AddTrack(aTrackId, 0, new VideoSegment());
     100           0 :   mSourceStream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
     101           0 :   mSourceStream->SetPullEnabled(true);
     102             : 
     103             :   // All CanvasCaptureMediaStreams shall at least get one frame.
     104           0 :   mFrameCaptureRequested = true;
     105           0 : }
     106             : 
     107           0 : OutputStreamDriver::~OutputStreamDriver()
     108             : {
     109           0 :   MOZ_ASSERT(NS_IsMainThread());
     110           0 :   if (mStreamListener) {
     111             :     // MediaStreamGraph will keep the listener alive until it can finish the
     112             :     // stream on the next NotifyPull().
     113           0 :     mStreamListener->EndStream();
     114             :   }
     115           0 : }
     116             : 
     117             : void
     118           0 : OutputStreamDriver::SetImage(const RefPtr<layers::Image>& aImage,
     119             :                              const TimeStamp& aTime)
     120             : {
     121           0 :   if (mStreamListener) {
     122           0 :     mStreamListener->SetImage(aImage, aTime);
     123             :   }
     124           0 : }
     125             : 
     126             : // ----------------------------------------------------------------------
     127             : 
     128             : class TimerDriver : public OutputStreamDriver
     129             : {
     130             : public:
     131           0 :   explicit TimerDriver(SourceMediaStream* aSourceStream,
     132             :                        const double& aFPS,
     133             :                        const TrackID& aTrackId,
     134             :                        const PrincipalHandle& aPrincipalHandle)
     135           0 :     : OutputStreamDriver(aSourceStream, aTrackId, aPrincipalHandle)
     136           0 :     , mFPS(aFPS)
     137           0 :     , mTimer(nullptr)
     138             :   {
     139           0 :     if (mFPS == 0.0) {
     140           0 :       return;
     141             :     }
     142             : 
     143           0 :     mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
     144           0 :     if (!mTimer) {
     145           0 :       return;
     146             :     }
     147           0 :     mTimer->InitWithNamedFuncCallback(&TimerTick,
     148             :                                       this,
     149           0 :                                       int(1000 / mFPS),
     150             :                                       nsITimer::TYPE_REPEATING_SLACK,
     151           0 :                                       "dom::TimerDriver::TimerDriver");
     152             :   }
     153             : 
     154           0 :   static void TimerTick(nsITimer* aTimer, void* aClosure)
     155             :   {
     156           0 :     MOZ_ASSERT(aClosure);
     157           0 :     TimerDriver* driver = static_cast<TimerDriver*>(aClosure);
     158             : 
     159           0 :     driver->RequestFrameCapture();
     160           0 :   }
     161             : 
     162           0 :   void NewFrame(already_AddRefed<Image> aImage, const TimeStamp& aTime) override
     163             :   {
     164           0 :     RefPtr<Image> image = aImage;
     165             : 
     166           0 :     if (!mFrameCaptureRequested) {
     167           0 :       return;
     168             :     }
     169             : 
     170           0 :     mFrameCaptureRequested = false;
     171           0 :     SetImage(image.forget(), aTime);
     172             :   }
     173             : 
     174           0 :   void Forget() override
     175             :   {
     176           0 :     if (mTimer) {
     177           0 :       mTimer->Cancel();
     178           0 :       mTimer = nullptr;
     179             :     }
     180           0 :   }
     181             : 
     182             : protected:
     183           0 :   virtual ~TimerDriver() {}
     184             : 
     185             : private:
     186             :   const double mFPS;
     187             :   nsCOMPtr<nsITimer> mTimer;
     188             : };
     189             : 
     190             : // ----------------------------------------------------------------------
     191             : 
     192             : class AutoDriver : public OutputStreamDriver
     193             : {
     194             : public:
     195           0 :   explicit AutoDriver(SourceMediaStream* aSourceStream,
     196             :                       const TrackID& aTrackId,
     197             :                       const PrincipalHandle& aPrincipalHandle)
     198           0 :     : OutputStreamDriver(aSourceStream, aTrackId, aPrincipalHandle) {}
     199             : 
     200           0 :   void NewFrame(already_AddRefed<Image> aImage, const TimeStamp& aTime) override
     201             :   {
     202             :     // Don't reset `mFrameCaptureRequested` since AutoDriver shall always have
     203             :     // `mFrameCaptureRequested` set to true.
     204             :     // This also means we should accept every frame as NewFrame is called only
     205             :     // after something changed.
     206             : 
     207           0 :     RefPtr<Image> image = aImage;
     208           0 :     SetImage(image.forget(), aTime);
     209           0 :   }
     210             : 
     211             : protected:
     212           0 :   virtual ~AutoDriver() {}
     213             : };
     214             : 
     215             : // ----------------------------------------------------------------------
     216             : 
     217           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(CanvasCaptureMediaStream, DOMMediaStream,
     218             :                                    mCanvas)
     219             : 
     220           0 : NS_IMPL_ADDREF_INHERITED(CanvasCaptureMediaStream, DOMMediaStream)
     221           0 : NS_IMPL_RELEASE_INHERITED(CanvasCaptureMediaStream, DOMMediaStream)
     222             : 
     223           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(CanvasCaptureMediaStream)
     224           0 : NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
     225             : 
     226           0 : CanvasCaptureMediaStream::CanvasCaptureMediaStream(nsPIDOMWindowInner* aWindow,
     227           0 :                                                    HTMLCanvasElement* aCanvas)
     228             :   : DOMMediaStream(aWindow, nullptr)
     229             :   , mCanvas(aCanvas)
     230           0 :   , mOutputStreamDriver(nullptr)
     231             : {
     232           0 : }
     233             : 
     234           0 : CanvasCaptureMediaStream::~CanvasCaptureMediaStream()
     235             : {
     236           0 :   if (mOutputStreamDriver) {
     237           0 :     mOutputStreamDriver->Forget();
     238             :   }
     239           0 : }
     240             : 
     241             : JSObject*
     242           0 : CanvasCaptureMediaStream::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     243             : {
     244           0 :   return dom::CanvasCaptureMediaStreamBinding::Wrap(aCx, this, aGivenProto);
     245             : }
     246             : 
     247             : void
     248           0 : CanvasCaptureMediaStream::RequestFrame()
     249             : {
     250           0 :   if (mOutputStreamDriver) {
     251           0 :     mOutputStreamDriver->RequestFrameCapture();
     252             :   }
     253           0 : }
     254             : 
     255             : nsresult
     256           0 : CanvasCaptureMediaStream::Init(const dom::Optional<double>& aFPS,
     257             :                                const TrackID& aTrackId,
     258             :                                nsIPrincipal* aPrincipal)
     259             : {
     260           0 :   PrincipalHandle principalHandle = MakePrincipalHandle(aPrincipal);
     261             : 
     262           0 :   if (!aFPS.WasPassed()) {
     263             :     mOutputStreamDriver =
     264           0 :       new AutoDriver(GetInputStream()->AsSourceStream(), aTrackId, principalHandle);
     265           0 :   } else if (aFPS.Value() < 0) {
     266           0 :     return NS_ERROR_ILLEGAL_VALUE;
     267             :   } else {
     268             :     // Cap frame rate to 60 FPS for sanity
     269           0 :     double fps = std::min(60.0, aFPS.Value());
     270             :     mOutputStreamDriver =
     271           0 :       new TimerDriver(GetInputStream()->AsSourceStream(), fps, aTrackId, principalHandle);
     272             :   }
     273           0 :   return NS_OK;
     274             : }
     275             : 
     276             : already_AddRefed<CanvasCaptureMediaStream>
     277           0 : CanvasCaptureMediaStream::CreateSourceStream(nsPIDOMWindowInner* aWindow,
     278             :                                              HTMLCanvasElement* aCanvas)
     279             : {
     280           0 :   RefPtr<CanvasCaptureMediaStream> stream = new CanvasCaptureMediaStream(aWindow, aCanvas);
     281             :   MediaStreamGraph* graph =
     282             :     MediaStreamGraph::GetInstance(MediaStreamGraph::SYSTEM_THREAD_DRIVER,
     283             :                                   AudioChannel::Normal,
     284           0 :                                   aWindow);
     285           0 :   stream->InitSourceStream(graph);
     286           0 :   return stream.forget();
     287             : }
     288             : 
     289             : FrameCaptureListener*
     290           0 : CanvasCaptureMediaStream::FrameCaptureListener()
     291             : {
     292           0 :   return mOutputStreamDriver;
     293             : }
     294             : 
     295             : void
     296           0 : CanvasCaptureMediaStream::StopCapture()
     297             : {
     298           0 :   if (!mOutputStreamDriver) {
     299           0 :     return;
     300             :   }
     301             : 
     302           0 :   mOutputStreamDriver->Forget();
     303           0 :   mOutputStreamDriver = nullptr;
     304             : }
     305             : 
     306             : } // namespace dom
     307             : } // namespace mozilla
     308             : 

Generated by: LCOV version 1.13