Backed out changeset 40518e514fc1 (bug 1925496) for causing bc failures @ browser_cop...
[gecko.git] / dom / media / ipc / RemoteMediaData.h
blob1797a81ea0dd070960986a0643be77b1220f6289
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
10 #include <functional>
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"
21 namespace mozilla {
23 class ShmemPool;
25 namespace ipc {
26 class IProtocol;
27 class Shmem;
28 } // namespace ipc
30 //-----------------------------------------------------------------------------
31 // Declaration of the IPDL type |struct RemoteVideoData|
33 // We can't use the generated binding in order to use move semantics properly
34 // (see bug 1664362)
35 class RemoteVideoData final {
36 private:
37 typedef mozilla::gfx::IntSize IntSize;
39 public:
40 RemoteVideoData() = default;
42 RemoteVideoData(const MediaDataIPDL& aBase, const IntSize& aDisplay,
43 RemoteImageHolder&& aImage, int32_t aFrameID)
44 : mBase(aBase),
45 mDisplay(aDisplay),
46 mImage(std::move(aImage)),
47 mFrameID(aFrameID) {}
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; }
64 private:
65 friend struct ipc::IPDLParamTraits<RemoteVideoData>;
66 MediaDataIPDL mBase;
67 IntSize mDisplay;
68 RemoteImageHolder mImage;
69 int32_t mFrameID;
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)
77 public:
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);
90 return *this;
92 ArrayOfRemoteVideoData& operator=(nsTArray<RemoteVideoData>&& aOther) {
93 mArray = std::move(aOther);
94 return *this;
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; }
106 private:
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 {
115 public:
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();
125 if (totalSize) {
126 if (!AllocateShmem(totalSize, aAllocator)) {
127 return;
130 size_t offset = 0;
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();
138 mIsValid = true;
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
160 // recovery.
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();
183 private:
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
197 // orignally empty.
198 Maybe<ipc::Shmem> mBuffers;
199 // The offset to the start of the individual buffer and its size (all in
200 // bytes)
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
212 * object over IPC.
214 class ArrayOfRemoteMediaRawData {
215 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ArrayOfRemoteMediaRawData)
216 public:
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 {
233 MediaDataIPDL mBase;
234 bool mEOS;
235 // This will be zero for audio.
236 int32_t mHeight;
237 Maybe<media::TimeInterval> mOriginalPresentationWindow;
238 Maybe<CryptoInfo> mCryptoConfig;
241 private:
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
252 * objects.
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
257 * object over IPC.
259 class ArrayOfRemoteAudioData final {
260 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ArrayOfRemoteAudioData)
261 public:
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>;
276 MediaDataIPDL mBase;
277 uint32_t mChannels;
278 uint32_t mRate;
279 uint32_t mChannelMap;
280 media::TimeUnit mOriginalTime;
281 Maybe<media::TimeInterval> mTrimWindow;
282 uint32_t mFrames;
283 size_t mDataOffset;
286 private:
287 friend struct ipc::IPDLParamTraits<ArrayOfRemoteAudioData*>;
288 ~ArrayOfRemoteAudioData() = default;
290 nsTArray<RemoteAudioData> mSamples;
291 RemoteArrayOfByteBuffer mBuffers;
294 namespace ipc {
296 template <>
297 struct IPDLParamTraits<RemoteVideoData> {
298 typedef RemoteVideoData paramType;
299 static void Write(IPC::MessageWriter* aWriter, ipc::IProtocol* aActor,
300 paramType&& aVar) {
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,
308 paramType* aVar) {
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)) {
313 return false;
315 return true;
319 template <>
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)) {
331 return false;
333 auto results = MakeRefPtr<ArrayOfRemoteVideoData>(std::move(array));
334 *aVar = std::move(results);
335 return true;
339 template <>
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,
348 paramType* aVar);
351 template <>
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,
358 paramType* aVar);
361 template <>
362 struct IPDLParamTraits<ArrayOfRemoteMediaRawData*> {
363 typedef ArrayOfRemoteMediaRawData paramType;
364 static void Write(IPC::MessageWriter* aWriter, ipc::IProtocol* aActor,
365 paramType* aVar);
367 static bool Read(IPC::MessageReader* aReader, ipc::IProtocol* aActor,
368 RefPtr<paramType>* aVar);
371 template <>
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,
378 paramType* aVar);
381 template <>
382 struct IPDLParamTraits<ArrayOfRemoteAudioData*> {
383 typedef ArrayOfRemoteAudioData paramType;
384 static void Write(IPC::MessageWriter* aWriter, ipc::IProtocol* aActor,
385 paramType* aVar);
387 static bool Read(IPC::MessageReader* aReader, ipc::IProtocol* aActor,
388 RefPtr<paramType>* aVar);
390 } // namespace ipc
392 } // namespace mozilla
394 #endif // mozilla_dom_media_ipc_RemoteMediaData_h