Bug 1149494 - Part 1. Add a listener directly to the unblocked input stream that reports the size of the first non-empty frame seen. r=pehrsons

--HG--
extra : rebase_source : 79b92a9726670125cd028355e298e43a200785ab
This commit is contained in:
Robert O'Callahan 2015-04-08 17:51:21 +12:00
Родитель f415610fd8
Коммит 1524dbeb74
3 изменённых файлов: 105 добавлений и 13 удалений

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

@ -2045,7 +2045,6 @@ HTMLMediaElement::LookupMediaElementURITable(nsIURI* aURI)
HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: nsGenericHTMLElement(aNodeInfo),
mSrcStreamListener(nullptr),
mCurrentLoadID(0),
mNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY),
mReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING),
@ -2955,6 +2954,61 @@ private:
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 {
public:
explicit StreamSizeListener(HTMLMediaElement* aElement) :
mElement(aElement),
mMutex("HTMLMediaElement::StreamSizeListener")
{}
void Forget() { mElement = nullptr; }
void ReceivedSize()
{
if (!mElement) {
return;
}
gfxIntSize size;
{
MutexAutoLock lock(mMutex);
size = mInitialSize;
}
nsRefPtr<HTMLMediaElement> deathGrip = mElement;
mElement->UpdateInitialMediaSize(size);
}
virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
StreamTime aTrackOffset,
uint32_t aTrackEvents,
const MediaSegment& aQueuedMedia) override
{
MutexAutoLock lock(mMutex);
if (mInitialSize != gfxIntSize(0,0) ||
aQueuedMedia.GetType() != MediaSegment::VIDEO) {
return;
}
const VideoSegment& video = static_cast<const VideoSegment&>(aQueuedMedia);
for (VideoSegment::ConstChunkIterator c(video); !c.IsEnded(); c.Next()) {
if (c->mFrame.GetIntrinsicSize() != gfxIntSize(0,0)) {
mInitialSize = c->mFrame.GetIntrinsicSize();
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;
gfxIntSize mInitialSize;
};
class HTMLMediaElement::MediaStreamTracksAvailableCallback:
public DOMMediaStream::OnTracksAvailableCallback
{
@ -2975,7 +3029,8 @@ private:
void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
{
NS_ASSERTION(!mSrcStream && !mSrcStreamListener, "Should have been ended already");
NS_ASSERTION(!mSrcStream && !mMediaStreamListener && !mMediaStreamSizeListener,
"Should have been ended already");
mSrcStream = aStream;
@ -3008,8 +3063,13 @@ void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
// XXX if we ever support capturing the output of a media element which is
// playing a stream, we'll need to add a CombineWithPrincipal call here.
mSrcStreamListener = new StreamListener(this);
GetSrcMediaStream()->AddListener(mSrcStreamListener);
mMediaStreamListener = new StreamListener(this);
mMediaStreamSizeListener = new StreamSizeListener(this);
GetSrcMediaStream()->AddListener(mMediaStreamListener);
// Listen for an initial image size on mSrcStream so we can get results even
// if we block the mPlaybackStream.
stream->AddListener(mMediaStreamSizeListener);
if (mPaused) {
GetSrcMediaStream()->ChangeExplicitBlockerCount(1);
}
@ -3042,7 +3102,10 @@ void HTMLMediaElement::EndSrcMediaStreamPlayback()
{
MediaStream* stream = GetSrcMediaStream();
if (stream) {
stream->RemoveListener(mSrcStreamListener);
stream->RemoveListener(mMediaStreamListener);
}
if (mSrcStream->GetStream()) {
mSrcStream->GetStream()->RemoveListener(mMediaStreamSizeListener);
}
mSrcStream->DisconnectTrackListListeners(AudioTracks(), VideoTracks());
@ -3051,8 +3114,10 @@ void HTMLMediaElement::EndSrcMediaStreamPlayback()
}
// Kill its reference to this element
mSrcStreamListener->Forget();
mSrcStreamListener = nullptr;
mMediaStreamListener->Forget();
mMediaStreamListener = nullptr;
mMediaStreamSizeListener->Forget();
mMediaStreamSizeListener = nullptr;
if (stream) {
stream->RemoveAudioOutput(this);
}
@ -3801,16 +3866,23 @@ void HTMLMediaElement::NotifyDecoderPrincipalChanged()
}
}
void HTMLMediaElement::UpdateMediaSize(nsIntSize size)
void HTMLMediaElement::UpdateMediaSize(const nsIntSize& aSize)
{
if (IsVideo() && mReadyState != HAVE_NOTHING && mMediaSize != size) {
if (IsVideo() && mReadyState != HAVE_NOTHING && mMediaSize != aSize) {
DispatchAsyncEvent(NS_LITERAL_STRING("resize"));
}
mMediaSize = size;
mMediaSize = aSize;
UpdateReadyStateForData(mLastNextFrameStatus);
}
void HTMLMediaElement::UpdateInitialMediaSize(const nsIntSize& aSize)
{
if (mMediaSize == nsIntSize(-1, -1)) {
UpdateMediaSize(aSize);
}
}
void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendEvents)
{
if (aPauseElement != mPausedForInactiveDocumentOrChannel) {

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

@ -260,7 +260,10 @@ public:
// Update the visual size of the media. Called from the decoder on the
// main thread when/if the size changes.
void UpdateMediaSize(nsIntSize size);
void UpdateMediaSize(const nsIntSize& aSize);
// Like UpdateMediaSize, but only updates the size if no size has yet
// been set.
void UpdateInitialMediaSize(const nsIntSize& aSize);
// Returns the CanPlayStatus indicating if we can handle the
// full MIME type including the optional codecs parameter.
@ -642,6 +645,7 @@ protected:
class MediaLoadListener;
class MediaStreamTracksAvailableCallback;
class StreamListener;
class StreamSizeListener;
virtual void GetItemValueText(DOMString& text) override;
virtual void SetItemValueText(const nsAString& text) override;
@ -1047,8 +1051,12 @@ protected:
};
nsTArray<OutputMediaStream> mOutputStreams;
// Holds a reference to the MediaStreamListener attached to mSrcStream.
nsRefPtr<StreamListener> mSrcStreamListener;
// Holds a reference to the MediaStreamListener attached to mPlaybackStream
// (or mSrcStream if mPlaybackStream is null).
nsRefPtr<StreamListener> mMediaStreamListener;
// Holds a reference to the size-getting MediaStreamListener attached to
// mSrcStream.
nsRefPtr<StreamSizeListener> mMediaStreamSizeListener;
// Holds a reference to the MediaSource supplying data for playback.
nsRefPtr<MediaSource> mMediaSource;

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

@ -265,6 +265,18 @@ public:
MediaSegmentBase<C, Chunk>& mSegment;
uint32_t mIndex;
};
class ConstChunkIterator {
public:
explicit ConstChunkIterator(const MediaSegmentBase<C, Chunk>& aSegment)
: mSegment(aSegment), mIndex(0) {}
bool IsEnded() { return mIndex >= mSegment.mChunks.Length(); }
void Next() { ++mIndex; }
const Chunk& operator*() { return mSegment.mChunks[mIndex]; }
const Chunk* operator->() { return &mSegment.mChunks[mIndex]; }
private:
const MediaSegmentBase<C, Chunk>& mSegment;
uint32_t mIndex;
};
void RemoveLeading(StreamTime aDuration)
{