diff options
Diffstat (limited to 'dom/media/MediaSpan.h')
-rw-r--r-- | dom/media/MediaSpan.h | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/dom/media/MediaSpan.h b/dom/media/MediaSpan.h new file mode 100644 index 0000000000..4bb512a7dc --- /dev/null +++ b/dom/media/MediaSpan.h @@ -0,0 +1,131 @@ +/* -*- 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(MediaSpan_h) +# define MediaSpan_h + +# include "MediaData.h" +# include "mozilla/RefPtr.h" +# include "mozilla/Span.h" + +namespace mozilla { + +// A MediaSpan wraps a MediaByteBuffer and exposes a slice/span, or subregion, +// of the buffer. This allows you to slice off a logical subregion without +// needing to reallocate a new buffer to hold it. You can also append to a +// MediaSpan without affecting other MediaSpans referencing the same buffer +// (the MediaSpan receiving the append will allocate a new buffer to store its +// result if necessary, to ensure other MediaSpans referencing its original +// buffer are unaffected). Note there are no protections here that something +// other than MediaSpans doesn't modify the underlying MediaByteBuffer while +// a MediaSpan is alive. +class MediaSpan { + public: + ~MediaSpan() = default; + + explicit MediaSpan(const MediaSpan& aOther) = default; + + MediaSpan(MediaSpan&& aOther) = default; + + explicit MediaSpan(const RefPtr<MediaByteBuffer>& aBuffer) + : mBuffer(aBuffer), mStart(0), mLength(aBuffer ? aBuffer->Length() : 0) { + MOZ_DIAGNOSTIC_ASSERT(mBuffer); + } + + explicit MediaSpan(MediaByteBuffer* aBuffer) + : mBuffer(aBuffer), mStart(0), mLength(aBuffer ? aBuffer->Length() : 0) { + MOZ_DIAGNOSTIC_ASSERT(mBuffer); + } + + MediaSpan& operator=(const MediaSpan& aOther) = default; + + static MediaSpan WithCopyOf(const RefPtr<MediaByteBuffer>& aBuffer) { + RefPtr<MediaByteBuffer> buffer = new MediaByteBuffer(aBuffer->Length()); + buffer->AppendElements(*aBuffer); + return MediaSpan(buffer); + } + + bool IsEmpty() const { return Length() == 0; } + + // Note: It's unsafe to store the pointer returned by this function, as an + // append operation could cause the wrapped MediaByteBuffer to be + // reallocated, invalidating pointers previously returned by this function. + const uint8_t* Elements() const { + MOZ_DIAGNOSTIC_ASSERT(mStart < mBuffer->Length()); + return mBuffer->Elements() + mStart; + } + + size_t Length() const { return mLength; } + + uint8_t operator[](size_t aIndex) const { + MOZ_DIAGNOSTIC_ASSERT(aIndex < Length()); + return (*mBuffer)[mStart + aIndex]; + } + + bool Append(const MediaSpan& aBuffer) { return Append(aBuffer.Buffer()); } + + bool Append(MediaByteBuffer* aBuffer) { + if (!aBuffer) { + return true; + } + if (mStart + mLength < mBuffer->Length()) { + // This MediaSpan finishes before the end of its buffer. The buffer + // could be shared with another MediaSpan. So we can't just append to + // the underlying buffer without risking damaging other MediaSpans' data. + // So we must reallocate a new buffer, copy our old data into it, and + // append the new data into it. + RefPtr<MediaByteBuffer> buffer = + new MediaByteBuffer(mLength + aBuffer->Length()); + if (!buffer->AppendElements(Elements(), Length(), fallible) || + !buffer->AppendElements(*aBuffer, fallible)) { + return false; + } + mBuffer = buffer; + mLength += aBuffer->Length(); + return true; + } + if (!mBuffer->AppendElements(*aBuffer, fallible)) { + return false; + } + mLength += aBuffer->Length(); + return true; + } + + // Returns a new MediaSpan, spanning from the start of this span, + // up until aEnd. + MediaSpan To(size_t aEnd) const { + MOZ_DIAGNOSTIC_ASSERT(aEnd <= Length()); + return MediaSpan(mBuffer, mStart, aEnd); + } + + // Returns a new MediaSpan, spanning from aStart bytes offset from + // the start of this span, until the end of this span. + MediaSpan From(size_t aStart) const { + MOZ_DIAGNOSTIC_ASSERT(aStart <= Length()); + return MediaSpan(mBuffer, mStart + aStart, Length() - aStart); + } + + void RemoveFront(size_t aNumBytes) { + MOZ_DIAGNOSTIC_ASSERT(aNumBytes <= Length()); + mStart += aNumBytes; + mLength -= aNumBytes; + } + + MediaByteBuffer* Buffer() const { return mBuffer; } + + private: + MediaSpan(MediaByteBuffer* aBuffer, size_t aStart, size_t aLength) + : mBuffer(aBuffer), mStart(aStart), mLength(aLength) { + MOZ_DIAGNOSTIC_ASSERT(mStart + mLength <= mBuffer->Length()); + } + + RefPtr<MediaByteBuffer> mBuffer; + size_t mStart = 0; + size_t mLength = 0; +}; + +} // namespace mozilla + +#endif // MediaSpan_h |