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 #ifndef mozilla_dom_media_ipc_RemoteMediaData_h
8 #define mozilla_dom_media_ipc_RemoteMediaData_h
12 #include "MediaData.h"
13 #include "PlatformDecoderModule.h"
14 #include "ipc/IPCMessageUtils.h"
15 #include "mozilla/GfxMessageUtils.h"
16 #include "mozilla/PMediaDecoderParams.h"
17 #include "mozilla/RemoteImageHolder.h"
18 #include "mozilla/ShmemPool.h"
19 #include "mozilla/gfx/Rect.h"
30 //-----------------------------------------------------------------------------
31 // Declaration of the IPDL type |struct RemoteVideoData|
33 // We can't use the generated binding in order to use move semantics properly
35 class RemoteVideoData final
{
37 typedef mozilla::gfx::IntSize IntSize
;
40 RemoteVideoData() = default;
42 RemoteVideoData(const MediaDataIPDL
& aBase
, const IntSize
& aDisplay
,
43 RemoteImageHolder
&& aImage
, int32_t aFrameID
)
46 mImage(std::move(aImage
)),
49 // This is equivalent to the old RemoteVideoDataIPDL object and is similar to
50 // the RemoteAudioDataIPDL object. To ensure style consistency we use the IPDL
51 // naming convention here.
52 MediaDataIPDL
& base() { return mBase
; }
53 const MediaDataIPDL
& base() const { return mBase
; }
55 IntSize
& display() { return mDisplay
; }
56 const IntSize
& display() const { return mDisplay
; }
58 RemoteImageHolder
& image() { return mImage
; }
59 const RemoteImageHolder
& image() const { return mImage
; }
61 int32_t& frameID() { return mFrameID
; }
62 const int32_t& frameID() const { return mFrameID
; }
65 friend struct ipc::IPDLParamTraits
<RemoteVideoData
>;
68 RemoteImageHolder mImage
;
72 // Until bug 1572054 is resolved, we can't move our objects when using IPDL's
73 // union or array. They are always copied. So we make the class refcounted to
74 // and always pass it by pointed to bypass the problem for now.
75 class ArrayOfRemoteVideoData final
{
76 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ArrayOfRemoteVideoData
)
78 ArrayOfRemoteVideoData() = default;
79 ArrayOfRemoteVideoData(ArrayOfRemoteVideoData
&& aOther
)
80 : mArray(std::move(aOther
.mArray
)) {}
81 explicit ArrayOfRemoteVideoData(nsTArray
<RemoteVideoData
>&& aOther
)
82 : mArray(std::move(aOther
)) {}
83 ArrayOfRemoteVideoData(const ArrayOfRemoteVideoData
& aOther
) {
84 MOZ_CRASH("Should never be used but declared by generated IPDL binding");
86 ArrayOfRemoteVideoData
& operator=(ArrayOfRemoteVideoData
&& aOther
) noexcept
{
87 if (this != &aOther
) {
88 mArray
= std::move(aOther
.mArray
);
92 ArrayOfRemoteVideoData
& operator=(nsTArray
<RemoteVideoData
>&& aOther
) {
93 mArray
= std::move(aOther
);
97 void AppendElements(nsTArray
<RemoteVideoData
>&& aOther
) {
98 mArray
.AppendElements(std::move(aOther
));
100 void Append(RemoteVideoData
&& aVideo
) {
101 mArray
.AppendElement(std::move(aVideo
));
103 const nsTArray
<RemoteVideoData
>& Array() const { return mArray
; }
104 nsTArray
<RemoteVideoData
>& Array() { return mArray
; }
107 ~ArrayOfRemoteVideoData() = default;
108 friend struct ipc::IPDLParamTraits
<mozilla::ArrayOfRemoteVideoData
*>;
109 nsTArray
<RemoteVideoData
> mArray
;
112 /* The class will pack either an array of AlignedBuffer or MediaByteBuffer
113 * into a single Shmem objects. */
114 class RemoteArrayOfByteBuffer
{
116 RemoteArrayOfByteBuffer();
117 template <typename Type
>
118 RemoteArrayOfByteBuffer(const nsTArray
<AlignedBuffer
<Type
>>& aArray
,
119 std::function
<ShmemBuffer(size_t)>& aAllocator
) {
120 // Determine the total size we will need for this object.
121 size_t totalSize
= 0;
122 for (auto& buffer
: aArray
) {
123 totalSize
+= buffer
.Size();
126 if (!AllocateShmem(totalSize
, aAllocator
)) {
131 for (auto& buffer
: aArray
) {
132 if (totalSize
&& buffer
&& buffer
.Size()) {
133 Write(offset
, buffer
.Data(), buffer
.Size());
135 mOffsets
.AppendElement(OffsetEntry
{offset
, buffer
.Size()});
136 offset
+= buffer
.Size();
141 RemoteArrayOfByteBuffer(const nsTArray
<RefPtr
<MediaByteBuffer
>>& aArray
,
142 std::function
<ShmemBuffer(size_t)>& aAllocator
);
143 RemoteArrayOfByteBuffer
& operator=(RemoteArrayOfByteBuffer
&& aOther
) noexcept
;
145 // Return the packed aIndexth buffer as an AlignedByteBuffer.
146 // The operation is fallible should an out of memory be encountered. The
147 // result should be tested accordingly.
148 template <typename Type
>
149 AlignedBuffer
<Type
> AlignedBufferAt(size_t aIndex
) const {
150 MOZ_ASSERT(aIndex
< Count());
151 const OffsetEntry
& entry
= mOffsets
[aIndex
];
152 size_t entrySize
= std::get
<1>(entry
);
153 if (!mBuffers
|| !entrySize
) {
154 // It's an empty one.
155 return AlignedBuffer
<Type
>();
157 if (!Check(std::get
<0>(entry
), entrySize
)) {
158 // This Shmem is corrupted and can't contain the data we are about to
159 // retrieve. We return an empty array instead of asserting to allow for
161 return AlignedBuffer
<Type
>();
163 if (0 != entrySize
% sizeof(Type
)) {
164 // There's an error, that entry can't represent this data.
165 return AlignedBuffer
<Type
>();
167 return AlignedBuffer
<Type
>(
168 reinterpret_cast<Type
*>(BuffersStartAddress() + std::get
<0>(entry
)),
169 entrySize
/ sizeof(Type
));
172 // Return the packed aIndexth buffer as aMediaByteBuffer.
173 // Will return nullptr if the packed buffer was originally empty.
174 already_AddRefed
<MediaByteBuffer
> MediaByteBufferAt(size_t aIndex
) const;
175 // Return the size of the aIndexth buffer.
176 size_t SizeAt(size_t aIndex
) const { return std::get
<1>(mOffsets
[aIndex
]); }
177 // Return false if an out of memory error was encountered during construction.
178 bool IsValid() const { return mIsValid
; };
179 // Return the number of buffers packed into this entity.
180 size_t Count() const { return mOffsets
.Length(); }
181 virtual ~RemoteArrayOfByteBuffer();
184 friend struct ipc::IPDLParamTraits
<RemoteArrayOfByteBuffer
>;
185 // Allocate shmem, false if an error occurred.
186 bool AllocateShmem(size_t aSize
,
187 std::function
<ShmemBuffer(size_t)>& aAllocator
);
188 // The starting address of the Shmem
189 uint8_t* BuffersStartAddress() const;
190 // Check that the allocated Shmem can contain such range.
191 bool Check(size_t aOffset
, size_t aSizeInBytes
) const;
192 void Write(size_t aOffset
, const void* aSourceAddr
, size_t aSizeInBytes
);
193 // Set to false is the buffer isn't initialized yet or a memory error occurred
194 // during construction.
195 bool mIsValid
= false;
196 // The packed data. The Maybe will be empty if all buffers packed were
198 Maybe
<ipc::Shmem
> mBuffers
;
199 // The offset to the start of the individual buffer and its size (all in
201 typedef std::tuple
<size_t, size_t> OffsetEntry
;
202 nsTArray
<OffsetEntry
> mOffsets
;
205 /* The class will pack an array of MediaRawData using at most three Shmem
206 * objects. Under the most common scenaria, only two Shmems will be used as
207 * there are few videos with an alpha channel in the wild.
208 * We unfortunately can't populate the array at construction nor present an
209 * interface similar to an actual nsTArray or the ArrayOfRemoteVideoData above
210 * as currently IPC serialization is always non-fallible. So we must create the
211 * object first, fill it to determine if we ran out of memory and then send the
214 class ArrayOfRemoteMediaRawData
{
215 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ArrayOfRemoteMediaRawData
)
217 // Fill the content, return false if an OOM occurred.
218 bool Fill(const nsTArray
<RefPtr
<MediaRawData
>>& aData
,
219 std::function
<ShmemBuffer(size_t)>&& aAllocator
);
221 // Return the aIndexth MediaRawData or nullptr if a memory error occurred.
222 already_AddRefed
<MediaRawData
> ElementAt(size_t aIndex
) const;
224 // Return the number of MediaRawData stored in this container.
225 size_t Count() const { return mSamples
.Length(); }
226 bool IsEmpty() const { return Count() == 0; }
227 bool IsValid() const {
228 return mBuffers
.IsValid() && mAlphaBuffers
.IsValid() &&
229 mExtraDatas
.IsValid();
232 struct RemoteMediaRawData
{
235 // This will be zero for audio.
237 Maybe
<media::TimeInterval
> mOriginalPresentationWindow
;
238 Maybe
<CryptoInfo
> mCryptoConfig
;
242 friend struct ipc::IPDLParamTraits
<ArrayOfRemoteMediaRawData
*>;
243 virtual ~ArrayOfRemoteMediaRawData() = default;
245 nsTArray
<RemoteMediaRawData
> mSamples
;
246 RemoteArrayOfByteBuffer mBuffers
;
247 RemoteArrayOfByteBuffer mAlphaBuffers
;
248 RemoteArrayOfByteBuffer mExtraDatas
;
251 /* The class will pack an array of MediaAudioData using at most a single Shmem
253 * We unfortunately can't populate the array at construction nor present an
254 * interface similar to an actual nsTArray or the ArrayOfRemoteVideoData above
255 * as currently IPC serialization is always non-fallible. So we must create the
256 * object first, fill it to determine if we ran out of memory and then send the
259 class ArrayOfRemoteAudioData final
{
260 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ArrayOfRemoteAudioData
)
262 // Fill the content, return false if an OOM occurred.
263 bool Fill(const nsTArray
<RefPtr
<AudioData
>>& aData
,
264 std::function
<ShmemBuffer(size_t)>&& aAllocator
);
266 // Return the aIndexth MediaRawData or nullptr if a memory error occurred.
267 already_AddRefed
<AudioData
> ElementAt(size_t aIndex
) const;
269 // Return the number of MediaRawData stored in this container.
270 size_t Count() const { return mSamples
.Length(); }
271 bool IsEmpty() const { return Count() == 0; }
272 bool IsValid() const { return mBuffers
.IsValid(); }
274 struct RemoteAudioData
{
275 friend struct ipc::IPDLParamTraits
<RemoteVideoData
>;
279 uint32_t mChannelMap
;
280 media::TimeUnit mOriginalTime
;
281 Maybe
<media::TimeInterval
> mTrimWindow
;
287 friend struct ipc::IPDLParamTraits
<ArrayOfRemoteAudioData
*>;
288 ~ArrayOfRemoteAudioData() = default;
290 nsTArray
<RemoteAudioData
> mSamples
;
291 RemoteArrayOfByteBuffer mBuffers
;
297 struct IPDLParamTraits
<RemoteVideoData
> {
298 typedef RemoteVideoData paramType
;
299 static void Write(IPC::MessageWriter
* aWriter
, ipc::IProtocol
* aActor
,
301 WriteIPDLParam(aWriter
, aActor
, std::move(aVar
.mBase
));
302 WriteIPDLParam(aWriter
, aActor
, std::move(aVar
.mDisplay
));
303 WriteIPDLParam(aWriter
, aActor
, std::move(aVar
.mImage
));
304 aWriter
->WriteBytes(&aVar
.mFrameID
, 4);
307 static bool Read(IPC::MessageReader
* aReader
, mozilla::ipc::IProtocol
* aActor
,
309 if (!ReadIPDLParam(aReader
, aActor
, &aVar
->mBase
) ||
310 !ReadIPDLParam(aReader
, aActor
, &aVar
->mDisplay
) ||
311 !ReadIPDLParam(aReader
, aActor
, &aVar
->mImage
) ||
312 !aReader
->ReadBytesInto(&aVar
->mFrameID
, 4)) {
320 struct IPDLParamTraits
<ArrayOfRemoteVideoData
*> {
321 typedef ArrayOfRemoteVideoData paramType
;
322 static void Write(IPC::MessageWriter
* aWriter
,
323 mozilla::ipc::IProtocol
* aActor
, paramType
* aVar
) {
324 WriteIPDLParam(aWriter
, aActor
, std::move(aVar
->mArray
));
327 static bool Read(IPC::MessageReader
* aReader
, ipc::IProtocol
* aActor
,
328 RefPtr
<paramType
>* aVar
) {
329 nsTArray
<RemoteVideoData
> array
;
330 if (!ReadIPDLParam(aReader
, aActor
, &array
)) {
333 auto results
= MakeRefPtr
<ArrayOfRemoteVideoData
>(std::move(array
));
334 *aVar
= std::move(results
);
340 struct IPDLParamTraits
<RemoteArrayOfByteBuffer
> {
341 typedef RemoteArrayOfByteBuffer paramType
;
342 // We do not want to move the RemoteArrayOfByteBuffer as we want to recycle
343 // the shmem it contains for another time.
344 static void Write(IPC::MessageWriter
* aWriter
, ipc::IProtocol
* aActor
,
345 const paramType
& aVar
);
347 static bool Read(IPC::MessageReader
* aReader
, ipc::IProtocol
* aActor
,
352 struct IPDLParamTraits
<ArrayOfRemoteMediaRawData::RemoteMediaRawData
> {
353 typedef ArrayOfRemoteMediaRawData::RemoteMediaRawData paramType
;
354 static void Write(IPC::MessageWriter
* aWriter
, ipc::IProtocol
* aActor
,
355 const paramType
& aVar
);
357 static bool Read(IPC::MessageReader
* aReader
, ipc::IProtocol
* aActor
,
362 struct IPDLParamTraits
<ArrayOfRemoteMediaRawData
*> {
363 typedef ArrayOfRemoteMediaRawData paramType
;
364 static void Write(IPC::MessageWriter
* aWriter
, ipc::IProtocol
* aActor
,
367 static bool Read(IPC::MessageReader
* aReader
, ipc::IProtocol
* aActor
,
368 RefPtr
<paramType
>* aVar
);
372 struct IPDLParamTraits
<ArrayOfRemoteAudioData::RemoteAudioData
> {
373 typedef ArrayOfRemoteAudioData::RemoteAudioData paramType
;
374 static void Write(IPC::MessageWriter
* aWriter
, ipc::IProtocol
* aActor
,
375 const paramType
& aVar
);
377 static bool Read(IPC::MessageReader
* aReader
, ipc::IProtocol
* aActor
,
382 struct IPDLParamTraits
<ArrayOfRemoteAudioData
*> {
383 typedef ArrayOfRemoteAudioData paramType
;
384 static void Write(IPC::MessageWriter
* aWriter
, ipc::IProtocol
* aActor
,
387 static bool Read(IPC::MessageReader
* aReader
, ipc::IProtocol
* aActor
,
388 RefPtr
<paramType
>* aVar
);
392 } // namespace mozilla
394 #endif // mozilla_dom_media_ipc_RemoteMediaData_h