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"
16 bool RemoteArrayOfByteBuffer::AllocateShmem(
17 size_t aSize
, std::function
<ShmemBuffer(size_t)>& aAllocator
) {
18 ShmemBuffer buffer
= aAllocator(aSize
);
19 if (!buffer
.Valid()) {
22 mBuffers
.emplace(std::move(buffer
.Get()));
26 uint8_t* RemoteArrayOfByteBuffer::BuffersStartAddress() const {
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
) {
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.
54 for (const auto& buffer
: aArray
) {
56 totalSize
+= buffer
->Length();
60 if (!AllocateShmem(totalSize
, aAllocator
)) {
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
});
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;
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
)) {
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
102 RefPtr
<MediaByteBuffer
> buffer
= new MediaByteBuffer(entrySize
);
103 buffer
->SetLength(entrySize
);
104 memcpy(buffer
->Elements(), mBuffers
->get
<uint8_t>() + std::get
<0>(entry
),
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.
117 WriteIPDLParam(aWriter
, aActor
, Some(ipc::Shmem(*aVar
.mBuffers
)));
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());
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
152 entry
->mCrypto
.mCryptoScheme
,
154 entry
->mCrypto
.mKeyId
,
155 entry
->mCrypto
.mPlainSizes
,
156 entry
->mCrypto
.mEncryptedSizes
,
160 PerformanceRecorder
<PlaybackStage
> perfRecorder(MediaStage::CopyDemuxedData
,
162 mBuffers
= RemoteArrayOfByteBuffer(dataBuffers
, aAllocator
);
163 if (!mBuffers
.IsValid()) {
166 mAlphaBuffers
= RemoteArrayOfByteBuffer(alphaBuffers
, aAllocator
);
167 if (!mAlphaBuffers
.IsValid()) {
170 mExtraDatas
= RemoteArrayOfByteBuffer(extraDataBuffers
, aAllocator
);
171 if (!mExtraDatas
.IsValid()) {
174 perfRecorder
.Record();
178 already_AddRefed
<MediaRawData
> ArrayOfRemoteMediaRawData::ElementAt(
179 size_t aIndex
) const {
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
,
191 AlignedByteBuffer data
= mBuffers
.AlignedBufferAt
<uint8_t>(aIndex
);
192 if (mBuffers
.SizeAt(aIndex
) && !data
) {
196 AlignedByteBuffer alphaData
= mAlphaBuffers
.AlignedBufferAt
<uint8_t>(aIndex
);
197 if (mAlphaBuffers
.SizeAt(aIndex
) && !alphaData
) {
201 RefPtr
<MediaRawData
> rawData
;
202 if (mAlphaBuffers
.SizeAt(aIndex
)) {
203 rawData
= new MediaRawData(std::move(data
), std::move(alphaData
));
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
)) {
246 *aVar
= std::move(array
);
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
);
262 ipc::IPDLParamTraits
<ArrayOfRemoteMediaRawData::RemoteMediaRawData
>::Read(
263 IPC::MessageReader
* aReader
, ipc::IProtocol
* aActor
, paramType
* aVar
) {
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()) {
292 already_AddRefed
<AudioData
> ArrayOfRemoteAudioData::ElementAt(
293 size_t aIndex
) const {
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
) {
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
)) {
335 *aVar
= std::move(array
);
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
);
354 ipc::IPDLParamTraits
<ArrayOfRemoteAudioData::RemoteAudioData
>::Read(
355 IPC::MessageReader
* aReader
, ipc::IProtocol
* aActor
, paramType
* aVar
) {
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
)) {
370 } // namespace mozilla