Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / dom / camera / CameraPreviewMediaStream.cpp
blob10fd63c292207492bcf9904956ce816f1b29b2d5
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 "CameraPreviewMediaStream.h"
7 #include "CameraCommon.h"
9 /**
10 * Maximum number of outstanding invalidates before we start to drop frames;
11 * if we hit this threshold, it is an indicator that the main thread is
12 * either very busy or the device is busy elsewhere (e.g. encoding or
13 * persisting video data).
15 #define MAX_INVALIDATE_PENDING 4
17 using namespace mozilla::layers;
18 using namespace mozilla::dom;
20 namespace mozilla {
22 static const TrackID TRACK_VIDEO = 2;
24 void
25 FakeMediaStreamGraph::DispatchToMainThreadAfterStreamStateUpdate(already_AddRefed<nsIRunnable> aRunnable)
27 nsRefPtr<nsIRunnable> task = aRunnable;
28 NS_DispatchToMainThread(task);
31 CameraPreviewMediaStream::CameraPreviewMediaStream(DOMMediaStream* aWrapper)
32 : MediaStream(aWrapper)
33 , mMutex("mozilla::camera::CameraPreviewMediaStream")
34 , mInvalidatePending(0)
35 , mDiscardedFrames(0)
36 , mRateLimit(false)
37 , mTrackCreated(false)
39 SetGraphImpl(MediaStreamGraph::GetInstance());
40 mFakeMediaStreamGraph = new FakeMediaStreamGraph();
41 mIsConsumed = false;
44 void
45 CameraPreviewMediaStream::AddAudioOutput(void* aKey)
49 void
50 CameraPreviewMediaStream::SetAudioOutputVolume(void* aKey, float aVolume)
54 void
55 CameraPreviewMediaStream::RemoveAudioOutput(void* aKey)
59 void
60 CameraPreviewMediaStream::AddVideoOutput(VideoFrameContainer* aContainer)
62 MutexAutoLock lock(mMutex);
63 nsRefPtr<VideoFrameContainer> container = aContainer;
64 AddVideoOutputImpl(container.forget());
66 if (mVideoOutputs.Length() > 1) {
67 return;
69 mIsConsumed = true;
70 for (uint32_t j = 0; j < mListeners.Length(); ++j) {
71 MediaStreamListener* l = mListeners[j];
72 l->NotifyConsumptionChanged(mFakeMediaStreamGraph, MediaStreamListener::CONSUMED);
76 void
77 CameraPreviewMediaStream::RemoveVideoOutput(VideoFrameContainer* aContainer)
79 MutexAutoLock lock(mMutex);
80 RemoveVideoOutputImpl(aContainer);
82 if (!mVideoOutputs.IsEmpty()) {
83 return;
85 mIsConsumed = false;
86 for (uint32_t j = 0; j < mListeners.Length(); ++j) {
87 MediaStreamListener* l = mListeners[j];
88 l->NotifyConsumptionChanged(mFakeMediaStreamGraph, MediaStreamListener::NOT_CONSUMED);
92 void
93 CameraPreviewMediaStream::ChangeExplicitBlockerCount(int32_t aDelta)
97 void
98 CameraPreviewMediaStream::AddListener(MediaStreamListener* aListener)
100 MutexAutoLock lock(mMutex);
102 MediaStreamListener* listener = *mListeners.AppendElement() = aListener;
103 listener->NotifyBlockingChanged(mFakeMediaStreamGraph, MediaStreamListener::UNBLOCKED);
104 listener->NotifyHasCurrentData(mFakeMediaStreamGraph);
107 void
108 CameraPreviewMediaStream::RemoveListener(MediaStreamListener* aListener)
110 MutexAutoLock lock(mMutex);
112 nsRefPtr<MediaStreamListener> listener(aListener);
113 mListeners.RemoveElement(aListener);
114 listener->NotifyEvent(mFakeMediaStreamGraph, MediaStreamListener::EVENT_REMOVED);
117 void
118 CameraPreviewMediaStream::OnPreviewStateChange(bool aActive)
120 if (aActive) {
121 MutexAutoLock lock(mMutex);
122 if (!mTrackCreated) {
123 mTrackCreated = true;
124 VideoSegment tmpSegment;
125 for (uint32_t j = 0; j < mListeners.Length(); ++j) {
126 MediaStreamListener* l = mListeners[j];
127 l->NotifyQueuedTrackChanges(mFakeMediaStreamGraph, TRACK_VIDEO, 0, 0,
128 MediaStreamListener::TRACK_EVENT_CREATED,
129 tmpSegment);
135 void
136 CameraPreviewMediaStream::Destroy()
138 MutexAutoLock lock(mMutex);
139 mMainThreadDestroyed = true;
140 DestroyImpl();
143 void
144 CameraPreviewMediaStream::Invalidate()
146 MutexAutoLock lock(mMutex);
147 --mInvalidatePending;
148 for (nsTArray<nsRefPtr<VideoFrameContainer> >::size_type i = 0; i < mVideoOutputs.Length(); ++i) {
149 VideoFrameContainer* output = mVideoOutputs[i];
150 output->Invalidate();
154 void
155 CameraPreviewMediaStream::RateLimit(bool aLimit)
157 mRateLimit = aLimit;
160 void
161 CameraPreviewMediaStream::SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Image* aImage)
164 MutexAutoLock lock(mMutex);
166 if (mInvalidatePending > 0) {
167 if (mRateLimit || mInvalidatePending > MAX_INVALIDATE_PENDING) {
168 ++mDiscardedFrames;
169 DOM_CAMERA_LOGW("Discard preview frame %d, %d invalidation(s) pending",
170 mDiscardedFrames, mInvalidatePending);
171 return;
174 DOM_CAMERA_LOGI("Update preview frame, %d invalidation(s) pending",
175 mInvalidatePending);
177 mDiscardedFrames = 0;
179 TimeStamp now = TimeStamp::Now();
180 for (nsTArray<nsRefPtr<VideoFrameContainer> >::size_type i = 0; i < mVideoOutputs.Length(); ++i) {
181 VideoFrameContainer* output = mVideoOutputs[i];
182 output->SetCurrentFrame(aIntrinsicSize, aImage, now);
185 ++mInvalidatePending;
188 nsCOMPtr<nsIRunnable> event =
189 NS_NewRunnableMethod(this, &CameraPreviewMediaStream::Invalidate);
190 NS_DispatchToMainThread(event);
193 void
194 CameraPreviewMediaStream::ClearCurrentFrame()
196 MutexAutoLock lock(mMutex);
198 for (nsTArray<nsRefPtr<VideoFrameContainer> >::size_type i = 0; i < mVideoOutputs.Length(); ++i) {
199 VideoFrameContainer* output = mVideoOutputs[i];
200 output->ClearCurrentFrame();
201 nsCOMPtr<nsIRunnable> event =
202 NS_NewRunnableMethod(output, &VideoFrameContainer::Invalidate);
203 NS_DispatchToMainThread(event);