RemoteMediaData.h (14247B)
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 7 #ifndef mozilla_dom_media_ipc_RemoteMediaData_h 8 #define mozilla_dom_media_ipc_RemoteMediaData_h 9 10 #include <functional> 11 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" 20 21 namespace mozilla { 22 23 class ShmemPool; 24 25 namespace ipc { 26 class IProtocol; 27 class Shmem; 28 } // namespace ipc 29 30 //----------------------------------------------------------------------------- 31 // Declaration of the IPDL type |struct RemoteVideoData| 32 // 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; 38 39 public: 40 RemoteVideoData() = default; 41 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) {} 48 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; } 54 55 IntSize& display() { return mDisplay; } 56 const IntSize& display() const { return mDisplay; } 57 58 RemoteImageHolder& image() { return mImage; } 59 const RemoteImageHolder& image() const { return mImage; } 60 61 int32_t& frameID() { return mFrameID; } 62 const int32_t& frameID() const { return mFrameID; } 63 64 private: 65 friend struct IPC::ParamTraits<RemoteVideoData>; 66 MediaDataIPDL mBase; 67 IntSize mDisplay; 68 RemoteImageHolder mImage; 69 int32_t mFrameID; 70 }; 71 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"); 85 } 86 ArrayOfRemoteVideoData& operator=(ArrayOfRemoteVideoData&& aOther) noexcept { 87 if (this != &aOther) { 88 mArray = std::move(aOther.mArray); 89 } 90 return *this; 91 } 92 ArrayOfRemoteVideoData& operator=(nsTArray<RemoteVideoData>&& aOther) { 93 mArray = std::move(aOther); 94 return *this; 95 } 96 97 void AppendElements(nsTArray<RemoteVideoData>&& aOther) { 98 mArray.AppendElements(std::move(aOther)); 99 } 100 void Append(RemoteVideoData&& aVideo) { 101 mArray.AppendElement(std::move(aVideo)); 102 } 103 const nsTArray<RemoteVideoData>& Array() const { return mArray; } 104 nsTArray<RemoteVideoData>& Array() { return mArray; } 105 106 private: 107 ~ArrayOfRemoteVideoData() = default; 108 friend struct IPC::ParamTraits<mozilla::ArrayOfRemoteVideoData*>; 109 nsTArray<RemoteVideoData> mArray; 110 }; 111 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(); 124 } 125 if (totalSize) { 126 if (!AllocateShmem(totalSize, aAllocator)) { 127 return; 128 } 129 } 130 size_t offset = 0; 131 for (auto& buffer : aArray) { 132 if (totalSize && buffer && buffer.Size()) { 133 Write(offset, buffer.Data(), buffer.Size()); 134 } 135 mOffsets.AppendElement(OffsetEntry{offset, buffer.Size()}); 136 offset += buffer.Size(); 137 } 138 mIsValid = true; 139 } 140 141 template <typename Type> 142 RemoteArrayOfByteBuffer(const AlignedBuffer<Type>& aBuffer, 143 std::function<ShmemBuffer(size_t)>& aAllocator) { 144 // Determine the total size we will need for this object. 145 size_t bufferSize = aBuffer.Size(); 146 if (bufferSize) { 147 if (!AllocateShmem(bufferSize, aAllocator)) { 148 return; 149 } 150 Write(0, aBuffer.Data(), bufferSize); 151 mOffsets.AppendElement(OffsetEntry{0, bufferSize}); 152 } 153 mIsValid = true; 154 } 155 156 RemoteArrayOfByteBuffer(const nsTArray<RefPtr<MediaByteBuffer>>& aArray, 157 std::function<ShmemBuffer(size_t)>& aAllocator); 158 RemoteArrayOfByteBuffer& operator=(RemoteArrayOfByteBuffer&& aOther) noexcept; 159 160 // Return the packed aIndexth buffer as an AlignedByteBuffer. 161 // The operation is fallible should an out of memory be encountered. The 162 // result should be tested accordingly. 163 template <typename Type> 164 AlignedBuffer<Type> AlignedBufferAt(size_t aIndex) const { 165 MOZ_ASSERT(aIndex < Count()); 166 const OffsetEntry& entry = mOffsets[aIndex]; 167 size_t entrySize = std::get<1>(entry); 168 if (!mBuffers || !entrySize) { 169 // It's an empty one. 170 return AlignedBuffer<Type>(); 171 } 172 if (!Check(std::get<0>(entry), entrySize)) { 173 // This Shmem is corrupted and can't contain the data we are about to 174 // retrieve. We return an empty array instead of asserting to allow for 175 // recovery. 176 return AlignedBuffer<Type>(); 177 } 178 if (0 != entrySize % sizeof(Type)) { 179 // There's an error, that entry can't represent this data. 180 return AlignedBuffer<Type>(); 181 } 182 return AlignedBuffer<Type>( 183 reinterpret_cast<Type*>(BuffersStartAddress() + std::get<0>(entry)), 184 entrySize / sizeof(Type)); 185 } 186 187 // Return the packed aIndexth buffer as aMediaByteBuffer. 188 // Will return nullptr if the packed buffer was originally empty. 189 already_AddRefed<MediaByteBuffer> MediaByteBufferAt(size_t aIndex) const; 190 // Return the size of the aIndexth buffer. 191 size_t SizeAt(size_t aIndex) const { return std::get<1>(mOffsets[aIndex]); } 192 // Return false if an out of memory error was encountered during construction. 193 bool IsValid() const { return mIsValid; }; 194 // Return the number of buffers packed into this entity. 195 size_t Count() const { return mOffsets.Length(); } 196 virtual ~RemoteArrayOfByteBuffer(); 197 198 private: 199 friend struct IPC::ParamTraits<RemoteArrayOfByteBuffer>; 200 // Allocate shmem, false if an error occurred. 201 bool AllocateShmem(size_t aSize, 202 std::function<ShmemBuffer(size_t)>& aAllocator); 203 // The starting address of the Shmem 204 uint8_t* BuffersStartAddress() const; 205 // Check that the allocated Shmem can contain such range. 206 bool Check(size_t aOffset, size_t aSizeInBytes) const; 207 void Write(size_t aOffset, const void* aSourceAddr, size_t aSizeInBytes); 208 // Set to false is the buffer isn't initialized yet or a memory error occurred 209 // during construction. 210 bool mIsValid = false; 211 // The packed data. The Maybe will be empty if all buffers packed were 212 // orignally empty. 213 Maybe<ipc::Shmem> mBuffers; 214 // The offset to the start of the individual buffer and its size (all in 215 // bytes) 216 typedef std::tuple<size_t, size_t> OffsetEntry; 217 nsTArray<OffsetEntry> mOffsets; 218 }; 219 220 /* The class will pack an array of MediaRawData using at most three Shmem 221 * objects. Under the most common scenaria, only two Shmems will be used as 222 * there are few videos with an alpha channel in the wild. 223 * We unfortunately can't populate the array at construction nor present an 224 * interface similar to an actual nsTArray or the ArrayOfRemoteVideoData above 225 * as currently IPC serialization is always non-fallible. So we must create the 226 * object first, fill it to determine if we ran out of memory and then send the 227 * object over IPC. 228 */ 229 class ArrayOfRemoteMediaRawData { 230 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ArrayOfRemoteMediaRawData) 231 public: 232 // Fill the content, return false if an OOM occurred. 233 bool Fill(const nsTArray<RefPtr<MediaRawData>>& aData, 234 std::function<ShmemBuffer(size_t)>&& aAllocator); 235 236 // Return the aIndexth MediaRawData or nullptr if a memory error occurred. 237 already_AddRefed<MediaRawData> ElementAt(size_t aIndex) const; 238 239 // Return the number of MediaRawData stored in this container. 240 size_t Count() const { return mSamples.Length(); } 241 bool IsEmpty() const { return Count() == 0; } 242 bool IsValid() const { 243 return mBuffers.IsValid() && mAlphaBuffers.IsValid() && 244 mExtraDatas.IsValid(); 245 } 246 247 struct RemoteMediaRawData { 248 MediaDataIPDL mBase; 249 bool mEOS; 250 // This will be zero for audio. 251 int32_t mHeight; 252 Maybe<uint8_t> mTemporalLayerId; 253 Maybe<media::TimeInterval> mOriginalPresentationWindow; 254 Maybe<CryptoInfo> mCryptoConfig; 255 }; 256 257 private: 258 friend struct IPC::ParamTraits<ArrayOfRemoteMediaRawData*>; 259 virtual ~ArrayOfRemoteMediaRawData() = default; 260 261 nsTArray<RemoteMediaRawData> mSamples; 262 RemoteArrayOfByteBuffer mBuffers; 263 RemoteArrayOfByteBuffer mAlphaBuffers; 264 RemoteArrayOfByteBuffer mExtraDatas; 265 }; 266 267 /* The class will pack an array of MediaAudioData using at most a single Shmem 268 * objects. 269 * We unfortunately can't populate the array at construction nor present an 270 * interface similar to an actual nsTArray or the ArrayOfRemoteVideoData above 271 * as currently IPC serialization is always non-fallible. So we must create the 272 * object first, fill it to determine if we ran out of memory and then send the 273 * object over IPC. 274 */ 275 class ArrayOfRemoteAudioData final { 276 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ArrayOfRemoteAudioData) 277 public: 278 // Fill the content, return false if an OOM occurred. 279 bool Fill(const nsTArray<RefPtr<AudioData>>& aData, 280 std::function<ShmemBuffer(size_t)>&& aAllocator); 281 bool Fill(const AudioData* aData, 282 std::function<ShmemBuffer(size_t)>&& aAllocator); 283 284 // Return the aIndexth MediaRawData or nullptr if a memory error occurred. 285 already_AddRefed<AudioData> ElementAt(size_t aIndex) const; 286 287 // Return the number of MediaRawData stored in this container. 288 size_t Count() const { return mSamples.Length(); } 289 bool IsEmpty() const { return Count() == 0; } 290 bool IsValid() const { return mBuffers.IsValid(); } 291 292 struct RemoteAudioData { 293 friend struct IPC::ParamTraits<RemoteVideoData>; 294 MediaDataIPDL mBase; 295 uint32_t mChannels; 296 uint32_t mRate; 297 uint32_t mChannelMap; 298 media::TimeUnit mOriginalTime; 299 Maybe<media::TimeInterval> mTrimWindow; 300 uint32_t mFrames; 301 size_t mDataOffset; 302 }; 303 304 private: 305 friend struct IPC::ParamTraits<ArrayOfRemoteAudioData*>; 306 ~ArrayOfRemoteAudioData() = default; 307 308 nsTArray<RemoteAudioData> mSamples; 309 RemoteArrayOfByteBuffer mBuffers; 310 }; 311 312 } // namespace mozilla 313 314 namespace IPC { 315 316 template <> 317 struct ParamTraits<mozilla::RemoteVideoData> { 318 using paramType = mozilla::RemoteVideoData; 319 static void Write(MessageWriter* aWriter, paramType&& aVar) { 320 WriteParam(aWriter, std::move(aVar.mBase)); 321 WriteParam(aWriter, std::move(aVar.mDisplay)); 322 WriteParam(aWriter, std::move(aVar.mImage)); 323 aWriter->WriteBytes(&aVar.mFrameID, 4); 324 } 325 326 static bool Read(IPC::MessageReader* aReader, paramType* aVar) { 327 return ReadParam(aReader, &aVar->mBase) && 328 ReadParam(aReader, &aVar->mDisplay) && 329 ReadParam(aReader, &aVar->mImage) && 330 aReader->ReadBytesInto(&aVar->mFrameID, 4); 331 } 332 }; 333 334 template <> 335 struct ParamTraits<mozilla::ArrayOfRemoteVideoData*> { 336 using paramType = mozilla::ArrayOfRemoteVideoData; 337 static void Write(IPC::MessageWriter* aWriter, paramType* aVar) { 338 WriteParam(aWriter, std::move(aVar->mArray)); 339 } 340 341 static bool Read(IPC::MessageReader* aReader, RefPtr<paramType>* aVar) { 342 nsTArray<mozilla::RemoteVideoData> array; 343 if (!ReadParam(aReader, &array)) { 344 return false; 345 } 346 auto results = 347 mozilla::MakeRefPtr<mozilla::ArrayOfRemoteVideoData>(std::move(array)); 348 *aVar = std::move(results); 349 return true; 350 } 351 }; 352 353 template <> 354 struct ParamTraits<mozilla::RemoteArrayOfByteBuffer> { 355 using paramType = mozilla::RemoteArrayOfByteBuffer; 356 // We do not want to move the RemoteArrayOfByteBuffer as we want to recycle 357 // the shmem it contains for another time. 358 static void Write(IPC::MessageWriter* aWriter, const paramType& aVar); 359 360 static bool Read(IPC::MessageReader* aReader, paramType* aVar); 361 }; 362 363 template <> 364 struct ParamTraits<mozilla::ArrayOfRemoteMediaRawData::RemoteMediaRawData> { 365 using paramType = mozilla::ArrayOfRemoteMediaRawData::RemoteMediaRawData; 366 static void Write(MessageWriter* aWriter, const paramType& aVar); 367 368 static bool Read(MessageReader* aReader, paramType* aVar); 369 }; 370 371 template <> 372 struct ParamTraits<mozilla::ArrayOfRemoteMediaRawData*> { 373 using paramType = mozilla::ArrayOfRemoteMediaRawData; 374 static void Write(MessageWriter* aWriter, paramType* aVar); 375 376 static bool Read(MessageReader* aReader, RefPtr<paramType>* aVar); 377 }; 378 379 template <> 380 struct ParamTraits<mozilla::ArrayOfRemoteAudioData::RemoteAudioData> { 381 using paramType = mozilla::ArrayOfRemoteAudioData::RemoteAudioData; 382 static void Write(MessageWriter* aWriter, const paramType& aVar); 383 384 static bool Read(MessageReader* aReader, paramType* aVar); 385 }; 386 387 template <> 388 struct ParamTraits<mozilla::ArrayOfRemoteAudioData*> { 389 using paramType = mozilla::ArrayOfRemoteAudioData; 390 static void Write(MessageWriter* aWriter, paramType* aVar); 391 392 static bool Read(MessageReader* aReader, RefPtr<paramType>* aVar); 393 }; 394 } // namespace IPC 395 396 #endif // mozilla_dom_media_ipc_RemoteMediaData_h