From 13232f716c28d8ba97ecaea41f46ca790bb87592 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Wed, 26 Aug 2020 14:25:05 +0000 Subject: [PATCH] Bug 1592539 - Move the FirstFrameListener to VideoOutput.h. r=jib This allows the FirstFrameListener to be instantiated outside of HTMLMediaElement. A future patch brings in a subclass in HTMLVideoElement. This also renames FirstFrameListener to FirstFrameVideoOutput since that better denotes what it is. Differential Revision: https://phabricator.services.mozilla.com/D87135 --- dom/html/HTMLMediaElement.cpp | 100 ++++++++-------------------------- dom/html/HTMLMediaElement.h | 1 - dom/media/VideoOutput.h | 57 +++++++++++++++++++ 3 files changed, 80 insertions(+), 78 deletions(-) diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 319c6fe3b8f8..910ee5be8ea8 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -759,63 +759,6 @@ class HTMLMediaElement::MediaStreamTrackListener const WeakPtr mElement; }; -/** - * This listener observes the first video frame to arrive with a non-empty size, - * and renders it to its VideoFrameContainer. - */ -class HTMLMediaElement::FirstFrameListener : public VideoOutput { - public: - FirstFrameListener(VideoFrameContainer* aContainer, - AbstractThread* aMainThread) - : VideoOutput(aContainer, aMainThread) { - MOZ_ASSERT(NS_IsMainThread()); - } - - // NB that this overrides VideoOutput::NotifyRealtimeTrackData, so we can - // filter out all frames but the first one with a real size. This allows us to - // later re-use the logic in VideoOutput for rendering that frame. - void NotifyRealtimeTrackData(MediaTrackGraph* aGraph, TrackTime aTrackOffset, - const MediaSegment& aMedia) override { - MOZ_ASSERT(aMedia.GetType() == MediaSegment::VIDEO); - - if (mInitialSizeFound) { - return; - } - - const VideoSegment& video = static_cast(aMedia); - for (VideoSegment::ConstChunkIterator c(video); !c.IsEnded(); c.Next()) { - if (c->mFrame.GetIntrinsicSize() != gfx::IntSize(0, 0)) { - mInitialSizeFound = true; - - mMainThread->Dispatch(NS_NewRunnableFunction( - "HTMLMediaElement::FirstFrameListener::FirstFrameRenderedSetter", - [self = RefPtr(this), this] { - mFirstFrameRendered = true; - })); - - // Pick the first frame and run it through the rendering code. - VideoSegment segment; - segment.AppendFrame(do_AddRef(c->mFrame.GetImage()), - c->mFrame.GetIntrinsicSize(), - c->mFrame.GetPrincipalHandle(), - c->mFrame.GetForceBlack(), c->mTimeStamp); - VideoOutput::NotifyRealtimeTrackData(aGraph, aTrackOffset, segment); - return; - } - } - } - - // Main thread only. - Watchable mFirstFrameRendered = { - false, "HTMLMediaElement::FirstFrameListener::mFirstFrameRendered"}; - - private: - // Whether a frame with a concrete size has been received. May only be - // accessed on the MTG's appending thread. (this is a direct listener so we - // get called by whoever is producing this track's data) - bool mInitialSizeFound = false; -}; - /** * Helper class that manages audio and video outputs for all enabled tracks in a * media element. It also manages calculating the current time when playing a @@ -832,11 +775,12 @@ class HTMLMediaElement::MediaStreamRenderer : mVideoContainer(aVideoContainer), mAudioOutputKey(aAudioOutputKey), mWatchManager(this, aMainThread), - mFirstFrameListener(aVideoContainer ? MakeAndAddRef( - aVideoContainer, aMainThread) - : nullptr) { - if (mFirstFrameListener) { - mWatchManager.Watch(mFirstFrameListener->mFirstFrameRendered, + mFirstFrameVideoOutput(aVideoContainer + ? MakeAndAddRef( + aVideoContainer, aMainThread) + : nullptr) { + if (mFirstFrameVideoOutput) { + mWatchManager.Watch(mFirstFrameVideoOutput->mFirstFrameRendered, &MediaStreamRenderer::SetFirstFrameRendered); } } @@ -851,7 +795,7 @@ class HTMLMediaElement::MediaStreamRenderer RemoveTrack(mVideoTrack->AsVideoStreamTrack()); } mWatchManager.Shutdown(); - mFirstFrameListener = nullptr; + mFirstFrameVideoOutput = nullptr; } void UpdateGraphTime() { @@ -860,15 +804,16 @@ class HTMLMediaElement::MediaStreamRenderer } void SetFirstFrameRendered() { - if (!mFirstFrameListener) { + if (!mFirstFrameVideoOutput) { return; } if (mVideoTrack) { - mVideoTrack->AsVideoStreamTrack()->RemoveVideoOutput(mFirstFrameListener); + mVideoTrack->AsVideoStreamTrack()->RemoveVideoOutput( + mFirstFrameVideoOutput); } - mWatchManager.Unwatch(mFirstFrameListener->mFirstFrameRendered, + mWatchManager.Unwatch(mFirstFrameVideoOutput->mFirstFrameRendered, &MediaStreamRenderer::SetFirstFrameRendered); - mFirstFrameListener = nullptr; + mFirstFrameVideoOutput = nullptr; } void SetProgressingCurrentTime(bool aProgress) { @@ -913,9 +858,9 @@ class HTMLMediaElement::MediaStreamRenderer } if (mVideoTrack) { - if (mFirstFrameListener) { + if (mFirstFrameVideoOutput) { mVideoTrack->AsVideoStreamTrack()->RemoveVideoOutput( - mFirstFrameListener); + mFirstFrameVideoOutput); } mVideoTrack->AsVideoStreamTrack()->AddVideoOutput(mVideoContainer); } @@ -940,8 +885,9 @@ class HTMLMediaElement::MediaStreamRenderer if (mVideoTrack) { mVideoTrack->AsVideoStreamTrack()->RemoveVideoOutput(mVideoContainer); - if (mFirstFrameListener) { - mVideoTrack->AsVideoStreamTrack()->AddVideoOutput(mFirstFrameListener); + if (mFirstFrameVideoOutput) { + mVideoTrack->AsVideoStreamTrack()->AddVideoOutput( + mFirstFrameVideoOutput); } } } @@ -1016,8 +962,8 @@ class HTMLMediaElement::MediaStreamRenderer EnsureGraphTimeDummy(); if (mRendering) { aTrack->AddVideoOutput(mVideoContainer); - } else if (mFirstFrameListener) { - aTrack->AddVideoOutput(mFirstFrameListener); + } else if (mFirstFrameVideoOutput) { + aTrack->AddVideoOutput(mFirstFrameVideoOutput); } } @@ -1035,8 +981,8 @@ class HTMLMediaElement::MediaStreamRenderer } if (mRendering) { aTrack->RemoveVideoOutput(mVideoContainer); - } else if (mFirstFrameListener) { - aTrack->RemoveVideoOutput(mFirstFrameListener); + } else if (mFirstFrameVideoOutput) { + aTrack->RemoveVideoOutput(mFirstFrameVideoOutput); } mVideoTrack = nullptr; } @@ -1122,10 +1068,10 @@ class HTMLMediaElement::MediaStreamRenderer // Currently selected (and rendered) video track. WeakPtr mVideoTrack; - // Holds a reference to the first-frame-getting track listener attached to + // Holds a reference to the first-frame-getting video output attached to // mVideoTrack. Set by the constructor, unset when the media element tells us // it has rendered the first frame. - RefPtr mFirstFrameListener; + RefPtr mFirstFrameVideoOutput; }; class HTMLMediaElement::MediaElementTrackSource diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h index 3e46c5746b17..d85b6ecaaec0 100644 --- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -766,7 +766,6 @@ class HTMLMediaElement : public nsGenericHTMLElement, class MediaLoadListener; class MediaStreamRenderer; class MediaStreamTrackListener; - class FirstFrameListener; class ShutdownObserver; class MediaControlKeyListener; diff --git a/dom/media/VideoOutput.h b/dom/media/VideoOutput.h index d8ec23b32ec8..41d9dcbe65ca 100644 --- a/dom/media/VideoOutput.h +++ b/dom/media/VideoOutput.h @@ -225,6 +225,63 @@ class VideoOutput : public DirectMediaTrackListener { layers::ImageContainer::AllocateProducerID(); }; +/** + * This listener observes the first video frame to arrive with a non-empty size, + * and renders it to its VideoFrameContainer. + */ +class FirstFrameVideoOutput : public VideoOutput { + public: + FirstFrameVideoOutput(VideoFrameContainer* aContainer, + AbstractThread* aMainThread) + : VideoOutput(aContainer, aMainThread) { + MOZ_ASSERT(NS_IsMainThread()); + } + + // NB that this overrides VideoOutput::NotifyRealtimeTrackData, so we can + // filter out all frames but the first one with a real size. This allows us to + // later re-use the logic in VideoOutput for rendering that frame. + void NotifyRealtimeTrackData(MediaTrackGraph* aGraph, TrackTime aTrackOffset, + const MediaSegment& aMedia) override { + MOZ_ASSERT(aMedia.GetType() == MediaSegment::VIDEO); + + if (mInitialSizeFound) { + return; + } + + const VideoSegment& video = static_cast(aMedia); + for (VideoSegment::ConstChunkIterator c(video); !c.IsEnded(); c.Next()) { + if (c->mFrame.GetIntrinsicSize() != gfx::IntSize(0, 0)) { + mInitialSizeFound = true; + + mMainThread->Dispatch(NS_NewRunnableFunction( + "FirstFrameVideoOutput::FirstFrameRenderedSetter", + [self = RefPtr(this)] { + self->mFirstFrameRendered = true; + })); + + // Pick the first frame and run it through the rendering code. + VideoSegment segment; + segment.AppendFrame(do_AddRef(c->mFrame.GetImage()), + c->mFrame.GetIntrinsicSize(), + c->mFrame.GetPrincipalHandle(), + c->mFrame.GetForceBlack(), c->mTimeStamp); + VideoOutput::NotifyRealtimeTrackData(aGraph, aTrackOffset, segment); + return; + } + } + } + + // Main thread only. + Watchable mFirstFrameRendered = { + false, "FirstFrameVideoOutput::mFirstFrameRendered"}; + + private: + // Whether a frame with a concrete size has been received. May only be + // accessed on the MTG's appending thread. (this is a direct listener so we + // get called by whoever is producing this track's data) + bool mInitialSizeFound = false; +}; + } // namespace mozilla #endif // VideoOutput_h