| 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 06d4a93b6dfca9cb3d42b26427ecb7be2d3f6673..b9991cce0c9884cd997f7798f3bd2285f527b8cc 100644
 | 
| --- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
 | 
| +++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
 | 
| @@ -83,6 +83,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"
 | 
| @@ -726,6 +727,18 @@ void HTMLMediaElement::setSrc(const AtomicString& url)
 | 
|      setAttribute(srcAttr, url);
 | 
|  }
 | 
|  
 | 
| +void HTMLMediaElement::setSrcObject(const WebMediaPlayerSource& srcObject)
 | 
| +{
 | 
| +    // srcObject can be a media-provider object or null.
 | 
| +    ASSERT(!srcObject.isURL());
 | 
| +
 | 
| +    // 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_srcObject = srcObject;
 | 
| +    invokeLoadAlgorithm();
 | 
| +}
 | 
| +
 | 
|  HTMLMediaElement::NetworkState HTMLMediaElement::getNetworkState() const
 | 
|  {
 | 
|      return m_networkState;
 | 
| @@ -904,68 +917,97 @@ 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_srcObject.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();
 | 
| +    }
 | 
| +}
 | 
| +
 | 
| +void HTMLMediaElement::loadSourceFromObject()
 | 
| +{
 | 
| +    ASSERT(m_srcObject.isMediaProviderObject());
 | 
| +    m_loadState = LoadingFromSrcObject;
 | 
|  
 | 
| -        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;
 | 
| -        }
 | 
| +    // No type is available when the resource comes from the 'srcObject'
 | 
| +    // attribute.
 | 
| +    ContentType contentType((String()));
 | 
| +    loadResource(m_srcObject, contentType);
 | 
| +}
 | 
|  
 | 
| -        KURL mediaURL = document().completeURL(srcValue);
 | 
| -        if (!isSafeToLoadURL(mediaURL, Complain)) {
 | 
| -            mediaLoadingFailed(WebMediaPlayer::NetworkStateFormatError);
 | 
| -            return;
 | 
| -        }
 | 
| +void HTMLMediaElement::loadSourceFromAttribute()
 | 
| +{
 | 
| +    m_loadState = LoadingFromSrcAttr;
 | 
| +    const AtomicString& srcValue = fastGetAttribute(srcAttr);
 | 
|  
 | 
| -        // 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);
 | 
| +    // 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()));
 | 
| +    loadResource(WebMediaPlayerSource(WebURL(mediaURL)), contentType);
 | 
|  }
 | 
|  
 | 
|  void HTMLMediaElement::loadNextSourceChild()
 | 
| @@ -981,15 +1023,18 @@ void HTMLMediaElement::loadNextSourceChild()
 | 
|      resetMediaPlayerAndMediaSource();
 | 
|  
 | 
|      m_loadState = LoadingFromSourceElement;
 | 
| -    loadResource(mediaURL, contentType);
 | 
| +    loadResource(WebMediaPlayerSource(WebURL(mediaURL)), contentType);
 | 
|  }
 | 
|  
 | 
| -void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType)
 | 
| +void HTMLMediaElement::loadResource(const WebMediaPlayerSource& source, 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 (source.isURL()) {
 | 
| +        url = 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) {
 | 
| @@ -1026,8 +1071,10 @@ void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType)
 | 
|  
 | 
|      bool attemptLoad = true;
 | 
|  
 | 
| -    if (url.protocolIs(mediaSourceBlobProtocol)) {
 | 
| -        if (isMediaStreamURL(url.getString())) {
 | 
| +    bool isObjectOrBlobURL = source.isMediaProviderObject() || url.protocolIs(mediaSourceBlobProtocol);
 | 
| +    if (isObjectOrBlobURL) {
 | 
| +        bool isMediaStream = source.isMediaStream() || (source.isURL() && isMediaStreamURL(url.getString()));
 | 
| +        if (isMediaStream) {
 | 
|              m_autoplayHelper->removeUserGestureRequirement(GesturelessPlaybackEnabledByStream);
 | 
|          } else {
 | 
|              m_mediaSource = HTMLMediaSource::lookup(url.getString());
 | 
| @@ -1043,7 +1090,8 @@ void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType)
 | 
|          }
 | 
|      }
 | 
|  
 | 
| -    if (attemptLoad && canLoadURL(url, contentType)) {
 | 
| +    bool canLoadResource = source.isMediaProviderObject() || canLoadURL(url, contentType);
 | 
| +    if (attemptLoad && canLoadResource) {
 | 
|          ASSERT(!webMediaPlayer());
 | 
|  
 | 
|          if (effectivePreloadType() == WebMediaPlayer::PreloadNone) {
 | 
| @@ -1067,24 +1115,33 @@ 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());
 | 
| +
 | 
| +    WebMediaPlayerSource source;
 | 
| +    if (m_srcObject.isMediaProviderObject()) {
 | 
| +        source = m_srcObject;
 | 
| +    } else {
 | 
| +        // 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);
 | 
| +        source = WebMediaPlayerSource(WebURL(kurl));
 | 
| +    }
 | 
|  
 | 
|      LocalFrame* frame = document().frame();
 | 
|      // TODO(srirama.m): Figure out how frame can be null when
 | 
| @@ -1094,8 +1151,7 @@ void HTMLMediaElement::startPlayerLoad()
 | 
|          return;
 | 
|      }
 | 
|  
 | 
| -    KURL kurl(ParsedURLString, requestURL);
 | 
| -    m_webMediaPlayer = frame->loader().client()->createWebMediaPlayer(*this, kurl, this);
 | 
| +    m_webMediaPlayer = frame->loader().client()->createWebMediaPlayer(*this, source, this);
 | 
|      if (!m_webMediaPlayer) {
 | 
|          mediaLoadingFailed(WebMediaPlayer::NetworkStateFormatError);
 | 
|          return;
 | 
| @@ -1111,7 +1167,7 @@ void HTMLMediaElement::startPlayerLoad()
 | 
|  
 | 
|      m_webMediaPlayer->setPreload(effectivePreloadType());
 | 
|  
 | 
| -    m_webMediaPlayer->load(loadType(), kurl, corsMode());
 | 
| +    m_webMediaPlayer->load(loadType(), source, corsMode());
 | 
|  
 | 
|      if (isFullscreen()) {
 | 
|          // This handles any transition to or from fullscreen overlay mode.
 | 
| @@ -1204,7 +1260,7 @@ WebMediaPlayer::LoadType HTMLMediaElement::loadType() const
 | 
|      if (m_mediaSource)
 | 
|          return WebMediaPlayer::LoadTypeMediaSource;
 | 
|  
 | 
| -    if (isMediaStreamURL(m_currentSrc.getString()))
 | 
| +    if (m_srcObject.isMediaStream() || isMediaStreamURL(m_currentSrc.getString()))
 | 
|          return WebMediaPlayer::LoadTypeMediaStream;
 | 
|  
 | 
|      return WebMediaPlayer::LoadTypeURL;
 | 
| 
 |