Skip to content
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 · 58 comments
Open

使用flv.js做直播 #3

gwuhaolin opened this issue May 17, 2017 · 58 comments

Comments

@gwuhaolin
Copy link
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 changed the title 使用flv.js做网页直播 使用flv.js做直播 Jun 7, 2017
@ipengyo
Copy link

ipengyo commented Jun 8, 2017

牛逼!

@NiuZhuang
Copy link

很棒!

@shi1991
Copy link

shi1991 commented Jun 9, 2017

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

@gwuhaolin
Copy link
Owner Author

gwuhaolin commented Jun 9, 2017

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

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

@yugasun
Copy link

yugasun commented Jun 16, 2017

6666

@hjzgg
Copy link

hjzgg commented Jun 20, 2017

很强,亲测成功!

@vipchens
Copy link

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

@gwuhaolin
Copy link
Owner Author

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

@zhanghuohuo1996
Copy link

nice!

@zhibocon
Copy link

zhibocon commented Aug 1, 2017

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

@gwuhaolin
Copy link
Owner Author

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

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

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

@jane35622
Copy link

很棒的应用方式

@wujunze
Copy link

wujunze commented Sep 7, 2017

🐂 我们用的HLS

@zcc19910728
Copy link

zcc19910728 commented Oct 5, 2017

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

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

@fanyoujian
Copy link

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

@ispfcn
Copy link

ispfcn commented Oct 23, 2017

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

@zhangketing
Copy link

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

@wujunze
Copy link

wujunze commented Nov 8, 2017

@zhangketing 你用流播放工具试试 http://www.ossrs.net/players/srs_player.html

@zhangketing
Copy link

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

@fa1com
Copy link

fa1com commented Dec 5, 2017

老哥稳!

@hlanr1
Copy link

hlanr1 commented Dec 25, 2017

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

@evanzlj
Copy link

evanzlj commented Jan 7, 2018

@luobic
Copy link

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
Copy link

你好我在用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
Copy link

wukaMM commented Feb 24, 2018

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

@luxueyan
Copy link

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

@0079123
Copy link

0079123 commented May 18, 2018

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

@codemongkey
Copy link

@NiuZhuang @hjzgg @ipengyo 你好,你用的obs推流还是ffmpeg

@Mtora
Copy link

Mtora commented Apr 17, 2019

@Mtora 你好,你用的obs推流还是ffmpeg

用的obs

@codemongkey
Copy link

@Mtora 好的,谢谢,我用obs推也可以。但是想自己用代码实现推流,所以用了ffmpeg的库,我看livego服务器的响应都是一样的,但是就是不能在浏览器上播放,实在找不到问题所在,您有空可以尝试教程中的指令试试

@codemongkey
Copy link

@gwuhaolin 你好,教程中ffmpeg那条指令会有Unknown input format: 'avfoundation',是因为只能在mac系统使用吗?
所以我用了:ffmpeg -i "rtsp:// " -vcodec copy -acodec copy -f flv "rtmp://localhost/live/test"
推是能推到livego但是不能在浏览器里播放,可以用vlc播放

@YuukiLa
Copy link

YuukiLa commented Jun 26, 2019

你好,我用obs推的时候,obs一直断线重连,是怎么回事

@HUGY1
Copy link

HUGY1 commented Jul 25, 2019

就一个需求。低延迟,ios safari兼容 直接就没方案了。

@guothion
Copy link

受教了

@opvexe
Copy link

opvexe commented Oct 17, 2019

牛逼 我一直在找一篇写的比较详细的推流,拉流文档

@mingzhanghui
Copy link

Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first

@yxyufo110
Copy link

请问在播放失败的时候怎么补货异常或者reload

@shenjianzch
Copy link

go 服务器跑起来了 我再前端 怎么查看啊 用ffmpeg 也推了 怎么浏览查看

@yangsijie666
Copy link

使用ffmpeg推流,livego端报错 ERRO[2020-06-24T22:32:04+08:00] CheckKey err: invalid key ,ffmpeg 端报错
WriteN, RTMP send error 32 (140 bytes)
WriteN, RTMP send error 32 (39 bytes)
WriteN, RTMP send error 9 (42 bytes)
av_interleaved_write_frame(): Operation not permitted
[flv @ 0x7fb777024000] Failed to update header with correct duration.
[flv @ 0x7fb777024000] Failed to update header with correct filesize.
Error writing trailer of rtmp://localhost/live/test: Operation not permitted
请问这个是怎么回事呢?同样是 mac 端,使用的 ffmpeg 命令为:ffmpeg -f avfoundation -framerate 30 -i "0" -c:v h264 -c:a copy -f flv rtmp://localhost/live/test

@soolaugust
Copy link

mark 👍

@LonHon
Copy link

LonHon commented Jul 7, 2020

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

@elon-hu 直接修改实例的currentTime

@comcn1949
Copy link

服务端用livego,用anyrtc-rtmp 推流, 视频h264,音频aac, 用flv.js网页里播放,一直在等待,m3u8能播放,用nodeplayer.js也能播放, 啥原因呢

@LW-Francis
Copy link

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

@LW-Francis
Copy link

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

@goodgirlElena
Copy link

优秀,写得很详细,赞!

@lanayalouisforever
Copy link

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

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

@matisse510
Copy link

matisse510 commented Feb 10, 2022 via email

@haixiangyan
Copy link

nice, mark!

@queryGood
Copy link

nice~

@matisse510
Copy link

matisse510 commented Oct 11, 2022 via email

@yanglun666
Copy link

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

@matisse510
Copy link

matisse510 commented Mar 13, 2024 via email

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

No branches or pull requests