Attachment #520040: Patch 2: Make nsMediaStream responsible for determining cached media data in a threadsafe manner for bug #639391

View | Details | Raw Unified | Return to bug 639391
Collapse All | Expand All

(-)a/content/media/nsMediaCache.cpp (+23 lines)
Line     Link Here 
 Lines 2288-2295   nsMediaCacheStream::InitAsClone(nsMediaC Link Here 
2288
    }
2288
    }
2289
    // Every block is a readahead block for the clone because the clone's initial
2289
    // Every block is a readahead block for the clone because the clone's initial
2290
    // stream offset is zero
2290
    // stream offset is zero
2291
    gMediaCache->AddBlockOwnerAsReadahead(cacheBlockIndex, this, i);
2291
    gMediaCache->AddBlockOwnerAsReadahead(cacheBlockIndex, this, i);
2292
  }
2292
  }
2293
2293
2294
  return NS_OK;
2294
  return NS_OK;
2295
}
2295
}
2296
2297
nsresult nsMediaCacheStream::GetCachedRanges(nsTArray<nsByteRange>& aRanges)
2298
{
2299
  // Take the monitor, so that the cached data ranges can't grow while we're
2300
  // trying to loop over them.
2301
  nsAutoMonitor mon(gMediaCache->Monitor());
2302
2303
  // We must be pinned while running this, otherwise the cached data ranges may
2304
  // shrink while we're trying to loop over them.
2305
  NS_ASSERTION(mPinCount > 0, "Must be pinned");
2306
2307
  PRInt64 startOffset = GetNextCachedData(0);
2308
  while (startOffset >= 0) {
2309
    PRInt64 endOffset = GetCachedDataEnd(startOffset);
2310
    NS_ASSERTION(startOffset < endOffset, "Buffered range must end after its start");
2311
    // Bytes [startOffset..endOffset] are cached.
2312
    aRanges.AppendElement(nsByteRange(startOffset, endOffset));
2313
    startOffset = GetNextCachedData(endOffset);
2314
    NS_ASSERTION(startOffset == -1 || startOffset > endOffset,
2315
      "Must have advanced to start of next range, or hit end of stream");
2316
  }
2317
  return NS_OK;
2318
}
(-)a/content/media/nsMediaCache.h (+7 lines)
Line     Link Here 
 Lines 39-54    Link Here 
39
#ifndef nsMediaCache_h_
39
#ifndef nsMediaCache_h_
40
#define nsMediaCache_h_
40
#define nsMediaCache_h_
41
41
42
#include "nsTArray.h"
42
#include "nsTArray.h"
43
#include "nsAutoLock.h"
43
#include "nsAutoLock.h"
44
#include "nsIPrincipal.h"
44
#include "nsIPrincipal.h"
45
#include "nsCOMPtr.h"
45
#include "nsCOMPtr.h"
46
46
47
class nsByteRange;
48
47
/**
49
/**
48
 * Media applications want fast, "on demand" random access to media data,
50
 * Media applications want fast, "on demand" random access to media data,
49
 * for pausing, seeking, etc. But we are primarily interested
51
 * for pausing, seeking, etc. But we are primarily interested
50
 * in transporting media data using HTTP over the Internet, which has
52
 * in transporting media data using HTTP over the Internet, which has
51
 * high latency to open a connection, requires a new connection for every
53
 * high latency to open a connection, requires a new connection for every
52
 * seek, may not even support seeking on some connections (especially
54
 * seek, may not even support seeking on some connections (especially
53
 * live streams), and uses a push model --- data comes from the server
55
 * live streams), and uses a push model --- data comes from the server
54
 * and you don't have much control over the rate. Also, transferring data
56
 * and you don't have much control over the rate. Also, transferring data
 Lines 305-320   public: Link Here 
305
  // Returns the unique resource ID
307
  // Returns the unique resource ID
306
  PRInt64 GetResourceID() { return mResourceID; }
308
  PRInt64 GetResourceID() { return mResourceID; }
307
  // Returns the end of the bytes starting at the given offset
309
  // Returns the end of the bytes starting at the given offset
308
  // which are in cache.
310
  // which are in cache.
309
  PRInt64 GetCachedDataEnd(PRInt64 aOffset);
311
  PRInt64 GetCachedDataEnd(PRInt64 aOffset);
310
  // Returns the offset of the first byte of cached data at or after aOffset,
312
  // Returns the offset of the first byte of cached data at or after aOffset,
311
  // or -1 if there is no such cached data.
313
  // or -1 if there is no such cached data.
312
  PRInt64 GetNextCachedData(PRInt64 aOffset);
314
  PRInt64 GetNextCachedData(PRInt64 aOffset);
315
  // Fills aRanges with the ByteRanges representing the data which is currently
316
  // cached. Locks the media cache while running, to prevent any ranges
317
  // growing. The stream should be pinned while this runs and while its results
318
  // are used, to ensure no data is evicted.
319
  nsresult GetCachedRanges(nsTArray<nsByteRange>& aRanges);
313
320
314
  // Reads from buffered data only. Will fail if not all data to be read is
321
  // Reads from buffered data only. Will fail if not all data to be read is
315
  // in the cache. Will not mark blocks as read. Can be called from the main
322
  // in the cache. Will not mark blocks as read. Can be called from the main
316
  // thread. It's the caller's responsibility to wrap the call in a pin/unpin,
323
  // thread. It's the caller's responsibility to wrap the call in a pin/unpin,
317
  // and also to check that the range they want is cached before calling this.
324
  // and also to check that the range they want is cached before calling this.
318
  nsresult ReadFromCache(char* aBuffer,
325
  nsresult ReadFromCache(char* aBuffer,
319
                         PRInt64 aOffset,
326
                         PRInt64 aOffset,
320
                         PRInt64 aCount);
327
                         PRInt64 aCount);
(-)a/content/media/nsMediaStream.cpp (+16 lines)
Line     Link Here 
 Lines 600-615   nsresult nsMediaChannelStream::Seek(PRIn Link Here 
600
600
601
PRInt64 nsMediaChannelStream::Tell()
601
PRInt64 nsMediaChannelStream::Tell()
602
{
602
{
603
  NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
603
  NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
604
604
605
  return mCacheStream.Tell();
605
  return mCacheStream.Tell();
606
}
606
}
607
607
608
nsresult nsMediaChannelStream::GetCachedRanges(nsTArray<nsByteRange>& aRanges)
609
{
610
  return mCacheStream.GetCachedRanges(aRanges);
611
}
612
608
void nsMediaChannelStream::Suspend(PRBool aCloseImmediately)
613
void nsMediaChannelStream::Suspend(PRBool aCloseImmediately)
609
{
614
{
610
  NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
615
  NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
611
616
612
  nsHTMLMediaElement* element = mDecoder->GetMediaElement();
617
  nsHTMLMediaElement* element = mDecoder->GetMediaElement();
613
  if (!element) {
618
  if (!element) {
614
    // Shutting down; do nothing.
619
    // Shutting down; do nothing.
615
    return;
620
    return;
 Lines 914-929   public: Link Here 
914
  {
919
  {
915
    return (aOffset < mSize) ? aOffset : -1;
920
    return (aOffset < mSize) ? aOffset : -1;
916
  }
921
  }
917
  virtual PRInt64 GetCachedDataEnd(PRInt64 aOffset) { return PR_MAX(aOffset, mSize); }
922
  virtual PRInt64 GetCachedDataEnd(PRInt64 aOffset) { return PR_MAX(aOffset, mSize); }
918
  virtual PRBool  IsDataCachedToEndOfStream(PRInt64 aOffset) { return PR_TRUE; }
923
  virtual PRBool  IsDataCachedToEndOfStream(PRInt64 aOffset) { return PR_TRUE; }
919
  virtual PRBool  IsSuspendedByCache() { return PR_FALSE; }
924
  virtual PRBool  IsSuspendedByCache() { return PR_FALSE; }
920
  virtual PRBool  IsSuspended() { return PR_FALSE; }
925
  virtual PRBool  IsSuspended() { return PR_FALSE; }
921
926
927
  nsresult GetCachedRanges(nsTArray<nsByteRange>& aRanges);
928
922
private:
929
private:
923
  // The file size, or -1 if not known. Immutable after Open().
930
  // The file size, or -1 if not known. Immutable after Open().
924
  PRInt64 mSize;
931
  PRInt64 mSize;
925
932
926
  // This lock handles synchronisation between calls to Close() and
933
  // This lock handles synchronisation between calls to Close() and
927
  // the Read, Seek, etc calls. Close must not be called while a
934
  // the Read, Seek, etc calls. Close must not be called while a
928
  // Read or Seek is in progress since it resets various internal
935
  // Read or Seek is in progress since it resets various internal
929
  // values to null.
936
  // values to null.
 Lines 956-971   public: Link Here 
956
    mDecoder->NotifyDownloadEnded(NS_OK);
963
    mDecoder->NotifyDownloadEnded(NS_OK);
957
    return NS_OK;
964
    return NS_OK;
958
  }
965
  }
959
966
960
private:
967
private:
961
  nsRefPtr<nsMediaDecoder> mDecoder;
968
  nsRefPtr<nsMediaDecoder> mDecoder;
962
};
969
};
963
970
971
nsresult nsMediaFileStream::GetCachedRanges(nsTArray<nsByteRange>& aRanges)
972
{
973
  if (mSize == -1) {
974
    return NS_ERROR_FAILURE;
975
  }
976
  aRanges.AppendElement(nsByteRange(0, mSize));
977
  return NS_OK;
978
}
979
964
nsresult nsMediaFileStream::Open(nsIStreamListener** aStreamListener)
980
nsresult nsMediaFileStream::Open(nsIStreamListener** aStreamListener)
965
{
981
{
966
  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
982
  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
967
983
968
  if (aStreamListener) {
984
  if (aStreamListener) {
969
    *aStreamListener = nsnull;
985
    *aStreamListener = nsnull;
970
  }
986
  }
971
987
(-)a/content/media/nsMediaStream.h (+28 lines)
Line     Link Here 
 Lines 122-137   public: Link Here 
122
  }
122
  }
123
private:
123
private:
124
  PRInt64      mAccumulatedBytes;
124
  PRInt64      mAccumulatedBytes;
125
  TimeDuration mAccumulatedTime;
125
  TimeDuration mAccumulatedTime;
126
  TimeStamp    mLastStartTime;
126
  TimeStamp    mLastStartTime;
127
  PRPackedBool mIsStarted;
127
  PRPackedBool mIsStarted;
128
};
128
};
129
129
130
// Represents a section of contiguous media, with a start and end offset.
131
// Used to denote ranges of data which are cached.
132
class nsByteRange {
133
public:
134
  nsByteRange() : mStart(0), mEnd(0) {}
135
136
  nsByteRange(PRInt64 aStart, PRInt64 aEnd)
137
    : mStart(aStart), mEnd(aEnd)
138
  {
139
    NS_ASSERTION(mStart < mEnd, "Range should end after start!");
140
  }
141
142
  PRBool IsNull() const {
143
    return mStart == 0 && mEnd == 0;
144
  }
145
146
  PRInt64 mStart, mEnd;
147
};
148
130
/*
149
/*
131
   Provides the ability to open, read and seek into a media stream
150
   Provides the ability to open, read and seek into a media stream
132
   (audio, video). Handles the underlying machinery to do range
151
   (audio, video). Handles the underlying machinery to do range
133
   requests, etc as needed by the actual stream type. Instances of
152
   requests, etc as needed by the actual stream type. Instances of
134
   this class must be created on the main thread. 
153
   this class must be created on the main thread. 
135
154
136
   Most methods must be called on the main thread only. Read, Seek and
155
   Most methods must be called on the main thread only. Read, Seek and
137
   Tell must only be called on non-main threads. In the case of the Ogg
156
   Tell must only be called on non-main threads. In the case of the Ogg
 Lines 270-285   public: Link Here 
270
  static nsMediaStream* Create(nsMediaDecoder* aDecoder, nsIChannel* aChannel);
289
  static nsMediaStream* Create(nsMediaDecoder* aDecoder, nsIChannel* aChannel);
271
290
272
  /**
291
  /**
273
   * Open the stream. This creates a stream listener and returns it in
292
   * Open the stream. This creates a stream listener and returns it in
274
   * aStreamListener; this listener needs to be notified of incoming data.
293
   * aStreamListener; this listener needs to be notified of incoming data.
275
   */
294
   */
276
  virtual nsresult Open(nsIStreamListener** aStreamListener) = 0;
295
  virtual nsresult Open(nsIStreamListener** aStreamListener) = 0;
277
296
297
  /**
298
   * Fills aRanges with ByteRanges representing the data which is cached
299
   * in the media cache. Stream should be pinned during call and while
300
   * aRanges is being used.
301
   */
302
  virtual nsresult GetCachedRanges(nsTArray<nsByteRange>& aRanges) = 0;
303
278
protected:
304
protected:
279
  nsMediaStream(nsMediaDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI) :
305
  nsMediaStream(nsMediaDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI) :
280
    mDecoder(aDecoder),
306
    mDecoder(aDecoder),
281
    mChannel(aChannel),
307
    mChannel(aChannel),
282
    mURI(aURI),
308
    mURI(aURI),
283
    mLoadInBackground(PR_FALSE)
309
    mLoadInBackground(PR_FALSE)
284
  {
310
  {
285
    MOZ_COUNT_CTOR(nsMediaStream);
311
    MOZ_COUNT_CTOR(nsMediaStream);
 Lines 390-405   public: Link Here 
390
416
391
    void Revoke() { mStream = nsnull; }
417
    void Revoke() { mStream = nsnull; }
392
418
393
  private:
419
  private:
394
    nsMediaChannelStream* mStream;
420
    nsMediaChannelStream* mStream;
395
  };
421
  };
396
  friend class Listener;
422
  friend class Listener;
397
423
424
  nsresult GetCachedRanges(nsTArray<nsByteRange>& aRanges);
425
398
protected:
426
protected:
399
  // These are called on the main thread by Listener.
427
  // These are called on the main thread by Listener.
400
  nsresult OnStartRequest(nsIRequest* aRequest);
428
  nsresult OnStartRequest(nsIRequest* aRequest);
401
  nsresult OnStopRequest(nsIRequest* aRequest, nsresult aStatus);
429
  nsresult OnStopRequest(nsIRequest* aRequest, nsresult aStatus);
402
  nsresult OnDataAvailable(nsIRequest* aRequest,
430
  nsresult OnDataAvailable(nsIRequest* aRequest,
403
                           nsIInputStream* aStream,
431
                           nsIInputStream* aStream,
404
                           PRUint32 aCount);
432
                           PRUint32 aCount);
405
  nsresult OnChannelRedirect(nsIChannel* aOld, nsIChannel* aNew, PRUint32 aFlags);
433
  nsresult OnChannelRedirect(nsIChannel* aOld, nsIChannel* aNew, PRUint32 aFlags);

Return to bug 639391