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
This commit is contained in:
Andreas Pehrson 2020-08-26 14:25:05 +00:00
Родитель 0bb8c3dc1d
Коммит 13232f716c
3 изменённых файлов: 80 добавлений и 78 удалений

Просмотреть файл

@ -759,63 +759,6 @@ class HTMLMediaElement::MediaStreamTrackListener
const WeakPtr<HTMLMediaElement> 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<const VideoSegment&>(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<FirstFrameListener>(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<bool> 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<FirstFrameListener>(
aVideoContainer, aMainThread)
: nullptr) {
if (mFirstFrameListener) {
mWatchManager.Watch(mFirstFrameListener->mFirstFrameRendered,
mFirstFrameVideoOutput(aVideoContainer
? MakeAndAddRef<FirstFrameVideoOutput>(
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<MediaStreamTrack> 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<FirstFrameListener> mFirstFrameListener;
RefPtr<FirstFrameVideoOutput> mFirstFrameVideoOutput;
};
class HTMLMediaElement::MediaElementTrackSource

Просмотреть файл

@ -766,7 +766,6 @@ class HTMLMediaElement : public nsGenericHTMLElement,
class MediaLoadListener;
class MediaStreamRenderer;
class MediaStreamTrackListener;
class FirstFrameListener;
class ShutdownObserver;
class MediaControlKeyListener;

Просмотреть файл

@ -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<const VideoSegment&>(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<FirstFrameVideoOutput>(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<bool> 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