зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 7 changesets (bug 1109437) for suspicious-looking crashes on a CLOSED TREE.
Backed out changeset dc45e97d102d (bug 1109437) Backed out changeset e6350e4fb18b (bug 1109437) Backed out changeset 4c38dda06880 (bug 1109437) Backed out changeset 72f171ec04ba (bug 1109437) Backed out changeset ec275f65c676 (bug 1109437) Backed out changeset 65d172e7a1cf (bug 1109437) Backed out changeset 0b8a156dcff0 (bug 1109437)
This commit is contained in:
Родитель
5b302452ea
Коммит
facb39a4e0
|
@ -13,8 +13,6 @@
|
|||
#include "MediaQueue.h"
|
||||
#include "AudioCompactor.h"
|
||||
|
||||
#include "mozilla/TypedEnum.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
|
@ -24,17 +22,6 @@ class TimeRanges;
|
|||
class MediaDecoderReader;
|
||||
class SharedDecoderManager;
|
||||
|
||||
struct WaitForDataRejectValue {
|
||||
enum Reason {
|
||||
SHUTDOWN
|
||||
};
|
||||
|
||||
WaitForDataRejectValue(MediaData::Type aType, Reason aReason)
|
||||
:mType(aType), mReason(aReason) {}
|
||||
MediaData::Type mType;
|
||||
Reason mReason;
|
||||
};
|
||||
|
||||
// Encapsulates the decoding and reading of media data. Reading can either
|
||||
// synchronous and done on the calling "decode" thread, or asynchronous and
|
||||
// performed on a background thread, with the result being returned by
|
||||
|
@ -53,7 +40,6 @@ public:
|
|||
typedef MediaPromise<nsRefPtr<AudioData>, NotDecodedReason> AudioDataPromise;
|
||||
typedef MediaPromise<nsRefPtr<VideoData>, NotDecodedReason> VideoDataPromise;
|
||||
typedef MediaPromise<bool, nsresult> SeekPromise;
|
||||
typedef MediaPromise<MediaData::Type, WaitForDataRejectValue> WaitForDataPromise;
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReader)
|
||||
|
||||
|
@ -127,12 +113,6 @@ public:
|
|||
virtual nsRefPtr<VideoDataPromise>
|
||||
RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold);
|
||||
|
||||
// By default, the state machine polls the reader once per second when it's
|
||||
// in buffering mode. Some readers support a promise-based mechanism by which
|
||||
// they notify the state machine when the data arrives.
|
||||
virtual bool IsWaitForDataSupported() { return false; }
|
||||
virtual nsRefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) { MOZ_CRASH(); }
|
||||
|
||||
virtual bool HasAudio() = 0;
|
||||
virtual bool HasVideo() = 0;
|
||||
|
||||
|
@ -195,11 +175,10 @@ public:
|
|||
|
||||
virtual int64_t ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio);
|
||||
|
||||
// The MediaDecoderStateMachine uses various heuristics that assume that
|
||||
// raw media data is arriving sequentially from a network channel. This
|
||||
// makes sense in the <video src="foo"> case, but not for more advanced use
|
||||
// cases like MSE.
|
||||
virtual bool UseBufferingHeuristics() { return true; }
|
||||
// Wait this number of seconds when buffering, then leave and play
|
||||
// as best as we can if the required amount of data hasn't been
|
||||
// retrieved.
|
||||
virtual uint32_t GetBufferingWait() { return 30; }
|
||||
|
||||
// Returns the number of bytes of memory allocated by structures/frames in
|
||||
// the video queue.
|
||||
|
|
|
@ -195,8 +195,8 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
|||
mAmpleVideoFrames(2),
|
||||
mLowAudioThresholdUsecs(LOW_AUDIO_USECS),
|
||||
mAmpleAudioThresholdUsecs(AMPLE_AUDIO_USECS),
|
||||
mAudioRequestStatus(RequestStatus::Idle),
|
||||
mVideoRequestStatus(RequestStatus::Idle),
|
||||
mAudioRequestPending(false),
|
||||
mVideoRequestPending(false),
|
||||
mAudioCaptured(false),
|
||||
mPositionChangeQueued(false),
|
||||
mAudioCompleted(false),
|
||||
|
@ -221,7 +221,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
|||
mAmpleVideoFrames =
|
||||
std::max<uint32_t>(Preferences::GetUint("media.video-queue.default-size", 10), 3);
|
||||
|
||||
mBufferingWait = mScheduler->IsRealTime() ? 0 : 30;
|
||||
mBufferingWait = mScheduler->IsRealTime() ? 0 : mReader->GetBufferingWait();
|
||||
mLowDataThresholdUsecs = mScheduler->IsRealTime() ? 0 : LOW_DATA_THRESHOLD_USECS;
|
||||
|
||||
mVideoPrerollFrames = mScheduler->IsRealTime() ? 0 : mAmpleVideoFrames / 2;
|
||||
|
@ -579,7 +579,7 @@ MediaDecoderStateMachine::DecodeVideo()
|
|||
if (mState != DECODER_STATE_DECODING &&
|
||||
mState != DECODER_STATE_BUFFERING &&
|
||||
mState != DECODER_STATE_SEEKING) {
|
||||
mVideoRequestStatus = RequestStatus::Idle;
|
||||
mVideoRequestPending = false;
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
return;
|
||||
}
|
||||
|
@ -658,7 +658,7 @@ MediaDecoderStateMachine::DecodeAudio()
|
|||
if (mState != DECODER_STATE_DECODING &&
|
||||
mState != DECODER_STATE_BUFFERING &&
|
||||
mState != DECODER_STATE_SEEKING) {
|
||||
mAudioRequestStatus = RequestStatus::Idle;
|
||||
mAudioRequestPending = false;
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
mon.NotifyAll();
|
||||
return;
|
||||
|
@ -713,7 +713,7 @@ MediaDecoderStateMachine::OnAudioDecoded(AudioData* aAudioSample)
|
|||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
nsRefPtr<AudioData> audio(aAudioSample);
|
||||
MOZ_ASSERT(audio);
|
||||
mAudioRequestStatus = RequestStatus::Idle;
|
||||
mAudioRequestPending = false;
|
||||
mDecodedAudioEndTime = audio->GetEndTime();
|
||||
|
||||
SAMPLE_LOG("OnAudioDecoded [%lld,%lld] disc=%d",
|
||||
|
@ -729,10 +729,8 @@ MediaDecoderStateMachine::OnAudioDecoded(AudioData* aAudioSample)
|
|||
}
|
||||
|
||||
case DECODER_STATE_BUFFERING:
|
||||
// If we're buffering, this may be the sample we need to stop buffering.
|
||||
// Schedule the state machine and then fall through.
|
||||
ScheduleStateMachine();
|
||||
case DECODER_STATE_DECODING: {
|
||||
// In buffering and decoding state, we simply enqueue samples.
|
||||
Push(audio);
|
||||
return;
|
||||
}
|
||||
|
@ -827,7 +825,11 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
|||
MOZ_ASSERT_IF(!isAudio, aType == MediaData::VIDEO_DATA);
|
||||
|
||||
// This callback means that the pending request is dead.
|
||||
RequestStatusRef(aType) = RequestStatus::Idle;
|
||||
if (isAudio) {
|
||||
mAudioRequestPending = false;
|
||||
} else {
|
||||
mVideoRequestPending = false;
|
||||
}
|
||||
|
||||
// If this is a decode error, delegate to the generic error path.
|
||||
if (aReason == MediaDecoderReader::DECODE_ERROR) {
|
||||
|
@ -835,15 +837,15 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
|||
return;
|
||||
}
|
||||
|
||||
// If the decoder is waiting for data, we tell it to call us back when the
|
||||
// data arrives.
|
||||
// If the decoder is waiting for data, we need to make sure that the requests
|
||||
// are cleared, which happened above. Additionally, if we're out of decoded
|
||||
// samples, we need to switch to buffering mode.
|
||||
if (aReason == MediaDecoderReader::WAITING_FOR_DATA) {
|
||||
MOZ_ASSERT(mReader->IsWaitForDataSupported(),
|
||||
"Readers that send WAITING_FOR_DATA need to implement WaitForData");
|
||||
RequestStatusRef(aType) = RequestStatus::Waiting;
|
||||
mReader->WaitForData(aType)->Then(DecodeTaskQueue(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnWaitForDataResolved,
|
||||
&MediaDecoderStateMachine::OnWaitForDataRejected);
|
||||
bool outOfSamples = isAudio ? !AudioQueue().GetSize() : !VideoQueue().GetSize();
|
||||
if (outOfSamples) {
|
||||
StartBuffering();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -928,7 +930,7 @@ MediaDecoderStateMachine::OnVideoDecoded(VideoData* aVideoSample)
|
|||
MOZ_ASSERT(OnDecodeThread());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
nsRefPtr<VideoData> video(aVideoSample);
|
||||
mVideoRequestStatus = RequestStatus::Idle;
|
||||
mVideoRequestPending = false;
|
||||
|
||||
SAMPLE_LOG("OnVideoDecoded [%lld,%lld] disc=%d",
|
||||
(video ? video->mTime : -1),
|
||||
|
@ -943,9 +945,6 @@ MediaDecoderStateMachine::OnVideoDecoded(VideoData* aVideoSample)
|
|||
}
|
||||
|
||||
case DECODER_STATE_BUFFERING:
|
||||
// If we're buffering, this may be the sample we need to stop buffering.
|
||||
// Schedule the state machine and then fall through.
|
||||
ScheduleStateMachine();
|
||||
case DECODER_STATE_DECODING: {
|
||||
Push(video);
|
||||
// If the requested video sample was slow to arrive, increase the
|
||||
|
@ -1746,9 +1745,9 @@ MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
|
|||
!needToDecodeVideo &&
|
||||
!IsPlaying();
|
||||
|
||||
SAMPLE_LOG("DispatchDecodeTasksIfNeeded needAudio=%d audioStatus=%d needVideo=%d videoStatus=%d needIdle=%d",
|
||||
needToDecodeAudio, mAudioRequestStatus,
|
||||
needToDecodeVideo, mVideoRequestStatus,
|
||||
SAMPLE_LOG("DispatchDecodeTasksIfNeeded needAudio=%d dispAudio=%d needVideo=%d dispVid=%d needIdle=%d",
|
||||
needToDecodeAudio, mAudioRequestPending,
|
||||
needToDecodeVideo, mVideoRequestPending,
|
||||
needIdle);
|
||||
|
||||
if (needToDecodeAudio) {
|
||||
|
@ -1818,8 +1817,8 @@ MediaDecoderStateMachine::EnsureAudioDecodeTaskQueued()
|
|||
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
|
||||
"Should be on state machine or decode thread.");
|
||||
|
||||
SAMPLE_LOG("EnsureAudioDecodeTaskQueued isDecoding=%d status=%d",
|
||||
IsAudioDecoding(), mAudioRequestStatus);
|
||||
SAMPLE_LOG("EnsureAudioDecodeTaskQueued isDecoding=%d dispatched=%d",
|
||||
IsAudioDecoding(), mAudioRequestPending);
|
||||
|
||||
if (mState >= DECODER_STATE_COMPLETED) {
|
||||
return NS_OK;
|
||||
|
@ -1827,12 +1826,12 @@ MediaDecoderStateMachine::EnsureAudioDecodeTaskQueued()
|
|||
|
||||
MOZ_ASSERT(mState > DECODER_STATE_DECODING_FIRSTFRAME);
|
||||
|
||||
if (IsAudioDecoding() && mAudioRequestStatus == RequestStatus::Idle && !mWaitingForDecoderSeek) {
|
||||
if (IsAudioDecoding() && !mAudioRequestPending && !mWaitingForDecoderSeek) {
|
||||
RefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DecodeAudio));
|
||||
nsresult rv = DecodeTaskQueue()->Dispatch(task);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mAudioRequestStatus = RequestStatus::Pending;
|
||||
mAudioRequestPending = true;
|
||||
} else {
|
||||
DECODER_WARN("Failed to dispatch task to decode audio");
|
||||
}
|
||||
|
@ -1860,8 +1859,8 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
|
|||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
SAMPLE_LOG("EnsureVideoDecodeTaskQueued isDecoding=%d status=%d",
|
||||
IsVideoDecoding(), mVideoRequestStatus);
|
||||
SAMPLE_LOG("EnsureVideoDecodeTaskQueued isDecoding=%d dispatched=%d",
|
||||
IsVideoDecoding(), mVideoRequestPending);
|
||||
|
||||
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
|
||||
"Should be on state machine or decode thread.");
|
||||
|
@ -1872,12 +1871,12 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
|
|||
|
||||
MOZ_ASSERT(mState > DECODER_STATE_DECODING_FIRSTFRAME);
|
||||
|
||||
if (IsVideoDecoding() && mVideoRequestStatus == RequestStatus::Idle && !mWaitingForDecoderSeek) {
|
||||
if (IsVideoDecoding() && !mVideoRequestPending && !mWaitingForDecoderSeek) {
|
||||
RefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DecodeVideo));
|
||||
nsresult rv = DecodeTaskQueue()->Dispatch(task);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mVideoRequestStatus = RequestStatus::Pending;
|
||||
mVideoRequestPending = true;
|
||||
} else {
|
||||
DECODER_WARN("Failed to dispatch task to decode video");
|
||||
}
|
||||
|
@ -1931,7 +1930,6 @@ int64_t MediaDecoderStateMachine::AudioDecodedUsecs()
|
|||
bool MediaDecoderStateMachine::HasLowDecodedData(int64_t aAudioUsecs)
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
MOZ_ASSERT(mReader->UseBufferingHeuristics());
|
||||
// We consider ourselves low on decoded data if we're low on audio,
|
||||
// provided we've not decoded to the end of the audio stream, or
|
||||
// if we're low on video frames, provided
|
||||
|
@ -2628,41 +2626,28 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||
TimeStamp now = TimeStamp::Now();
|
||||
NS_ASSERTION(!mBufferingStart.IsNull(), "Must know buffering start time.");
|
||||
|
||||
// With buffering heuristics we will remain in the buffering state if
|
||||
// we've not decoded enough data to begin playback, or if we've not
|
||||
// downloaded a reasonable amount of data inside our buffering time.
|
||||
if (mReader->UseBufferingHeuristics()) {
|
||||
TimeDuration elapsed = now - mBufferingStart;
|
||||
bool isLiveStream = resource->GetLength() == -1;
|
||||
if ((isLiveStream || !mDecoder->CanPlayThrough()) &&
|
||||
elapsed < TimeDuration::FromSeconds(mBufferingWait * mPlaybackRate) &&
|
||||
(mQuickBuffering ? HasLowDecodedData(QUICK_BUFFERING_LOW_DATA_USECS)
|
||||
: HasLowUndecodedData(mBufferingWait * USECS_PER_S)) &&
|
||||
mDecoder->IsExpectingMoreData())
|
||||
{
|
||||
DECODER_LOG("Buffering: wait %ds, timeout in %.3lfs %s",
|
||||
mBufferingWait, mBufferingWait - elapsed.ToSeconds(),
|
||||
(mQuickBuffering ? "(quick exit)" : ""));
|
||||
ScheduleStateMachine(USECS_PER_S);
|
||||
return NS_OK;
|
||||
}
|
||||
} else if (OutOfDecodedAudio() || OutOfDecodedVideo()) {
|
||||
MOZ_ASSERT(mReader->IsWaitForDataSupported(),
|
||||
"Don't yet have a strategy for non-heuristic + non-WaitForData");
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
MOZ_ASSERT_IF(OutOfDecodedAudio(), mAudioRequestStatus != RequestStatus::Idle);
|
||||
MOZ_ASSERT_IF(OutOfDecodedVideo(), mVideoRequestStatus != RequestStatus::Idle);
|
||||
DECODER_LOG("In buffering mode, waiting to be notified: outOfAudio: %d, "
|
||||
"mAudioStatus: %d, outOfVideo: %d, mVideoStatus: %d",
|
||||
OutOfDecodedAudio(), mAudioRequestStatus,
|
||||
OutOfDecodedVideo(), mVideoRequestStatus);
|
||||
// We will remain in the buffering state if we've not decoded enough
|
||||
// data to begin playback, or if we've not downloaded a reasonable
|
||||
// amount of data inside our buffering time.
|
||||
TimeDuration elapsed = now - mBufferingStart;
|
||||
bool isLiveStream = resource->GetLength() == -1;
|
||||
if ((isLiveStream || !mDecoder->CanPlayThrough()) &&
|
||||
elapsed < TimeDuration::FromSeconds(mBufferingWait * mPlaybackRate) &&
|
||||
(mQuickBuffering ? HasLowDecodedData(QUICK_BUFFERING_LOW_DATA_USECS)
|
||||
: HasLowUndecodedData(mBufferingWait * USECS_PER_S)) &&
|
||||
mDecoder->IsExpectingMoreData())
|
||||
{
|
||||
DECODER_LOG("Buffering: wait %ds, timeout in %.3lfs %s",
|
||||
mBufferingWait, mBufferingWait - elapsed.ToSeconds(),
|
||||
(mQuickBuffering ? "(quick exit)" : ""));
|
||||
ScheduleStateMachine(USECS_PER_S);
|
||||
return NS_OK;
|
||||
} else {
|
||||
DECODER_LOG("Changed state from BUFFERING to DECODING");
|
||||
DECODER_LOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds());
|
||||
StartDecoding();
|
||||
}
|
||||
|
||||
DECODER_LOG("Changed state from BUFFERING to DECODING");
|
||||
DECODER_LOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds());
|
||||
StartDecoding();
|
||||
|
||||
// Notify to allow blocked decoder thread to continue
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
UpdateReadyState();
|
||||
|
@ -2762,8 +2747,8 @@ MediaDecoderStateMachine::FlushDecoding()
|
|||
// These flags will be reset when the decoded data returned in OnAudioDecoded()
|
||||
// and OnVideoDecoded(). Because the decode tasks are flushed, these flags need
|
||||
// to be reset here.
|
||||
mAudioRequestStatus = RequestStatus::Idle;
|
||||
mVideoRequestStatus = RequestStatus::Idle;
|
||||
mAudioRequestPending = false;
|
||||
mVideoRequestPending = false;
|
||||
|
||||
// We must reset playback so that all references to frames queued
|
||||
// in the state machine are dropped, else subsequent calls to Shutdown()
|
||||
|
@ -2919,16 +2904,9 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
|||
// If we don't, switch to buffering mode.
|
||||
if (mState == DECODER_STATE_DECODING &&
|
||||
mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
|
||||
HasLowDecodedData(remainingTime + EXHAUSTED_DATA_MARGIN_USECS) &&
|
||||
mDecoder->IsExpectingMoreData()) {
|
||||
bool shouldBuffer;
|
||||
if (mReader->UseBufferingHeuristics()) {
|
||||
shouldBuffer = HasLowDecodedData(remainingTime + EXHAUSTED_DATA_MARGIN_USECS) &&
|
||||
(JustExitedQuickBuffering() || HasLowUndecodedData());
|
||||
} else {
|
||||
MOZ_ASSERT(mReader->IsWaitForDataSupported());
|
||||
shouldBuffer = OutOfDecodedAudio() || OutOfDecodedVideo();
|
||||
}
|
||||
if (shouldBuffer) {
|
||||
if (JustExitedQuickBuffering() || HasLowUndecodedData()) {
|
||||
if (currentFrame) {
|
||||
VideoQueue().PushFront(currentFrame);
|
||||
}
|
||||
|
|
|
@ -389,23 +389,6 @@ public:
|
|||
void OnSeekCompleted();
|
||||
void OnSeekFailed(nsresult aResult);
|
||||
|
||||
void OnWaitForDataResolved(MediaData::Type aType)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (RequestStatusRef(aType) == RequestStatus::Waiting) {
|
||||
RequestStatusRef(aType) = RequestStatus::Idle;
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
void OnWaitForDataRejected(WaitForDataRejectValue aRejection)
|
||||
{
|
||||
MOZ_ASSERT(aRejection.mReason == WaitForDataRejectValue::SHUTDOWN);
|
||||
if (RequestStatusRef(aRejection.mType) == RequestStatus::Waiting) {
|
||||
RequestStatusRef(aRejection.mType) = RequestStatus::Idle;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void AcquireMonitorAndInvokeDecodeError();
|
||||
|
||||
|
@ -479,23 +462,8 @@ protected:
|
|||
|
||||
// Returns true if we've got less than aAudioUsecs microseconds of decoded
|
||||
// and playable data. The decoder monitor must be held.
|
||||
//
|
||||
// May not be invoked when mReader->UseBufferingHeuristics() is false.
|
||||
bool HasLowDecodedData(int64_t aAudioUsecs);
|
||||
|
||||
bool OutOfDecodedAudio()
|
||||
{
|
||||
return IsAudioDecoding() && !AudioQueue().IsFinished() && AudioQueue().GetSize() == 0;
|
||||
}
|
||||
|
||||
bool OutOfDecodedVideo()
|
||||
{
|
||||
// In buffering mode, we keep the last already-played frame in the queue.
|
||||
int emptyVideoSize = mState == DECODER_STATE_BUFFERING ? 1 : 0;
|
||||
return IsVideoDecoding() && !VideoQueue().IsFinished() && VideoQueue().GetSize() <= emptyVideoSize;
|
||||
}
|
||||
|
||||
|
||||
// Returns true if we're running low on data which is not yet decoded.
|
||||
// The decoder monitor must be held.
|
||||
bool HasLowUndecodedData();
|
||||
|
@ -943,22 +911,11 @@ protected:
|
|||
bool mIsAudioPrerolling;
|
||||
bool mIsVideoPrerolling;
|
||||
|
||||
MOZ_BEGIN_NESTED_ENUM_CLASS(RequestStatus)
|
||||
Idle,
|
||||
Pending,
|
||||
Waiting
|
||||
MOZ_END_NESTED_ENUM_CLASS(RequestStatus)
|
||||
|
||||
// True when we have dispatched a task to the decode task queue to request
|
||||
// decoded audio/video, and/or we are waiting for the requested sample to be
|
||||
// returned by callback from the Reader.
|
||||
RequestStatus mAudioRequestStatus;
|
||||
RequestStatus mVideoRequestStatus;
|
||||
|
||||
RequestStatus& RequestStatusRef(MediaData::Type aType)
|
||||
{
|
||||
return aType == MediaData::AUDIO_DATA ? mAudioRequestStatus : mVideoRequestStatus;
|
||||
}
|
||||
bool mAudioRequestPending;
|
||||
bool mVideoRequestPending;
|
||||
|
||||
// True if we shouldn't play our audio (but still write it to any capturing
|
||||
// streams). When this is true, mStopAudioThread is always true and
|
||||
|
|
|
@ -61,6 +61,7 @@ public:
|
|||
: mCreationSite(aCreationSite)
|
||||
, mMutex("MediaPromise Mutex")
|
||||
{
|
||||
MOZ_COUNT_CTOR(MediaPromise);
|
||||
PROMISE_LOG("%s creating MediaPromise (%p)", mCreationSite, this);
|
||||
}
|
||||
|
||||
|
@ -98,10 +99,14 @@ protected:
|
|||
public:
|
||||
ResolveRunnable(ThenValueBase* aThenValue, ResolveValueType aResolveValue)
|
||||
: mThenValue(aThenValue)
|
||||
, mResolveValue(aResolveValue) {}
|
||||
, mResolveValue(aResolveValue)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ResolveRunnable);
|
||||
}
|
||||
|
||||
~ResolveRunnable()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ResolveRunnable);
|
||||
MOZ_ASSERT(!mThenValue);
|
||||
}
|
||||
|
||||
|
@ -125,10 +130,14 @@ protected:
|
|||
public:
|
||||
RejectRunnable(ThenValueBase* aThenValue, RejectValueType aRejectValue)
|
||||
: mThenValue(aThenValue)
|
||||
, mRejectValue(aRejectValue) {}
|
||||
, mRejectValue(aRejectValue)
|
||||
{
|
||||
MOZ_COUNT_CTOR(RejectRunnable);
|
||||
}
|
||||
|
||||
~RejectRunnable()
|
||||
{
|
||||
MOZ_COUNT_DTOR(RejectRunnable);
|
||||
MOZ_ASSERT(!mThenValue);
|
||||
}
|
||||
|
||||
|
@ -318,6 +327,7 @@ protected:
|
|||
|
||||
~MediaPromise()
|
||||
{
|
||||
MOZ_COUNT_DTOR(MediaPromise);
|
||||
PROMISE_LOG("MediaPromise::~MediaPromise [this=%p]", this);
|
||||
MOZ_ASSERT(!IsPending());
|
||||
MOZ_ASSERT(mThenValues.IsEmpty());
|
||||
|
|
|
@ -66,7 +66,8 @@ MediaSourceDecoder::Load(nsIStreamListener**, MediaDecoder*)
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
SetStateMachineParameters();
|
||||
return ScheduleStateMachineThread();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -345,9 +345,6 @@ MediaSourceReader::ContinueShutdown()
|
|||
MOZ_ASSERT(mAudioPromise.IsEmpty());
|
||||
MOZ_ASSERT(mVideoPromise.IsEmpty());
|
||||
|
||||
mAudioWaitPromise.RejectIfExists(WaitForDataRejectValue(MediaData::AUDIO_DATA, WaitForDataRejectValue::SHUTDOWN), __func__);
|
||||
mVideoWaitPromise.RejectIfExists(WaitForDataRejectValue(MediaData::VIDEO_DATA, WaitForDataRejectValue::SHUTDOWN), __func__);
|
||||
|
||||
MediaDecoderReader::Shutdown()->ChainTo(mMediaSourceShutdownPromise.Steal(), __func__);
|
||||
}
|
||||
|
||||
|
@ -394,15 +391,6 @@ MediaSourceReader::SelectReader(int64_t aTarget,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSourceReader::HaveData(int64_t aTarget, MediaData::Type aType)
|
||||
{
|
||||
TrackBuffer* trackBuffer = aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack;
|
||||
MOZ_ASSERT(trackBuffer);
|
||||
nsRefPtr<MediaDecoderReader> reader = SelectReader(aTarget, trackBuffer->Decoders());
|
||||
return !!reader;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSourceReader::SwitchAudioReader(int64_t aTarget)
|
||||
{
|
||||
|
@ -732,32 +720,6 @@ MediaSourceReader::GetBuffered(dom::TimeRanges* aBuffered)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDecoderReader::WaitForDataPromise>
|
||||
MediaSourceReader::WaitForData(MediaData::Type aType)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
nsRefPtr<WaitForDataPromise> p = WaitPromise(aType).Ensure(__func__);
|
||||
MaybeNotifyHaveData();
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::MaybeNotifyHaveData()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
bool haveAudio = false, haveVideo = false;
|
||||
if (!mAudioIsSeeking && mAudioTrack && HaveData(mLastAudioTime, MediaData::AUDIO_DATA)) {
|
||||
haveAudio = true;
|
||||
WaitPromise(MediaData::AUDIO_DATA).ResolveIfExists(MediaData::AUDIO_DATA, __func__);
|
||||
}
|
||||
if (!mVideoIsSeeking && mVideoTrack && HaveData(mLastVideoTime, MediaData::VIDEO_DATA)) {
|
||||
haveVideo = true;
|
||||
WaitPromise(MediaData::VIDEO_DATA).ResolveIfExists(MediaData::VIDEO_DATA, __func__);
|
||||
}
|
||||
MSE_DEBUG("MediaSourceReader(%p)::MaybeNotifyHaveData haveAudio=%d, haveVideo=%d", this,
|
||||
haveAudio, haveVideo);
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
|
||||
{
|
||||
|
|
|
@ -61,10 +61,6 @@ public:
|
|||
void OnSeekCompleted();
|
||||
void OnSeekFailed(nsresult aResult);
|
||||
|
||||
virtual bool IsWaitForDataSupported() MOZ_OVERRIDE { return true; }
|
||||
virtual nsRefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) MOZ_OVERRIDE;
|
||||
void MaybeNotifyHaveData();
|
||||
|
||||
bool HasVideo() MOZ_OVERRIDE
|
||||
{
|
||||
return mInfo.HasVideo();
|
||||
|
@ -82,11 +78,11 @@ public:
|
|||
// as chrome/blink and assumes that we always start at t=0.
|
||||
virtual int64_t ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio) MOZ_OVERRIDE { return 0; }
|
||||
|
||||
// Buffering heuristics don't make sense for MSE, because the arrival of data
|
||||
// is at least partly controlled by javascript, and javascript does not expect
|
||||
// us to sit on unplayed data just because it may not be enough to play
|
||||
// through.
|
||||
bool UseBufferingHeuristics() MOZ_OVERRIDE { return false; }
|
||||
// Buffering waits (in which we decline to present decoded frames because we
|
||||
// "don't have enough") don't really make sense for MSE. The delay is
|
||||
// essentially a streaming heuristic, but JS is supposed to take care of that
|
||||
// in the MSE world. Avoid injecting inexplicable delays.
|
||||
virtual uint32_t GetBufferingWait() { return 0; }
|
||||
|
||||
bool IsMediaSeekable() { return true; }
|
||||
|
||||
|
@ -136,7 +132,6 @@ private:
|
|||
// available in the range requested by aTarget.
|
||||
already_AddRefed<MediaDecoderReader> SelectReader(int64_t aTarget,
|
||||
const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders);
|
||||
bool HaveData(int64_t aTarget, MediaData::Type aType);
|
||||
|
||||
void AttemptSeek();
|
||||
void FinalizeSeek();
|
||||
|
@ -153,13 +148,6 @@ private:
|
|||
MediaPromiseHolder<AudioDataPromise> mAudioPromise;
|
||||
MediaPromiseHolder<VideoDataPromise> mVideoPromise;
|
||||
|
||||
MediaPromiseHolder<WaitForDataPromise> mAudioWaitPromise;
|
||||
MediaPromiseHolder<WaitForDataPromise> mVideoWaitPromise;
|
||||
MediaPromiseHolder<WaitForDataPromise>& WaitPromise(MediaData::Type aType)
|
||||
{
|
||||
return aType == MediaData::AUDIO_DATA ? mAudioWaitPromise : mVideoWaitPromise;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsRefPtr<CDMProxy> mCDMProxy;
|
||||
#endif
|
||||
|
|
|
@ -183,9 +183,9 @@ TrackBuffer::AppendData(const uint8_t* aData, uint32_t aLength)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Tell our reader that we have more data to ensure that playback starts if
|
||||
// required when data is appended.
|
||||
mParentDecoder->GetReader()->MaybeNotifyHaveData();
|
||||
// Schedule the state machine thread to ensure playback starts if required
|
||||
// when data is appended.
|
||||
mParentDecoder->ScheduleStateMachineThread();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -440,11 +440,6 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
|
|||
RemoveDecoder(aDecoder);
|
||||
return;
|
||||
}
|
||||
|
||||
// Tell our reader that we have more data to ensure that playback starts if
|
||||
// required when data is appended.
|
||||
mParentDecoder->GetReader()->MaybeNotifyHaveData();
|
||||
|
||||
MSE_DEBUG("TrackBuffer(%p): Reader %p activated", this, reader);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче