author | ctai <ctai@mozilla.com> |
Tue, 10 May 2016 17:02:15 +0800 | |
changeset 346047 | 49295086e189276fdab180f5e907538d929c6f7f |
parent 346046 | 6062a5e09ab773085a16cd0cd91f0cb0c352aa9a |
child 346048 | fc2c0cb9c6a822ca684742c79a88eab3c1c301ac |
push id | 1230 |
push user | jlund@mozilla.com |
push date | Mon, 31 Oct 2016 18:13:35 +0000 |
treeherder | mozilla-release@5e06e3766db2 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | pehrsons |
bugs | 1266646 |
milestone | 50.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -270,16 +270,66 @@ public: mSource, NS_LITERAL_STRING("error"), false, false); } }; /** + * 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 DirectMediaStreamTrackListener { +public: + explicit StreamSizeListener(HTMLMediaElement* aElement) : + mElement(aElement), + mInitialSizeFound(false) + {} + void Forget() { mElement = nullptr; } + + void ReceivedSize(gfx::IntSize aSize) + { + if (!mElement) { + return; + } + RefPtr<HTMLMediaElement> deathGrip = mElement; + mElement->UpdateInitialMediaSize(aSize); + } + + void NotifyRealtimeTrackData(MediaStreamGraph* aGraph, + StreamTime aTrackOffset, + const MediaSegment& aMedia) override + { + if (mInitialSizeFound || aMedia.GetType() != MediaSegment::VIDEO) { + 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; + nsCOMPtr<nsIRunnable> event = + NewRunnableMethod<gfx::IntSize>( + this, &StreamSizeListener::ReceivedSize, + c->mFrame.GetIntrinsicSize()); + aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget()); + return; + } + } + } + +private: + // These fields may only be accessed on the main thread + HTMLMediaElement* mElement; + + // These fields may only be accessed on the MSG thread + bool mInitialSizeFound; +}; + +/** * There is a reference cycle involving this class: MediaLoadListener * holds a reference to the HTMLMediaElement, which holds a reference * to an nsIChannel, which holds a reference to this listener. * We break the reference cycle in OnStartRequest by clearing mElement. */ class HTMLMediaElement::MediaLoadListener final : public nsIStreamListener, public nsIChannelEventSink, public nsIInterfaceRequestor, @@ -652,16 +702,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_ } NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlayed); NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextTrackManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioTrackList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVideoTrackList) #ifdef MOZ_EME NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeys) #endif + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectedVideoStreamTrack) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLElement) if (tmp->mSrcStream) { // Need to EndMediaStreamPlayback to clear mSrcStream and make sure everything // gets unhooked correctly. tmp->EndSrcMediaStreamPlayback(); } @@ -678,16 +729,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_IN } NS_IMPL_CYCLE_COLLECTION_UNLINK(mPlayed) NS_IMPL_CYCLE_COLLECTION_UNLINK(mTextTrackManager) NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioTrackList) NS_IMPL_CYCLE_COLLECTION_UNLINK(mVideoTrackList) #ifdef MOZ_EME NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaKeys) #endif + NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectedVideoStreamTrack) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLMediaElement) NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLMediaElement) NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback) NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement) // nsIDOMHTMLMediaElement @@ -876,16 +928,24 @@ void HTMLMediaElement::AbortExistingLoad if (mChannelLoader) { mChannelLoader->Cancel(); mChannelLoader = nullptr; } bool fireTimeUpdate = false; + // We need to remove StreamSizeListener before VideoTracks get emptied. + if (mMediaStreamSizeListener) { + mSelectedVideoStreamTrack->RemoveDirectListener(mMediaStreamSizeListener); + mSelectedVideoStreamTrack = nullptr; + mMediaStreamSizeListener->Forget(); + mMediaStreamSizeListener = nullptr; + } + // When aborting the existing loads, empty the objects in audio track list and // video track list, no events (in particular, no removetrack events) are // fired as part of this. Ending MediaStream sends track ended notifications, // so we empty the track lists prior. AudioTracks()->EmptyTracks(); VideoTracks()->EmptyTracks(); if (mDecoder) { @@ -3368,69 +3428,16 @@ private: bool mBlocked; bool mFinished; // mMutex protects the fields below; they can be accessed on any thread 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 { -public: - explicit StreamSizeListener(HTMLMediaElement* aElement) : - mElement(aElement), - mInitialSizeFound(false) - {} - void Forget() { mElement = nullptr; } - - void ReceivedSize(gfx::IntSize aSize) - { - if (!mElement) { - return; - } - RefPtr<HTMLMediaElement> deathGrip = mElement; - mElement->UpdateInitialMediaSize(aSize); - } - - void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID, - StreamTime aTrackOffset, - TrackEventCommand aTrackEvents, - const MediaSegment& aQueuedMedia, - MediaStream* aInputStream, - TrackID aInputTrackID) override - { - if (mInitialSizeFound || 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() != gfx::IntSize(0,0)) { - mInitialSizeFound = true; - nsCOMPtr<nsIRunnable> event = - NewRunnableMethod<gfx::IntSize>( - this, &StreamSizeListener::ReceivedSize, - c->mFrame.GetIntrinsicSize()); - aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget()); - return; - } - } - } - -private: - // These fields may only be accessed on the main thread - HTMLMediaElement* mElement; - - // These fields may only be accessed on the MSG thread - bool mInitialSizeFound; -}; - class HTMLMediaElement::MediaStreamTracksAvailableCallback: public OnTracksAvailableCallback { public: explicit MediaStreamTracksAvailableCallback(HTMLMediaElement* aElement): OnTracksAvailableCallback(), mElement(aElement) {} virtual void NotifyTracksAvailable(DOMMediaStream* aStream) @@ -3539,19 +3546,16 @@ void HTMLMediaElement::SetupSrcMediaStre nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow(); if (!window) { return; } RefPtr<MediaStream> stream = GetSrcMediaStream(); if (stream) { stream->SetAudioChannelType(mAudioChannel); - - mMediaStreamSizeListener = new StreamSizeListener(this); - stream->AddListener(mMediaStreamSizeListener); } UpdateSrcMediaStreamPlaying(); // If we pause this media element, track changes in the underlying stream // will continue to fire events at this element and alter its track list. // That's simpler than delaying the events, but probably confusing... ConstructMediaTracks(); @@ -3572,20 +3576,18 @@ void HTMLMediaElement::SetupSrcMediaStre void HTMLMediaElement::EndSrcMediaStreamPlayback() { MOZ_ASSERT(mSrcStream); UpdateSrcMediaStreamPlaying(REMOVING_SRC_STREAM); if (mMediaStreamSizeListener) { - RefPtr<MediaStream> stream = GetSrcMediaStream(); - if (stream) { - stream->RemoveListener(mMediaStreamSizeListener); - } + mSelectedVideoStreamTrack->RemoveDirectListener(mMediaStreamSizeListener); + mSelectedVideoStreamTrack = nullptr; mMediaStreamSizeListener->Forget(); mMediaStreamSizeListener = nullptr; } mSrcStream->UnregisterTrackListener(mMediaStreamTrackListener); mMediaStreamTrackListener = nullptr; mSrcStream->RemovePrincipalChangeObserver(this); @@ -3611,17 +3613,18 @@ static already_AddRefed<VideoTrack> CreateVideoTrack(VideoStreamTrack* aStreamTrack) { nsAutoString id; nsAutoString label; aStreamTrack->GetId(id); aStreamTrack->GetLabel(label); return MediaTrackList::CreateVideoTrack(id, NS_LITERAL_STRING("main"), - label, EmptyString()); + label, EmptyString(), + aStreamTrack); } void HTMLMediaElement::ConstructMediaTracks() { nsTArray<RefPtr<MediaStreamTrack>> tracks; mSrcStream->GetTracks(tracks); int firstEnabledVideo = -1; @@ -3643,16 +3646,21 @@ void HTMLMediaElement::ConstructMediaTra } if (VideoTracks()->Length() > 0) { // If media resource does not indicate a particular set of video tracks to // enable, the one that is listed first in the element's videoTracks object // must be selected. int index = firstEnabledVideo >= 0 ? firstEnabledVideo : 0; (*VideoTracks())[index]->SetEnabledInternal(true, MediaTrack::FIRE_NO_EVENTS); + VideoTrack* track = (*VideoTracks())[index]; + VideoStreamTrack* streamTrack = track->GetVideoStreamTrack(); + mMediaStreamSizeListener = new StreamSizeListener(this); + streamTrack->AddDirectListener(mMediaStreamSizeListener); + mSelectedVideoStreamTrack = streamTrack; } } void HTMLMediaElement::NotifyMediaStreamTrackAdded(const RefPtr<MediaStreamTrack>& aTrack) { MOZ_ASSERT(aTrack); @@ -3663,18 +3671,30 @@ HTMLMediaElement::NotifyMediaStreamTrack LOG(LogLevel::Debug, ("%p, Adding MediaTrack with id %s", this, NS_ConvertUTF16toUTF8(id).get())); #endif if (AudioStreamTrack* t = aTrack->AsAudioStreamTrack()) { RefPtr<AudioTrack> audioTrack = CreateAudioTrack(t); AudioTracks()->AddTrack(audioTrack); } else if (VideoStreamTrack* t = aTrack->AsVideoStreamTrack()) { + // TODO: Fix this per the spec on bug 1273443. + int32_t selectedIndex = VideoTracks()->SelectedIndex(); RefPtr<VideoTrack> videoTrack = CreateVideoTrack(t); VideoTracks()->AddTrack(videoTrack); + // New MediaStreamTrack added, set the new added video track as selected + // video track when there is no selected track. + if (selectedIndex == -1) { + MOZ_ASSERT(!mSelectedVideoStreamTrack); + videoTrack->SetEnabledInternal(true, MediaTrack::FIRE_NO_EVENTS); + mMediaStreamSizeListener = new StreamSizeListener(this); + t->AddDirectListener(mMediaStreamSizeListener); + mSelectedVideoStreamTrack = t; + } + } } void HTMLMediaElement::NotifyMediaStreamTrackRemoved(const RefPtr<MediaStreamTrack>& aTrack) { MOZ_ASSERT(aTrack); @@ -3683,16 +3703,58 @@ HTMLMediaElement::NotifyMediaStreamTrack LOG(LogLevel::Debug, ("%p, Removing MediaTrack with id %s", this, NS_ConvertUTF16toUTF8(id).get())); if (MediaTrack* t = AudioTracks()->GetTrackById(id)) { AudioTracks()->RemoveTrack(t); } else if (MediaTrack* t = VideoTracks()->GetTrackById(id)) { VideoTracks()->RemoveTrack(t); + // TODO: Fix this per the spec on bug 1273443. + // If the removed media stream track is selected video track and there are + // still video tracks, change the selected video track to the first + // remaining track. + if (aTrack == mSelectedVideoStreamTrack) { + // The mMediaStreamSizeListener might already reset to nullptr. + if (mMediaStreamSizeListener) { + mSelectedVideoStreamTrack->RemoveDirectListener(mMediaStreamSizeListener); + } + mSelectedVideoStreamTrack = nullptr; + MOZ_ASSERT(mSrcStream); + nsTArray<RefPtr<VideoStreamTrack>> tracks; + mSrcStream->GetVideoTracks(tracks); + + for (const RefPtr<VideoStreamTrack>& track : tracks) { + if (track->Ended()) { + continue; + } + if (!track->Enabled()) { + continue; + } + + nsAutoString trackId; + track->GetId(trackId); + MediaTrack* videoTrack = VideoTracks()->GetTrackById(trackId); + MOZ_ASSERT(videoTrack); + + videoTrack->SetEnabledInternal(true, MediaTrack::FIRE_NO_EVENTS); + if (mMediaStreamSizeListener) { + track->AddDirectListener(mMediaStreamSizeListener); + } + mSelectedVideoStreamTrack = track; + return; + } + + // There is no enabled video track existing, clean the + // mMediaStreamSizeListener. + if (mMediaStreamSizeListener) { + mMediaStreamSizeListener->Forget(); + mMediaStreamSizeListener = nullptr; + } + } } else { // XXX (bug 1208328) Uncomment this when DOMMediaStream doesn't call // NotifyTrackRemoved multiple times for the same track, i.e., when it // implements the "addtrack" and "removetrack" events. // NS_ASSERTION(false, "MediaStreamTrack ended but did not exist in track lists"); return; } } @@ -4601,20 +4663,17 @@ void HTMLMediaElement::UpdateInitialMedi { if (!mMediaInfo.HasVideo()) { UpdateMediaSize(aSize); } if (!mMediaStreamSizeListener) { return; } - RefPtr<MediaStream> stream = GetSrcMediaStream(); - if (stream) { - stream->RemoveListener(mMediaStreamSizeListener); - } + mSelectedVideoStreamTrack->RemoveDirectListener(mMediaStreamSizeListener); mMediaStreamSizeListener->Forget(); mMediaStreamSizeListener = nullptr; } void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendEvents) { LOG(LogLevel::Debug, ("%p SuspendOrResumeElement(pause=%d, suspendEvents=%d) hidden=%d", this, aPauseElement, aSuspendEvents, OwnerDoc()->Hidden()));
--- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -1239,16 +1239,18 @@ protected: 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. RefPtr<StreamSizeListener> mMediaStreamSizeListener; + // The selected video stream track which contained mMediaStreamSizeListener. + RefPtr<VideoStreamTrack> mSelectedVideoStreamTrack; const RefPtr<ShutdownObserver> mShutdownObserver; // 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
--- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -2939,43 +2939,48 @@ SourceMediaStream::RemoveDirectListener( void SourceMediaStream::AddDirectTrackListenerImpl(already_AddRefed<DirectMediaStreamTrackListener> aListener, TrackID aTrackID) { MOZ_ASSERT(IsTrackIDExplicit(aTrackID)); TrackData* data; bool found; bool isAudio; + bool isVideo; RefPtr<DirectMediaStreamTrackListener> listener = aListener; STREAM_LOG(LogLevel::Debug, ("Adding direct track listener %p bound to track %d to source stream %p", listener.get(), aTrackID, this)); + { MutexAutoLock lock(mMutex); data = FindDataForTrack(aTrackID); found = !!data; - isAudio = found && data->mData->GetType() == MediaSegment::AUDIO; - if (found && isAudio) { + if (found) { + isAudio = data->mData->GetType() == MediaSegment::AUDIO; + isVideo = data->mData->GetType() == MediaSegment::VIDEO; + } + if (found && (isAudio || isVideo)) { TrackBound<DirectMediaStreamTrackListener>* sourceListener = mDirectTrackListeners.AppendElement(); sourceListener->mListener = listener; sourceListener->mTrackID = aTrackID; } } if (!found) { STREAM_LOG(LogLevel::Warning, ("Couldn't find source track for direct track listener %p", listener.get())); listener->NotifyDirectListenerInstalled( DirectMediaStreamTrackListener::InstallationResult::TRACK_NOT_FOUND_AT_SOURCE); return; } - if (!isAudio) { - STREAM_LOG(LogLevel::Warning, ("Source track for direct track listener %p is not audio", + if (!isAudio && !isVideo) { + STREAM_LOG(LogLevel::Warning, ("Source track for direct track listener %p is unknown", listener.get())); - listener->NotifyDirectListenerInstalled( - DirectMediaStreamTrackListener::InstallationResult::TRACK_TYPE_NOT_SUPPORTED); + // It is not a video or audio track. + MOZ_ASSERT(true); return; } STREAM_LOG(LogLevel::Debug, ("Added direct track listener %p", listener.get())); listener->NotifyDirectListenerInstalled( DirectMediaStreamTrackListener::InstallationResult::SUCCESS); } void
--- a/dom/media/MediaStreamListener.h +++ b/dom/media/MediaStreamListener.h @@ -233,19 +233,16 @@ public: /** * When a direct listener is processed for installation by the * MediaStreamGraph it will be notified with whether the installation was * successful or not. The results of this installation are the following: * TRACK_NOT_FOUND_AT_SOURCE * We found the source stream of media data for this track, but the track * didn't exist. This should only happen if you try to install the listener * directly to a SourceMediaStream that doesn't contain the given TrackID. - * TRACK_TYPE_NOT_SUPPORTED - * This is the failure when you install the listener to a - * non-(audio or video) track. * STREAM_NOT_SUPPORTED * While looking for the data source of this track, we found a MediaStream * that is not a SourceMediaStream or a TrackUnionStream. * SUCCESS * Installation was successful and this listener will start receiving * NotifyRealtimeData on the next AppendToTrack(). */ enum class InstallationResult {
--- a/dom/media/MediaStreamTrack.cpp +++ b/dom/media/MediaStreamTrack.cpp @@ -4,16 +4,17 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MediaStreamTrack.h" #include "DOMMediaStream.h" #include "MediaStreamGraph.h" #include "nsIUUIDGenerator.h" #include "nsServiceManagerUtils.h" +#include "MediaStreamListener.h" #ifdef LOG #undef LOG #endif static PRLogModuleInfo* gMediaStreamTrackLog; #define LOG(type, msg) MOZ_LOG(gMediaStreamTrackLog, type, msg) @@ -156,16 +157,22 @@ MediaStreamTrack::Destroy() } if (mPrincipalHandleListener) { if (GetOwnedStream()) { RemoveListener(mPrincipalHandleListener); } mPrincipalHandleListener->Forget(); mPrincipalHandleListener = nullptr; } + for (auto l : mTrackListeners) { + RemoveListener(l); + } + for (auto l : mDirectTrackListeners) { + RemoveDirectListener(l); + } } NS_IMPL_CYCLE_COLLECTION_CLASS(MediaStreamTrack) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MediaStreamTrack, DOMEventTargetHelper) tmp->Destroy(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwningStream) @@ -382,55 +389,70 @@ MediaStreamTrack::GetInputStream() DOMMediaStream* inputDOMStream = GetInputDOMStream(); MOZ_RELEASE_ASSERT(inputDOMStream->GetInputStream()); return inputDOMStream->GetInputStream(); } ProcessedMediaStream* MediaStreamTrack::GetOwnedStream() { + if (!mOwningStream) + { + return nullptr; + } + return mOwningStream->GetOwnedStream(); } void MediaStreamTrack::AddListener(MediaStreamTrackListener* aListener) { LOG(LogLevel::Debug, ("MediaStreamTrack %p adding listener %p", this, aListener)); + MOZ_ASSERT(GetOwnedStream()); GetOwnedStream()->AddTrackListener(aListener, mTrackID); + mTrackListeners.AppendElement(aListener); } void MediaStreamTrack::RemoveListener(MediaStreamTrackListener* aListener) { LOG(LogLevel::Debug, ("MediaStreamTrack %p removing listener %p", this, aListener)); - GetOwnedStream()->RemoveTrackListener(aListener, mTrackID); + if (GetOwnedStream()) { + GetOwnedStream()->RemoveTrackListener(aListener, mTrackID); + mTrackListeners.RemoveElement(aListener); + } } void MediaStreamTrack::AddDirectListener(DirectMediaStreamTrackListener *aListener) { LOG(LogLevel::Debug, ("MediaStreamTrack %p (%s) adding direct listener %p to " "stream %p, track %d", this, AsAudioStreamTrack() ? "audio" : "video", aListener, GetOwnedStream(), mTrackID)); + MOZ_ASSERT(GetOwnedStream()); GetOwnedStream()->AddDirectTrackListener(aListener, mTrackID); + mDirectTrackListeners.AppendElement(aListener); } void MediaStreamTrack::RemoveDirectListener(DirectMediaStreamTrackListener *aListener) { LOG(LogLevel::Debug, ("MediaStreamTrack %p removing direct listener %p from stream %p", this, aListener, GetOwnedStream())); - GetOwnedStream()->RemoveDirectTrackListener(aListener, mTrackID); + if (GetOwnedStream()) { + GetOwnedStream()->RemoveDirectTrackListener(aListener, mTrackID); + mDirectTrackListeners.RemoveElement(aListener); + } } already_AddRefed<MediaInputPort> MediaStreamTrack::ForwardTrackContentsTo(ProcessedMediaStream* aStream) { MOZ_ASSERT(NS_IsMainThread()); MOZ_RELEASE_ASSERT(aStream); RefPtr<MediaInputPort> port =
--- a/dom/media/MediaStreamTrack.h +++ b/dom/media/MediaStreamTrack.h @@ -373,16 +373,18 @@ public: already_AddRefed<MediaInputPort> ForwardTrackContentsTo(ProcessedMediaStream* aStream); /** * Returns true if this track is connected to aPort and forwarded to aPort's * output stream. */ bool IsForwardedThrough(MediaInputPort* aPort); + void SetMediaStreamSizeListener(DirectMediaStreamTrackListener* aListener); + protected: virtual ~MediaStreamTrack(); void Destroy(); // Returns the original DOMMediaStream's underlying input stream. MediaStream* GetInputStream(); @@ -411,16 +413,20 @@ protected: RefPtr<DOMMediaStream> mOwningStream; TrackID mTrackID; TrackID mInputTrackID; RefPtr<MediaStreamTrackSource> mSource; RefPtr<MediaStreamTrack> mOriginalTrack; nsCOMPtr<nsIPrincipal> mPrincipal; nsCOMPtr<nsIPrincipal> mPendingPrincipal; RefPtr<PrincipalHandleListener> mPrincipalHandleListener; + // Keep tracking MediaStreamTrackListener and DirectMediaStreamTrackListener, + // so we can remove them in |Destory|. + nsTArray<RefPtr<MediaStreamTrackListener>> mTrackListeners; + nsTArray<RefPtr<DirectMediaStreamTrackListener>> mDirectTrackListeners; nsString mID; MediaStreamTrackState mReadyState; bool mEnabled; const bool mRemote; }; } // namespace dom } // namespace mozilla
--- a/dom/media/MediaTrackList.cpp +++ b/dom/media/MediaTrackList.cpp @@ -4,16 +4,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MediaTrack.h" #include "MediaTrackList.h" #include "mozilla/AsyncEventDispatcher.h" #include "mozilla/dom/HTMLMediaElement.h" #include "mozilla/dom/AudioTrack.h" +#include "mozilla/dom/VideoStreamTrack.h" #include "mozilla/dom/VideoTrack.h" #include "mozilla/dom/TrackEvent.h" #include "nsThreadUtils.h" namespace mozilla { namespace dom { MediaTrackList::MediaTrackList(nsPIDOMWindowInner* aOwnerWindow, @@ -101,19 +102,20 @@ MediaTrackList::CreateAudioTrack(const n aEnabled); return track.forget(); } already_AddRefed<VideoTrack> MediaTrackList::CreateVideoTrack(const nsAString& aId, const nsAString& aKind, const nsAString& aLabel, - const nsAString& aLanguage) + const nsAString& aLanguage, + VideoStreamTrack* aVideoTrack) { - RefPtr<VideoTrack> track = new VideoTrack(aId, aKind, aLabel, aLanguage); + RefPtr<VideoTrack> track = new VideoTrack(aId, aKind, aLabel, aLanguage, aVideoTrack); return track.forget(); } void MediaTrackList::EmptyTracks() { for (uint32_t i = 0; i < mTracks.Length(); ++i) { mTracks[i]->SetTrackList(nullptr);
--- a/dom/media/MediaTrackList.h +++ b/dom/media/MediaTrackList.h @@ -15,16 +15,17 @@ class DOMMediaStream; namespace dom { class HTMLMediaElement; class MediaTrack; class AudioTrackList; class VideoTrackList; class AudioTrack; class VideoTrack; +class VideoStreamTrack; /** * Base class of AudioTrackList and VideoTrackList. The AudioTrackList and * VideoTrackList objects represent a dynamic list of zero or more audio and * video tracks respectively. * * When a media element is to forget its media-resource-specific tracks, its * audio track list and video track list will be emptied. @@ -53,21 +54,24 @@ public: static already_AddRefed<AudioTrack> CreateAudioTrack(const nsAString& aId, const nsAString& aKind, const nsAString& aLabel, const nsAString& aLanguage, bool aEnabled); + // For the case of src of HTMLMediaElement is non-MediaStream, leave the + // aVideoTrack as default(nullptr). static already_AddRefed<VideoTrack> CreateVideoTrack(const nsAString& aId, const nsAString& aKind, const nsAString& aLabel, - const nsAString& aLanguage); + const nsAString& aLanguage, + VideoStreamTrack* aVideoTrack = nullptr); virtual void EmptyTracks(); void CreateAndDispatchChangeEvent(); // WebIDL MediaTrack* IndexedGetter(uint32_t aIndex, bool& aFound);
--- a/dom/media/VideoTrack.cpp +++ b/dom/media/VideoTrack.cpp @@ -1,31 +1,45 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 et tw=78: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/HTMLMediaElement.h" +#include "mozilla/dom/VideoStreamTrack.h" #include "mozilla/dom/VideoTrack.h" #include "mozilla/dom/VideoTrackBinding.h" #include "mozilla/dom/VideoTrackList.h" namespace mozilla { namespace dom { VideoTrack::VideoTrack(const nsAString& aId, const nsAString& aKind, const nsAString& aLabel, - const nsAString& aLanguage) + const nsAString& aLanguage, + VideoStreamTrack* aStreamTarck) : MediaTrack(aId, aKind, aLabel, aLanguage) , mSelected(false) + , mVideoStreamTrack(aStreamTarck) +{ +} + +VideoTrack::~VideoTrack() { } +NS_IMPL_CYCLE_COLLECTION_INHERITED(VideoTrack, MediaTrack, mVideoStreamTrack) + +NS_IMPL_ADDREF_INHERITED(VideoTrack, MediaTrack) +NS_IMPL_RELEASE_INHERITED(VideoTrack, MediaTrack) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(VideoTrack) +NS_INTERFACE_MAP_END_INHERITING(MediaTrack) + JSObject* VideoTrack::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { return VideoTrackBinding::Wrap(aCx, this, aGivenProto); } void VideoTrack::SetSelected(bool aSelected) {
--- a/dom/media/VideoTrack.h +++ b/dom/media/VideoTrack.h @@ -8,50 +8,63 @@ #define mozilla_dom_VideoTrack_h #include "MediaTrack.h" namespace mozilla { namespace dom { class VideoTrackList; +class VideoStreamTrack; class VideoTrack : public MediaTrack { public: VideoTrack(const nsAString& aId, const nsAString& aKind, const nsAString& aLabel, - const nsAString& aLanguage); + const nsAString& aLanguage, + VideoStreamTrack* aStreamTarck = nullptr); + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(VideoTrack, MediaTrack) JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; VideoTrack* AsVideoTrack() override { return this; } // When fetching media resource, if no video track is selected by the media // resource, then the first VideoTrack object in the list is set selected as // default. If multiple video tracks are selected by its media resource at // fetching phase, then the first enabled video track is set selected. // aFlags contains FIRE_NO_EVENTS because no events are fired in such cases. void SetEnabledInternal(bool aEnabled, int aFlags) override; + // Get associated video stream track when the video track comes from + // MediaStream. This might be nullptr when the src of owning HTMLMediaElement + // is not MediaStream. + VideoStreamTrack* GetVideoStreamTrack() { return mVideoStreamTrack; } + // WebIDL bool Selected() const { return mSelected; } // Either zero or one video track is selected in a list; If the selected track // is in a VideoTrackList, then all the other VideoTrack objects in that list // must be unselected. void SetSelected(bool aSelected); private: + virtual ~VideoTrack(); + bool mSelected; + RefPtr<VideoStreamTrack> mVideoStreamTrack; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_VideoTrack_h
--- a/dom/media/VideoTrackList.cpp +++ b/dom/media/VideoTrackList.cpp @@ -26,37 +26,37 @@ VideoTrackList::operator[](uint32_t aInd void VideoTrackList::RemoveTrack(const RefPtr<MediaTrack>& aTrack) { // we need to find the video track before |MediaTrackList::RemoveTrack|. Or // mSelectedIndex will not be valid. The check of mSelectedIndex == -1 // need to be done after RemoveTrack. Also the call of // |MediaTrackList::RemoveTrack| is necessary even when mSelectedIndex = -1. bool found; - VideoTrack* videoTrack = IndexedGetter(mSelectedIndex, found); + VideoTrack* selectedVideoTrack = IndexedGetter(mSelectedIndex, found); MediaTrackList::RemoveTrack(aTrack); if (mSelectedIndex == -1) { // There was no selected track and we don't select another track on removal. return; } MOZ_ASSERT(found, "When mSelectedIndex is set it should point to a track"); - MOZ_ASSERT(videoTrack, "The mSelectedIndex should be set to video track only"); + MOZ_ASSERT(selectedVideoTrack, "The mSelectedIndex should be set to video track only"); // Let the caller of RemoveTrack deal with choosing the new selected track if // it removes the currently-selected track. - if (aTrack == videoTrack) { + if (aTrack == selectedVideoTrack) { mSelectedIndex = -1; return; } // The removed track was not the selected track and there is a // currently-selected video track. We need to find the new location of the // selected track. for (size_t ix = 0; ix < mTracks.Length(); ix++) { - if (mTracks[ix] == videoTrack) { + if (mTracks[ix] == selectedVideoTrack) { mSelectedIndex = ix; return; } } } void VideoTrackList::EmptyTracks()