tor-browser

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

GMPVideoi420FrameImpl.cpp (16211B)


      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
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "GMPVideoi420FrameImpl.h"
      7 
      8 #include <algorithm>
      9 
     10 #include "GMPSharedMemManager.h"
     11 #include "GMPVideoHost.h"
     12 #include "mozilla/CheckedInt.h"
     13 #include "mozilla/gmp/GMPTypes.h"
     14 
     15 namespace mozilla::gmp {
     16 
     17 GMPVideoi420FrameImpl::GMPFramePlane::GMPFramePlane(
     18    const GMPPlaneData& aPlaneData)
     19    : mOffset(aPlaneData.mOffset()),
     20      mSize(aPlaneData.mSize()),
     21      mStride(aPlaneData.mStride()) {}
     22 
     23 void GMPVideoi420FrameImpl::GMPFramePlane::InitPlaneData(
     24    GMPPlaneData& aPlaneData) {
     25  aPlaneData.mOffset() = mOffset;
     26  aPlaneData.mSize() = mSize;
     27  aPlaneData.mStride() = mStride;
     28 }
     29 
     30 void GMPVideoi420FrameImpl::GMPFramePlane::Copy(uint8_t* aDst,
     31                                                int32_t aDstOffset,
     32                                                const uint8_t* aSrc,
     33                                                int32_t aSize,
     34                                                int32_t aStride) {
     35  mOffset = aDstOffset;
     36  mSize = aSize;
     37  mStride = aStride;
     38  if (aDst && aSrc && aSize > 0) {
     39    memcpy(aDst + aDstOffset, aSrc, aSize);
     40  }
     41 }
     42 
     43 GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(
     44    GMPVideoHostImpl* aHost,
     45    HostReportPolicy aReportPolicy /*= HostReportPolicy::None*/)
     46    : mReportPolicy(aReportPolicy),
     47      mHost(aHost),
     48      mWidth(0),
     49      mHeight(0),
     50      mTimestamp(0ll),
     51      mDuration(0ll) {
     52  MOZ_ASSERT(aHost);
     53  aHost->DecodedFrameCreated(this);
     54 }
     55 
     56 GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(
     57    const GMPVideoi420FrameData& aFrameData, ipc::Shmem&& aShmemBuffer,
     58    GMPVideoHostImpl* aHost,
     59    HostReportPolicy aReportPolicy /*= HostReportPolicy::None*/)
     60    : mReportPolicy(aReportPolicy),
     61      mHost(aHost),
     62      mShmemBuffer(std::move(aShmemBuffer)),
     63      mYPlane(aFrameData.mYPlane()),
     64      mUPlane(aFrameData.mUPlane()),
     65      mVPlane(aFrameData.mVPlane()),
     66      mWidth(aFrameData.mWidth()),
     67      mHeight(aFrameData.mHeight()),
     68      mTimestamp(aFrameData.mTimestamp()),
     69      mUpdatedTimestamp(aFrameData.mUpdatedTimestamp()),
     70      mDuration(aFrameData.mDuration()) {
     71  MOZ_ASSERT(aHost);
     72  aHost->DecodedFrameCreated(this);
     73 }
     74 
     75 GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(
     76    const GMPVideoi420FrameData& aFrameData, nsTArray<uint8_t>&& aArrayBuffer,
     77    GMPVideoHostImpl* aHost,
     78    HostReportPolicy aReportPolicy /*= HostReportPolicy::None*/)
     79    : mReportPolicy(aReportPolicy),
     80      mHost(aHost),
     81      mArrayBuffer(std::move(aArrayBuffer)),
     82      mYPlane(aFrameData.mYPlane()),
     83      mUPlane(aFrameData.mUPlane()),
     84      mVPlane(aFrameData.mVPlane()),
     85      mWidth(aFrameData.mWidth()),
     86      mHeight(aFrameData.mHeight()),
     87      mTimestamp(aFrameData.mTimestamp()),
     88      mUpdatedTimestamp(aFrameData.mUpdatedTimestamp()),
     89      mDuration(aFrameData.mDuration()) {
     90  MOZ_ASSERT(aHost);
     91  aHost->DecodedFrameCreated(this);
     92 }
     93 
     94 GMPVideoi420FrameImpl::~GMPVideoi420FrameImpl() {
     95  DestroyBuffer();
     96  if (mHost) {
     97    mHost->DecodedFrameDestroyed(this);
     98  }
     99 }
    100 
    101 void GMPVideoi420FrameImpl::DoneWithAPI() {
    102  DestroyBuffer();
    103 
    104  // Do this after destroying the buffer because destruction
    105  // involves deallocation, which requires a host.
    106  mHost = nullptr;
    107 }
    108 
    109 void GMPVideoi420FrameImpl::InitFrameData(GMPVideoi420FrameData& aFrameData) {
    110  mYPlane.InitPlaneData(aFrameData.mYPlane());
    111  mUPlane.InitPlaneData(aFrameData.mUPlane());
    112  mVPlane.InitPlaneData(aFrameData.mVPlane());
    113  aFrameData.mWidth() = mWidth;
    114  aFrameData.mHeight() = mHeight;
    115  aFrameData.mTimestamp() = mTimestamp;
    116  aFrameData.mUpdatedTimestamp() = mUpdatedTimestamp;
    117  aFrameData.mDuration() = mDuration;
    118 }
    119 
    120 bool GMPVideoi420FrameImpl::InitFrameData(GMPVideoi420FrameData& aFrameData,
    121                                          ipc::Shmem& aShmemBuffer) {
    122  if (!mShmemBuffer.IsReadable()) {
    123    return false;
    124  }
    125 
    126  aShmemBuffer = mShmemBuffer;
    127 
    128  // This method is called right before Shmem is sent to another process.
    129  // We need to effectively zero out our member copy so that we don't
    130  // try to delete memory we don't own later.
    131  mShmemBuffer = ipc::Shmem();
    132 
    133  InitFrameData(aFrameData);
    134  return true;
    135 }
    136 
    137 bool GMPVideoi420FrameImpl::InitFrameData(GMPVideoi420FrameData& aFrameData,
    138                                          nsTArray<uint8_t>& aArrayBuffer) {
    139  if (mShmemBuffer.IsReadable()) {
    140    return false;
    141  }
    142 
    143  aArrayBuffer = std::move(mArrayBuffer);
    144  InitFrameData(aFrameData);
    145  return true;
    146 }
    147 
    148 GMPVideoFrameFormat GMPVideoi420FrameImpl::GetFrameFormat() {
    149  return kGMPI420VideoFrame;
    150 }
    151 
    152 void GMPVideoi420FrameImpl::Destroy() { delete this; }
    153 
    154 /* static */
    155 bool GMPVideoi420FrameImpl::CheckFrameData(
    156    const GMPVideoi420FrameData& aFrameData, size_t aBufferSize) {
    157  // We may be passed the "wrong" shmem (one smaller than the actual size).
    158  // This implies a bug or serious error on the child size.  Ignore this frame
    159  // if so. Note: Size() greater than expected is also an error, but with no
    160  // negative consequences
    161  int32_t half_width = (aFrameData.mWidth() + 1) / 2;
    162  if ((aFrameData.mYPlane().mStride() <= 0) ||
    163      (aFrameData.mYPlane().mSize() <= 0) ||
    164      (aFrameData.mYPlane().mOffset() < 0) ||
    165      (aFrameData.mUPlane().mStride() <= 0) ||
    166      (aFrameData.mUPlane().mSize() <= 0) ||
    167      (aFrameData.mUPlane().mOffset() <
    168       aFrameData.mYPlane().mOffset() + aFrameData.mYPlane().mSize()) ||
    169      (aFrameData.mVPlane().mStride() <= 0) ||
    170      (aFrameData.mVPlane().mSize() <= 0) ||
    171      (aFrameData.mVPlane().mOffset() <
    172       aFrameData.mUPlane().mOffset() + aFrameData.mUPlane().mSize()) ||
    173      (aBufferSize < static_cast<size_t>(aFrameData.mVPlane().mOffset()) +
    174                         static_cast<size_t>(aFrameData.mVPlane().mSize())) ||
    175      (aFrameData.mYPlane().mStride() < aFrameData.mWidth()) ||
    176      (aFrameData.mUPlane().mStride() < half_width) ||
    177      (aFrameData.mVPlane().mStride() < half_width) ||
    178      (aFrameData.mYPlane().mSize() <
    179       aFrameData.mYPlane().mStride() * aFrameData.mHeight()) ||
    180      (aFrameData.mUPlane().mSize() <
    181       aFrameData.mUPlane().mStride() * ((aFrameData.mHeight() + 1) / 2)) ||
    182      (aFrameData.mVPlane().mSize() <
    183       aFrameData.mVPlane().mStride() * ((aFrameData.mHeight() + 1) / 2))) {
    184    return false;
    185  }
    186  return true;
    187 }
    188 
    189 bool GMPVideoi420FrameImpl::CheckDimensions(int32_t aWidth, int32_t aHeight,
    190                                            int32_t aStride_y,
    191                                            int32_t aStride_u,
    192                                            int32_t aStride_v, int32_t aSize_y,
    193                                            int32_t aSize_u, int32_t aSize_v) {
    194  if (aWidth < 1 || aHeight < 1 || aStride_y < aWidth || aSize_y < 1 ||
    195      aSize_u < 1 || aSize_v < 1) {
    196    return false;
    197  }
    198  auto halfWidth = (CheckedInt<int32_t>(aWidth) + 1) / 2;
    199  if (!halfWidth.isValid() || aStride_u < halfWidth.value() ||
    200      aStride_v < halfWidth.value()) {
    201    return false;
    202  }
    203  auto height = CheckedInt<int32_t>(aHeight);
    204  auto halfHeight = (height + 1) / 2;
    205  auto minSizeY = height * aStride_y;
    206  auto minSizeU = halfHeight * aStride_u;
    207  auto minSizeV = halfHeight * aStride_v;
    208  auto totalSize = minSizeY + minSizeU + minSizeV;
    209  if (!minSizeY.isValid() || !minSizeU.isValid() || !minSizeV.isValid() ||
    210      !totalSize.isValid() || minSizeY.value() > aSize_y ||
    211      minSizeU.value() > aSize_u || minSizeV.value() > aSize_v) {
    212    return false;
    213  }
    214  return true;
    215 }
    216 
    217 bool GMPVideoi420FrameImpl::CheckDimensions(int32_t aWidth, int32_t aHeight,
    218                                            int32_t aStride_y,
    219                                            int32_t aStride_u,
    220                                            int32_t aStride_v) {
    221  int32_t half_width = (aWidth + 1) / 2;
    222  if (aWidth < 1 || aHeight < 1 || aStride_y < aWidth ||
    223      aStride_u < half_width || aStride_v < half_width ||
    224      !(CheckedInt<int32_t>(aHeight) * aStride_y +
    225        ((CheckedInt<int32_t>(aHeight) + 1) / 2) *
    226            (CheckedInt<int32_t>(aStride_u) + aStride_v))
    227           .isValid()) {
    228    return false;
    229  }
    230  return true;
    231 }
    232 
    233 const GMPVideoi420FrameImpl::GMPFramePlane* GMPVideoi420FrameImpl::GetPlane(
    234    GMPPlaneType aType) const {
    235  switch (aType) {
    236    case kGMPYPlane:
    237      return &mYPlane;
    238    case kGMPUPlane:
    239      return &mUPlane;
    240    case kGMPVPlane:
    241      return &mVPlane;
    242    default:
    243      MOZ_CRASH("Unknown plane type!");
    244  }
    245  return nullptr;
    246 }
    247 
    248 GMPVideoi420FrameImpl::GMPFramePlane* GMPVideoi420FrameImpl::GetPlane(
    249    GMPPlaneType aType) {
    250  switch (aType) {
    251    case kGMPYPlane:
    252      return &mYPlane;
    253    case kGMPUPlane:
    254      return &mUPlane;
    255    case kGMPVPlane:
    256      return &mVPlane;
    257    default:
    258      MOZ_CRASH("Unknown plane type!");
    259  }
    260  return nullptr;
    261 }
    262 
    263 GMPErr GMPVideoi420FrameImpl::MaybeResize(int32_t aNewSize) {
    264  if (aNewSize <= AllocatedSize()) {
    265    return GMPNoErr;
    266  }
    267 
    268  if (!mHost) {
    269    return GMPGenericErr;
    270  }
    271 
    272  if (!mArrayBuffer.IsEmpty()) {
    273    if (!mArrayBuffer.SetLength(aNewSize, fallible)) {
    274      return GMPAllocErr;
    275    }
    276    return GMPNoErr;
    277  }
    278 
    279  ipc::Shmem new_mem;
    280  if (!mHost->SharedMemMgr()->MgrTakeShmem(GMPSharedMemClass::Decoded, aNewSize,
    281                                           &new_mem) &&
    282      !mArrayBuffer.SetLength(aNewSize, fallible)) {
    283    return GMPAllocErr;
    284  }
    285 
    286  if (mShmemBuffer.IsReadable()) {
    287    if (new_mem.IsWritable()) {
    288      memcpy(new_mem.get<uint8_t>(), mShmemBuffer.get<uint8_t>(), aNewSize);
    289    }
    290    mHost->SharedMemMgr()->MgrGiveShmem(GMPSharedMemClass::Decoded,
    291                                        std::move(mShmemBuffer));
    292  }
    293 
    294  mShmemBuffer = new_mem;
    295 
    296  return GMPNoErr;
    297 }
    298 
    299 void GMPVideoi420FrameImpl::DestroyBuffer() {
    300  if (mHost && mShmemBuffer.IsWritable()) {
    301    mHost->SharedMemMgr()->MgrGiveShmem(GMPSharedMemClass::Decoded,
    302                                        std::move(mShmemBuffer));
    303  }
    304  mShmemBuffer = ipc::Shmem();
    305  mArrayBuffer.Clear();
    306 }
    307 
    308 GMPErr GMPVideoi420FrameImpl::CreateEmptyFrame(int32_t aWidth, int32_t aHeight,
    309                                               int32_t aStride_y,
    310                                               int32_t aStride_u,
    311                                               int32_t aStride_v) {
    312  if (!CheckDimensions(aWidth, aHeight, aStride_y, aStride_u, aStride_v)) {
    313    return GMPGenericErr;
    314  }
    315 
    316  int32_t size_y = aStride_y * aHeight;
    317  int32_t half_height = (aHeight + 1) / 2;
    318  int32_t size_u = aStride_u * half_height;
    319  int32_t size_v = aStride_v * half_height;
    320 
    321  int32_t bufferSize = size_y + size_u + size_v;
    322  GMPErr err = MaybeResize(bufferSize);
    323  if (err != GMPNoErr) {
    324    return err;
    325  }
    326 
    327  mYPlane.mOffset = 0;
    328  mYPlane.mSize = size_y;
    329  mYPlane.mStride = aStride_y;
    330 
    331  mUPlane.mOffset = size_y;
    332  mUPlane.mSize = size_u;
    333  mUPlane.mStride = aStride_u;
    334 
    335  mVPlane.mOffset = size_y + size_u;
    336  mVPlane.mSize = size_v;
    337  mVPlane.mStride = aStride_v;
    338 
    339  mWidth = aWidth;
    340  mHeight = aHeight;
    341  mTimestamp = 0ll;
    342  mUpdatedTimestamp.reset();
    343  mDuration = 0ll;
    344 
    345  return GMPNoErr;
    346 }
    347 
    348 GMPErr GMPVideoi420FrameImpl::CreateFrame(
    349    int32_t aSize_y, const uint8_t* aBuffer_y, int32_t aSize_u,
    350    const uint8_t* aBuffer_u, int32_t aSize_v, const uint8_t* aBuffer_v,
    351    int32_t aWidth, int32_t aHeight, int32_t aStride_y, int32_t aStride_u,
    352    int32_t aStride_v) {
    353  MOZ_ASSERT(aBuffer_y);
    354  MOZ_ASSERT(aBuffer_u);
    355  MOZ_ASSERT(aBuffer_v);
    356 
    357  if (!CheckDimensions(aWidth, aHeight, aStride_y, aStride_u, aStride_v,
    358                       aSize_y, aSize_u, aSize_v)) {
    359    return GMPGenericErr;
    360  }
    361 
    362  int32_t bufferSize = aSize_y + aSize_u + aSize_v;
    363  GMPErr err = MaybeResize(bufferSize);
    364  if (err != GMPNoErr) {
    365    return err;
    366  }
    367 
    368  uint8_t* bufferPtr = Buffer();
    369  mYPlane.Copy(bufferPtr, 0, aBuffer_y, aSize_y, aStride_y);
    370  mUPlane.Copy(bufferPtr, aSize_y, aBuffer_u, aSize_u, aStride_u);
    371  mVPlane.Copy(bufferPtr, aSize_y + aSize_u, aBuffer_v, aSize_v, aStride_v);
    372 
    373  mWidth = aWidth;
    374  mHeight = aHeight;
    375 
    376  return GMPNoErr;
    377 }
    378 
    379 GMPErr GMPVideoi420FrameImpl::CopyFrame(const GMPVideoi420Frame& aFrame) {
    380  auto& f = static_cast<const GMPVideoi420FrameImpl&>(aFrame);
    381 
    382  int32_t bufferSize = f.mYPlane.mSize + f.mUPlane.mSize + f.mVPlane.mSize;
    383  if (bufferSize != AllocatedSize()) {
    384    return GMPGenericErr;
    385  }
    386 
    387  GMPErr err = MaybeResize(bufferSize);
    388  if (err != GMPNoErr) {
    389    return err;
    390  }
    391 
    392  mYPlane = f.mYPlane;
    393  mUPlane = f.mUPlane;
    394  mVPlane = f.mVPlane;
    395  mWidth = f.mWidth;
    396  mHeight = f.mHeight;
    397  mTimestamp = f.mTimestamp;
    398  mUpdatedTimestamp = f.mUpdatedTimestamp;
    399  mDuration = f.mDuration;
    400 
    401  memcpy(Buffer(), f.Buffer(), bufferSize);
    402 
    403  return GMPNoErr;
    404 }
    405 
    406 void GMPVideoi420FrameImpl::SwapFrame(GMPVideoi420Frame* aFrame) {
    407  auto f = static_cast<GMPVideoi420FrameImpl*>(aFrame);
    408  mArrayBuffer.SwapElements(f->mArrayBuffer);
    409  std::swap(mShmemBuffer, f->mShmemBuffer);
    410  std::swap(mYPlane, f->mYPlane);
    411  std::swap(mUPlane, f->mUPlane);
    412  std::swap(mVPlane, f->mVPlane);
    413  std::swap(mWidth, f->mWidth);
    414  std::swap(mHeight, f->mHeight);
    415  std::swap(mTimestamp, f->mTimestamp);
    416  std::swap(mUpdatedTimestamp, f->mUpdatedTimestamp);
    417  std::swap(mDuration, f->mDuration);
    418 }
    419 
    420 uint8_t* GMPVideoi420FrameImpl::Buffer() {
    421  if (mShmemBuffer.IsWritable()) {
    422    return mShmemBuffer.get<uint8_t>();
    423  }
    424  if (!mArrayBuffer.IsEmpty()) {
    425    return mArrayBuffer.Elements();
    426  }
    427  return nullptr;
    428 }
    429 
    430 const uint8_t* GMPVideoi420FrameImpl::Buffer() const {
    431  if (mShmemBuffer.IsReadable()) {
    432    return mShmemBuffer.get<uint8_t>();
    433  }
    434  if (!mArrayBuffer.IsEmpty()) {
    435    return mArrayBuffer.Elements();
    436  }
    437  return nullptr;
    438 }
    439 
    440 uint8_t* GMPVideoi420FrameImpl::Buffer(GMPPlaneType aType) {
    441  if (auto* p = GetPlane(aType)) {
    442    if (auto* buffer = Buffer()) {
    443      return buffer + p->mOffset;
    444    }
    445  }
    446  return nullptr;
    447 }
    448 
    449 const uint8_t* GMPVideoi420FrameImpl::Buffer(GMPPlaneType aType) const {
    450  if (const auto* p = GetPlane(aType)) {
    451    if (const auto* buffer = Buffer()) {
    452      return buffer + p->mOffset;
    453    }
    454  }
    455  return nullptr;
    456 }
    457 
    458 int32_t GMPVideoi420FrameImpl::AllocatedSize() const {
    459  if (mShmemBuffer.IsWritable()) {
    460    return static_cast<int32_t>(mShmemBuffer.Size<uint8_t>());
    461  }
    462  return static_cast<int32_t>(mArrayBuffer.Length());
    463 }
    464 
    465 int32_t GMPVideoi420FrameImpl::AllocatedSize(GMPPlaneType aType) const {
    466  if (const auto* p = GetPlane(aType)) {
    467    return p->mSize;
    468  }
    469  return -1;
    470 }
    471 
    472 int32_t GMPVideoi420FrameImpl::Stride(GMPPlaneType aType) const {
    473  if (const auto* p = GetPlane(aType)) {
    474    return p->mStride;
    475  }
    476  return -1;
    477 }
    478 
    479 GMPErr GMPVideoi420FrameImpl::SetWidth(int32_t aWidth) {
    480  if (!CheckDimensions(aWidth, mHeight, mYPlane.mStride, mUPlane.mStride,
    481                       mVPlane.mStride)) {
    482    return GMPGenericErr;
    483  }
    484  mWidth = aWidth;
    485  return GMPNoErr;
    486 }
    487 
    488 GMPErr GMPVideoi420FrameImpl::SetHeight(int32_t aHeight) {
    489  if (!CheckDimensions(mWidth, aHeight, mYPlane.mStride, mUPlane.mStride,
    490                       mVPlane.mStride)) {
    491    return GMPGenericErr;
    492  }
    493  mHeight = aHeight;
    494  return GMPNoErr;
    495 }
    496 
    497 int32_t GMPVideoi420FrameImpl::Width() const { return mWidth; }
    498 
    499 int32_t GMPVideoi420FrameImpl::Height() const { return mHeight; }
    500 
    501 void GMPVideoi420FrameImpl::SetTimestamp(uint64_t aTimestamp) {
    502  mTimestamp = aTimestamp;
    503 }
    504 
    505 uint64_t GMPVideoi420FrameImpl::Timestamp() const { return mTimestamp; }
    506 
    507 void GMPVideoi420FrameImpl::SetUpdatedTimestamp(uint64_t aTimestamp) {
    508  mUpdatedTimestamp = Some(aTimestamp);
    509 }
    510 
    511 uint64_t GMPVideoi420FrameImpl::UpdatedTimestamp() const {
    512  return mUpdatedTimestamp ? *mUpdatedTimestamp : mTimestamp;
    513 }
    514 
    515 void GMPVideoi420FrameImpl::SetDuration(uint64_t aDuration) {
    516  mDuration = aDuration;
    517 }
    518 
    519 uint64_t GMPVideoi420FrameImpl::Duration() const { return mDuration; }
    520 
    521 bool GMPVideoi420FrameImpl::IsZeroSize() const {
    522  return (mYPlane.mSize == 0 && mUPlane.mSize == 0 && mVPlane.mSize == 0);
    523 }
    524 
    525 void GMPVideoi420FrameImpl::ResetSize() {
    526  mYPlane.mSize = 0;
    527  mUPlane.mSize = 0;
    528  mVPlane.mSize = 0;
    529 }
    530 
    531 }  // namespace mozilla::gmp