当所有类型都不支持时,使用HTML5视频回退

10
在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文件。

在HTML5视频中没有可用视频源时,是否有一种方式进行回退?我知道我尝试的回退仅适用于旧浏览器,但我仍然需要一种没有可用源的回退。


2
回退仅在不支持_HTML5 <video> 元素本身_时显示,而不是其中的视频类型。 - Sebastian Simon
1
@Xufox 我明白这一点,但如果它无法呈现任何源代码,我仍然需要一种回退的方法。 - Josh
2
使用canPlayType怎么样? - Sebastian Simon
1
如果无法加载源,则该元素无法处理此问题。 - Rob
4个回答

13

实际上,当您尝试在<source>元素中加载不支持的媒体类型时,将会触发一个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
@Sora2455 你是什么意思?我现在在FF上,这段代码片段完美地运行,显示消息“找不到支持的媒体和MIME类型的视频”。 - Kaiido
抱歉,我将事件处理程序附加到了视频标签而不是源标签。我的错。 - Sora2455
然而,当我在IE11和Edge 18中运行上述示例时,它会保留视频标签。IE似乎在视频标签上触发错误事件,而Edge似乎根本不触发它。 - Sora2455
这个救了我的一天,对我很有效。 - Garima Jain

2
规格说明中提到了一种回退的方法。
“监听最后一个源元素上的错误事件并触发回退行为。”
<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>

1

对于此事,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条件标记,因为旧版IE无法读取带有脚本的noscript标记的内容。
(在Edge、Firefox、Chrome以及IE的每个兼容模式下进行测试。Webm在除IE外的所有浏览器中显示,而IE在每个兼容模式下都显示GIF。)

0

1
你应该阅读第一个链接下被接受的答案下面的评论:“请记住,即使HTML5浏览器无法本地读取视频,Flash回退也永远不会被使用”,以及第二个链接中的“如果浏览器不支持html5(某些移动设备),则使用直接链接回退:”。OP想知道是否没有识别到任何源类型,因此假定浏览器支持videoElement - Kaiido
Flash可以在任何非移动浏览器中播放,只要它们具有普遍存在的Adobe插件。是的,移动设备不支持直接下载,这点我们同意。所以让我重新阅读一下问题...是的,楼主没有提到移动设备。让我戴上我的读眼镜...还是没有看到它被提及。移动设备是一个完全不同的复杂性问题,而楼主担心的是像回退这样的基本问题。 - zer00ne
2
不,我的意思是,如果浏览器支持<video>元素,则无论您使用文本、Flash或其他任何东西作为后备选项,浏览器都不会解析它们。因此,如果需要后备选项,因为给定源中没有受支持的媒体,但是浏览器支持<video>元素,则这些后备选项将无法起作用。 - Kaiido
在这种情况下,JW Player是一个不需要考虑的选择,但除了Chromium(一个不稳定的开发者版本)之外,还有哪些浏览器不能渲染视频标签?IE 8及以下版本? - zer00ne
是的,Mozilla 一度坚持不使用 H.264,但最终屈服了。对我来说,这是一次文艺复兴,我不再被这个问题所困扰。所以,我把媒体的神秘方面留给您,先生。 :) - zer00ne
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接