Bug 1572460 - Refactor `selection` out of the `InspectorFront`. r=yulia
[gecko.git] / dom / media / CanvasCaptureMediaStream.cpp
blob5624ba2873c0554ed277ac01c5f7a5d32fccba43
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 "gfxPlatform.h"
12 #include "mozilla/Atomics.h"
13 #include "mozilla/dom/CanvasCaptureMediaStreamBinding.h"
14 #include "mozilla/gfx/2D.h"
15 #include "nsContentUtils.h"
16 #include "Tracing.h"
18 using namespace mozilla::layers;
19 using namespace mozilla::gfx;
21 namespace mozilla {
22 namespace dom {
24 OutputStreamDriver::OutputStreamDriver(SourceMediaStream* aSourceStream,
25 const TrackID& aTrackId,
26 const PrincipalHandle& aPrincipalHandle)
27 : FrameCaptureListener(),
28 mTrackId(aTrackId),
29 mSourceStream(aSourceStream),
30 mPrincipalHandle(aPrincipalHandle) {
31 MOZ_ASSERT(NS_IsMainThread());
32 MOZ_ASSERT(mSourceStream);
33 MOZ_ASSERT(IsTrackIDExplicit(mTrackId));
34 mSourceStream->AddTrack(aTrackId, new VideoSegment());
36 // All CanvasCaptureMediaStreams shall at least get one frame.
37 mFrameCaptureRequested = true;
40 OutputStreamDriver::~OutputStreamDriver() {
41 MOZ_ASSERT(NS_IsMainThread());
42 EndTrack();
45 void OutputStreamDriver::EndTrack() {
46 MOZ_ASSERT(NS_IsMainThread());
47 if (!mSourceStream->IsDestroyed()) {
48 mSourceStream->Destroy();
52 void OutputStreamDriver::SetImage(const RefPtr<layers::Image>& aImage,
53 const TimeStamp& aTime) {
54 MOZ_ASSERT(NS_IsMainThread());
56 TRACE_COMMENT("SourceMediaStream %p track %i", mSourceStream.get(), mTrackId);
58 VideoSegment segment;
59 segment.AppendFrame(do_AddRef(aImage), aImage->GetSize(), mPrincipalHandle,
60 false, aTime);
61 mSourceStream->AppendToTrack(mTrackId, &segment);
64 // ----------------------------------------------------------------------
66 class TimerDriver : public OutputStreamDriver {
67 public:
68 explicit TimerDriver(SourceMediaStream* aSourceStream, const double& aFPS,
69 const TrackID& aTrackId,
70 const PrincipalHandle& aPrincipalHandle)
71 : OutputStreamDriver(aSourceStream, aTrackId, aPrincipalHandle),
72 mFPS(aFPS),
73 mTimer(nullptr) {
74 if (mFPS == 0.0) {
75 return;
78 NS_NewTimerWithFuncCallback(
79 getter_AddRefs(mTimer), &TimerTick, this, int(1000 / mFPS),
80 nsITimer::TYPE_REPEATING_SLACK, "dom::TimerDriver::TimerDriver");
83 static void TimerTick(nsITimer* aTimer, void* aClosure) {
84 MOZ_ASSERT(aClosure);
85 TimerDriver* driver = static_cast<TimerDriver*>(aClosure);
87 driver->RequestFrameCapture();
90 void NewFrame(already_AddRefed<Image> aImage,
91 const TimeStamp& aTime) override {
92 RefPtr<Image> image = aImage;
94 if (!mFrameCaptureRequested) {
95 return;
98 mFrameCaptureRequested = false;
99 SetImage(image.forget(), aTime);
102 void Forget() override {
103 if (mTimer) {
104 mTimer->Cancel();
105 mTimer = nullptr;
109 protected:
110 virtual ~TimerDriver() {}
112 private:
113 const double mFPS;
114 nsCOMPtr<nsITimer> mTimer;
117 // ----------------------------------------------------------------------
119 class AutoDriver : public OutputStreamDriver {
120 public:
121 explicit AutoDriver(SourceMediaStream* aSourceStream, const TrackID& aTrackId,
122 const PrincipalHandle& aPrincipalHandle)
123 : OutputStreamDriver(aSourceStream, aTrackId, aPrincipalHandle) {}
125 void NewFrame(already_AddRefed<Image> aImage,
126 const TimeStamp& aTime) override {
127 // Don't reset `mFrameCaptureRequested` since AutoDriver shall always have
128 // `mFrameCaptureRequested` set to true.
129 // This also means we should accept every frame as NewFrame is called only
130 // after something changed.
132 RefPtr<Image> image = aImage;
133 SetImage(image.forget(), aTime);
136 protected:
137 virtual ~AutoDriver() {}
140 // ----------------------------------------------------------------------
142 NS_IMPL_CYCLE_COLLECTION_INHERITED(CanvasCaptureMediaStream, DOMMediaStream,
143 mCanvas)
145 NS_IMPL_ADDREF_INHERITED(CanvasCaptureMediaStream, DOMMediaStream)
146 NS_IMPL_RELEASE_INHERITED(CanvasCaptureMediaStream, DOMMediaStream)
148 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CanvasCaptureMediaStream)
149 NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
151 CanvasCaptureMediaStream::CanvasCaptureMediaStream(nsPIDOMWindowInner* aWindow,
152 HTMLCanvasElement* aCanvas)
153 : DOMMediaStream(aWindow), mCanvas(aCanvas) {}
155 CanvasCaptureMediaStream::~CanvasCaptureMediaStream() {
156 if (mOutputStreamDriver) {
157 mOutputStreamDriver->Forget();
161 JSObject* CanvasCaptureMediaStream::WrapObject(
162 JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
163 return dom::CanvasCaptureMediaStream_Binding::Wrap(aCx, this, aGivenProto);
166 void CanvasCaptureMediaStream::RequestFrame() {
167 if (mOutputStreamDriver) {
168 mOutputStreamDriver->RequestFrameCapture();
172 nsresult CanvasCaptureMediaStream::Init(const dom::Optional<double>& aFPS,
173 const TrackID aTrackId,
174 nsIPrincipal* aPrincipal) {
175 MediaStreamGraph* graph = MediaStreamGraph::GetInstance(
176 MediaStreamGraph::SYSTEM_THREAD_DRIVER, mWindow,
177 MediaStreamGraph::REQUEST_DEFAULT_SAMPLE_RATE);
178 SourceMediaStream* source = graph->CreateSourceStream();
179 PrincipalHandle principalHandle = MakePrincipalHandle(aPrincipal);
180 if (!aFPS.WasPassed()) {
181 mOutputStreamDriver = new AutoDriver(source, aTrackId, principalHandle);
182 } else if (aFPS.Value() < 0) {
183 return NS_ERROR_ILLEGAL_VALUE;
184 } else {
185 // Cap frame rate to 60 FPS for sanity
186 double fps = std::min(60.0, aFPS.Value());
187 mOutputStreamDriver =
188 new TimerDriver(source, fps, aTrackId, principalHandle);
190 return NS_OK;
193 FrameCaptureListener* CanvasCaptureMediaStream::FrameCaptureListener() {
194 return mOutputStreamDriver;
197 void CanvasCaptureMediaStream::StopCapture() {
198 if (!mOutputStreamDriver) {
199 return;
202 mOutputStreamDriver->EndTrack();
203 mOutputStreamDriver->Forget();
204 mOutputStreamDriver = nullptr;
207 SourceMediaStream* CanvasCaptureMediaStream::GetSourceStream() const {
208 if (!mOutputStreamDriver) {
209 return nullptr;
211 return mOutputStreamDriver->mSourceStream;
214 } // namespace dom
215 } // namespace mozilla