Bug 1449132 [wpt PR 10194] - [css-grid] Fix resolution of percentage paddings and...
[gecko.git] / dom / media / CanvasCaptureMediaStream.cpp
blob35deaad8a9a8d2f0990c3eb015b562918bcebc41
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/. */
6 #include "CanvasCaptureMediaStream.h"
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"
18 using namespace mozilla::layers;
19 using namespace mozilla::gfx;
21 namespace mozilla {
22 namespace dom {
24 class OutputStreamDriver::StreamListener : public MediaStreamListener
26 public:
27 explicit StreamListener(OutputStreamDriver* aDriver,
28 TrackID aTrackId,
29 PrincipalHandle aPrincipalHandle,
30 SourceMediaStream* aSourceStream)
31 : mEnded(false)
32 , mSourceStream(aSourceStream)
33 , mTrackId(aTrackId)
34 , mPrincipalHandle(aPrincipalHandle)
35 , mMutex("CanvasCaptureMediaStream OutputStreamDriver::StreamListener")
37 MOZ_ASSERT(mSourceStream);
40 void EndStream() {
41 mEnded = true;
44 void SetImage(const RefPtr<layers::Image>& aImage, const TimeStamp& aTime)
46 MutexAutoLock lock(mMutex);
47 mImage = aImage;
48 mImageTime = aTime;
51 void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) override
53 // Called on the MediaStreamGraph thread.
54 MOZ_ASSERT(mSourceStream);
55 StreamTime delta = aDesiredTime - mSourceStream->GetEndOfAppendedData(mTrackId);
56 if (delta > 0) {
57 MutexAutoLock lock(mMutex);
59 RefPtr<Image> image = mImage;
60 IntSize size = image ? image->GetSize() : IntSize(0, 0);
61 VideoSegment segment;
62 segment.AppendFrame(image.forget(), delta, size, mPrincipalHandle, false,
63 mImageTime);
65 mSourceStream->AppendToTrack(mTrackId, &segment);
68 if (mEnded) {
69 mSourceStream->EndAllTrackAndFinish();
73 void NotifyEvent(MediaStreamGraph* aGraph, MediaStreamGraphEvent aEvent) override
75 if (aEvent == MediaStreamGraphEvent::EVENT_REMOVED) {
76 EndStream();
77 mSourceStream->EndAllTrackAndFinish();
79 MutexAutoLock lock(mMutex);
80 mImage = nullptr;
84 protected:
85 ~StreamListener() { }
87 private:
88 Atomic<bool> mEnded;
89 const RefPtr<SourceMediaStream> mSourceStream;
90 const TrackID mTrackId;
91 const PrincipalHandle mPrincipalHandle;
93 Mutex mMutex;
94 // The below members are protected by mMutex.
95 RefPtr<layers::Image> mImage;
96 TimeStamp mImageTime;
99 OutputStreamDriver::OutputStreamDriver(SourceMediaStream* aSourceStream,
100 const TrackID& aTrackId,
101 const PrincipalHandle& aPrincipalHandle)
102 : FrameCaptureListener()
103 , mSourceStream(aSourceStream)
104 , mStreamListener(new StreamListener(this, aTrackId, aPrincipalHandle,
105 aSourceStream))
107 MOZ_ASSERT(NS_IsMainThread());
108 MOZ_ASSERT(mSourceStream);
109 mSourceStream->AddListener(mStreamListener);
110 mSourceStream->AddTrack(aTrackId, 0, new VideoSegment());
111 mSourceStream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
112 mSourceStream->SetPullEnabled(true);
114 // All CanvasCaptureMediaStreams shall at least get one frame.
115 mFrameCaptureRequested = true;
118 OutputStreamDriver::~OutputStreamDriver()
120 MOZ_ASSERT(NS_IsMainThread());
121 if (mStreamListener) {
122 // MediaStreamGraph will keep the listener alive until it can finish the
123 // stream on the next NotifyPull().
124 mStreamListener->EndStream();
128 void
129 OutputStreamDriver::SetImage(const RefPtr<layers::Image>& aImage,
130 const TimeStamp& aTime)
132 if (mStreamListener) {
133 mStreamListener->SetImage(aImage, aTime);
137 // ----------------------------------------------------------------------
139 class TimerDriver : public OutputStreamDriver
141 public:
142 explicit TimerDriver(SourceMediaStream* aSourceStream,
143 const double& aFPS,
144 const TrackID& aTrackId,
145 const PrincipalHandle& aPrincipalHandle)
146 : OutputStreamDriver(aSourceStream, aTrackId, aPrincipalHandle)
147 , mFPS(aFPS)
148 , mTimer(nullptr)
150 if (mFPS == 0.0) {
151 return;
154 NS_NewTimerWithFuncCallback(getter_AddRefs(mTimer),
155 &TimerTick,
156 this,
157 int(1000 / mFPS),
158 nsITimer::TYPE_REPEATING_SLACK,
159 "dom::TimerDriver::TimerDriver");
162 static void TimerTick(nsITimer* aTimer, void* aClosure)
164 MOZ_ASSERT(aClosure);
165 TimerDriver* driver = static_cast<TimerDriver*>(aClosure);
167 driver->RequestFrameCapture();
170 void NewFrame(already_AddRefed<Image> aImage, const TimeStamp& aTime) override
172 RefPtr<Image> image = aImage;
174 if (!mFrameCaptureRequested) {
175 return;
178 mFrameCaptureRequested = false;
179 SetImage(image.forget(), aTime);
182 void Forget() override
184 if (mTimer) {
185 mTimer->Cancel();
186 mTimer = nullptr;
190 protected:
191 virtual ~TimerDriver() {}
193 private:
194 const double mFPS;
195 nsCOMPtr<nsITimer> mTimer;
198 // ----------------------------------------------------------------------
200 class AutoDriver : public OutputStreamDriver
202 public:
203 explicit AutoDriver(SourceMediaStream* aSourceStream,
204 const TrackID& aTrackId,
205 const PrincipalHandle& aPrincipalHandle)
206 : OutputStreamDriver(aSourceStream, aTrackId, aPrincipalHandle) {}
208 void NewFrame(already_AddRefed<Image> aImage, const TimeStamp& aTime) override
210 // Don't reset `mFrameCaptureRequested` since AutoDriver shall always have
211 // `mFrameCaptureRequested` set to true.
212 // This also means we should accept every frame as NewFrame is called only
213 // after something changed.
215 RefPtr<Image> image = aImage;
216 SetImage(image.forget(), aTime);
219 protected:
220 virtual ~AutoDriver() {}
223 // ----------------------------------------------------------------------
225 NS_IMPL_CYCLE_COLLECTION_INHERITED(CanvasCaptureMediaStream, DOMMediaStream,
226 mCanvas)
228 NS_IMPL_ADDREF_INHERITED(CanvasCaptureMediaStream, DOMMediaStream)
229 NS_IMPL_RELEASE_INHERITED(CanvasCaptureMediaStream, DOMMediaStream)
231 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CanvasCaptureMediaStream)
232 NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
234 CanvasCaptureMediaStream::CanvasCaptureMediaStream(nsPIDOMWindowInner* aWindow,
235 HTMLCanvasElement* aCanvas)
236 : DOMMediaStream(aWindow, nullptr)
237 , mCanvas(aCanvas)
238 , mOutputStreamDriver(nullptr)
242 CanvasCaptureMediaStream::~CanvasCaptureMediaStream()
244 if (mOutputStreamDriver) {
245 mOutputStreamDriver->Forget();
249 JSObject*
250 CanvasCaptureMediaStream::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
252 return dom::CanvasCaptureMediaStreamBinding::Wrap(aCx, this, aGivenProto);
255 void
256 CanvasCaptureMediaStream::RequestFrame()
258 if (mOutputStreamDriver) {
259 mOutputStreamDriver->RequestFrameCapture();
263 nsresult
264 CanvasCaptureMediaStream::Init(const dom::Optional<double>& aFPS,
265 const TrackID& aTrackId,
266 nsIPrincipal* aPrincipal)
268 PrincipalHandle principalHandle = MakePrincipalHandle(aPrincipal);
270 if (!aFPS.WasPassed()) {
271 mOutputStreamDriver =
272 new AutoDriver(GetInputStream()->AsSourceStream(), aTrackId, principalHandle);
273 } else if (aFPS.Value() < 0) {
274 return NS_ERROR_ILLEGAL_VALUE;
275 } else {
276 // Cap frame rate to 60 FPS for sanity
277 double fps = std::min(60.0, aFPS.Value());
278 mOutputStreamDriver =
279 new TimerDriver(GetInputStream()->AsSourceStream(), fps, aTrackId, principalHandle);
281 return NS_OK;
284 already_AddRefed<CanvasCaptureMediaStream>
285 CanvasCaptureMediaStream::CreateSourceStream(nsPIDOMWindowInner* aWindow,
286 HTMLCanvasElement* aCanvas)
288 RefPtr<CanvasCaptureMediaStream> stream = new CanvasCaptureMediaStream(aWindow, aCanvas);
289 MediaStreamGraph* graph =
290 MediaStreamGraph::GetInstance(MediaStreamGraph::SYSTEM_THREAD_DRIVER, aWindow,
291 MediaStreamGraph::REQUEST_DEFAULT_SAMPLE_RATE);
292 stream->InitSourceStream(graph);
293 return stream.forget();
296 FrameCaptureListener*
297 CanvasCaptureMediaStream::FrameCaptureListener()
299 return mOutputStreamDriver;
302 void
303 CanvasCaptureMediaStream::StopCapture()
305 if (!mOutputStreamDriver) {
306 return;
309 mOutputStreamDriver->Forget();
310 mOutputStreamDriver = nullptr;
313 } // namespace dom
314 } // namespace mozilla