整合营销服务商

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

免费咨询热线:

拉流端直播xgplayer使用经验

、背景介绍

为了强化官方验的心智,平台要做一版新的质检直播间,将我们的质检车间全方位透明的展现给用户。按照产品的设计来实现的话,其实就是将各个镜头的内容同时在一个页面内进行播放,除了工作时间的直播,还有休息时间的录播播放。不过直播和录播的生成都是在后端实现,前端只负责视频资源的播放。

二、前期调研

对于简单的直播场景,我们需要关注的主要是「编解码格式」「直播协议」,因为这两点直接决定直播能否播放。

「编解码格式:」视频的编码方式决定了视频的压缩方式,同样的需要对应的解码格式才能正常播放视频。但视频编码这个过程是在推流端做的,通常会采用H.264,目前基本上所有的播放器和浏览器都支持该解码方式,其兼容性基本不用考虑;所以虽然视频的编解码格式很重要,但只要没有特殊的场景如4k,一般无需过多考虑。

「拉流端直播协议:」不同的直播协议,其兼容性和直播效果有一些差异,而前端对兼容性的差异是敏感的,所以对于Web端,尽量选择兼容性最佳的HLS。

以下是我了解到的不同直播协议的特点及他们的优劣势:

「RTMP」

特点/优点:

1.基于TCP长连接,不需要多次建连,延时低,通常只有1~3s;2.技术成熟,配套完善。

缺点:

1.兼容性差,需要依赖flash,因此无法在移动端使用。2.容易被防火墙拦截。

「HLS」

特点/优点:

1.其工作原理是切片式传输,把直播流切成无数片,用户在观看视频时,每次客户端可以只下载一部分;2.基于 HTTP协议,所以接入CDN较为容易,很少被防火墙拦下;3.自带多码率自适应;4.几乎支持所有设备;

缺点:

1.延时较大,通常不低于10s;2.大量的TS片文件,会造成服务器存储和请求的压力;

「HTTP-FLV」

特点/优点:

1.把音视频数据封装成FLV,然后通过HTTP连接传输,与RTMP相比只是传输协议变了,能有效避免防火墙和代理的影响;2.低延时,整体效果与RTMP非常接近;

缺点:

1.它的传输特性会让流媒体资源缓存在本地客户端,保密性较差;2.不支持IOS;

三、为什么使用xgPlayer

在确定了我所需要使用的直播协议后,我调研了一些社区推荐的播放器:tcplayer.js、xgplayer、DPlayer、plyr、ArtPlayer.js、Video.js。

其实以上的播放器在功能上都可以满足我的需求,并且也都支持H.264编码格式;在直播能力的支持上也都会在底层依赖hls.js,flv.js,不过像tcplayer和xgplayer还单独包了一层,使得直播的实现更加的符合播放器的体系;

在我所调研的播放器里xgPlayer的文档是最清晰和完善的,并且xgPlayer使用插件机制,所有功能均可插拔,而且支持自定义扩展能力,十分方便,所以在开发体验上我认为更胜一筹。

四、基本使用

1.初始化

import Player from 'xgplayer'
import FlvPlugin from 'xgplayer-flv'
import "xgplayer/dist/index.min.css"

new Player({
    id:'dom-id', // 播放器实例化所需的dom
   url: 'test.flv', // 视频源
    width: '100%',
   height: '100%'
})

2.多实例

初始化时可以使用选择器id或容器el。但对于同时实例化多个播放器的场景,使用Id很容易导致最终只实例化成功一个,虽然你可以通过ID+索引的方式避免,但使用容器el还是更为简洁的。

<div ref="playerRef"></div>

const playerRef = ref()

new Player({
    el: playerRef.value,
		...
})

3.常用属性

new Player({
   poster // 封面
  autoplay // 自动播放,基本上不支持有声自动播放;
  autoplayMuted // 自动静音播放,需要自动播放可使用改属性
  playsinline // 对于移动 Safari 浏览器来说是必需的,它允许视频播放时不强制全屏模式
  loop // 循环播放
  fitVideoSize // 根据视频内容调整容器宽高
  videoFillMode // 视频画面填充模式
  controls // 是否展示进度条
  videoAttributes // 透传给video标签的属性 
})

关于自动播放的限制还是很多的,所以把预期降低到大部分设备可以静音播放即可...

关于自动播放

4.直播能力

「FLV协议:」使用xgplayer-flv,可用于PC、安卓。

import FlvPlugin from 'xgplayer-flv'
if (FlvPlugin.isSupported()) { // 第一步,检测当前环境是否支持
    const player = new Player({
        id: 'dom-id',
        url: 'test.flv', // flv 流地址
        isLive: true,
        plugins: [FlvPlugin] // 第二步
    })
}

「HLS协议:」使用xgplayer-hls,可用于PC、安卓、IOS(ios&部分andr不需要插件,原生支持)。

在原生支持hls的情况下尽可能不使用xgplayer-hls,IOS浏览器原生即支持hls格式播放,但是缺少xgplayer-hls运行所需的Media Source Extensions。

import Player from 'xgplayer'
import HlsPlugin from 'xgplayer-hls'

let player
if (document.createElement('video').canPlayType('application/vnd.apple.mpegurl')) {
    // 原生支持 hls 播放
    player = new Player({
        el: document.querySelector('.player'),
        url: 'test.m3u8'
    })
} else if (HlsPlugin.isSupported()) { // 第一步,检测当前环境是否支持
    player = new Player({
        el: document.querySelector('.player'),
        isLive: true,
        url: 'test.m3u8', // hls 流地址
        plugins: [HlsPlugin] // 第二步
    })
}

5.样式自定义

xgplayer提供了十分便捷的方式去配置icon。

const playerConfig = {
  icons: {
    // 1.通过function方式 返回一个dom
    play: () => {
      const dom = Util.createDom('div', '<img src="./start"/>', {}, 'customclass')
      return dom
    },
    // 2.直接html代码
    pause: `<div class='customclass'><img src="./start"/></div>`,
    // 3.直接一张图片链接
    startPlay: 'https://xxx.zhuanzhuan.com/xxx.png'
  }
}

但是很多地方的icon大小尺寸是固定死的,如果想要修改还是要去覆盖xgplayer默认的样式

image-20231123163802551

6.自定义插件

xgplayer支持插件的扩展机制,无论是简单的功能按钮还是复杂的播放逻辑都可以通过插件的形式来实现。

这里实现一个简单的插件,结合我们的通用组件库,用于在视频暂停时,展示一些提示。

// demoPlugin.js
import Vue from 'vue'
import { Events, Plugin } from 'xgplayer'
import Demo from './demoPlugin.vue'
const { POSITIONS } = Plugin

export default class DemoPlugin extends Plugin {
  // 插件的名称,将作为插件实例的唯一key值
  static get pluginName() {
    return 'demoPlugin'
  }
  static get defaultConfig() {
    return {
      // 挂载在播放器最上方
      position: POSITIONS.ROOT_TOP
    }
  }
  constructor(args) {
    super(args)
    this.vm = null
  }
  // 插件实例化之后
  afterCreate() {
   // 使用vue组件
    const Component = Vue.extend(Demo)
    this.vm = new Component().$mount('.demo-plugin')
  // 视频播放时
    this.on(Events.PLAY, () => {
      this.vm.hide()
    })
  // 视频暂停时
    this.on([Events.PAUSE], () => {
      this.vm.show()
    })
  }
  destroy() {
    // 播放器销毁的时候一些逻辑
  }
  render() {
    return '<div class="demo-plugin"></div>'
  }
}
// demoPlugin.vue
<template>
  <NoticeBar v-show="visible" swipe>
    <span style="padding-right: 50px;">我一定会回来的~我一定会回来的~我一定会回来的~</span>
  </NoticeBar>
</template>
<script setup lang="ts">
import { ref, defineExpose } from 'vue'
import { NoticeBar } from '@zz-common/zz-ui';

const visible = ref(true)

const show = () => {
  visible.value = true
}
const hide = () => {
  visible.value = false
}
defineExpose({
  show,
  hide
})
</script>
// 使用
import DemoPlugin from './demoPlugin.js'
...
new Player({
  ...,
  plugins: [DemoPlugin]
})

image

五、遇到的问题

1.事件监听相关

在播放器的事件中有两个与播放操作相关的事件——play、canplay

「play」表示播放已开始。

「canplay」表示浏览器可以播放媒体文件了,但估计没有足够的数据来支撑播放到结束,不必停下来进一步缓冲内容。

简单区分下这两个事件:play可以具象的理解为点击播放按钮或者自动播放成功,canplay则表示视频资源已经开始加载并缓冲了一部分数据达到了启播的条件。

这两个事件的先后顺序不固定——如果没有设置自动播放、也没有设置预加载,那应该是play、canplay。如果设置了预加载,但没有设置自动播放,则应该是canplay、play,到目前按照事件的定义来看,还是能抓住一些规律的。但是呢经过我测试发现,同样的设置,在原生video标签和xgplayer上执行顺序不同。另外在不同的操作系统上也会导致执行顺序不同,比如 ios Safari 从不预加载导致无法在未播放时触发canplay事件。所以十分不建议根据这两个事件的执行时机来做一些事(不过目前也想不到这种场景,只是无意中发现的)

2.跨域问题

问题的起因是当时的直播流内容总是会间隔性的黑屏,而且后端无法监控到并调整视频源。于是需要前端通过截取画面并分析截图的像素点来判断是否黑屏,以实现黑屏自动切换视频源的能力。

但是当通过canvas获取图片数据时getImageData报了一个SecurityError异常。

经查阅发现这是浏览器的安全策略,不通过CORS使用其他来源的资源,会污染画布。

在"被污染"的 canvas 中调用以下方法将会抛出安全错误:

  • canvas 的上下文上调用getImageData()
  • canvas元素本身调用toBlob()toDataURL()captureStream()

所以如果要对视频内容进行截图或者对视频画面做一些操作处理,需要给video标签设置crossOrigin属性,在xgplayer中可以通过videoAttributes属性传入。

const player = new Player({
  ...,
  videoAttributes: {
    crossOrigin: 'anonymous'
  }
})

3.内存溢出

当不需要播放器时,记得及时销毁,否则可能会导致内存溢出。(尤其是多实例、切换播放的场景)

player.destroy() // 销毁播放器
player = null // 将实例引用置空

「无需单独销毁插件实例,xgplayer自动会帮我们执行该操作。」—— xgplayer将所有注册的插件维护在pluginGroup对象中,当我们调用播放器的destroy方法时,遍历所有插件并依次执行插件的销毁方法。

image

image

image

4.兼容性问题???

在测试的时候发现,iPhone 14Pro机型,直播播放的时候,如果跳转到其他页面,再返回到直播页,会导致视频播放错误;该问题暂时没有思路,不清楚原因...

目前的解决办法是,在页面不可见时,记录并销毁该播放器,在页面展现时再重新实例化之前的播放器。

六、最终效果

目前线上正常运行,暂时没有发现其他问题。

七、参考资料

1.允许图片和 canvas 跨源使用(https://developer.mozilla.org/zh-CN/docs/Web/HTML/CORS_enabled_image)

2.西瓜播放器(https://h5player.bytedance.com/guide/)

3.Safari HTML5 Audio and Video Guide(https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/AudioandVideoTagBasics/AudioandVideoTagBasics.html)


作者:杨双星

来源:微信公众号:大转转FE

出处:https://mp.weixin.qq.com/s/Q7XZIOLH-nSYtZ4F6MKs8w

前,视频直播(尤其是移动端的视频直播)已经火到不行了,基本上各大互联网公司都有了自己的直播产品,所以对于我们而言,了解直播的一些基本知识和主要技术点是有必要的。

一、移动视频直播发展

可以看到,直播从 PC 到一直发展到移动端,越来越多的直播类 App 上线,同时移动直播进入了前所未有的爆发阶段,但是对于大多数移动直播来说,还是要以 Native 客户端实现为主,但是 HTML5 在移动直播端也承载着不可替代的作用,例如 HTML5 有着传播快,易发布的优势,同时最为关键的时 HTML5 同样可以播放直播视频。

二、直播流程

完整的直播可以分为以下几块:

  1. 视频录制端:一般是电脑上的音视频输入设备或者手机端的摄像头或者麦克风,目前以移动端的手机视频为主。

  2. 视频播放端:可以是电脑上的播放器,手机端的 Native 播放器,还有就是 HTML5 的 video 标签等,目前还是已手机端的 Native 播放器为主。

  3. 视频服务器端:一般是一台 nginx 服务器,用来接受视频录制端提供的视频源,同时提供给视频播放端流服务。

流程如下:

三、直播协议

1、HLS

HLS 全称是 HTTP Live Streaming。这是 Apple 提出的直播流协议。目前,IOS 和 高版本 Android 都支持 HLS。

那什么是 HLS 呢?

HLS 主要的两块内容是 .m3u8 文件和 .ts 播放文件。接受服务器会将接受到的视频流进行缓存,然后缓存到一定程度后,会将这些视频流进行编码格式化,同时会生成一份 .m3u8 文件和其它很多的 .ts 文件。

根据 wiki 阐述,HLS 的基本架构为:

  • 服务器:后台服务器接受视频流,然后进行编码和片段化。

  • 编码:视频格式编码采用 H.264。音频编码为 AAC, MP3, AC-3,EC-3。然后使用 MPEG-2 Transport Stream 作为容器格式。

  • 分片:将 TS 文件分成若干个相等大小的 .ts 文件。并且生成一个 .m3u8 作为索引文件(确保包的顺序)

  • 分发:由于 HLS 是基于 HTTP 的,所以,作为分发,最常用的就是 CDN 了。

  • 客户端:使用一个 URL 去下载 m3u8 文件,然后,开始下载 ts 文件,下载完成后,使用 playback software(即时播放器) 进行播放。

2、RTMP

RTMP 全称为:Real-Time Messaging Protocol 。它是专门应对实时交流场景而开发出来的一个协议。它爹是 Macromedia,后来卖身给了 Adobe。RTMP 根据不同的业务场景,有很多变种:

  • 纯 RTMP 使用 TCP 连接,默认端口为 1935(有可能被封)。

  • RTMPS: 就是 RTMP + TLS/SSL

  • RTMPE: RTMP + encryption。在 RTMP 原始协议上使用,Adobe 自身的加密方法

  • RTMPT: RTMP + HTTP。使用 HTTP 的方式来包裹 RTMP 流,这样能直接通过防火墙。

  • RTMFP: RMPT + UDP。该协议常常用于 P2P 的场景中,针对延时有变态的要求。

3、HLS与RTMP

四、视频录制

关于音视频采集录制,首先明确下面几个概念:

  • 视频编码:所谓视频编码就是指通过特定的压缩技术,将某个视频格式的文件转换成另一种视频格式文件的方式,我们使用的 iPhone 录制的视频,必须要经过编码,上传,解码,才能真正的在用户端的播放器里播放。

  • 编解码标准:视频流传输中最为重要的编解码标准有国际电联的 H.261、H.263、H.264,其中 HLS 协议支持 H.264 格式的编码。

  • 音频编码:同视频编码类似,将原始的音频流按照一定的标准进行编码,上传,解码,同时在播放器里播放,当然音频也有许多编码标准,例如 PCM 编码,WMA 编码,AAC 编码等等,这里我们 HLS 协议支持的音频编码方式是 AAC 编码。

1、HTML5录制视频

对于HTML5视频录制,可以使用强大的 webRTC (Web Real-Time Communication)是一个支持网页浏览器进行实时语音对话或视频对话的技术,缺点是只在 PC 的 Chrome 上支持较好,移动端支持不太理想。

使用 webRTC 录制视频基本流程是:

  1. 调用 window.navigator.webkitGetUserMedia() 获取用户的PC摄像头视频数据。

  2. 将获取到视频流数据转换成 window.webkitRTCPeerConnection (一种视频流数据格式)。

  3. 利用 webscoket 将视频流数据传输到服务端

由于许多方法都要加上浏览器前缀,所以很多移动端的浏览器还不支持 webRTC,所以真正的视频录制还是要靠客户端(iOS,Android)来实现,效果会好一些。

2、iOS录制视频

利用 iOS 上的摄像头,进行音视频的数据采集,主要分为以下几个步骤:

  1. 音视频的采集,iOS 中,利用 AVCaptureSession 和 AVCaptureDevice 可以采集到原始的音视频数据流。

  2. 对视频进行 H264 编码,对音频进行 AAC 编码,在 iOS 中分别有已经封装好的编码库来实现对音视频的编码。

  3. 对编码后的音、视频数据进行组装封包;

  4. 建立 RTMP 连接并上推到服务端。

五、推流

所谓推流,就是将我们已经编码好的音视频数据发往视频流服务器中,在 iOS 代码里面一般常用的是使用 RTMP 推流,可以使用第三方库 librtmp-iOS 进行推流,librtmp 封装了一些核心的 API 供使用者调用。例如推流 API 等等,配置服务器地址,即可将转码后的视频流推往服务器。

那么如何搭建一个推流服务器呢?

简单的推流服务器搭建,由于我们上传的视频流都是基于 RTMP 协议的,所以服务器也必须要支持 RTMP 才行,大概需要以下几个步骤:

  1. 安装一台 nginx 服务器。

  2. 安装 nginx 的 RTMP 扩展,目前使用比较多的是 https://github.com/arut/nginx-rtmp-module

  3. 配置 nginx 的 conf 文件

  4. 重启 nginx,将 RTMP 的推流地址写为 rtmp://ip:1935/hls/mystream, 其中 hls_path 表示生成的 .m3u8 和 ts 文件所存放的地址,hls_fragment 表示切片时长,mysteam 表示一个实例,即将来要生成的文件名可以先自己随便设置一个。

更多配置可以参考:https://github.com/arut/nginx-rtmp-module/wiki/

下面是 nginx 的配置文件

六、播放视频

对于视频播放,可以使用 HLS(HTTP Live Streaming)协议播放直播流,iOS和 Android 都天然支持这种协议,配置简单,直接使用 video 标签即可。

下面是简单的代码使用 video 播放直播视频:


本文转载于互联网,如侵犯你的权益,请及时告知。

参考地址:http://geek.csdn.net/news/detail/95188、https://aotu.io/notes/2016/10/09/HTML5-SopCast/


osted by
Red5 Pro

url : https://www.red5pro.com/blog/3-problems-with-cdn-video-streaming-and-how-we-solved-them/


由于CDN要求您通过其数据网导入所有的内容,因此一些流媒体提供商发现他们需要使用多个CDN来到达不同的地区。这意味着管理不同的系统、分散的流媒体以及添加更多的连接来传输流会带来更长时间的延迟以及额外的复杂性。


这促使实时流媒体市场的许多人开始转向multi-CDN解决方案。事实上,据预测,到2025年,multi-CDN市场将增长到240亿美元。虽然multi-CDN解决了单个CDN网络的一些问题(地区/区域可用性、价格等),但实际上它只是实时视频流的权宜之计。现在,纯WebRTC分发服务是创建实时流媒体的最佳方式。


因此,纯CDN解决方案正逐渐退出市场,至少在直播视频分发方面是如此。原因如下:


延迟


基于HTTP体系架构构建的CDN根本不具备处理动态更新内容(如实时视频)的传输的能力。它们的工作原理是在区域数据中心缓存数据,以便高效地传递大量数据。这种设计的重点在于吞吐量和可伸缩性,从而形成了最适合处理静态对象(例如网站或预先录制的视频)的网络。


缓存会影响延迟,而延迟与传递静态元素(例如网页和VOD)无关紧要。随着实时视频体验变得更具交互性,这意味着它们越来越依赖于低延迟传输。即使只有一秒钟的延迟也会对用户体验和应用程序的实用性产生负面影响。如果它不是实时流式传输,就无法直播。


为了解决这个延迟问题,我们需要使用一种新的方案:WebRTC。WebRTC是围绕低延迟流媒体设计的。它可以以小于500毫秒的端到端延迟传输实时视频,这比HLS传输快得多,后者即使经过修改,也只能在最低的情况下降低到2-3秒。因此,纯WebRTC服务预计将从多CDN总流量(total Multi-CDN traffic)的1.2%增长到8.3%。


单向流动


除了高延迟之外,CDN实际上是围绕着将数据分发到客户端而不是回接收信息而设计的。随着现场体验变得更具交互性,将诸如缩放呼叫、共同查看和粉丝墙体验等功能集成到这些事件中,无法在多个方向上流传输内容对CNDs的实用性是一个重大的损害。


CDN中的每个服务器本质上都被用作一个摄取点,它将流推送到CDN以进行大规模的传输。这意味着它可以很好地将数据从原点分发到边缘,但对于反向传输流信息(从边缘返回原点)则不太好。在这种架构下,双向通信效率不高,因为CDN最适合于广播只由订阅者观看的单个流,而不是双向聊天,其中订阅者在订阅视频的同时也在广播视频。对话在双方之间来回进行,因此他们都必须发送和接收视频。这意味着CDN根本不提供这一功能,而想要构建交互式视频体验的开发人员则不得不将完全不同的技术拼凑在一起,而这些技术从来都是预备过的。


在CDN模型中,请求的数据需要从原点传输到边缘。一旦中继到最近的边缘服务器,它就必须与每个试图访问流的客户机建立单独的连接。这被称为“最后一英里”,是CDN视频流解决方案带宽消耗的主要来源。一些网络已经找到了解决这个问题的方法来降低数据传输成本。


一些提供商使用WebRTC来提高CDN容量。使用WebRTC的话,将有高达70%的峰值流量可以被卸载,这有助于CDN供应商避免基础设施升级,并使CDN分销商能够利用现有预算做更多事情。


例如,Peer5、StreamRoot和StriveCast已经创建了点对点共享网络,以转移它们在CDN上的总带宽消耗。他们不必将所有的内容一对一地从edge流到客户端,而是在流相同文件的所有客户端之间创建数据通道连接。这样,视频通过高效的分块传输HLS协议从源服务器发送到边缘服务器。一旦订阅者拉出那些HLS (.ts)段,它就可以在WebRTC数据通道上建立一个P2P连接来将那些段转发给那个对等者。然后,该对等端可以与另一方建立连接。然后重复这个连接过程,这样他们就可以共享相同的视频文件了。这意味着每个用户都不必从CDN(为数据传输收费的网络)中冗余地拉出所有的数据段。


虽然这些点对点的网状网络对于VOD传输是有效的,但是对于低延迟的实时流媒体则不是有效的。首先,他们仍然使用HLS段作为流的源,这将导致高延迟的问题。其次,这种网状网络并没有解决双向流的问题。此外,还有另一类新兴的纯WebRTC基础提供商,他们根本不使用CDN,事实上它们已经完全取代了CDN。


同步化


实时延迟还释放了与视频流的其他数据正确同步的能力。这开启了添加聊天功能、实时覆盖叠加和交互式图形、虚拟黑板、实时下注和拍卖出价、GPS数据和许多其他的功能。例如,一个体育广播可以有一个实时的图形显示功能,它可以与屏幕上发生的最新状态保持同步。正确的同步与实时延迟相结合,也可以防止恼人的剧透,从而确保不会破坏其他人的观看体验。它还可以确保聊天中的评论与当前显示的内容一致。


对于这些用例,数据可以通过WebRTC数据通道或单独的websocket通道发送,这可以使用SharedObjects方法实现。SharedObjects管理多个客户端之间的数据提要,从而实现数据的一致传输。这样可以确保广播者,订户和任何其他功能之间的完全交互。


在GitHub上可以找到更多示例:


  • SharedObjecthttps://github.com/red5pro/streaming-html5/tree/master/src/page/test/sharedObject
  • SharedObject

iOS:https://github.com/red5pro/streaming-ios/tree/master/R5ProTestbed/Tests/SharedObject

Android:https://github.com/red5pro/streaming-android/tree/master/app/src/main/java/red5pro/org/testandroidproject/tests/SharedObjectTest


所有这些关于CDN实时流传输局限性的讨论可能会给你一种印象:即它们应该被纯WebRTC解决方案所取代。然而,它们在视频流媒体中仍然扮演着非常有价值的角色。CDN对于交付视频点播内容以及静态对象(如网站和静态图像)仍然很有用。然而,当涉及到动态更新的元素(如实时视频流)时,CDN永远无法正确处理它们。与许多其他技术要素一样,市场的需求也扩大并发生了变化。CND正在试图适应这种情况,但它们基于HTTP的基本架构造成了高延迟、单向流限制和同步问题。这些问题,会由新的直播架构模型来解决。