RemoteDecoderParent.cpp (7746B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 #include "RemoteDecoderParent.h" 7 8 #include "RemoteCDMParent.h" 9 #include "RemoteMediaManagerParent.h" 10 11 namespace mozilla { 12 13 RemoteDecoderParent::RemoteDecoderParent( 14 RemoteMediaManagerParent* aParent, 15 const CreateDecoderParams::OptionSet& aOptions, 16 nsISerialEventTarget* aManagerThread, TaskQueue* aDecodeTaskQueue, 17 const Maybe<uint64_t>& aMediaEngineId, Maybe<TrackingId> aTrackingId, 18 RemoteCDMParent* aCDM) 19 : ShmemRecycleAllocator(this), 20 mParent(aParent), 21 mOptions(aOptions), 22 mDecodeTaskQueue(aDecodeTaskQueue), 23 mCDM(aCDM), 24 mTrackingId(aTrackingId), 25 mMediaEngineId(aMediaEngineId), 26 mManagerThread(aManagerThread) { 27 MOZ_COUNT_CTOR(RemoteDecoderParent); 28 MOZ_ASSERT(OnManagerThread()); 29 // We hold a reference to ourselves to keep us alive until IPDL 30 // explicitly destroys us. There may still be refs held by 31 // tasks, but no new ones should be added after we're 32 // destroyed. 33 mIPDLSelfRef = this; 34 } 35 36 RemoteDecoderParent::~RemoteDecoderParent() { 37 MOZ_COUNT_DTOR(RemoteDecoderParent); 38 } 39 40 void RemoteDecoderParent::Destroy() { 41 MOZ_ASSERT(OnManagerThread()); 42 mIPDLSelfRef = nullptr; 43 } 44 45 mozilla::ipc::IPCResult RemoteDecoderParent::RecvInit( 46 InitResolver&& aResolver) { 47 MOZ_ASSERT(OnManagerThread()); 48 RefPtr<RemoteDecoderParent> self = this; 49 mDecoder->Init()->Then( 50 mManagerThread, __func__, 51 [self, resolver = std::move(aResolver)]( 52 MediaDataDecoder::InitPromise::ResolveOrRejectValue&& aValue) { 53 if (!self->CanRecv()) { 54 // The promise to the child would have already been rejected. 55 return; 56 } 57 if (aValue.IsReject()) { 58 resolver(aValue.RejectValue()); 59 return; 60 } 61 auto track = aValue.ResolveValue(); 62 MOZ_ASSERT(track == TrackInfo::kAudioTrack || 63 track == TrackInfo::kVideoTrack); 64 if (self->mDecoder) { 65 nsCString hardwareReason; 66 bool hardwareAccelerated = 67 self->mDecoder->IsHardwareAccelerated(hardwareReason); 68 nsTArray<DecodePropertyIPDL> properties; 69 for (size_t i = 0; i < MediaDataDecoder::sPropertyNameCount; i++) { 70 MediaDataDecoder::PropertyName name = 71 static_cast<MediaDataDecoder::PropertyName>(i); 72 if (auto v = self->mDecoder->GetDecodeProperty(name)) { 73 properties.AppendElement( 74 DecodePropertyIPDL(name, std::move(v.ref()))); 75 } 76 } 77 resolver(InitCompletionIPDL{ 78 track, self->mDecoder->GetDescriptionName(), 79 self->mDecoder->GetProcessName(), self->mDecoder->GetCodecName(), 80 hardwareAccelerated, hardwareReason, 81 self->mDecoder->NeedsConversion(), 82 self->mDecoder->ShouldDecoderAlwaysBeRecycled(), properties}); 83 } 84 }); 85 return IPC_OK(); 86 } 87 88 void RemoteDecoderParent::DecodeNextSample( 89 const RefPtr<ArrayOfRemoteMediaRawData>& aData, size_t aIndex, 90 MediaDataDecoder::DecodedData&& aOutput, DecodeResolver&& aResolver) { 91 MOZ_ASSERT(OnManagerThread()); 92 93 if (!CanRecv()) { 94 // Avoid unnecessarily creating shmem objects later. 95 return; 96 } 97 98 if (!mDecoder) { 99 // We got shutdown or the child got destroyed. 100 aResolver(MediaResult(NS_ERROR_ABORT, __func__)); 101 return; 102 } 103 104 if (aData->Count() == aIndex) { 105 DecodedOutputIPDL result; 106 MediaResult rv = ProcessDecodedData(std::move(aOutput), result); 107 if (NS_FAILED(rv)) { 108 aResolver(std::move(rv)); // Out of Memory. 109 } else { 110 aResolver(std::move(result)); 111 } 112 return; 113 } 114 115 RefPtr<MediaRawData> rawData = aData->ElementAt(aIndex); 116 if (!rawData) { 117 // OOM 118 aResolver(MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__)); 119 return; 120 } 121 122 mDecoder->Decode(rawData)->Then( 123 mManagerThread, __func__, 124 [self = RefPtr{this}, this, aData, aIndex, output = std::move(aOutput), 125 resolver = std::move(aResolver)]( 126 MediaDataDecoder::DecodePromise::ResolveOrRejectValue&& 127 aValue) mutable { 128 if (aValue.IsReject()) { 129 resolver(aValue.RejectValue()); 130 return; 131 } 132 133 output.AppendElements(std::move(aValue.ResolveValue())); 134 135 // Call again in case we have more data to decode. 136 DecodeNextSample(aData, aIndex + 1, std::move(output), 137 std::move(resolver)); 138 }); 139 } 140 141 mozilla::ipc::IPCResult RemoteDecoderParent::RecvDecode( 142 ArrayOfRemoteMediaRawData* aData, DecodeResolver&& aResolver) { 143 MOZ_ASSERT(OnManagerThread()); 144 // If we are here, we know all previously returned DecodedOutputIPDL got 145 // used by the child. We can mark all previously sent ShmemBuffer as 146 // available again. 147 ReleaseAllBuffers(); 148 MediaDataDecoder::DecodedData output; 149 DecodeNextSample(aData, 0, std::move(output), std::move(aResolver)); 150 151 return IPC_OK(); 152 } 153 154 mozilla::ipc::IPCResult RemoteDecoderParent::RecvFlush( 155 FlushResolver&& aResolver) { 156 MOZ_ASSERT(OnManagerThread()); 157 RefPtr<RemoteDecoderParent> self = this; 158 mDecoder->Flush()->Then( 159 mManagerThread, __func__, 160 [self, resolver = std::move(aResolver)]( 161 MediaDataDecoder::FlushPromise::ResolveOrRejectValue&& aValue) { 162 self->ReleaseAllBuffers(); 163 if (aValue.IsReject()) { 164 resolver(aValue.RejectValue()); 165 } else { 166 resolver(MediaResult(NS_OK)); 167 } 168 }); 169 170 return IPC_OK(); 171 } 172 173 mozilla::ipc::IPCResult RemoteDecoderParent::RecvDrain( 174 DrainResolver&& aResolver) { 175 MOZ_ASSERT(OnManagerThread()); 176 RefPtr<RemoteDecoderParent> self = this; 177 mDecoder->Drain()->Then( 178 mManagerThread, __func__, 179 [self, this, resolver = std::move(aResolver)]( 180 MediaDataDecoder::DecodePromise::ResolveOrRejectValue&& aValue) { 181 ReleaseAllBuffers(); 182 if (!self->CanRecv()) { 183 // Avoid unnecessarily creating shmem objects later. 184 return; 185 } 186 if (aValue.IsReject()) { 187 resolver(aValue.RejectValue()); 188 return; 189 } 190 DecodedOutputIPDL output; 191 MediaResult rv = 192 ProcessDecodedData(std::move(aValue.ResolveValue()), output); 193 if (NS_FAILED(rv)) { 194 resolver(rv); 195 } else { 196 resolver(std::move(output)); 197 } 198 }); 199 return IPC_OK(); 200 } 201 202 mozilla::ipc::IPCResult RemoteDecoderParent::RecvShutdown( 203 ShutdownResolver&& aResolver) { 204 MOZ_ASSERT(OnManagerThread()); 205 if (mDecoder) { 206 RefPtr<RemoteDecoderParent> self = this; 207 mDecoder->Shutdown()->Then( 208 mManagerThread, __func__, 209 [self, resolver = std::move(aResolver)]( 210 const ShutdownPromise::ResolveOrRejectValue& aValue) { 211 MOZ_ASSERT(aValue.IsResolve()); 212 self->ReleaseAllBuffers(); 213 resolver(true); 214 }); 215 } 216 mDecoder = nullptr; 217 return IPC_OK(); 218 } 219 220 mozilla::ipc::IPCResult RemoteDecoderParent::RecvSetSeekThreshold( 221 const TimeUnit& aTime) { 222 MOZ_ASSERT(OnManagerThread()); 223 mDecoder->SetSeekThreshold(aTime); 224 return IPC_OK(); 225 } 226 227 void RemoteDecoderParent::ActorDestroy(ActorDestroyReason aWhy) { 228 MOZ_ASSERT(OnManagerThread()); 229 if (mDecoder) { 230 mDecoder->Shutdown(); 231 mDecoder = nullptr; 232 } 233 CleanupShmemRecycleAllocator(); 234 } 235 236 bool RemoteDecoderParent::OnManagerThread() { 237 return mParent->OnManagerThread(); 238 } 239 240 } // namespace mozilla