2014-02-04 05:49:21 +04:00
|
|
|
/* -*- 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/. */
|
|
|
|
#if !defined(MediaData_h)
|
|
|
|
#define MediaData_h
|
|
|
|
|
2016-10-12 05:46:28 +03:00
|
|
|
#include "AudioSampleFormat.h"
|
|
|
|
#include "ImageTypes.h"
|
2014-02-04 05:49:21 +04:00
|
|
|
#include "nsSize.h"
|
2014-02-09 12:04:38 +04:00
|
|
|
#include "mozilla/gfx/Rect.h"
|
2014-02-04 05:49:21 +04:00
|
|
|
#include "nsRect.h"
|
|
|
|
#include "nsIMemoryReporter.h"
|
|
|
|
#include "SharedBuffer.h"
|
2015-10-18 08:24:48 +03:00
|
|
|
#include "mozilla/RefPtr.h"
|
2017-04-22 02:12:55 +03:00
|
|
|
#include "mozilla/Span.h"
|
2015-11-02 01:34:26 +03:00
|
|
|
#include "mozilla/UniquePtr.h"
|
2016-04-03 12:25:21 +03:00
|
|
|
#include "mozilla/UniquePtrExtensions.h"
|
2015-01-26 18:01:09 +03:00
|
|
|
#include "nsTArray.h"
|
2016-04-03 12:25:21 +03:00
|
|
|
#include "mozilla/CheckedInt.h"
|
|
|
|
#include "mozilla/PodOperations.h"
|
2017-04-12 12:27:34 +03:00
|
|
|
#include "TimeUnits.h"
|
2014-02-04 05:49:21 +04:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
namespace layers {
|
|
|
|
class Image;
|
|
|
|
class ImageContainer;
|
2015-07-13 18:25:42 +03:00
|
|
|
} // namespace layers
|
2014-02-04 05:49:21 +04:00
|
|
|
|
2015-04-15 08:27:38 +03:00
|
|
|
class MediaByteBuffer;
|
2017-02-13 21:18:05 +03:00
|
|
|
class TrackInfoSharedPtr;
|
2015-04-09 14:14:55 +03:00
|
|
|
|
2016-04-03 12:25:21 +03:00
|
|
|
// AlignedBuffer:
|
|
|
|
// Memory allocations are fallibles. Methods return a boolean indicating if
|
|
|
|
// memory allocations were successful. Return values should always be checked.
|
|
|
|
// AlignedBuffer::mData will be nullptr if no memory has been allocated or if
|
|
|
|
// an error occurred during construction.
|
|
|
|
// Existing data is only ever modified if new memory allocation has succeeded
|
|
|
|
// and preserved if not.
|
|
|
|
//
|
|
|
|
// The memory referenced by mData will always be Alignment bytes aligned and the
|
|
|
|
// underlying buffer will always have a size such that Alignment bytes blocks
|
|
|
|
// can be used to read the content, regardless of the mSize value. Buffer is
|
|
|
|
// zeroed on creation, elements are not individually constructed.
|
|
|
|
// An Alignment value of 0 means that the data isn't aligned.
|
|
|
|
//
|
|
|
|
// Type must be trivially copyable.
|
|
|
|
//
|
|
|
|
// AlignedBuffer can typically be used in place of UniquePtr<Type[]> however
|
|
|
|
// care must be taken as all memory allocations are fallible.
|
|
|
|
// Example:
|
|
|
|
// auto buffer = MakeUniqueFallible<float[]>(samples)
|
|
|
|
// becomes: AlignedFloatBuffer buffer(samples)
|
|
|
|
//
|
|
|
|
// auto buffer = MakeUnique<float[]>(samples)
|
|
|
|
// becomes:
|
|
|
|
// AlignedFloatBuffer buffer(samples);
|
|
|
|
// if (!buffer) { return NS_ERROR_OUT_OF_MEMORY; }
|
|
|
|
|
|
|
|
template <typename Type, int Alignment = 32>
|
|
|
|
class AlignedBuffer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
AlignedBuffer()
|
|
|
|
: mData(nullptr)
|
|
|
|
, mLength(0)
|
|
|
|
, mBuffer(nullptr)
|
|
|
|
, mCapacity(0)
|
2017-02-07 11:15:59 +03:00
|
|
|
{
|
|
|
|
}
|
2016-04-03 12:25:21 +03:00
|
|
|
|
|
|
|
explicit AlignedBuffer(size_t aLength)
|
|
|
|
: mData(nullptr)
|
|
|
|
, mLength(0)
|
|
|
|
, mBuffer(nullptr)
|
|
|
|
, mCapacity(0)
|
|
|
|
{
|
|
|
|
if (EnsureCapacity(aLength)) {
|
|
|
|
mLength = aLength;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AlignedBuffer(const Type* aData, size_t aLength)
|
|
|
|
: AlignedBuffer(aLength)
|
|
|
|
{
|
|
|
|
if (!mData) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
PodCopy(mData, aData, aLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
AlignedBuffer(const AlignedBuffer& aOther)
|
|
|
|
: AlignedBuffer(aOther.Data(), aOther.Length())
|
2017-02-07 11:15:59 +03:00
|
|
|
{
|
|
|
|
}
|
2016-04-03 12:25:21 +03:00
|
|
|
|
|
|
|
AlignedBuffer(AlignedBuffer&& aOther)
|
|
|
|
: mData(aOther.mData)
|
|
|
|
, mLength(aOther.mLength)
|
|
|
|
, mBuffer(Move(aOther.mBuffer))
|
|
|
|
, mCapacity(aOther.mCapacity)
|
|
|
|
{
|
|
|
|
aOther.mData = nullptr;
|
|
|
|
aOther.mLength = 0;
|
|
|
|
aOther.mCapacity = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
AlignedBuffer& operator=(AlignedBuffer&& aOther)
|
|
|
|
{
|
|
|
|
this->~AlignedBuffer();
|
|
|
|
new (this) AlignedBuffer(Move(aOther));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Type* Data() const { return mData; }
|
|
|
|
size_t Length() const { return mLength; }
|
|
|
|
size_t Size() const { return mLength * sizeof(Type); }
|
|
|
|
Type& operator[](size_t aIndex)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aIndex < mLength);
|
|
|
|
return mData[aIndex];
|
|
|
|
}
|
|
|
|
const Type& operator[](size_t aIndex) const
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aIndex < mLength);
|
|
|
|
return mData[aIndex];
|
|
|
|
}
|
|
|
|
// Set length of buffer, allocating memory as required.
|
|
|
|
// If length is increased, new buffer area is filled with 0.
|
|
|
|
bool SetLength(size_t aLength)
|
|
|
|
{
|
|
|
|
if (aLength > mLength && !EnsureCapacity(aLength)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
mLength = aLength;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// Add aData at the beginning of buffer.
|
|
|
|
bool Prepend(const Type* aData, size_t aLength)
|
|
|
|
{
|
|
|
|
if (!EnsureCapacity(aLength + mLength)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shift the data to the right by aLength to leave room for the new data.
|
|
|
|
PodMove(mData + aLength, mData, mLength);
|
|
|
|
PodCopy(mData, aData, aLength);
|
|
|
|
|
|
|
|
mLength += aLength;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// Add aData at the end of buffer.
|
|
|
|
bool Append(const Type* aData, size_t aLength)
|
|
|
|
{
|
|
|
|
if (!EnsureCapacity(aLength + mLength)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
PodCopy(mData + mLength, aData, aLength);
|
|
|
|
|
|
|
|
mLength += aLength;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// Replace current content with aData.
|
|
|
|
bool Replace(const Type* aData, size_t aLength)
|
|
|
|
{
|
|
|
|
// If aLength is smaller than our current length, we leave the buffer as is,
|
|
|
|
// only adjusting the reported length.
|
|
|
|
if (!EnsureCapacity(aLength)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
PodCopy(mData, aData, aLength);
|
|
|
|
mLength = aLength;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// Clear the memory buffer. Will set target mData and mLength to 0.
|
|
|
|
void Clear()
|
|
|
|
{
|
|
|
|
mLength = 0;
|
|
|
|
mData = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Methods for reporting memory.
|
|
|
|
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
|
|
|
{
|
|
|
|
size_t size = aMallocSizeOf(this);
|
|
|
|
size += aMallocSizeOf(mBuffer.get());
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
// AlignedBuffer is typically allocated on the stack. As such, you likely
|
|
|
|
// want to use SizeOfExcludingThis
|
|
|
|
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
|
|
|
{
|
|
|
|
return aMallocSizeOf(mBuffer.get());
|
|
|
|
}
|
|
|
|
size_t ComputedSizeOfExcludingThis() const
|
|
|
|
{
|
|
|
|
return mCapacity;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For backward compatibility with UniquePtr<Type[]>
|
|
|
|
Type* get() const { return mData; }
|
|
|
|
explicit operator bool() const { return mData != nullptr; }
|
|
|
|
|
2016-04-09 14:11:16 +03:00
|
|
|
// Size in bytes of extra space allocated for padding.
|
|
|
|
static size_t AlignmentPaddingSize()
|
|
|
|
{
|
|
|
|
return AlignmentOffset() * 2;
|
|
|
|
}
|
|
|
|
|
2016-04-03 12:25:21 +03:00
|
|
|
private:
|
2016-04-09 14:11:16 +03:00
|
|
|
static size_t AlignmentOffset()
|
2016-04-03 12:25:21 +03:00
|
|
|
{
|
|
|
|
return Alignment ? Alignment - 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that the backend buffer can hold aLength data. Will update mData.
|
|
|
|
// Will enforce that the start of allocated data is always Alignment bytes
|
|
|
|
// aligned and that it has sufficient end padding to allow for Alignment bytes
|
|
|
|
// block read as required by some data decoders.
|
|
|
|
// Returns false if memory couldn't be allocated.
|
|
|
|
bool EnsureCapacity(size_t aLength)
|
|
|
|
{
|
2016-12-16 08:20:06 +03:00
|
|
|
if (!aLength) {
|
|
|
|
// No need to allocate a buffer yet.
|
|
|
|
return true;
|
|
|
|
}
|
2016-04-03 12:25:21 +03:00
|
|
|
const CheckedInt<size_t> sizeNeeded =
|
2016-04-09 14:11:16 +03:00
|
|
|
CheckedInt<size_t>(aLength) * sizeof(Type) + AlignmentPaddingSize();
|
2016-04-03 12:25:21 +03:00
|
|
|
|
2016-05-03 03:03:18 +03:00
|
|
|
if (!sizeNeeded.isValid() || sizeNeeded.value() >= INT32_MAX) {
|
|
|
|
// overflow or over an acceptable size.
|
2016-04-03 12:25:21 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (mData && mCapacity >= sizeNeeded.value()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
auto newBuffer = MakeUniqueFallible<uint8_t[]>(sizeNeeded.value());
|
|
|
|
if (!newBuffer) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find alignment address.
|
|
|
|
const uintptr_t alignmask = AlignmentOffset();
|
|
|
|
Type* newData = reinterpret_cast<Type*>(
|
|
|
|
(reinterpret_cast<uintptr_t>(newBuffer.get()) + alignmask) & ~alignmask);
|
|
|
|
MOZ_ASSERT(uintptr_t(newData) % (AlignmentOffset()+1) == 0);
|
|
|
|
|
2016-04-20 09:07:16 +03:00
|
|
|
MOZ_ASSERT(!mLength || mData);
|
|
|
|
|
2016-04-03 12:25:21 +03:00
|
|
|
PodZero(newData + mLength, aLength - mLength);
|
2016-04-20 09:07:16 +03:00
|
|
|
if (mLength) {
|
|
|
|
PodCopy(newData, mData, mLength);
|
|
|
|
}
|
2016-04-03 12:25:21 +03:00
|
|
|
|
|
|
|
mBuffer = Move(newBuffer);
|
|
|
|
mCapacity = sizeNeeded.value();
|
|
|
|
mData = newData;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
Type* mData;
|
|
|
|
size_t mLength;
|
|
|
|
UniquePtr<uint8_t[]> mBuffer;
|
|
|
|
size_t mCapacity;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef AlignedBuffer<uint8_t> AlignedByteBuffer;
|
|
|
|
typedef AlignedBuffer<float> AlignedFloatBuffer;
|
|
|
|
typedef AlignedBuffer<int16_t> AlignedShortBuffer;
|
|
|
|
typedef AlignedBuffer<AudioDataValue> AlignedAudioBuffer;
|
|
|
|
|
2014-02-04 05:49:21 +04:00
|
|
|
// Container that holds media samples.
|
2017-01-27 15:20:37 +03:00
|
|
|
class MediaData
|
|
|
|
{
|
2014-02-04 05:49:21 +04:00
|
|
|
public:
|
|
|
|
|
2014-11-20 00:01:10 +03:00
|
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaData)
|
|
|
|
|
2017-01-27 15:20:37 +03:00
|
|
|
enum Type
|
|
|
|
{
|
2014-11-03 11:20:14 +03:00
|
|
|
AUDIO_DATA = 0,
|
2015-04-09 14:14:55 +03:00
|
|
|
VIDEO_DATA,
|
2016-06-08 05:59:57 +03:00
|
|
|
RAW_DATA,
|
|
|
|
NULL_DATA
|
2014-02-04 05:49:21 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
MediaData(Type aType,
|
|
|
|
int64_t aOffset,
|
2017-04-24 12:33:05 +03:00
|
|
|
const media::TimeUnit& aTimestamp,
|
|
|
|
const media::TimeUnit& aDuration,
|
2015-07-27 19:21:33 +03:00
|
|
|
uint32_t aFrames)
|
2014-02-04 05:49:21 +04:00
|
|
|
: mType(aType)
|
|
|
|
, mOffset(aOffset)
|
2017-04-24 12:33:05 +03:00
|
|
|
, mTime(aTimestamp)
|
|
|
|
, mTimecode(aTimestamp)
|
|
|
|
, mDuration(aDuration)
|
2015-07-27 19:21:33 +03:00
|
|
|
, mFrames(aFrames)
|
2015-04-09 14:14:55 +03:00
|
|
|
, mKeyframe(false)
|
2017-01-27 15:20:37 +03:00
|
|
|
{
|
|
|
|
}
|
2014-02-04 05:49:21 +04:00
|
|
|
|
|
|
|
// Type of contained data.
|
|
|
|
const Type mType;
|
|
|
|
|
|
|
|
// Approximate byte offset where this data was demuxed from its media.
|
2015-04-09 14:14:55 +03:00
|
|
|
int64_t mOffset;
|
2014-02-04 05:49:21 +04:00
|
|
|
|
2017-04-14 12:13:36 +03:00
|
|
|
// Start time of sample.
|
|
|
|
media::TimeUnit mTime;
|
2015-04-09 14:14:55 +03:00
|
|
|
|
|
|
|
// Codec specific internal time code. For Ogg based codecs this is the
|
|
|
|
// granulepos.
|
2017-04-14 09:52:14 +03:00
|
|
|
media::TimeUnit mTimecode;
|
2014-02-04 05:49:21 +04:00
|
|
|
|
|
|
|
// Duration of sample, in microseconds.
|
2017-04-12 12:27:34 +03:00
|
|
|
media::TimeUnit mDuration;
|
2015-04-09 14:14:55 +03:00
|
|
|
|
2015-07-27 19:21:33 +03:00
|
|
|
// Amount of frames for contained data.
|
|
|
|
const uint32_t mFrames;
|
|
|
|
|
2015-04-09 14:14:55 +03:00
|
|
|
bool mKeyframe;
|
2014-02-04 05:49:21 +04:00
|
|
|
|
2017-04-14 09:14:08 +03:00
|
|
|
media::TimeUnit GetEndTime() const
|
|
|
|
{
|
2017-04-14 12:13:36 +03:00
|
|
|
return mTime + mDuration;
|
2017-04-14 09:14:08 +03:00
|
|
|
}
|
2014-02-04 05:49:21 +04:00
|
|
|
|
2015-06-07 01:01:23 +03:00
|
|
|
bool AdjustForStartTime(int64_t aStartTime)
|
|
|
|
{
|
2017-04-14 12:13:36 +03:00
|
|
|
mTime = mTime - media::TimeUnit::FromMicroseconds(aStartTime);
|
|
|
|
return !mTime.IsNegative();
|
2015-06-07 01:01:23 +03:00
|
|
|
}
|
2015-07-27 19:21:33 +03:00
|
|
|
|
|
|
|
template <typename ReturnType>
|
|
|
|
const ReturnType* As() const
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(this->mType == ReturnType::sType);
|
|
|
|
return static_cast<const ReturnType*>(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename ReturnType>
|
|
|
|
ReturnType* As()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(this->mType == ReturnType::sType);
|
|
|
|
return static_cast<ReturnType*>(this);
|
|
|
|
}
|
|
|
|
|
2014-11-20 00:01:10 +03:00
|
|
|
protected:
|
2015-07-27 19:21:33 +03:00
|
|
|
MediaData(Type aType, uint32_t aFrames)
|
2015-04-09 14:14:55 +03:00
|
|
|
: mType(aType)
|
|
|
|
, mOffset(0)
|
2015-07-27 19:21:33 +03:00
|
|
|
, mFrames(aFrames)
|
2015-04-09 14:14:55 +03:00
|
|
|
, mKeyframe(false)
|
2017-01-27 15:20:37 +03:00
|
|
|
{
|
|
|
|
}
|
2015-04-09 14:14:55 +03:00
|
|
|
|
2017-02-07 11:15:59 +03:00
|
|
|
virtual ~MediaData() { }
|
2014-11-20 00:01:10 +03:00
|
|
|
|
2014-02-04 05:49:21 +04:00
|
|
|
};
|
|
|
|
|
2016-06-08 05:59:57 +03:00
|
|
|
// NullData is for decoder generating a sample which doesn't need to be
|
|
|
|
// rendered.
|
2017-01-27 15:20:37 +03:00
|
|
|
class NullData : public MediaData
|
|
|
|
{
|
2016-06-08 05:59:57 +03:00
|
|
|
public:
|
2017-04-24 12:33:05 +03:00
|
|
|
NullData(int64_t aOffset,
|
|
|
|
const media::TimeUnit& aTime,
|
|
|
|
const media::TimeUnit& aDuration)
|
2016-06-08 05:59:57 +03:00
|
|
|
: MediaData(NULL_DATA, aOffset, aTime, aDuration, 0)
|
2017-02-07 11:15:59 +03:00
|
|
|
{
|
|
|
|
}
|
2016-06-08 05:59:57 +03:00
|
|
|
|
|
|
|
static const Type sType = NULL_DATA;
|
|
|
|
};
|
|
|
|
|
2014-02-04 05:49:21 +04:00
|
|
|
// Holds chunk a decoded audio frames.
|
2017-01-27 15:20:37 +03:00
|
|
|
class AudioData : public MediaData
|
|
|
|
{
|
2014-02-04 05:49:21 +04:00
|
|
|
public:
|
|
|
|
|
|
|
|
AudioData(int64_t aOffset,
|
2017-04-24 12:33:05 +03:00
|
|
|
const media::TimeUnit& aTime,
|
|
|
|
const media::TimeUnit& aDuration,
|
2014-02-04 05:49:21 +04:00
|
|
|
uint32_t aFrames,
|
2016-04-03 16:09:45 +03:00
|
|
|
AlignedAudioBuffer&& aData,
|
2014-08-11 09:27:00 +04:00
|
|
|
uint32_t aChannels,
|
|
|
|
uint32_t aRate)
|
2015-07-27 19:21:33 +03:00
|
|
|
: MediaData(sType, aOffset, aTime, aDuration, aFrames)
|
2014-02-04 05:49:21 +04:00
|
|
|
, mChannels(aChannels)
|
2014-08-11 09:27:00 +04:00
|
|
|
, mRate(aRate)
|
2017-02-07 11:15:59 +03:00
|
|
|
, mAudioData(Move(aData))
|
|
|
|
{
|
|
|
|
}
|
2014-02-04 05:49:21 +04:00
|
|
|
|
2015-06-07 00:42:40 +03:00
|
|
|
static const Type sType = AUDIO_DATA;
|
|
|
|
static const char* sTypeName;
|
|
|
|
|
2015-09-10 04:06:00 +03:00
|
|
|
// Creates a new AudioData identical to aOther, but with a different
|
2015-02-09 15:28:59 +03:00
|
|
|
// specified timestamp and duration. All data from aOther is copied
|
|
|
|
// into the new AudioData but the audio data which is transferred.
|
|
|
|
// After such call, the original aOther is unusable.
|
|
|
|
static already_AddRefed<AudioData>
|
|
|
|
TransferAndUpdateTimestampAndDuration(AudioData* aOther,
|
2017-04-24 12:33:05 +03:00
|
|
|
const media::TimeUnit& aTimestamp,
|
|
|
|
const media::TimeUnit& aDuration);
|
2015-02-09 15:28:59 +03:00
|
|
|
|
2014-05-13 21:38:00 +04:00
|
|
|
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
|
2014-02-04 05:49:21 +04:00
|
|
|
|
|
|
|
// If mAudioBuffer is null, creates it from mAudioData.
|
|
|
|
void EnsureAudioBuffer();
|
|
|
|
|
2016-01-21 05:19:19 +03:00
|
|
|
// To check whether mAudioData has audible signal, it's used to distinguish
|
|
|
|
// the audiable data and silent data.
|
|
|
|
bool IsAudible() const;
|
|
|
|
|
2014-02-04 05:49:21 +04:00
|
|
|
const uint32_t mChannels;
|
2014-08-11 09:27:00 +04:00
|
|
|
const uint32_t mRate;
|
2014-02-04 05:49:21 +04:00
|
|
|
// At least one of mAudioBuffer/mAudioData must be non-null.
|
|
|
|
// mChannels channels, each with mFrames frames
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<SharedBuffer> mAudioBuffer;
|
2014-02-04 05:49:21 +04:00
|
|
|
// mFrames frames, each with mChannels values
|
2016-04-03 16:09:45 +03:00
|
|
|
AlignedAudioBuffer mAudioData;
|
2014-11-20 00:01:10 +03:00
|
|
|
|
|
|
|
protected:
|
2017-01-27 15:20:37 +03:00
|
|
|
~AudioData() { }
|
2014-02-04 05:49:21 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
namespace layers {
|
2014-03-31 19:24:28 +04:00
|
|
|
class TextureClient;
|
2014-02-18 18:50:20 +04:00
|
|
|
class PlanarYCbCrImage;
|
2015-07-13 18:25:42 +03:00
|
|
|
} // namespace layers
|
2014-02-04 05:49:21 +04:00
|
|
|
|
|
|
|
class VideoInfo;
|
|
|
|
|
|
|
|
// Holds a decoded video frame, in YCbCr format. These are queued in the reader.
|
2017-01-27 15:20:37 +03:00
|
|
|
class VideoData : public MediaData
|
|
|
|
{
|
2014-02-04 05:49:21 +04:00
|
|
|
public:
|
2014-02-09 12:04:38 +04:00
|
|
|
typedef gfx::IntRect IntRect;
|
|
|
|
typedef gfx::IntSize IntSize;
|
2014-02-04 05:49:21 +04:00
|
|
|
typedef layers::ImageContainer ImageContainer;
|
|
|
|
typedef layers::Image Image;
|
2014-02-18 18:50:20 +04:00
|
|
|
typedef layers::PlanarYCbCrImage PlanarYCbCrImage;
|
2014-02-04 05:49:21 +04:00
|
|
|
|
2015-06-07 00:42:40 +03:00
|
|
|
static const Type sType = VIDEO_DATA;
|
|
|
|
static const char* sTypeName;
|
|
|
|
|
2014-02-04 05:49:21 +04:00
|
|
|
// YCbCr data obtained from decoding the video. The index's are:
|
|
|
|
// 0 = Y
|
|
|
|
// 1 = Cb
|
|
|
|
// 2 = Cr
|
2017-01-27 15:20:37 +03:00
|
|
|
struct YCbCrBuffer
|
|
|
|
{
|
|
|
|
struct Plane
|
|
|
|
{
|
2014-02-04 05:49:21 +04:00
|
|
|
uint8_t* mData;
|
|
|
|
uint32_t mWidth;
|
|
|
|
uint32_t mHeight;
|
|
|
|
uint32_t mStride;
|
|
|
|
uint32_t mOffset;
|
|
|
|
uint32_t mSkip;
|
|
|
|
};
|
|
|
|
|
|
|
|
Plane mPlanes[3];
|
2016-10-12 05:46:28 +03:00
|
|
|
YUVColorSpace mYUVColorSpace = YUVColorSpace::BT601;
|
2014-02-04 05:49:21 +04:00
|
|
|
};
|
|
|
|
|
2017-01-27 15:20:37 +03:00
|
|
|
class Listener
|
|
|
|
{
|
2016-11-23 10:08:17 +03:00
|
|
|
public:
|
|
|
|
virtual void OnSentToCompositor() = 0;
|
2017-02-07 11:15:59 +03:00
|
|
|
virtual ~Listener() { }
|
2016-11-23 10:08:17 +03:00
|
|
|
};
|
|
|
|
|
2014-02-04 05:49:21 +04:00
|
|
|
// Constructs a VideoData object. If aImage is nullptr, creates a new Image
|
|
|
|
// holding a copy of the YCbCr data passed in aBuffer. If aImage is not
|
|
|
|
// nullptr, it's stored as the underlying video image and aBuffer is assumed
|
|
|
|
// to point to memory within aImage so no copy is made. aTimecode is a codec
|
|
|
|
// specific number representing the timestamp of the frame of video data.
|
|
|
|
// Returns nsnull if an error occurs. This may indicate that memory couldn't
|
|
|
|
// be allocated to create the VideoData object, or it may indicate some
|
|
|
|
// problem with the input data (e.g. negative stride).
|
2016-08-04 06:31:52 +03:00
|
|
|
|
|
|
|
|
2017-02-07 11:15:59 +03:00
|
|
|
// Creates a new VideoData containing a deep copy of aBuffer. May use
|
|
|
|
// aContainer to allocate an Image to hold the copied data.
|
2017-01-27 15:20:37 +03:00
|
|
|
static already_AddRefed<VideoData> CreateAndCopyData(
|
|
|
|
const VideoInfo& aInfo,
|
|
|
|
ImageContainer* aContainer,
|
|
|
|
int64_t aOffset,
|
2017-04-24 12:33:05 +03:00
|
|
|
const media::TimeUnit& aTime,
|
2017-04-12 12:46:09 +03:00
|
|
|
const media::TimeUnit& aDuration,
|
2017-02-07 11:15:59 +03:00
|
|
|
const YCbCrBuffer& aBuffer,
|
2017-01-27 15:20:37 +03:00
|
|
|
bool aKeyframe,
|
2017-04-24 12:33:05 +03:00
|
|
|
const media::TimeUnit& aTimecode,
|
2017-01-27 15:20:37 +03:00
|
|
|
const IntRect& aPicture);
|
|
|
|
|
|
|
|
static already_AddRefed<VideoData> CreateAndCopyData(
|
|
|
|
const VideoInfo& aInfo,
|
|
|
|
ImageContainer* aContainer,
|
|
|
|
int64_t aOffset,
|
2017-04-24 12:33:05 +03:00
|
|
|
const media::TimeUnit& aTime,
|
2017-04-12 12:46:09 +03:00
|
|
|
const media::TimeUnit& aDuration,
|
2017-02-07 11:15:59 +03:00
|
|
|
const YCbCrBuffer& aBuffer,
|
|
|
|
const YCbCrBuffer::Plane& aAlphaPlane,
|
2017-01-27 15:20:37 +03:00
|
|
|
bool aKeyframe,
|
2017-04-24 12:33:05 +03:00
|
|
|
const media::TimeUnit& aTimecode,
|
2017-01-27 15:20:37 +03:00
|
|
|
const IntRect& aPicture);
|
|
|
|
|
|
|
|
static already_AddRefed<VideoData> CreateAndCopyIntoTextureClient(
|
|
|
|
const VideoInfo& aInfo,
|
|
|
|
int64_t aOffset,
|
2017-04-24 12:33:05 +03:00
|
|
|
const media::TimeUnit& aTime,
|
2017-04-12 12:46:09 +03:00
|
|
|
const media::TimeUnit& aDuration,
|
2017-01-27 15:20:37 +03:00
|
|
|
layers::TextureClient* aBuffer,
|
|
|
|
bool aKeyframe,
|
2017-04-24 12:33:05 +03:00
|
|
|
const media::TimeUnit& aTimecode,
|
2017-01-27 15:20:37 +03:00
|
|
|
const IntRect& aPicture);
|
|
|
|
|
|
|
|
static already_AddRefed<VideoData> CreateFromImage(
|
2017-03-09 07:06:24 +03:00
|
|
|
const IntSize& aDisplay,
|
2017-01-27 15:20:37 +03:00
|
|
|
int64_t aOffset,
|
2017-04-24 12:33:05 +03:00
|
|
|
const media::TimeUnit& aTime,
|
2017-04-12 12:46:09 +03:00
|
|
|
const media::TimeUnit& aDuration,
|
2017-01-27 15:20:37 +03:00
|
|
|
const RefPtr<Image>& aImage,
|
|
|
|
bool aKeyframe,
|
2017-04-24 12:33:05 +03:00
|
|
|
const media::TimeUnit& aTimecode);
|
2014-02-04 05:49:21 +04:00
|
|
|
|
2014-02-18 18:50:20 +04:00
|
|
|
// Initialize PlanarYCbCrImage. Only When aCopyData is true,
|
|
|
|
// video data is copied to PlanarYCbCrImage.
|
2015-11-03 14:24:26 +03:00
|
|
|
static bool SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
|
2015-04-14 08:15:46 +03:00
|
|
|
const VideoInfo& aInfo,
|
2017-02-07 11:15:59 +03:00
|
|
|
const YCbCrBuffer& aBuffer,
|
2014-02-18 18:50:20 +04:00
|
|
|
const IntRect& aPicture,
|
|
|
|
bool aCopyData);
|
|
|
|
|
2014-03-20 01:33:12 +04:00
|
|
|
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
|
|
|
|
|
2014-02-04 05:49:21 +04:00
|
|
|
// Dimensions at which to display the video frame. The picture region
|
|
|
|
// will be scaled to this size. This is should be the picture region's
|
|
|
|
// dimensions scaled with respect to its aspect ratio.
|
2014-02-09 12:04:38 +04:00
|
|
|
const IntSize mDisplay;
|
2014-02-04 05:49:21 +04:00
|
|
|
|
|
|
|
// This frame's image.
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Image> mImage;
|
2014-02-04 05:49:21 +04:00
|
|
|
|
2015-06-07 12:34:00 +03:00
|
|
|
int32_t mFrameID;
|
2014-02-04 05:49:21 +04:00
|
|
|
|
|
|
|
VideoData(int64_t aOffset,
|
2017-04-24 12:33:05 +03:00
|
|
|
const media::TimeUnit& aTime,
|
|
|
|
const media::TimeUnit& aDuration,
|
2014-02-04 05:49:21 +04:00
|
|
|
bool aKeyframe,
|
2017-04-24 12:33:05 +03:00
|
|
|
const media::TimeUnit& aTimecode,
|
2015-06-07 12:34:00 +03:00
|
|
|
IntSize aDisplay,
|
2015-08-12 02:02:41 +03:00
|
|
|
uint32_t aFrameID);
|
2014-02-04 05:49:21 +04:00
|
|
|
|
2016-11-23 10:08:17 +03:00
|
|
|
void SetListener(UniquePtr<Listener> aListener);
|
|
|
|
void MarkSentToCompositor();
|
|
|
|
bool IsSentToCompositor() { return mSentToCompositor; }
|
|
|
|
|
2017-04-12 12:34:06 +03:00
|
|
|
void UpdateDuration(const media::TimeUnit& aDuration);
|
2017-04-14 09:17:04 +03:00
|
|
|
void UpdateTimestamp(const media::TimeUnit& aTimestamp);
|
2016-12-15 12:57:21 +03:00
|
|
|
|
2014-11-20 00:01:10 +03:00
|
|
|
protected:
|
|
|
|
~VideoData();
|
2016-11-23 10:08:17 +03:00
|
|
|
|
|
|
|
bool mSentToCompositor;
|
|
|
|
UniquePtr<Listener> mListener;
|
2014-02-04 05:49:21 +04:00
|
|
|
};
|
|
|
|
|
2015-04-09 14:14:55 +03:00
|
|
|
class CryptoTrack
|
|
|
|
{
|
|
|
|
public:
|
2017-01-27 15:20:37 +03:00
|
|
|
CryptoTrack() : mValid(false), mMode(0), mIVSize(0) { }
|
2015-04-09 14:14:56 +03:00
|
|
|
bool mValid;
|
|
|
|
int32_t mMode;
|
|
|
|
int32_t mIVSize;
|
|
|
|
nsTArray<uint8_t> mKeyId;
|
2015-04-09 14:14:55 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
class CryptoSample : public CryptoTrack
|
|
|
|
{
|
|
|
|
public:
|
2015-04-09 14:14:56 +03:00
|
|
|
nsTArray<uint16_t> mPlainSizes;
|
|
|
|
nsTArray<uint32_t> mEncryptedSizes;
|
|
|
|
nsTArray<uint8_t> mIV;
|
|
|
|
nsTArray<nsCString> mSessionIds;
|
2015-04-09 14:14:55 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
// MediaRawData is a MediaData container used to store demuxed, still compressed
|
|
|
|
// samples.
|
|
|
|
// Use MediaRawData::CreateWriter() to obtain a MediaRawDataWriter object that
|
|
|
|
// provides methods to modify and manipulate the data.
|
2016-04-03 12:25:21 +03:00
|
|
|
// Memory allocations are fallible. Methods return a boolean indicating if
|
2015-04-09 14:14:55 +03:00
|
|
|
// memory allocations were successful. Return values should always be checked.
|
|
|
|
// MediaRawData::mData will be nullptr if no memory has been allocated or if
|
|
|
|
// an error occurred during construction.
|
|
|
|
// Existing data is only ever modified if new memory allocation has succeeded
|
|
|
|
// and preserved if not.
|
|
|
|
//
|
|
|
|
// The memory referenced by mData will always be 32 bytes aligned and the
|
|
|
|
// underlying buffer will always have a size such that 32 bytes blocks can be
|
|
|
|
// used to read the content, regardless of the mSize value. Buffer is zeroed
|
|
|
|
// on creation.
|
|
|
|
//
|
|
|
|
// Typical usage: create new MediaRawData; create the associated
|
|
|
|
// MediaRawDataWriter, call SetSize() to allocate memory, write to mData,
|
|
|
|
// up to mSize bytes.
|
|
|
|
|
|
|
|
class MediaRawData;
|
|
|
|
|
|
|
|
class MediaRawDataWriter
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
// Pointer to data or null if not-yet allocated
|
2015-08-06 03:58:35 +03:00
|
|
|
uint8_t* Data();
|
2015-04-09 14:14:55 +03:00
|
|
|
// Writeable size of buffer.
|
2015-08-06 03:58:35 +03:00
|
|
|
size_t Size();
|
2015-04-14 08:15:46 +03:00
|
|
|
// Writeable reference to MediaRawData::mCryptoInternal
|
|
|
|
CryptoSample& mCrypto;
|
2015-04-09 14:14:55 +03:00
|
|
|
|
|
|
|
// Data manipulation methods. mData and mSize may be updated accordingly.
|
|
|
|
|
|
|
|
// Set size of buffer, allocating memory as required.
|
|
|
|
// If size is increased, new buffer area is filled with 0.
|
|
|
|
bool SetSize(size_t aSize);
|
|
|
|
// Add aData at the beginning of buffer.
|
|
|
|
bool Prepend(const uint8_t* aData, size_t aSize);
|
|
|
|
// Replace current content with aData.
|
|
|
|
bool Replace(const uint8_t* aData, size_t aSize);
|
2015-08-06 03:58:35 +03:00
|
|
|
// Clear the memory buffer. Will set target mData and mSize to 0.
|
2015-04-09 14:14:55 +03:00
|
|
|
void Clear();
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend class MediaRawData;
|
|
|
|
explicit MediaRawDataWriter(MediaRawData* aMediaRawData);
|
|
|
|
bool EnsureSize(size_t aSize);
|
|
|
|
MediaRawData* mTarget;
|
|
|
|
};
|
|
|
|
|
2017-01-27 15:20:37 +03:00
|
|
|
class MediaRawData : public MediaData
|
|
|
|
{
|
2015-04-09 14:14:55 +03:00
|
|
|
public:
|
|
|
|
MediaRawData();
|
2016-11-23 01:52:16 +03:00
|
|
|
MediaRawData(const uint8_t* aData, size_t aSize);
|
|
|
|
MediaRawData(const uint8_t* aData, size_t aSize,
|
|
|
|
const uint8_t* aAlphaData, size_t aAlphaSize);
|
2015-04-09 14:14:55 +03:00
|
|
|
|
|
|
|
// Pointer to data or null if not-yet allocated
|
2016-04-03 14:05:23 +03:00
|
|
|
const uint8_t* Data() const { return mBuffer.Data(); }
|
2016-11-23 01:52:16 +03:00
|
|
|
// Pointer to alpha data or null if not-yet allocated
|
|
|
|
const uint8_t* AlphaData() const { return mAlphaBuffer.Data(); }
|
2015-04-09 14:14:55 +03:00
|
|
|
// Size of buffer.
|
2016-04-03 14:05:23 +03:00
|
|
|
size_t Size() const { return mBuffer.Length(); }
|
2016-11-23 01:52:16 +03:00
|
|
|
size_t AlphaSize() const { return mAlphaBuffer.Length(); }
|
2015-08-05 14:45:53 +03:00
|
|
|
size_t ComputedSizeOfIncludingThis() const
|
|
|
|
{
|
2016-11-23 01:52:16 +03:00
|
|
|
return sizeof(*this)
|
|
|
|
+ mBuffer.ComputedSizeOfExcludingThis()
|
|
|
|
+ mAlphaBuffer.ComputedSizeOfExcludingThis();
|
2015-08-05 14:45:53 +03:00
|
|
|
}
|
2017-04-22 02:12:55 +03:00
|
|
|
// Access the buffer as a Span.
|
|
|
|
operator Span<const uint8_t>() { return MakeSpan(Data(), Size()); }
|
2015-04-09 14:14:55 +03:00
|
|
|
|
2015-04-14 08:15:46 +03:00
|
|
|
const CryptoSample& mCrypto;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaByteBuffer> mExtraData;
|
2015-04-09 14:14:55 +03:00
|
|
|
|
2016-07-28 19:19:21 +03:00
|
|
|
// Used by the Vorbis decoder and Ogg demuxer.
|
|
|
|
// Indicates that this is the last packet of the stream.
|
|
|
|
bool mEOS = false;
|
|
|
|
|
2016-11-30 09:24:45 +03:00
|
|
|
// Indicate to the audio decoder that mDiscardPadding frames should be
|
|
|
|
// trimmed.
|
|
|
|
uint32_t mDiscardPadding = 0;
|
|
|
|
|
2017-02-13 21:18:05 +03:00
|
|
|
RefPtr<TrackInfoSharedPtr> mTrackInfo;
|
2015-06-12 08:18:05 +03:00
|
|
|
|
2015-04-09 14:14:55 +03:00
|
|
|
// Return a deep copy or nullptr if out of memory.
|
|
|
|
virtual already_AddRefed<MediaRawData> Clone() const;
|
|
|
|
// Create a MediaRawDataWriter for this MediaRawData. The caller must
|
|
|
|
// delete the writer once done. The writer is not thread-safe.
|
|
|
|
virtual MediaRawDataWriter* CreateWriter();
|
|
|
|
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
~MediaRawData();
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend class MediaRawDataWriter;
|
2016-04-03 14:05:23 +03:00
|
|
|
AlignedByteBuffer mBuffer;
|
2016-11-23 01:52:16 +03:00
|
|
|
AlignedByteBuffer mAlphaBuffer;
|
2015-04-14 08:15:46 +03:00
|
|
|
CryptoSample mCryptoInternal;
|
2015-04-09 14:14:55 +03:00
|
|
|
MediaRawData(const MediaRawData&); // Not implemented
|
|
|
|
};
|
|
|
|
|
2015-04-15 08:27:38 +03:00
|
|
|
// MediaByteBuffer is a ref counted infallible TArray.
|
2017-02-07 11:15:59 +03:00
|
|
|
class MediaByteBuffer : public nsTArray<uint8_t>
|
|
|
|
{
|
2015-04-15 08:27:38 +03:00
|
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaByteBuffer);
|
2015-07-17 08:46:44 +03:00
|
|
|
MediaByteBuffer() = default;
|
2017-01-27 15:20:37 +03:00
|
|
|
explicit MediaByteBuffer(size_t aCapacity) : nsTArray<uint8_t>(aCapacity) { }
|
2015-04-09 14:14:55 +03:00
|
|
|
|
|
|
|
private:
|
2017-01-27 15:20:37 +03:00
|
|
|
~MediaByteBuffer() { }
|
2015-04-09 14:14:55 +03:00
|
|
|
};
|
|
|
|
|
2014-02-04 05:49:21 +04:00
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
#endif // MediaData_h
|