content/media/mediasource/SourceBufferResource.h

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef MOZILLA_SOURCEBUFFERRESOURCE_H_
michael@0 8 #define MOZILLA_SOURCEBUFFERRESOURCE_H_
michael@0 9
michael@0 10 #include <algorithm>
michael@0 11 #include "MediaCache.h"
michael@0 12 #include "MediaResource.h"
michael@0 13 #include "mozilla/Attributes.h"
michael@0 14 #include "mozilla/ReentrantMonitor.h"
michael@0 15 #include "nsCOMPtr.h"
michael@0 16 #include "nsError.h"
michael@0 17 #include "nsIPrincipal.h"
michael@0 18 #include "nsStringGlue.h"
michael@0 19 #include "nsTArray.h"
michael@0 20 #include "nsDeque.h"
michael@0 21 #include "nscore.h"
michael@0 22
michael@0 23 class nsIStreamListener;
michael@0 24
michael@0 25 namespace mozilla {
michael@0 26
michael@0 27 class MediaDecoder;
michael@0 28
michael@0 29 namespace dom {
michael@0 30
michael@0 31 class SourceBuffer;
michael@0 32
michael@0 33 } // namespace dom
michael@0 34
michael@0 35 class SourceBufferResource MOZ_FINAL : public MediaResource
michael@0 36 {
michael@0 37 private:
michael@0 38 // A SourceBufferResource has a queue containing the data
michael@0 39 // that is appended to it. The queue holds instances of
michael@0 40 // ResourceItem which is an array of the bytes. Appending
michael@0 41 // data to the SourceBufferResource pushes this onto the
michael@0 42 // queue. As items are played they are taken off the front
michael@0 43 // of the queue.
michael@0 44 // Data is evicted once it reaches a size threshold. This
michael@0 45 // pops the items off the front of the queue and deletes it.
michael@0 46 // If an eviction happens then the MediaSource is notified
michael@0 47 // (done in SourceBuffer::AppendData) which then requests
michael@0 48 // all SourceBuffers to evict data up to approximately
michael@0 49 // the same timepoint.
michael@0 50 struct ResourceItem {
michael@0 51 ResourceItem(uint8_t const* aData, uint32_t aSize) {
michael@0 52 mData.AppendElements(aData, aSize);
michael@0 53 }
michael@0 54 nsTArray<uint8_t> mData;
michael@0 55
michael@0 56 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
michael@0 57 // size including this
michael@0 58 size_t size = aMallocSizeOf(this);
michael@0 59
michael@0 60 // size excluding this
michael@0 61 size += mData.SizeOfExcludingThis(aMallocSizeOf);
michael@0 62
michael@0 63 return size;
michael@0 64 }
michael@0 65 };
michael@0 66
michael@0 67 class ResourceQueueDeallocator : public nsDequeFunctor {
michael@0 68 virtual void* operator() (void* anObject) {
michael@0 69 delete static_cast<ResourceItem*>(anObject);
michael@0 70 return nullptr;
michael@0 71 }
michael@0 72 };
michael@0 73
michael@0 74 class ResourceQueue : private nsDeque {
michael@0 75 private:
michael@0 76 // Logical offset into the resource of the first element
michael@0 77 // in the queue.
michael@0 78 uint64_t mOffset;
michael@0 79
michael@0 80 public:
michael@0 81 ResourceQueue() :
michael@0 82 nsDeque(new ResourceQueueDeallocator()),
michael@0 83 mOffset(0)
michael@0 84 {
michael@0 85 }
michael@0 86
michael@0 87 // Clears all items from the queue
michael@0 88 inline void Clear() {
michael@0 89 return nsDeque::Erase();
michael@0 90 }
michael@0 91
michael@0 92 // Returns the number of items in the queue
michael@0 93 inline uint32_t GetSize() {
michael@0 94 return nsDeque::GetSize();
michael@0 95 }
michael@0 96
michael@0 97 // Returns the logical byte offset of the start of the data.
michael@0 98 inline uint64_t GetOffset() {
michael@0 99 return mOffset;
michael@0 100 }
michael@0 101
michael@0 102 inline ResourceItem* ResourceAt(uint32_t aIndex) {
michael@0 103 return static_cast<ResourceItem*>(nsDeque::ObjectAt(aIndex));
michael@0 104 }
michael@0 105
michael@0 106 // Returns the length of all items in the queue plus the offset.
michael@0 107 // This is the logical length of the resource.
michael@0 108 inline uint64_t GetLength() {
michael@0 109 uint64_t s = mOffset;
michael@0 110 for (uint32_t i = 0; i < GetSize(); ++i) {
michael@0 111 ResourceItem* item = ResourceAt(i);
michael@0 112 s += item->mData.Length();
michael@0 113 }
michael@0 114 return s;
michael@0 115 }
michael@0 116
michael@0 117 // Returns the index of the resource that contains the given
michael@0 118 // logical offset. aResourceOffset will contain the offset into
michael@0 119 // the resource at the given index returned if it is not null. If
michael@0 120 // no such resource exists, returns GetSize() and aOffset is
michael@0 121 // untouched.
michael@0 122 inline uint32_t GetAtOffset(uint64_t aOffset, uint32_t *aResourceOffset) {
michael@0 123 MOZ_ASSERT(aOffset >= mOffset);
michael@0 124 uint64_t offset = mOffset;
michael@0 125 for (uint32_t i = 0; i < GetSize(); ++i) {
michael@0 126 ResourceItem* item = ResourceAt(i);
michael@0 127 // If the item contains the start of the offset we want to
michael@0 128 // break out of the loop.
michael@0 129 if (item->mData.Length() + offset > aOffset) {
michael@0 130 if (aResourceOffset) {
michael@0 131 *aResourceOffset = aOffset - offset;
michael@0 132 }
michael@0 133 return i;
michael@0 134 }
michael@0 135 offset += item->mData.Length();
michael@0 136 }
michael@0 137 return GetSize();
michael@0 138 }
michael@0 139
michael@0 140 // Copies aCount bytes from aOffset in the queue into aDest.
michael@0 141 inline void CopyData(uint64_t aOffset, uint32_t aCount, char* aDest) {
michael@0 142 uint32_t offset = 0;
michael@0 143 uint32_t start = GetAtOffset(aOffset, &offset);
michael@0 144 uint32_t end = std::min(GetAtOffset(aOffset + aCount, nullptr) + 1, GetSize());
michael@0 145 for (uint32_t i = start; i < end; ++i) {
michael@0 146 ResourceItem* item = ResourceAt(i);
michael@0 147 uint32_t bytes = std::min(aCount, item->mData.Length() - offset);
michael@0 148 if (bytes != 0) {
michael@0 149 memcpy(aDest, &item->mData[offset], bytes);
michael@0 150 offset = 0;
michael@0 151 aCount -= bytes;
michael@0 152 aDest += bytes;
michael@0 153 }
michael@0 154 }
michael@0 155 }
michael@0 156
michael@0 157 inline void PushBack(ResourceItem* aItem) {
michael@0 158 nsDeque::Push(aItem);
michael@0 159 }
michael@0 160
michael@0 161 inline void PushFront(ResourceItem* aItem) {
michael@0 162 nsDeque::PushFront(aItem);
michael@0 163 }
michael@0 164
michael@0 165 inline ResourceItem* PopBack() {
michael@0 166 return static_cast<ResourceItem*>(nsDeque::Pop());
michael@0 167 }
michael@0 168
michael@0 169 inline ResourceItem* PopFront() {
michael@0 170 return static_cast<ResourceItem*>(nsDeque::PopFront());
michael@0 171 }
michael@0 172
michael@0 173 // Evict data in queue if the total queue size is greater than
michael@0 174 // aThreshold past the offset. Returns true if some data was
michael@0 175 // actually evicted.
michael@0 176 inline bool Evict(uint64_t aOffset, uint32_t aThreshold) {
michael@0 177 bool evicted = false;
michael@0 178 while (GetLength() - mOffset > aThreshold) {
michael@0 179 ResourceItem* item = ResourceAt(0);
michael@0 180 if (item->mData.Length() + mOffset > aOffset) {
michael@0 181 break;
michael@0 182 }
michael@0 183 mOffset += item->mData.Length();
michael@0 184 delete PopFront();
michael@0 185 evicted = true;
michael@0 186 }
michael@0 187 return evicted;
michael@0 188 }
michael@0 189
michael@0 190 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
michael@0 191 // Calculate the size of the internal deque.
michael@0 192 size_t size = nsDeque::SizeOfExcludingThis(aMallocSizeOf);
michael@0 193
michael@0 194 // Sum the ResourceItems.
michael@0 195 for (int32_t i = 0; i < nsDeque::GetSize(); ++i) {
michael@0 196 const ResourceItem* item =
michael@0 197 static_cast<const ResourceItem*>(nsDeque::ObjectAt(i));
michael@0 198 size += item->SizeOfIncludingThis(aMallocSizeOf);
michael@0 199 }
michael@0 200
michael@0 201 return size;
michael@0 202 }
michael@0 203 };
michael@0 204
michael@0 205 public:
michael@0 206 SourceBufferResource(nsIPrincipal* aPrincipal,
michael@0 207 const nsACString& aType);
michael@0 208 ~SourceBufferResource();
michael@0 209
michael@0 210 virtual nsresult Close() MOZ_OVERRIDE;
michael@0 211 virtual void Suspend(bool aCloseImmediately) MOZ_OVERRIDE {}
michael@0 212 virtual void Resume() MOZ_OVERRIDE {}
michael@0 213
michael@0 214 virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() MOZ_OVERRIDE
michael@0 215 {
michael@0 216 return nsCOMPtr<nsIPrincipal>(mPrincipal).forget();
michael@0 217 }
michael@0 218
michael@0 219 virtual already_AddRefed<MediaResource> CloneData(MediaDecoder* aDecoder) MOZ_OVERRIDE
michael@0 220 {
michael@0 221 return nullptr;
michael@0 222 }
michael@0 223
michael@0 224 virtual void SetReadMode(MediaCacheStream::ReadMode aMode) MOZ_OVERRIDE {}
michael@0 225 virtual void SetPlaybackRate(uint32_t aBytesPerSecond) MOZ_OVERRIDE {}
michael@0 226 virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes) MOZ_OVERRIDE;
michael@0 227 virtual nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount, uint32_t* aBytes) MOZ_OVERRIDE;
michael@0 228 virtual nsresult Seek(int32_t aWhence, int64_t aOffset) MOZ_OVERRIDE;
michael@0 229 virtual void StartSeekingForMetadata() MOZ_OVERRIDE { }
michael@0 230 virtual void EndSeekingForMetadata() MOZ_OVERRIDE {}
michael@0 231 virtual int64_t Tell() MOZ_OVERRIDE { return mOffset; }
michael@0 232 virtual void Pin() MOZ_OVERRIDE {}
michael@0 233 virtual void Unpin() MOZ_OVERRIDE {}
michael@0 234 virtual double GetDownloadRate(bool* aIsReliable) MOZ_OVERRIDE { return 0; }
michael@0 235 virtual int64_t GetLength() MOZ_OVERRIDE { return mInputBuffer.GetLength(); }
michael@0 236 virtual int64_t GetNextCachedData(int64_t aOffset) MOZ_OVERRIDE { return aOffset; }
michael@0 237 virtual int64_t GetCachedDataEnd(int64_t aOffset) MOZ_OVERRIDE { return GetLength(); }
michael@0 238 virtual bool IsDataCachedToEndOfResource(int64_t aOffset) MOZ_OVERRIDE { return false; }
michael@0 239 virtual bool IsSuspendedByCache() MOZ_OVERRIDE { return false; }
michael@0 240 virtual bool IsSuspended() MOZ_OVERRIDE { return false; }
michael@0 241 virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) MOZ_OVERRIDE;
michael@0 242 virtual bool IsTransportSeekable() MOZ_OVERRIDE { return true; }
michael@0 243 virtual nsresult Open(nsIStreamListener** aStreamListener) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }
michael@0 244
michael@0 245 virtual nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges) MOZ_OVERRIDE
michael@0 246 {
michael@0 247 aRanges.AppendElement(MediaByteRange(mInputBuffer.GetOffset(),
michael@0 248 mInputBuffer.GetLength()));
michael@0 249 return NS_OK;
michael@0 250 }
michael@0 251
michael@0 252 virtual const nsCString& GetContentType() const MOZ_OVERRIDE { return mType; }
michael@0 253
michael@0 254 virtual size_t SizeOfExcludingThis(
michael@0 255 MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
michael@0 256 {
michael@0 257 ReentrantMonitorAutoEnter mon(mMonitor);
michael@0 258
michael@0 259 // Not owned:
michael@0 260 // - mPrincipal
michael@0 261 size_t size = MediaResource::SizeOfExcludingThis(aMallocSizeOf);
michael@0 262 size += mType.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
michael@0 263 size += mInputBuffer.SizeOfExcludingThis(aMallocSizeOf);
michael@0 264
michael@0 265 return size;
michael@0 266 }
michael@0 267
michael@0 268 virtual size_t SizeOfIncludingThis(
michael@0 269 MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
michael@0 270 {
michael@0 271 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
michael@0 272 }
michael@0 273
michael@0 274 // Used by SourceBuffer.
michael@0 275 void AppendData(const uint8_t* aData, uint32_t aLength);
michael@0 276 void Ended();
michael@0 277 // Remove data from resource if it holds more than the threshold
michael@0 278 // number of bytes. Returns true if some data was evicted.
michael@0 279 bool EvictData(uint32_t aThreshold);
michael@0 280
michael@0 281 // Remove data from resource before the given offset.
michael@0 282 void EvictBefore(uint64_t aOffset);
michael@0 283
michael@0 284 private:
michael@0 285 nsCOMPtr<nsIPrincipal> mPrincipal;
michael@0 286 const nsAutoCString mType;
michael@0 287
michael@0 288 // Provides synchronization between SourceBuffers and InputAdapters.
michael@0 289 // Protects all of the member variables below. Read() will await a
michael@0 290 // Notify() (from Seek, AppendData, Ended, or Close) when insufficient
michael@0 291 // data is available in mData.
michael@0 292 mutable ReentrantMonitor mMonitor;
michael@0 293
michael@0 294 // The buffer holding resource data is a queue of ResourceItem's.
michael@0 295 ResourceQueue mInputBuffer;
michael@0 296
michael@0 297 uint64_t mOffset;
michael@0 298 bool mClosed;
michael@0 299 bool mEnded;
michael@0 300 };
michael@0 301
michael@0 302 } // namespace mozilla
michael@0 303 #endif /* MOZILLA_SOURCEBUFFERRESOURCE_H_ */

mercurial