summaryrefslogtreecommitdiffstats
path: root/dom/media/ipc/RemoteDecoderParent.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/media/ipc/RemoteDecoderParent.cpp228
1 files changed, 228 insertions, 0 deletions
diff --git a/dom/media/ipc/RemoteDecoderParent.cpp b/dom/media/ipc/RemoteDecoderParent.cpp
new file mode 100644
index 0000000000..2ca9eaa2d7
--- /dev/null
+++ b/dom/media/ipc/RemoteDecoderParent.cpp
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "RemoteDecoderParent.h"
+
+#include "RemoteDecoderManagerParent.h"
+#include "mozilla/Unused.h"
+
+namespace mozilla {
+
+RemoteDecoderParent::RemoteDecoderParent(
+ RemoteDecoderManagerParent* aParent,
+ const CreateDecoderParams::OptionSet& aOptions,
+ nsISerialEventTarget* aManagerThread, TaskQueue* aDecodeTaskQueue,
+ const Maybe<uint64_t>& aMediaEngineId, Maybe<TrackingId> aTrackingId)
+ : ShmemRecycleAllocator(this),
+ mParent(aParent),
+ mOptions(aOptions),
+ mDecodeTaskQueue(aDecodeTaskQueue),
+ mTrackingId(aTrackingId),
+ mMediaEngineId(aMediaEngineId),
+ mManagerThread(aManagerThread) {
+ MOZ_COUNT_CTOR(RemoteDecoderParent);
+ MOZ_ASSERT(OnManagerThread());
+ // We hold a reference to ourselves to keep us alive until IPDL
+ // explictly destroys us. There may still be refs held by
+ // tasks, but no new ones should be added after we're
+ // destroyed.
+ mIPDLSelfRef = this;
+}
+
+RemoteDecoderParent::~RemoteDecoderParent() {
+ MOZ_COUNT_DTOR(RemoteDecoderParent);
+}
+
+void RemoteDecoderParent::Destroy() {
+ MOZ_ASSERT(OnManagerThread());
+ mIPDLSelfRef = nullptr;
+}
+
+mozilla::ipc::IPCResult RemoteDecoderParent::RecvInit(
+ InitResolver&& aResolver) {
+ MOZ_ASSERT(OnManagerThread());
+ RefPtr<RemoteDecoderParent> self = this;
+ mDecoder->Init()->Then(
+ mManagerThread, __func__,
+ [self, resolver = std::move(aResolver)](
+ MediaDataDecoder::InitPromise::ResolveOrRejectValue&& aValue) {
+ if (!self->CanRecv()) {
+ // The promise to the child would have already been rejected.
+ return;
+ }
+ if (aValue.IsReject()) {
+ resolver(aValue.RejectValue());
+ return;
+ }
+ auto track = aValue.ResolveValue();
+ MOZ_ASSERT(track == TrackInfo::kAudioTrack ||
+ track == TrackInfo::kVideoTrack);
+ if (self->mDecoder) {
+ nsCString hardwareReason;
+ bool hardwareAccelerated =
+ self->mDecoder->IsHardwareAccelerated(hardwareReason);
+ resolver(InitCompletionIPDL{
+ track, self->mDecoder->GetDescriptionName(),
+ self->mDecoder->GetProcessName(), self->mDecoder->GetCodecName(),
+ hardwareAccelerated, hardwareReason,
+ self->mDecoder->NeedsConversion()});
+ }
+ });
+ return IPC_OK();
+}
+
+void RemoteDecoderParent::DecodeNextSample(
+ const RefPtr<ArrayOfRemoteMediaRawData>& aData, size_t aIndex,
+ MediaDataDecoder::DecodedData&& aOutput, DecodeResolver&& aResolver) {
+ MOZ_ASSERT(OnManagerThread());
+
+ if (!CanRecv()) {
+ // Avoid unnecessarily creating shmem objects later.
+ return;
+ }
+
+ if (!mDecoder) {
+ // We got shutdown or the child got destroyed.
+ aResolver(MediaResult(NS_ERROR_ABORT, __func__));
+ return;
+ }
+
+ if (aData->Count() == aIndex) {
+ DecodedOutputIPDL result;
+ MediaResult rv = ProcessDecodedData(std::move(aOutput), result);
+ if (NS_FAILED(rv)) {
+ aResolver(std::move(rv)); // Out of Memory.
+ } else {
+ aResolver(std::move(result));
+ }
+ return;
+ }
+
+ RefPtr<MediaRawData> rawData = aData->ElementAt(aIndex);
+ if (!rawData) {
+ // OOM
+ aResolver(MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__));
+ return;
+ }
+
+ mDecoder->Decode(rawData)->Then(
+ mManagerThread, __func__,
+ [self = RefPtr{this}, this, aData, aIndex, output = std::move(aOutput),
+ resolver = std::move(aResolver)](
+ MediaDataDecoder::DecodePromise::ResolveOrRejectValue&&
+ aValue) mutable {
+ if (aValue.IsReject()) {
+ resolver(aValue.RejectValue());
+ return;
+ }
+
+ output.AppendElements(std::move(aValue.ResolveValue()));
+
+ // Call again in case we have more data to decode.
+ DecodeNextSample(aData, aIndex + 1, std::move(output),
+ std::move(resolver));
+ });
+}
+
+mozilla::ipc::IPCResult RemoteDecoderParent::RecvDecode(
+ ArrayOfRemoteMediaRawData* aData, DecodeResolver&& aResolver) {
+ MOZ_ASSERT(OnManagerThread());
+ // If we are here, we know all previously returned DecodedOutputIPDL got
+ // used by the child. We can mark all previously sent ShmemBuffer as
+ // available again.
+ ReleaseAllBuffers();
+ MediaDataDecoder::DecodedData output;
+ DecodeNextSample(aData, 0, std::move(output), std::move(aResolver));
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult RemoteDecoderParent::RecvFlush(
+ FlushResolver&& aResolver) {
+ MOZ_ASSERT(OnManagerThread());
+ RefPtr<RemoteDecoderParent> self = this;
+ mDecoder->Flush()->Then(
+ mManagerThread, __func__,
+ [self, resolver = std::move(aResolver)](
+ MediaDataDecoder::FlushPromise::ResolveOrRejectValue&& aValue) {
+ self->ReleaseAllBuffers();
+ if (aValue.IsReject()) {
+ resolver(aValue.RejectValue());
+ } else {
+ resolver(MediaResult(NS_OK));
+ }
+ });
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult RemoteDecoderParent::RecvDrain(
+ DrainResolver&& aResolver) {
+ MOZ_ASSERT(OnManagerThread());
+ RefPtr<RemoteDecoderParent> self = this;
+ mDecoder->Drain()->Then(
+ mManagerThread, __func__,
+ [self, this, resolver = std::move(aResolver)](
+ MediaDataDecoder::DecodePromise::ResolveOrRejectValue&& aValue) {
+ ReleaseAllBuffers();
+ if (!self->CanRecv()) {
+ // Avoid unnecessarily creating shmem objects later.
+ return;
+ }
+ if (aValue.IsReject()) {
+ resolver(aValue.RejectValue());
+ return;
+ }
+ DecodedOutputIPDL output;
+ MediaResult rv =
+ ProcessDecodedData(std::move(aValue.ResolveValue()), output);
+ if (NS_FAILED(rv)) {
+ resolver(rv);
+ } else {
+ resolver(std::move(output));
+ }
+ });
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult RemoteDecoderParent::RecvShutdown(
+ ShutdownResolver&& aResolver) {
+ MOZ_ASSERT(OnManagerThread());
+ if (mDecoder) {
+ RefPtr<RemoteDecoderParent> self = this;
+ mDecoder->Shutdown()->Then(
+ mManagerThread, __func__,
+ [self, resolver = std::move(aResolver)](
+ const ShutdownPromise::ResolveOrRejectValue& aValue) {
+ MOZ_ASSERT(aValue.IsResolve());
+ self->ReleaseAllBuffers();
+ resolver(true);
+ });
+ }
+ mDecoder = nullptr;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult RemoteDecoderParent::RecvSetSeekThreshold(
+ const TimeUnit& aTime) {
+ MOZ_ASSERT(OnManagerThread());
+ mDecoder->SetSeekThreshold(aTime);
+ return IPC_OK();
+}
+
+void RemoteDecoderParent::ActorDestroy(ActorDestroyReason aWhy) {
+ MOZ_ASSERT(OnManagerThread());
+ if (mDecoder) {
+ mDecoder->Shutdown();
+ mDecoder = nullptr;
+ }
+ CleanupShmemRecycleAllocator();
+}
+
+bool RemoteDecoderParent::OnManagerThread() {
+ return mParent->OnManagerThread();
+}
+
+} // namespace mozilla