web直播探索

Aditya2022-04-15前端Video

引子

这是个忧伤的故事,最开始朋友问我如何接收裸流H264,并播放,我随手Google了下,答曰wfs,朋友曰就决定是你了。 从最开始用wfs库来处理裸流H264,到解码H264用video标签输出、再到使用flv.js,最终确定用hls来搞,我几经放弃因为XX坚持下来了……

wfs.js处理h264裸流

wfs.js下载地址open in new window

<video ref="video" id="video" controls></video></div>

this.$nextTick(() => {
  if (Wfs.isSupported()) {
    this.wfs = new Wfs()
    this.wfs.attachMedia(this.$refs.video,'ch1')
    }
  })

// 断开
this.wfs.destory()

在前一篇博文也写到了该库的用法,以及注意事项,但我仅仅站在了第一层。

在写演示demo以及开发的时候,都是在chrome的模拟器来做的,没有测试过真机,交付的时候发现竟然不支持在ios播放……

Wfs.isSupported() 抄写栗子的时候完全没考虑过这玩意是干嘛的

function isSupported() {
    return window.MediaSource && typeof window.MediaSource.isTypeSupported === 'function' && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42c01f,mp4a.40.2"');
}

源码中它判断的是window.MediaSource这个对象是否存在。

MSE(Media Source Extensions):W3C 标准API,解决 HTML5 的流问题(HTML5 原生仅支持播放 mp4/webm 非流格式,不支持 FLV),允许JavaScript动态构建 <video><audio> 的媒体流。可以用MediaSource.isTypeSupported() 判断是否支持某种MINE类型。

123

很重要一点在iOS的不支持Safari。

所以这个方案基本嗝屁了。

解码H264

调研了几个解码方式,最后选择了比较简单的Broadway.js来做个demo

使用Broadway.js

https://github.com/mbebenita/Broadwayopen in new window下载其源码,其中最主要的代码在文件夹Player下,在其中添加一个任意名称的.html文件,并将如下代码写入此文件

<script type="text/javascript">
	var player = new Player({size: {
    width: 640,
    height: 320
     }});

	document.body.appendChild(player.canvas);
	
	var strhost = "ws://" + window.location.host + "/test";
	// Setup the WebSocket connection and start the player
	var client = new WebSocket( strhost );
		client.binaryType = 'arraybuffer';

    client.onmessage = function(evt) { 
        onMessage(evt) 
    }; 
    
 
function onMessage(evt) { 
    var messageData = new Uint8Array(evt.data);       
    player.decode(messageData);
}  
 
function onError(evt) { 
    alert("error");
}  
	
</script>

跟github栗子不太一样的是得用Uint8Array转一下流才能输出。

问题

该库尴尬点在于解码不支持分流,我测试的时候是传输整个h264文件,没什么问题,但是如果切割分流传输就会卡住不动了。

还有点就是他的上线竟然是1024x1024,大小超过就会报超过边界错误。

flv.js

该库的问题也是MSE问题,这里简单介绍一下吧。

  • FLV里所包含的视频编码必须是H.264,音频编码必须是AACMP3, IE11和Edge浏览器不支持MP3音频编码,所以FLV里采用的编码最好是H.264+AAC,这个让音视频服务兼容不是问题。
  • 对于录播,依赖 原生HTML5 Video标签Media Source Extensionsopen in new window API
  • 对于直播,依赖录播所需要的播放技术,同时依赖 HTTP FLV 或者 WebSocket 中的一种协议来传输FLV。其中HTTP FLV需通过流式IO去拉取数据,支持流式IO的有fetchopen in new window或者streamopen in new window
  • flv.min.js 文件大小 164Kb,gzip后 35.5Kb,flash播放器gzip后差不多也是这么大。
  • 由于依赖Media Source Extensions,目前所有iOS和Android4.4.4以下里的浏览器都不支持,也就是说目前对于移动端flv.js基本是不能用的。

HLS的一个直播的技术方案

最后的解决就是采用http-hls的方式来做视频直播:

  1. 采集视频流,并完成分片
  2. 前端请求获取m3u8文件
  3. 解析m3u8文件,获取ts文件
  4. ts文件转码放入ArrayBuffer
  5. MediaSource API进行合流,用video标签输出直播

如果天然支持HLS的浏览器,其实就是自己完成了3 4 5三个流程。

The Play() request was interrupted by a new load request

在调试过程中有几率出现上述问题,出现后会卡住,所以简单处理就是对错误回调进行处理

if (Hls.isSupported()) {
  console.log('请求')
  this.hls = new Hls({
    // debug: true
  });
  this.hls.loadSource(source);
  this.hls.attachMedia(this.$refs.video);

  this.hls.on(Hls.Events.MANIFEST_PARSED, () => {
    console.log("加载成功");
    this.$refs.video.play();
  });
  this.hls.on(Hls.Events.ERROR, (event, data) => {
    console.log(event, data);
    // 监听出错事件
    console.log("加载失败");
    if (data.fatal) {
      switch (data.type) {
        case Hls.ErrorTypes.NETWORK_ERROR:
          // try to recover network error
          console.log('fatal network error encountered, try to recover');
          this.hls.startLoad();
          break;
        case Hls.ErrorTypes.MEDIA_ERROR:
          console.log('fatal media error encountered, try to recover');
          this.hls.recoverMediaError();
          break;
        default:
          // cannot recover
          this.hls.destroy();
          break;
      }
    }
  });
}

缓存问题

在开发环境对于请求打勾了 Diasble cache,所以没发现该问题,他们测试的时候一直有请求,抓包却抓不多,一看都是from disk cache。

解决方案还是后端接口无缓存状态no-cache, no-store, max-age=0, must-revalidate

IOS自动全屏问题

<video ref="video" x5-video-player-type='h5' x5-video-player-fullscreen='true' playsinline webkit-playsinline autoplay preload="auto" id="video" type="application/x-mpegURL"></video>

网上大部分帖子都是加playsinline,但是无效,还需要再加上webkit-playsinline

参考

hls.js APIopen in new window

hls.js githubopen in new window

Web端解码视频流:(Part1 纯Java Script 解码[不建议大家这样做,因为普适性不强])open in new window

Web直播,你需要先知道这些open in new window

Last Updated 2024/12/27 11:36:49