tor-browser

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

WebCodecsUtils.h (14015B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef MOZILLA_DOM_WEBCODECS_WEBCODECSUTILS_H
      8 #define MOZILLA_DOM_WEBCODECS_WEBCODECSUTILS_H
      9 
     10 #include "ErrorList.h"
     11 #include "MediaData.h"
     12 #include "PlatformEncoderModule.h"
     13 #include "js/TypeDecls.h"
     14 #include "mozilla/Maybe.h"
     15 #include "mozilla/MozPromise.h"
     16 #include "mozilla/ProfilerMarkers.h"
     17 #include "mozilla/Result.h"
     18 #include "mozilla/TaskQueue.h"
     19 #include "mozilla/dom/AudioDataBinding.h"
     20 #include "mozilla/dom/BindingDeclarations.h"
     21 #include "mozilla/dom/BufferSourceBindingFwd.h"
     22 #include "mozilla/dom/Nullable.h"
     23 #include "mozilla/dom/VideoColorSpaceBinding.h"
     24 #include "mozilla/dom/VideoEncoderBinding.h"
     25 #include "mozilla/dom/VideoFrameBinding.h"
     26 #include "nsIGlobalObject.h"
     27 
     28 namespace mozilla {
     29 
     30 namespace dom {
     31 class VideoEncoderConfigInternal;
     32 class VideoDecoderConfigInternal;
     33 }  // namespace dom
     34 
     35 #define WEBCODECS_MARKER(codecType, desc, options, markerType, ...)    \
     36  do {                                                                 \
     37    if (profiler_is_collecting_markers()) {                            \
     38      nsFmtCString marker(FMT_STRING("{}{}"), codecType, desc);        \
     39      PROFILER_MARKER(                                                 \
     40          ProfilerString8View::WrapNullTerminatedString(marker.get()), \
     41          MEDIA_RT, options, markerType, __VA_ARGS__);                 \
     42    }                                                                  \
     43  } while (0)
     44 
     45 #define WEBCODECS_MARKER_INTERVAL_START(type, desc)                      \
     46  WEBCODECS_MARKER(type, desc, {MarkerTiming::IntervalStart()}, Tracing, \
     47                   "WebCodecs")
     48 #define WEBCODECS_MARKER_INTERVAL_END(type, desc)                      \
     49  WEBCODECS_MARKER(type, desc, {MarkerTiming::IntervalEnd()}, Tracing, \
     50                   "WebCodecs")
     51 
     52 class AutoWebCodecsMarker {
     53 public:
     54  AutoWebCodecsMarker(const char* aType, const char* aDesc)
     55      : mType(aType), mDesc(aDesc) {
     56    WEBCODECS_MARKER_INTERVAL_START(mType, mDesc);
     57  }
     58 
     59  AutoWebCodecsMarker(AutoWebCodecsMarker&& aOther) noexcept {
     60    MOZ_ASSERT(!aOther.mEnded, "Ended marker should not be moved");
     61    mType = std::move(aOther.mType);
     62    mDesc = std::move(aOther.mDesc);
     63    mEnded = std::move(aOther.mEnded);
     64    aOther.mEnded = true;
     65  }
     66 
     67  AutoWebCodecsMarker& operator=(AutoWebCodecsMarker&& aOther) noexcept {
     68    if (this != &aOther) {
     69      MOZ_ASSERT(!aOther.mEnded, "Ended marker should not be moved");
     70      mType = std::move(aOther.mType);
     71      mDesc = std::move(aOther.mDesc);
     72      mEnded = std::move(aOther.mEnded);
     73      aOther.mEnded = true;
     74    }
     75    return *this;
     76  }
     77 
     78  AutoWebCodecsMarker(const AutoWebCodecsMarker& aOther) = delete;
     79  AutoWebCodecsMarker& operator=(const AutoWebCodecsMarker& aOther) = delete;
     80 
     81  ~AutoWebCodecsMarker() { End(); }
     82 
     83  void End() {
     84    if (!mEnded) {
     85      WEBCODECS_MARKER_INTERVAL_END(mType, mDesc);
     86      mEnded = true;
     87    }
     88  }
     89 
     90 private:
     91  const char* mType;
     92  const char* mDesc;
     93  bool mEnded = false;
     94 };
     95 
     96 // Use this macro only when you do not need to call `AutoWebCodecsMarker::End()`
     97 // manually; it will automatically end the marker when the object goes out of
     98 // scope.
     99 #define AUTO_WEBCODECS_MARKER(type, desc) \
    100  AutoWebCodecsMarker PROFILER_RAII(type, desc)
    101 
    102 class AsyncDurationTracker {
    103 public:
    104  AsyncDurationTracker() : mOwningThread(GetCurrentSerialEventTarget()) {}
    105  ~AsyncDurationTracker() { Clear(); }
    106 
    107  void Start(int64_t aTimestamp, AutoWebCodecsMarker&& aMarker) {
    108    MOZ_ASSERT(mOwningThread->IsOnCurrentThread());
    109    mEntries.push_back(
    110        Entry{.mTimestamp = aTimestamp, .mMarker = std::move(aMarker)});
    111  }
    112 
    113  size_t End(int64_t aTimestamp) {
    114    MOZ_ASSERT(mOwningThread->IsOnCurrentThread());
    115    size_t popped = 0;
    116    while (!mEntries.empty() && mEntries.front().mTimestamp <= aTimestamp) {
    117      mEntries.front().mMarker.End();
    118      popped += 1;
    119      mEntries.pop_front();
    120    }
    121    return popped;
    122  }
    123 
    124  void Clear() {
    125    MOZ_ASSERT(mOwningThread->IsOnCurrentThread());
    126    while (!mEntries.empty()) {
    127      mEntries.front().mMarker.End();
    128      mEntries.pop_front();
    129    }
    130  }
    131 
    132 private:
    133  struct Entry {
    134    int64_t mTimestamp;
    135    AutoWebCodecsMarker mMarker;
    136  };
    137 
    138  std::deque<Entry> mEntries;
    139  const nsCOMPtr<nsISerialEventTarget> mOwningThread;
    140 };
    141 
    142 namespace gfx {
    143 enum class ColorRange : uint8_t;
    144 enum class ColorSpace2 : uint8_t;
    145 enum class SurfaceFormat : int8_t;
    146 enum class TransferFunction : uint8_t;
    147 enum class YUVColorSpace : uint8_t;
    148 }  // namespace gfx
    149 
    150 using WebCodecsId = size_t;
    151 
    152 extern std::atomic<WebCodecsId> sNextId;
    153 
    154 class EncoderConfigurationChangeList;
    155 
    156 namespace dom {
    157 
    158 /*
    159 * The followings are helpers for WebCodecs methods.
    160 */
    161 
    162 nsTArray<nsCString> GuessContainers(const nsAString& aCodec);
    163 
    164 Maybe<nsString> ParseCodecString(const nsAString& aCodec);
    165 
    166 bool IsSameColorSpace(const VideoColorSpaceInit& aLhs,
    167                      const VideoColorSpaceInit& aRhs);
    168 
    169 /*
    170 * Below are helpers for conversion among Maybe, Optional, and Nullable.
    171 */
    172 
    173 template <typename T>
    174 Maybe<T> OptionalToMaybe(const Optional<T>& aOptional) {
    175  if (aOptional.WasPassed()) {
    176    return Some(aOptional.Value());
    177  }
    178  return Nothing();
    179 }
    180 
    181 template <typename T>
    182 const T* OptionalToPointer(const Optional<T>& aOptional) {
    183  return aOptional.WasPassed() ? &aOptional.Value() : nullptr;
    184 }
    185 
    186 template <typename T>
    187 Maybe<T> NullableToMaybe(const Nullable<T>& aNullable) {
    188  if (!aNullable.IsNull()) {
    189    return Some(aNullable.Value());
    190  }
    191  return Nothing();
    192 }
    193 
    194 template <typename T>
    195 Nullable<T> MaybeToNullable(const Maybe<T>& aOptional) {
    196  if (aOptional.isSome()) {
    197    return Nullable<T>(aOptional.value());
    198  }
    199  return Nullable<T>();
    200 }
    201 
    202 /*
    203 * Below are helpers to operate ArrayBuffer or ArrayBufferView.
    204 */
    205 
    206 Result<Ok, nsresult> CloneBuffer(JSContext* aCx,
    207                                 OwningAllowSharedBufferSource& aDest,
    208                                 const OwningAllowSharedBufferSource& aSrc,
    209                                 ErrorResult& aRv);
    210 
    211 Result<RefPtr<MediaByteBuffer>, nsresult> GetExtraDataFromArrayBuffer(
    212    const OwningAllowSharedBufferSource& aBuffer);
    213 
    214 bool CopyExtradataToDescription(JSContext* aCx, Span<const uint8_t>& aSrc,
    215                                OwningAllowSharedBufferSource& aDest);
    216 
    217 /*
    218 * The following are utilities to convert between VideoColorSpace values to
    219 * gfx's values.
    220 */
    221 
    222 struct VideoColorSpaceInternal {
    223  explicit VideoColorSpaceInternal(const VideoColorSpaceInit& aColorSpaceInit);
    224  VideoColorSpaceInternal() = default;
    225  VideoColorSpaceInternal(const bool& aFullRange,
    226                          const VideoMatrixCoefficients& aMatrix,
    227                          const VideoColorPrimaries& aPrimaries,
    228                          const VideoTransferCharacteristics& aTransfer)
    229      : mFullRange(Some(aFullRange)),
    230        mMatrix(Some(aMatrix)),
    231        mPrimaries(Some(aPrimaries)),
    232        mTransfer(Some(aTransfer)) {}
    233  VideoColorSpaceInternal(const VideoColorSpaceInternal& aOther) = default;
    234  VideoColorSpaceInternal(VideoColorSpaceInternal&& aOther) = default;
    235 
    236  VideoColorSpaceInternal& operator=(const VideoColorSpaceInternal& aOther) =
    237      default;
    238  VideoColorSpaceInternal& operator=(VideoColorSpaceInternal&& aOther) =
    239      default;
    240 
    241  bool operator==(const VideoColorSpaceInternal& aOther) const {
    242    return mFullRange == aOther.mFullRange && mMatrix == aOther.mMatrix &&
    243           mPrimaries == aOther.mPrimaries && mTransfer == aOther.mTransfer;
    244  }
    245  bool operator!=(const VideoColorSpaceInternal& aOther) const {
    246    return !(*this == aOther);
    247  }
    248 
    249  VideoColorSpaceInit ToColorSpaceInit() const;
    250  nsCString ToString() const;
    251 
    252  Maybe<bool> mFullRange;
    253  Maybe<VideoMatrixCoefficients> mMatrix;
    254  Maybe<VideoColorPrimaries> mPrimaries;
    255  Maybe<VideoTransferCharacteristics> mTransfer;
    256 };
    257 
    258 gfx::ColorRange ToColorRange(bool aIsFullRange);
    259 
    260 gfx::YUVColorSpace ToColorSpace(VideoMatrixCoefficients aMatrix);
    261 
    262 gfx::TransferFunction ToTransferFunction(
    263    VideoTransferCharacteristics aTransfer);
    264 
    265 gfx::ColorSpace2 ToPrimaries(VideoColorPrimaries aPrimaries);
    266 
    267 bool ToFullRange(const gfx::ColorRange& aColorRange);
    268 
    269 Maybe<VideoMatrixCoefficients> ToMatrixCoefficients(
    270    const gfx::YUVColorSpace& aColorSpace);
    271 
    272 Maybe<VideoTransferCharacteristics> ToTransferCharacteristics(
    273    const gfx::TransferFunction& aTransferFunction);
    274 
    275 Maybe<VideoColorPrimaries> ToPrimaries(const gfx::ColorSpace2& aColorSpace);
    276 
    277 /*
    278 * The following are utilities to convert from gfx's formats to
    279 * VideoPixelFormats.
    280 */
    281 
    282 enum class ImageBitmapFormat : uint8_t;
    283 enum class VideoPixelFormat : uint8_t;
    284 
    285 Maybe<VideoPixelFormat> SurfaceFormatToVideoPixelFormat(
    286    gfx::SurfaceFormat aFormat);
    287 
    288 Maybe<VideoPixelFormat> ImageBitmapFormatToVideoPixelFormat(
    289    ImageBitmapFormat aFormat);
    290 
    291 template <typename T>
    292 class MessageRequestHolder {
    293 public:
    294  MessageRequestHolder() = default;
    295  ~MessageRequestHolder() = default;
    296 
    297  MozPromiseRequestHolder<T>& Request() { return mRequest; }
    298  void Disconnect() { mRequest.DisconnectIfExists(); }
    299  void Complete() { mRequest.Complete(); }
    300  bool Exists() const { return mRequest.Exists(); }
    301 
    302 protected:
    303  MozPromiseRequestHolder<T> mRequest{};
    304 };
    305 
    306 enum class MessageProcessedResult { NotProcessed, Processed };
    307 
    308 bool IsOnAndroid();
    309 bool IsOnMacOS();
    310 bool IsOnLinux();
    311 
    312 // Wrap a type to make it unique. This allows using ergonomically in the Variant
    313 // below. Simply aliasing with `using` isn't enough, because typedefs in C++
    314 // don't produce strong types, so two integer variants result in
    315 // the same type, making it ambiguous to the Variant code.
    316 // T is the type to be wrapped. Phantom is a type that is only used to
    317 // disambiguate and should be unique in the program.
    318 template <typename T, typename Phantom>
    319 class StrongTypedef {
    320 public:
    321  explicit StrongTypedef(T const& value) : mValue(value) {}
    322  explicit StrongTypedef(T&& value) : mValue(std::move(value)) {}
    323  T& get() { return mValue; }
    324  T const& get() const { return mValue; }
    325 
    326 private:
    327  T mValue;
    328 };
    329 
    330 using CodecChange = StrongTypedef<nsString, struct CodecChangeTypeWebCodecs>;
    331 using DimensionsChange =
    332    StrongTypedef<gfx::IntSize, struct DimensionsChangeTypeWebCodecs>;
    333 using DisplayDimensionsChange =
    334    StrongTypedef<Maybe<gfx::IntSize>,
    335                  struct DisplayDimensionsChangeTypeWebCodecs>;
    336 using BitrateChange =
    337    StrongTypedef<Maybe<uint32_t>, struct BitrateChangeTypeWebCodecs>;
    338 using FramerateChange =
    339    StrongTypedef<Maybe<double>, struct FramerateChangeTypeWebCodecs>;
    340 using HardwareAccelerationChange =
    341    StrongTypedef<dom::HardwareAcceleration,
    342                  struct HardwareAccelerationChangeTypeWebCodecs>;
    343 using AlphaChange =
    344    StrongTypedef<dom::AlphaOption, struct AlphaChangeTypeWebCodecs>;
    345 using ScalabilityModeChange =
    346    StrongTypedef<Maybe<nsString>, struct ScalabilityModeChangeTypeWebCodecs>;
    347 using BitrateModeChange = StrongTypedef<dom::VideoEncoderBitrateMode,
    348                                        struct BitrateModeChangeTypeWebCodecs>;
    349 using LatencyModeChange =
    350    StrongTypedef<dom::LatencyMode, struct LatencyModeTypeChangeTypeWebCodecs>;
    351 using ContentHintChange =
    352    StrongTypedef<Maybe<nsString>, struct ContentHintTypeTypeWebCodecs>;
    353 
    354 using WebCodecsEncoderConfigurationItem =
    355    Variant<CodecChange, DimensionsChange, DisplayDimensionsChange,
    356            BitrateModeChange, BitrateChange, FramerateChange,
    357            HardwareAccelerationChange, AlphaChange, ScalabilityModeChange,
    358            LatencyModeChange, ContentHintChange>;
    359 
    360 struct WebCodecsConfigurationChangeList {
    361  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebCodecsConfigurationChangeList)
    362  bool Empty() const { return mChanges.IsEmpty(); }
    363  template <typename T>
    364  void Push(const T& aItem) {
    365    mChanges.AppendElement(aItem);
    366  }
    367  // This returns true if it should be possible to attempt to reconfigure the
    368  // encoder on the fly. It can fail, in which case the encoder will be flushed
    369  // and a new one will be created with the new set of parameters.
    370  bool CanAttemptReconfigure() const;
    371 
    372  // Convert this to the format the underlying PEM can understand
    373  RefPtr<EncoderConfigurationChangeList> ToPEMChangeList() const;
    374  nsCString ToString() const;
    375 
    376  nsTArray<WebCodecsEncoderConfigurationItem> mChanges;
    377 
    378 private:
    379  ~WebCodecsConfigurationChangeList() = default;
    380 };
    381 
    382 nsCString ColorSpaceInitToString(
    383    const dom::VideoColorSpaceInit& aColorSpaceInit);
    384 
    385 RefPtr<TaskQueue> GetWebCodecsEncoderTaskQueue();
    386 VideoColorSpaceInternal FallbackColorSpaceForVideoContent();
    387 VideoColorSpaceInternal FallbackColorSpaceForWebContent();
    388 
    389 Maybe<CodecType> CodecStringToCodecType(const nsAString& aCodecString);
    390 
    391 nsCString ConfigToString(const VideoDecoderConfig& aConfig);
    392 
    393 // Returns true if a particular codec is supported by WebCodecs.
    394 bool IsSupportedVideoCodec(const nsAString& aCodec);
    395 bool IsSupportedAudioCodec(const nsAString& aCodec);
    396 
    397 // Returns the codec string to use in Gecko for a particular container and
    398 // codec name given by WebCodecs. This maps pcm description to the profile
    399 // number, and simply returns the codec name for all other codecs.
    400 nsCString ConvertCodecName(const nsCString& aContainer,
    401                           const nsCString& aCodec);
    402 
    403 uint32_t BytesPerSamples(const mozilla::dom::AudioSampleFormat& aFormat);
    404 
    405 // If resisting fingerprinting, remove all hardware/software preference.
    406 void ApplyResistFingerprintingIfNeeded(
    407    const RefPtr<VideoEncoderConfigInternal>& aConfig,
    408    nsIGlobalObject* aGlobal);
    409 void ApplyResistFingerprintingIfNeeded(
    410    const RefPtr<VideoDecoderConfigInternal>& aConfig,
    411    nsIGlobalObject* aGlobal);
    412 }  // namespace dom
    413 }  // namespace mozilla
    414 
    415 #endif  // MOZILLA_DOM_WEBCODECS_WEBCODECSUTILS_H