tor-browser

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

RemoteMediaData.h (14247B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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_media_ipc_RemoteMediaData_h
      8 #define mozilla_dom_media_ipc_RemoteMediaData_h
      9 
     10 #include <functional>
     11 
     12 #include "MediaData.h"
     13 #include "PlatformDecoderModule.h"
     14 #include "ipc/IPCMessageUtils.h"
     15 #include "mozilla/GfxMessageUtils.h"
     16 #include "mozilla/PMediaDecoderParams.h"
     17 #include "mozilla/RemoteImageHolder.h"
     18 #include "mozilla/ShmemPool.h"
     19 #include "mozilla/gfx/Rect.h"
     20 
     21 namespace mozilla {
     22 
     23 class ShmemPool;
     24 
     25 namespace ipc {
     26 class IProtocol;
     27 class Shmem;
     28 }  // namespace ipc
     29 
     30 //-----------------------------------------------------------------------------
     31 // Declaration of the IPDL type |struct RemoteVideoData|
     32 //
     33 // We can't use the generated binding in order to use move semantics properly
     34 // (see bug 1664362)
     35 class RemoteVideoData final {
     36 private:
     37  typedef mozilla::gfx::IntSize IntSize;
     38 
     39 public:
     40  RemoteVideoData() = default;
     41 
     42  RemoteVideoData(const MediaDataIPDL& aBase, const IntSize& aDisplay,
     43                  RemoteImageHolder&& aImage, int32_t aFrameID)
     44      : mBase(aBase),
     45        mDisplay(aDisplay),
     46        mImage(std::move(aImage)),
     47        mFrameID(aFrameID) {}
     48 
     49  // This is equivalent to the old RemoteVideoDataIPDL object and is similar to
     50  // the RemoteAudioDataIPDL object. To ensure style consistency we use the IPDL
     51  // naming convention here.
     52  MediaDataIPDL& base() { return mBase; }
     53  const MediaDataIPDL& base() const { return mBase; }
     54 
     55  IntSize& display() { return mDisplay; }
     56  const IntSize& display() const { return mDisplay; }
     57 
     58  RemoteImageHolder& image() { return mImage; }
     59  const RemoteImageHolder& image() const { return mImage; }
     60 
     61  int32_t& frameID() { return mFrameID; }
     62  const int32_t& frameID() const { return mFrameID; }
     63 
     64 private:
     65  friend struct IPC::ParamTraits<RemoteVideoData>;
     66  MediaDataIPDL mBase;
     67  IntSize mDisplay;
     68  RemoteImageHolder mImage;
     69  int32_t mFrameID;
     70 };
     71 
     72 // Until bug 1572054 is resolved, we can't move our objects when using IPDL's
     73 // union or array. They are always copied. So we make the class refcounted to
     74 // and always pass it by pointed to bypass the problem for now.
     75 class ArrayOfRemoteVideoData final {
     76  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ArrayOfRemoteVideoData)
     77 public:
     78  ArrayOfRemoteVideoData() = default;
     79  ArrayOfRemoteVideoData(ArrayOfRemoteVideoData&& aOther)
     80      : mArray(std::move(aOther.mArray)) {}
     81  explicit ArrayOfRemoteVideoData(nsTArray<RemoteVideoData>&& aOther)
     82      : mArray(std::move(aOther)) {}
     83  ArrayOfRemoteVideoData(const ArrayOfRemoteVideoData& aOther) {
     84    MOZ_CRASH("Should never be used but declared by generated IPDL binding");
     85  }
     86  ArrayOfRemoteVideoData& operator=(ArrayOfRemoteVideoData&& aOther) noexcept {
     87    if (this != &aOther) {
     88      mArray = std::move(aOther.mArray);
     89    }
     90    return *this;
     91  }
     92  ArrayOfRemoteVideoData& operator=(nsTArray<RemoteVideoData>&& aOther) {
     93    mArray = std::move(aOther);
     94    return *this;
     95  }
     96 
     97  void AppendElements(nsTArray<RemoteVideoData>&& aOther) {
     98    mArray.AppendElements(std::move(aOther));
     99  }
    100  void Append(RemoteVideoData&& aVideo) {
    101    mArray.AppendElement(std::move(aVideo));
    102  }
    103  const nsTArray<RemoteVideoData>& Array() const { return mArray; }
    104  nsTArray<RemoteVideoData>& Array() { return mArray; }
    105 
    106 private:
    107  ~ArrayOfRemoteVideoData() = default;
    108  friend struct IPC::ParamTraits<mozilla::ArrayOfRemoteVideoData*>;
    109  nsTArray<RemoteVideoData> mArray;
    110 };
    111 
    112 /* The class will pack either an array of AlignedBuffer or MediaByteBuffer
    113 * into a single Shmem objects. */
    114 class RemoteArrayOfByteBuffer {
    115 public:
    116  RemoteArrayOfByteBuffer();
    117  template <typename Type>
    118  RemoteArrayOfByteBuffer(const nsTArray<AlignedBuffer<Type>>& aArray,
    119                          std::function<ShmemBuffer(size_t)>& aAllocator) {
    120    // Determine the total size we will need for this object.
    121    size_t totalSize = 0;
    122    for (auto& buffer : aArray) {
    123      totalSize += buffer.Size();
    124    }
    125    if (totalSize) {
    126      if (!AllocateShmem(totalSize, aAllocator)) {
    127        return;
    128      }
    129    }
    130    size_t offset = 0;
    131    for (auto& buffer : aArray) {
    132      if (totalSize && buffer && buffer.Size()) {
    133        Write(offset, buffer.Data(), buffer.Size());
    134      }
    135      mOffsets.AppendElement(OffsetEntry{offset, buffer.Size()});
    136      offset += buffer.Size();
    137    }
    138    mIsValid = true;
    139  }
    140 
    141  template <typename Type>
    142  RemoteArrayOfByteBuffer(const AlignedBuffer<Type>& aBuffer,
    143                          std::function<ShmemBuffer(size_t)>& aAllocator) {
    144    // Determine the total size we will need for this object.
    145    size_t bufferSize = aBuffer.Size();
    146    if (bufferSize) {
    147      if (!AllocateShmem(bufferSize, aAllocator)) {
    148        return;
    149      }
    150      Write(0, aBuffer.Data(), bufferSize);
    151      mOffsets.AppendElement(OffsetEntry{0, bufferSize});
    152    }
    153    mIsValid = true;
    154  }
    155 
    156  RemoteArrayOfByteBuffer(const nsTArray<RefPtr<MediaByteBuffer>>& aArray,
    157                          std::function<ShmemBuffer(size_t)>& aAllocator);
    158  RemoteArrayOfByteBuffer& operator=(RemoteArrayOfByteBuffer&& aOther) noexcept;
    159 
    160  // Return the packed aIndexth buffer as an AlignedByteBuffer.
    161  // The operation is fallible should an out of memory be encountered. The
    162  // result should be tested accordingly.
    163  template <typename Type>
    164  AlignedBuffer<Type> AlignedBufferAt(size_t aIndex) const {
    165    MOZ_ASSERT(aIndex < Count());
    166    const OffsetEntry& entry = mOffsets[aIndex];
    167    size_t entrySize = std::get<1>(entry);
    168    if (!mBuffers || !entrySize) {
    169      // It's an empty one.
    170      return AlignedBuffer<Type>();
    171    }
    172    if (!Check(std::get<0>(entry), entrySize)) {
    173      // This Shmem is corrupted and can't contain the data we are about to
    174      // retrieve. We return an empty array instead of asserting to allow for
    175      // recovery.
    176      return AlignedBuffer<Type>();
    177    }
    178    if (0 != entrySize % sizeof(Type)) {
    179      // There's an error, that entry can't represent this data.
    180      return AlignedBuffer<Type>();
    181    }
    182    return AlignedBuffer<Type>(
    183        reinterpret_cast<Type*>(BuffersStartAddress() + std::get<0>(entry)),
    184        entrySize / sizeof(Type));
    185  }
    186 
    187  // Return the packed aIndexth buffer as aMediaByteBuffer.
    188  // Will return nullptr if the packed buffer was originally empty.
    189  already_AddRefed<MediaByteBuffer> MediaByteBufferAt(size_t aIndex) const;
    190  // Return the size of the aIndexth buffer.
    191  size_t SizeAt(size_t aIndex) const { return std::get<1>(mOffsets[aIndex]); }
    192  // Return false if an out of memory error was encountered during construction.
    193  bool IsValid() const { return mIsValid; };
    194  // Return the number of buffers packed into this entity.
    195  size_t Count() const { return mOffsets.Length(); }
    196  virtual ~RemoteArrayOfByteBuffer();
    197 
    198 private:
    199  friend struct IPC::ParamTraits<RemoteArrayOfByteBuffer>;
    200  // Allocate shmem, false if an error occurred.
    201  bool AllocateShmem(size_t aSize,
    202                     std::function<ShmemBuffer(size_t)>& aAllocator);
    203  // The starting address of the Shmem
    204  uint8_t* BuffersStartAddress() const;
    205  // Check that the allocated Shmem can contain such range.
    206  bool Check(size_t aOffset, size_t aSizeInBytes) const;
    207  void Write(size_t aOffset, const void* aSourceAddr, size_t aSizeInBytes);
    208  // Set to false is the buffer isn't initialized yet or a memory error occurred
    209  // during construction.
    210  bool mIsValid = false;
    211  // The packed data. The Maybe will be empty if all buffers packed were
    212  // orignally empty.
    213  Maybe<ipc::Shmem> mBuffers;
    214  // The offset to the start of the individual buffer and its size (all in
    215  // bytes)
    216  typedef std::tuple<size_t, size_t> OffsetEntry;
    217  nsTArray<OffsetEntry> mOffsets;
    218 };
    219 
    220 /* The class will pack an array of MediaRawData using at most three Shmem
    221 * objects. Under the most common scenaria, only two Shmems will be used as
    222 * there are few videos with an alpha channel in the wild.
    223 * We unfortunately can't populate the array at construction nor present an
    224 * interface similar to an actual nsTArray or the ArrayOfRemoteVideoData above
    225 * as currently IPC serialization is always non-fallible. So we must create the
    226 * object first, fill it to determine if we ran out of memory and then send the
    227 * object over IPC.
    228 */
    229 class ArrayOfRemoteMediaRawData {
    230  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ArrayOfRemoteMediaRawData)
    231 public:
    232  // Fill the content, return false if an OOM occurred.
    233  bool Fill(const nsTArray<RefPtr<MediaRawData>>& aData,
    234            std::function<ShmemBuffer(size_t)>&& aAllocator);
    235 
    236  // Return the aIndexth MediaRawData or nullptr if a memory error occurred.
    237  already_AddRefed<MediaRawData> ElementAt(size_t aIndex) const;
    238 
    239  // Return the number of MediaRawData stored in this container.
    240  size_t Count() const { return mSamples.Length(); }
    241  bool IsEmpty() const { return Count() == 0; }
    242  bool IsValid() const {
    243    return mBuffers.IsValid() && mAlphaBuffers.IsValid() &&
    244           mExtraDatas.IsValid();
    245  }
    246 
    247  struct RemoteMediaRawData {
    248    MediaDataIPDL mBase;
    249    bool mEOS;
    250    // This will be zero for audio.
    251    int32_t mHeight;
    252    Maybe<uint8_t> mTemporalLayerId;
    253    Maybe<media::TimeInterval> mOriginalPresentationWindow;
    254    Maybe<CryptoInfo> mCryptoConfig;
    255  };
    256 
    257 private:
    258  friend struct IPC::ParamTraits<ArrayOfRemoteMediaRawData*>;
    259  virtual ~ArrayOfRemoteMediaRawData() = default;
    260 
    261  nsTArray<RemoteMediaRawData> mSamples;
    262  RemoteArrayOfByteBuffer mBuffers;
    263  RemoteArrayOfByteBuffer mAlphaBuffers;
    264  RemoteArrayOfByteBuffer mExtraDatas;
    265 };
    266 
    267 /* The class will pack an array of MediaAudioData using at most a single Shmem
    268 * objects.
    269 * We unfortunately can't populate the array at construction nor present an
    270 * interface similar to an actual nsTArray or the ArrayOfRemoteVideoData above
    271 * as currently IPC serialization is always non-fallible. So we must create the
    272 * object first, fill it to determine if we ran out of memory and then send the
    273 * object over IPC.
    274 */
    275 class ArrayOfRemoteAudioData final {
    276  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ArrayOfRemoteAudioData)
    277 public:
    278  // Fill the content, return false if an OOM occurred.
    279  bool Fill(const nsTArray<RefPtr<AudioData>>& aData,
    280            std::function<ShmemBuffer(size_t)>&& aAllocator);
    281  bool Fill(const AudioData* aData,
    282            std::function<ShmemBuffer(size_t)>&& aAllocator);
    283 
    284  // Return the aIndexth MediaRawData or nullptr if a memory error occurred.
    285  already_AddRefed<AudioData> ElementAt(size_t aIndex) const;
    286 
    287  // Return the number of MediaRawData stored in this container.
    288  size_t Count() const { return mSamples.Length(); }
    289  bool IsEmpty() const { return Count() == 0; }
    290  bool IsValid() const { return mBuffers.IsValid(); }
    291 
    292  struct RemoteAudioData {
    293    friend struct IPC::ParamTraits<RemoteVideoData>;
    294    MediaDataIPDL mBase;
    295    uint32_t mChannels;
    296    uint32_t mRate;
    297    uint32_t mChannelMap;
    298    media::TimeUnit mOriginalTime;
    299    Maybe<media::TimeInterval> mTrimWindow;
    300    uint32_t mFrames;
    301    size_t mDataOffset;
    302  };
    303 
    304 private:
    305  friend struct IPC::ParamTraits<ArrayOfRemoteAudioData*>;
    306  ~ArrayOfRemoteAudioData() = default;
    307 
    308  nsTArray<RemoteAudioData> mSamples;
    309  RemoteArrayOfByteBuffer mBuffers;
    310 };
    311 
    312 }  // namespace mozilla
    313 
    314 namespace IPC {
    315 
    316 template <>
    317 struct ParamTraits<mozilla::RemoteVideoData> {
    318  using paramType = mozilla::RemoteVideoData;
    319  static void Write(MessageWriter* aWriter, paramType&& aVar) {
    320    WriteParam(aWriter, std::move(aVar.mBase));
    321    WriteParam(aWriter, std::move(aVar.mDisplay));
    322    WriteParam(aWriter, std::move(aVar.mImage));
    323    aWriter->WriteBytes(&aVar.mFrameID, 4);
    324  }
    325 
    326  static bool Read(IPC::MessageReader* aReader, paramType* aVar) {
    327    return ReadParam(aReader, &aVar->mBase) &&
    328           ReadParam(aReader, &aVar->mDisplay) &&
    329           ReadParam(aReader, &aVar->mImage) &&
    330           aReader->ReadBytesInto(&aVar->mFrameID, 4);
    331  }
    332 };
    333 
    334 template <>
    335 struct ParamTraits<mozilla::ArrayOfRemoteVideoData*> {
    336  using paramType = mozilla::ArrayOfRemoteVideoData;
    337  static void Write(IPC::MessageWriter* aWriter, paramType* aVar) {
    338    WriteParam(aWriter, std::move(aVar->mArray));
    339  }
    340 
    341  static bool Read(IPC::MessageReader* aReader, RefPtr<paramType>* aVar) {
    342    nsTArray<mozilla::RemoteVideoData> array;
    343    if (!ReadParam(aReader, &array)) {
    344      return false;
    345    }
    346    auto results =
    347        mozilla::MakeRefPtr<mozilla::ArrayOfRemoteVideoData>(std::move(array));
    348    *aVar = std::move(results);
    349    return true;
    350  }
    351 };
    352 
    353 template <>
    354 struct ParamTraits<mozilla::RemoteArrayOfByteBuffer> {
    355  using paramType = mozilla::RemoteArrayOfByteBuffer;
    356  // We do not want to move the RemoteArrayOfByteBuffer as we want to recycle
    357  // the shmem it contains for another time.
    358  static void Write(IPC::MessageWriter* aWriter, const paramType& aVar);
    359 
    360  static bool Read(IPC::MessageReader* aReader, paramType* aVar);
    361 };
    362 
    363 template <>
    364 struct ParamTraits<mozilla::ArrayOfRemoteMediaRawData::RemoteMediaRawData> {
    365  using paramType = mozilla::ArrayOfRemoteMediaRawData::RemoteMediaRawData;
    366  static void Write(MessageWriter* aWriter, const paramType& aVar);
    367 
    368  static bool Read(MessageReader* aReader, paramType* aVar);
    369 };
    370 
    371 template <>
    372 struct ParamTraits<mozilla::ArrayOfRemoteMediaRawData*> {
    373  using paramType = mozilla::ArrayOfRemoteMediaRawData;
    374  static void Write(MessageWriter* aWriter, paramType* aVar);
    375 
    376  static bool Read(MessageReader* aReader, RefPtr<paramType>* aVar);
    377 };
    378 
    379 template <>
    380 struct ParamTraits<mozilla::ArrayOfRemoteAudioData::RemoteAudioData> {
    381  using paramType = mozilla::ArrayOfRemoteAudioData::RemoteAudioData;
    382  static void Write(MessageWriter* aWriter, const paramType& aVar);
    383 
    384  static bool Read(MessageReader* aReader, paramType* aVar);
    385 };
    386 
    387 template <>
    388 struct ParamTraits<mozilla::ArrayOfRemoteAudioData*> {
    389  using paramType = mozilla::ArrayOfRemoteAudioData;
    390  static void Write(MessageWriter* aWriter, paramType* aVar);
    391 
    392  static bool Read(MessageReader* aReader, RefPtr<paramType>* aVar);
    393 };
    394 }  // namespace IPC
    395 
    396 #endif  // mozilla_dom_media_ipc_RemoteMediaData_h