gwuhaolin / blog

浩的技术博客
https://wuhaolin.cn
2.22k stars 280 forks source link

使用flv.js做直播 #3

Open gwuhaolin opened 7 years ago

gwuhaolin commented 7 years ago

为什么要在这个时候探索flv.js做直播呢?原因在于各大浏览器厂商已经默认禁用Flash,之前常见的Flash直播方案需要用户同意使用Flash后才可以正常使用直播功能,这样的用户体验很致命。

在介绍flv.js之前先介绍下常见的直播协议以及给出我对它们的延迟与性能所做的测试得出的数据。 如果你看的很吃力可以先了解下音视频技术的一些基础概念

常见直播协议

常见直播协议延迟与性能数据以下数据只做对比参考

传输协议 播放器 延迟 内存 CPU
RTMP Flash 1s 430M 11%
HTTP-FLV Video 1s 310M 4.4%
HLS Video 20s 205M 3%

在支持浏览器的协议里,延迟排序是: RTMP = HTTP-FLV = WebSocket-FLV < HLS 而性能排序恰好相反: RTMP > HTTP-FLV = WebSocket-FLV > HLS 也就是说延迟小的性能不好。

可以看出在浏览器里做直播,使用HTTP-FLV协议是不错的,性能优于RTMP+Flash,延迟可以做到和RTMP+Flash一样甚至更好。

flv.js 简介

flv.js是来自Bilibli的开源项目。它解析FLV文件喂给原生HTML5 Video标签播放音视频数据,使浏览器在不借助Flash的情况下播放FLV成为可能。

flv.js 优势

flv.js 限制

flv.js依赖的浏览器特性兼容列表

flv.js 为什么要绕一圈,从服务器获取FLV再解码转换后再喂给Video标签呢?原因如下:

  1. 兼容目前的直播方案:目前大多数直播方案的音视频服务都是采用FLV容器格式传输音视频数据。
  2. FLV容器格式相比于MP4格式更加简单,解析起来更快更方便。

flv.js兼容方案

由于目前flv.js兼容性还不是很好,要用在产品中必要要兼顾到不支持flv.js的浏览器。兼容方案如下:

PC端

  1. 优先使用 HTTP-FLV,因为它延迟小,性能也不差1080P都很流畅。
  2. 不支持 flv.js 就使用 Flash播放器播 RTMP 流。Flash兼容性很好,但是性能差默认被很多浏览器禁用。
  3. 不想用Flash兼容也可以用HLS,但是PC端只有Safari支持HLS

    移动端

  4. 优先使用 HTTP-FLV,因为它延迟小,支持HTTP-FLV的设备性能运行 flv.js 足够了。
  5. 不支持 flv.js 就使用 HLS,但是 HLS延迟非常大。
  6. HLS 也不支持就没法直播了,因为移动端都不支持Flash。

flv.js实战

说了这么多介绍与原理,接下来教大家如何用flv.js搭建一个完整的直播系统。 我已经搭建好了一个demo可以供大家体验。

搭建音视频服务

主播推流到音视频服务,音视频服务再转发给所有连接的客户端。为了让你快速搭建服务推荐我用go语言实现的livego,因为它可以运行在任何操作系统上,对Golang感兴趣?请看Golang 中文学习资料汇总

  1. 下载livego,注意选对你的操作系统和位数。
  2. 解压,执行livego,服务就启动好了。它会启动RTMP(1935端口)服务用于主播推流,以及HTTP-FLV(7001端口)服务用于播放。

    实现播放页

    在react体系里使用react flv.js 组件reflv 快速实现。 先安装npm i reflv,再写代码:

    
    import React, { PureComponent } from 'react';
    import Reflv from 'reflv';

export class HttpFlv extends PureComponent { render() { return ( <Reflv url={http://localhost:7001/live/test.flv} type="flv" isLive cors /> ) } }

让以上代码在浏览器里运行。这是你还看不到直播,是因为还没有主播推流。
- 你可以使用[OBS](https://obsproject.com)来推流,注意要配置好OBS:
<img width="961" alt="screen shot 2017-06-07 at 5 41 32 pm" src="https://user-images.githubusercontent.com/5773264/26872300-9c1c5bb4-4ba8-11e7-98eb-98e6d6ba751f.png">

- 也可以使用[ffmpeg](https://ffmpeg.org)来推流,推流命令`ffmpeg -f avfoundation -i "0" -vcodec h264 -acodec aac -f flv rtmp://localhost/live/test`

## flv.js延迟优化
按照上面的教程运行起来的直播延迟大概有3秒,经过优化可以到1秒。在教你怎么优化前先要介绍下直播运行流程:
1. 主播端在采集到一段时间的音视频原数据后,因为音视频原数据庞大需要先压缩数据:
    - 通过H264视频编码压缩数据数据
    - 通过PCM音频编码压缩音频AAC数据

2. 压缩完后再通过FLV容器格式封装压缩后的数据,封装成一个FLV TAG
3. 再把FLV TAG通过RTMP协议推流到音视频服务器,音视频服务器再从RTMP协议里解析出FLV TAG。
4. 音视频服务器再通过HTTP协议通过和浏览器建立的长链接流式把FLV TAG传给浏览器。
5. flv.js 获取FLV TAG后解析出压缩后的音视频数据喂给Video播放。

知道流程后我们就知道从哪入手优化了:
- 主播端采集时收集了一段时间的音视频原数据,它专业的叫法是[GOP](http://blog.csdn.net/zqj6893/article/details/50262189)。缩短这个收集时间(也就是减少GOP长度)可以优化延迟,但这样做的坏处是导致视频压缩率不高,传输效率低。
- 关闭音视频服务器的I桢缓存可以优化延迟,坏处是用户看到直播首屏的时间变大。
- 减少音视频服务器的buffer可以优化延迟,坏处是音视频服务器处理效率降低。
- 减少浏览器端flv.js的buffer可以优化延迟,坏处是浏览器端处理效率降低。
- 浏览器端开启flv.js的Worker,多线程运行flv.js提升解析速度可以优化延迟,这样做的flv.js配置代码是:
```js
{
          enableWorker: true,
          enableStashBuffer: false,
          stashInitialSize: 128,// 减少首桢显示等待时长
}

这里是优化后的完整代码

阅读原文

goodgirlElena commented 2 years ago

优秀,写得很详细,赞!

lanayalouisforever commented 2 years ago

您好。我这边流媒体服务器是使用nginx的nginx-http-flv-module,然后推流是使用javacv去获取网络摄像头的视频帧,在将视频帧推向流媒体服务器之前,我这边是先做了一系列的处理,包括人体识别,人体属性识别等,但是客户端(Chrome)去使用flv.js获取视频流进行播放时,视频会卡顿或延迟,我这边猜想可能是因为处理的时间长导致的,我想问一下从flvjs的角度有没有办法优化 @LW-Francis

您好,您留言实现的功能,代码能发给我一份码,个人学习使用,十分感谢。

matisse510 commented 2 years ago

已收到,谢谢! 

haixiangyan commented 2 years ago

nice, mark!

queryGood commented 1 year ago

nice~

matisse510 commented 1 year ago

已收到,谢谢! 

yanglun666 commented 3 months ago

我在前端通过 flv正常播放后,http://192.168.0.16:8090/stat/livestat 只有 推流的记录,没有拉流的记录这是什么情况,通过ffplay.exe rtmp://192.168.0.16:1935/live/name 来又有

matisse510 commented 3 months ago

已收到,谢谢!