Bug 1842773 - Part 5: Add ArrayBuffer.prototype.{maxByteLength,resizable} getters...
[gecko.git] / dom / media / MediaResource.h
blob223340b87620dbf079861adf00f0a1c9228b855a
1 /* vim:set ts=2 sw=2 sts=2 et cindent: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #if !defined(MediaResource_h_)
7 # define MediaResource_h_
9 # include "DecoderDoctorLogger.h"
10 # include "Intervals.h"
11 # include "MediaData.h"
12 # include "mozilla/Attributes.h"
13 # include "mozilla/UniquePtr.h"
14 # include "nsISeekableStream.h"
15 # include "nsThreadUtils.h"
17 namespace mozilla {
19 // Represents a section of contiguous media, with a start and end offset.
20 // Used to denote ranges of data which are cached.
22 typedef media::Interval<int64_t> MediaByteRange;
23 typedef media::IntervalSet<int64_t> MediaByteRangeSet;
25 DDLoggedTypeDeclName(MediaResource);
27 /**
28 * Provides a thread-safe, seek/read interface to resources
29 * loaded from a URI. Uses MediaCache to cache data received over
30 * Necko's async channel API, thus resolving the mismatch between clients
31 * that need efficient random access to the data and protocols that do not
32 * support efficient random access, such as HTTP.
34 * Instances of this class must be created on the main thread.
35 * Most methods must be called on the main thread only. Read, Seek and
36 * Tell must only be called on non-main threads. In the case of the Ogg
37 * Decoder they are called on the Decode thread for example. You must
38 * ensure that no threads are calling these methods once Close is called.
40 * Instances of this class are reference counted. Use nsRefPtr for
41 * managing the lifetime of instances of this class.
43 * The generic implementation of this class is ChannelMediaResource, which can
44 * handle any URI for which Necko supports AsyncOpen.
45 * The 'file:' protocol can be implemented efficiently with direct random
46 * access, so the FileMediaResource implementation class bypasses the cache.
47 * For cross-process blob URL, CloneableWithRangeMediaResource is used.
48 * MediaResource::Create automatically chooses the best implementation class.
50 class MediaResource : public DecoderDoctorLifeLogger<MediaResource> {
51 public:
52 // Our refcounting is threadsafe, and when our refcount drops to zero
53 // we dispatch an event to the main thread to delete the MediaResource.
54 // Note that this means it's safe for references to this object to be
55 // released on a non main thread, but the destructor will always run on
56 // the main thread.
57 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD(
58 MediaResource)
60 // Close the resource, stop any listeners, channels, etc.
61 // Cancels any currently blocking Read request and forces that request to
62 // return an error. This must be called (and resolve) before the MediaResource
63 // is deleted.
64 virtual RefPtr<GenericPromise> Close() {
65 return GenericPromise::CreateAndResolve(true, __func__);
68 // These methods are called off the main thread.
69 // Read up to aCount bytes from the stream. The read starts at
70 // aOffset in the stream, seeking to that location initially if
71 // it is not the current stream offset. The remaining arguments,
72 // results and requirements are the same as per the Read method.
73 virtual nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount,
74 uint32_t* aBytes) = 0;
75 // Indicate whether caching data in advance of reads is worth it.
76 // E.g. Caching lockless and memory-based MediaResource subclasses would be a
77 // waste, but caching lock/IO-bound resources means reducing the impact of
78 // each read.
79 virtual bool ShouldCacheReads() = 0;
81 // These can be called on any thread.
82 // Cached blocks associated with this stream will not be evicted
83 // while the stream is pinned.
84 virtual void Pin() = 0;
85 virtual void Unpin() = 0;
86 // Get the length of the stream in bytes. Returns -1 if not known.
87 // This can change over time; after a seek operation, a misbehaving
88 // server may give us a resource of a different length to what it had
89 // reported previously --- or it may just lie in its Content-Length
90 // header and give us more or less data than it reported. We will adjust
91 // the result of GetLength to reflect the data that's actually arriving.
92 virtual int64_t GetLength() = 0;
93 // Returns the offset of the first byte of cached data at or after aOffset,
94 // or -1 if there is no such cached data.
95 virtual int64_t GetNextCachedData(int64_t aOffset) = 0;
96 // Returns the end of the bytes starting at the given offset which are in
97 // cache. Returns aOffset itself if there are zero bytes available there.
98 virtual int64_t GetCachedDataEnd(int64_t aOffset) = 0;
99 // Returns true if all the data from aOffset to the end of the stream
100 // is in cache. If the end of the stream is not known, we return false.
101 virtual bool IsDataCachedToEndOfResource(int64_t aOffset) = 0;
102 // Reads only data which is cached in the media cache. If you try to read
103 // any data which overlaps uncached data, or if aCount bytes otherwise can't
104 // be read, this function will return failure. This function be called from
105 // any thread, and it is the only read operation which is safe to call on
106 // the main thread, since it's guaranteed to be non blocking.
107 virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset,
108 uint32_t aCount) = 0;
111 * Fills aRanges with MediaByteRanges representing the data which is cached
112 * in the media cache. Stream should be pinned during call and while
113 * aRanges is being used.
115 virtual nsresult GetCachedRanges(MediaByteRangeSet& aRanges) = 0;
117 protected:
118 virtual ~MediaResource() = default;
122 * RAII class that handles pinning and unpinning for MediaResource and derived.
123 * This should be used when making calculations that involve potentially-cached
124 * MediaResource data, so that the state of the world can't change out from
125 * under us.
127 template <class T>
128 class MOZ_RAII AutoPinned {
129 public:
130 explicit AutoPinned(T* aResource) : mResource(aResource) {
131 MOZ_ASSERT(mResource);
132 mResource->Pin();
135 ~AutoPinned() { mResource->Unpin(); }
137 operator T*() const { return mResource; }
138 T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return mResource; }
140 private:
141 T* mResource;
144 DDLoggedTypeDeclName(MediaResourceIndex);
147 * MediaResourceIndex provides a way to access MediaResource objects.
148 * Read, Seek and Tell must only be called on non-main threads.
149 * In the case of the Ogg Decoder they are called on the Decode thread for
150 * example. You must ensure that no threads are calling these methods once
151 * the MediaResource has been Closed.
153 class MediaResourceIndex : public DecoderDoctorLifeLogger<MediaResourceIndex> {
154 public:
155 explicit MediaResourceIndex(MediaResource* aResource);
157 // Read up to aCount bytes from the stream. The buffer must have
158 // enough room for at least aCount bytes. Stores the number of
159 // actual bytes read in aBytes (0 on end of file).
160 // May read less than aCount bytes if the number of
161 // available bytes is less than aCount. Always check *aBytes after
162 // read, and call again if necessary.
163 nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes);
164 // Seek to the given bytes offset in the stream. aWhence can be
165 // one of:
166 // nsISeekableStream::NS_SEEK_SET
167 // nsISeekableStream::NS_SEEK_CUR
168 // nsISeekableStream::NS_SEEK_END
170 // In the Http strategy case the cancel will cause the http
171 // channel's listener to close the pipe, forcing an i/o error on any
172 // blocked read. This will allow the decode thread to complete the
173 // event.
175 // In the case of a seek in progress, the byte range request creates
176 // a new listener. This is done on the main thread via seek
177 // synchronously dispatching an event. This avoids the issue of us
178 // closing the listener but an outstanding byte range request
179 // creating a new one. They run on the same thread so no explicit
180 // synchronisation is required. The byte range request checks for
181 // the cancel flag and does not create a new channel or listener if
182 // we are cancelling.
184 // The default strategy does not do any seeking - the only issue is
185 // a blocked read which it handles by causing the listener to close
186 // the pipe, as per the http case.
188 // The file strategy doesn't block for any great length of time so
189 // is fine for a no-op cancel.
190 nsresult Seek(int32_t aWhence, int64_t aOffset);
191 // Report the current offset in bytes from the start of the stream.
192 int64_t Tell() const { return mOffset; }
194 // Return the underlying MediaResource.
195 MediaResource* GetResource() const { return mResource; }
197 // Read up to aCount bytes from the stream. The read starts at
198 // aOffset in the stream, seeking to that location initially if
199 // it is not the current stream offset.
200 // Unlike MediaResource::ReadAt, ReadAt only returns fewer bytes than
201 // requested if end of stream or an error is encountered. There is no need to
202 // call it again to get more data.
203 // If the resource has cached data past the end of the request, it will be
204 // used to fill a local cache, which should speed up consecutive ReadAt's
205 // (mostly by avoiding using the resource's IOs and locks.)
206 // *aBytes will contain the number of bytes copied, even if an error occurred.
207 // ReadAt doesn't have an impact on the offset returned by Tell().
208 nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount,
209 uint32_t* aBytes);
211 // Same as ReadAt, but doesn't try to cache around the read.
212 // Useful if you know that you will not read again from the same area.
213 nsresult UncachedReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount,
214 uint32_t* aBytes) const;
216 // Similar to ReadAt, but doesn't try to cache around the read.
217 // Useful if you know that you will not read again from the same area.
218 // Will attempt to read aRequestedCount+aExtraCount, repeatedly calling
219 // MediaResource/ ReadAt()'s until a read returns 0 bytes (so we may actually
220 // get less than aRequestedCount bytes), or until we get at least
221 // aRequestedCount bytes (so we may not get any/all of the aExtraCount bytes.)
222 nsresult UncachedRangedReadAt(int64_t aOffset, char* aBuffer,
223 uint32_t aRequestedCount, uint32_t aExtraCount,
224 uint32_t* aBytes) const;
226 // This method returns nullptr if anything fails.
227 // Otherwise, it returns an owned buffer.
228 // MediaReadAt may return fewer bytes than requested if end of stream is
229 // encountered. There is no need to call it again to get more data.
230 // Note this method will not update mOffset.
231 already_AddRefed<MediaByteBuffer> MediaReadAt(int64_t aOffset,
232 uint32_t aCount) const;
234 already_AddRefed<MediaByteBuffer> CachedMediaReadAt(int64_t aOffset,
235 uint32_t aCount) const;
237 // Get the length of the stream in bytes. Returns -1 if not known.
238 // This can change over time; after a seek operation, a misbehaving
239 // server may give us a resource of a different length to what it had
240 // reported previously --- or it may just lie in its Content-Length
241 // header and give us more or less data than it reported. We will adjust
242 // the result of GetLength to reflect the data that's actually arriving.
243 int64_t GetLength() const;
245 private:
246 // If the resource has cached data past the requested range, try to grab it
247 // into our local cache.
248 // If there is no cached data, or attempting to read it fails, fallback on
249 // a (potentially-blocking) read of just what was requested, so that we don't
250 // get unexpected side-effects by trying to read more than intended.
251 nsresult CacheOrReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount,
252 uint32_t* aBytes);
254 // Maps a file offset to a mCachedBlock index.
255 uint32_t IndexInCache(int64_t aOffsetInFile) const;
257 // Starting file offset of the cache block that contains a given file offset.
258 int64_t CacheOffsetContaining(int64_t aOffsetInFile) const;
260 RefPtr<MediaResource> mResource;
261 int64_t mOffset;
263 // Local cache used by ReadAt().
264 // mCachedBlock is valid when mCachedBytes != 0, in which case it contains
265 // data of length mCachedBytes, starting at offset `mCachedOffset` in the
266 // resource, located at index `IndexInCache(mCachedOffset)` in mCachedBlock.
268 // resource: |------------------------------------------------------|
269 // <----------> mCacheBlockSize
270 // <---------------------------------> mCachedOffset
271 // <--> mCachedBytes
272 // mCachedBlock: |..----....|
273 // CacheOffsetContaining(mCachedOffset) <--> IndexInCache(mCachedOffset)
274 // <------------------------------>
275 const uint32_t mCacheBlockSize;
276 int64_t mCachedOffset;
277 uint32_t mCachedBytes;
278 UniquePtr<char[]> mCachedBlock;
281 } // namespace mozilla
283 #endif