content/media/webrtc/MediaEngineTabVideoSource.cpp

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include "MediaEngineTabVideoSource.h"
michael@0 6
michael@0 7 #include "mozilla/gfx/2D.h"
michael@0 8 #include "mozilla/RefPtr.h"
michael@0 9 #include "nsGlobalWindow.h"
michael@0 10 #include "nsDOMWindowUtils.h"
michael@0 11 #include "nsIDOMClientRect.h"
michael@0 12 #include "nsIDocShell.h"
michael@0 13 #include "nsIPresShell.h"
michael@0 14 #include "nsPresContext.h"
michael@0 15 #include "gfxContext.h"
michael@0 16 #include "gfx2DGlue.h"
michael@0 17 #include "ImageContainer.h"
michael@0 18 #include "Layers.h"
michael@0 19 #include "nsIInterfaceRequestorUtils.h"
michael@0 20 #include "nsIDOMDocument.h"
michael@0 21 #include "nsITabSource.h"
michael@0 22 #include "VideoUtils.h"
michael@0 23 #include "nsServiceManagerUtils.h"
michael@0 24 #include "nsIPrefService.h"
michael@0 25
michael@0 26 namespace mozilla {
michael@0 27
michael@0 28 using namespace mozilla::gfx;
michael@0 29
michael@0 30 NS_IMPL_ISUPPORTS(MediaEngineTabVideoSource, nsIDOMEventListener, nsITimerCallback)
michael@0 31
michael@0 32 MediaEngineTabVideoSource::MediaEngineTabVideoSource()
michael@0 33 : mMonitor("MediaEngineTabVideoSource")
michael@0 34 {
michael@0 35 }
michael@0 36
michael@0 37 nsresult
michael@0 38 MediaEngineTabVideoSource::StartRunnable::Run()
michael@0 39 {
michael@0 40 mVideoSource->Draw();
michael@0 41 nsCOMPtr<nsPIDOMWindow> privateDOMWindow = do_QueryInterface(mVideoSource->mWindow);
michael@0 42 if (privateDOMWindow) {
michael@0 43 privateDOMWindow->GetChromeEventHandler()->AddEventListener(NS_LITERAL_STRING("MozAfterPaint"), mVideoSource, false);
michael@0 44 } else {
michael@0 45 mVideoSource->mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
michael@0 46 mVideoSource->mTimer->InitWithCallback(mVideoSource, mVideoSource->mTimePerFrame, nsITimer:: TYPE_REPEATING_SLACK);
michael@0 47 }
michael@0 48 mVideoSource->mTabSource->NotifyStreamStart(mVideoSource->mWindow);
michael@0 49 return NS_OK;
michael@0 50 }
michael@0 51
michael@0 52 nsresult
michael@0 53 MediaEngineTabVideoSource::StopRunnable::Run()
michael@0 54 {
michael@0 55 nsCOMPtr<nsPIDOMWindow> privateDOMWindow = do_QueryInterface(mVideoSource->mWindow);
michael@0 56 if (privateDOMWindow && mVideoSource && privateDOMWindow->GetChromeEventHandler()) {
michael@0 57 privateDOMWindow->GetChromeEventHandler()->RemoveEventListener(NS_LITERAL_STRING("MozAfterPaint"), mVideoSource, false);
michael@0 58 }
michael@0 59
michael@0 60 if (mVideoSource->mTimer) {
michael@0 61 mVideoSource->mTimer->Cancel();
michael@0 62 mVideoSource->mTimer = nullptr;
michael@0 63 }
michael@0 64 mVideoSource->mTabSource->NotifyStreamStop(mVideoSource->mWindow);
michael@0 65 return NS_OK;
michael@0 66 }
michael@0 67
michael@0 68 NS_IMETHODIMP
michael@0 69 MediaEngineTabVideoSource::HandleEvent(nsIDOMEvent *event) {
michael@0 70 Draw();
michael@0 71 return NS_OK;
michael@0 72 }
michael@0 73
michael@0 74 NS_IMETHODIMP
michael@0 75 MediaEngineTabVideoSource::Notify(nsITimer*) {
michael@0 76 Draw();
michael@0 77 return NS_OK;
michael@0 78 }
michael@0 79
michael@0 80 nsresult
michael@0 81 MediaEngineTabVideoSource::InitRunnable::Run()
michael@0 82 {
michael@0 83 nsresult rv;
michael@0 84 nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
michael@0 85 NS_ENSURE_SUCCESS(rv, rv);
michael@0 86 nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
michael@0 87 if (!branch)
michael@0 88 return NS_OK;
michael@0 89 branch->GetIntPref("media.tabstreaming.width", &mVideoSource->mBufW);
michael@0 90 branch->GetIntPref("media.tabstreaming.height", &mVideoSource->mBufH);
michael@0 91 branch->GetIntPref("media.tabstreaming.time_per_frame", &mVideoSource->mTimePerFrame);
michael@0 92 mVideoSource->mData = (unsigned char*)malloc(mVideoSource->mBufW * mVideoSource->mBufH * 4);
michael@0 93
michael@0 94 mVideoSource->mTabSource = do_GetService(NS_TABSOURCESERVICE_CONTRACTID, &rv);
michael@0 95 NS_ENSURE_SUCCESS(rv, rv);
michael@0 96
michael@0 97 nsCOMPtr<nsIDOMWindow> win;
michael@0 98 rv = mVideoSource->mTabSource->GetTabToStream(getter_AddRefs(win));
michael@0 99 NS_ENSURE_SUCCESS(rv, rv);
michael@0 100 if (!win)
michael@0 101 return NS_OK;
michael@0 102
michael@0 103 mVideoSource->mWindow = win;
michael@0 104 nsCOMPtr<nsIRunnable> start(new StartRunnable(mVideoSource));
michael@0 105 start->Run();
michael@0 106 return NS_OK;
michael@0 107 }
michael@0 108
michael@0 109 void
michael@0 110 MediaEngineTabVideoSource::GetName(nsAString_internal& aName)
michael@0 111 {
michael@0 112 aName.Assign(NS_LITERAL_STRING("&getUserMedia.videoDevice.tabShare;"));
michael@0 113 }
michael@0 114
michael@0 115 void
michael@0 116 MediaEngineTabVideoSource::GetUUID(nsAString_internal& aUuid)
michael@0 117 {
michael@0 118 aUuid.Assign(NS_LITERAL_STRING("uuid"));
michael@0 119 }
michael@0 120
michael@0 121 nsresult
michael@0 122 MediaEngineTabVideoSource::Allocate(const VideoTrackConstraintsN&,
michael@0 123 const MediaEnginePrefs&)
michael@0 124 {
michael@0 125 return NS_OK;
michael@0 126 }
michael@0 127
michael@0 128 nsresult
michael@0 129 MediaEngineTabVideoSource::Deallocate()
michael@0 130 {
michael@0 131 return NS_OK;
michael@0 132 }
michael@0 133
michael@0 134 nsresult
michael@0 135 MediaEngineTabVideoSource::Start(mozilla::SourceMediaStream* aStream, mozilla::TrackID aID)
michael@0 136 {
michael@0 137 nsCOMPtr<nsIRunnable> runnable;
michael@0 138 if (!mWindow)
michael@0 139 runnable = new InitRunnable(this);
michael@0 140 else
michael@0 141 runnable = new StartRunnable(this);
michael@0 142 NS_DispatchToMainThread(runnable);
michael@0 143 aStream->AddTrack(aID, USECS_PER_S, 0, new VideoSegment());
michael@0 144 aStream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
michael@0 145
michael@0 146 return NS_OK;
michael@0 147 }
michael@0 148
michael@0 149 nsresult
michael@0 150 MediaEngineTabVideoSource::Snapshot(uint32_t, nsIDOMFile**)
michael@0 151 {
michael@0 152 return NS_OK;
michael@0 153 }
michael@0 154
michael@0 155 void
michael@0 156 MediaEngineTabVideoSource::
michael@0 157 NotifyPull(MediaStreamGraph*, SourceMediaStream* aSource, mozilla::TrackID aID, mozilla::StreamTime aDesiredTime, mozilla::TrackTicks& aLastEndTime)
michael@0 158 {
michael@0 159 VideoSegment segment;
michael@0 160 MonitorAutoLock mon(mMonitor);
michael@0 161
michael@0 162 // Note: we're not giving up mImage here
michael@0 163 nsRefPtr<layers::CairoImage> image = mImage;
michael@0 164 TrackTicks target = TimeToTicksRoundUp(USECS_PER_S, aDesiredTime);
michael@0 165 TrackTicks delta = target - aLastEndTime;
michael@0 166 if (delta > 0) {
michael@0 167 // nullptr images are allowed
michael@0 168 gfx::IntSize size = image ? image->GetSize() : IntSize(0, 0);
michael@0 169 segment.AppendFrame(image.forget().downcast<layers::Image>(), delta, size);
michael@0 170 // This can fail if either a) we haven't added the track yet, or b)
michael@0 171 // we've removed or finished the track.
michael@0 172 if (aSource->AppendToTrack(aID, &(segment))) {
michael@0 173 aLastEndTime = target;
michael@0 174 }
michael@0 175 }
michael@0 176 }
michael@0 177
michael@0 178 void
michael@0 179 MediaEngineTabVideoSource::Draw() {
michael@0 180
michael@0 181 IntSize size(mBufW, mBufH);
michael@0 182
michael@0 183 nsresult rv;
michael@0 184 float scale = 1.0;
michael@0 185
michael@0 186 nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mWindow);
michael@0 187
michael@0 188 if (!win) {
michael@0 189 return;
michael@0 190 }
michael@0 191
michael@0 192 // take a screenshot, as wide as possible, proportional to the destination size
michael@0 193 nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(win);
michael@0 194 if (!utils) {
michael@0 195 return;
michael@0 196 }
michael@0 197
michael@0 198 nsCOMPtr<nsIDOMClientRect> rect;
michael@0 199 rv = utils->GetRootBounds(getter_AddRefs(rect));
michael@0 200 NS_ENSURE_SUCCESS_VOID(rv);
michael@0 201 if (!rect) {
michael@0 202 return;
michael@0 203 }
michael@0 204
michael@0 205 float left, top, width, height;
michael@0 206 rect->GetLeft(&left);
michael@0 207 rect->GetTop(&top);
michael@0 208 rect->GetWidth(&width);
michael@0 209 rect->GetHeight(&height);
michael@0 210
michael@0 211 if (width == 0 || height == 0) {
michael@0 212 return;
michael@0 213 }
michael@0 214
michael@0 215 int32_t srcX = left;
michael@0 216 int32_t srcY = top;
michael@0 217 int32_t srcW;
michael@0 218 int32_t srcH;
michael@0 219
michael@0 220 float aspectRatio = ((float) size.width) / size.height;
michael@0 221 if (width / aspectRatio < height) {
michael@0 222 srcW = width;
michael@0 223 srcH = width / aspectRatio;
michael@0 224 } else {
michael@0 225 srcW = height * aspectRatio;
michael@0 226 srcH = height;
michael@0 227 }
michael@0 228
michael@0 229 nsRefPtr<nsPresContext> presContext;
michael@0 230 nsIDocShell* docshell = win->GetDocShell();
michael@0 231 if (docshell) {
michael@0 232 docshell->GetPresContext(getter_AddRefs(presContext));
michael@0 233 }
michael@0 234 if (!presContext) {
michael@0 235 return;
michael@0 236 }
michael@0 237 nscolor bgColor = NS_RGB(255, 255, 255);
michael@0 238 nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
michael@0 239 uint32_t renderDocFlags = (nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING |
michael@0 240 nsIPresShell::RENDER_DOCUMENT_RELATIVE);
michael@0 241 nsRect r(nsPresContext::CSSPixelsToAppUnits(srcX / scale),
michael@0 242 nsPresContext::CSSPixelsToAppUnits(srcY / scale),
michael@0 243 nsPresContext::CSSPixelsToAppUnits(srcW / scale),
michael@0 244 nsPresContext::CSSPixelsToAppUnits(srcH / scale));
michael@0 245
michael@0 246 gfxImageFormat format = gfxImageFormat::RGB24;
michael@0 247 uint32_t stride = gfxASurface::FormatStrideForWidth(format, size.width);
michael@0 248
michael@0 249 nsRefPtr<layers::ImageContainer> container = layers::LayerManager::CreateImageContainer();
michael@0 250 RefPtr<DrawTarget> dt =
michael@0 251 Factory::CreateDrawTargetForData(BackendType::CAIRO,
michael@0 252 mData.rwget(),
michael@0 253 size,
michael@0 254 stride,
michael@0 255 SurfaceFormat::B8G8R8X8);
michael@0 256 if (!dt) {
michael@0 257 return;
michael@0 258 }
michael@0 259 nsRefPtr<gfxContext> context = new gfxContext(dt);
michael@0 260 gfxPoint pt(0, 0);
michael@0 261 context->Translate(pt);
michael@0 262 context->Scale(scale * size.width / srcW, scale * size.height / srcH);
michael@0 263 rv = presShell->RenderDocument(r, renderDocFlags, bgColor, context);
michael@0 264
michael@0 265 NS_ENSURE_SUCCESS_VOID(rv);
michael@0 266
michael@0 267 RefPtr<SourceSurface> surface = dt->Snapshot();
michael@0 268 if (!surface) {
michael@0 269 return;
michael@0 270 }
michael@0 271
michael@0 272 layers::CairoImage::Data cairoData;
michael@0 273 cairoData.mSize = size;
michael@0 274 cairoData.mSourceSurface = surface;
michael@0 275
michael@0 276 nsRefPtr<layers::CairoImage> image = new layers::CairoImage();
michael@0 277
michael@0 278 image->SetData(cairoData);
michael@0 279
michael@0 280 MonitorAutoLock mon(mMonitor);
michael@0 281 mImage = image;
michael@0 282 }
michael@0 283
michael@0 284 nsresult
michael@0 285 MediaEngineTabVideoSource::Stop(mozilla::SourceMediaStream*, mozilla::TrackID)
michael@0 286 {
michael@0 287 NS_DispatchToMainThread(new StopRunnable(this));
michael@0 288 return NS_OK;
michael@0 289 }
michael@0 290
michael@0 291 nsresult
michael@0 292 MediaEngineTabVideoSource::Config(bool, uint32_t, bool, uint32_t, bool, uint32_t, int32_t)
michael@0 293 {
michael@0 294 return NS_OK;
michael@0 295 }
michael@0 296
michael@0 297 bool
michael@0 298 MediaEngineTabVideoSource::IsFake()
michael@0 299 {
michael@0 300 return false;
michael@0 301 }
michael@0 302
michael@0 303 }

mercurial