Backed out changeset 06f41c22f3a6 (bug 1888460) for causing linux xpcshell failures...
[gecko.git] / dom / media / CanvasCaptureMediaStream.cpp
blob377243540c227b83549ab3e556c558aa1e8f8adc
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 "MediaTrackGraph.h"
11 #include "Tracing.h"
12 #include "VideoSegment.h"
13 #include "gfxPlatform.h"
14 #include "mozilla/Atomics.h"
15 #include "mozilla/dom/CanvasCaptureMediaStreamBinding.h"
16 #include "mozilla/gfx/2D.h"
17 #include "nsContentUtils.h"
19 using namespace mozilla::layers;
20 using namespace mozilla::gfx;
22 namespace mozilla::dom {
24 OutputStreamDriver::OutputStreamDriver(SourceMediaTrack* aSourceStream,
25 const PrincipalHandle& aPrincipalHandle)
26 : mSourceStream(aSourceStream), mPrincipalHandle(aPrincipalHandle) {
27 MOZ_ASSERT(NS_IsMainThread());
28 MOZ_ASSERT(mSourceStream);
31 OutputStreamDriver::~OutputStreamDriver() {
32 MOZ_ASSERT(NS_IsMainThread());
33 EndTrack();
36 void OutputStreamDriver::EndTrack() {
37 MOZ_ASSERT(NS_IsMainThread());
38 if (!mSourceStream->IsDestroyed()) {
39 mSourceStream->Destroy();
43 void OutputStreamDriver::SetImage(RefPtr<layers::Image>&& aImage,
44 const TimeStamp& aTime) {
45 MOZ_ASSERT(NS_IsMainThread());
47 VideoSegment segment;
48 const auto size = aImage->GetSize();
49 segment.AppendFrame(aImage.forget(), size, mPrincipalHandle, false, aTime);
50 mSourceStream->AppendData(&segment);
53 // ----------------------------------------------------------------------
55 class TimerDriver : public OutputStreamDriver {
56 public:
57 explicit TimerDriver(SourceMediaTrack* aSourceStream, const double& aFPS,
58 const PrincipalHandle& aPrincipalHandle)
59 : OutputStreamDriver(aSourceStream, aPrincipalHandle),
60 mFrameInterval(aFPS == 0.0 ? TimeDuration::Forever()
61 : TimeDuration::FromSeconds(1.0 / aFPS)) {}
63 void RequestFrameCapture() override { mExplicitCaptureRequested = true; }
65 bool FrameCaptureRequested(const TimeStamp& aTime) const override {
66 if (mLastFrameTime.IsNull()) {
67 // All CanvasCaptureMediaStreams shall at least get one frame.
68 return true;
71 if (mExplicitCaptureRequested) {
72 return true;
75 if ((aTime - mLastFrameTime) >= mFrameInterval) {
76 return true;
79 return false;
82 void NewFrame(already_AddRefed<Image> aImage,
83 const TimeStamp& aTime) override {
84 nsCString str;
85 if (profiler_thread_is_being_profiled_for_markers()) {
86 TimeDuration sinceLast =
87 aTime - (mLastFrameTime.IsNull() ? aTime : mLastFrameTime);
88 str.AppendPrintf(
89 "TimerDriver %staking frame (%sexplicitly requested; after %.2fms; "
90 "interval cap %.2fms)",
91 sinceLast >= mFrameInterval ? "" : "NOT ",
92 mExplicitCaptureRequested ? "" : "NOT ", sinceLast.ToMilliseconds(),
93 mFrameInterval.ToMilliseconds());
95 AUTO_PROFILER_MARKER_TEXT("Canvas CaptureStream", MEDIA_RT, {}, str);
97 RefPtr<Image> image = aImage;
99 if (!FrameCaptureRequested(aTime)) {
100 return;
103 mLastFrameTime = aTime;
104 mExplicitCaptureRequested = false;
105 SetImage(std::move(image), aTime);
108 protected:
109 virtual ~TimerDriver() = default;
111 private:
112 const TimeDuration mFrameInterval;
113 bool mExplicitCaptureRequested = false;
114 TimeStamp mLastFrameTime;
117 // ----------------------------------------------------------------------
119 class AutoDriver : public OutputStreamDriver {
120 public:
121 explicit AutoDriver(SourceMediaTrack* aSourceStream,
122 const PrincipalHandle& aPrincipalHandle)
123 : OutputStreamDriver(aSourceStream, aPrincipalHandle) {}
125 void RequestFrameCapture() override {}
127 bool FrameCaptureRequested(const TimeStamp& aTime) const override {
128 return true;
131 void NewFrame(already_AddRefed<Image> aImage,
132 const TimeStamp& aTime) override {
133 AUTO_PROFILER_MARKER_TEXT("Canvas CaptureStream", MEDIA_RT, {},
134 "AutoDriver taking frame"_ns);
136 RefPtr<Image> image = aImage;
137 SetImage(std::move(image), aTime);
140 protected:
141 virtual ~AutoDriver() = default;
144 // ----------------------------------------------------------------------
146 NS_IMPL_CYCLE_COLLECTION_INHERITED(CanvasCaptureMediaStream, DOMMediaStream,
147 mCanvas)
149 NS_IMPL_ADDREF_INHERITED(CanvasCaptureMediaStream, DOMMediaStream)
150 NS_IMPL_RELEASE_INHERITED(CanvasCaptureMediaStream, DOMMediaStream)
152 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CanvasCaptureMediaStream)
153 NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
155 CanvasCaptureMediaStream::CanvasCaptureMediaStream(nsPIDOMWindowInner* aWindow,
156 HTMLCanvasElement* aCanvas)
157 : DOMMediaStream(aWindow), mCanvas(aCanvas) {}
159 CanvasCaptureMediaStream::~CanvasCaptureMediaStream() = default;
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 nsIPrincipal* aPrincipal) {
174 MediaTrackGraph* graph = MediaTrackGraph::GetInstance(
175 MediaTrackGraph::SYSTEM_THREAD_DRIVER, GetOwner(),
176 MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE,
177 MediaTrackGraph::DEFAULT_OUTPUT_DEVICE);
178 SourceMediaTrack* source = graph->CreateSourceTrack(MediaSegment::VIDEO);
179 PrincipalHandle principalHandle = MakePrincipalHandle(aPrincipal);
180 if (!aFPS.WasPassed()) {
181 mOutputStreamDriver = new AutoDriver(source, 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 = new TimerDriver(source, fps, principalHandle);
189 return NS_OK;
192 FrameCaptureListener* CanvasCaptureMediaStream::FrameCaptureListener() {
193 return mOutputStreamDriver;
196 void CanvasCaptureMediaStream::StopCapture() {
197 if (!mOutputStreamDriver) {
198 return;
201 mOutputStreamDriver->EndTrack();
202 mOutputStreamDriver = nullptr;
205 SourceMediaTrack* CanvasCaptureMediaStream::GetSourceStream() const {
206 if (!mOutputStreamDriver) {
207 return nullptr;
209 return mOutputStreamDriver->mSourceStream;
212 } // namespace mozilla::dom