整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

洞察 video 超能力系列-玩转 mp4

技术提升美好事物发生的概率。Technologically, for greater probability to be happy

前言

只要在 HTML5 中使用过视频播放的同学对 video 标签一定不会陌生,不过很多同学只使用了 video 的基础功能,实际上 video 拥有强大潜能的,只要姿势正确就能让其拥有超能力。不妨从下面几个场景来逐渐了解下video 未曾被发掘的神秘空间:

  • 清晰度无缝切换
  • 节省视频流量

清晰度无缝切换

点播领域里 mp4 是最普遍、兼容性最好的视频容器,不过 mp4 也有它的局限性,比如常见的清晰度切换,我们是无法像youtube那样做到无缝切换的。我们可以看下普通的mp4播放的网络请求和youtube视频播放的网络请求的区别。

图1.1 普通mp4的下载请求过程

图1.2 Youtube视频下载请求过程

这两张图不难看出,在默认情况下 mp4 使用一次 http 请求所有的视频数据,Youtube 则分次请求。当然这个描述很不专业,但确实形象。造成这种差异的是 video 不支持流式的视频数据,Youtube 采用的是流式的视频容器 webm,而 mp4 是非流式的。那如何解释清楚流式的视频数据呢,从专业的角度三言两语很难说清楚,但用大白话翻译过来就是流式的视频数据支持分段独立播放,非流式的不可以。换句话说一个10M的视频文件,流式的视频可以把0~1M的数据请求回来单独播放,但是非流式的不可以。

上面我们描述了视频格式的不同,接下来我们要说的是第一张图中的视频加载是浏览器来控制的,通过给 video 的 src 属性配置视频地址,触发播放之后浏览器就会开始下载了,JS干涉不了。而 Youtube 的视频加载是通过JS来控制的,各位可以再次看下第二张图的网络请求类型:xhr,足以证明这一点。

上面两点搞清楚之后我们就该说下清晰度切换的事情了。这个需求大家都不陌生,但是直接使用 mp4 格式做无缝清晰度切换,难度还挺大的。先解释下“无缝清晰度切换”的概念:从播放一个分辨率的视频到另一个分辨率且保证画面、声音不停顿的平滑切换过程。了解了这个概念,大家应该知道了用 video 无缝切换 mp4 有多难。一方面,video 是不支持流式的视频格式的,一方面,video 的加载是不受JS控制的。通过切换 video 的 src 属性,必然会导致画面中断、重新请求视频数据等。有的同学想到说利用两个 video 再结合 z-index 来搞,但是当你生成另一个video去加载视频的时候,无法保证两个画面是严格一致的,即使将原来的画面暂停到一个时刻,用另一个视频通过 currentTime 属性与之同步,切换仍然看到画面闪烁,基本无法和 Youtube 无缝切换的体验匹敌。而且还会造成更多流量的浪费,背后的原因大家可以研究下 mp4 容器和 webm 容器的异同,也可以看下视频解码相关的文章。

还有一种方法就是将 mp4 格式统统转码到流式的视频格式比如 hls、webm 等。不过这种看上去可行的方式实际上会带来很大的成本开销,如将大量视频做转码会消耗高昂的机器资源、双倍存储的费用、CDN的双倍费用等等。其实我们也是在这种背景下研究出来新的技术问题解决清晰度无缝切换的。

首先,我们改变对 mp4 视频的播放流程,不再直接使用 video 的 src 来播放,因为我们没有任何可以操作的空间。video不仅支持 src 属性还支持 Blob 对象,我们就是利用后者。播放的流程如下:

图1.3 mp4 视频新播放流程

  1. 来请求 mp4 视频数据,这样可以结合视频 Range 服务,做到精确加载。
  2. 编写解析器将加载回来的部分 mp4 视频数据进行解复用
  3. 将解复用的视频数据转成 fmp4 格式并传递给 MediaSource
  4. 使用 video 进行解码完成播放

然后在做清晰度切换的时候流程如下:

图1.4 mp4视频清晰度切换原理示意图

  1. 播放视频A,过程同上
  2. 在某个时刻,用户切换到播放视频B,首先解析B的索引文件(moov),反向计算mp4的range区间
  3. 加载B的视频区间数据
  4. 解复用
  5. 把数据转换成fmp4格式并传递给MediaSource
  6. 删除A的部分Buffer
  7. 在下一个关键帧自动完成画质的切换

图1.5 mp4视频清晰度切换流程示意图

这个过程看上去比较繁琐,但是所有的操作都是在浏览器端完成,也就是说都是JS来实现的。这样之前说的所有成本问题都不存在,还能做到youtube相同体验的无缝切换。如果大家也想使用这个功能不需要自己再去实现一遍上述流程,可以使用如下代码:

如果对这段代码有什么疑惑,或者想深入了解下它背后是如何实现的,可以参考 Github:https://github.com/bytedance/xgplayer 或 阅读原文:https://techblog.toutiao.com/

节省视频流量

使用 video 的同学基本上都是这样用的,如下:

  1. 利用src属性

2.利用source标签

这样就可以播放视频了,不过前面我们讲过这样使用 video ,视频的加载是受浏览器控制的,可以看下浏览器在视频刚开始播放的时候下载了多少数据:

图2.1 video默认下载截图

我随便找了个视频,大家看下视频总长度是 02:08,在播放到 00:05 的时候,浏览器已经下载到 01:30 了,如果用户终止观看,下载的视频就这样被浪费掉了。当然,如果不断的 seek 也会造成较多的流量浪费。按照我们之前的统计在短视频领域,用户 seek 的频率在 80%,所以这部分流量是可以节省掉的。具体原理如下:

图2.2 播放器加载视频原理

  1. 设置每次加载的数据包大小
  2. 设置预加载时长
  3. 开启加载队列,完成第一次数据包下载,判断缓冲时间和预加载时长是否满足,不满足请求下一个数据包

具体实现代码如下:

这样就实现了视频在播放过程中永远只预加载10秒的数据,进而保证节省流量。

扩展链接,了解超能力西瓜视频是怎样炼成的。

多站点都会使用到视频. HTML5 提供了展示视频的标准。

检测您的浏览器是否支持 HTML5 视频:

检测

Web站点上的视频

直到现在,仍然不存在一项旨在网页上显示视频的标准。

今天,大多数视频是通过插件(比如 Flash)来显示的。然而,并非所有浏览器都拥有同样的插件。

HTML5 规定了一种通过 video 元素来包含视频的标准方法。

浏览器支持

Internet Explorer 9+, Firefox, Opera, Chrome, 和 Safari 支持 <video> 元素.

注意: Internet Explorer 8 或者更早的IE版本不支持 <video> 元素。

HTML5 (视频)- 如何工作

如需在 HTML5 中显示视频,您所有需要的是:

实例

<video width="320" height="240" controls>

<source src="movie.mp4" type="video/mp4">

<source src="movie.ogg" type="video/ogg">

您的浏览器不支持Video标签。

</video>

<video> 元素提供了 播放、暂停和音量控件来控制视频。

同时<video> 元素元素也提供了 width 和 height 属性控制视频的尺寸.如果设置的高度和宽度,所需的视频空间会在页面加载时保留。。如果没有设置这些属性,浏览器不知道大小的视频,浏览器就不能再加载时保留特定的空间,页面就会根据原始视频的大小而改变。

<video> 与</video> 标签之间插入的内容是提供给不支持 video 元素的浏览器显示的。

<video> 元素支持多个 <source> 元素. <source> 元素可以链接不同的视频文件。浏览器将使用第一个可识别的格式:

视频格式与浏览器的支持

当前, <video> 元素支持三种视频格式: MP4, WebM, 和 Ogg:

浏览器MP4WebMOgg
Internet ExplorerYESNONO
ChromeYESYESYES
FirefoxYESYESYES
SafariYESNONO
OperaYES (从 Opera 25 起)YESYES
  • MP4 = 带有 H.264 视频编码和 AAC 音频编码的 MPEG 4 文件

  • WebM = 带有 VP8 视频编码和 Vorbis 音频编码的 WebM 文件

  • Ogg = 带有 Theora 视频编码和 Vorbis 音频编码的 Ogg 文件

视频格式

格式MIME-type
MP4video/mp4
WebMvideo/webm
Oggvideo/ogg

HTML5 <video> - 使用 DOM 进行控制

HTML5 <video> 和 <audio> 元素同样拥有方法、属性和事件。

<video> 和 <audio>元素的方法、属性和事件可以使用JavaScript进行控制.

其中的方法有用于播放、暂停以及加载等。其中的属性(比如时长、音量等)可以被读取或设置。其中的 DOM 事件能够通知您,比方说,<video> 元素开始播放、已暂停,已停止,等等。

例中简单的方法,向我们演示了如何使用 <video> 元素,读取并设置属性,以及如何调用方法。

实例 1

为视频创建简单的播放/暂停以及调整尺寸控件:

播放/暂停 放大 缩小 普通

上面的例子调用了两个方法:play() 和 pause()。它同时使用了两个属性:paused 和 width。

HTML5 Video 标签

标签描述
<video>定义一个视频
<source>定义多种媒体资源,比如 <video> 和<audio>
<track>定义在媒体播放器文本轨迹

.标签

1.1meta标签

meta主要用于设置网页中的一些元数据,元数据不是给用户看 charset 指定网页的字符集 name 指定的数据的名称 content 指定的数据的内容

keywords 表示网站的关键字,可以同时指定多个关键字,关键字间使用,隔开

<meta name="Keywords" content="网上购物,网上商城,手机,笔记本,电脑,MP3,CD,VCD,DV,相机,数码,配件,手表,存储卡,京东"/>

description 用于指定网站的描述

<meta name="description" content="京东JD.COM-专业的综合网上购物商城,销售家电、数码通讯、电脑、家居百货、服装服饰、母婴、图书、食品等数万个品牌优质商品.便捷、诚信的服务,为您提供愉悦的网上购物体验!"/>
<meta http-equiv="refresh" content="3;url=https://www.mozilla.org">

将页面重定向到另一个网站

1.2title标签

title标签的内容会作为搜索结果的超链接上的文字显示

<title>Document</title>

1.3标题

  • h1 ~ h6 一共有六级标题
  • 从h1~h6重要性递减,h1最重要,h6最不重要
  • h1在网页中的重要性仅次于title标签,一般情况下一个页面中只会有一个h1
  • 标题元素是块元素
  • <h1>一级标题</h1>
    <h2>二级标题</h2>
    <h3>三级标题</h3>
    <h4>四级标题</h4>
    <h5>五级标题</h5>
    <h6>六级标题</h6>

  • hgroup标签用来为标题分组,可以将一组相关的标题同时放入到hgroup
  • <hgroup>
    <h1>回乡偶书二首</h1>
    <h2>其一</h2>
    </hgroup>
  • 其他标签
    • p标签表示页面中的一个段落
    • <p>在p标签中的内容就表示一个段落</p>
    • em标签用于表示语音语调的一个加重
    • <p>今天天气<em></em>不错!</p>
    • strong表示强调,重要内容!
    • <p>你今天必须要<strong>完成作业</strong></p>
    • blockquote 表示一个长引用
    • <blockquote>
      这句话我是从来没有说过的!
      </blockquote>
    • q表示一个短引用
    • 子曰<q>学而时习之,乐呵乐呵!</q>
    • br标签表示页面中的换行
    • <br>

1.4布局标签

header 表示网页的头部 main 表示网页的主体部分(一个页面中只会有一个main) footer 表示网页的底部 nav 表示网页中的导航 aside 和主体相关的其他内容(侧边栏) article 表示一个独立的文章 section 表示一个独立的区块,上边的标签都不能表示时使用section

div 没有语义,就用来表示一个区块,目前来讲div还是我们主要的布局元素

span 行内元素,没有任何的语义,一般用于在网页中选中文字

<header></header>
    <main></main>
    <footer></footer>

    <nav></nav>
    <aside></aside>
    <article></article>

    <section></section>

    <div></div>

    <span></span>

1.5列表

1.1.1分类

1.1.1.1有序列表

使用ol标签来创建无序列表,使用li表示列表项

<ul>
       <li>结构</li>
       <li>表现</li>
       <li>行为</li>
   </ul>

1.1.1.2 无序列表

使用ul标签来创建无序列表,使用li表示列表项

<ol>
       <li>结构</li>
       <li>表现</li>
       <li>行为</li>
   </ol>

1.1.1.3定义列表

使用dl标签来创建一个定义列表, 使用dt来表示定义的内容,使用dd来对内容进行解释说明

<dl>
       <dt>结构</dt>
       <dd>结构表示网页的结构,结构用来规定网页中哪里是标题,哪里是段落</dd>
       <dd>结构表示网页的结构,结构用来规定网页中哪里是标题,哪里是段落</dd>
       <dd>结构表示网页的结构,结构用来规定网页中哪里是标题,哪里是段落</dd>
   </dl>

1.1.1.4列表之间可以互相嵌套

<ul>
       <li>
          aa
           <ul>
               <li>aa-1</li>
               <li>aa-2
                   <ul>
                       <li>aa-1</li>
                       <li>aa-2</li>
                   </ul>
               </li>
           </ul>
       </li>
   </ul>

1.6超链接

1.6.1 作用

超链接可以让我们从一个页面跳转到其他页面, 或者是当前页面的其他的位置

1.6.2 定义

使用 a 标签来定义超链接

<a href="https://www.baidu.com">超链接</a>

1.6.3 属性

1.6.3.1属性1:href

指定跳转的目标路径

值可以是一个外部网站的地址

也可以写一个内部页面的地址

超链接是也是一个行内元素,在a标签中可以嵌套除它自身外的任何元素

1.6.3.2 属性2:target

用来指定超链接打开的位置

_self 默认值 在当前页面中打开超链接

_blank 在一个新的要么中打开超链接

<a href="07.列表.html" target="_blank">超链接</a>

1.6.4其他

将#作为超链接的路径的展位符使用

javascript:; 来作为href的属性,此时点击这个超链接什么也不会发生

将超链接的href属性设置为#,这样点击超链接以后 页面不会发生跳转,而是转到当前页面的顶部的位置

跳转到页面的指定位置,只需将href属性设置 #目标元素的id属性值

<a href="#bottom">去底部</a>
   <br><br>
<a href="#p3">去第三个自然段</a>
   <br><br>
<p>
  内容多一点
</p>
<a href="#">这是一个新的超链接</a>
   <br><br>
<a href="javascript:;">这是一个新的超链接</a>
   <br><br>
<a id="bottom" href="#">回到顶部</a>

1.7图片标签

img标签来引入外部图片,img标签是一个自结束标签

属性:src 属性指定的是外部图片的路径(路径规则和超链接是一样的)

alt 图片的描述,这个描述默认情况下不会显示,有些浏览器会图片无法加载时显示

<img src="./img/1.gif" alt="松鼠">

1.8内联框架

用于向当前页面中引入一个其他页面

  • src 指定要引入的网页的路径
  • frameborder 指定内联框架的边框
<iframe src="https://www.qq.com" width="800" height="600" frameborder="0"></iframe>

1.8 音视频标签

1.8.1音频

audio 标签用来向页面中引入一个外部的音频文件的

1.8.1.1 属性

  • controls 是否允许用户控制播放
  • autoplay 音频文件是否自动播放
    • 如果设置了autoplay 则音乐在打开页面时会自动播放
  • loop 音乐是否循环播放
<audio src="./source/audio.mp3" controls autoplay loop></audio>

除了通过src来指定外部文件的路径以外,还可以通过source来指定文件的路径

<audio controls>
       <!-- 对不起,您的浏览器不支持播放音频!请升级浏览器!-->
       <source src="./source/audio.mp3">
       <source src="./source/audio.ogg">
       <embed src="./source/audio.mp3" type="audio/mp3" width="300" height="100">
   </audio>

1.8.2视频

与 audio 相似

<video controls>
       <source src="./source/flower.webm">
       <source src="./source/flower.mp4">
       <embed src="./source/flower.mp4" type="video/mp4">
   </video>


2.表格table

  • 在table中使用tr表示表格中的一行,有几个tr就有几行
  • 在tr中使用td表示一个单元格,有几个td就有几个单元格
  • rowspan 纵向的合并单元格
  • colspan 横向的合并单元格
<table border="1" width='50%' align="center">
      <tr>
          <td>A1</td>
          <td>B1</td>
          <td>C1</td>
          <td>D1</td>
      </tr>
      <tr>
          <td>A2</td>
          <td>B2</td>
          <td>C2</td>
          <td rowspan="2">D2</td>
      </tr>
      <tr>
          <td>A3</td>
          <td>B3</td>
          <td>C3</td>
      </tr>
      <tr>
          <td>A4</td>
          <td>B4</td>
          <td colspan="2">C4</td>
      </tr>
  </table>

长表格

  • 可以将一个表格分成三个部分:
    • 头部 thead
    • 主体 tbody
    • 底部 tfoot
  • th 表示头部的单元格
<table border="1" width='50%' align="center">  
      <thead>
          <tr>
              <th>日期</th>
              <th>收入</th>
              <th>支出</th>
              <th>合计</th>
          </tr>
      </thead>
      <tbody>
          <tr>
              <td>2000.1.1</td>
              <td>500</td>
              <td>200</td>
              <td>300</td>
          </tr>
          <tr>
              <td>2000.1.1</td>
              <td>500</td>
              <td>200</td>
              <td>300</td>
          </tr>
          <tr>
              <td>2000.1.1</td>
              <td>500</td>
              <td>200</td>
              <td>300</td>
          </tr>
          <tr>
              <td>2000.1.1</td>
              <td>500</td>
              <td>200</td>
              <td>300</td>
          </tr>
      </tbody>
      <tfoot>
          <tr>
              <td></td>
              <td></td>
              <td>合计</td>
              <td>300</td>
          </tr>
      </tfoot>

  </table>

表格样式

  • border-spacing: 指定边框之间的距离
border-spacing: 0px;
  • border-collapse: collapse; 设置边框的合并
border-collapse: collapse;
  • 如果表格中没有使用tbody而是直接使用tr,那么浏览器会自动创建一个tbody,并且将tr全都放到tbody中tr不是table的子元素

3.表单(form)

  • 使用form标签来创建一个表单
  • action 表单要提交的服务器的地址
  • 数据要提交到服务器中,必须要为元素指定一个name属性值
<input type="text" name="username">
  • 单选按钮
    • 像这种选择框,必须要指定一个value属性,value属性最终会作为用户的填写的值传递给服务器
    • checked 可以将单选按钮设置为默认选中
<input type="radio" name="hello" value="a">
<input type="radio" name="hello" value="b" checked>
  • 多选框
<input type="checkbox" name="test" value="1">
      <input type="checkbox" name="test" value="2">
      <input type="checkbox" name="test" value="3" checked>
  • 下拉列表
<select name="haha">
          <option value="i">选项一</option>
          <option selected value="ii">选项二</option>
          <option value="iii">选项三</option>
      </select>
  • 提交按钮
<input type="submit" value="注册">

属性

  • autocomplete="off" 关闭自动补全
  • readonly 将表单项设置为只读,数据会提交
  • disabled 将表单项设置为禁用,数据不会提交
  • autofocus 设置表单项自动获取焦点
<form action="target.html">
      <input type="text" name="username" value="hello" readonly>
      <br><br>
      <input type="text" name="username" autofocus>
      <br><br>
      <input type="text" name="b">

      <br><br>

      <!-- <input type="color"> -->
      <br><br>
      <!-- <input type="email"> -->
      <br><br>

      <input type="submit">
      <!-- 重置按钮 -->
      <input type="reset">
      <!-- 普通的按钮 -->
      <input type="button" value="按钮">

      <br><br>
       

      <button type="submit">提交</button>
      <button type="reset">重置</button>
      <button type="button">按钮</button>
  </form>

4.注释

<!--
我是注释中的注释 注释不能嵌套
-->

5.属性

  • 属性,在标签中(开始标签或自结束标签)还可以设置属性
  • 属性是一个名值对(x=y)
  • 属性用来设置标签中的内容如何显示
  • 属性和标签名或其他属性应该使用空格隔开
  • 属性不能瞎写,应该根据文档中的规定来编写,有些属性有属性值,有些没有。如果有属性值,属性值应该使用引号引起来

6.文档声明

<!doctype html>