tor-browser

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

RemoteMediaData.cpp (14674B)


      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 #include "RemoteMediaData.h"
      8 
      9 #include "PerformanceRecorder.h"
     10 #include "mozilla/CheckedInt.h"
     11 #include "mozilla/dom/MediaIPCUtils.h"
     12 #include "mozilla/ipc/Shmem.h"
     13 
     14 namespace mozilla {
     15 
     16 bool RemoteArrayOfByteBuffer::AllocateShmem(
     17    size_t aSize, std::function<ShmemBuffer(size_t)>& aAllocator) {
     18  ShmemBuffer buffer = aAllocator(aSize);
     19  if (!buffer.Valid()) {
     20    return false;
     21  }
     22  mBuffers.emplace(std::move(buffer.Get()));
     23  return true;
     24 }
     25 
     26 uint8_t* RemoteArrayOfByteBuffer::BuffersStartAddress() const {
     27  MOZ_ASSERT(mBuffers);
     28  return mBuffers->get<uint8_t>();
     29 }
     30 
     31 bool RemoteArrayOfByteBuffer::Check(size_t aOffset, size_t aSizeInBytes) const {
     32  if (!mBuffers || !mBuffers->IsReadable()) {
     33    return false;
     34  }
     35  auto size = CheckedInt<size_t>(aOffset) + aSizeInBytes;
     36  return size.isValid() && size.value() <= mBuffers->Size<uint8_t>();
     37 }
     38 
     39 void RemoteArrayOfByteBuffer::Write(size_t aOffset, const void* aSourceAddr,
     40                                    size_t aSizeInBytes) {
     41  if (!aSizeInBytes) {
     42    return;
     43  }
     44  MOZ_DIAGNOSTIC_ASSERT(Check(aOffset, aSizeInBytes),
     45                        "Allocated Shmem is too small");
     46  memcpy(BuffersStartAddress() + aOffset, aSourceAddr, aSizeInBytes);
     47 }
     48 
     49 RemoteArrayOfByteBuffer::RemoteArrayOfByteBuffer() = default;
     50 
     51 RemoteArrayOfByteBuffer::RemoteArrayOfByteBuffer(
     52    const nsTArray<RefPtr<MediaByteBuffer>>& aArray,
     53    std::function<ShmemBuffer(size_t)>& aAllocator) {
     54  // Determine the total size we will need for this object.
     55  size_t totalSize = 0;
     56  for (const auto& buffer : aArray) {
     57    if (buffer) {
     58      totalSize += buffer->Length();
     59    }
     60  }
     61  if (totalSize) {
     62    if (!AllocateShmem(totalSize, aAllocator)) {
     63      return;
     64    }
     65  }
     66  size_t offset = 0;
     67  for (const auto& buffer : aArray) {
     68    size_t sizeBuffer = buffer ? buffer->Length() : 0;
     69    if (totalSize && sizeBuffer) {
     70      Write(offset, buffer->Elements(), sizeBuffer);
     71    }
     72    mOffsets.AppendElement(OffsetEntry{offset, sizeBuffer});
     73    offset += sizeBuffer;
     74  }
     75  mIsValid = true;
     76 }
     77 
     78 RemoteArrayOfByteBuffer& RemoteArrayOfByteBuffer::operator=(
     79    RemoteArrayOfByteBuffer&& aOther) noexcept {
     80  mIsValid = aOther.mIsValid;
     81  mBuffers = std::move(aOther.mBuffers);
     82  mOffsets = std::move(aOther.mOffsets);
     83  aOther.mIsValid = false;
     84  return *this;
     85 }
     86 
     87 RemoteArrayOfByteBuffer::~RemoteArrayOfByteBuffer() = default;
     88 
     89 already_AddRefed<MediaByteBuffer> RemoteArrayOfByteBuffer::MediaByteBufferAt(
     90    size_t aIndex) const {
     91  MOZ_ASSERT(aIndex < Count());
     92  const OffsetEntry& entry = mOffsets[aIndex];
     93  if (!mBuffers || !std::get<1>(entry)) {
     94    // It's an empty one.
     95    return nullptr;
     96  }
     97  size_t entrySize = std::get<1>(entry);
     98  if (!Check(std::get<0>(entry), entrySize)) {
     99    // This Shmem is corrupted and can't contain the data we are about to
    100    // retrieve. We return an empty array instead of asserting to allow for
    101    // recovery.
    102    return nullptr;
    103  }
    104  RefPtr<MediaByteBuffer> buffer = new MediaByteBuffer(entrySize);
    105  buffer->SetLength(entrySize);
    106  memcpy(buffer->Elements(), mBuffers->get<uint8_t>() + std::get<0>(entry),
    107         entrySize);
    108  return buffer.forget();
    109 }
    110 
    111 }  // namespace mozilla
    112 
    113 /*static */ void IPC::ParamTraits<mozilla::RemoteArrayOfByteBuffer>::Write(
    114    IPC::MessageWriter* aWriter, const mozilla::RemoteArrayOfByteBuffer& aVar) {
    115  WriteParam(aWriter, aVar.mIsValid);
    116  // We need the following gymnastic as the Shmem transfered over IPC will be
    117  // revoked. We must create a temporary one instead so that it can be recycled
    118  // later back into the original ShmemPool.
    119  if (aVar.mBuffers) {
    120    WriteParam(aWriter, mozilla::Some(mozilla::ipc::Shmem(*aVar.mBuffers)));
    121  } else {
    122    WriteParam(aWriter, mozilla::Maybe<mozilla::ipc::Shmem>());
    123  }
    124  WriteParam(aWriter, aVar.mOffsets);
    125 }
    126 
    127 /* static */ bool IPC::ParamTraits<mozilla::RemoteArrayOfByteBuffer>::Read(
    128    IPC::MessageReader* aReader, mozilla::RemoteArrayOfByteBuffer* aVar) {
    129  return ReadParam(aReader, &aVar->mIsValid) &&
    130         ReadParam(aReader, &aVar->mBuffers) &&
    131         ReadParam(aReader, &aVar->mOffsets);
    132 }
    133 
    134 namespace mozilla {
    135 
    136 bool ArrayOfRemoteMediaRawData::Fill(
    137    const nsTArray<RefPtr<MediaRawData>>& aData,
    138    std::function<ShmemBuffer(size_t)>&& aAllocator) {
    139  nsTArray<AlignedByteBuffer> dataBuffers(aData.Length());
    140  nsTArray<AlignedByteBuffer> alphaBuffers(aData.Length());
    141  nsTArray<RefPtr<MediaByteBuffer>> extraDataBuffers(aData.Length());
    142  int32_t height = 0;
    143  for (auto&& entry : aData) {
    144    dataBuffers.AppendElement(std::move(entry->mBuffer));
    145    alphaBuffers.AppendElement(std::move(entry->mAlphaBuffer));
    146    extraDataBuffers.AppendElement(std::move(entry->mExtraData));
    147    if (auto&& info = entry->mTrackInfo; info && info->GetAsVideoInfo()) {
    148      height = info->GetAsVideoInfo()->mImage.height;
    149    }
    150    mSamples.AppendElement(RemoteMediaRawData{
    151        MediaDataIPDL(entry->mOffset, entry->mTime, entry->mTimecode,
    152                      entry->mDuration, entry->mKeyframe),
    153        entry->mEOS, height, entry->mTemporalLayerId,
    154        entry->mOriginalPresentationWindow,
    155        entry->mCrypto.IsEncrypted() && entry->mShouldCopyCryptoToRemoteRawData
    156            ? Some(CryptoInfo{
    157                  entry->mCrypto.mCryptoScheme,
    158                  entry->mCrypto.mIV,
    159                  entry->mCrypto.mConstantIV,
    160                  entry->mCrypto.mKeyId,
    161                  entry->mCrypto.mPlainSizes,
    162                  entry->mCrypto.mEncryptedSizes,
    163                  entry->mCrypto.mCryptByteBlock,
    164                  entry->mCrypto.mSkipByteBlock,
    165              })
    166            : Nothing()});
    167  }
    168  PerformanceRecorder<PlaybackStage> perfRecorder(MediaStage::CopyDemuxedData,
    169                                                  height);
    170  mBuffers = RemoteArrayOfByteBuffer(dataBuffers, aAllocator);
    171  if (!mBuffers.IsValid()) {
    172    return false;
    173  }
    174  mAlphaBuffers = RemoteArrayOfByteBuffer(alphaBuffers, aAllocator);
    175  if (!mAlphaBuffers.IsValid()) {
    176    return false;
    177  }
    178  mExtraDatas = RemoteArrayOfByteBuffer(extraDataBuffers, aAllocator);
    179  if (!mExtraDatas.IsValid()) {
    180    return false;
    181  }
    182  perfRecorder.Record();
    183  return true;
    184 }
    185 
    186 already_AddRefed<MediaRawData> ArrayOfRemoteMediaRawData::ElementAt(
    187    size_t aIndex) const {
    188  if (!IsValid()) {
    189    return nullptr;
    190  }
    191  MOZ_ASSERT(aIndex < Count());
    192  MOZ_DIAGNOSTIC_ASSERT(mBuffers.Count() == Count() &&
    193                            mAlphaBuffers.Count() == Count() &&
    194                            mExtraDatas.Count() == Count(),
    195                        "Something ain't right here");
    196  const auto& sample = mSamples[aIndex];
    197  PerformanceRecorder<PlaybackStage> perfRecorder(MediaStage::CopyDemuxedData,
    198                                                  sample.mHeight);
    199  AlignedByteBuffer data = mBuffers.AlignedBufferAt<uint8_t>(aIndex);
    200  if (mBuffers.SizeAt(aIndex) && !data) {
    201    // OOM
    202    return nullptr;
    203  }
    204  AlignedByteBuffer alphaData = mAlphaBuffers.AlignedBufferAt<uint8_t>(aIndex);
    205  if (mAlphaBuffers.SizeAt(aIndex) && !alphaData) {
    206    // OOM
    207    return nullptr;
    208  }
    209  RefPtr<MediaRawData> rawData;
    210  if (mAlphaBuffers.SizeAt(aIndex)) {
    211    rawData = new MediaRawData(std::move(data), std::move(alphaData));
    212  } else {
    213    rawData = new MediaRawData(std::move(data));
    214  }
    215  rawData->mOffset = sample.mBase.offset();
    216  rawData->mTime = sample.mBase.time();
    217  rawData->mTimecode = sample.mBase.timecode();
    218  rawData->mDuration = sample.mBase.duration();
    219  rawData->mKeyframe = sample.mBase.keyframe();
    220  rawData->mEOS = sample.mEOS;
    221  rawData->mTemporalLayerId = sample.mTemporalLayerId;
    222  rawData->mExtraData = mExtraDatas.MediaByteBufferAt(aIndex);
    223  if (sample.mCryptoConfig) {
    224    CryptoSample& cypto = rawData->GetWritableCrypto();
    225    cypto.mCryptoScheme = sample.mCryptoConfig->mEncryptionScheme();
    226    cypto.mIV = std::move(sample.mCryptoConfig->mIV());
    227    cypto.mConstantIV = std::move(sample.mCryptoConfig->mConstantIV());
    228    cypto.mIVSize = cypto.mIV.Length();
    229    cypto.mKeyId = std::move(sample.mCryptoConfig->mKeyId());
    230    cypto.mPlainSizes = std::move(sample.mCryptoConfig->mClearBytes());
    231    cypto.mEncryptedSizes = std::move(sample.mCryptoConfig->mCipherBytes());
    232    cypto.mCryptByteBlock = sample.mCryptoConfig->mCryptByteBlock();
    233    cypto.mSkipByteBlock = sample.mCryptoConfig->mSkipByteBlock();
    234  }
    235  perfRecorder.Record();
    236  return rawData.forget();
    237 }
    238 
    239 }  // namespace mozilla
    240 
    241 /*static */ void IPC::ParamTraits<mozilla::ArrayOfRemoteMediaRawData*>::Write(
    242    MessageWriter* aWriter, mozilla::ArrayOfRemoteMediaRawData* aVar) {
    243  WriteParam(aWriter, std::move(aVar->mSamples));
    244  WriteParam(aWriter, std::move(aVar->mBuffers));
    245  WriteParam(aWriter, std::move(aVar->mAlphaBuffers));
    246  WriteParam(aWriter, std::move(aVar->mExtraDatas));
    247 }
    248 
    249 /* static */ bool IPC::ParamTraits<mozilla::ArrayOfRemoteMediaRawData*>::Read(
    250    MessageReader* aReader, RefPtr<mozilla::ArrayOfRemoteMediaRawData>* aVar) {
    251  auto array = mozilla::MakeRefPtr<mozilla::ArrayOfRemoteMediaRawData>();
    252  if (!ReadParam(aReader, &array->mSamples) ||
    253      !ReadParam(aReader, &array->mBuffers) ||
    254      !ReadParam(aReader, &array->mAlphaBuffers) ||
    255      !ReadParam(aReader, &array->mExtraDatas)) {
    256    return false;
    257  }
    258  *aVar = std::move(array);
    259  return true;
    260 }
    261 
    262 /* static */ void
    263 IPC::ParamTraits<mozilla::ArrayOfRemoteMediaRawData::RemoteMediaRawData>::Write(
    264    MessageWriter* aWriter, const paramType& aVar) {
    265  WriteParam(aWriter, aVar.mBase);
    266  WriteParam(aWriter, aVar.mEOS);
    267  WriteParam(aWriter, aVar.mHeight);
    268  WriteParam(aWriter, aVar.mTemporalLayerId);
    269  WriteParam(aWriter, aVar.mOriginalPresentationWindow);
    270  WriteParam(aWriter, aVar.mCryptoConfig);
    271 }
    272 
    273 /* static */ bool
    274 IPC::ParamTraits<mozilla::ArrayOfRemoteMediaRawData::RemoteMediaRawData>::Read(
    275    MessageReader* aReader, paramType* aVar) {
    276  mozilla::MediaDataIPDL mBase;
    277  return ReadParam(aReader, &aVar->mBase) && ReadParam(aReader, &aVar->mEOS) &&
    278         ReadParam(aReader, &aVar->mHeight) &&
    279         ReadParam(aReader, &aVar->mTemporalLayerId) &&
    280         ReadParam(aReader, &aVar->mOriginalPresentationWindow) &&
    281         ReadParam(aReader, &aVar->mCryptoConfig);
    282 };
    283 
    284 namespace mozilla {
    285 
    286 bool ArrayOfRemoteAudioData::Fill(
    287    const AudioData* aData, std::function<ShmemBuffer(size_t)>&& aAllocator) {
    288  mSamples.AppendElement(RemoteAudioData{
    289      MediaDataIPDL(aData->mOffset, aData->mTime, aData->mTimecode,
    290                    aData->mDuration, aData->mKeyframe),
    291      aData->mChannels, aData->mRate, uint32_t(aData->mChannelMap),
    292      aData->mOriginalTime, aData->mTrimWindow, aData->mFrames,
    293      aData->mDataOffset});
    294  mBuffers = RemoteArrayOfByteBuffer(aData->mAudioData, aAllocator);
    295  if (!mBuffers.IsValid()) {
    296    return false;
    297  }
    298  return true;
    299 }
    300 
    301 bool ArrayOfRemoteAudioData::Fill(
    302    const nsTArray<RefPtr<AudioData>>& aData,
    303    std::function<ShmemBuffer(size_t)>&& aAllocator) {
    304  nsTArray<AlignedAudioBuffer> dataBuffers(aData.Length());
    305  for (auto&& entry : aData) {
    306    dataBuffers.AppendElement(std::move(entry->mAudioData));
    307    mSamples.AppendElement(RemoteAudioData{
    308        MediaDataIPDL(entry->mOffset, entry->mTime, entry->mTimecode,
    309                      entry->mDuration, entry->mKeyframe),
    310        entry->mChannels, entry->mRate, uint32_t(entry->mChannelMap),
    311        entry->mOriginalTime, entry->mTrimWindow, entry->mFrames,
    312        entry->mDataOffset});
    313  }
    314  mBuffers = RemoteArrayOfByteBuffer(dataBuffers, aAllocator);
    315  if (!mBuffers.IsValid()) {
    316    return false;
    317  }
    318  return true;
    319 }
    320 
    321 already_AddRefed<AudioData> ArrayOfRemoteAudioData::ElementAt(
    322    size_t aIndex) const {
    323  if (!IsValid()) {
    324    return nullptr;
    325  }
    326  MOZ_ASSERT(aIndex < Count());
    327  MOZ_DIAGNOSTIC_ASSERT(mBuffers.Count() == Count(),
    328                        "Something ain't right here");
    329  const auto& sample = mSamples[aIndex];
    330  AlignedAudioBuffer data = mBuffers.AlignedBufferAt<AudioDataValue>(aIndex);
    331  if (mBuffers.SizeAt(aIndex) && !data) {
    332    // OOM
    333    return nullptr;
    334  }
    335  auto audioData = MakeRefPtr<AudioData>(
    336      sample.mBase.offset(), sample.mBase.time(), std::move(data),
    337      sample.mChannels, sample.mRate, sample.mChannelMap);
    338  // An AudioData's duration is set at construction time based on the size of
    339  // the provided buffer. However, if a trim window is set, this value will be
    340  // incorrect. We have to re-set it to what it actually was.
    341  audioData->mDuration = sample.mBase.duration();
    342  audioData->mOriginalTime = sample.mOriginalTime;
    343  audioData->mTrimWindow = sample.mTrimWindow;
    344  audioData->mFrames = sample.mFrames;
    345  audioData->mDataOffset = sample.mDataOffset;
    346  return audioData.forget();
    347 }
    348 
    349 }  // namespace mozilla
    350 
    351 /*static */ void IPC::ParamTraits<mozilla::ArrayOfRemoteAudioData*>::Write(
    352    IPC::MessageWriter* aWriter, mozilla::ArrayOfRemoteAudioData* aVar) {
    353  WriteParam(aWriter, std::move(aVar->mSamples));
    354  WriteParam(aWriter, std::move(aVar->mBuffers));
    355 }
    356 
    357 /* static */ bool IPC::ParamTraits<mozilla::ArrayOfRemoteAudioData*>::Read(
    358    IPC::MessageReader* aReader,
    359    RefPtr<mozilla::ArrayOfRemoteAudioData>* aVar) {
    360  auto array = mozilla::MakeRefPtr<mozilla::ArrayOfRemoteAudioData>();
    361  if (!ReadParam(aReader, &array->mSamples) ||
    362      !ReadParam(aReader, &array->mBuffers)) {
    363    return false;
    364  }
    365  *aVar = std::move(array);
    366  return true;
    367 }
    368 
    369 /* static */ void
    370 IPC::ParamTraits<mozilla::ArrayOfRemoteAudioData::RemoteAudioData>::Write(
    371    IPC::MessageWriter* aWriter, const paramType& aVar) {
    372  WriteParam(aWriter, aVar.mBase);
    373  WriteParam(aWriter, aVar.mChannels);
    374  WriteParam(aWriter, aVar.mRate);
    375  WriteParam(aWriter, aVar.mChannelMap);
    376  WriteParam(aWriter, aVar.mOriginalTime);
    377  WriteParam(aWriter, aVar.mTrimWindow);
    378  WriteParam(aWriter, aVar.mFrames);
    379  WriteParam(aWriter, aVar.mDataOffset);
    380 }
    381 
    382 /* static */ bool
    383 IPC::ParamTraits<mozilla::ArrayOfRemoteAudioData::RemoteAudioData>::Read(
    384    IPC::MessageReader* aReader, paramType* aVar) {
    385  mozilla::MediaDataIPDL mBase;
    386  return ReadParam(aReader, &aVar->mBase) &&
    387         ReadParam(aReader, &aVar->mChannels) &&
    388         ReadParam(aReader, &aVar->mRate) &&
    389         ReadParam(aReader, &aVar->mChannelMap) &&
    390         ReadParam(aReader, &aVar->mOriginalTime) &&
    391         ReadParam(aReader, &aVar->mTrimWindow) &&
    392         ReadParam(aReader, &aVar->mFrames) &&
    393         ReadParam(aReader, &aVar->mDataOffset);
    394 };