mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 01:48:05 +00:00
e38733eb15
--HG-- rename : content/media/video/src/nsAudioStream.cpp => content/media/nsAudioStream.cpp rename : content/media/video/public/nsAudioStream.h => content/media/nsAudioStream.h rename : content/media/video/src/nsMediaCache.cpp => content/media/nsMediaCache.cpp rename : content/media/video/public/nsMediaCache.h => content/media/nsMediaCache.h rename : content/media/video/src/nsMediaDecoder.cpp => content/media/nsMediaDecoder.cpp rename : content/media/video/public/nsMediaDecoder.h => content/media/nsMediaDecoder.h rename : content/media/video/src/nsMediaStream.cpp => content/media/nsMediaStream.cpp rename : content/media/video/public/nsMediaStream.h => content/media/nsMediaStream.h rename : content/media/video/src/nsChannelReader.cpp => content/media/ogg/nsChannelReader.cpp rename : content/media/video/public/nsChannelReader.h => content/media/ogg/nsChannelReader.h rename : content/media/video/src/nsOggDecoder.cpp => content/media/ogg/nsOggDecoder.cpp rename : content/media/video/public/nsOggDecoder.h => content/media/ogg/nsOggDecoder.h rename : content/media/video/test/320x240.allow-origin.ogv => content/media/test/320x240.allow-origin.ogv rename : content/media/video/test/320x240.allow-origin.ogv^headers^ => content/media/test/320x240.allow-origin.ogv^headers^ rename : content/media/video/test/320x240.ogv => content/media/test/320x240.ogv rename : content/media/video/test/Makefile.in => content/media/test/Makefile.in rename : content/media/video/test/big.wav => content/media/test/big.wav rename : content/media/video/test/bug461281.ogg => content/media/test/bug461281.ogg rename : content/media/video/test/bug482461.ogv => content/media/test/bug482461.ogv rename : content/media/video/test/can_play_type_ogg.js => content/media/test/can_play_type_ogg.js rename : content/media/video/test/can_play_type_wave.js => content/media/test/can_play_type_wave.js rename : content/media/video/test/contentDuration1.sjs => content/media/test/contentDuration1.sjs rename : content/media/video/test/contentDuration2.sjs => content/media/test/contentDuration2.sjs rename : content/media/video/test/contentDuration3.sjs => content/media/test/contentDuration3.sjs rename : content/media/video/test/contentDuration4.sjs => content/media/test/contentDuration4.sjs rename : content/media/video/test/contentDuration5.sjs => content/media/test/contentDuration5.sjs rename : content/media/video/test/contentDuration6.sjs => content/media/test/contentDuration6.sjs rename : content/media/video/test/crashtests/468763-1.html => content/media/test/crashtests/468763-1.html rename : content/media/video/test/crashtests/474744-1.html => content/media/test/crashtests/474744-1.html rename : content/media/video/test/crashtests/crashtests.list => content/media/test/crashtests/crashtests.list rename : content/media/video/test/dynamic_redirect.sjs => content/media/test/dynamic_redirect.sjs rename : content/media/video/test/file_access_controls.html => content/media/test/file_access_controls.html rename : content/media/video/test/r11025_s16_c1.wav => content/media/test/r11025_s16_c1.wav rename : content/media/video/test/r11025_s16_c1_trailing.wav => content/media/test/r11025_s16_c1_trailing.wav rename : content/media/video/test/r11025_u8_c1.wav => content/media/test/r11025_u8_c1.wav rename : content/media/video/test/r11025_u8_c1_trunc.wav => content/media/test/r11025_u8_c1_trunc.wav rename : content/media/video/test/r16000_u8_c1_list.wav => content/media/test/r16000_u8_c1_list.wav rename : content/media/video/test/redirect.sjs => content/media/test/redirect.sjs rename : content/media/video/test/seek.ogv => content/media/test/seek.ogv rename : content/media/video/test/small-shot.ogg => content/media/test/small-shot.ogg rename : content/media/video/test/sound.ogg => content/media/test/sound.ogg rename : content/media/video/test/test_access_control.html => content/media/test/test_access_control.html rename : content/media/video/test/test_audio1.html => content/media/test/test_audio1.html rename : content/media/video/test/test_audio2.html => content/media/test/test_audio2.html rename : content/media/video/test/test_audioDocumentTitle.html => content/media/test/test_audioDocumentTitle.html rename : content/media/video/test/test_autobuffer.html => content/media/test/test_autobuffer.html rename : content/media/video/test/test_autobuffer2.html => content/media/test/test_autobuffer2.html rename : content/media/video/test/test_autoplay.html => content/media/test/test_autoplay.html rename : content/media/video/test/test_bug448534.html => content/media/test/test_bug448534.html rename : content/media/video/test/test_bug461281.html => content/media/test/test_bug461281.html rename : content/media/video/test/test_bug463162.xhtml => content/media/test/test_bug463162.xhtml rename : content/media/video/test/test_bug465498.html => content/media/test/test_bug465498.html rename : content/media/video/test/test_bug468190.html => content/media/test/test_bug468190.html rename : content/media/video/test/test_bug468190_wav.html => content/media/test/test_bug468190_wav.html rename : content/media/video/test/test_bug476973.html => content/media/test/test_bug476973.html rename : content/media/video/test/test_bug482461.html => content/media/test/test_bug482461.html rename : content/media/video/test/test_bug493187.html => content/media/test/test_bug493187.html rename : content/media/video/test/test_bug495145.html => content/media/test/test_bug495145.html rename : content/media/video/test/test_bug495145_wav.html => content/media/test/test_bug495145_wav.html rename : content/media/video/test/test_bug495300.html => content/media/test/test_bug495300.html rename : content/media/video/test/test_bug495319.html => content/media/test/test_bug495319.html rename : content/media/video/test/test_can_play_type.html => content/media/test/test_can_play_type.html rename : content/media/video/test/test_can_play_type_no_ogg.html => content/media/test/test_can_play_type_no_ogg.html rename : content/media/video/test/test_can_play_type_no_wave.html => content/media/test/test_can_play_type_no_wave.html rename : content/media/video/test/test_can_play_type_ogg.html => content/media/test/test_can_play_type_ogg.html rename : content/media/video/test/test_can_play_type_wave.html => content/media/test/test_can_play_type_wave.html rename : content/media/video/test/test_closing_connections.html => content/media/test/test_closing_connections.html rename : content/media/video/test/test_constants.html => content/media/test/test_constants.html rename : content/media/video/test/test_contentDuration1.html => content/media/test/test_contentDuration1.html rename : content/media/video/test/test_contentDuration2.html => content/media/test/test_contentDuration2.html rename : content/media/video/test/test_contentDuration3.html => content/media/test/test_contentDuration3.html rename : content/media/video/test/test_contentDuration4.html => content/media/test/test_contentDuration4.html rename : content/media/video/test/test_contentDuration5.html => content/media/test/test_contentDuration5.html rename : content/media/video/test/test_contentDuration6.html => content/media/test/test_contentDuration6.html rename : content/media/video/test/test_controls.html => content/media/test/test_controls.html rename : content/media/video/test/test_currentTime.html => content/media/test/test_currentTime.html rename : content/media/video/test/test_decoder_disable.html => content/media/test/test_decoder_disable.html rename : content/media/video/test/test_delay_load.html => content/media/test/test_delay_load.html rename : content/media/video/test/test_duration1.html => content/media/test/test_duration1.html rename : content/media/video/test/test_ended1.html => content/media/test/test_ended1.html rename : content/media/video/test/test_ended2.html => content/media/test/test_ended2.html rename : content/media/video/test/test_error_on_404.html => content/media/test/test_error_on_404.html rename : content/media/video/test/test_info_leak.html => content/media/test/test_info_leak.html rename : content/media/video/test/test_load.html => content/media/test/test_load.html rename : content/media/video/test/test_load_candidates.html => content/media/test/test_load_candidates.html rename : content/media/video/test/test_media_selection.html => content/media/test/test_media_selection.html rename : content/media/video/test/test_mixed_principals.html => content/media/test/test_mixed_principals.html rename : content/media/video/test/test_networkState.html => content/media/test/test_networkState.html rename : content/media/video/test/test_onloadedmetadata.html => content/media/test/test_onloadedmetadata.html rename : content/media/video/test/test_paused.html => content/media/test/test_paused.html rename : content/media/video/test/test_paused_after_ended.html => content/media/test/test_paused_after_ended.html rename : content/media/video/test/test_play.html => content/media/test/test_play.html rename : content/media/video/test/test_progress1.html => content/media/test/test_progress1.html rename : content/media/video/test/test_progress2.html => content/media/test/test_progress2.html rename : content/media/video/test/test_progress3.html => content/media/test/test_progress3.html rename : content/media/video/test/test_progress4.html => content/media/test/test_progress4.html rename : content/media/video/test/test_readyState.html => content/media/test/test_readyState.html rename : content/media/video/test/test_seek1.html => content/media/test/test_seek1.html rename : content/media/video/test/test_seek2.html => content/media/test/test_seek2.html rename : content/media/video/test/test_seek3.html => content/media/test/test_seek3.html rename : content/media/video/test/test_seek4.html => content/media/test/test_seek4.html rename : content/media/video/test/test_seek5.html => content/media/test/test_seek5.html rename : content/media/video/test/test_seek6.html => content/media/test/test_seek6.html rename : content/media/video/test/test_seek7.html => content/media/test/test_seek7.html rename : content/media/video/test/test_seek8.html => content/media/test/test_seek8.html rename : content/media/video/test/test_seek9.html => content/media/test/test_seek9.html rename : content/media/video/test/test_source.html => content/media/test/test_source.html rename : content/media/video/test/test_source_write.html => content/media/test/test_source_write.html rename : content/media/video/test/test_standalone.html => content/media/test/test_standalone.html rename : content/media/video/test/test_timeupdate1.html => content/media/test/test_timeupdate1.html rename : content/media/video/test/test_timeupdate2.html => content/media/test/test_timeupdate2.html rename : content/media/video/test/test_timeupdate3.html => content/media/test/test_timeupdate3.html rename : content/media/video/test/test_videoDocumentTitle.html => content/media/test/test_videoDocumentTitle.html rename : content/media/video/test/test_volume.html => content/media/test/test_volume.html rename : content/media/video/test/test_wav_8bit.html => content/media/test/test_wav_8bit.html rename : content/media/video/test/test_wav_ended1.html => content/media/test/test_wav_ended1.html rename : content/media/video/test/test_wav_ended2.html => content/media/test/test_wav_ended2.html rename : content/media/video/test/test_wav_list.html => content/media/test/test_wav_list.html rename : content/media/video/test/test_wav_onloadedmetadata.html => content/media/test/test_wav_onloadedmetadata.html rename : content/media/video/test/test_wav_seek1.html => content/media/test/test_wav_seek1.html rename : content/media/video/test/test_wav_seek3.html => content/media/test/test_wav_seek3.html rename : content/media/video/test/test_wav_seek4.html => content/media/test/test_wav_seek4.html rename : content/media/video/test/test_wav_seek5.html => content/media/test/test_wav_seek5.html rename : content/media/video/test/test_wav_seek6.html => content/media/test/test_wav_seek6.html rename : content/media/video/test/test_wav_seek7.html => content/media/test/test_wav_seek7.html rename : content/media/video/test/test_wav_seek8.html => content/media/test/test_wav_seek8.html rename : content/media/video/test/test_wav_seek_past_end.html => content/media/test/test_wav_seek_past_end.html rename : content/media/video/test/test_wav_seek_then_play.html => content/media/test/test_wav_seek_then_play.html rename : content/media/video/test/test_wav_standalone.html => content/media/test/test_wav_standalone.html rename : content/media/video/test/test_wav_timeupdate1.html => content/media/test/test_wav_timeupdate1.html rename : content/media/video/test/test_wav_timeupdate2.html => content/media/test/test_wav_timeupdate2.html rename : content/media/video/test/test_wav_trailing.html => content/media/test/test_wav_trailing.html rename : content/media/video/test/test_wav_trunc.html => content/media/test/test_wav_trunc.html rename : content/media/video/test/test_wav_trunc_seek.html => content/media/test/test_wav_trunc_seek.html rename : content/media/video/test/use_large_cache.js => content/media/test/use_large_cache.js rename : content/media/video/src/nsWaveDecoder.cpp => content/media/wave/nsWaveDecoder.cpp rename : content/media/video/public/nsWaveDecoder.h => content/media/wave/nsWaveDecoder.h
412 lines
16 KiB
C++
412 lines
16 KiB
C++
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Mozilla code.
|
|
*
|
|
* The Initial Developer of the Original Code is the Mozilla Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 2007
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Chris Double <chris.double@double.co.nz>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#if !defined(nsMediaStream_h_)
|
|
#define nsMediaStream_h_
|
|
|
|
#include "mozilla/XPCOM.h"
|
|
#include "nsIChannel.h"
|
|
#include "nsIPrincipal.h"
|
|
#include "nsIURI.h"
|
|
#include "nsIStreamListener.h"
|
|
#include "nsIChannelEventSink.h"
|
|
#include "nsIInterfaceRequestor.h"
|
|
#include "prlock.h"
|
|
#include "nsMediaCache.h"
|
|
|
|
// For HTTP seeking, if number of bytes needing to be
|
|
// seeked forward is less than this value then a read is
|
|
// done rather than a byte range request.
|
|
#define SEEK_VS_READ_THRESHOLD (32*1024)
|
|
|
|
class nsMediaDecoder;
|
|
|
|
/**
|
|
* This class is useful for estimating rates of data passing through
|
|
* some channel. The idea is that activity on the channel "starts"
|
|
* and "stops" over time. At certain times data passes through the
|
|
* channel (usually while the channel is active; data passing through
|
|
* an inactive channel is ignored). The GetRate() function computes
|
|
* an estimate of the "current rate" of the channel, which is some
|
|
* kind of average of the data passing through over the time the
|
|
* channel is active.
|
|
*
|
|
* All methods take "now" as a parameter so the user of this class can
|
|
* control the timeline used.
|
|
*/
|
|
class nsChannelStatistics {
|
|
public:
|
|
typedef mozilla::TimeStamp TimeStamp;
|
|
typedef mozilla::TimeDuration TimeDuration;
|
|
|
|
nsChannelStatistics() { Reset(); }
|
|
void Reset() {
|
|
mLastStartTime = TimeStamp();
|
|
mAccumulatedTime = TimeDuration(0);
|
|
mAccumulatedBytes = 0;
|
|
mIsStarted = PR_FALSE;
|
|
}
|
|
void Start(TimeStamp aNow) {
|
|
if (mIsStarted)
|
|
return;
|
|
mLastStartTime = aNow;
|
|
mIsStarted = PR_TRUE;
|
|
}
|
|
void Stop(TimeStamp aNow) {
|
|
if (!mIsStarted)
|
|
return;
|
|
mAccumulatedTime += aNow - mLastStartTime;
|
|
mIsStarted = PR_FALSE;
|
|
}
|
|
void AddBytes(PRInt64 aBytes) {
|
|
if (!mIsStarted) {
|
|
// ignore this data, it may be related to seeking or some other
|
|
// operation we don't care about
|
|
return;
|
|
}
|
|
mAccumulatedBytes += aBytes;
|
|
}
|
|
double GetRateAtLastStop(PRPackedBool* aReliable) {
|
|
double seconds = mAccumulatedTime.ToSeconds();
|
|
*aReliable = seconds >= 1.0;
|
|
if (seconds <= 0.0)
|
|
return 0.0;
|
|
return double(mAccumulatedBytes)/seconds;
|
|
}
|
|
double GetRate(TimeStamp aNow, PRPackedBool* aReliable) {
|
|
TimeDuration time = mAccumulatedTime;
|
|
if (mIsStarted) {
|
|
time += aNow - mLastStartTime;
|
|
}
|
|
double seconds = time.ToSeconds();
|
|
*aReliable = seconds >= 3.0;
|
|
if (seconds <= 0.0)
|
|
return 0.0;
|
|
return double(mAccumulatedBytes)/seconds;
|
|
}
|
|
private:
|
|
PRInt64 mAccumulatedBytes;
|
|
TimeDuration mAccumulatedTime;
|
|
TimeStamp mLastStartTime;
|
|
PRPackedBool mIsStarted;
|
|
};
|
|
|
|
/*
|
|
Provides the ability to open, read and seek into a media stream
|
|
(audio, video). Handles the underlying machinery to do range
|
|
requests, etc as needed by the actual stream type. Instances of
|
|
this class must be created on the main thread.
|
|
|
|
Most methods must be called on the main thread only. Read, Seek and
|
|
Tell may be called on another thread which may be a non main
|
|
thread. They may not be called on multiple other threads though. In
|
|
the case of the Ogg Decoder they are called on the Decode thread
|
|
for example. You must ensure that no threads are calling these
|
|
methods once Close is called.
|
|
|
|
Instances of this class are explicitly managed. 'delete' it when done.
|
|
*/
|
|
class nsMediaStream
|
|
{
|
|
public:
|
|
virtual ~nsMediaStream()
|
|
{
|
|
MOZ_COUNT_DTOR(nsMediaStream);
|
|
}
|
|
|
|
// The following can be called on the main thread only:
|
|
// Get the decoder
|
|
nsMediaDecoder* Decoder() { return mDecoder; }
|
|
// Close the stream, stop any listeners, channels, etc.
|
|
// Cancels any currently blocking Read request and forces that request to
|
|
// return an error.
|
|
virtual nsresult Close() = 0;
|
|
// Suspend any downloads that are in progress.
|
|
// If aCloseImmediately is set, resources should be released immediately
|
|
// since we don't expect to resume again any time soon. Otherwise we
|
|
// may resume again soon so resources should be held for a little
|
|
// while.
|
|
virtual void Suspend(PRBool aCloseImmediately) = 0;
|
|
// Resume any downloads that have been suspended.
|
|
virtual void Resume() = 0;
|
|
// Get the current principal for the channel
|
|
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() = 0;
|
|
|
|
// These methods are called off the main thread.
|
|
// The mode is initially MODE_PLAYBACK.
|
|
virtual void SetReadMode(nsMediaCacheStream::ReadMode aMode) = 0;
|
|
// This is the client's estimate of the playback rate assuming
|
|
// the media plays continuously. The cache can't guess this itself
|
|
// because it doesn't know when the decoder was paused, buffering, etc.
|
|
virtual void SetPlaybackRate(PRUint32 aBytesPerSecond) = 0;
|
|
// Read up to aCount bytes from the stream. The buffer must have
|
|
// enough room for at least aCount bytes. Stores the number of
|
|
// actual bytes read in aBytes (0 on end of file).
|
|
// May read less than aCount bytes if the number of
|
|
// available bytes is less than aCount. Always check *aBytes after
|
|
// read, and call again if necessary.
|
|
virtual nsresult Read(char* aBuffer, PRUint32 aCount, PRUint32* aBytes) = 0;
|
|
// Seek to the given bytes offset in the stream. aWhence can be
|
|
// one of:
|
|
// NS_SEEK_SET
|
|
// NS_SEEK_CUR
|
|
// NS_SEEK_END
|
|
//
|
|
// In the Http strategy case the cancel will cause the http
|
|
// channel's listener to close the pipe, forcing an i/o error on any
|
|
// blocked read. This will allow the decode thread to complete the
|
|
// event.
|
|
//
|
|
// In the case of a seek in progress, the byte range request creates
|
|
// a new listener. This is done on the main thread via seek
|
|
// synchronously dispatching an event. This avoids the issue of us
|
|
// closing the listener but an outstanding byte range request
|
|
// creating a new one. They run on the same thread so no explicit
|
|
// synchronisation is required. The byte range request checks for
|
|
// the cancel flag and does not create a new channel or listener if
|
|
// we are cancelling.
|
|
//
|
|
// The default strategy does not do any seeking - the only issue is
|
|
// a blocked read which it handles by causing the listener to close
|
|
// the pipe, as per the http case.
|
|
//
|
|
// The file strategy doesn't block for any great length of time so
|
|
// is fine for a no-op cancel.
|
|
virtual nsresult Seek(PRInt32 aWhence, PRInt64 aOffset) = 0;
|
|
// Report the current offset in bytes from the start of the stream.
|
|
virtual PRInt64 Tell() = 0;
|
|
// Moves any existing channel loads into the background, so that they don't
|
|
// block the load event. Any new loads initiated (for example to seek)
|
|
// will also be in the background.
|
|
void MoveLoadsToBackground();
|
|
|
|
// These can be called on any thread.
|
|
// Cached blocks associated with this stream will not be evicted
|
|
// while the stream is pinned.
|
|
virtual void Pin() = 0;
|
|
virtual void Unpin() = 0;
|
|
// Get the estimated download rate in bytes per second (assuming no
|
|
// pausing of the channel is requested by Gecko).
|
|
// *aIsReliable is set to true if we think the estimate is useful.
|
|
virtual double GetDownloadRate(PRPackedBool* aIsReliable) = 0;
|
|
// Get the length of the stream in bytes. Returns -1 if not known.
|
|
// This can change over time; after a seek operation, a misbehaving
|
|
// server may give us a resource of a different length to what it had
|
|
// reported previously --- or it may just lie in its Content-Length
|
|
// header and give us more or less data than it reported. We will adjust
|
|
// the result of GetLength to reflect the data that's actually arriving.
|
|
virtual PRInt64 GetLength() = 0;
|
|
// Returns the offset of the first byte of cached data at or after aOffset,
|
|
// or -1 if there is no such cached data.
|
|
virtual PRInt64 GetNextCachedData(PRInt64 aOffset) = 0;
|
|
// Returns the end of the bytes starting at the given offset
|
|
// which are in cache.
|
|
virtual PRInt64 GetCachedDataEnd(PRInt64 aOffset) = 0;
|
|
// Returns true if all the data from aOffset to the end of the stream
|
|
// is in cache. If the end of the stream is not known, we return false.
|
|
virtual PRBool IsDataCachedToEndOfStream(PRInt64 aOffset) = 0;
|
|
// Returns true if this stream is suspended by the cache because the
|
|
// cache is full. If true then the decoder should try to start consuming
|
|
// data, otherwise we may not be able to make progress.
|
|
// nsMediaDecoder::NotifySuspendedStatusChanged is called when this
|
|
// changes.
|
|
virtual PRBool IsSuspendedByCache() = 0;
|
|
|
|
/**
|
|
* Create a stream, reading data from the
|
|
* media resource at the URI. Call on main thread only.
|
|
* @param aChannel if non-null, this channel is used and aListener
|
|
* is set to the listener we want for the channel. aURI must
|
|
* be the URI for the channel, obtained via NS_GetFinalChannelURI.
|
|
*/
|
|
static nsresult Open(nsMediaDecoder* aDecoder, nsIURI* aURI,
|
|
nsIChannel* aChannel, nsMediaStream** aStream,
|
|
nsIStreamListener** aListener);
|
|
|
|
protected:
|
|
nsMediaStream(nsMediaDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI) :
|
|
mDecoder(aDecoder),
|
|
mChannel(aChannel),
|
|
mURI(aURI),
|
|
mLoadInBackground(PR_FALSE)
|
|
{
|
|
MOZ_COUNT_CTOR(nsMediaStream);
|
|
}
|
|
|
|
/**
|
|
* @param aStreamListener if null, the strategy should open mChannel
|
|
* itself. Otherwise, mChannel is already open and the strategy
|
|
* should just return its stream listener in aStreamListener (or set
|
|
* *aStreamListener to null, if it doesn't need a listener).
|
|
*/
|
|
virtual nsresult Open(nsIStreamListener** aStreamListener) = 0;
|
|
|
|
// This is not an nsCOMPointer to prevent a circular reference
|
|
// between the decoder to the media stream object. The stream never
|
|
// outlives the lifetime of the decoder.
|
|
nsMediaDecoder* mDecoder;
|
|
|
|
// Channel used to download the media data. Must be accessed
|
|
// from the main thread only.
|
|
nsCOMPtr<nsIChannel> mChannel;
|
|
|
|
// URI in case the stream needs to be re-opened. Access from
|
|
// main thread only.
|
|
nsCOMPtr<nsIURI> mURI;
|
|
|
|
// PR_TRUE if MoveLoadsToBackground() has been called, i.e. the load event
|
|
// has been fired, and all channel loads will be in the background.
|
|
PRPackedBool mLoadInBackground;
|
|
};
|
|
|
|
/**
|
|
* This is the nsMediaStream implementation that wraps Necko channels.
|
|
* Much of its functionality is actually delegated to nsMediaCache via
|
|
* an underlying nsMediaCacheStream.
|
|
*
|
|
* All synchronization is performed by nsMediaCacheStream; all off-main-
|
|
* thread operations are delegated directly to that object.
|
|
*/
|
|
class nsMediaChannelStream : public nsMediaStream
|
|
{
|
|
public:
|
|
nsMediaChannelStream(nsMediaDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI);
|
|
~nsMediaChannelStream();
|
|
|
|
// These are called on the main thread by nsMediaCache. These must
|
|
// not block or grab locks.
|
|
// Start a new load at the given aOffset. The old load is cancelled
|
|
// and no more data from the old load will be notified via
|
|
// nsMediaCacheStream::NotifyDataReceived/Ended.
|
|
// This can fail.
|
|
nsresult CacheClientSeek(PRInt64 aOffset, PRBool aResume);
|
|
// Suspend the current load since data is currently not wanted
|
|
nsresult CacheClientSuspend();
|
|
// Resume the current load since data is wanted again
|
|
nsresult CacheClientResume();
|
|
|
|
// Main thread
|
|
virtual nsresult Open(nsIStreamListener** aStreamListener);
|
|
virtual nsresult Close();
|
|
virtual void Suspend(PRBool aCloseImmediately);
|
|
virtual void Resume();
|
|
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
|
|
// Return PR_TRUE if the stream has been closed.
|
|
PRBool IsClosed() const { return mCacheStream.IsClosed(); }
|
|
|
|
// Other thread
|
|
virtual void SetReadMode(nsMediaCacheStream::ReadMode aMode);
|
|
virtual void SetPlaybackRate(PRUint32 aBytesPerSecond);
|
|
virtual nsresult Read(char* aBuffer, PRUint32 aCount, PRUint32* aBytes);
|
|
virtual nsresult Seek(PRInt32 aWhence, PRInt64 aOffset);
|
|
virtual PRInt64 Tell();
|
|
|
|
// Any thread
|
|
virtual void Pin();
|
|
virtual void Unpin();
|
|
virtual double GetDownloadRate(PRPackedBool* aIsReliable);
|
|
virtual PRInt64 GetLength();
|
|
virtual PRInt64 GetNextCachedData(PRInt64 aOffset);
|
|
virtual PRInt64 GetCachedDataEnd(PRInt64 aOffset);
|
|
virtual PRBool IsDataCachedToEndOfStream(PRInt64 aOffset);
|
|
virtual PRBool IsSuspendedByCache();
|
|
|
|
protected:
|
|
class Listener : public nsIStreamListener,
|
|
public nsIInterfaceRequestor,
|
|
public nsIChannelEventSink
|
|
{
|
|
public:
|
|
Listener(nsMediaChannelStream* aStream) : mStream(aStream) {}
|
|
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSIREQUESTOBSERVER
|
|
NS_DECL_NSISTREAMLISTENER
|
|
NS_DECL_NSICHANNELEVENTSINK
|
|
NS_DECL_NSIINTERFACEREQUESTOR
|
|
|
|
void Revoke() { mStream = nsnull; }
|
|
|
|
private:
|
|
nsMediaChannelStream* mStream;
|
|
};
|
|
friend class Listener;
|
|
|
|
// These are called on the main thread by Listener.
|
|
nsresult OnStartRequest(nsIRequest* aRequest);
|
|
nsresult OnStopRequest(nsIRequest* aRequest, nsresult aStatus);
|
|
nsresult OnDataAvailable(nsIRequest* aRequest,
|
|
nsIInputStream* aStream,
|
|
PRUint32 aCount);
|
|
nsresult OnChannelRedirect(nsIChannel* aOld, nsIChannel* aNew, PRUint32 aFlags);
|
|
|
|
// Opens the channel, using an HTTP byte range request to start at mOffset
|
|
// if possible. Main thread only.
|
|
nsresult OpenChannel(nsIStreamListener** aStreamListener);
|
|
void SetupChannelHeaders();
|
|
// Closes the channel. Main thread only.
|
|
void CloseChannel();
|
|
|
|
static NS_METHOD CopySegmentToCache(nsIInputStream *aInStream,
|
|
void *aClosure,
|
|
const char *aFromSegment,
|
|
PRUint32 aToOffset,
|
|
PRUint32 aCount,
|
|
PRUint32 *aWriteCount);
|
|
|
|
// Main thread access only
|
|
PRInt64 mOffset;
|
|
nsRefPtr<Listener> mListener;
|
|
PRUint32 mSuspendCount;
|
|
// When this flag is set, if we get a network error we should silently
|
|
// reopen the stream.
|
|
PRPackedBool mReopenOnError;
|
|
// When this flag is set, we should not report the next close of the
|
|
// channel.
|
|
PRPackedBool mIgnoreClose;
|
|
|
|
// Any thread access
|
|
nsMediaCacheStream mCacheStream;
|
|
|
|
// This lock protects mChannelStatistics and mCacheSuspendCount
|
|
PRLock* mLock;
|
|
nsChannelStatistics mChannelStatistics;
|
|
PRUint32 mCacheSuspendCount;
|
|
};
|
|
|
|
#endif
|