| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  | /* This Source Code Form is subject to the terms of the Mozilla Public
 | 
					
						
							|  |  |  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | 
					
						
							|  |  |  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "nsScreencastService.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "ScreencastEncoder.h"
 | 
					
						
							| 
									
										
										
										
											2020-07-14 11:20:36 -07:00
										 |  |  | #include "HeadlessWidget.h"
 | 
					
						
							|  |  |  | #include "HeadlessWindowCapturer.h"
 | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  | #include "mozilla/Base64.h"
 | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  | #include "mozilla/ClearOnShutdown.h"
 | 
					
						
							|  |  |  | #include "mozilla/PresShell.h"
 | 
					
						
							|  |  |  | #include "mozilla/StaticPtr.h"
 | 
					
						
							|  |  |  | #include "nsIDocShell.h"
 | 
					
						
							| 
									
										
										
										
											2020-07-17 17:34:09 -07:00
										 |  |  | #include "nsIObserverService.h"
 | 
					
						
							| 
									
										
										
										
											2020-10-14 16:14:24 -07:00
										 |  |  | #include "nsIRandomGenerator.h"
 | 
					
						
							| 
									
										
										
										
											2020-07-17 17:34:09 -07:00
										 |  |  | #include "nsISupportsPrimitives.h"
 | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  | #include "nsThreadManager.h"
 | 
					
						
							|  |  |  | #include "nsView.h"
 | 
					
						
							|  |  |  | #include "nsViewManager.h"
 | 
					
						
							| 
									
										
										
										
											2022-01-18 04:16:04 -07:00
										 |  |  | #include "modules/desktop_capture/desktop_capturer.h"
 | 
					
						
							|  |  |  | #include "modules/desktop_capture/desktop_capture_options.h"
 | 
					
						
							|  |  |  | #include "modules/desktop_capture/desktop_frame.h"
 | 
					
						
							|  |  |  | #include "modules/video_capture/video_capture.h"
 | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  | #include "mozilla/widget/PlatformWidgetTypes.h"
 | 
					
						
							|  |  |  | #include "video_engine/desktop_capture_impl.h"
 | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  | extern "C" { | 
					
						
							|  |  |  | #include "jpeglib.h"
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-05-10 22:01:41 -07:00
										 |  |  | #include <libyuv.h>
 | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-14 11:20:36 -07:00
										 |  |  | using namespace mozilla::widget; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  | namespace mozilla { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NS_IMPL_ISUPPORTS(nsScreencastService, nsIScreencastService) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  | const int kMaxFramesInFlight = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  | StaticRefPtr<nsScreencastService> gScreencastService; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  | rtc::scoped_refptr<webrtc::VideoCaptureModuleEx> CreateWindowCapturer(nsIWidget* widget) { | 
					
						
							| 
									
										
										
										
											2020-07-14 11:20:36 -07:00
										 |  |  |   if (gfxPlatform::IsHeadless()) { | 
					
						
							|  |  |  |     HeadlessWidget* headlessWidget = static_cast<HeadlessWidget*>(widget); | 
					
						
							|  |  |  |     return HeadlessWindowCapturer::Create(headlessWidget); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-07-16 15:34:33 -07:00
										 |  |  |   uintptr_t rawWindowId = reinterpret_cast<uintptr_t>(widget->GetNativeData(NS_NATIVE_WINDOW_WEBRTC_DEVICE_ID)); | 
					
						
							|  |  |  |   if (!rawWindowId) { | 
					
						
							|  |  |  |     fprintf(stderr, "Failed to get native window id\n"); | 
					
						
							|  |  |  |     return nullptr; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-07-15 16:58:58 -07:00
										 |  |  |   nsCString windowId; | 
					
						
							| 
									
										
										
										
											2020-07-16 15:34:33 -07:00
										 |  |  |   windowId.AppendPrintf("%" PRIuPTR, rawWindowId); | 
					
						
							| 
									
										
										
										
											2020-07-27 16:22:02 -07:00
										 |  |  |   bool captureCursor = false; | 
					
						
							| 
									
										
										
										
											2020-10-14 16:14:24 -07:00
										 |  |  |   static int moduleId = 0; | 
					
						
							|  |  |  |   return webrtc::DesktopCaptureImpl::Create(++moduleId, windowId.get(), webrtc::CaptureDeviceType::Window, captureCursor); | 
					
						
							| 
									
										
										
										
											2020-07-14 11:20:36 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-07-17 17:34:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-14 16:14:24 -07:00
										 |  |  | nsresult generateUid(nsString& uid) { | 
					
						
							|  |  |  |   nsresult rv = NS_OK; | 
					
						
							|  |  |  |   nsCOMPtr<nsIRandomGenerator> rg = do_GetService("@mozilla.org/security/random-generator;1", &rv); | 
					
						
							|  |  |  |   NS_ENSURE_SUCCESS(rv, rv); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uint8_t* buffer; | 
					
						
							|  |  |  |   const int kLen = 16; | 
					
						
							|  |  |  |   rv = rg->GenerateRandomBytes(kLen, &buffer); | 
					
						
							|  |  |  |   NS_ENSURE_SUCCESS(rv, rv); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int i = 0; i < kLen; i++) { | 
					
						
							| 
									
										
										
										
											2020-11-06 15:08:03 -08:00
										 |  |  |     uid.AppendPrintf("%02x", buffer[i]); | 
					
						
							| 
									
										
										
										
											2020-10-14 16:14:24 -07:00
										 |  |  |   } | 
					
						
							|  |  |  |   free(buffer); | 
					
						
							|  |  |  |   return rv; | 
					
						
							| 
									
										
										
										
											2020-07-17 17:34:09 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  | class nsScreencastService::Session : public rtc::VideoSinkInterface<webrtc::VideoFrame>, | 
					
						
							|  |  |  |                                      public webrtc::RawFrameCallback { | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  |  public: | 
					
						
							| 
									
										
										
										
											2021-05-10 22:01:41 -07:00
										 |  |  |   Session( | 
					
						
							|  |  |  |     nsIScreencastServiceClient* client, | 
					
						
							|  |  |  |     rtc::scoped_refptr<webrtc::VideoCaptureModuleEx>&& capturer, | 
					
						
							|  |  |  |     RefPtr<ScreencastEncoder>&& encoder, | 
					
						
							|  |  |  |     int width, int height, | 
					
						
							|  |  |  |     int viewportWidth, int viewportHeight, | 
					
						
							|  |  |  |     gfx::IntMargin margin, | 
					
						
							|  |  |  |     uint32_t jpegQuality) | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |       : mClient(client) | 
					
						
							|  |  |  |       , mCaptureModule(std::move(capturer)) | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |       , mEncoder(std::move(encoder)) | 
					
						
							|  |  |  |       , mJpegQuality(jpegQuality) | 
					
						
							| 
									
										
										
										
											2021-05-10 22:01:41 -07:00
										 |  |  |       , mWidth(width) | 
					
						
							|  |  |  |       , mHeight(height) | 
					
						
							|  |  |  |       , mViewportWidth(viewportWidth) | 
					
						
							|  |  |  |       , mViewportHeight(viewportHeight) | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |       , mMargin(margin) { | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool Start() { | 
					
						
							|  |  |  |     webrtc::VideoCaptureCapability capability; | 
					
						
							|  |  |  |     // The size is ignored in fact.
 | 
					
						
							|  |  |  |     capability.width = 1280; | 
					
						
							|  |  |  |     capability.height = 960; | 
					
						
							| 
									
										
										
										
											2020-10-20 13:39:56 -07:00
										 |  |  |     capability.maxFPS = ScreencastEncoder::fps; | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  |     capability.videoType = webrtc::VideoType::kI420; | 
					
						
							|  |  |  |     int error = mCaptureModule->StartCapture(capability); | 
					
						
							|  |  |  |     if (error) { | 
					
						
							|  |  |  |       fprintf(stderr, "StartCapture error %d\n", error); | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     if (mEncoder) | 
					
						
							|  |  |  |       mCaptureModule->RegisterCaptureDataCallback(this); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       mCaptureModule->RegisterRawFrameCallback(this); | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |   void Stop() { | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     if (mEncoder) | 
					
						
							|  |  |  |       mCaptureModule->DeRegisterCaptureDataCallback(this); | 
					
						
							|  |  |  |     else | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |       mCaptureModule->DeRegisterRawFrameCallback(this); | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  |     int error = mCaptureModule->StopCapture(); | 
					
						
							|  |  |  |     if (error) { | 
					
						
							|  |  |  |       fprintf(stderr, "StopCapture error %d\n", error); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |     if (mEncoder) { | 
					
						
							|  |  |  |       rtc::CritScope lock(&mCaptureCallbackCs); | 
					
						
							|  |  |  |       mEncoder->finish([client = std::move(mClient)] { | 
					
						
							|  |  |  |         NS_DispatchToMainThread(NS_NewRunnableFunction( | 
					
						
							|  |  |  |             "NotifyScreencastStopped", [client = std::move(client)]() -> void { | 
					
						
							|  |  |  |               client->ScreencastStopped(); | 
					
						
							|  |  |  |             })); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       rtc::CritScope lock(&mCaptureCallbackCs); | 
					
						
							|  |  |  |       mClient->ScreencastStopped(); | 
					
						
							|  |  |  |       mClient = nullptr; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void ScreencastFrameAck() { | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |     rtc::CritScope lock(&mCaptureCallbackCs); | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     --mFramesInFlight; | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // These callbacks end up running on the VideoCapture thread.
 | 
					
						
							|  |  |  |   void OnFrame(const webrtc::VideoFrame& videoFrame) override { | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     if (!mEncoder) | 
					
						
							|  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  |     mEncoder->encodeFrame(videoFrame); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |   // These callbacks end up running on the VideoCapture thread.
 | 
					
						
							|  |  |  |   void OnRawFrame(uint8_t* videoFrame, size_t videoFrameStride, const webrtc::VideoCaptureCapability& frameInfo) override { | 
					
						
							| 
									
										
										
										
											2021-05-10 22:01:41 -07:00
										 |  |  |     int pageWidth = frameInfo.width - mMargin.LeftRight(); | 
					
						
							|  |  |  |     int pageHeight = frameInfo.height - mMargin.TopBottom(); | 
					
						
							| 
									
										
										
										
											2021-11-01 17:11:21 -07:00
										 |  |  |     // Frame size is 1x1 when browser window is minimized.
 | 
					
						
							|  |  |  |     if (pageWidth <= 1 || pageHeight <= 1) | 
					
						
							|  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2021-05-10 22:01:41 -07:00
										 |  |  |     // Headed Firefox brings sizes in sync slowly.
 | 
					
						
							|  |  |  |     if (mViewportWidth && pageWidth > mViewportWidth) | 
					
						
							|  |  |  |       pageWidth = mViewportWidth; | 
					
						
							|  |  |  |     if (mViewportHeight && pageHeight > mViewportHeight) | 
					
						
							|  |  |  |       pageHeight = mViewportHeight; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |       rtc::CritScope lock(&mCaptureCallbackCs); | 
					
						
							|  |  |  |       if (mFramesInFlight >= kMaxFramesInFlight) { | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |       ++mFramesInFlight; | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |       if (!mClient) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-10 22:01:41 -07:00
										 |  |  |     int screenshotWidth = pageWidth; | 
					
						
							|  |  |  |     int screenshotHeight = pageHeight; | 
					
						
							|  |  |  |     int screenshotTopMargin = mMargin.TopBottom(); | 
					
						
							|  |  |  |     std::unique_ptr<uint8_t[]> canvas; | 
					
						
							|  |  |  |     uint8_t* canvasPtr = videoFrame; | 
					
						
							|  |  |  |     int canvasStride = videoFrameStride; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mWidth < pageWidth || mHeight < pageHeight) { | 
					
						
							|  |  |  |       double scale = std::min(1., std::min((double)mWidth / pageWidth, (double)mHeight / pageHeight)); | 
					
						
							|  |  |  |       int canvasWidth = frameInfo.width * scale; | 
					
						
							|  |  |  |       int canvasHeight = frameInfo.height * scale; | 
					
						
							|  |  |  |       canvasStride = canvasWidth * 4; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       screenshotWidth *= scale; | 
					
						
							|  |  |  |       screenshotHeight *= scale; | 
					
						
							|  |  |  |       screenshotTopMargin *= scale; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       canvas.reset(new uint8_t[canvasWidth * canvasHeight * 4]); | 
					
						
							|  |  |  |       canvasPtr = canvas.get(); | 
					
						
							|  |  |  |       libyuv::ARGBScale(videoFrame, | 
					
						
							|  |  |  |                         videoFrameStride, | 
					
						
							|  |  |  |                         frameInfo.width, | 
					
						
							|  |  |  |                         frameInfo.height, | 
					
						
							|  |  |  |                         canvasPtr, | 
					
						
							|  |  |  |                         canvasStride, | 
					
						
							|  |  |  |                         canvasWidth, | 
					
						
							|  |  |  |                         canvasHeight, | 
					
						
							|  |  |  |                         libyuv::kFilterBilinear); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     jpeg_compress_struct info; | 
					
						
							|  |  |  |     jpeg_error_mgr error; | 
					
						
							|  |  |  |     info.err = jpeg_std_error(&error); | 
					
						
							|  |  |  |     jpeg_create_compress(&info); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     unsigned char* bufferPtr = nullptr; | 
					
						
							|  |  |  |     unsigned long bufferSize; | 
					
						
							|  |  |  |     jpeg_mem_dest(&info, &bufferPtr, &bufferSize); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-10 22:01:41 -07:00
										 |  |  |     info.image_width = screenshotWidth; | 
					
						
							|  |  |  |     info.image_height = screenshotHeight; | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if MOZ_LITTLE_ENDIAN()
 | 
					
						
							|  |  |  |     if (frameInfo.videoType == webrtc::VideoType::kARGB) | 
					
						
							|  |  |  |       info.in_color_space = JCS_EXT_BGRA; | 
					
						
							|  |  |  |     if (frameInfo.videoType == webrtc::VideoType::kBGRA) | 
					
						
							|  |  |  |       info.in_color_space = JCS_EXT_ARGB; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     if (frameInfo.videoType == webrtc::VideoType::kARGB) | 
					
						
							|  |  |  |       info.in_color_space = JCS_EXT_ARGB; | 
					
						
							|  |  |  |     if (frameInfo.videoType == webrtc::VideoType::kBGRA) | 
					
						
							|  |  |  |       info.in_color_space = JCS_EXT_BGRA; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // # of color components in input image
 | 
					
						
							|  |  |  |     info.input_components = 4; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     jpeg_set_defaults(&info); | 
					
						
							|  |  |  |     jpeg_set_quality(&info, mJpegQuality, true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     jpeg_start_compress(&info, true); | 
					
						
							|  |  |  |     while (info.next_scanline < info.image_height) { | 
					
						
							| 
									
										
										
										
											2021-05-10 22:01:41 -07:00
										 |  |  |       JSAMPROW row = canvasPtr + (screenshotTopMargin + info.next_scanline) * canvasStride; | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |       if (jpeg_write_scanlines(&info, &row, 1) != 1) { | 
					
						
							|  |  |  |         fprintf(stderr, "JPEG library failed to encode line\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     jpeg_finish_compress(&info); | 
					
						
							|  |  |  |     jpeg_destroy_compress(&info); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     nsCString base64; | 
					
						
							|  |  |  |     nsresult rv = mozilla::Base64Encode(reinterpret_cast<char *>(bufferPtr), bufferSize, base64); | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |     free(bufferPtr); | 
					
						
							|  |  |  |     if (NS_WARN_IF(NS_FAILED(rv))) { | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |       return; | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |     nsIScreencastServiceClient* client = mClient.get(); | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     NS_DispatchToMainThread(NS_NewRunnableFunction( | 
					
						
							| 
									
										
										
										
											2021-05-10 22:01:41 -07:00
										 |  |  |         "NotifyScreencastFrame", [client, base64, pageWidth, pageHeight]() -> void { | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |           NS_ConvertUTF8toUTF16 utf16(base64); | 
					
						
							| 
									
										
										
										
											2021-05-10 22:01:41 -07:00
										 |  |  |           client->ScreencastFrame(utf16, pageWidth, pageHeight); | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |         })); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  |  private: | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |   RefPtr<nsIScreencastServiceClient> mClient; | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |   rtc::scoped_refptr<webrtc::VideoCaptureModuleEx> mCaptureModule; | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  |   RefPtr<ScreencastEncoder> mEncoder; | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |   uint32_t mJpegQuality; | 
					
						
							| 
									
										
										
										
											2022-01-18 04:16:04 -07:00
										 |  |  |   rtc::RecursiveCriticalSection mCaptureCallbackCs; | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |   uint32_t mFramesInFlight = 0; | 
					
						
							| 
									
										
										
										
											2021-05-10 22:01:41 -07:00
										 |  |  |   int mWidth; | 
					
						
							|  |  |  |   int mHeight; | 
					
						
							|  |  |  |   int mViewportWidth; | 
					
						
							|  |  |  |   int mViewportHeight; | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |   gfx::IntMargin mMargin; | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // static
 | 
					
						
							|  |  |  | already_AddRefed<nsIScreencastService> nsScreencastService::GetSingleton() { | 
					
						
							|  |  |  |   if (gScreencastService) { | 
					
						
							|  |  |  |     return do_AddRef(gScreencastService); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   gScreencastService = new nsScreencastService(); | 
					
						
							|  |  |  |   // ClearOnShutdown(&gScreencastService);
 | 
					
						
							|  |  |  |   return do_AddRef(gScreencastService); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | nsScreencastService::nsScreencastService() = default; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | nsScreencastService::~nsScreencastService() { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-10 22:01:41 -07:00
										 |  |  | nsresult nsScreencastService::StartVideoRecording(nsIScreencastServiceClient* aClient, nsIDocShell* aDocShell, bool isVideo, const nsACString& aVideoFileName, uint32_t width, uint32_t height, uint32_t quality, uint32_t viewportWidth, uint32_t viewportHeight, uint32_t offsetTop, nsAString& sessionId) { | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  |   MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Screencast service must be started on the Main thread."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   PresShell* presShell = aDocShell->GetPresShell(); | 
					
						
							|  |  |  |   if (!presShell) | 
					
						
							|  |  |  |     return NS_ERROR_UNEXPECTED; | 
					
						
							|  |  |  |   nsViewManager* viewManager = presShell->GetViewManager(); | 
					
						
							|  |  |  |   if (!viewManager) | 
					
						
							|  |  |  |     return NS_ERROR_UNEXPECTED; | 
					
						
							|  |  |  |   nsView* view = viewManager->GetRootView(); | 
					
						
							|  |  |  |   if (!view) | 
					
						
							|  |  |  |     return NS_ERROR_UNEXPECTED; | 
					
						
							|  |  |  |   nsIWidget* widget = view->GetWidget(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |   rtc::scoped_refptr<webrtc::VideoCaptureModuleEx> capturer = CreateWindowCapturer(widget); | 
					
						
							| 
									
										
										
										
											2020-07-14 11:20:36 -07:00
										 |  |  |   if (!capturer) | 
					
						
							|  |  |  |     return NS_ERROR_FAILURE; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 17:10:06 -07:00
										 |  |  |   gfx::IntMargin margin; | 
					
						
							| 
									
										
										
										
											2020-08-10 15:10:12 -07:00
										 |  |  |   auto bounds = widget->GetScreenBounds().ToUnknownRect(); | 
					
						
							|  |  |  |   auto clientBounds = widget->GetClientBounds().ToUnknownRect(); | 
					
						
							|  |  |  |   // Crop the image to exclude frame (if any).
 | 
					
						
							| 
									
										
										
										
											2020-09-01 17:10:06 -07:00
										 |  |  |   margin = bounds - clientBounds; | 
					
						
							| 
									
										
										
										
											2020-08-10 15:10:12 -07:00
										 |  |  |   // Crop the image to exclude controls.
 | 
					
						
							|  |  |  |   margin.top += offsetTop; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-05 13:27:51 -07:00
										 |  |  |   nsCString error; | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |   RefPtr<ScreencastEncoder> encoder; | 
					
						
							|  |  |  |   if (isVideo) { | 
					
						
							|  |  |  |     encoder = ScreencastEncoder::create(error, PromiseFlatCString(aVideoFileName), width, height, margin); | 
					
						
							|  |  |  |     if (!encoder) { | 
					
						
							|  |  |  |       fprintf(stderr, "Failed to create ScreencastEncoder: %s\n", error.get()); | 
					
						
							|  |  |  |       return NS_ERROR_FAILURE; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-14 16:14:24 -07:00
										 |  |  |   nsString uid; | 
					
						
							|  |  |  |   nsresult rv = generateUid(uid); | 
					
						
							|  |  |  |   NS_ENSURE_SUCCESS(rv, rv); | 
					
						
							|  |  |  |   sessionId = uid; | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-10 22:01:41 -07:00
										 |  |  |   auto session = std::make_unique<Session>(aClient, std::move(capturer), std::move(encoder), width, height, viewportWidth, viewportHeight, margin, isVideo ? 0 : quality); | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |   if (!session->Start()) | 
					
						
							|  |  |  |     return NS_ERROR_FAILURE; | 
					
						
							|  |  |  |   mIdToSession.emplace(sessionId, std::move(session)); | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  |   return NS_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-14 16:14:24 -07:00
										 |  |  | nsresult nsScreencastService::StopVideoRecording(const nsAString& aSessionId) { | 
					
						
							|  |  |  |   nsString sessionId(aSessionId); | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  |   auto it = mIdToSession.find(sessionId); | 
					
						
							|  |  |  |   if (it == mIdToSession.end()) | 
					
						
							|  |  |  |     return NS_ERROR_INVALID_ARG; | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |   it->second->Stop(); | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  |   mIdToSession.erase(it); | 
					
						
							|  |  |  |   return NS_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  | nsresult nsScreencastService::ScreencastFrameAck(const nsAString& aSessionId) { | 
					
						
							|  |  |  |   nsString sessionId(aSessionId); | 
					
						
							|  |  |  |   auto it = mIdToSession.find(sessionId); | 
					
						
							|  |  |  |   if (it == mIdToSession.end()) | 
					
						
							|  |  |  |     return NS_ERROR_INVALID_ARG; | 
					
						
							|  |  |  |   it->second->ScreencastFrameAck(); | 
					
						
							|  |  |  |   return NS_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-02 10:43:04 -07:00
										 |  |  | }  // namespace mozilla
 |