Backed out 35 changesets (bug 941158, bug 972518, bug 959520, bug 986063, bug 948895...
[gecko.git] / content / media / webrtc / MediaEngineTabVideoSource.cpp
bloba73cf2c9ed9020b6202ff3be58727f594517d61e
1 #include "nsGlobalWindow.h"
2 #include "nsDOMWindowUtils.h"
3 #include "nsIDOMClientRect.h"
4 #include "nsIDocShell.h"
5 #include "nsIPresShell.h"
6 #include "nsPresContext.h"
7 #include "gfxImageSurface.h"
8 #include "gfxContext.h"
9 #include "ImageContainer.h"
10 #include "Layers.h"
11 #include "nsIInterfaceRequestorUtils.h"
12 #include "nsIDOMDocument.h"
13 #include "nsITabSource.h"
14 #include "MediaEngineTabVideoSource.h"
15 #include "VideoUtils.h"
16 #include "nsServiceManagerUtils.h"
17 #include "nsIPrefService.h"
18 namespace mozilla {
20 NS_IMPL_ISUPPORTS1(MediaEngineTabVideoSource, MediaEngineVideoSource)
22 MediaEngineTabVideoSource::MediaEngineTabVideoSource()
23 : mName(NS_LITERAL_STRING("share tab")), mUuid(NS_LITERAL_STRING("uuid")),
24 mMonitor("MediaEngineTabVideoSource")
28 nsresult
29 MediaEngineTabVideoSource::StartRunnable::Run()
31 mVideoSource->Draw();
32 nsCOMPtr<nsPIDOMWindow> privateDOMWindow = do_QueryInterface(mVideoSource->mWindow);
33 if (privateDOMWindow) {
34 privateDOMWindow->GetChromeEventHandler()->AddEventListener(NS_LITERAL_STRING("MozAfterPaint"), mVideoSource, false);
35 } else {
36 mVideoSource->mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
37 mVideoSource->mTimer->InitWithCallback(mVideoSource, mVideoSource->mTimePerFrame, nsITimer:: TYPE_REPEATING_SLACK);
39 return NS_OK;
42 nsresult
43 MediaEngineTabVideoSource::StopRunnable::Run()
45 nsCOMPtr<nsPIDOMWindow> privateDOMWindow = do_QueryInterface(mVideoSource->mWindow);
46 if (privateDOMWindow && mVideoSource && privateDOMWindow->GetChromeEventHandler()) {
47 privateDOMWindow->GetChromeEventHandler()->RemoveEventListener(NS_LITERAL_STRING("MozAfterPaint"), mVideoSource, false);
50 if (mVideoSource->mTimer) {
51 mVideoSource->mTimer->Cancel();
52 mVideoSource->mTimer = nullptr;
54 return NS_OK;
57 NS_IMETHODIMP
58 MediaEngineTabVideoSource::HandleEvent(nsIDOMEvent *event) {
59 Draw();
60 return NS_OK;
63 NS_IMETHODIMP
64 MediaEngineTabVideoSource::Notify(nsITimer*) {
65 Draw();
66 return NS_OK;
69 nsresult
70 MediaEngineTabVideoSource::InitRunnable::Run()
72 nsresult rv;
73 nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
74 NS_ENSURE_SUCCESS(rv, rv);
75 nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
76 if (!branch)
77 return NS_OK;
78 branch->GetIntPref("media.tabstreaming.width", &mVideoSource->mBufW);
79 branch->GetIntPref("media.tabstreaming.height", &mVideoSource->mBufH);
80 branch->GetIntPref("media.tabstreaming.time_per_frame", &mVideoSource->mTimePerFrame);
81 mVideoSource->mData = (unsigned char*)malloc(mVideoSource->mBufW * mVideoSource->mBufH * 4);
83 nsCOMPtr<nsITabSource> tabSource = do_GetService(NS_TABSOURCESERVICE_CONTRACTID, &rv);
84 NS_ENSURE_SUCCESS(rv, rv);
85 nsCOMPtr<nsIDOMWindow> win;
86 rv = tabSource->GetTabToStream(getter_AddRefs(win));
87 NS_ENSURE_SUCCESS(rv, rv);
88 if (!win)
89 return NS_OK;
91 mVideoSource->mWindow = win;
92 nsCOMPtr<nsIRunnable> start(new StartRunnable(mVideoSource));
93 start->Run();
94 return NS_OK;
97 void
98 MediaEngineTabVideoSource::GetName(nsAString_internal& aName)
100 aName.Assign(mName);
104 void
105 MediaEngineTabVideoSource::GetUUID(nsAString_internal& aUuid)
107 aUuid.Assign(mUuid);
110 nsresult
111 MediaEngineTabVideoSource::Allocate(const mozilla::MediaEnginePrefs&)
113 return NS_OK;
116 nsresult
117 MediaEngineTabVideoSource::Deallocate()
119 return NS_OK;
122 nsresult
123 MediaEngineTabVideoSource::Start(mozilla::SourceMediaStream* aStream, mozilla::TrackID aID)
125 nsCOMPtr<nsIRunnable> runnable;
126 if (!mWindow)
127 runnable = new InitRunnable(this);
128 else
129 runnable = new StartRunnable(this);
130 NS_DispatchToMainThread(runnable);
131 aStream->AddTrack(aID, USECS_PER_S, 0, new VideoSegment());
132 aStream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
134 return NS_OK;
137 nsresult
138 MediaEngineTabVideoSource::Snapshot(uint32_t, nsIDOMFile**)
140 return NS_OK;
143 void
144 MediaEngineTabVideoSource::
145 NotifyPull(MediaStreamGraph*, SourceMediaStream* aSource, mozilla::TrackID aID, mozilla::StreamTime aDesiredTime, mozilla::TrackTicks& aLastEndTime)
147 VideoSegment segment;
148 MonitorAutoLock mon(mMonitor);
150 // Note: we're not giving up mImage here
151 nsRefPtr<layers::CairoImage> image = mImage;
152 TrackTicks target = TimeToTicksRoundUp(USECS_PER_S, aDesiredTime);
153 TrackTicks delta = target - aLastEndTime;
154 if (delta > 0) {
155 // nullptr images are allowed
156 if (image) {
157 gfxIntSize size = image->GetSize();
158 segment.AppendFrame(image.forget(), delta, size);
159 } else {
160 segment.AppendFrame(nullptr, delta, gfxIntSize(0,0));
162 // This can fail if either a) we haven't added the track yet, or b)
163 // we've removed or finished the track.
164 if (aSource->AppendToTrack(aID, &(segment))) {
165 aLastEndTime = target;
170 void
171 MediaEngineTabVideoSource::Draw() {
173 nsIntSize size(mBufW, mBufH);
175 nsresult rv;
176 float scale = 1.0;
178 nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mWindow);
180 if (!win) {
181 return;
184 // take a screenshot, as wide as possible, proportional to the destination size
185 nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(win);
186 if (!utils) {
187 return;
190 nsCOMPtr<nsIDOMClientRect> rect;
191 rv = utils->GetRootBounds(getter_AddRefs(rect));
192 NS_ENSURE_SUCCESS_VOID(rv);
193 if (!rect) {
194 return;
197 float left, top, width, height;
198 rect->GetLeft(&left);
199 rect->GetTop(&top);
200 rect->GetWidth(&width);
201 rect->GetHeight(&height);
203 if (width == 0 || height == 0) {
204 return;
207 int32_t srcX = left;
208 int32_t srcY = top;
209 int32_t srcW;
210 int32_t srcH;
212 float aspectRatio = ((float) size.width) / size.height;
213 if (width / aspectRatio < height) {
214 srcW = width;
215 srcH = width / aspectRatio;
216 } else {
217 srcW = height * aspectRatio;
218 srcH = height;
221 nsRefPtr<nsPresContext> presContext;
222 nsIDocShell* docshell = win->GetDocShell();
223 if (docshell) {
224 docshell->GetPresContext(getter_AddRefs(presContext));
226 if (!presContext) {
227 return;
229 nscolor bgColor = NS_RGB(255, 255, 255);
230 nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
231 uint32_t renderDocFlags = (nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING |
232 nsIPresShell::RENDER_DOCUMENT_RELATIVE);
233 nsRect r(nsPresContext::CSSPixelsToAppUnits(srcX / scale),
234 nsPresContext::CSSPixelsToAppUnits(srcY / scale),
235 nsPresContext::CSSPixelsToAppUnits(srcW / scale),
236 nsPresContext::CSSPixelsToAppUnits(srcH / scale));
238 gfxImageFormat format = gfxImageFormatRGB24;
239 uint32_t stride = gfxASurface::FormatStrideForWidth(format, size.width);
241 nsRefPtr<layers::ImageContainer> container = layers::LayerManager::CreateImageContainer();
242 nsRefPtr<gfxASurface> surf;
243 surf = new gfxImageSurface(static_cast<unsigned char*>(mData), size,
244 stride, format);
245 if (surf->CairoStatus() != 0) {
246 return;
248 nsRefPtr<gfxContext> context = new gfxContext(surf);
249 gfxPoint pt(0, 0);
250 context->Translate(pt);
251 context->Scale(scale * size.width / srcW, scale * size.height / srcH);
252 rv = presShell->RenderDocument(r, renderDocFlags, bgColor, context);
254 NS_ENSURE_SUCCESS_VOID(rv);
256 layers::CairoImage::Data cairoData;
257 cairoData.mSurface = surf;
258 cairoData.mSize = size;
260 nsRefPtr<layers::CairoImage> image = new layers::CairoImage();
262 image->SetData(cairoData);
264 MonitorAutoLock mon(mMonitor);
265 mImage = image;
268 nsresult
269 MediaEngineTabVideoSource::Stop(mozilla::SourceMediaStream*, mozilla::TrackID)
271 NS_DispatchToMainThread(new StopRunnable(this));
272 return NS_OK;
275 nsresult
276 MediaEngineTabVideoSource::Config(bool, uint32_t, bool, uint32_t, bool, uint32_t)
278 return NS_OK;
281 bool
282 MediaEngineTabVideoSource::IsFake()
284 return false;