Bug 1526591 - Remove devtools.inspector.shapesHighlighter.enabled pref. r=rcaliman
[gecko.git] / dom / media / imagecapture / CaptureTask.cpp
blob3f8a1d83040a7891e9a75e41ab7e83ae0d18d129
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "CaptureTask.h"
8 #include "mozilla/dom/ImageCapture.h"
9 #include "mozilla/dom/ImageCaptureError.h"
10 #include "mozilla/dom/ImageEncoder.h"
11 #include "mozilla/dom/MediaStreamTrack.h"
12 #include "mozilla/dom/VideoStreamTrack.h"
13 #include "gfxUtils.h"
14 #include "nsThreadUtils.h"
16 namespace mozilla {
18 class CaptureTask::MediaStreamEventListener : public MediaStreamTrackListener {
19 public:
20 explicit MediaStreamEventListener(CaptureTask* aCaptureTask)
21 : mCaptureTask(aCaptureTask){};
23 // MediaStreamTrackListener methods.
24 void NotifyEnded() override {
25 if (!mCaptureTask->mImageGrabbedOrTrackEnd) {
26 mCaptureTask->PostTrackEndEvent();
30 private:
31 CaptureTask* mCaptureTask;
34 CaptureTask::CaptureTask(dom::ImageCapture* aImageCapture)
35 : mImageCapture(aImageCapture),
36 mEventListener(new MediaStreamEventListener(this)),
37 mImageGrabbedOrTrackEnd(false),
38 mPrincipalChanged(false) {}
40 nsresult CaptureTask::TaskComplete(already_AddRefed<dom::Blob> aBlob,
41 nsresult aRv) {
42 MOZ_ASSERT(NS_IsMainThread());
44 DetachTrack();
46 nsresult rv;
47 RefPtr<dom::Blob> blob(aBlob);
49 // We have to set the parent because the blob has been generated with a valid
50 // one.
51 if (blob) {
52 blob = dom::Blob::Create(mImageCapture->GetParentObject(), blob->Impl());
55 if (mPrincipalChanged) {
56 aRv = NS_ERROR_DOM_SECURITY_ERR;
57 IC_LOG("MediaStream principal should not change during TakePhoto().");
60 if (NS_SUCCEEDED(aRv)) {
61 rv = mImageCapture->PostBlobEvent(blob);
62 } else {
63 rv =
64 mImageCapture->PostErrorEvent(dom::ImageCaptureError::PHOTO_ERROR, aRv);
67 // Ensure ImageCapture dereference on main thread here because the TakePhoto()
68 // sequences stopped here.
69 mImageCapture = nullptr;
71 return rv;
74 void CaptureTask::AttachTrack() {
75 MOZ_ASSERT(NS_IsMainThread());
77 dom::MediaStreamTrack* track = mImageCapture->GetVideoStreamTrack();
78 track->AddPrincipalChangeObserver(this);
79 track->AddListener(mEventListener.get());
80 track->AddDirectListener(this);
83 void CaptureTask::DetachTrack() {
84 MOZ_ASSERT(NS_IsMainThread());
86 dom::MediaStreamTrack* track = mImageCapture->GetVideoStreamTrack();
87 track->RemovePrincipalChangeObserver(this);
88 track->RemoveListener(mEventListener.get());
89 track->RemoveDirectListener(this);
92 void CaptureTask::PrincipalChanged(dom::MediaStreamTrack* aMediaStreamTrack) {
93 MOZ_ASSERT(NS_IsMainThread());
94 mPrincipalChanged = true;
97 void CaptureTask::SetCurrentFrames(const VideoSegment& aSegment) {
98 if (mImageGrabbedOrTrackEnd) {
99 return;
102 // Callback for encoding complete, it calls on main thread.
103 class EncodeComplete : public dom::EncodeCompleteCallback {
104 public:
105 explicit EncodeComplete(CaptureTask* aTask) : mTask(aTask) {}
107 nsresult ReceiveBlob(already_AddRefed<dom::Blob> aBlob) override {
108 RefPtr<dom::Blob> blob(aBlob);
109 mTask->TaskComplete(blob.forget(), NS_OK);
110 mTask = nullptr;
111 return NS_OK;
114 protected:
115 RefPtr<CaptureTask> mTask;
118 for (VideoSegment::ConstChunkIterator iter(aSegment); !iter.IsEnded();
119 iter.Next()) {
120 VideoChunk chunk = *iter;
122 // Extract the first valid video frame.
123 VideoFrame frame;
124 if (!chunk.IsNull()) {
125 RefPtr<layers::Image> image;
126 if (chunk.mFrame.GetForceBlack()) {
127 // Create a black image.
128 image = VideoFrame::CreateBlackImage(chunk.mFrame.GetIntrinsicSize());
129 } else {
130 image = chunk.mFrame.GetImage();
132 if (!image) {
133 MOZ_ASSERT(image);
134 continue;
136 mImageGrabbedOrTrackEnd = true;
138 // Encode image.
139 nsresult rv;
140 nsAutoString type(NS_LITERAL_STRING("image/jpeg"));
141 nsAutoString options;
142 rv = dom::ImageEncoder::ExtractDataFromLayersImageAsync(
143 type, options, false, image, false, new EncodeComplete(this));
144 if (NS_FAILED(rv)) {
145 PostTrackEndEvent();
147 return;
152 void CaptureTask::PostTrackEndEvent() {
153 mImageGrabbedOrTrackEnd = true;
155 // Got track end or finish event, stop the task.
156 class TrackEndRunnable : public Runnable {
157 public:
158 explicit TrackEndRunnable(CaptureTask* aTask)
159 : mozilla::Runnable("TrackEndRunnable"), mTask(aTask) {}
161 NS_IMETHOD Run() override {
162 mTask->TaskComplete(nullptr, NS_ERROR_FAILURE);
163 mTask = nullptr;
164 return NS_OK;
167 protected:
168 RefPtr<CaptureTask> mTask;
171 IC_LOG("Got MediaStream track removed or finished event.");
172 nsCOMPtr<nsIRunnable> event = new TrackEndRunnable(this);
173 SystemGroup::Dispatch(TaskCategory::Other, event.forget());
176 } // namespace mozilla