mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-26 12:20:56 +00:00
Bug 1224973 - Part 5: Implement suspend decoding for background video. r=cpearce,jwwang,jya
Implemented by short-circuiting calls to RequestVideoData in MDSM so no frames are decoded. Resuming playback when video moves to foreground by using the SeekTask/SeekJob/Seek in MDSM with result of GetMediaTime(). Special consideration is made to only seek the video part of Seek() to remove an audible glitch in the audio playback when the video becomes visible again. MozReview-Commit-ID: 7YFDTanslXu
This commit is contained in:
parent
26d0966736
commit
526fdd85f6
@ -132,17 +132,18 @@ size_t MediaDecoderReader::SizeOfAudioQueueInFrames()
|
||||
return mAudioQueue.GetSize();
|
||||
}
|
||||
|
||||
nsresult MediaDecoderReader::ResetDecode()
|
||||
nsresult MediaDecoderReader::ResetDecode(TargetQueues aQueues /*= AUDIO_VIDEO*/)
|
||||
{
|
||||
VideoQueue().Reset();
|
||||
AudioQueue().Reset();
|
||||
|
||||
mAudioDiscontinuity = true;
|
||||
mVideoDiscontinuity = true;
|
||||
|
||||
mBaseAudioPromise.RejectIfExists(CANCELED, __func__);
|
||||
mBaseVideoPromise.RejectIfExists(CANCELED, __func__);
|
||||
|
||||
if (aQueues == AUDIO_VIDEO) {
|
||||
AudioQueue().Reset();
|
||||
mAudioDiscontinuity = true;
|
||||
mBaseAudioPromise.RejectIfExists(CANCELED, __func__);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,11 @@ public:
|
||||
CANCELED
|
||||
};
|
||||
|
||||
enum TargetQueues {
|
||||
VIDEO_ONLY,
|
||||
AUDIO_VIDEO
|
||||
};
|
||||
|
||||
using MetadataPromise =
|
||||
MozPromise<RefPtr<MetadataHolder>, ReadMetadataFailureReason, IsExclusive>;
|
||||
using MediaDataPromise =
|
||||
@ -125,7 +130,7 @@ public:
|
||||
// The first samples of every stream produced after a ResetDecode() call
|
||||
// *must* be marked as "discontinuities". If it's not, seeking work won't
|
||||
// properly!
|
||||
virtual nsresult ResetDecode();
|
||||
virtual nsresult ResetDecode(TargetQueues aQueues = AUDIO_VIDEO);
|
||||
|
||||
// Requests one audio sample from the reader.
|
||||
//
|
||||
|
@ -330,7 +330,7 @@ MediaDecoderReaderWrapper::SetIdle()
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderReaderWrapper::ResetDecode()
|
||||
MediaDecoderReaderWrapper::ResetDecode(TargetQueues aQueues)
|
||||
{
|
||||
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
||||
|
||||
@ -338,7 +338,9 @@ MediaDecoderReaderWrapper::ResetDecode()
|
||||
mVideoDataRequest.DisconnectIfExists();
|
||||
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NewRunnableMethod(mReader, &MediaDecoderReader::ResetDecode);
|
||||
NewRunnableMethod<TargetQueues>(mReader,
|
||||
&MediaDecoderReader::ResetDecode,
|
||||
aQueues);
|
||||
mReader->OwnerThread()->Dispatch(r.forget());
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ class MediaDecoderReaderWrapper {
|
||||
typedef MediaDecoderReader::SeekPromise SeekPromise;
|
||||
typedef MediaDecoderReader::WaitForDataPromise WaitForDataPromise;
|
||||
typedef MediaDecoderReader::BufferedUpdatePromise BufferedUpdatePromise;
|
||||
typedef MediaDecoderReader::TargetQueues TargetQueues;
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReaderWrapper);
|
||||
|
||||
/*
|
||||
@ -255,7 +256,7 @@ public:
|
||||
|
||||
void ReleaseMediaResources();
|
||||
void SetIdle();
|
||||
void ResetDecode();
|
||||
void ResetDecode(TargetQueues aQueues);
|
||||
|
||||
nsresult Init() { return mReader->Init(); }
|
||||
bool IsWaitForDataSupported() const { return mReader->IsWaitForDataSupported(); }
|
||||
|
@ -476,6 +476,10 @@ bool MediaDecoderStateMachine::HaveEnoughDecodedVideo()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
if (IsVideoDecodeSuspended()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (VideoQueue().GetSize() == 0) {
|
||||
return false;
|
||||
}
|
||||
@ -1333,12 +1337,81 @@ void MediaDecoderStateMachine::PlayStateChanged()
|
||||
|
||||
void MediaDecoderStateMachine::VisibilityChanged()
|
||||
{
|
||||
DECODER_LOG("VisibilityChanged: is visible = %c", mIsVisible ? 'T' : 'F');
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
DECODER_LOG("VisibilityChanged: is visible = %d", mIsVisible.Ref());
|
||||
|
||||
// Not suspending background videos so there's nothing to do.
|
||||
if (!sSuspendBackgroundVideos) {
|
||||
// Not suspending background videos so there's nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasVideo()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If not transitioning to visible and not playing then there's
|
||||
// nothing to do.
|
||||
if (!mIsVisible || mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If an existing seek is in flight don't bother creating a new one to catch
|
||||
// up.
|
||||
if (mSeekTask || mQueuedSeek.Exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Start video-only seek to the current time...
|
||||
InitiateVideoDecodeRecoverySeek();
|
||||
}
|
||||
|
||||
// InitiateVideoDecodeRecoverySeek is responsible for setting up a video-only
|
||||
// seek using the seek task. When suspension of decoding for videos that are in
|
||||
// background tabs (ie. invisible) is enabled, the audio keeps playing and when
|
||||
// switching back to decoding video, it is highly desirable to not cause the
|
||||
// audio to pause as the video is seeked else there be a noticeable audio glitch
|
||||
// as the tab becomes visible.
|
||||
void MediaDecoderStateMachine::InitiateVideoDecodeRecoverySeek()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
SeekJob seekJob;
|
||||
seekJob.mTarget = SeekTarget(GetMediaTime(),
|
||||
SeekTarget::Type::AccurateVideoOnly,
|
||||
MediaDecoderEventVisibility::Suppressed);
|
||||
|
||||
SetState(DECODER_STATE_SEEKING);
|
||||
|
||||
// Discard the existing seek task.
|
||||
DiscardSeekTaskIfExist();
|
||||
|
||||
mSeekTaskRequest.DisconnectIfExists();
|
||||
|
||||
// SeekTask will register its callbacks to MediaDecoderReaderWrapper.
|
||||
CancelMediaDecoderReaderWrapperCallback();
|
||||
|
||||
// Create a new SeekTask instance for the incoming seek task.
|
||||
mSeekTask = SeekTask::CreateSeekTask(mDecoderID, OwnerThread(),
|
||||
mReader.get(), Move(seekJob),
|
||||
mInfo, Duration(), GetMediaTime());
|
||||
|
||||
mOnSeekingStart.Notify(MediaDecoderEventVisibility::Suppressed);
|
||||
|
||||
// Reset our state machine and decoding pipeline before seeking.
|
||||
if (mSeekTask->NeedToResetMDSM()) {
|
||||
Reset(MediaDecoderReader::VIDEO_ONLY);
|
||||
}
|
||||
|
||||
// Do the seek.
|
||||
mSeekTaskRequest.Begin(
|
||||
mSeekTask->Seek(Duration())->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnSeekTaskResolved,
|
||||
&MediaDecoderStateMachine::OnSeekTaskRejected));
|
||||
// Nobody is listening to this as OnSeekTaskResolved handles what is
|
||||
// required but the promise needs to exist or SeekJob::Exists() will
|
||||
// assert.
|
||||
RefPtr<MediaDecoder::SeekPromise> unused =
|
||||
mSeekTask->GetSeekJob().mPromise.Ensure(__func__);
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::BufferedRangeUpdated()
|
||||
@ -1688,6 +1761,13 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (IsVideoDecodeSuspended() && !IsDecodingFirstFrame()) {
|
||||
// The element is invisible and background videos should be suspended.
|
||||
// If the first frame has already been decoded, don't request anymore video
|
||||
// frames.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!IsVideoDecoding() || mReader->IsRequestingVidoeData() ||
|
||||
mVideoWaitRequest.Exists()) {
|
||||
return NS_OK;
|
||||
@ -2269,7 +2349,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::Reset()
|
||||
MediaDecoderStateMachine::Reset(MediaDecoderReader::TargetQueues aQueues /*= AUDIO_VIDEO*/)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
DECODER_LOG("MediaDecoderStateMachine::Reset");
|
||||
@ -2282,26 +2362,29 @@ MediaDecoderStateMachine::Reset()
|
||||
mState == DECODER_STATE_SEEKING ||
|
||||
mState == DECODER_STATE_DORMANT);
|
||||
|
||||
// Stop the audio thread. Otherwise, MediaSink might be accessing AudioQueue
|
||||
// outside of the decoder monitor while we are clearing the queue and causes
|
||||
// crash for no samples to be popped.
|
||||
StopMediaSink();
|
||||
|
||||
mDecodedVideoEndTime = 0;
|
||||
mDecodedAudioEndTime = 0;
|
||||
mAudioCompleted = false;
|
||||
mVideoCompleted = false;
|
||||
AudioQueue().Reset();
|
||||
VideoQueue().Reset();
|
||||
mVideoWaitRequest.DisconnectIfExists();
|
||||
|
||||
if (aQueues == MediaDecoderReader::AUDIO_VIDEO) {
|
||||
// Stop the audio thread. Otherwise, MediaSink might be accessing AudioQueue
|
||||
// outside of the decoder monitor while we are clearing the queue and causes
|
||||
// crash for no samples to be popped.
|
||||
StopMediaSink();
|
||||
mDecodedAudioEndTime = 0;
|
||||
mAudioCompleted = false;
|
||||
AudioQueue().Reset();
|
||||
mAudioWaitRequest.DisconnectIfExists();
|
||||
}
|
||||
|
||||
mMetadataRequest.DisconnectIfExists();
|
||||
mAudioWaitRequest.DisconnectIfExists();
|
||||
mVideoWaitRequest.DisconnectIfExists();
|
||||
mSeekTaskRequest.DisconnectIfExists();
|
||||
|
||||
mPlaybackOffset = 0;
|
||||
|
||||
mReader->ResetDecode();
|
||||
mReader->ResetDecode(aQueues);
|
||||
}
|
||||
|
||||
int64_t
|
||||
@ -2501,6 +2584,12 @@ bool MediaDecoderStateMachine::IsStateMachineScheduled() const
|
||||
return mDispatchedStateMachine || mDelayedScheduler.IsScheduled();
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::IsVideoDecodeSuspended() const
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
return sSuspendBackgroundVideos && !mIsVisible;
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::LogicalPlaybackRateChanged()
|
||||
{
|
||||
|
@ -368,7 +368,7 @@ private:
|
||||
|
||||
// Resets all state related to decoding and playback, emptying all buffers
|
||||
// and aborting all pending operations on the decode task queue.
|
||||
void Reset();
|
||||
void Reset(MediaDecoderReader::TargetQueues aQueues = MediaDecoderReader::AUDIO_VIDEO);
|
||||
|
||||
protected:
|
||||
virtual ~MediaDecoderStateMachine();
|
||||
@ -509,10 +509,15 @@ protected:
|
||||
|
||||
void EnqueueFirstFrameLoadedEvent();
|
||||
|
||||
// Clears any previous seeking state and initiates a new see on the decoder.
|
||||
// Clears any previous seeking state and initiates a new seek on the decoder.
|
||||
// The decoder monitor must be held.
|
||||
void InitiateSeek(SeekJob aSeekJob);
|
||||
|
||||
// Clears any previous seeking state and initiates a video-only seek on the
|
||||
// decoder to catch up the video to the current audio position, when recovering
|
||||
// from video decoding being suspended in background.
|
||||
void InitiateVideoDecodeRecoverySeek();
|
||||
|
||||
nsresult DispatchAudioDecodeTaskIfNeeded();
|
||||
|
||||
// Ensures a task to decode audio has been dispatched to the decode task queue.
|
||||
@ -595,6 +600,10 @@ protected:
|
||||
// case as it may not be needed again.
|
||||
bool IsPausedAndDecoderWaiting();
|
||||
|
||||
// Returns true if the video decoding is suspended because the element is not
|
||||
// visible
|
||||
bool IsVideoDecodeSuspended() const;
|
||||
|
||||
// These return true if the respective stream's decode has not yet reached
|
||||
// the end of stream.
|
||||
bool IsAudioDecoding();
|
||||
@ -756,7 +765,7 @@ private:
|
||||
// At the start of decoding we want to "preroll" the decode until we've
|
||||
// got a few frames decoded before we consider whether decode is falling
|
||||
// behind. Otherwise our "we're falling behind" logic will trigger
|
||||
// unneccessarily if we start playing as soon as the first sample is
|
||||
// unnecessarily if we start playing as soon as the first sample is
|
||||
// decoded. These two fields store how many video frames and audio
|
||||
// samples we must consume before are considered to be finished prerolling.
|
||||
uint32_t AudioPrerollUsecs() const
|
||||
@ -781,7 +790,8 @@ private:
|
||||
bool DonePrerollingVideo()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
return !IsVideoDecoding() ||
|
||||
return !mIsVisible ||
|
||||
!IsVideoDecoding() ||
|
||||
static_cast<uint32_t>(VideoQueue().GetSize()) >=
|
||||
VideoPrerollFrames() * mPlaybackRate + 1;
|
||||
}
|
||||
@ -862,7 +872,7 @@ private:
|
||||
|
||||
// True if we've dispatched an event to the decode task queue to call
|
||||
// DecodeThreadRun(). We use this flag to prevent us from dispatching
|
||||
// unneccessary runnables, since the decode thread runs in a loop.
|
||||
// unnecessary runnables, since the decode thread runs in a loop.
|
||||
bool mDispatchedEventToDecode;
|
||||
|
||||
// If this is true while we're in buffering mode, we can exit early,
|
||||
@ -904,7 +914,7 @@ private:
|
||||
MozPromiseRequestHolder<MediaDecoderReader::BufferedUpdatePromise> mBufferedUpdateRequest;
|
||||
|
||||
// True if we need to call FinishDecodeFirstFrame() upon frame decoding
|
||||
// successeeding.
|
||||
// succeeding.
|
||||
bool mDecodingFirstFrame;
|
||||
|
||||
// True if we are back from DECODER_STATE_DORMANT state and
|
||||
|
@ -1283,7 +1283,7 @@ MediaFormatReader::WaitForData(MediaData::Type aType)
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaFormatReader::ResetDecode()
|
||||
MediaFormatReader::ResetDecode(TargetQueues aQueues)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
LOGV("");
|
||||
@ -1306,13 +1306,14 @@ MediaFormatReader::ResetDecode()
|
||||
mVideo.RejectPromise(CANCELED, __func__);
|
||||
}
|
||||
}
|
||||
if (HasAudio()) {
|
||||
|
||||
if (HasAudio() && aQueues == AUDIO_VIDEO) {
|
||||
Reset(TrackInfo::kAudioTrack);
|
||||
if (mAudio.HasPromise()) {
|
||||
mAudio.RejectPromise(CANCELED, __func__);
|
||||
}
|
||||
}
|
||||
return MediaDecoderReader::ResetDecode();
|
||||
return MediaDecoderReader::ResetDecode(aQueues);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1608,9 +1609,10 @@ MediaFormatReader::OnVideoSeekCompleted(media::TimeUnit aTime)
|
||||
LOGV("Video seeked to %lld", aTime.ToMicroseconds());
|
||||
mVideo.mSeekRequest.Complete();
|
||||
|
||||
if (HasAudio()) {
|
||||
MOZ_ASSERT(mPendingSeekTime.isSome() && mOriginalSeekTarget.isSome());
|
||||
if (mOriginalSeekTarget.ref().IsFast()) {
|
||||
MOZ_ASSERT(mOriginalSeekTarget.isSome());
|
||||
if (HasAudio() && !mOriginalSeekTarget->IsVideoOnly()) {
|
||||
MOZ_ASSERT(mPendingSeekTime.isSome());
|
||||
if (mOriginalSeekTarget->IsFast()) {
|
||||
// We are performing a fast seek. We need to seek audio to where the
|
||||
// video seeked to, to ensure proper A/V sync once playback resume.
|
||||
mPendingSeekTime = Some(aTime);
|
||||
|
@ -62,7 +62,7 @@ public:
|
||||
// For Media Resource Management
|
||||
void ReleaseMediaResources() override;
|
||||
|
||||
nsresult ResetDecode() override;
|
||||
nsresult ResetDecode(TargetQueues aQueues) override;
|
||||
|
||||
RefPtr<ShutdownPromise> Shutdown() override;
|
||||
|
||||
@ -322,7 +322,7 @@ private:
|
||||
uint64_t mNumSamplesOutputTotalSinceTelemetry;
|
||||
uint64_t mNumSamplesSkippedTotalSinceTelemetry;
|
||||
|
||||
// These get overriden in the templated concrete class.
|
||||
// These get overridden in the templated concrete class.
|
||||
// Indicate if we have a pending promise for decoded frame.
|
||||
// Rejecting the promise will stop the reader from decoding ahead.
|
||||
virtual bool HasPromise() const = 0;
|
||||
|
@ -33,7 +33,7 @@ SeekJob& SeekJob::operator=(SeekJob&& aOther)
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool SeekJob::Exists()
|
||||
bool SeekJob::Exists() const
|
||||
{
|
||||
MOZ_ASSERT(mTarget.IsValid() == !mPromise.IsEmpty());
|
||||
return mTarget.IsValid();
|
||||
|
@ -21,7 +21,7 @@ struct SeekJob {
|
||||
|
||||
SeekJob& operator=(SeekJob&& aOther);
|
||||
|
||||
bool Exists();
|
||||
bool Exists() const;
|
||||
|
||||
void Resolve(bool aAtEnd, const char* aCallSite);
|
||||
|
||||
|
@ -17,12 +17,14 @@ enum class MediaDecoderEventVisibility : int8_t {
|
||||
};
|
||||
|
||||
// Stores the seek target; the time to seek to, and whether an Accurate,
|
||||
// or "Fast" (nearest keyframe) seek was requested.
|
||||
// "Fast" (nearest keyframe), or "Video Only" (no audio seek) seek was
|
||||
// requested.
|
||||
struct SeekTarget {
|
||||
enum Type {
|
||||
Invalid,
|
||||
PrevSyncPoint,
|
||||
Accurate
|
||||
Accurate,
|
||||
AccurateVideoOnly,
|
||||
};
|
||||
SeekTarget()
|
||||
: mEventVisibility(MediaDecoderEventVisibility::Observable)
|
||||
@ -78,6 +80,9 @@ struct SeekTarget {
|
||||
bool IsAccurate() const {
|
||||
return mType == SeekTarget::Type::Accurate;
|
||||
}
|
||||
bool IsVideoOnly() const {
|
||||
return mType == SeekTarget::Type::AccurateVideoOnly;
|
||||
}
|
||||
|
||||
MediaDecoderEventVisibility mEventVisibility;
|
||||
|
||||
@ -85,7 +90,7 @@ private:
|
||||
// Seek target time.
|
||||
media::TimeUnit mTime;
|
||||
// Whether we should seek "Fast", or "Accurate".
|
||||
// "Fast" seeks to the seek point preceeding mTime, whereas
|
||||
// "Fast" seeks to the seek point preceding mTime, whereas
|
||||
// "Accurate" seeks as close as possible to mTime.
|
||||
Type mType;
|
||||
};
|
||||
|
@ -177,7 +177,7 @@ SeekTask::GetSeekJob()
|
||||
}
|
||||
|
||||
bool
|
||||
SeekTask::Exists()
|
||||
SeekTask::Exists() const
|
||||
{
|
||||
return mSeekJob.Exists();
|
||||
}
|
||||
@ -422,6 +422,7 @@ SeekTask::IsAudioSeekComplete()
|
||||
mSeekJob.Exists(), mDropAudioUntilNextDiscontinuity, mIsAudioQueueFinished, !!mSeekedAudioData);
|
||||
return
|
||||
!HasAudio() ||
|
||||
mSeekJob.mTarget.IsVideoOnly() ||
|
||||
(Exists() && !mDropAudioUntilNextDiscontinuity &&
|
||||
(mIsAudioQueueFinished || mSeekedAudioData));
|
||||
}
|
||||
@ -478,8 +479,10 @@ SeekTask::OnSeekResolved(media::TimeUnit)
|
||||
mSeekRequest.Complete();
|
||||
// We must decode the first samples of active streams, so we can determine
|
||||
// the new stream time. So dispatch tasks to do that.
|
||||
EnsureAudioDecodeTaskQueued();
|
||||
EnsureVideoDecodeTaskQueued();
|
||||
if (!mSeekJob.mTarget.IsVideoOnly()) {
|
||||
EnsureAudioDecodeTaskQueued();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -63,7 +63,7 @@ public:
|
||||
|
||||
SeekJob& GetSeekJob();
|
||||
|
||||
bool Exists();
|
||||
bool Exists() const;
|
||||
|
||||
protected:
|
||||
SeekTask(const void* aDecoderID,
|
||||
|
@ -94,7 +94,7 @@ nsresult AndroidMediaReader::ReadMetadata(MediaInfo* aInfo,
|
||||
RefPtr<ShutdownPromise>
|
||||
AndroidMediaReader::Shutdown()
|
||||
{
|
||||
ResetDecode();
|
||||
ResetDecode(AUDIO_VIDEO);
|
||||
if (mPlugin) {
|
||||
GetAndroidMediaPluginHost()->DestroyDecoder(mPlugin);
|
||||
mPlugin = nullptr;
|
||||
@ -104,14 +104,14 @@ AndroidMediaReader::Shutdown()
|
||||
}
|
||||
|
||||
// Resets all state related to decoding, emptying all buffers etc.
|
||||
nsresult AndroidMediaReader::ResetDecode()
|
||||
nsresult AndroidMediaReader::ResetDecode(TargetQueues aQueues)
|
||||
{
|
||||
if (mLastVideoFrame) {
|
||||
mLastVideoFrame = nullptr;
|
||||
}
|
||||
mSeekRequest.DisconnectIfExists();
|
||||
mSeekPromise.RejectIfExists(NS_OK, __func__);
|
||||
return MediaDecoderReader::ResetDecode();
|
||||
return MediaDecoderReader::ResetDecode(aQueues);
|
||||
}
|
||||
|
||||
bool AndroidMediaReader::DecodeVideoFrame(bool &aKeyframeSkip,
|
||||
|
@ -42,7 +42,7 @@ public:
|
||||
AndroidMediaReader(AbstractMediaDecoder* aDecoder,
|
||||
const nsACString& aContentType);
|
||||
|
||||
nsresult ResetDecode() override;
|
||||
nsresult ResetDecode(TargetQueues aQueues) override;
|
||||
|
||||
bool DecodeAudioData() override;
|
||||
bool DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) override;
|
||||
|
@ -169,17 +169,17 @@ nsresult OggReader::Init() {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult OggReader::ResetDecode()
|
||||
nsresult OggReader::ResetDecode(TargetQueues aQueues)
|
||||
{
|
||||
return ResetDecode(false);
|
||||
return ResetDecode(false, aQueues);
|
||||
}
|
||||
|
||||
nsresult OggReader::ResetDecode(bool start)
|
||||
nsresult OggReader::ResetDecode(bool start, TargetQueues aQueues)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
nsresult res = NS_OK;
|
||||
|
||||
if (NS_FAILED(MediaDecoderReader::ResetDecode())) {
|
||||
if (NS_FAILED(MediaDecoderReader::ResetDecode(aQueues))) {
|
||||
res = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ protected:
|
||||
|
||||
public:
|
||||
nsresult Init() override;
|
||||
nsresult ResetDecode() override;
|
||||
nsresult ResetDecode(TargetQueues aQueues = AUDIO_VIDEO) override;
|
||||
bool DecodeAudioData() override;
|
||||
|
||||
// If the Theora granulepos has not been captured, it may read several packets
|
||||
@ -86,7 +86,7 @@ private:
|
||||
|
||||
// Specialized Reset() method to signal if the seek is
|
||||
// to the start of the stream.
|
||||
nsresult ResetDecode(bool start);
|
||||
nsresult ResetDecode(bool start, TargetQueues aQueues = AUDIO_VIDEO);
|
||||
|
||||
nsresult SeekInternal(int64_t aTime, int64_t aEndTime);
|
||||
|
||||
@ -94,7 +94,7 @@ private:
|
||||
return mSkeletonState != 0 && mSkeletonState->mActive;
|
||||
}
|
||||
|
||||
// Seeks to the keyframe preceeding the target time using available
|
||||
// Seeks to the keyframe preceding the target time using available
|
||||
// keyframe indexes.
|
||||
enum IndexedSeekResult {
|
||||
SEEK_OK, // Success.
|
||||
|
@ -27,10 +27,10 @@ RawReader::~RawReader()
|
||||
MOZ_COUNT_DTOR(RawReader);
|
||||
}
|
||||
|
||||
nsresult RawReader::ResetDecode()
|
||||
nsresult RawReader::ResetDecode(TargetQueues aQueues)
|
||||
{
|
||||
mCurrentFrame = 0;
|
||||
return MediaDecoderReader::ResetDecode();
|
||||
return MediaDecoderReader::ResetDecode(aQueues);
|
||||
}
|
||||
|
||||
nsresult RawReader::ReadMetadata(MediaInfo* aInfo,
|
||||
|
@ -20,7 +20,7 @@ protected:
|
||||
~RawReader();
|
||||
|
||||
public:
|
||||
nsresult ResetDecode() override;
|
||||
nsresult ResetDecode(TargetQueues aQueues) override;
|
||||
bool DecodeAudioData() override;
|
||||
|
||||
bool DecodeVideoFrame(bool &aKeyframeSkip,
|
||||
|
@ -785,7 +785,7 @@ public:
|
||||
// Provide a Monitor that should always be held when accessing this instance.
|
||||
void SetMonitor(Monitor* aMonitor) { mMonitor = aMonitor; }
|
||||
|
||||
bool IsEmpty()
|
||||
bool IsEmpty() const
|
||||
{
|
||||
if (mMonitor) {
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
|
Loading…
x
Reference in New Issue
Block a user