| Index: third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
|
| diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
|
| index 4d4e353a1845a1ef49ae026a8adbfe81b4bc7683..0a58fd632e73c40ddcbbb7e237ca068897bae97a 100644
|
| --- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
|
| +++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
|
| @@ -81,6 +81,7 @@
|
| #include "public/platform/WebAudioSourceProvider.h"
|
| #include "public/platform/WebContentDecryptionModule.h"
|
| #include "public/platform/WebInbandTextTrack.h"
|
| +#include "public/platform/WebMediaStream.h"
|
| #include "public/platform/modules/remoteplayback/WebRemotePlaybackClient.h"
|
| #include "public/platform/modules/remoteplayback/WebRemotePlaybackState.h"
|
| #include "wtf/CurrentTime.h"
|
| @@ -654,6 +655,15 @@ void HTMLMediaElement::setSrc(const AtomicString& url)
|
| setAttribute(srcAttr, url);
|
| }
|
|
|
| +void HTMLMediaElement::setSrcObject(const WebMediaElementSource& srcObject)
|
| +{
|
| + // The srcObject IDL attribute, on setting, must set the element's assigned
|
| + // media provider object to the new value, and then invoke the element's
|
| + // media element load algorithm.
|
| + m_source = srcObject;
|
| + invokeLoadAlgorithm();
|
| +}
|
| +
|
| HTMLMediaElement::NetworkState HTMLMediaElement::getNetworkState() const
|
| {
|
| return m_networkState;
|
| @@ -868,68 +878,98 @@ void HTMLMediaElement::selectMediaResource()
|
| {
|
| WTF_LOG(Media, "HTMLMediaElement::selectMediaResource(%p)", this);
|
|
|
| - enum Mode { attribute, children };
|
| -
|
| - // 3 - If the media element has a src attribute, then let mode be attribute.
|
| - Mode mode = attribute;
|
| - if (!fastHasAttribute(srcAttr)) {
|
| - // Otherwise, if the media element does not have a src attribute but has a source
|
| - // element child, then let mode be children and let candidate be the first such
|
| - // source element child in tree order.
|
| - if (HTMLSourceElement* element = Traversal<HTMLSourceElement>::firstChild(*this)) {
|
| - mode = children;
|
| - m_nextChildNodeToConsider = element;
|
| - m_currentSourceNode = nullptr;
|
| - } else {
|
| - // Otherwise the media element has neither a src attribute nor a source element
|
| - // child: set the networkState to NETWORK_EMPTY, and abort these steps; the
|
| - // synchronous section ends.
|
| - m_loadState = WaitingForSource;
|
| - setShouldDelayLoadEvent(false);
|
| - setNetworkState(NETWORK_EMPTY);
|
| - updateDisplayState();
|
| + enum Mode { Object, Attribute, Children, Nothing };
|
| + Mode mode = Nothing;
|
| +
|
| + // 6 - If the media element has an assigned media provider object, then let
|
| + // mode be object.
|
| + if (m_source.isMediaProviderObject()) {
|
| + mode = Object;
|
| + } else if (fastHasAttribute(srcAttr)) {
|
| + // Otherwise, if the media element has no assigned media provider object
|
| + // but has a src attribute, then let mode be attribute.
|
| + mode = Attribute;
|
| + } else if (HTMLSourceElement* element = Traversal<HTMLSourceElement>::firstChild(*this)) {
|
| + // Otherwise, if the media element does not have an assigned media
|
| + // provider object and does not have a src attribute, but does have a
|
| + // source element child, then let mode be children and let candidate be
|
| + // the first such source element child in tree order.
|
| + mode = Children;
|
| + m_nextChildNodeToConsider = element;
|
| + m_currentSourceNode = nullptr;
|
| + } else {
|
| + // Otherwise the media element has no assigned media provider object and
|
| + // has neither a src attribute nor a source element child: set the
|
| + // networkState to NETWORK_EMPTY, and abort these steps; the synchronous
|
| + // section ends.
|
| + m_loadState = WaitingForSource;
|
| + setShouldDelayLoadEvent(false);
|
| + setNetworkState(NETWORK_EMPTY);
|
| + updateDisplayState();
|
|
|
| - WTF_LOG(Media, "HTMLMediaElement::selectMediaResource(%p), nothing to load", this);
|
| - return;
|
| - }
|
| + WTF_LOG(Media, "HTMLMediaElement::selectMediaResource(%p), nothing to load", this);
|
| + return;
|
| }
|
|
|
| - // 4 - Set the media element's delaying-the-load-event flag to true (this delays the load event),
|
| - // and set its networkState to NETWORK_LOADING.
|
| - setShouldDelayLoadEvent(true);
|
| + // 7 - Set the media element's networkState to NETWORK_LOADING.
|
| setNetworkState(NETWORK_LOADING);
|
|
|
| - // 5 - Queue a task to fire a simple event named loadstart at the media element.
|
| + // 8 - Queue a task to fire a simple event named loadstart at the media element.
|
| scheduleEvent(EventTypeNames::loadstart);
|
|
|
| - // 6 - If mode is attribute, then run these substeps
|
| - if (mode == attribute) {
|
| - m_loadState = LoadingFromSrcAttr;
|
| + // 9 - Run the appropriate steps...
|
| + switch (mode) {
|
| + case Object:
|
| + loadSourceFromObject();
|
| + WTF_LOG(Media, "HTMLMediaElement::selectMediaResource(%p), using 'srcObject' attribute", this);
|
| + break;
|
| + case Attribute:
|
| + loadSourceFromAttribute();
|
| + WTF_LOG(Media, "HTMLMediaElement::selectMediaResource(%p), using 'src' attribute url", this);
|
| + break;
|
| + case Children:
|
| + loadNextSourceChild();
|
| + WTF_LOG(Media, "HTMLMediaElement::selectMediaResource(%p), using source element", this);
|
| + break;
|
| + default:
|
| + ASSERT_NOT_REACHED();
|
| + }
|
| +}
|
|
|
| - const AtomicString& srcValue = fastGetAttribute(srcAttr);
|
| - // If the src attribute's value is the empty string ... jump down to the failed step below
|
| - if (srcValue.isEmpty()) {
|
| - mediaLoadingFailed(WebMediaPlayer::NetworkStateFormatError);
|
| - WTF_LOG(Media, "HTMLMediaElement::selectMediaResource(%p), empty 'src'", this);
|
| - return;
|
| - }
|
| +void HTMLMediaElement::loadSourceFromObject()
|
| +{
|
| + ASSERT(m_source.isMediaProviderObject());
|
| + m_loadState = LoadingFromSrcObject;
|
|
|
| - KURL mediaURL = document().completeURL(srcValue);
|
| - if (!isSafeToLoadURL(mediaURL, Complain)) {
|
| - mediaLoadingFailed(WebMediaPlayer::NetworkStateFormatError);
|
| - return;
|
| - }
|
| + // No type is available when the resource comes from the 'srcObject'
|
| + // attribute.
|
| + ContentType contentType((String()));
|
| + loadResource(contentType);
|
| +}
|
|
|
| - // No type is available when the url comes from the 'src' attribute so MediaPlayer
|
| - // will have to pick a media engine based on the file extension.
|
| - ContentType contentType((String()));
|
| - loadResource(mediaURL, contentType);
|
| - WTF_LOG(Media, "HTMLMediaElement::selectMediaResource(%p), using 'src' attribute url", this);
|
| +void HTMLMediaElement::loadSourceFromAttribute()
|
| +{
|
| + m_loadState = LoadingFromSrcAttr;
|
| + const AtomicString& srcValue = fastGetAttribute(srcAttr);
|
| +
|
| + // If the src attribute's value is the empty string ... jump down to the failed step below
|
| + if (srcValue.isEmpty()) {
|
| + mediaLoadingFailed(WebMediaPlayer::NetworkStateFormatError);
|
| + WTF_LOG(Media, "HTMLMediaElement::selectMediaResource(%p), empty 'src'", this);
|
| return;
|
| }
|
|
|
| - // Otherwise, the source elements will be used
|
| - loadNextSourceChild();
|
| + KURL mediaURL = document().completeURL(srcValue);
|
| + if (!isSafeToLoadURL(mediaURL, Complain)) {
|
| + mediaLoadingFailed(WebMediaPlayer::NetworkStateFormatError);
|
| + return;
|
| + }
|
| +
|
| + // No type is available when the url comes from the 'src' attribute so
|
| + // MediaPlayer will have to pick a media engine based on the file extension.
|
| + ContentType contentType((String()));
|
| + m_source = WebMediaElementSource(WebURL(mediaURL));
|
| + loadResource(contentType);
|
| }
|
|
|
| void HTMLMediaElement::loadNextSourceChild()
|
| @@ -945,15 +985,19 @@ void HTMLMediaElement::loadNextSourceChild()
|
| resetMediaPlayerAndMediaSource();
|
|
|
| m_loadState = LoadingFromSourceElement;
|
| - loadResource(mediaURL, contentType);
|
| + m_source = WebMediaElementSource(WebURL(mediaURL));
|
| + loadResource(contentType);
|
| }
|
|
|
| -void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType)
|
| +void HTMLMediaElement::loadResource(ContentType& contentType)
|
| {
|
| ASSERT(isMainThread());
|
| - ASSERT(isSafeToLoadURL(url, Complain));
|
| -
|
| - WTF_LOG(Media, "HTMLMediaElement::loadResource(%p, %s, %s)", this, urlForLoggingMedia(url).utf8().data(), contentType.raw().utf8().data());
|
| + KURL url;
|
| + if (m_source.isURL()) {
|
| + url = m_source.getAsURL();
|
| + ASSERT(isSafeToLoadURL(url, Complain));
|
| + WTF_LOG(Media, "HTMLMediaElement::loadResource(%p, %s, %s)", this, urlForLoggingMedia(url).utf8().data(), contentType.raw().utf8().data());
|
| + }
|
|
|
| LocalFrame* frame = document().frame();
|
| if (!frame) {
|
| @@ -988,8 +1032,10 @@ void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType)
|
|
|
| bool attemptLoad = true;
|
|
|
| - if (url.protocolIs(mediaSourceBlobProtocol)) {
|
| - if (isMediaStreamURL(url.getString())) {
|
| + bool isBlobProtocol = m_source.isMediaProviderObject() || url.protocolIs(mediaSourceBlobProtocol);
|
| + if (isBlobProtocol) {
|
| + bool isMediaStream = m_source.isMediaStream() || (m_source.isURL() && isMediaStreamURL(url.getString()));
|
| + if (isMediaStream) {
|
| m_userGestureRequiredForPlay = false;
|
| } else {
|
| m_mediaSource = HTMLMediaSource::lookup(url.getString());
|
| @@ -1005,7 +1051,8 @@ void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType)
|
| }
|
| }
|
|
|
| - if (attemptLoad && canLoadURL(url, contentType)) {
|
| + bool canLoadResource = m_source.isMediaProviderObject() || canLoadURL(url, contentType);
|
| + if (attemptLoad && canLoadResource) {
|
| ASSERT(!webMediaPlayer());
|
|
|
| if (effectivePreloadType() == WebMediaPlayer::PreloadNone) {
|
| @@ -1029,24 +1076,30 @@ void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType)
|
| void HTMLMediaElement::startPlayerLoad()
|
| {
|
| ASSERT(!m_webMediaPlayer);
|
| - // Filter out user:pass as those two URL components aren't
|
| - // considered for media resource fetches (including for the CORS
|
| - // use-credentials mode.) That behavior aligns with Gecko, with IE
|
| - // being more restrictive and not allowing fetches to such URLs.
|
| - //
|
| - // Spec reference: http://whatwg.org/c/#concept-media-load-resource
|
| - //
|
| - // FIXME: when the HTML spec switches to specifying resource
|
| - // fetches in terms of Fetch (http://fetch.spec.whatwg.org), and
|
| - // along with that potentially also specifying a setting for its
|
| - // 'authentication flag' to control how user:pass embedded in a
|
| - // media resource URL should be treated, then update the handling
|
| - // here to match.
|
| - KURL requestURL = m_currentSrc;
|
| - if (!requestURL.user().isEmpty())
|
| - requestURL.setUser(String());
|
| - if (!requestURL.pass().isEmpty())
|
| - requestURL.setPass(String());
|
| +
|
| + if (m_source.isURL()) {
|
| + // Filter out user:pass as those two URL components aren't
|
| + // considered for media resource fetches (including for the CORS
|
| + // use-credentials mode.) That behavior aligns with Gecko, with IE
|
| + // being more restrictive and not allowing fetches to such URLs.
|
| + //
|
| + // Spec reference: http://whatwg.org/c/#concept-media-load-resource
|
| + //
|
| + // FIXME: when the HTML spec switches to specifying resource
|
| + // fetches in terms of Fetch (http://fetch.spec.whatwg.org), and
|
| + // along with that potentially also specifying a setting for its
|
| + // 'authentication flag' to control how user:pass embedded in a
|
| + // media resource URL should be treated, then update the handling
|
| + // here to match.
|
| + KURL requestURL = m_currentSrc;
|
| + if (!requestURL.user().isEmpty())
|
| + requestURL.setUser(String());
|
| + if (!requestURL.pass().isEmpty())
|
| + requestURL.setPass(String());
|
| +
|
| + KURL kurl(ParsedURLString, requestURL);
|
| + m_source = WebMediaElementSource(WebURL(kurl));
|
| + }
|
|
|
| LocalFrame* frame = document().frame();
|
| // TODO(srirama.m): Figure out how frame can be null when
|
| @@ -1056,8 +1109,7 @@ void HTMLMediaElement::startPlayerLoad()
|
| return;
|
| }
|
|
|
| - KURL kurl(ParsedURLString, requestURL);
|
| - m_webMediaPlayer = frame->loader().client()->createWebMediaPlayer(*this, loadType(), kurl, this);
|
| + m_webMediaPlayer = frame->loader().client()->createWebMediaPlayer(*this, loadType(), m_source, this);
|
| if (!m_webMediaPlayer) {
|
| mediaLoadingFailed(WebMediaPlayer::NetworkStateFormatError);
|
| return;
|
| @@ -1073,7 +1125,7 @@ void HTMLMediaElement::startPlayerLoad()
|
|
|
| m_webMediaPlayer->setPreload(effectivePreloadType());
|
|
|
| - m_webMediaPlayer->load(loadType(), kurl, corsMode());
|
| + m_webMediaPlayer->load(loadType(), m_source, corsMode());
|
|
|
| if (isFullscreen()) {
|
| // This handles any transition to or from fullscreen overlay mode.
|
| @@ -1166,6 +1218,9 @@ WebMediaPlayer::LoadType HTMLMediaElement::loadType() const
|
| if (m_mediaSource)
|
| return WebMediaPlayer::LoadTypeMediaSource;
|
|
|
| + if (m_source.isMediaStream())
|
| + return WebMediaPlayer::LoadTypeMediaStream;
|
| +
|
| if (isMediaStreamURL(m_currentSrc.getString()))
|
| return WebMediaPlayer::LoadTypeMediaStream;
|
|
|
|
|