New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

使用flv.js做直播 #3

Open
gwuhaolin opened this Issue May 17, 2017 · 32 comments

Comments

Projects
None yet
@gwuhaolin
Owner

gwuhaolin commented May 17, 2017

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

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

常见直播协议

  • RTMP: 底层基于TCP,在浏览器端依赖Flash。
  • HTTP-FLV: 基于HTTP流式IO传输FLV,依赖浏览器支持播放FLV。
  • WebSocket-FLV: 基于WebSocket传输FLV,依赖浏览器支持播放FLV。WebSocket建立在HTTP之上,建立WebSocket连接前还要先建立HTTP连接。
  • HLS: Http Live Streaming,苹果提出基于HTTP的流媒体传输协议。HTML5可以直接打开播放。
  • RTP: 基于UDP,延迟1秒,浏览器不支持。

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

传输协议 播放器 延迟 内存 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 优势

  • 由于浏览器对原生Video标签采用了硬件加速,性能很好,支持高清。
  • 同时支持录播和直播
  • 去掉对Flash的依赖

flv.js 限制

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

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

flv.js 原理

flv.js只做了一件事,在获取到FLV格式的音视频数据后通过原生的JS去解码FLV数据,再通过Media Source Extensions API 喂给原生HTML5 Video标签。(HTML5 原生仅支持播放 mp4/webm 格式,不支持 FLV)

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

移动端

  1. 优先使用 HTTP-FLV,因为它延迟小,支持HTTP-FLV的设备性能运行 flv.js 足够了。
  2. 不支持 flv.js 就使用 HLS,但是 HLS延迟非常大。
  3. 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来推流,注意要配置好OBS:

screen shot 2017-06-07 at 5 41 32 pm

  • 也可以使用ffmpeg来推流,推流命令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。缩短这个收集时间(也就是减少GOP长度)可以优化延迟,但这样做的坏处是导致视频压缩率不高,传输效率低。
  • 关闭音视频服务器的I桢缓存可以优化延迟,坏处是用户看到直播首屏的时间变大。
  • 减少音视频服务器的buffer可以优化延迟,坏处是音视频服务器处理效率降低。
  • 减少浏览器端flv.js的buffer可以优化延迟,坏处是浏览器端处理效率降低。
  • 浏览器端开启flv.js的Worker,多线程运行flv.js提升解析速度可以优化延迟,这样做的flv.js配置代码是:
{
          enableWorker: true,
          enableStashBuffer: false,
          stashInitialSize: 128,// 减少首桢显示等待时长
}

这里是优化后的完整代码

阅读原文

@gwuhaolin gwuhaolin added the 音视频 label Jun 3, 2017

@gwuhaolin gwuhaolin changed the title from 使用flv.js做网页直播 to 使用flv.js做直播 Jun 7, 2017

@ipengyo

This comment has been minimized.

Show comment
Hide comment
@ipengyo

ipengyo Jun 8, 2017

牛逼!

ipengyo commented Jun 8, 2017

牛逼!

@NiuZhuang

This comment has been minimized.

Show comment
Hide comment
@NiuZhuang

NiuZhuang commented Jun 8, 2017

很棒!

@shi1991

This comment has been minimized.

Show comment
Hide comment
@shi1991

shi1991 Jun 9, 2017

推流用的 RTMP 吗?rtmp 怎么转换成 flv呢?

shi1991 commented Jun 9, 2017

推流用的 RTMP 吗?rtmp 怎么转换成 flv呢?

@gwuhaolin

This comment has been minimized.

Show comment
Hide comment
@gwuhaolin

gwuhaolin Jun 9, 2017

Owner

@shi1991
RTMP是用来传输FLV的。RTMP是传输协议,FLV是存放音视频数据的文件容器格式。
要从RTMP里解析出FLV需要解RTMP。
这有RTMP协议文档
以及FLV容器文档

推荐你阅读我收集的音视频文档集

Owner

gwuhaolin commented Jun 9, 2017

@shi1991
RTMP是用来传输FLV的。RTMP是传输协议,FLV是存放音视频数据的文件容器格式。
要从RTMP里解析出FLV需要解RTMP。
这有RTMP协议文档
以及FLV容器文档

推荐你阅读我收集的音视频文档集

@yugasun

This comment has been minimized.

Show comment
Hide comment
@yugasun

yugasun commented Jun 16, 2017

6666

@hjzgg

This comment has been minimized.

Show comment
Hide comment
@hjzgg

hjzgg Jun 20, 2017

很强,亲测成功!

hjzgg commented Jun 20, 2017

很强,亲测成功!

@vipchens

This comment has been minimized.

Show comment
Hide comment
@vipchens

vipchens Jun 25, 2017

linux上配置livego该如何操作,我配置了go环境build失败

vipchens commented Jun 25, 2017

linux上配置livego该如何操作,我配置了go环境build失败

@gwuhaolin

This comment has been minimized.

Show comment
Hide comment
@gwuhaolin

gwuhaolin Jun 25, 2017

Owner

@vipchens 如果是go build失败请提供 详细错误堆栈
你还可以直接在 https://github.com/gwuhaolin/livego/releases 下载可执行文件跳过自己编译

Owner

gwuhaolin commented Jun 25, 2017

@vipchens 如果是go build失败请提供 详细错误堆栈
你还可以直接在 https://github.com/gwuhaolin/livego/releases 下载可执行文件跳过自己编译

@WithLin

This comment has been minimized.

Show comment
Hide comment
@WithLin

WithLin Jul 23, 2017

实现播放页 这个代码 跑不起来~

WithLin commented Jul 23, 2017

实现播放页 这个代码 跑不起来~

@zhanghuohuo1996

This comment has been minimized.

Show comment
Hide comment
@zhanghuohuo1996

zhanghuohuo1996 commented Jul 26, 2017

nice!

@bimulinsen

This comment has been minimized.

Show comment
Hide comment
@bimulinsen

bimulinsen Aug 1, 2017

这里问下可能不太相关的问题,据我了解bilibili是用HTTP-FLV技术直播的 http://www.manew.com/blog-166094-12265.html ,那主播这边如果想缩短直播延时,在obs推流的时候,有什么地方需要特别设置吗?

bimulinsen commented Aug 1, 2017

这里问下可能不太相关的问题,据我了解bilibili是用HTTP-FLV技术直播的 http://www.manew.com/blog-166094-12265.html ,那主播这边如果想缩短直播延时,在obs推流的时候,有什么地方需要特别设置吗?

@gwuhaolin

This comment has been minimized.

Show comment
Hide comment
@gwuhaolin

gwuhaolin Aug 1, 2017

Owner

@bimulinsen
播放直播的时候,延时主要会出现在3个地方:

  1. 推流端的数据缓存
  2. 服务端的gop缓存
  3. 播放器的buffer缓存

针对1 obs会缓存数据可以调整:
0015811d234a97c617d2d481427a476

Owner

gwuhaolin commented Aug 1, 2017

@bimulinsen
播放直播的时候,延时主要会出现在3个地方:

  1. 推流端的数据缓存
  2. 服务端的gop缓存
  3. 播放器的buffer缓存

针对1 obs会缓存数据可以调整:
0015811d234a97c617d2d481427a476

@jane35622

This comment has been minimized.

Show comment
Hide comment
@jane35622

jane35622 Sep 3, 2017

很棒的应用方式

jane35622 commented Sep 3, 2017

很棒的应用方式

@wujunze

This comment has been minimized.

Show comment
Hide comment
@wujunze

wujunze Sep 7, 2017

🐂 我们用的HLS

wujunze commented Sep 7, 2017

🐂 我们用的HLS

@zcc19910728

This comment has been minimized.

Show comment
Hide comment
@zcc19910728

zcc19910728 Oct 5, 2017

帮我看下用你的源码webpack之后,本地报错video的src是个空指针blob:null/5230135f-a1aa-4d6f-956d-b149e7b36180

不知道为什么之前启动本地sever之后视频出不来,后来重新试了下 确实通了,不过还有很多问题需要调整

zcc19910728 commented Oct 5, 2017

帮我看下用你的源码webpack之后,本地报错video的src是个空指针blob:null/5230135f-a1aa-4d6f-956d-b149e7b36180

不知道为什么之前启动本地sever之后视频出不来,后来重新试了下 确实通了,不过还有很多问题需要调整

@fanyoujian

This comment has been minimized.

Show comment
Hide comment
@fanyoujian

fanyoujian Oct 19, 2017

有对应的声量控制方法吗?

fanyoujian commented Oct 19, 2017

有对应的声量控制方法吗?

@ispfcn

This comment has been minimized.

Show comment
Hide comment
@ispfcn

ispfcn Oct 23, 2017

你的livego有权限控制模块吗?如何确认推流身份?

ispfcn commented Oct 23, 2017

你的livego有权限控制模块吗?如何确认推流身份?

@zhangketing

This comment has been minimized.

Show comment
Hide comment
@zhangketing

zhangketing Nov 8, 2017

请教一下,我服务器用的srs,想直接用浏览器观看http-flv流,为什么提示我下载文件呢,不能直接播放直播流

zhangketing commented Nov 8, 2017

请教一下,我服务器用的srs,想直接用浏览器观看http-flv流,为什么提示我下载文件呢,不能直接播放直播流

@wujunze

This comment has been minimized.

Show comment
Hide comment
@wujunze

wujunze commented Nov 8, 2017

@zhangketing

This comment has been minimized.

Show comment
Hide comment
@zhangketing

zhangketing Nov 8, 2017

@wujunze,播放器是可以放的,这个应该是跨域的问题,需要修改一下http回应消息就应该可以了,谢谢哈。

zhangketing commented Nov 8, 2017

@wujunze,播放器是可以放的,这个应该是跨域的问题,需要修改一下http回应消息就应该可以了,谢谢哈。

@MerlinPong

This comment has been minimized.

Show comment
Hide comment
@MerlinPong

MerlinPong Dec 5, 2017

老哥稳!

MerlinPong commented Dec 5, 2017

老哥稳!

@hlanr1

This comment has been minimized.

Show comment
Hide comment
@hlanr1

hlanr1 Dec 25, 2017

請問,那websocket-flv該如何推送呢

hlanr1 commented Dec 25, 2017

請問,那websocket-flv該如何推送呢

@evanzlj

This comment has been minimized.

Show comment
Hide comment
@evanzlj

evanzlj commented Jan 7, 2018

@luobic

This comment has been minimized.

Show comment
Hide comment
@luobic

luobic Jan 15, 2018

您好,我下载您的源码运行go get.时报错:# github.com/gwuhaolin/livego/utils/uid
../../go/src/github.com/gwuhaolin/livego/utils/uid/uuid.go:9:18: multiple-value uuid.NewV4() in single-value context;
我是mac系统, 下载您的编译好的二进制文件freebsd版本时无法运行。
两天了解决不了这个问题非常着急,希望您指点

luobic commented Jan 15, 2018

您好,我下载您的源码运行go get.时报错:# github.com/gwuhaolin/livego/utils/uid
../../go/src/github.com/gwuhaolin/livego/utils/uid/uuid.go:9:18: multiple-value uuid.NewV4() in single-value context;
我是mac系统, 下载您的编译好的二进制文件freebsd版本时无法运行。
两天了解决不了这个问题非常着急,希望您指点

@lcl987512

This comment has been minimized.

Show comment
Hide comment
@lcl987512

lcl987512 Feb 6, 2018

你好我在用flv.js测试时,用127.0.0.1:7001连接可以正常播放,而采用实际的本机IP地址就是播放不成功,flv.js返回信息也是正确的:
[FLVDemuxer] > Parsed onMetaData
[FLVDemuxer] > Parsed AVCDecoderConfigurationRecord
[MSEController] > Received Initialization Segment, mimeType: video/mp4;codecs=avc1.4d002a
请问又遇到这个问题的吗?

lcl987512 commented Feb 6, 2018

你好我在用flv.js测试时,用127.0.0.1:7001连接可以正常播放,而采用实际的本机IP地址就是播放不成功,flv.js返回信息也是正确的:
[FLVDemuxer] > Parsed onMetaData
[FLVDemuxer] > Parsed AVCDecoderConfigurationRecord
[MSEController] > Received Initialization Segment, mimeType: video/mp4;codecs=avc1.4d002a
请问又遇到这个问题的吗?

@wukaMM

This comment has been minimized.

Show comment
Hide comment
@wukaMM

wukaMM Feb 24, 2018

你好,请教一下,是否遇到过使用 safari 播放时,第一帧卡住的情况?

wukaMM commented Feb 24, 2018

你好,请教一下,是否遇到过使用 safari 播放时,第一帧卡住的情况?

@waltkong

This comment has been minimized.

Show comment
Hide comment
@waltkong

waltkong Mar 20, 2018

go build出错了。大佬 。 我在github里去找这个包,没找到额
default

waltkong commented Mar 20, 2018

go build出错了。大佬 。 我在github里去找这个包,没找到额
default

@luxueyan

This comment has been minimized.

Show comment
Hide comment
@luxueyan

luxueyan Apr 11, 2018

赞!大侠,可以做到渲染前 取到每一帧做做处理之后在渲染吗?

luxueyan commented Apr 11, 2018

赞!大侠,可以做到渲染前 取到每一帧做做处理之后在渲染吗?

@0079123

This comment has been minimized.

Show comment
Hide comment
@0079123

0079123 May 18, 2018

Chrome后台播放flv直播暂停 怎么 处理的?

0079123 commented May 18, 2018

Chrome后台播放flv直播暂停 怎么 处理的?

@elon-hu

This comment has been minimized.

Show comment
Hide comment
@elon-hu

elon-hu May 23, 2018

flv.js暂停后,过几秒重新播放,结果是从暂停的地方播放,如何确保暂停后重新播放是最新的画面呢?

elon-hu commented May 23, 2018

flv.js暂停后,过几秒重新播放,结果是从暂停的地方播放,如何确保暂停后重新播放是最新的画面呢?

@ddi6599

This comment has been minimized.

Show comment
Hide comment
@ddi6599

ddi6599 Aug 27, 2018

本地跑起来的,提示
Fetch API cannot load rtmp://localhost:1935/live/movie/test. URL scheme must be "http" or "https" for CORS request.
这个怎么配置跨域呢

ddi6599 commented Aug 27, 2018

本地跑起来的,提示
Fetch API cannot load rtmp://localhost:1935/live/movie/test. URL scheme must be "http" or "https" for CORS request.
这个怎么配置跨域呢

@Mtora

This comment has been minimized.

Show comment
Hide comment
@Mtora

Mtora Oct 17, 2018

亲测,配合fiv.js效果非常好!

Mtora commented Oct 17, 2018

亲测,配合fiv.js效果非常好!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment