Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  GMPVideoi420FrameImpl.cpp

  Sprache: C
 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "GMPVideoi420FrameImpl.h"

#include <algorithm>

#include "GMPSharedMemManager.h"
#include "GMPVideoHost.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/gmp/GMPTypes.h"
#include "nsProxyRelease.h"
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"

namespace mozilla::gmp {

GMPVideoi420FrameImpl::GMPFramePlane::GMPFramePlane(
    const GMPPlaneData& aPlaneData)
    : mOffset(aPlaneData.mOffset()),
      mSize(aPlaneData.mSize()),
      mStride(aPlaneData.mStride()) {}

void GMPVideoi420FrameImpl::GMPFramePlane::InitPlaneData(
    GMPPlaneData& aPlaneData) {
  aPlaneData.mOffset() = mOffset;
  aPlaneData.mSize() = mSize;
  aPlaneData.mStride() = mStride;
}

void GMPVideoi420FrameImpl::GMPFramePlane::Copy(uint8_t* aDst,
                                                int32_t aDstOffset,
                                                const uint8_t* aSrc,
                                                int32_t aSize,
                                                int32_t aStride) {
  mOffset = aDstOffset;
  mSize = aSize;
  mStride = aStride;
  if (aDst && aSrc && aSize > 0) {
    memcpy(aDst + aDstOffset, aSrc, aSize);
  }
}

GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(
    GMPVideoHostImpl* aHost,
    HostReportPolicy aReportPolicy /*= HostReportPolicy::None*/)
    : mReportPolicy(aReportPolicy),
      mHost(aHost),
      mWidth(0),
      mHeight(0),
      mTimestamp(0ll),
      mDuration(0ll) {
  MOZ_ASSERT(aHost);
}

GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(
    const GMPVideoi420FrameData& aFrameData, ipc::Shmem&& aShmemBuffer,
    GMPVideoHostImpl* aHost,
    HostReportPolicy aReportPolicy /*= HostReportPolicy::None*/)
    : mReportPolicy(aReportPolicy),
      mHost(aHost),
      mShmemBuffer(std::move(aShmemBuffer)),
      mYPlane(aFrameData.mYPlane()),
      mUPlane(aFrameData.mUPlane()),
      mVPlane(aFrameData.mVPlane()),
      mWidth(aFrameData.mWidth()),
      mHeight(aFrameData.mHeight()),
      mTimestamp(aFrameData.mTimestamp()),
      mUpdatedTimestamp(aFrameData.mUpdatedTimestamp()),
      mDuration(aFrameData.mDuration()) {
  MOZ_ASSERT(aHost);
}

GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(
    const GMPVideoi420FrameData& aFrameData, nsTArray<uint8_t>&& aArrayBuffer,
    GMPVideoHostImpl* aHost,
    HostReportPolicy aReportPolicy /*= HostReportPolicy::None*/)
    : mReportPolicy(aReportPolicy),
      mHost(aHost),
      mArrayBuffer(std::move(aArrayBuffer)),
      mYPlane(aFrameData.mYPlane()),
      mUPlane(aFrameData.mUPlane()),
      mVPlane(aFrameData.mVPlane()),
      mWidth(aFrameData.mWidth()),
      mHeight(aFrameData.mHeight()),
      mTimestamp(aFrameData.mTimestamp()),
      mUpdatedTimestamp(aFrameData.mUpdatedTimestamp()),
      mDuration(aFrameData.mDuration()) {
  MOZ_ASSERT(aHost);
}

GMPVideoi420FrameImpl::~GMPVideoi420FrameImpl() {
  if (mReportPolicy == HostReportPolicy::Destroyed) {
    mHost->MgrDecodedFrameDestroyed(this);
  }
  if (mShmemBuffer.IsWritable()) {
    mHost->MgrGiveShmem(GMPSharedMemClass::Decoded, std::move(mShmemBuffer));
  }
  // Proxy release to ensure that any synchronous runnables from the plugin can
  // first unblock the worker thread. If we destroy the plugin once this
  // reference is freed, we won't be blocked trying to join the worker thread.
  if (XRE_IsGMPluginProcess()) {
    NS_ProxyRelease("GMPVideoi420FrameImpl::~GMPVideoi420FrameImpl",
                    GetMainThreadSerialEventTarget(), mHost.forget(),
                    /* aAlwaysProxy */ true);
  }
}

void GMPVideoi420FrameImpl::InitFrameData(GMPVideoi420FrameData& aFrameData) {
  mYPlane.InitPlaneData(aFrameData.mYPlane());
  mUPlane.InitPlaneData(aFrameData.mUPlane());
  mVPlane.InitPlaneData(aFrameData.mVPlane());
  aFrameData.mWidth() = mWidth;
  aFrameData.mHeight() = mHeight;
  aFrameData.mTimestamp() = mTimestamp;
  aFrameData.mUpdatedTimestamp() = mUpdatedTimestamp;
  aFrameData.mDuration() = mDuration;
}

bool GMPVideoi420FrameImpl::InitFrameData(GMPVideoi420FrameData& aFrameData,
                                          ipc::Shmem& aShmemBuffer) {
  if (!mShmemBuffer.IsReadable()) {
    return false;
  }

  aShmemBuffer = mShmemBuffer;

  // This method is called right before Shmem is sent to another process.
  // We need to effectively zero out our member copy so that we don't
  // try to delete memory we don't own later.
  mShmemBuffer = ipc::Shmem();

  InitFrameData(aFrameData);
  return true;
}

bool GMPVideoi420FrameImpl::InitFrameData(GMPVideoi420FrameData& aFrameData,
                                          nsTArray<uint8_t>& aArrayBuffer) {
  if (mShmemBuffer.IsReadable()) {
    return false;
  }

  aArrayBuffer = std::move(mArrayBuffer);
  InitFrameData(aFrameData);
  return true;
}

GMPVideoFrameFormat GMPVideoi420FrameImpl::GetFrameFormat() {
  return kGMPI420VideoFrame;
}

void GMPVideoi420FrameImpl::Destroy() { delete this; }

/* static */
bool GMPVideoi420FrameImpl::CheckFrameData(
    const GMPVideoi420FrameData& aFrameData, size_t aBufferSize) {
  // We may be passed the "wrong" shmem (one smaller than the actual size).
  // This implies a bug or serious error on the child size.  Ignore this frame
  // if so. Note: Size() greater than expected is also an error, but with no
  // negative consequences
  if (aFrameData.mWidth() <= 0 || aFrameData.mHeight() <= 0) {
    return false;
  }
  int32_t half_width = (aFrameData.mWidth() + 1) / 2;
  int32_t half_height = (aFrameData.mHeight() + 1) / 2;

  // Check for negative offsets
  if ((aFrameData.mYPlane().mOffset() < 0) ||
      (aFrameData.mUPlane().mOffset() < 0) ||
      (aFrameData.mVPlane().mOffset() < 0)) {
    return false;
  }

  // Check for non-positive strides and sizes
  if ((aFrameData.mYPlane().mStride() <= 0) ||
      (aFrameData.mYPlane().mSize() <= 0) ||
      (aFrameData.mUPlane().mStride() <= 0) ||
      (aFrameData.mUPlane().mSize() <= 0) ||
      (aFrameData.mVPlane().mStride() <= 0) ||
      (aFrameData.mVPlane().mSize() <= 0)) {
    return false;
  }

  // Check stride requirements (must be at least as wide as the data)
  if ((aFrameData.mYPlane().mStride() < aFrameData.mWidth()) ||
      (aFrameData.mUPlane().mStride() < half_width) ||
      (aFrameData.mVPlane().mStride() < half_width)) {
    return false;
  }

  // Check that plane strides match.
  if (aFrameData.mUPlane().mStride() != aFrameData.mVPlane().mStride()) {
    return false;
  }

  // Validate plane end calculations
  auto y_plane_end = CheckedInt<int32_t>(aFrameData.mYPlane().mOffset()) +
                     aFrameData.mYPlane().mSize();
  auto u_plane_end = CheckedInt<int32_t>(aFrameData.mUPlane().mOffset()) +
                     aFrameData.mUPlane().mSize();
  auto v_plane_end = CheckedInt<int32_t>(aFrameData.mVPlane().mOffset()) +
                     aFrameData.mVPlane().mSize();

  if (!y_plane_end.isValid() || !u_plane_end.isValid() ||
      !v_plane_end.isValid()) {
    return false;
  }

  // Check that planes don't overlap
  if ((aFrameData.mUPlane().mOffset() < y_plane_end.value()) ||
      (aFrameData.mVPlane().mOffset() < u_plane_end.value())) {
    return false;
  }

  // Check buffer size
  if (aBufferSize < static_cast<size_t>(v_plane_end.value())) {
    return false;
  }

  // Validate size calculations
  auto y_expected_size = CheckedInt<int32_t>(aFrameData.mYPlane().mStride()) *
                         aFrameData.mHeight();
  auto u_expected_size =
      CheckedInt<int32_t>(aFrameData.mUPlane().mStride()) * half_height;
  auto v_expected_size =
      CheckedInt<int32_t>(aFrameData.mVPlane().mStride()) * half_height;

  if (!y_expected_size.isValid() || !u_expected_size.isValid() ||
      !v_expected_size.isValid()) {
    return false;
  }

  // Check that allocated sizes are sufficient
  if ((aFrameData.mYPlane().mSize() < y_expected_size.value()) ||
      (aFrameData.mUPlane().mSize() < u_expected_size.value()) ||
      (aFrameData.mVPlane().mSize() < v_expected_size.value())) {
    return false;
  }

  return true;
}

bool GMPVideoi420FrameImpl::CheckDimensions(int32_t aWidth, int32_t aHeight,
                                            int32_t aStride_y,
                                            int32_t aStride_u,
                                            int32_t aStride_v, int32_t aSize_y,
                                            int32_t aSize_u, int32_t aSize_v) {
  if (aWidth < 1 || aHeight < 1 || aStride_y < aWidth || aSize_y < 1 ||
      aSize_u < 1 || aSize_v < 1) {
    return false;
  }
  auto halfWidth = (CheckedInt<int32_t>(aWidth) + 1) / 2;
  if (!halfWidth.isValid() || aStride_u < halfWidth.value() ||
      aStride_v < halfWidth.value()) {
    return false;
  }
  auto height = CheckedInt<int32_t>(aHeight);
  auto halfHeight = (height + 1) / 2;
  auto minSizeY = height * aStride_y;
  auto minSizeU = halfHeight * aStride_u;
  auto minSizeV = halfHeight * aStride_v;
  auto totalSize = minSizeY + minSizeU + minSizeV;
  if (!minSizeY.isValid() || !minSizeU.isValid() || !minSizeV.isValid() ||
      !totalSize.isValid() || minSizeY.value() > aSize_y ||
      minSizeU.value() > aSize_u || minSizeV.value() > aSize_v) {
    return false;
  }
  return true;
}

bool GMPVideoi420FrameImpl::CheckDimensions(int32_t aWidth, int32_t aHeight,
                                            int32_t aStride_y,
                                            int32_t aStride_u,
                                            int32_t aStride_v) {
  int32_t half_width = (aWidth + 1) / 2;
  if (aWidth < 1 || aHeight < 1 || aStride_y < aWidth ||
      aStride_u < half_width || aStride_v < half_width ||
      !(CheckedInt<int32_t>(aHeight) * aStride_y +
        ((CheckedInt<int32_t>(aHeight) + 1) / 2) *
            (CheckedInt<int32_t>(aStride_u) + aStride_v))
           .isValid()) {
    return false;
  }
  return true;
}

const GMPVideoi420FrameImpl::GMPFramePlane* GMPVideoi420FrameImpl::GetPlane(
    GMPPlaneType aType) const {
  switch (aType) {
    case kGMPYPlane:
      return &mYPlane;
    case kGMPUPlane:
      return &mUPlane;
    case kGMPVPlane:
      return &mVPlane;
    default:
      MOZ_CRASH("Unknown plane type!");
  }
  return nullptr;
}

GMPVideoi420FrameImpl::GMPFramePlane* GMPVideoi420FrameImpl::GetPlane(
    GMPPlaneType aType) {
  switch (aType) {
    case kGMPYPlane:
      return &mYPlane;
    case kGMPUPlane:
      return &mUPlane;
    case kGMPVPlane:
      return &mVPlane;
    default:
      MOZ_CRASH("Unknown plane type!");
  }
  return nullptr;
}

GMPErr GMPVideoi420FrameImpl::MaybeResize(int32_t aNewSize) {
  if (aNewSize <= AllocatedSize()) {
    return GMPNoErr;
  }

  if (!mArrayBuffer.IsEmpty()) {
    if (!mArrayBuffer.SetLength(aNewSize, fallible)) {
      return GMPAllocErr;
    }
    return GMPNoErr;
  }

  ipc::Shmem new_mem;
  if (!mHost->MgrTakeShmem(GMPSharedMemClass::Decoded, aNewSize, &new_mem) &&
      !mArrayBuffer.SetLength(aNewSize, fallible)) {
    return GMPAllocErr;
  }

  if (mShmemBuffer.IsReadable()) {
    if (new_mem.IsWritable()) {
      memcpy(new_mem.get<uint8_t>(), mShmemBuffer.get<uint8_t>(),
             mShmemBuffer.Size<uint8_t>());
    }
    mHost->MgrGiveShmem(GMPSharedMemClass::Decoded, std::move(mShmemBuffer));
  }

  mShmemBuffer = new_mem;

  return GMPNoErr;
}

GMPErr GMPVideoi420FrameImpl::CreateEmptyFrame(int32_t aWidth, int32_t aHeight,
                                               int32_t aStride_y,
                                               int32_t aStride_u,
                                               int32_t aStride_v) {
  if (!CheckDimensions(aWidth, aHeight, aStride_y, aStride_u, aStride_v)) {
    return GMPGenericErr;
  }

  int32_t size_y = aStride_y * aHeight;
  int32_t half_height = (aHeight + 1) / 2;
  int32_t size_u = aStride_u * half_height;
  int32_t size_v = aStride_v * half_height;

  int32_t bufferSize = size_y + size_u + size_v;
  GMPErr err = MaybeResize(bufferSize);
  if (err != GMPNoErr) {
    return err;
  }

  mYPlane.mOffset = 0;
  mYPlane.mSize = size_y;
  mYPlane.mStride = aStride_y;

  mUPlane.mOffset = size_y;
  mUPlane.mSize = size_u;
  mUPlane.mStride = aStride_u;

  mVPlane.mOffset = size_y + size_u;
  mVPlane.mSize = size_v;
  mVPlane.mStride = aStride_v;

  mWidth = aWidth;
  mHeight = aHeight;
  mTimestamp = 0ll;
  mUpdatedTimestamp.reset();
  mDuration = 0ll;

  return GMPNoErr;
}

GMPErr GMPVideoi420FrameImpl::CreateFrame(
    int32_t aSize_y, const uint8_t* aBuffer_y, int32_t aSize_u,
    const uint8_t* aBuffer_u, int32_t aSize_v, const uint8_t* aBuffer_v,
    int32_t aWidth, int32_t aHeight, int32_t aStride_y, int32_t aStride_u,
    int32_t aStride_v) {
  MOZ_ASSERT(aBuffer_y);
  MOZ_ASSERT(aBuffer_u);
  MOZ_ASSERT(aBuffer_v);

  if (!CheckDimensions(aWidth, aHeight, aStride_y, aStride_u, aStride_v,
                       aSize_y, aSize_u, aSize_v)) {
    return GMPGenericErr;
  }

  int32_t bufferSize = aSize_y + aSize_u + aSize_v;
  GMPErr err = MaybeResize(bufferSize);
  if (err != GMPNoErr) {
    return err;
  }

  uint8_t* bufferPtr = Buffer();
  mYPlane.Copy(bufferPtr, 0, aBuffer_y, aSize_y, aStride_y);
  mUPlane.Copy(bufferPtr, aSize_y, aBuffer_u, aSize_u, aStride_u);
  mVPlane.Copy(bufferPtr, aSize_y + aSize_u, aBuffer_v, aSize_v, aStride_v);

  mWidth = aWidth;
  mHeight = aHeight;

  return GMPNoErr;
}

GMPErr GMPVideoi420FrameImpl::CopyFrame(const GMPVideoi420Frame& aFrame) {
  auto& f = static_cast<const GMPVideoi420FrameImpl&>(aFrame);

  int32_t bufferSize = f.mYPlane.mSize + f.mUPlane.mSize + f.mVPlane.mSize;
  if (bufferSize != AllocatedSize()) {
    return GMPGenericErr;
  }

  GMPErr err = MaybeResize(bufferSize);
  if (err != GMPNoErr) {
    return err;
  }

  mYPlane = f.mYPlane;
  mUPlane = f.mUPlane;
  mVPlane = f.mVPlane;
  mWidth = f.mWidth;
  mHeight = f.mHeight;
  mTimestamp = f.mTimestamp;
  mUpdatedTimestamp = f.mUpdatedTimestamp;
  mDuration = f.mDuration;

  memcpy(Buffer(), f.Buffer(), bufferSize);

  return GMPNoErr;
}

void GMPVideoi420FrameImpl::SwapFrame(GMPVideoi420Frame* aFrame) {
  auto f = static_cast<GMPVideoi420FrameImpl*>(aFrame);
  mArrayBuffer.SwapElements(f->mArrayBuffer);
  std::swap(mShmemBuffer, f->mShmemBuffer);
  std::swap(mYPlane, f->mYPlane);
  std::swap(mUPlane, f->mUPlane);
  std::swap(mVPlane, f->mVPlane);
  std::swap(mWidth, f->mWidth);
  std::swap(mHeight, f->mHeight);
  std::swap(mTimestamp, f->mTimestamp);
  std::swap(mUpdatedTimestamp, f->mUpdatedTimestamp);
  std::swap(mDuration, f->mDuration);
}

uint8_t* GMPVideoi420FrameImpl::Buffer() {
  if (mShmemBuffer.IsWritable()) {
    return mShmemBuffer.get<uint8_t>();
  }
  if (!mArrayBuffer.IsEmpty()) {
    return mArrayBuffer.Elements();
  }
  return nullptr;
}

const uint8_t* GMPVideoi420FrameImpl::Buffer() const {
  if (mShmemBuffer.IsReadable()) {
    return mShmemBuffer.get<uint8_t>();
  }
  if (!mArrayBuffer.IsEmpty()) {
    return mArrayBuffer.Elements();
  }
  return nullptr;
}

uint8_t* GMPVideoi420FrameImpl::Buffer(GMPPlaneType aType) {
  if (auto* p = GetPlane(aType)) {
    if (auto* buffer = Buffer()) {
      return buffer + p->mOffset;
    }
  }
  return nullptr;
}

const uint8_t* GMPVideoi420FrameImpl::Buffer(GMPPlaneType aType) const {
  if (const auto* p = GetPlane(aType)) {
    if (const auto* buffer = Buffer()) {
      return buffer + p->mOffset;
    }
  }
  return nullptr;
}

int32_t GMPVideoi420FrameImpl::AllocatedSize() const {
  if (mShmemBuffer.IsWritable()) {
    return static_cast<int32_t>(mShmemBuffer.Size<uint8_t>());
  }
  return static_cast<int32_t>(mArrayBuffer.Length());
}

int32_t GMPVideoi420FrameImpl::AllocatedSize(GMPPlaneType aType) const {
  if (const auto* p = GetPlane(aType)) {
    return p->mSize;
  }
  return -1;
}

int32_t GMPVideoi420FrameImpl::Stride(GMPPlaneType aType) const {
  if (const auto* p = GetPlane(aType)) {
    return p->mStride;
  }
  return -1;
}

GMPErr GMPVideoi420FrameImpl::SetWidth(int32_t aWidth) {
  if (!CheckDimensions(aWidth, mHeight, mYPlane.mStride, mUPlane.mStride,
                       mVPlane.mStride)) {
    return GMPGenericErr;
  }
  mWidth = aWidth;
  return GMPNoErr;
}

GMPErr GMPVideoi420FrameImpl::SetHeight(int32_t aHeight) {
  if (!CheckDimensions(mWidth, aHeight, mYPlane.mStride, mUPlane.mStride,
                       mVPlane.mStride)) {
    return GMPGenericErr;
  }
  mHeight = aHeight;
  return GMPNoErr;
}

int32_t GMPVideoi420FrameImpl::Width() const { return mWidth; }

int32_t GMPVideoi420FrameImpl::Height() const { return mHeight; }

void GMPVideoi420FrameImpl::SetTimestamp(uint64_t aTimestamp) {
  mTimestamp = aTimestamp;
}

uint64_t GMPVideoi420FrameImpl::Timestamp() const { return mTimestamp; }

void GMPVideoi420FrameImpl::SetUpdatedTimestamp(uint64_t aTimestamp) {
  mUpdatedTimestamp = Some(aTimestamp);
}

uint64_t GMPVideoi420FrameImpl::UpdatedTimestamp() const {
  return mUpdatedTimestamp ? *mUpdatedTimestamp : mTimestamp;
}

void GMPVideoi420FrameImpl::SetDuration(uint64_t aDuration) {
  mDuration = aDuration;
}

uint64_t GMPVideoi420FrameImpl::Duration() const { return mDuration; }

bool GMPVideoi420FrameImpl::IsZeroSize() const {
  return (mYPlane.mSize == 0 && mUPlane.mSize == 0 && mVPlane.mSize == 0);
}

void GMPVideoi420FrameImpl::ResetSize() {
  mYPlane.mSize = 0;
  mUPlane.mSize = 0;
  mVPlane.mSize = 0;
}

}  // namespace mozilla::gmp

Messung V0.5 in Prozent
C=93 H=99 G=95

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=752002