nginx-rtmp 实现直播
需求描述:海康NVR内网摄像头在外网进行播放.
问题原因:由于海康布置在无法转入/映射的内网环境,仅能通过内部网络发送出来,所以需要对海康RTSP视频流进行拉取转推送,以下是解决办法.
一.内网转发服务器安装nginx-rtmp for docker
这里之所以使用docker 主要是我懒,有现成的可以用.
#拉取镜像
docker pull alfg/nginx-rtmp # docker 拉取已经封装好的nginx-rtmp镜像
docker pull tiangolo/nginx-rtmp # 这个镜像也可以 看你喜欢
#启动demo
docker run -d --name de tiangolo/nginx-rtmp # 后台启动镜像 这里不用管他端口问题 反正一会就删了
docker ps #查看启动成功没有
#复制配置文件到本地
mkdir /seventyseven/nginx-rtmp #建立docker nginx 配置文件存放位置
cd /seventyseven/nginx-rtmp #进入目录
mkdir conf #配置文件地址
mkdir data #映射data文件地址(访问页面位置)
docker cp de:/etc/nginx /seventyseven/nginx-rtmp/conf #将demo中的配置文件复制到本机/seventyseven/nginx-rtmp/conf目录 之所以这样做是因为直接-v映射总是启动失败,配置文件不见了,可能有更好的解决办法,但是我这样解决了就不管他了
#删除demo
docker stop de #停止容器
docker rm de #删除容器
#正式启动nginx-rtmp
docker run -d --name my_nginx_rtmp -p [直播推流端口]:1935 -p [http浏览端口]:80 -v /seventyseven/nginx-rtmp/conf:/etc/nginx -v /seventyseven/nginx-rtmp/data:/nginxdata tiangolo/nginx-rtmp #启动nginx
#注意↑:1935为nginx默认配置端口,如果你要自己改 可以这里随便写,之后改配置文件即可
docker ps #查看启动是否完成
看到这个结果则说明启动完成
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
63da tiangolo/nginx-rtmp "ngin of…" 5 days ago Up 2 hours 0.0.0.0:1935->1935/tcp, 0.0.0.0:50001->80/tcp nginx-rtmp
然后打开配置文件我们来改一下配置
cd /seventyseven/nginx-rtmp/conf #进入配置文件目录
vi nginx.conf #配置文件如下
# rtmp conf
worker_processes auto;
rtmp_auto_push on;
events {}
rtmp {
server {
listen 1935;
listen [::]:1935 ipv6only=on;
application live {
live on;
record off;
}
application hls {
live on;
hls on;
hls_path /nginxdata; # 这里跟启动命令-v /seventyseven/nginx-rtmp/data:/nginxdata 对应上
hls_fragment 5s;
record off;
}
}
}
后面会对rtmp.conf做全配置详解 这里仅展示demo使用的conf
二.启动OBS进行模拟推流
OBS软件怎么用这里就不作介绍了.
推流地址:rtmp://[你的ip]:1935/hls
obs中有一个密钥的东西,虽然这个软件叫做密钥,实质上就是给你的视频流取一个名称比如demo123
等待obs推流成功后,则 服务器/seventyseven/nginx/data 文件中则会出现demo123.m3u8 文件 出现文件则说明流已经推送成功 跳转五.VLC播放器验证推流是否成功 进行验证流是否可以播放
此处播放地址为: rtmp://[你的ip]:1935/hls/demo123
三.转发服务器安装ffmpeg for windows
ffmpeg下载地址:http://ffmpeg.org/download.html
这里贴出的是其官网地址,没有贴github主要是因为这玩意源码我不会打包,C++写的我看的很懵逼
由于前面需求的原因,这里我使用的是windows版本,直接下载解压到任意目录即可.
其目录树为:
ffmpeg-N-103179-gac0408522a-win64-gpl
-
bin
- doc
此处将bin目录添加windows环境变量
cmd -> ffmpeg -version
ffmpeg version N-103179-gac0408522a-20210808 Copyright (c) 2000-2021 the FFmpeg developers #看到这个则说明安装完成
四.首次转发推流
ffmpeg 命令:
ffmpeg -i rtsp://原流地址 -vcodec copy -acodec copy -c:v libx264 -f flv rtmp://[你的ip]:1935/hls/demo123
如果启动成功则转发推流完成 附录有ffmpeg 详细说明 附录.ffmpeg使用详解
这里主要说一下这个 -c:v libx264 之所以要加上这一串,由于海康摄像头过来的流是h264的 直接转flv会失败,各种百度最后找到的解决办法
正常情况不需要加
转发成功后五.VLC播放器验证推流是否成功 进行验证
五.VLC播放器验证推流是否成功
VLC->媒体->打开网络串流->播放地址
等待播放即可
如果播放失败,检查
1.是否是rtmp/rtsp/http/https开头
2.服务器端口是否开启
3.是否已经有了***.M3U8文件
4.文件名称即obs说的密钥是否正确
附录.nginx-rtmp配置文件详解
# rtmp conf
worker_processes auto;
rtmp_auto_push on;
events {}
rtmp { # rtmp主块 所有rtmp配置均需要写在这里面
server { # 声明一个rtmp实例/nginx中监听某某端口一个意思
listen 1935; # 监听端口 1935
listen [::]:1935 ipv6only=on; #配置访问请求限制
timeout 60s; # 配置访问超时时间 这个值主要用于写数据时,如果推过来的流死卡死卡可以在这里被关闭 如果想要快速关闭可以配置ping
ping 3m; #配置socket心跳ping 这里是3分钟一次
ping_timeout 30s; #ping完回复时间这里设置成30s 默认为1min 如果超时则断开本次连接
max_streams 32; #设置 RTMP 流的最大数目。数据流被整合到一个单一的数据流里。不同的频道用于发送命令、音频、视频等。默认值为32,适用于大多数情况。
ack_window 5000000;#设置 RTMP 确认视窗大小。这是对端发送确认包到远端后应该收到的字节数量。默认值为 5000000。
chunk_size 4096;#流整合的最大的块大小。默认值为 4096。这个值设置的越大 CPU 负载就越小。这个值不能低于 128。
max_message 1M;#输入数据报文最大尺寸。所有输入数据会被分割成报文(然后进一步分割为块)。报文在处理结束之前会放在内存里。理论上讲,接收到的报文很大的话对于服务器的稳定性可能会有影响。默认值 1M 对于大多数情况就足够了。 没看懂?那就别碰她默认的挺好
on_connect http://baidu.com;#设置 HTTP 连接回调。当客户分发连接命令一个连接命令时,一个 HTTP 请求异步发送,命令处理将被暂停,直到它返回结果代码。当 HTTP 2XX 码(成功状态码)返回时,RTMP 会话继续。返回码 3XX (重定向状态码)会使 RTMP 重定向到另一个从 HTTP 返回头里获取到的 application。否则(其他状态码)连接丢弃。注意这一指令在 application 域是不允许的,因为 application 在连接阶段还是未知的。
#HTTP 请求接收到一些参数。在 application/x-www-form-urlencoded MIME 类型下使用 POST 方法。以下参数将被传给调用者:
# call=connect。
# addr - 客户端 IP 地址。
# app - application 名。
# flashVer - 客户端 flash 版本。
# swfUrl - 客户端 swf url。
# tcUrl - tcUrl。
# pageUrl - 客户端页面 url。
#除了上述参数以外,所有显式传递给连接命令的参数也由回调发送。你应该将连接参数和 play/publish 参数区分开。播放器常常有独特的方式设置连接字符串不同于 play/publish 流名字。这里是 JWPayer 是如何设置这些参数的一个示例:
application live { #新建rtmp应用 说人话 启动一个具体的直播间 命名为live
live on; #开启直播即一对多播放
allow publish 127.0.0.1; #允许什么地址的流进行推送
deny publish all; # 不允许什么地址的流进行推送
allow play 192.168.0.0/24; #允许什么ip的人进行播放
deny play all; # 不允许什么ip的人进行播放
exec ffmpeg -i rtmp://localhost/src/$name -vcodec libx264 -vprofile baseline -g 10 -s 300x200 -acodec libfaac -ar 44100 -ac 1 -f flv rtmp://localhost/hls/$name; # exec 命令 定义每个流发布时要执行的带有参数的外部命令。发布结束时进程终止。第一个参数应该是二进制可执行文件的完整路径。关于这个进程将会做些什么事没有任何假定。但这一特点在使用 ffmpeg 进行流转换时是很有用的。FFmpeg 被假定作为客户端连接到 nginx-rtmp 然后作为发布者输出转换流到 nginx-rtmp。类似于 $var/${var} 形式的替换可以在命令行使用:以上为ffmpeg 调用将输入流转码为 HLS-ready 流(H264/AAC)。运行这个示例,FFmpeg 须编译为支持 libx264 & libfaac。
#替换列表
# $name - 流的名字。
# $app - 应用名。
# $addr - 客户端地址。
# $flashver - 客户端 flash 版本。
# $swfurl - 客户端 swf url。
# $tcurl - 客户端 tc url。
# $pageurl - 客户端页面 url。
可以在 exec 指令中定义 Shell 格式的转向符用于写输出和接收输入。支持如下
exec_static ffmpeg -i http://example.com/video.ts -c copy -f flv rtmp://localhost/myapp/mystream; #类似于 exec 指令,但在 nginx 启动时将运行定义的命令。因为(启动时)尚无会话上下文,不支持替换。
exec_kill_signal term;#设置进程终止信号。默认为 kill(SIGKILL)。你可以定义为数字或者符号名(POSIX.1-1990 信号)。
respawn off;#如果打开 respawn 子进程,进程终止时发布会仍然继续。默认为打开。
respawn_timeout 10s;#启动新的子实例之前,设置 respawn 超时时间。默认为五秒
meta off;#切换发送元数据到客户端。默认为 on。
interleave on;#切换交叉模式。在这个模式下,音频和视频数据会在同一个 RTMP chunk 流中传输。默认为 off。
wait_key on;#使视频流从一个关键帧开始。默认为 off
wait_video on;#在第一个视频帧发送之前禁用音频。默认为 off。可以和 wait_key 进行组合以使客户端可以收到具有所有其他数据的视频关键帧。然而这通常增加连接延迟。您可以通过在编码器中调整关键帧间隔来减少延迟。
publish_notify on;#发送 NetStream.Publish.Start 和 NetStream.Publish.Stop 给用户。默认为 off。
drop_idle_publisher 10s;#终止指定时间内闲置(没有音频/视频数据)的发布连接。默认为 off。注意这个仅仅对于发布模式的连接起作用(发送 publish 命令之后)。
sync 10ms;#同步音频和视频流。如果用户带宽不足以接收发布率,服务器会丢弃一些帧。这将导致同步问题。当时间戳差超过 sync 指定的值,将会发送一个绝对帧来解决这个问题。默认为 300 ms。
play_restart off;#使 nginx-rtmp 能够在发布启动或停止时发送 NetStream.Play.Start 和 NetStream.Play.Stop 到每个用户。如果关闭的话,那么每个用户就只能在回放的开始和结束时收到这些通知了。默认为 on。
record off;#切换录制模式。流可以被记录到 flv 文件。本指令指定应该被记录的:
# off - 什么也不录制
# all - 音频和视频(所有)
# audio - 音频
# video - 视频
# keyframes - 只录制关键视频帧
# manual - 用不自动启动录制,使用控制接口来启动/停止
#在单个记录指令中可以有任何兼容的组合键。
on_play http://baidu.com;#设置 HTTP 播放回调。每次一个客户分发播放命令时,一个 HTTP 请求异步发送,命令处理会挂起 - 直到它返回结果码。之后再解析 HTTP 结果码。
# HTTP 2XX 返回码的话继续 RTMP 会话。
# HTTP 3XX 返回码的话 重定向 RTMP 到另一个流,这个流的名字在 HTTP 返回头的 Location 获取。如果新流的名字起始于 rtmp:// 然后远程 relay 会被创建。relay 要求 IP 地址是指定的而不是域名,并且只工作在 1.3.10 版本以上的 nginx。另请参考 notify_relay_redirect。
# 其他返回码的话 RTMP 连接丢弃。
#HTTP 请求接收到一些个参数。在 application/x-www-form-urlencoded MIME 类型下使用 POST 方法。以下参数会被传送给调用者:
# call=play。
# addr - 客户端 IP 地址。
# app - application 名。
# flashVer - 客户端 flash 版本。
# swfUrl - 客户端 swf url。
# tcUrl - tcUrl。
# pageUrl - 客户端页面 url。
# name - 流名。
#出了上述参数之外其他所有播放命令参数显式地发送回调。例如如果一个流由 url rtmp://localhost/app/movie?a=100&b=face&foo=bar 访问,然后呢 a,b 和 foo 发送回调。
on_publish url; #同上面提到的 on_play 一样,唯一的不同点在于这个指令在发布命令设置回调。不同于远程 pull,push 在这里是可以的。
on_done url;#播放禁止回调
on_play_done url;#播放结束回调
on_publish_done url#推送结束回调
...
#更多请见 https://www.cnblogs.com/surplus/p/12632549.html
}
application hls {
live on;
hls_path /nginxdata; # 这里跟启动命令-v /seventyseven/nginx-rtmp/data:/nginxdata 对应上
hls_fragment 5s;
record off;
}
}
}
附录.ffmpeg使用详解
附录.nginx-rtmp鉴权播放
详见: