зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
0bb8c3dc1d
Коммит
13232f716c
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче