tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CanvasCaptureMediaStream.cpp (6720B)


      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/. */
      5 
      6 #include "CanvasCaptureMediaStream.h"
      7 
      8 #include "DOMMediaStream.h"
      9 #include "ImageContainer.h"
     10 #include "MediaTrackGraph.h"
     11 #include "Tracing.h"
     12 #include "VideoSegment.h"
     13 #include "mozilla/dom/CanvasCaptureMediaStreamBinding.h"
     14 #include "mozilla/gfx/2D.h"
     15 #include "nsContentUtils.h"
     16 #include "nsGlobalWindowInner.h"
     17 
     18 using namespace mozilla::layers;
     19 using namespace mozilla::gfx;
     20 
     21 namespace mozilla::dom {
     22 
     23 OutputStreamDriver::OutputStreamDriver(SourceMediaTrack* aSourceStream,
     24                                       const PrincipalHandle& aPrincipalHandle)
     25    : mSourceStream(aSourceStream), mPrincipalHandle(aPrincipalHandle) {
     26  MOZ_ASSERT(NS_IsMainThread());
     27  MOZ_ASSERT(mSourceStream);
     28 }
     29 
     30 OutputStreamDriver::~OutputStreamDriver() {
     31  MOZ_ASSERT(NS_IsMainThread());
     32  EndTrack();
     33 }
     34 
     35 void OutputStreamDriver::EndTrack() {
     36  MOZ_ASSERT(NS_IsMainThread());
     37  if (!mSourceStream->IsDestroyed()) {
     38    mSourceStream->Destroy();
     39  }
     40 }
     41 
     42 void OutputStreamDriver::SetImage(RefPtr<layers::Image>&& aImage,
     43                                  const TimeStamp& aTime) {
     44  MOZ_ASSERT(NS_IsMainThread());
     45 
     46  VideoSegment segment;
     47  const auto size = aImage->GetSize();
     48  segment.AppendFrame(aImage.forget(), size, mPrincipalHandle, false, aTime);
     49  mSourceStream->AppendData(&segment);
     50 }
     51 
     52 // ----------------------------------------------------------------------
     53 
     54 class TimerDriver : public OutputStreamDriver {
     55 public:
     56  explicit TimerDriver(SourceMediaTrack* aSourceStream, const double& aFPS,
     57                       const PrincipalHandle& aPrincipalHandle)
     58      : OutputStreamDriver(aSourceStream, aPrincipalHandle),
     59        mFrameInterval(aFPS == 0.0 ? TimeDuration::Forever()
     60                                   : TimeDuration::FromSeconds(1.0 / aFPS)) {}
     61 
     62  void RequestFrameCapture() override { mExplicitCaptureRequested = true; }
     63 
     64  bool FrameCaptureRequested(const TimeStamp& aTime) const override {
     65    if (mLastFrameTime.IsNull()) {
     66      // All CanvasCaptureMediaStreams shall at least get one frame.
     67      return true;
     68    }
     69 
     70    if (mExplicitCaptureRequested) {
     71      return true;
     72    }
     73 
     74    if ((aTime - mLastFrameTime) >= mFrameInterval) {
     75      return true;
     76    }
     77 
     78    return false;
     79  }
     80 
     81  void NewFrame(already_AddRefed<Image> aImage,
     82                const TimeStamp& aTime) override {
     83    nsCString str;
     84    if (profiler_thread_is_being_profiled_for_markers()) {
     85      TimeDuration sinceLast =
     86          aTime - (mLastFrameTime.IsNull() ? aTime : mLastFrameTime);
     87      str.AppendPrintf(
     88          "TimerDriver %staking frame (%sexplicitly requested; after %.2fms; "
     89          "interval cap %.2fms)",
     90          sinceLast >= mFrameInterval ? "" : "NOT ",
     91          mExplicitCaptureRequested ? "" : "NOT ", sinceLast.ToMilliseconds(),
     92          mFrameInterval.ToMilliseconds());
     93    }
     94    AUTO_PROFILER_MARKER_TEXT("Canvas CaptureStream", MEDIA_RT, {}, str);
     95 
     96    RefPtr<Image> image = aImage;
     97 
     98    if (!FrameCaptureRequested(aTime)) {
     99      return;
    100    }
    101 
    102    mLastFrameTime = aTime;
    103    mExplicitCaptureRequested = false;
    104    SetImage(std::move(image), aTime);
    105  }
    106 
    107 protected:
    108  virtual ~TimerDriver() = default;
    109 
    110 private:
    111  const TimeDuration mFrameInterval;
    112  bool mExplicitCaptureRequested = false;
    113  TimeStamp mLastFrameTime;
    114 };
    115 
    116 // ----------------------------------------------------------------------
    117 
    118 class AutoDriver : public OutputStreamDriver {
    119 public:
    120  explicit AutoDriver(SourceMediaTrack* aSourceStream,
    121                      const PrincipalHandle& aPrincipalHandle)
    122      : OutputStreamDriver(aSourceStream, aPrincipalHandle) {}
    123 
    124  void RequestFrameCapture() override {}
    125 
    126  bool FrameCaptureRequested(const TimeStamp& aTime) const override {
    127    return true;
    128  }
    129 
    130  void NewFrame(already_AddRefed<Image> aImage,
    131                const TimeStamp& aTime) override {
    132    AUTO_PROFILER_MARKER_TEXT("Canvas CaptureStream", MEDIA_RT, {},
    133                              "AutoDriver taking frame"_ns);
    134 
    135    RefPtr<Image> image = aImage;
    136    SetImage(std::move(image), aTime);
    137  }
    138 
    139 protected:
    140  virtual ~AutoDriver() = default;
    141 };
    142 
    143 // ----------------------------------------------------------------------
    144 
    145 NS_IMPL_CYCLE_COLLECTION_INHERITED(CanvasCaptureMediaStream, DOMMediaStream,
    146                                   mCanvas)
    147 
    148 NS_IMPL_ADDREF_INHERITED(CanvasCaptureMediaStream, DOMMediaStream)
    149 NS_IMPL_RELEASE_INHERITED(CanvasCaptureMediaStream, DOMMediaStream)
    150 
    151 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CanvasCaptureMediaStream)
    152 NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
    153 
    154 CanvasCaptureMediaStream::CanvasCaptureMediaStream(nsPIDOMWindowInner* aWindow,
    155                                                   HTMLCanvasElement* aCanvas)
    156    : DOMMediaStream(aWindow), mCanvas(aCanvas) {}
    157 
    158 CanvasCaptureMediaStream::~CanvasCaptureMediaStream() = default;
    159 
    160 JSObject* CanvasCaptureMediaStream::WrapObject(
    161    JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
    162  return dom::CanvasCaptureMediaStream_Binding::Wrap(aCx, this, aGivenProto);
    163 }
    164 
    165 void CanvasCaptureMediaStream::RequestFrame() {
    166  if (mOutputStreamDriver) {
    167    mOutputStreamDriver->RequestFrameCapture();
    168  }
    169 }
    170 
    171 nsresult CanvasCaptureMediaStream::Init(const dom::Optional<double>& aFPS,
    172                                        nsIPrincipal* aPrincipal) {
    173  MediaTrackGraph* graph = MediaTrackGraph::GetInstance(
    174      MediaTrackGraph::SYSTEM_THREAD_DRIVER, GetOwnerWindow(),
    175      MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE,
    176      MediaTrackGraph::DEFAULT_OUTPUT_DEVICE);
    177  SourceMediaTrack* source = graph->CreateSourceTrack(MediaSegment::VIDEO);
    178  PrincipalHandle principalHandle = MakePrincipalHandle(aPrincipal);
    179  if (!aFPS.WasPassed()) {
    180    mOutputStreamDriver = new AutoDriver(source, principalHandle);
    181  } else if (aFPS.Value() < 0) {
    182    return NS_ERROR_ILLEGAL_VALUE;
    183  } else {
    184    // Cap frame rate to 60 FPS for sanity
    185    double fps = std::min(60.0, aFPS.Value());
    186    mOutputStreamDriver = new TimerDriver(source, fps, principalHandle);
    187  }
    188  return NS_OK;
    189 }
    190 
    191 FrameCaptureListener* CanvasCaptureMediaStream::FrameCaptureListener() {
    192  return mOutputStreamDriver;
    193 }
    194 
    195 void CanvasCaptureMediaStream::StopCapture() {
    196  if (!mOutputStreamDriver) {
    197    return;
    198  }
    199 
    200  mOutputStreamDriver->EndTrack();
    201  mOutputStreamDriver = nullptr;
    202 }
    203 
    204 SourceMediaTrack* CanvasCaptureMediaStream::GetSourceStream() const {
    205  if (!mOutputStreamDriver) {
    206    return nullptr;
    207  }
    208  return mOutputStreamDriver->mSourceStream;
    209 }
    210 
    211 }  // namespace mozilla::dom