【问题标题】:HTML5 video fallback when all types unsupported不支持所有类型时的 HTML5 视频回退
【发布时间】:2015-09-07 02:19:18
【问题描述】:

在 HTML5 规范中,它建议您将备用材料放在不支持它的旧浏览器的 <video> 标记中。

<video width="400" controls>
    <source src="mov_bbb.mp4" type="video/mp4">
    <source src="mov_bbb.ogg" type="video/ogg">
    Your browser does not support HTML5 video.
</video>

但是,当所有源类型均不受支持时,我找不到任何用于回退的内容。例如,我的 Chromium 浏览器无法播放 video/mp4,但可以播放 video/ogg。所以我希望这会呈现回退文本。

<video width="400" controls>
    <source src="mov_bbb.mp4" type="video/mp4">
    Your browser does not support HTML5 video.
</video>

相反,我只是得到一个没有任何内容的视频播放器,因为它无法加载 mp4 文件。

当没有可用的视频源时,有没有办法在 HTML 5 视频中回退?我知道我尝试的后备方案仅适用于旧浏览器,但我仍然需要一个没有可用资源的后备方案。

【问题讨论】:

  • 仅当 HTML5 &lt;video&gt; 元素本身不支持而不支持其中的视频类型时才会显示回退。
  • @Xufox 我意识到了这一点,但是如果它不能渲染任何源,我仍然需要一种方法来做回退。
  • canPlayType怎么样?
  • 如果它无法加载源代码,这是该元素无法处理的问题。

标签: html html5-video


【解决方案1】:

实际上,当您尝试在&lt;source&gt; 元素中加载不受支持的媒体类型时,将触发error 事件。
然后您可以监听这些事件,如果没有识别到​​任何源,则触发回退:

var sources = document.querySelectorAll('source');
var source_errors = 0;
for (var i = 0; i < sources.length; i++) {
  sources[i].addEventListener('error', function(e) {
    if (++source_errors >= sources.length)
      fallBack();
  });
}

function fallBack() {
  document.body.removeChild(document.querySelector('video'));
  document.body.appendChild(document.createTextNode('No video with supported media and MIME type found'));
}
<video controls>
  <source src="foo.bar" type="video/foo" />
  <source src="bar.foo" type="video/bar" />
</video>

【讨论】:

  • 这在 Firefox 中似乎不起作用 - 它会抛出控制台日志,但没有错误。
  • @Sora2455 你是什么意思?现在在 FF 上,sn-p 完美运行,显示消息 No video with supported media and MIME type found
  • 抱歉,我将事件处理程序附加到视频标签,而不是源标签。我的错。
  • 但是,当我在 IE11 和 Edge 18 中运行上述示例时,它会保留视频标签。 IE 似乎在 video 标签处触发了错误事件,而 Edge 似乎根本没有触发它。
  • 这节省了我的时间,对我来说工作正常
【解决方案2】:

这没有 HTML 行为,所以我们必须用 JavaScript 添加我们自己的行为。

(function() {
  "use strict";

  function insertAfter(newNode, referenceNode) {
    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
  }

  function setVideoFallback(lazyArea) {
    var lowData = false;
    if ("connection" in navigator) {
      lowData = navigator.connection.saveData === true ||
        navigator.connection.effectiveType === "slow-2g" ||
        navigator.connection.effectiveType === "2g";
    }
    //DocumentFragments don't support getElementsByTagName
    //oldIE doesn't support querySelectorAll
    var lazyVideos = lazyArea.querySelectorAll ?
      lazyArea.querySelectorAll("video") :
      lazyArea.getElementsByTagName("video");
    for (var i = lazyVideos.length; i--;) {
      var lazyVideo = lazyVideos[i];
      var cantPlay = true;
      if (lazyVideo.canPlayType) {
        //Loop through the various source elements, and check if
        //the browser thinks it can play them
        //This works better if we specify the codec along with
        //the MIME type
        var sources = lazyVideo.getElementsByTagName("source");
        for (var i2 = sources.length; i2--;) {
          if (lazyVideo.canPlayType(sources[i2].type)) {
            cantPlay = false;
            break;
          }
        }
      }
      //If on a low-data connection, remove the autoplay attribute
      //(it's only polite)
      if (lowData) {
        lazyVideo.removeAttribute("autoplay");
        lazyVideo.setAttribute("controls", "");
      }
      //If you can't play any of the available formats, skip straight to fallback content
      if (cantPlay) {
        //Extract the fallback and replace the video with it
        var children = lazyVideo.childNodes;
        for (var i3 = children.length; i3--;) {
          var childNode = children[i3];
          if (childNode.tagName !== "TRACK" && childNode.tagName !== "SOURCE") {
            insertAfter(childNode, lazyVideo);
          }
        }
        lazyVideo.parentNode.removeChild(lazyVideo);
      }
    }
  }
  /**
   * Retrieve the elements from the 'lazy load' noscript tags and prepare them for display
   */
  function setUp() {
    //Get all the noscript tags on the page
    var lazyLoadAreas = document.getElementsByTagName("noscript");
    var supportsTemplates = typeof HTMLTemplateElement === "function";
    for (var i = lazyLoadAreas.length; i--;) {
      var noScriptTag = lazyLoadAreas[i];
      //only process the ones marked for lazy loading
      if (!noScriptTag.hasAttribute("data-lazy-load")) continue;
      // The contents of a noscript tag are treated as text to JavaScript
      var lazyAreaHtml = noScriptTag.textContent || noScriptTag.innerHTML;
      // So we stick them in the innerHTML of a new div tag to 'load' them
      var lazyArea;
      if (supportsTemplates) {
        //(if possible, templates are better as they won't start any network calls)
        var lazyTemplate = document.createElement("template");
        lazyTemplate.innerHTML = lazyAreaHtml;
        lazyArea = lazyTemplate.content;
      } else {
        lazyArea = document.createElement("div");
        lazyArea.innerHTML = lazyAreaHtml;
      }
      setVideoFallback(lazyArea);
      noScriptTag.parentNode.replaceChild(lazyArea, noScriptTag);
    }
  }
  //If the page has loaded already, run setup - if it hasn't, run as soon as it has.
  if (document.readyState !== "loading") {
    setUp();
  } else {
    document.addEventListener("DOMContentLoaded", setUp);
  }
})();
<main>
  <figure>
    <!--[if !IE]><!-->
    <noscript data-lazy-load>
			<video height="338" width="600" autoplay loop muted>
				<!--<source src="./Sample.mp4"	type="video/mp4; codecs=avc1.42E01E,mp4a.40.2">-->
				<source src="http://dl3.webmfiles.org/big-buck-bunny_trailer.webm" type="video/webm; codecs=vp8,vorbis">
				<source src="https://upload.wikimedia.org/wikipedia/commons/0/07/Backgammon_example.ogv"	type="video/ogg; codecs=theora,vorbis">
				<!--<![endif]-->
				<img src="https://media2.giphy.com/media/BfbUe877N4xsUhpcPc/giphy.gif?cid=790b76115cadcffa59306b73776453f3" height="360" width="480"/>
				<!--[if !IE]><!-->
			</video>
		</noscript>
    <!--<![endif]-->
    <figcaption>
      A bunny emerging from his den and stretching.
      <!--[if !IE]><!-->
      <noscript aria-hidden="true"><p>
        Note: Without JavaScript, the above animation might not play. In that case, the animation can be directly accessed
			  <a href="./giphy.gif">here</a>.
      </p></noscript>
      <!--<![endif]-->
    </figcaption>
  </figure>
</main>

使用 canPlayType 函数,我们询问浏览器是否认为它可以播放任何源类型。如果没有,我们会提取后备内容。

我们将视频封装在 noscript 标记中,以便在我们运行脚本之前它不会开始加载(除非脚本被禁用,这是所需的行为)。

我们也用IE条件标签,因为oldIE不能用script读取noscript标签的内容。

(已在 Edge、Firefox、Chrome 和 IE 的所有兼容模式下测试。Webm 显示在所有浏览器栏中 IE 中,其中显示了每种兼容模式下的 GIF。)

【讨论】:

    【解决方案3】:

    @Jaw.sh 有两个常用的备用选项。

    1. Fallback to Flash version of the video.
    2. Fallback to a direct download of the video.

    今天的浏览器(Opera 我不确定也不太关心)都可以播放MP4 H.264。所以你不应该太担心不兼容,除非你的大部分观众都住在中国。

    【讨论】:

    • 您应该阅读第一个链接的已接受答案下的评论:“请记住,Flash 后备将永远不会在 HTML5 浏览器中使用,即使它们无法原生阅读视频”和第二个链接:“如果浏览器不支持 html5(某些移动设备),则使用直接链接回退:”。 OP 想知道是否没有识别源类型,因此它假定浏览器确实支持videoElement
    • Flash 可以在任何非移动浏览器中播放,只要它们具有无处不在的 Adob​​e 插件。是的,手机不做直接下载,同意。所以让我重新阅读这个问题......是的,OP没有提到移动设备。让我拿上我的老花镜……不,还没有看到顺便提过。移动是一组完全不同的复杂性,OP 担心诸如后备之类的基本问题。
    • 不,我的意思是,如果浏览器确实支持 &lt;video&gt; 元素,那么那些后备,无论是文本还是 Flash 或任何你喜欢的,都不会被浏览器解析。因此,如果由于给定源中没有支持的媒体而需要回退,但浏览器确实支持 &lt;video&gt; 元素,则这些回退将不起作用。
    • 在那种情况下,JW Player 是一个明智的选择,但除了 Chromium(一个不稳定的开发者版本),还有什么浏览器不呈现视频标签? IE 8 及以下?
    • 这与问题无关,但是是的,IEan interesting reading for you)
    【解决方案4】:

    the specs 中提到了一种回退方式。

    “监听最后一个源元素的错误事件并触发回退行为”

    <div>
     <video width="400" controls>
      <source src="mov_bbb.mp4" type="video/mp4">
      <source src="mov_bbb.ogg" type="video/ogg"
             onerror="parentNode.parentElement.innerText = 'Your browser does not support the video codec' ">
     </video>
    </div>
    

    【讨论】:

      猜你喜欢
      • 2014-05-20
      • 1970-01-01
      • 2013-05-10
      • 2014-03-03
      • 2011-12-16
      • 1970-01-01
      • 1970-01-01
      • 2012-09-18
      • 1970-01-01
      相关资源
      最近更新 更多