зеркало из https://github.com/mozilla/gecko-dev.git
229 строки
7.0 KiB
C++
229 строки
7.0 KiB
C++
/* -*- 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)
|
|
: ShmemRecycleAllocator(this),
|
|
mParent(aParent),
|
|
mOptions(aOptions),
|
|
mDecodeTaskQueue(aDecodeTaskQueue),
|
|
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(), 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());
|
|
// XXX: This copies the data into a buffer owned by the MediaRawData. Ideally
|
|
// we'd just take ownership of the shmem.
|
|
// Use the passed bufferSize in MediaRawDataIPDL since we can get a Shmem
|
|
// buffer from ShmemPool larger than the requested size.
|
|
|
|
// 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
|