no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / media / ipc / RemoteMediaData.cpp
blob6334a3bd6d5570d9a823ca6426bbbd3b07f0431f
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/. */
7 #include "RemoteMediaData.h"
9 #include "PerformanceRecorder.h"
10 #include "mozilla/CheckedInt.h"
11 #include "mozilla/dom/MediaIPCUtils.h"
12 #include "mozilla/ipc/Shmem.h"
14 namespace mozilla {
16 bool RemoteArrayOfByteBuffer::AllocateShmem(
17 size_t aSize, std::function<ShmemBuffer(size_t)>& aAllocator) {
18 ShmemBuffer buffer = aAllocator(aSize);
19 if (!buffer.Valid()) {
20 return false;
22 mBuffers.emplace(std::move(buffer.Get()));
23 return true;
26 uint8_t* RemoteArrayOfByteBuffer::BuffersStartAddress() const {
27 MOZ_ASSERT(mBuffers);
28 return mBuffers->get<uint8_t>();
31 bool RemoteArrayOfByteBuffer::Check(size_t aOffset, size_t aSizeInBytes) const {
32 return mBuffers && mBuffers->IsReadable() &&
33 detail::IsAddValid(aOffset, aSizeInBytes) &&
34 aOffset + aSizeInBytes <= mBuffers->Size<uint8_t>();
37 void RemoteArrayOfByteBuffer::Write(size_t aOffset, const void* aSourceAddr,
38 size_t aSizeInBytes) {
39 if (!aSizeInBytes) {
40 return;
42 MOZ_DIAGNOSTIC_ASSERT(Check(aOffset, aSizeInBytes),
43 "Allocated Shmem is too small");
44 memcpy(BuffersStartAddress() + aOffset, aSourceAddr, aSizeInBytes);
47 RemoteArrayOfByteBuffer::RemoteArrayOfByteBuffer() = default;
49 RemoteArrayOfByteBuffer::RemoteArrayOfByteBuffer(
50 const nsTArray<RefPtr<MediaByteBuffer>>& aArray,
51 std::function<ShmemBuffer(size_t)>& aAllocator) {
52 // Determine the total size we will need for this object.
53 size_t totalSize = 0;
54 for (const auto& buffer : aArray) {
55 if (buffer) {
56 totalSize += buffer->Length();
59 if (totalSize) {
60 if (!AllocateShmem(totalSize, aAllocator)) {
61 return;
64 size_t offset = 0;
65 for (const auto& buffer : aArray) {
66 size_t sizeBuffer = buffer ? buffer->Length() : 0;
67 if (totalSize && sizeBuffer) {
68 Write(offset, buffer->Elements(), sizeBuffer);
70 mOffsets.AppendElement(OffsetEntry{offset, sizeBuffer});
71 offset += sizeBuffer;
73 mIsValid = true;
76 RemoteArrayOfByteBuffer& RemoteArrayOfByteBuffer::operator=(
77 RemoteArrayOfByteBuffer&& aOther) noexcept {
78 mIsValid = aOther.mIsValid;
79 mBuffers = std::move(aOther.mBuffers);
80 mOffsets = std::move(aOther.mOffsets);
81 aOther.mIsValid = false;
82 return *this;
85 RemoteArrayOfByteBuffer::~RemoteArrayOfByteBuffer() = default;
87 already_AddRefed<MediaByteBuffer> RemoteArrayOfByteBuffer::MediaByteBufferAt(
88 size_t aIndex) const {
89 MOZ_ASSERT(aIndex < Count());
90 const OffsetEntry& entry = mOffsets[aIndex];
91 if (!mBuffers || !std::get<1>(entry)) {
92 // It's an empty one.
93 return nullptr;
95 size_t entrySize = std::get<1>(entry);
96 if (!Check(std::get<0>(entry), entrySize)) {
97 // This Shmem is corrupted and can't contain the data we are about to
98 // retrieve. We return an empty array instead of asserting to allow for
99 // recovery.
100 return nullptr;
102 RefPtr<MediaByteBuffer> buffer = new MediaByteBuffer(entrySize);
103 buffer->SetLength(entrySize);
104 memcpy(buffer->Elements(), mBuffers->get<uint8_t>() + std::get<0>(entry),
105 entrySize);
106 return buffer.forget();
109 /*static */ void ipc::IPDLParamTraits<RemoteArrayOfByteBuffer>::Write(
110 IPC::MessageWriter* aWriter, ipc::IProtocol* aActor,
111 const RemoteArrayOfByteBuffer& aVar) {
112 WriteIPDLParam(aWriter, aActor, aVar.mIsValid);
113 // We need the following gymnastic as the Shmem transfered over IPC will be
114 // revoked. We must create a temporary one instead so that it can be recycled
115 // later back into the original ShmemPool.
116 if (aVar.mBuffers) {
117 WriteIPDLParam(aWriter, aActor, Some(ipc::Shmem(*aVar.mBuffers)));
118 } else {
119 WriteIPDLParam(aWriter, aActor, Maybe<ipc::Shmem>());
121 WriteIPDLParam(aWriter, aActor, aVar.mOffsets);
124 /* static */ bool ipc::IPDLParamTraits<RemoteArrayOfByteBuffer>::Read(
125 IPC::MessageReader* aReader, mozilla::ipc::IProtocol* aActor,
126 RemoteArrayOfByteBuffer* aVar) {
127 return ReadIPDLParam(aReader, aActor, &aVar->mIsValid) &&
128 ReadIPDLParam(aReader, aActor, &aVar->mBuffers) &&
129 ReadIPDLParam(aReader, aActor, &aVar->mOffsets);
132 bool ArrayOfRemoteMediaRawData::Fill(
133 const nsTArray<RefPtr<MediaRawData>>& aData,
134 std::function<ShmemBuffer(size_t)>&& aAllocator) {
135 nsTArray<AlignedByteBuffer> dataBuffers(aData.Length());
136 nsTArray<AlignedByteBuffer> alphaBuffers(aData.Length());
137 nsTArray<RefPtr<MediaByteBuffer>> extraDataBuffers(aData.Length());
138 int32_t height = 0;
139 for (auto&& entry : aData) {
140 dataBuffers.AppendElement(std::move(entry->mBuffer));
141 alphaBuffers.AppendElement(std::move(entry->mAlphaBuffer));
142 extraDataBuffers.AppendElement(std::move(entry->mExtraData));
143 if (auto&& info = entry->mTrackInfo; info && info->GetAsVideoInfo()) {
144 height = info->GetAsVideoInfo()->mImage.height;
146 mSamples.AppendElement(RemoteMediaRawData{
147 MediaDataIPDL(entry->mOffset, entry->mTime, entry->mTimecode,
148 entry->mDuration, entry->mKeyframe),
149 entry->mEOS, height, entry->mOriginalPresentationWindow,
150 entry->mCrypto.IsEncrypted() && entry->mShouldCopyCryptoToRemoteRawData
151 ? Some(CryptoInfo{
152 entry->mCrypto.mCryptoScheme,
153 entry->mCrypto.mIV,
154 entry->mCrypto.mKeyId,
155 entry->mCrypto.mPlainSizes,
156 entry->mCrypto.mEncryptedSizes,
158 : Nothing()});
160 PerformanceRecorder<PlaybackStage> perfRecorder(MediaStage::CopyDemuxedData,
161 height);
162 mBuffers = RemoteArrayOfByteBuffer(dataBuffers, aAllocator);
163 if (!mBuffers.IsValid()) {
164 return false;
166 mAlphaBuffers = RemoteArrayOfByteBuffer(alphaBuffers, aAllocator);
167 if (!mAlphaBuffers.IsValid()) {
168 return false;
170 mExtraDatas = RemoteArrayOfByteBuffer(extraDataBuffers, aAllocator);
171 if (!mExtraDatas.IsValid()) {
172 return false;
174 perfRecorder.Record();
175 return true;
178 already_AddRefed<MediaRawData> ArrayOfRemoteMediaRawData::ElementAt(
179 size_t aIndex) const {
180 if (!IsValid()) {
181 return nullptr;
183 MOZ_ASSERT(aIndex < Count());
184 MOZ_DIAGNOSTIC_ASSERT(mBuffers.Count() == Count() &&
185 mAlphaBuffers.Count() == Count() &&
186 mExtraDatas.Count() == Count(),
187 "Something ain't right here");
188 const auto& sample = mSamples[aIndex];
189 PerformanceRecorder<PlaybackStage> perfRecorder(MediaStage::CopyDemuxedData,
190 sample.mHeight);
191 AlignedByteBuffer data = mBuffers.AlignedBufferAt<uint8_t>(aIndex);
192 if (mBuffers.SizeAt(aIndex) && !data) {
193 // OOM
194 return nullptr;
196 AlignedByteBuffer alphaData = mAlphaBuffers.AlignedBufferAt<uint8_t>(aIndex);
197 if (mAlphaBuffers.SizeAt(aIndex) && !alphaData) {
198 // OOM
199 return nullptr;
201 RefPtr<MediaRawData> rawData;
202 if (mAlphaBuffers.SizeAt(aIndex)) {
203 rawData = new MediaRawData(std::move(data), std::move(alphaData));
204 } else {
205 rawData = new MediaRawData(std::move(data));
207 rawData->mOffset = sample.mBase.offset();
208 rawData->mTime = sample.mBase.time();
209 rawData->mTimecode = sample.mBase.timecode();
210 rawData->mDuration = sample.mBase.duration();
211 rawData->mKeyframe = sample.mBase.keyframe();
212 rawData->mEOS = sample.mEOS;
213 rawData->mExtraData = mExtraDatas.MediaByteBufferAt(aIndex);
214 if (sample.mCryptoConfig) {
215 CryptoSample& cypto = rawData->GetWritableCrypto();
216 cypto.mCryptoScheme = sample.mCryptoConfig->mEncryptionScheme();
217 cypto.mIV = std::move(sample.mCryptoConfig->mIV());
218 cypto.mIVSize = cypto.mIV.Length();
219 cypto.mKeyId = std::move(sample.mCryptoConfig->mKeyId());
220 cypto.mPlainSizes = std::move(sample.mCryptoConfig->mClearBytes());
221 cypto.mEncryptedSizes = std::move(sample.mCryptoConfig->mCipherBytes());
223 perfRecorder.Record();
224 return rawData.forget();
227 /*static */ void ipc::IPDLParamTraits<ArrayOfRemoteMediaRawData*>::Write(
228 IPC::MessageWriter* aWriter, ipc::IProtocol* aActor,
229 ArrayOfRemoteMediaRawData* aVar) {
230 WriteIPDLParam(aWriter, aActor, std::move(aVar->mSamples));
231 WriteIPDLParam(aWriter, aActor, std::move(aVar->mBuffers));
232 WriteIPDLParam(aWriter, aActor, std::move(aVar->mAlphaBuffers));
233 WriteIPDLParam(aWriter, aActor, std::move(aVar->mExtraDatas));
236 /* static */ bool ipc::IPDLParamTraits<ArrayOfRemoteMediaRawData*>::Read(
237 IPC::MessageReader* aReader, mozilla::ipc::IProtocol* aActor,
238 RefPtr<ArrayOfRemoteMediaRawData>* aVar) {
239 auto array = MakeRefPtr<ArrayOfRemoteMediaRawData>();
240 if (!ReadIPDLParam(aReader, aActor, &array->mSamples) ||
241 !ReadIPDLParam(aReader, aActor, &array->mBuffers) ||
242 !ReadIPDLParam(aReader, aActor, &array->mAlphaBuffers) ||
243 !ReadIPDLParam(aReader, aActor, &array->mExtraDatas)) {
244 return false;
246 *aVar = std::move(array);
247 return true;
250 /* static */ void
251 ipc::IPDLParamTraits<ArrayOfRemoteMediaRawData::RemoteMediaRawData>::Write(
252 IPC::MessageWriter* aWriter, ipc::IProtocol* aActor,
253 const paramType& aVar) {
254 WriteIPDLParam(aWriter, aActor, aVar.mBase);
255 WriteIPDLParam(aWriter, aActor, aVar.mEOS);
256 WriteIPDLParam(aWriter, aActor, aVar.mHeight);
257 WriteIPDLParam(aWriter, aActor, aVar.mOriginalPresentationWindow);
258 WriteIPDLParam(aWriter, aActor, aVar.mCryptoConfig);
261 /* static */ bool
262 ipc::IPDLParamTraits<ArrayOfRemoteMediaRawData::RemoteMediaRawData>::Read(
263 IPC::MessageReader* aReader, ipc::IProtocol* aActor, paramType* aVar) {
264 MediaDataIPDL mBase;
265 return ReadIPDLParam(aReader, aActor, &aVar->mBase) &&
266 ReadIPDLParam(aReader, aActor, &aVar->mEOS) &&
267 ReadIPDLParam(aReader, aActor, &aVar->mHeight) &&
268 ReadIPDLParam(aReader, aActor, &aVar->mOriginalPresentationWindow) &&
269 ReadIPDLParam(aReader, aActor, &aVar->mCryptoConfig);
272 bool ArrayOfRemoteAudioData::Fill(
273 const nsTArray<RefPtr<AudioData>>& aData,
274 std::function<ShmemBuffer(size_t)>&& aAllocator) {
275 nsTArray<AlignedAudioBuffer> dataBuffers(aData.Length());
276 for (auto&& entry : aData) {
277 dataBuffers.AppendElement(std::move(entry->mAudioData));
278 mSamples.AppendElement(RemoteAudioData{
279 MediaDataIPDL(entry->mOffset, entry->mTime, entry->mTimecode,
280 entry->mDuration, entry->mKeyframe),
281 entry->mChannels, entry->mRate, uint32_t(entry->mChannelMap),
282 entry->mOriginalTime, entry->mTrimWindow, entry->mFrames,
283 entry->mDataOffset});
285 mBuffers = RemoteArrayOfByteBuffer(dataBuffers, aAllocator);
286 if (!mBuffers.IsValid()) {
287 return false;
289 return true;
292 already_AddRefed<AudioData> ArrayOfRemoteAudioData::ElementAt(
293 size_t aIndex) const {
294 if (!IsValid()) {
295 return nullptr;
297 MOZ_ASSERT(aIndex < Count());
298 MOZ_DIAGNOSTIC_ASSERT(mBuffers.Count() == Count(),
299 "Something ain't right here");
300 const auto& sample = mSamples[aIndex];
301 AlignedAudioBuffer data = mBuffers.AlignedBufferAt<AudioDataValue>(aIndex);
302 if (mBuffers.SizeAt(aIndex) && !data) {
303 // OOM
304 return nullptr;
306 auto audioData = MakeRefPtr<AudioData>(
307 sample.mBase.offset(), sample.mBase.time(), std::move(data),
308 sample.mChannels, sample.mRate, sample.mChannelMap);
309 // An AudioData's duration is set at construction time based on the size of
310 // the provided buffer. However, if a trim window is set, this value will be
311 // incorrect. We have to re-set it to what it actually was.
312 audioData->mDuration = sample.mBase.duration();
313 audioData->mOriginalTime = sample.mOriginalTime;
314 audioData->mTrimWindow = sample.mTrimWindow;
315 audioData->mFrames = sample.mFrames;
316 audioData->mDataOffset = sample.mDataOffset;
317 return audioData.forget();
320 /*static */ void ipc::IPDLParamTraits<ArrayOfRemoteAudioData*>::Write(
321 IPC::MessageWriter* aWriter, ipc::IProtocol* aActor,
322 ArrayOfRemoteAudioData* aVar) {
323 WriteIPDLParam(aWriter, aActor, std::move(aVar->mSamples));
324 WriteIPDLParam(aWriter, aActor, std::move(aVar->mBuffers));
327 /* static */ bool ipc::IPDLParamTraits<ArrayOfRemoteAudioData*>::Read(
328 IPC::MessageReader* aReader, mozilla::ipc::IProtocol* aActor,
329 RefPtr<ArrayOfRemoteAudioData>* aVar) {
330 auto array = MakeRefPtr<ArrayOfRemoteAudioData>();
331 if (!ReadIPDLParam(aReader, aActor, &array->mSamples) ||
332 !ReadIPDLParam(aReader, aActor, &array->mBuffers)) {
333 return false;
335 *aVar = std::move(array);
336 return true;
339 /* static */ void
340 ipc::IPDLParamTraits<ArrayOfRemoteAudioData::RemoteAudioData>::Write(
341 IPC::MessageWriter* aWriter, ipc::IProtocol* aActor,
342 const paramType& aVar) {
343 WriteIPDLParam(aWriter, aActor, aVar.mBase);
344 WriteIPDLParam(aWriter, aActor, aVar.mChannels);
345 WriteIPDLParam(aWriter, aActor, aVar.mRate);
346 WriteIPDLParam(aWriter, aActor, aVar.mChannelMap);
347 WriteIPDLParam(aWriter, aActor, aVar.mOriginalTime);
348 WriteIPDLParam(aWriter, aActor, aVar.mTrimWindow);
349 WriteIPDLParam(aWriter, aActor, aVar.mFrames);
350 WriteIPDLParam(aWriter, aActor, aVar.mDataOffset);
353 /* static */ bool
354 ipc::IPDLParamTraits<ArrayOfRemoteAudioData::RemoteAudioData>::Read(
355 IPC::MessageReader* aReader, ipc::IProtocol* aActor, paramType* aVar) {
356 MediaDataIPDL mBase;
357 if (!ReadIPDLParam(aReader, aActor, &aVar->mBase) ||
358 !ReadIPDLParam(aReader, aActor, &aVar->mChannels) ||
359 !ReadIPDLParam(aReader, aActor, &aVar->mRate) ||
360 !ReadIPDLParam(aReader, aActor, &aVar->mChannelMap) ||
361 !ReadIPDLParam(aReader, aActor, &aVar->mOriginalTime) ||
362 !ReadIPDLParam(aReader, aActor, &aVar->mTrimWindow) ||
363 !ReadIPDLParam(aReader, aActor, &aVar->mFrames) ||
364 !ReadIPDLParam(aReader, aActor, &aVar->mDataOffset)) {
365 return false;
367 return true;
370 } // namespace mozilla