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 #if !defined(MediaSpan_h) 7 # define MediaSpan_h 8 9 # include "MediaData.h" 10 # include "mozilla/RefPtr.h" 11 # include "mozilla/Span.h" 12 13 namespace mozilla { 14 15 // A MediaSpan wraps a MediaByteBuffer and exposes a slice/span, or subregion, 16 // of the buffer. This allows you to slice off a logical subregion without 17 // needing to reallocate a new buffer to hold it. You can also append to a 18 // MediaSpan without affecting other MediaSpans referencing the same buffer 19 // (the MediaSpan receiving the append will allocate a new buffer to store its 20 // result if necessary, to ensure other MediaSpans referencing its original 21 // buffer are unaffected). Note there are no protections here that something 22 // other than MediaSpans doesn't modify the underlying MediaByteBuffer while 23 // a MediaSpan is alive. 24 class MediaSpan { 25 public: 26 ~MediaSpan() = default; 27 28 explicit MediaSpan(const MediaSpan& aOther) = default; 29 30 MediaSpan(MediaSpan&& aOther) = default; 31 MediaSpan(const RefPtr<MediaByteBuffer> & aBuffer)32 explicit MediaSpan(const RefPtr<MediaByteBuffer>& aBuffer) 33 : mBuffer(aBuffer), mStart(0), mLength(aBuffer ? aBuffer->Length() : 0) { 34 MOZ_DIAGNOSTIC_ASSERT(mBuffer); 35 } 36 MediaSpan(MediaByteBuffer * aBuffer)37 explicit MediaSpan(MediaByteBuffer* aBuffer) 38 : mBuffer(aBuffer), mStart(0), mLength(aBuffer ? aBuffer->Length() : 0) { 39 MOZ_DIAGNOSTIC_ASSERT(mBuffer); 40 } 41 42 MediaSpan& operator=(const MediaSpan& aOther) = default; 43 WithCopyOf(const RefPtr<MediaByteBuffer> & aBuffer)44 static MediaSpan WithCopyOf(const RefPtr<MediaByteBuffer>& aBuffer) { 45 RefPtr<MediaByteBuffer> buffer = new MediaByteBuffer(aBuffer->Length()); 46 buffer->AppendElements(*aBuffer); 47 return MediaSpan(buffer); 48 } 49 IsEmpty()50 bool IsEmpty() const { return Length() == 0; } 51 52 // Note: It's unsafe to store the pointer returned by this function, as an 53 // append operation could cause the wrapped MediaByteBuffer to be 54 // reallocated, invalidating pointers previously returned by this function. Elements()55 const uint8_t* Elements() const { 56 MOZ_DIAGNOSTIC_ASSERT(mStart < mBuffer->Length()); 57 return mBuffer->Elements() + mStart; 58 } 59 Length()60 size_t Length() const { return mLength; } 61 62 uint8_t operator[](size_t aIndex) const { 63 MOZ_DIAGNOSTIC_ASSERT(aIndex < Length()); 64 return (*mBuffer)[mStart + aIndex]; 65 } 66 Append(const MediaSpan & aBuffer)67 bool Append(const MediaSpan& aBuffer) { return Append(aBuffer.Buffer()); } 68 Append(MediaByteBuffer * aBuffer)69 bool Append(MediaByteBuffer* aBuffer) { 70 if (!aBuffer) { 71 return true; 72 } 73 if (mStart + mLength < mBuffer->Length()) { 74 // This MediaSpan finishes before the end of its buffer. The buffer 75 // could be shared with another MediaSpan. So we can't just append to 76 // the underlying buffer without risking damaging other MediaSpans' data. 77 // So we must reallocate a new buffer, copy our old data into it, and 78 // append the new data into it. 79 RefPtr<MediaByteBuffer> buffer = 80 new MediaByteBuffer(mLength + aBuffer->Length()); 81 if (!buffer->AppendElements(Elements(), Length(), fallible) || 82 !buffer->AppendElements(*aBuffer, fallible)) { 83 return false; 84 } 85 mBuffer = buffer; 86 mLength += aBuffer->Length(); 87 return true; 88 } 89 if (!mBuffer->AppendElements(*aBuffer, fallible)) { 90 return false; 91 } 92 mLength += aBuffer->Length(); 93 return true; 94 } 95 96 // Returns a new MediaSpan, spanning from the start of this span, 97 // up until aEnd. To(size_t aEnd)98 MediaSpan To(size_t aEnd) const { 99 MOZ_DIAGNOSTIC_ASSERT(aEnd <= Length()); 100 return MediaSpan(mBuffer, mStart, aEnd); 101 } 102 103 // Returns a new MediaSpan, spanning from aStart bytes offset from 104 // the start of this span, until the end of this span. From(size_t aStart)105 MediaSpan From(size_t aStart) const { 106 MOZ_DIAGNOSTIC_ASSERT(aStart <= Length()); 107 return MediaSpan(mBuffer, mStart + aStart, Length() - aStart); 108 } 109 RemoveFront(size_t aNumBytes)110 void RemoveFront(size_t aNumBytes) { 111 MOZ_DIAGNOSTIC_ASSERT(aNumBytes <= Length()); 112 mStart += aNumBytes; 113 mLength -= aNumBytes; 114 } 115 Buffer()116 MediaByteBuffer* Buffer() const { return mBuffer; } 117 118 private: MediaSpan(MediaByteBuffer * aBuffer,size_t aStart,size_t aLength)119 MediaSpan(MediaByteBuffer* aBuffer, size_t aStart, size_t aLength) 120 : mBuffer(aBuffer), mStart(aStart), mLength(aLength) { 121 MOZ_DIAGNOSTIC_ASSERT(mStart + mLength <= mBuffer->Length()); 122 } 123 124 RefPtr<MediaByteBuffer> mBuffer; 125 size_t mStart = 0; 126 size_t mLength = 0; 127 }; 128 129 } // namespace mozilla 130 131 #endif // MediaSpan_h 132