зеркало из https://github.com/mozilla/gecko-dev.git
393 строки
14 KiB
C++
393 строки
14 KiB
C++
/* -*- 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 = Get<1>(entry);
|
|
if (!mBuffers || !entrySize) {
|
|
// It's an empty one.
|
|
return AlignedBuffer<Type>();
|
|
}
|
|
if (!Check(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() + 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 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 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;
|
|
uint32_t mDiscardPadding;
|
|
Maybe<media::TimeInterval> mOriginalPresentationWindow;
|
|
};
|
|
|
|
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::Message* aMsg, ipc::IProtocol* aActor,
|
|
paramType&& aVar) {
|
|
WriteIPDLParam(aMsg, aActor, std::move(aVar.mBase));
|
|
WriteIPDLParam(aMsg, aActor, std::move(aVar.mDisplay));
|
|
WriteIPDLParam(aMsg, aActor, std::move(aVar.mImage));
|
|
aMsg->WriteBytes(&aVar.mFrameID, 4);
|
|
}
|
|
|
|
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
|
mozilla::ipc::IProtocol* aActor, paramType* aVar) {
|
|
if (!ReadIPDLParam(aMsg, aIter, aActor, &aVar->mBase) ||
|
|
!ReadIPDLParam(aMsg, aIter, aActor, &aVar->mDisplay) ||
|
|
!ReadIPDLParam(aMsg, aIter, aActor, &aVar->mImage) ||
|
|
!aMsg->ReadBytesInto(aIter, &aVar->mFrameID, 4)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct IPDLParamTraits<ArrayOfRemoteVideoData*> {
|
|
typedef ArrayOfRemoteVideoData paramType;
|
|
static void Write(IPC::Message* aMsg, mozilla::ipc::IProtocol* aActor,
|
|
paramType* aVar) {
|
|
WriteIPDLParam(aMsg, aActor, std::move(aVar->mArray));
|
|
}
|
|
|
|
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
|
ipc::IProtocol* aActor, RefPtr<paramType>* aVar) {
|
|
nsTArray<RemoteVideoData> array;
|
|
if (!ReadIPDLParam(aMsg, aIter, 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::Message* aMsg, ipc::IProtocol* aActor,
|
|
const paramType& aVar);
|
|
|
|
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
|
ipc::IProtocol* aActor, paramType* aVar);
|
|
};
|
|
|
|
template <>
|
|
struct IPDLParamTraits<ArrayOfRemoteMediaRawData::RemoteMediaRawData> {
|
|
typedef ArrayOfRemoteMediaRawData::RemoteMediaRawData paramType;
|
|
static void Write(IPC::Message* aMsg, ipc::IProtocol* aActor,
|
|
const paramType& aVar);
|
|
|
|
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
|
ipc::IProtocol* aActor, paramType* aVar);
|
|
};
|
|
|
|
template <>
|
|
struct IPDLParamTraits<ArrayOfRemoteMediaRawData*> {
|
|
typedef ArrayOfRemoteMediaRawData paramType;
|
|
static void Write(IPC::Message* aMsg, ipc::IProtocol* aActor,
|
|
paramType* aVar);
|
|
|
|
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
|
ipc::IProtocol* aActor, RefPtr<paramType>* aVar);
|
|
};
|
|
|
|
template <>
|
|
struct IPDLParamTraits<ArrayOfRemoteAudioData::RemoteAudioData> {
|
|
typedef ArrayOfRemoteAudioData::RemoteAudioData paramType;
|
|
static void Write(IPC::Message* aMsg, ipc::IProtocol* aActor,
|
|
const paramType& aVar);
|
|
|
|
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
|
ipc::IProtocol* aActor, paramType* aVar);
|
|
};
|
|
|
|
template <>
|
|
struct IPDLParamTraits<ArrayOfRemoteAudioData*> {
|
|
typedef ArrayOfRemoteAudioData paramType;
|
|
static void Write(IPC::Message* aMsg, ipc::IProtocol* aActor,
|
|
paramType* aVar);
|
|
|
|
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
|
ipc::IProtocol* aActor, RefPtr<paramType>* aVar);
|
|
};
|
|
} // namespace ipc
|
|
|
|
} // namespace mozilla
|
|
|
|
#endif // mozilla_dom_media_ipc_RemoteMediaData_h
|