Bug 1201363 - Add ImageSizeChangedListener to notify image size changed. r?jesup,r?pehrsons
HTMLMediaElement uses ImageSizeChangedListener to receive the image size changed event from VideoFrameContainer.
MozReview-Commit-ID: G9IQKuQw6z5
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3046,19 +3046,20 @@ private:
Mutex mMutex;
bool mPendingNotifyOutput;
};
/**
* This listener observes the first video frame to arrive with a non-empty size,
* and calls HTMLMediaElement::ReceivedMediaStreamInitialSize() with that size.
*/
-class HTMLMediaElement::StreamSizeListener : public MediaStreamListener {
+class HTMLMediaElement::StreamSizeListener : public ImageSizeChangedListener {
public:
- explicit StreamSizeListener(HTMLMediaElement* aElement) :
+ explicit StreamSizeListener(HTMLMediaElement* aElement, MediaStreamGraph* aGraph) :
+ ImageSizeChangedListener(aGraph),
mElement(aElement),
mMutex("HTMLMediaElement::StreamSizeListener")
{}
void Forget() { mElement = nullptr; }
void ReceivedSize()
{
if (!mElement) {
@@ -3067,37 +3068,30 @@ public:
gfx::IntSize size;
{
MutexAutoLock lock(mMutex);
size = mInitialSize;
}
RefPtr<HTMLMediaElement> deathGrip = mElement;
mElement->UpdateInitialMediaSize(size);
}
- virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
- StreamTime aTrackOffset,
- uint32_t aTrackEvents,
- const MediaSegment& aQueuedMedia,
- MediaStream* aInputStream,
- TrackID aInputTrackID) override
+ virtual void NotifyImageSizeChanged(MediaStreamGraph* aGraph,
+ const gfx::IntSize& aIntrinsicSize) override
{
+ MOZ_ASSERT(aGraph);
MutexAutoLock lock(mMutex);
- if (mInitialSize != gfx::IntSize(0,0) ||
- aQueuedMedia.GetType() != MediaSegment::VIDEO) {
+ if (mInitialSize != gfx::IntSize(0,0))
+ {
return;
}
- const VideoSegment& video = static_cast<const VideoSegment&>(aQueuedMedia);
- for (VideoSegment::ConstChunkIterator c(video); !c.IsEnded(); c.Next()) {
- if (c->mFrame.GetIntrinsicSize() != gfx::IntSize(0,0)) {
- mInitialSize = c->mFrame.GetIntrinsicSize();
- nsCOMPtr<nsIRunnable> event =
- NS_NewRunnableMethod(this, &StreamSizeListener::ReceivedSize);
- aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
- }
- }
+
+ mInitialSize = aIntrinsicSize;
+ nsCOMPtr<nsIRunnable> event =
+ NS_NewRunnableMethod(this, &StreamSizeListener::ReceivedSize);
+ aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
}
private:
// These fields may only be accessed on the main thread
HTMLMediaElement* mElement;
// mMutex protects the fields below; they can be accessed on any thread
Mutex mMutex;
@@ -3166,40 +3160,40 @@ void HTMLMediaElement::UpdateSrcMediaStr
this, shouldPlay ? "Setting up" : "Removing",
mSrcStream.get()));
if (shouldPlay) {
mSrcStreamPausedCurrentTime = -1;
mMediaStreamListener = new StreamListener(this,
"HTMLMediaElement::mMediaStreamListener");
- mMediaStreamSizeListener = new StreamSizeListener(this);
+ mMediaStreamSizeListener = new StreamSizeListener(this, stream->Graph());
stream->AddListener(mMediaStreamListener);
- stream->AddListener(mMediaStreamSizeListener);
mWatchManager.Watch(*mMediaStreamListener,
&HTMLMediaElement::UpdateReadyStateInternal);
stream->AddAudioOutput(this);
SetVolumeInternal();
VideoFrameContainer* container = GetVideoFrameContainer();
if (container) {
+ container->AddImageSizeChangedListener(mMediaStreamSizeListener);
stream->AddVideoOutput(container);
}
} else {
if (stream) {
mSrcStreamPausedCurrentTime = CurrentTime();
stream->RemoveListener(mMediaStreamListener);
- stream->RemoveListener(mMediaStreamSizeListener);
stream->RemoveAudioOutput(this);
VideoFrameContainer* container = GetVideoFrameContainer();
if (container) {
+ container->RemoveImageSizeChangedListener(mMediaStreamSizeListener);
stream->RemoveVideoOutput(container);
}
}
// If stream is null, then DOMMediaStream::Destroy must have been
// called and that will remove all listeners/outputs.
mWatchManager.Unwatch(*mMediaStreamListener,
&HTMLMediaElement::UpdateReadyStateInternal);
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -1134,18 +1134,18 @@ protected:
RefPtr<DOMMediaStream> mStream;
bool mFinishWhenEnded;
};
nsTArray<OutputMediaStream> mOutputStreams;
// Holds a reference to the MediaStreamListener attached to mSrcStream's
// playback stream.
RefPtr<StreamListener> mMediaStreamListener;
- // Holds a reference to the size-getting MediaStreamListener attached to
- // mSrcStream.
+ // Holds a reference to the size-getting ImageSizeChangedListener attached to
+ // VideoFrameContainer.
RefPtr<StreamSizeListener> mMediaStreamSizeListener;
// Holds a reference to the MediaSource, if any, referenced by the src
// attribute on the media element.
RefPtr<MediaSource> mSrcMediaSource;
// Holds a reference to the MediaSource supplying data for playback. This
// may either match mSrcMediaSource or come from Source element children.
--- a/dom/media/VideoFrameContainer.cpp
+++ b/dom/media/VideoFrameContainer.cpp
@@ -75,16 +75,19 @@ void VideoFrameContainer::SetCurrentFram
if (aImages.IsEmpty()) {
mImageContainer->ClearAllImages();
} else {
mImageContainer->SetCurrentImages(aImages);
}
gfx::IntSize newFrameSize = mImageContainer->GetCurrentSize();
if (oldFrameSize != newFrameSize) {
mImageSizeChanged = true;
+ for (ImageSizeChangedListener* l : mListeners) {
+ l->NotifyImageSizeChanged(l->mGraph, newFrameSize);
+ }
}
}
void VideoFrameContainer::ClearCurrentFrame()
{
MutexAutoLock lock(mMutex);
// See comment in SetCurrentFrame for the reasoning behind
--- a/dom/media/VideoFrameContainer.h
+++ b/dom/media/VideoFrameContainer.h
@@ -15,16 +15,31 @@
#include "ImageContainer.h"
namespace mozilla {
namespace dom {
class HTMLMediaElement;
} // namespace dom
+class MediaStreamGraph;
+
+class ImageSizeChangedListener {
+protected:
+ // Protected destructor, to discourage deletion outside of Release():
+ virtual ~ImageSizeChangedListener() {}
+
+public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageSizeChangedListener)
+ ImageSizeChangedListener(MediaStreamGraph* aGraph) : mGraph(aGraph) {}
+ virtual void NotifyImageSizeChanged(MediaStreamGraph* aGraph,
+ const gfx::IntSize& aIntrinsicSize) = 0;
+ MediaStreamGraph* mGraph;
+};
+
/**
* This object is used in the decoder backend threads and the main thread
* to manage the "current video frame" state. This state includes timing data
* and an intrinsic size (see below).
* This has to be a thread-safe object since it's accessed by resource decoders
* and other off-main-thread components. So we can't put this state in the media
* element itself ... well, maybe we could, but it could be risky and/or
* confusing.
@@ -37,18 +52,28 @@ public:
typedef layers::Image Image;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoFrameContainer)
VideoFrameContainer(dom::HTMLMediaElement* aElement,
already_AddRefed<ImageContainer> aContainer);
// Call on any thread
+ void AddImageSizeChangedListener(ImageSizeChangedListener* aListener)
+ {
+ MutexAutoLock lock(mMutex);
+ *mListeners.AppendElement() = aListener;
+ }
+ void RemoveImageSizeChangedListener(ImageSizeChangedListener* aListener)
+ {
+ MutexAutoLock lock(mMutex);
+ mListeners.RemoveElement(aListener);
+ }
B2G_ACL_EXPORT void SetCurrentFrame(const gfx::IntSize& aIntrinsicSize, Image* aImage,
- const TimeStamp& aTargetTime);
+ const TimeStamp& aTargetTime);
void SetCurrentFrames(const gfx::IntSize& aIntrinsicSize,
const nsTArray<ImageContainer::NonOwningImage>& aImages);
void ClearCurrentFrame(const gfx::IntSize& aIntrinsicSize)
{
SetCurrentFrames(aIntrinsicSize, nsTArray<ImageContainer::NonOwningImage>());
}
void ClearCurrentFrame();
@@ -86,16 +111,17 @@ protected:
// Non-addreffed pointer to the element. The element calls ForgetElement
// to clear this reference when the element is destroyed.
dom::HTMLMediaElement* mElement;
RefPtr<ImageContainer> mImageContainer;
// mMutex protects all the fields below.
Mutex mMutex;
+ nsTArray<RefPtr<ImageSizeChangedListener>> mListeners;
// The intrinsic size is the ideal size which we should render the
// ImageContainer's current Image at.
// This can differ from the Image's actual size when the media resource
// specifies that the Image should be stretched to have the correct aspect
// ratio.
gfx::IntSize mIntrinsicSize;
// We maintain our own mFrameID which is auto-incremented at every
// SetCurrentFrame() or NewFrameID() call.