Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/media/ipc/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 18 kB image not shown  

Quelle  RemoteMediaDataEncoder.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 "RemoteMediaDataEncoder.h"

#include "RemoteDecodeUtils.h"
#include "mozilla/dom/WebCodecsUtils.h"

namespace mozilla {

extern LazyLogModule sPEMLog;

#define AUTO_MARKER(var, postfix) \
  AutoWebCodecsMarker var("RemoteMediaDataEncoder", postfix);

#define LOGE(fmt, ...)                           \
  MOZ_LOG_FMT(sPEMLog, mozilla::LogLevel::Error, \
              "[RemoteMediaDataEncoder] {}: " fmt, __func__, __VA_ARGS__)
#define LOGW(fmt, ...)                             \
  MOZ_LOG_FMT(sPEMLog, mozilla::LogLevel::Warning, \
              "[RemoteMediaDataEncoder] {}: " fmt, __func__, __VA_ARGS__)
#define LOGD(fmt, ...)                           \
  MOZ_LOG_FMT(sPEMLog, mozilla::LogLevel::Debug, \
              "[RemoteMediaDataEncoder] {}: " fmt, __func__, __VA_ARGS__)
#define LOGV(fmt, ...)                             \
  MOZ_LOG_FMT(sPEMLog, mozilla::LogLevel::Verbose, \
              "[RemoteMediaDataEncoder] {}: " fmt, __func__, __VA_ARGS__)

RemoteMediaDataEncoder::RemoteMediaDataEncoder(
    nsCOMPtr<nsISerialEventTarget>&& aThread, RemoteMediaIn aLocation)
    : mChild(MakeRefPtr<RemoteMediaDataEncoderChild>()),
      mThread(std::move(aThread)),
      mLocation(aLocation) {
  LOGV("[{}] child {}", fmt::ptr(this), fmt::ptr(mChild.get()));
}

RemoteMediaDataEncoder::~RemoteMediaDataEncoder() {
  LOGV("[{}]", fmt::ptr(this));
  // If this is the last reference, and we still have an actor, then we know
  // that the last reference is solely due to the IPDL reference. Dispatch to
  // the owning thread to delete that so that we can clean up.
  MutexAutoLock lock(mMutex);
  if (mNeedsShutdown) {
    mNeedsShutdown = false;
    mThread->Dispatch(
        NS_NewRunnableFunction(__func__, [child = RefPtr{mChild}]() {
          if (child->CanSend()) {
            LOGD("[{}] destroying final self reference", fmt::ptr(child.get()));
            child->Send__delete__(child);
          }
        }));
  }
}

RefPtr<PlatformEncoderModule::CreateEncoderPromise>
RemoteMediaDataEncoder::Construct() {
  {
    MutexAutoLock lock(mMutex);
    mNeedsShutdown = mChild->CanSend();
  }

  LOGD("[{}] send", fmt::ptr(this));
  mChild->SendConstruct()->Then(
      mThread, __func__,
      [self = RefPtr{this}](MediaResult aResult) {
        LOGD("[{}] Construct resolved code={}", fmt::ptr(self.get()),
             aResult.Description());
        self->mHasConstructed = true;
        self->mConstructPromise.Resolve(self, __func__);
        if (!self->mInitPromise.IsEmpty()) {
          self->DoSendInit();
        }
      },
      [self = RefPtr{this}](const mozilla::ipc::ResponseRejectReason& aReason) {
        LOGE("[{}] Construct ipc failed", fmt::ptr(self.get()));
        RemoteMediaManagerChild::HandleRejectionError(
            self->GetManager(), self->mLocation, aReason,
            [self](const MediaResult& aError) {
              self->mConstructPromise.RejectIfExists(aError, __func__);
              self->mInitPromise.RejectIfExists(aError, __func__);
            });
      });
  return mConstructPromise.Ensure(__func__);
}

void RemoteMediaDataEncoder::DoSendInit() {
  MOZ_ASSERT(mHasConstructed);

  LOGD("[{}] Init send", fmt::ptr(this));
  mChild->SendInit()->Then(
      mThread, __func__,
      [self = RefPtr{this}](EncodeInitResultIPDL&& aResponse) {
        if (aResponse.type() == EncodeInitResultIPDL::TMediaResult) {
          LOGE("[{}] Init resolved code={}", fmt::ptr(self.get()),
               aResponse.get_MediaResult().Description());
          self->mInitPromise.Reject(aResponse.get_MediaResult(), __func__);
          return;
        }

        const auto& initResponse = aResponse.get_EncodeInitCompletionIPDL();

        LOGD("[{}] Init resolved hwAccel={} desc=\"{}\"", fmt::ptr(self.get()),
             initResponse.hardware(), initResponse.description().get());
        MutexAutoLock lock(self->mMutex);
        self->mDescription = initResponse.description();
        self->mDescription.AppendFmt(
            " ({})", RemoteMediaInToStr(self->GetManager()->Location()));

        self->mIsHardwareAccelerated = initResponse.hardware();
        self->mHardwareAcceleratedReason = initResponse.hardwareReason();
        self->mInitPromise.ResolveIfExists(true, __func__);
      },
      [self = RefPtr{this}](const mozilla::ipc::ResponseRejectReason& aReason) {
        LOGE("[{}] Init ipc failed", fmt::ptr(self.get()));
        RemoteMediaManagerChild::HandleRejectionError(
            self->GetManager(), self->mLocation, aReason,
            [self](const MediaResult& aError) {
              self->mInitPromise.RejectIfExists(aError, __func__);
            });
      });
}

RefPtr<MediaDataEncoder::InitPromise> RemoteMediaDataEncoder::Init() {
  return InvokeAsync(
      mThread, __func__,
      [self = RefPtr{this}]() -> RefPtr<MediaDataEncoder::InitPromise> {
        // If the owner called Init before the Construct response, then just
        // create promise and wait for that first. This can happen if the owner
        // created the encoder via RemoteEncoderModule's CreateAudioEncoder or
        // CreateVideoEncoder instead of AsyncCreateEncoder.
        //
        // mConstructPromise might not have been created yet either because we
        // may have delayed dispatching related to the process launching.
        // mHasConstructed will be set when the construct IPDL call returns.
        if (self->mHasConstructed) {
          self->DoSendInit();
        } else {
          LOGD("[{}] Init deferred, still constructing", fmt::ptr(self.get()));
        }
        return self->mInitPromise.Ensure(__func__);
      });
}

RefPtr<PRemoteEncoderChild::EncodePromise> RemoteMediaDataEncoder::DoSendEncode(
    const nsTArray<RefPtr<MediaData>>& aSamples, ShmemRecycleTicket* aTicket) {
  if (mChild->HasRemoteCrashed()) {
    LOGE("[{}] remote crashed", fmt::ptr(this));
    nsresult err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_UTILITY_ERR;
    if (mLocation == RemoteMediaIn::GpuProcess ||
        mLocation == RemoteMediaIn::RddProcess) {
      err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_RDD_OR_GPU_ERR;
    } else if (mLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) {
      err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_MF_CDM_ERR;
    }
    return PRemoteEncoderChild::EncodePromise::CreateAndResolve(
        MediaResult(err, "Remote process crashed"), __func__);
  }

  if (aSamples.IsEmpty()) {
    LOGE("[{}] no samples to encode", fmt::ptr(this));
    return PRemoteEncoderChild::EncodePromise::CreateAndResolve(
        MediaResult(NS_ERROR_INVALID_ARG), __func__);
  }

  MediaData::Type type = aSamples[0]->mType;

  if (type == MediaData::Type::AUDIO_DATA) {
    nsTArray<RefPtr<AudioData>> audioSamples;
    for (auto& sample : aSamples) {
      audioSamples.AppendElement(sample->As<AudioData>());
    }

    auto samples = MakeRefPtr<ArrayOfRemoteAudioData>();
    if (!samples->Fill(audioSamples, [&](size_t aSize) {
          return mChild->AllocateBuffer(aSize, aTicket);
        })) {
      LOGE("[{}] buffer audio failed", fmt::ptr(this));
      return PRemoteEncoderChild::EncodePromise::CreateAndResolve(
          MediaResult(NS_ERROR_OUT_OF_MEMORY), __func__);
    }
    LOGD("[{}] send {} audio samples", fmt::ptr(this), audioSamples.Length());
    return mChild->SendEncode(std::move(samples));
  }

  if (type == MediaData::Type::VIDEO_DATA) {
    nsTArray<RefPtr<VideoData>> videoSamples;
    for (auto& sample : aSamples) {
      videoSamples.AppendElement(sample->As<VideoData>());
    }

    auto samples = MakeRefPtr<ArrayOfRemoteVideoData>();
    for (const auto& videoSample : videoSamples) {
      if (layers::Image* videoImage = videoSample->mImage) {
        // We don't need to supply a working deallocator because the ticket is
        // responsible for that cleanup.
        layers::SurfaceDescriptor sd;
        nsresult rv = videoImage->BuildSurfaceDescriptorGPUVideoOrBuffer(
            sd, layers::Image::BuildSdbFlags::Default,
            Some(GetVideoBridgeSourceFromRemoteMediaIn(mLocation)),
            [&](uint32_t aBufferSize) {
              ShmemBuffer buffer = mChild->AllocateBuffer(aBufferSize, aTicket);
              if (buffer.Valid()) {
                return layers::MemoryOrShmem(std::move(buffer.Get()));
              }
              return layers::MemoryOrShmem();
            },
            [&](layers::MemoryOrShmem&&) {});

        if (NS_WARN_IF(NS_FAILED(rv))) {
          LOGE("[{}] buffer video failed, code={}", fmt::ptr(this),
               fmt::enums::format_as(rv));
          return PRemoteEncoderChild::EncodePromise::CreateAndResolve(
              MediaResult(rv), __func__);
        }

        samples->Append(RemoteVideoData(
            MediaDataIPDL(videoSample->mOffset, videoSample->mTime,
                          videoSample->mTimecode, videoSample->mDuration,
                          videoSample->mKeyframe),
            videoSample->mDisplay, RemoteImageHolder(std::move(sd)),
            videoSample->mFrameID));
      }
    }
    LOGD("[{}] send {} video samples", fmt::ptr(this), videoSamples.Length());
    return mChild->SendEncode(std::move(samples));
  }

  return PRemoteEncoderChild::EncodePromise::CreateAndResolve(
      MediaResult(NS_ERROR_INVALID_ARG), __func__);
}

RefPtr<MediaDataEncoder::EncodePromise> RemoteMediaDataEncoder::Encode(
    const MediaData* aSample) {
  return Encode(nsTArray<RefPtr<MediaData>>{const_cast<MediaData*>(aSample)});
}

RefPtr<MediaDataEncoder::EncodePromise> RemoteMediaDataEncoder::Encode(
    nsTArray<RefPtr<MediaData>>&& aSamples) {
  return InvokeAsync(
      mThread, __func__,
      [self = RefPtr{this}, samples = std::move(aSamples)]()
          -> RefPtr<MediaDataEncoder::EncodePromise> {
        auto promise =
            MakeRefPtr<MediaDataEncoder::EncodePromise::Private>(__func__);
        auto ticket = MakeRefPtr<ShmemRecycleTicket>();
        self->DoSendEncode(samples, ticket)
            ->Then(
                self->mThread, __func__,
                [self, promise, ticket](EncodeResultIPDL&& aResponse) {
                  self->mChild->ReleaseTicket(ticket);

                  if (aResponse.type() == EncodeResultIPDL::TMediaResult) {
                    LOGD("[{}] Encode resolved, code={}", fmt::ptr(self.get()),
                         aResponse.get_MediaResult().Description());
                    promise->Reject(aResponse.get_MediaResult(), __func__);
                    return;
                  }

                  const auto& encodeResponse =
                      aResponse.get_EncodeCompletionIPDL();

                  nsTArray<RefPtr<MediaRawData>> samples;
                  if (auto remoteSamples = encodeResponse.samples()) {
                    size_t count = remoteSamples->Count();
                    samples.SetCapacity(count);
                    for (size_t i = 0; i < count; ++i) {
                      AUTO_MARKER(marker, ".Encode.ElementAt");
                      if (RefPtr<MediaRawData> sample =
                              remoteSamples->ElementAt(i)) {
                        marker.End();
                        samples.AppendElement(std::move(sample));
                      } else {
                        LOGE(
                            "[{}] Encode resolved, failed to buffer "
                            "samples",
                            fmt::ptr(self.get()));
                        promise->Reject(MediaResult(NS_ERROR_OUT_OF_MEMORY),
                                        __func__);
                        return;
                      }
                    }
                  }

                  LOGV("[{}] Encode resolved, {} samples", fmt::ptr(self.get()),
                       samples.Length());
                  promise->Resolve(std::move(samples), __func__);
                  self->mChild->SendReleaseTicket(encodeResponse.ticketId());
                },
                [self, promise,
                 ticket](const mozilla::ipc::ResponseRejectReason& aReason) {
                  LOGE("[{}] Encode ipc failed", fmt::ptr(self.get()));
                  self->mChild->ReleaseTicket(ticket);
                  RemoteMediaManagerChild::HandleRejectionError(
                      self->GetManager(), self->mLocation, aReason,
                      [promise](const MediaResult& aError) {
                        promise->Reject(aError, __func__);
                      });
                });
        return promise;
      });
}

RefPtr<MediaDataEncoder::EncodePromise> RemoteMediaDataEncoder::Drain() {
  return InvokeAsync(
      mThread, __func__,
      [self = RefPtr{this}]() -> RefPtr<MediaDataEncoder::EncodePromise> {
        LOGD("[{}] Drain send", fmt::ptr(self.get()));
        self->mChild->SendDrain()->Then(
            self->mThread, __func__,
            [self](EncodeResultIPDL&& aResponse) {
              if (aResponse.type() == EncodeResultIPDL::TMediaResult) {
                LOGE("[{}] Drain resolved, code={}", fmt::ptr(self.get()),
                     aResponse.get_MediaResult().Description());
                self->mDrainPromise.Reject(aResponse.get_MediaResult(),
                                           __func__);
                return;
              }

              const auto& encodeResponse = aResponse.get_EncodeCompletionIPDL();

              nsTArray<RefPtr<MediaRawData>> samples;
              if (auto remoteSamples = encodeResponse.samples()) {
                size_t count = remoteSamples->Count();
                samples.SetCapacity(count);
                for (size_t i = 0; i < count; ++i) {
                  if (RefPtr<MediaRawData> sample =
                          remoteSamples->ElementAt(i)) {
                    samples.AppendElement(std::move(sample));
                  } else {
                    LOGE("[{}] Drain resolved, failed to buffer samples",
                         fmt::ptr(self.get()));
                    self->mDrainPromise.Reject(
                        MediaResult(NS_ERROR_OUT_OF_MEMORY), __func__);
                    return;
                  }
                }
              }

              LOGD("[{}] Drain resolved, {} samples", fmt::ptr(self.get()),
                   samples.Length());
              self->mDrainPromise.Resolve(std::move(samples), __func__);
              self->mChild->SendReleaseTicket(encodeResponse.ticketId());
            },
            [self](const mozilla::ipc::ResponseRejectReason& aReason) {
              LOGE("[{}] Drain ipc failed", fmt::ptr(self.get()));
              RemoteMediaManagerChild::HandleRejectionError(
                  self->GetManager(), self->mLocation, aReason,
                  [self](const MediaResult& aError) {
                    self->mDrainPromise.RejectIfExists(aError, __func__);
                  });
            });
        return self->mDrainPromise.Ensure(__func__);
      });
}

RefPtr<MediaDataEncoder::ReconfigurationPromise>
RemoteMediaDataEncoder::Reconfigure(
    const RefPtr<const EncoderConfigurationChangeList>& aConfigurationChanges) {
  return InvokeAsync(
      mThread, __func__,
      [self = RefPtr{this}, changes = RefPtr{aConfigurationChanges}]()
          -> RefPtr<MediaDataEncoder::ReconfigurationPromise> {
        LOGD("[{}] Reconfigure send", fmt::ptr(self.get()));
        self->mChild
            ->SendReconfigure(
                const_cast<EncoderConfigurationChangeList*>(changes.get()))
            ->Then(
                self->mThread, __func__,
                [self](const MediaResult& aResult) {
                  if (NS_SUCCEEDED(aResult)) {
                    LOGD("[{}] Reconfigure resolved", fmt::ptr(self.get()));
                    self->mReconfigurePromise.ResolveIfExists(true, __func__);
                  } else {
                    LOGD("[{}] Reconfigure resolved, code={}",
                         fmt::ptr(self.get()), aResult.Description());
                    self->mReconfigurePromise.RejectIfExists(aResult, __func__);
                  }
                },
                [self](const mozilla::ipc::ResponseRejectReason& aReason) {
                  LOGE("[{}] Reconfigure ipc failed", fmt::ptr(self.get()));
                  RemoteMediaManagerChild::HandleRejectionError(
                      self->GetManager(), self->mLocation, aReason,
                      [self](const MediaResult& aError) {
                        self->mReconfigurePromise.RejectIfExists(aError,
                                                                 __func__);
                      });
                });
        return self->mReconfigurePromise.Ensure(__func__);
      });
}

RefPtr<mozilla::ShutdownPromise> RemoteMediaDataEncoder::Shutdown() {
  {
    MutexAutoLock lock(mMutex);
    mNeedsShutdown = false;
  }

  return InvokeAsync(
      mThread, __func__,
      [self = RefPtr{this}]() -> RefPtr<mozilla::ShutdownPromise> {
        LOGD("[{}] Shutdown send", fmt::ptr(self.get()));
        self->mChild->SendShutdown()->Then(
            self->mThread, __func__,
            [self](PRemoteEncoderChild::ShutdownPromise::ResolveOrRejectValue&&
                       aValue) {
              LOGD("[{}] Shutdown resolved", fmt::ptr(self.get()));
              if (self->mChild->CanSend()) {
                self->mChild->Send__delete__(self->mChild);
              }
              self->mShutdownPromise.Resolve(aValue.IsResolve(), __func__);
            });
        return self->mShutdownPromise.Ensure(__func__);
      });
}

RefPtr<GenericPromise> RemoteMediaDataEncoder::SetBitrate(
    uint32_t aBitsPerSec) {
  return InvokeAsync(
      mThread, __func__,
      [self = RefPtr{this}, aBitsPerSec]() -> RefPtr<GenericPromise> {
        auto promise = MakeRefPtr<GenericPromise::Private>(__func__);
        self->mChild->SendSetBitrate(aBitsPerSec)
            ->Then(
                self->mThread, __func__,
                [promise](const nsresult& aRv) {
                  if (NS_SUCCEEDED(aRv)) {
                    promise->Resolve(true, __func__);
                  } else {
                    promise->Reject(aRv, __func__);
                  }
                },
                [self,
                 promise](const mozilla::ipc::ResponseRejectReason& aReason) {
                  LOGE("[{}] SetBitrate ipc failed", fmt::ptr(self.get()));
                  RemoteMediaManagerChild::HandleRejectionError(
                      self->GetManager(), self->mLocation, aReason,
                      [promise](const MediaResult& aError) {
                        promise->Reject(aError.Code(), __func__);
                      });
                });
        return promise.forget();
      });
}

RemoteMediaManagerChild* RemoteMediaDataEncoder::GetManager() {
  if (!mChild->CanSend()) {
    return nullptr;
  }
  return static_cast<RemoteMediaManagerChild*>(mChild->Manager());
}

bool RemoteMediaDataEncoder::IsHardwareAccelerated(
    nsACString& aFailureReason) const {
  MutexAutoLock lock(mMutex);
  aFailureReason = mHardwareAcceleratedReason;
  return mIsHardwareAccelerated;
}

nsCString RemoteMediaDataEncoder::GetDescriptionName() const {
  MutexAutoLock lock(mMutex);
  return mDescription;
}

#undef AUTO_MARKER

}  // namespace mozilla

Messung V0.5 in Prozent
C=98 H=94 G=95

¤ Dauer der Verarbeitung: 0.6 Sekunden  ¤

*© 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.