summaryrefslogtreecommitdiffstats
path: root/dom/media/ipc/RemoteMediaData.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/media/ipc/RemoteMediaData.h395
1 files changed, 395 insertions, 0 deletions
diff --git a/dom/media/ipc/RemoteMediaData.h b/dom/media/ipc/RemoteMediaData.h
new file mode 100644
index 0000000000..8055a397d9
--- /dev/null
+++ b/dom/media/ipc/RemoteMediaData.h
@@ -0,0 +1,395 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_media_ipc_RemoteMediaData_h
+#define mozilla_dom_media_ipc_RemoteMediaData_h
+
+#include <functional>
+
+#include "MediaData.h"
+#include "PlatformDecoderModule.h"
+#include "ipc/IPCMessageUtils.h"
+#include "mozilla/GfxMessageUtils.h"
+#include "mozilla/PMediaDecoderParams.h"
+#include "mozilla/RemoteImageHolder.h"
+#include "mozilla/ShmemPool.h"
+#include "mozilla/gfx/Rect.h"
+
+namespace mozilla {
+
+class ShmemPool;
+
+namespace ipc {
+class IProtocol;
+class Shmem;
+} // namespace ipc
+
+//-----------------------------------------------------------------------------
+// Declaration of the IPDL type |struct RemoteVideoData|
+//
+// We can't use the generated binding in order to use move semantics properly
+// (see bug 1664362)
+class RemoteVideoData final {
+ private:
+ typedef mozilla::gfx::IntSize IntSize;
+
+ public:
+ RemoteVideoData() = default;
+
+ RemoteVideoData(const MediaDataIPDL& aBase, const IntSize& aDisplay,
+ RemoteImageHolder&& aImage, int32_t aFrameID)
+ : mBase(aBase),
+ mDisplay(aDisplay),
+ mImage(std::move(aImage)),
+ mFrameID(aFrameID) {}
+
+ // This is equivalent to the old RemoteVideoDataIPDL object and is similar to
+ // the RemoteAudioDataIPDL object. To ensure style consistency we use the IPDL
+ // naming convention here.
+ MediaDataIPDL& base() { return mBase; }
+ const MediaDataIPDL& base() const { return mBase; }
+
+ IntSize& display() { return mDisplay; }
+ const IntSize& display() const { return mDisplay; }
+
+ RemoteImageHolder& image() { return mImage; }
+ const RemoteImageHolder& image() const { return mImage; }
+
+ int32_t& frameID() { return mFrameID; }
+ const int32_t& frameID() const { return mFrameID; }
+
+ private:
+ friend struct ipc::IPDLParamTraits<RemoteVideoData>;
+ MediaDataIPDL mBase;
+ IntSize mDisplay;
+ RemoteImageHolder mImage;
+ int32_t mFrameID;
+};
+
+// Until bug 1572054 is resolved, we can't move our objects when using IPDL's
+// union or array. They are always copied. So we make the class refcounted to
+// and always pass it by pointed to bypass the problem for now.
+class ArrayOfRemoteVideoData final {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ArrayOfRemoteVideoData)
+ public:
+ ArrayOfRemoteVideoData() = default;
+ ArrayOfRemoteVideoData(ArrayOfRemoteVideoData&& aOther)
+ : mArray(std::move(aOther.mArray)) {}
+ explicit ArrayOfRemoteVideoData(nsTArray<RemoteVideoData>&& aOther)
+ : mArray(std::move(aOther)) {}
+ ArrayOfRemoteVideoData(const ArrayOfRemoteVideoData& aOther) {
+ MOZ_CRASH("Should never be used but declared by generated IPDL binding");
+ }
+ ArrayOfRemoteVideoData& operator=(ArrayOfRemoteVideoData&& aOther) noexcept {
+ if (this != &aOther) {
+ mArray = std::move(aOther.mArray);
+ }
+ return *this;
+ }
+ ArrayOfRemoteVideoData& operator=(nsTArray<RemoteVideoData>&& aOther) {
+ mArray = std::move(aOther);
+ return *this;
+ }
+
+ void AppendElements(nsTArray<RemoteVideoData>&& aOther) {
+ mArray.AppendElements(std::move(aOther));
+ }
+ void Append(RemoteVideoData&& aVideo) {
+ mArray.AppendElement(std::move(aVideo));
+ }
+ const nsTArray<RemoteVideoData>& Array() const { return mArray; }
+ nsTArray<RemoteVideoData>& Array() { return mArray; }
+
+ private:
+ ~ArrayOfRemoteVideoData() = default;
+ friend struct ipc::IPDLParamTraits<mozilla::ArrayOfRemoteVideoData*>;
+ nsTArray<RemoteVideoData> mArray;
+};
+
+/* The class will pack either an array of AlignedBuffer or MediaByteBuffer
+ * into a single Shmem objects. */
+class RemoteArrayOfByteBuffer {
+ public:
+ RemoteArrayOfByteBuffer();
+ template <typename Type>
+ RemoteArrayOfByteBuffer(const nsTArray<AlignedBuffer<Type>>& aArray,
+ std::function<ShmemBuffer(size_t)>& aAllocator) {
+ // Determine the total size we will need for this object.
+ size_t totalSize = 0;
+ for (auto& buffer : aArray) {
+ totalSize += buffer.Size();
+ }
+ if (totalSize) {
+ if (!AllocateShmem(totalSize, aAllocator)) {
+ return;
+ }
+ }
+ size_t offset = 0;
+ for (auto& buffer : aArray) {
+ if (totalSize && buffer && buffer.Size()) {
+ Write(offset, buffer.Data(), buffer.Size());
+ }
+ mOffsets.AppendElement(OffsetEntry{offset, buffer.Size()});
+ offset += buffer.Size();
+ }
+ mIsValid = true;
+ }
+
+ RemoteArrayOfByteBuffer(const nsTArray<RefPtr<MediaByteBuffer>>& aArray,
+ std::function<ShmemBuffer(size_t)>& aAllocator);
+ RemoteArrayOfByteBuffer& operator=(RemoteArrayOfByteBuffer&& aOther) noexcept;
+
+ // Return the packed aIndexth buffer as an AlignedByteBuffer.
+ // The operation is fallible should an out of memory be encountered. The
+ // result should be tested accordingly.
+ template <typename Type>
+ AlignedBuffer<Type> AlignedBufferAt(size_t aIndex) const {
+ MOZ_ASSERT(aIndex < Count());
+ const OffsetEntry& entry = mOffsets[aIndex];
+ size_t entrySize = std::get<1>(entry);
+ if (!mBuffers || !entrySize) {
+ // It's an empty one.
+ return AlignedBuffer<Type>();
+ }
+ if (!Check(std::get<0>(entry), entrySize)) {
+ // This Shmem is corrupted and can't contain the data we are about to
+ // retrieve. We return an empty array instead of asserting to allow for
+ // recovery.
+ return AlignedBuffer<Type>();
+ }
+ if (0 != entrySize % sizeof(Type)) {
+ // There's an error, that entry can't represent this data.
+ return AlignedBuffer<Type>();
+ }
+ return AlignedBuffer<Type>(
+ reinterpret_cast<Type*>(BuffersStartAddress() + std::get<0>(entry)),
+ entrySize / sizeof(Type));
+ }
+
+ // Return the packed aIndexth buffer as aMediaByteBuffer.
+ // Will return nullptr if the packed buffer was originally empty.
+ already_AddRefed<MediaByteBuffer> MediaByteBufferAt(size_t aIndex) const;
+ // Return the size of the aIndexth buffer.
+ size_t SizeAt(size_t aIndex) const { return std::get<1>(mOffsets[aIndex]); }
+ // Return false if an out of memory error was encountered during construction.
+ bool IsValid() const { return mIsValid; };
+ // Return the number of buffers packed into this entity.
+ size_t Count() const { return mOffsets.Length(); }
+ virtual ~RemoteArrayOfByteBuffer();
+
+ private:
+ friend struct ipc::IPDLParamTraits<RemoteArrayOfByteBuffer>;
+ // Allocate shmem, false if an error occurred.
+ bool AllocateShmem(size_t aSize,
+ std::function<ShmemBuffer(size_t)>& aAllocator);
+ // The starting address of the Shmem
+ uint8_t* BuffersStartAddress() const;
+ // Check that the allocated Shmem can contain such range.
+ bool Check(size_t aOffset, size_t aSizeInBytes) const;
+ void Write(size_t aOffset, const void* aSourceAddr, size_t aSizeInBytes);
+ // Set to false is the buffer isn't initialized yet or a memory error occurred
+ // during construction.
+ bool mIsValid = false;
+ // The packed data. The Maybe will be empty if all buffers packed were
+ // orignally empty.
+ Maybe<ipc::Shmem> mBuffers;
+ // The offset to the start of the individual buffer and its size (all in
+ // bytes)
+ typedef std::tuple<size_t, size_t> OffsetEntry;
+ nsTArray<OffsetEntry> mOffsets;
+};
+
+/* The class will pack an array of MediaRawData using at most three Shmem
+ * objects. Under the most common scenaria, only two Shmems will be used as
+ * there are few videos with an alpha channel in the wild.
+ * We unfortunately can't populate the array at construction nor present an
+ * interface similar to an actual nsTArray or the ArrayOfRemoteVideoData above
+ * as currently IPC serialization is always non-fallible. So we must create the
+ * object first, fill it to determine if we ran out of memory and then send the
+ * object over IPC.
+ */
+class ArrayOfRemoteMediaRawData {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ArrayOfRemoteMediaRawData)
+ public:
+ // Fill the content, return false if an OOM occurred.
+ bool Fill(const nsTArray<RefPtr<MediaRawData>>& aData,
+ std::function<ShmemBuffer(size_t)>&& aAllocator);
+
+ // Return the aIndexth MediaRawData or nullptr if a memory error occurred.
+ already_AddRefed<MediaRawData> ElementAt(size_t aIndex) const;
+
+ // Return the number of MediaRawData stored in this container.
+ size_t Count() const { return mSamples.Length(); }
+ bool IsEmpty() const { return Count() == 0; }
+ bool IsValid() const {
+ return mBuffers.IsValid() && mAlphaBuffers.IsValid() &&
+ mExtraDatas.IsValid();
+ }
+
+ struct RemoteMediaRawData {
+ MediaDataIPDL mBase;
+ bool mEOS;
+ // This will be zero for audio.
+ int32_t mHeight;
+ uint32_t mDiscardPadding;
+ Maybe<media::TimeInterval> mOriginalPresentationWindow;
+ Maybe<CryptoInfo> mCryptoConfig;
+ };
+
+ private:
+ friend struct ipc::IPDLParamTraits<ArrayOfRemoteMediaRawData*>;
+ virtual ~ArrayOfRemoteMediaRawData() = default;
+
+ nsTArray<RemoteMediaRawData> mSamples;
+ RemoteArrayOfByteBuffer mBuffers;
+ RemoteArrayOfByteBuffer mAlphaBuffers;
+ RemoteArrayOfByteBuffer mExtraDatas;
+};
+
+/* The class will pack an array of MediaAudioData using at most a single Shmem
+ * objects.
+ * We unfortunately can't populate the array at construction nor present an
+ * interface similar to an actual nsTArray or the ArrayOfRemoteVideoData above
+ * as currently IPC serialization is always non-fallible. So we must create the
+ * object first, fill it to determine if we ran out of memory and then send the
+ * object over IPC.
+ */
+class ArrayOfRemoteAudioData final {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ArrayOfRemoteAudioData)
+ public:
+ // Fill the content, return false if an OOM occurred.
+ bool Fill(const nsTArray<RefPtr<AudioData>>& aData,
+ std::function<ShmemBuffer(size_t)>&& aAllocator);
+
+ // Return the aIndexth MediaRawData or nullptr if a memory error occurred.
+ already_AddRefed<AudioData> ElementAt(size_t aIndex) const;
+
+ // Return the number of MediaRawData stored in this container.
+ size_t Count() const { return mSamples.Length(); }
+ bool IsEmpty() const { return Count() == 0; }
+ bool IsValid() const { return mBuffers.IsValid(); }
+
+ struct RemoteAudioData {
+ friend struct ipc::IPDLParamTraits<RemoteVideoData>;
+ MediaDataIPDL mBase;
+ uint32_t mChannels;
+ uint32_t mRate;
+ uint32_t mChannelMap;
+ media::TimeUnit mOriginalTime;
+ Maybe<media::TimeInterval> mTrimWindow;
+ uint32_t mFrames;
+ size_t mDataOffset;
+ };
+
+ private:
+ friend struct ipc::IPDLParamTraits<ArrayOfRemoteAudioData*>;
+ ~ArrayOfRemoteAudioData() = default;
+
+ nsTArray<RemoteAudioData> mSamples;
+ RemoteArrayOfByteBuffer mBuffers;
+};
+
+namespace ipc {
+
+template <>
+struct IPDLParamTraits<RemoteVideoData> {
+ typedef RemoteVideoData paramType;
+ static void Write(IPC::MessageWriter* aWriter, ipc::IProtocol* aActor,
+ paramType&& aVar) {
+ WriteIPDLParam(aWriter, aActor, std::move(aVar.mBase));
+ WriteIPDLParam(aWriter, aActor, std::move(aVar.mDisplay));
+ WriteIPDLParam(aWriter, aActor, std::move(aVar.mImage));
+ aWriter->WriteBytes(&aVar.mFrameID, 4);
+ }
+
+ static bool Read(IPC::MessageReader* aReader, mozilla::ipc::IProtocol* aActor,
+ paramType* aVar) {
+ if (!ReadIPDLParam(aReader, aActor, &aVar->mBase) ||
+ !ReadIPDLParam(aReader, aActor, &aVar->mDisplay) ||
+ !ReadIPDLParam(aReader, aActor, &aVar->mImage) ||
+ !aReader->ReadBytesInto(&aVar->mFrameID, 4)) {
+ return false;
+ }
+ return true;
+ }
+};
+
+template <>
+struct IPDLParamTraits<ArrayOfRemoteVideoData*> {
+ typedef ArrayOfRemoteVideoData paramType;
+ static void Write(IPC::MessageWriter* aWriter,
+ mozilla::ipc::IProtocol* aActor, paramType* aVar) {
+ WriteIPDLParam(aWriter, aActor, std::move(aVar->mArray));
+ }
+
+ static bool Read(IPC::MessageReader* aReader, ipc::IProtocol* aActor,
+ RefPtr<paramType>* aVar) {
+ nsTArray<RemoteVideoData> array;
+ if (!ReadIPDLParam(aReader, aActor, &array)) {
+ return false;
+ }
+ auto results = MakeRefPtr<ArrayOfRemoteVideoData>(std::move(array));
+ *aVar = std::move(results);
+ return true;
+ }
+};
+
+template <>
+struct IPDLParamTraits<RemoteArrayOfByteBuffer> {
+ typedef RemoteArrayOfByteBuffer paramType;
+ // We do not want to move the RemoteArrayOfByteBuffer as we want to recycle
+ // the shmem it contains for another time.
+ static void Write(IPC::MessageWriter* aWriter, ipc::IProtocol* aActor,
+ const paramType& aVar);
+
+ static bool Read(IPC::MessageReader* aReader, ipc::IProtocol* aActor,
+ paramType* aVar);
+};
+
+template <>
+struct IPDLParamTraits<ArrayOfRemoteMediaRawData::RemoteMediaRawData> {
+ typedef ArrayOfRemoteMediaRawData::RemoteMediaRawData paramType;
+ static void Write(IPC::MessageWriter* aWriter, ipc::IProtocol* aActor,
+ const paramType& aVar);
+
+ static bool Read(IPC::MessageReader* aReader, ipc::IProtocol* aActor,
+ paramType* aVar);
+};
+
+template <>
+struct IPDLParamTraits<ArrayOfRemoteMediaRawData*> {
+ typedef ArrayOfRemoteMediaRawData paramType;
+ static void Write(IPC::MessageWriter* aWriter, ipc::IProtocol* aActor,
+ paramType* aVar);
+
+ static bool Read(IPC::MessageReader* aReader, ipc::IProtocol* aActor,
+ RefPtr<paramType>* aVar);
+};
+
+template <>
+struct IPDLParamTraits<ArrayOfRemoteAudioData::RemoteAudioData> {
+ typedef ArrayOfRemoteAudioData::RemoteAudioData paramType;
+ static void Write(IPC::MessageWriter* aWriter, ipc::IProtocol* aActor,
+ const paramType& aVar);
+
+ static bool Read(IPC::MessageReader* aReader, ipc::IProtocol* aActor,
+ paramType* aVar);
+};
+
+template <>
+struct IPDLParamTraits<ArrayOfRemoteAudioData*> {
+ typedef ArrayOfRemoteAudioData paramType;
+ static void Write(IPC::MessageWriter* aWriter, ipc::IProtocol* aActor,
+ paramType* aVar);
+
+ static bool Read(IPC::MessageReader* aReader, ipc::IProtocol* aActor,
+ RefPtr<paramType>* aVar);
+};
+} // namespace ipc
+
+} // namespace mozilla
+
+#endif // mozilla_dom_media_ipc_RemoteMediaData_h