有三种运行方式三种运行方式:
-
windows下可以直接获取编译好的安装包,然后运行
-
linux版本可以参考本文目录[linux源码编译及测试]
构建好后打开 release/xx/Debug 目录,可以看到有 config.ini 是项目的配置文件。其中需要特别注意的有两个地方:
- 一是 [http] 的 port,因为 ZLMediaKit 项目也有很多 API 接口,都需要通过这个接口来访问,包括生成的播放的URL,都是这个端口,如遇到端口被你的其它服务占用,可自行配置。
- 二是 [rtp_proxy] 的 port,是我们下面 MVP 项目配置的 media.port
- docket版本
docker方式
使用单个端口接收视频流
# 此镜像为 zlmediakit 开发团队提供,推荐
docker run -d -p 1935:1935 -p 8091:80 -p 8554:554 \
-p 10000:10000 -p 10000:10000/udp -p 8000:8000/udp \
--name zlmediakit \
zlmediakit/zlmediakit:Release.last
docker run -d -it -p 8091:80 -p 10000:10000 -p 10000:10000/udp panjjo/zlmediakit
# 使用多个端口接收视频流
# 30000-30500端口端保持内外一致
docker run -it -p 8091:80 -p 30000-30500:30000-30500/udp -p 30000-30500:30000-30500/tcp zlmediakit/zlmediakit:Release.last
# 自定义启动ZLMediaKit
docker run -d -p 1935:1935 -p 8091:80 -p 8554:554 \
-p 10000:10000 -p 10000:10000/udp -p 8000:8000/udp \
-p 30000-30500:30000-30500 -p 30000-30500:30000-30500/udp \
--name zlmediakit \
--network woniu_network \
--ip 172.0.0.68 \
--restart=always \
--env MODE=standalone \
-e TZ="Asia/Shanghai" \
-v /home/docker/zlmediakit/media/bin:/opt/media/bin \
-v /home/docker/zlmediakit/media/conf:/opt/media/conf \
zlmediakit/zlmediakit:Release.last
端口 | 说明 | 是否必须 | WVP对应配置(这是一个国标平台,可以不看这一列) |
---|---|---|---|
-p 1935:1935 | rtmp服务器监听地址为1935,将1925端口映射到外部的1935 | 否 | |
-p 8091:80 | HTTP服务器监听端口为80,将80端口映射到外部的8091 | 是 | 对应media的httpPort |
-p 8554:554 | rtsp服务器监听端口为554 ,将554 端口映射到外部的8554 | 否 | |
-p 10000:10000 | RTP 代理方式 | 否 | 对应media的rtpProxyPort |
-p 8000:8000/udp | RTC UDP服务器播放监听端口为8080,将8080端口映射到外部的1935 | 否 | |
-p 30000-30500:30000-30500 | 否 | 对应media.rtp.portRange |
- docker查看启动
docker ps
- docker查看运行日志
docker logs -f xxx
linux源码编译及测试
编译启动
(1) 安装依赖
# 安装编译器
sudo apt install build-essential cmake
# 其它依赖库
sudo apt-get install libssl-dev libsdl-dev libavcodec-dev libavutil-dev ffmpeg
(2) 获取代码
- 请不要使用github 下载zip包的方式下载源码,务必使用git克隆ZLMediaKit的代码,因为ZLMediaKit依赖于第三方代码,zip包不会下载第三方依赖源码,你可以这样操作:
#国内用户推荐从同步镜像网站gitee下载
git clone --depth 1 https://gitee.com/xia-chu/ZLMediaKit
cd ZLMediaKit
#千万不要忘记执行这句命令 -- 更新子模块
git submodule update --init
(3)构建和编译项目
- 由于开启webrtc相关功能比较复杂,默认是不开启编译的,默认编译如下
mkdir build
cd build
cmake ..
make -j4
(4)启动服务
- 可执行文件是 ZLMediaKit/release/linux/Debug/MediaServer
cd ../release/linux/Debug/
# 可以通过-h来查看命令支持的参数
sudo ./MediaServer -d
服务启动好了以后,就可以在客户端推流,简单起见,就在同一台机器上推流,不同主机的话,修改下 ip 地址即可。 如下测试
测试
(0) 准备
测试用视频下载
- 1、地址:http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4 1分钟
- 2、地址:http://vjs.zencdn.net/v/oceans.mp4
- 3、地址:https://media.w3.org/2010/05/sintel/trailer.mp4 52秒
- 4、http://mirror.aarnet.edu.au/pub/TED-talks/911Mothers_2010W-480p.mp4 10分钟
其他各种格式,MP4, flv, mkv, 3gp 视频下载
- https://www.sample-videos.com/index.php#sample-mp4-video
(1) 使用rtsp方式推流
# h264编码
ffmpeg -re -i test.mp4 -vcodec h264 -acodec aac -f rtsp -rtsp_transport tcp rtsp://127.0.0.1/live/test
# h265编码
ffmpeg -re -i test.mp4 -vcodec h265 -acodec aac -f rtsp -rtsp_transport tcp rtsp://127.0.0.1/live/test
ffmpeg 推流成功后,注意看下服务器端的输出信息
可以看到几个媒体注册的消息,同时支持 rtsp、rtmp、hls等协议,现在可以另一台机器上开个播放器播放了,像 vlc、ffplay 都可以,播放的 url 是
rtsp://192.168.0.59/live/test
rtmp://192.168.0.59/live/test
http://192.168.0.59/live/test/hls.m3u8
其中192.168.0.59 是开启视频服务的机器 IP 地址
注意,必须在关闭之前测试
(3) 使用rtmp方式推流
ffmpeg -re -i test.mp4 -vcodec h264 -acodec aac -f flv rtmp://127.0.0.1/live/test
# RTMP标准不支持H265,但是国内有自行扩展的,如果你想让ffmpeg支持RTMP-H265,需要重新编译ffmpeg,可以参考:https://github.com/ksvc/FFmpeg/wiki/hevcpush
ffmpeg 推流成功后,服务器端产生的 url 与 上面的rtsp 推流方式类似,这里不再赘述
(4) 使用rtp方式推流
ffmpeg -re -i test.mp4 -vcodec h264 -acodec aac -f rtp_mpegts rtp://127.0.0.1:10000
ffmpeg 推送后,服务器端输出了对应流的 ID
拿到了这个 ID 后,这时候就可以拼接 url 进行播放了,如
rtsp://192.168.0.59/rtp/8143BDFE
rtmp://192.168.0.59/rtp/8143BDFE
http://192.168.0.59/rtp/8143BDFE/hls.m3u8
主程序和配置文件
主服务程序
程序所在路径
- 在编译zlmediakit后,会生成MediaServer主程序,该程序相对路径为
release/${platform}/${build_type}/MediaServer
。- ${platform}根据您的操作系统,可能为windows/linux/mac
- ${build_type}根据您cmake时指定的编译类型,可能为Debug/Release
- 我的可执行文件在: ZLMediaKit/release/linux/Debug/MediaServer
MediaServer 的启动参数如下
$ ./MediaServer -h
-h --help 无参 默认:null 选填 打印此信息
-d --daemon 无参 默认:null 选填 是否以Daemon方式启动
-l --level 有参 默认:0 选填 日志等级,LTrace~LError(0~4)
-m --max_day 有参 默认:7 选填 日志最多保存天数
-c --config 有参 默认:/home/oceanstar/CLionProjects/ZLMediaKit/release/linux/Debug/config.ini 选填 配置文件路径
-s --ssl 有参 默认:/home/oceanstar/CLionProjects/ZLMediaKit/release/linux/Debug/default.pem 选填 ssl证书文件或文件夹,支持p12/pem类型
-t --threads 有参 默认:4 选填 启动事件触发线程数
-v --version 无参 默认:null 选填 显示版本号
- -d(–daemon):是否以守护程序的方式启动,守护进程只做一件事,就是判断子进程(这个才是干活的进程)是否已经退出,退出后会不断尝试重启子进程
- -l(–level): 指定日志打印等级,赋值范围为0~4,等级越高,日志越少。
- -m(–max_day): 日志文件保存天数,程序本次运行期间的日志如果超过这个天数,就会被删除。
- -c(–config): 指定配置文件路径,配置文件为ini格式
- -s(–ssl): 指定ssl证书路径,证书格式支持p12和pem类型,里面必须包含公钥和私钥,私钥不能有加密密码。如果指定文件夹,会加载文件夹下所有证书。
- -t(–threads): 指定事件驱动线程(干重活)和后台工作线程(干阻塞的活)个数。
启动方式
./MediaServer
./MediaServer -d
./MediaServer -d &
nohup ./MediaServer -d &
- 注意:
- 如果你启动MediaServer后需要关闭shell,用第三种方式,否则关闭shell会导致MediaServer一起被关闭。
- 如果你会使用到FFmpeg相关功能,你应该这样启动程序
nohup ./MediaServer -d &
,否则在fork FFmpeg进程时会导致MediaServer进程挂起。
配置文件的热加载
- 修改并保存配置文件后,在shell里面输入killall -1 MediaServer就能使ZLMediaKit热加载配置文件
关闭服务器
- 如果你是后台启动方式,请在shell中输入killall -2 MediaServer以便优雅关闭服务器(程序收到SIGINT信号后会自动释放资源并退出)。
- 否则你可以同时按下Ctr + C退出程序。
配置文件
当主程序MediaServer
启动时,默认使用的配置文件是其同目录下的config.ini
,,当然也可以通过 -c 参数来指定其它路径下的配置文件
./MediaServer -c test.ini
修改并保存配置文件后,在 shell 里面输入 killall -1 MediaServer
就能使 ZLMediaKit
热加载配置文件,而不必先关闭服务然后再开启
URL规则
流媒体源
当主程序启动后,客户端启动推流(这里以 rtsp 方式为例,rtmp 和 rtp 也类似)
ffmpeg -re -i test.mp4 -vcodec h264 -acodec aac -f rtsp -rtsp_transport tcp rtsp://127.0.0.1/live/test
这时,在 MediaServer 主程序的输出中,可以看到类似下图的信息
在ZLMediaKit
中,有个叫做流媒体源(MediaSource
)的数据对象,它可以被用于直播转发、推流转发等功能,目前支持5种类型的流媒体源,分别是 RtspMediaSource、RtmpMediaSource、HlsMediaSource、TSMediaSource 和 FMP4MediaSource
在 ffmpeg 推流成功后,对应到播放地址分别是
rtsp://192.168.0.59/live/test
rtmp://192.168.0.59/live/test
http://192.168.0.59/live/test/hls.m3u8
http://192.168.0.59/live/test.live.ts
http://192.168.0.59/live/test.live.mp4
这些 url,使用播放器 ffplay 是可以直接播放的
URL的组成
以 rtsp://somedomain.com:554/live/test?token=abcdefg&field=value
为例,该 url 分为以下几个部分
- 协议(
scheam
) :rtsp
协议 - 虚拟主机(
vhost
) :somedomain.com
,该字段既可以是域名也可以是 ip 地址,如果是 ip 的话,则对应的虚拟主机为__defaultVhost__
- 服务端口号(
port
) :554
,如果不指定端口号,则使用协议默认端口号。rtsp
默认端口554
,rtmp
默认端口1935
,http
默认端口80
- 应用名(
app
) : 此例是live
- 流 ID(
streamid
) : 此例是test
- 参数(
args
) :token=abcdefg&field=value
,格式跟 http 一致,url 参数主要用于播放、推流鉴权,在触发 hook api 时,会把这些参数提交给第三方业务服务器
点播
ZLMediaKit
的点播一般通过mp4
文件实现,推荐大家使用 http mp4 点播,这样是最简单,服务器也无需解复用 mp4 文件,当然 ZLMediaKit 目前也支持 rtsp、rtmp、http-flv、websocket-flv 的 mp4 点播, 对应的 url 跟直播 url 类似
- 要在
ZLMediaKit
中实现点播,只需要将mp4
文件放到www/record
下,默认情况下,应用名是record
,可以在config.ini
中修改
那么,点播 URL 就是
rtsp://192.168.0.59/record/test.mp4
rtmp://192.168.0.59/record/test.mp4
http://192.168.0.59/record/test.mp4 (通用http点播,推荐)
HTTP API
ZLMediaKit 支持 http api
,具体哪些支持哪些接口可以参考:
http api使用示例
当我们启动 MediaServer 时,可以注意到 http api 接口默认已经启动
/index/api/getApiList
(1) 方式:
- GET
(2) 测试
- 本地使用:直接在浏览器中输入
http://127.0.0.1/index/api/getApiList
即可
- 如果是在其它主机上操作的话,接口会返回错误:
http://192.168.0.59/index/api/getApiList
- 从提示中可以看到,接口中需要添加参数 secret,也就是需要进行鉴权,这是出于安全的考虑,这个 secret 在配置文件 config.ini 中有定义,直接拷贝出来,跟在 /index/api/getApiList 后面,为:
http://192.168.0.59/index/api/getApiList?secret=035c73f7-bb6b-4889-a715-d9eb2d1925cc
- 考虑到接口调试的便利性,推荐大家使用工具 Postman
/index/api/addFFmpegSource
使用 http api 的方式来拉取一路 rtmp摄像头视频流,来代替前面教程中使用的 ffmpeg 命令行推流
参数:
- 比如:
{{ZLMediaKit_URL}}/index/api/addFFmpegSource?secret={{ZLMediaKit_secret}}&src_url=http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4&dst_url=rtmp://127.0.0.1/live/hks2&timeout_ms=10000&enable_hls=0&enable_mp4=0
rtmp://127.0.0.1/live/hks2
-
请求成功后,服务器就开始去拉取 rtmp视频流了,然后打开播放器,就可以进行播放了
-
最后,如果要取消拉流的话,可以使用 /index/api/delFFmpegSource 接口进行关闭
/index/api/addStreamProxy
安防监控常见使用场景中,经常会出现这种情况:一个网络摄像机/网络录像机,有多个用户需要同时观看实况。而设备的取流是有上限的,无法满足所有用户都能观看成功。比如,一台IPC的取流上限只有10路,当已经有10个用户在局域网电脑上进行了实况预览,那么如果局域网内还有另一个用户也想访问实况就不行了。再或者NVR设备,假设支持的取流上限是64路,如果某个用户播放端上已经看了40路实况,那么就只剩下24路实况供其它用户观看了。
要解决以上限制,我们可以使用流媒体服务器来对设备的视频流进行转发,摄像机的视频流经过流媒体服务器转发到不同的用户播放段,用户将不再直接向摄像头拉流,这样就能降低设备的取流压力,满足了都用户的需求
在监控网络传输中,流媒体技术也可以降低网络中的带宽限制。当多个用户要查看同一路监控图像时,流媒体服务器将从IPC/NVR取流,并进行视频流的分发,对IPC/NVR而言只需要取一路视频流,服务器解除了发流设备的带宽限制以及发流端到流媒体的带宽限制,对于后续部分的监控网络传输带宽是没有影响的,这样就可以减少了网络的负荷。
操作过程
1)、启动服务器,直接运行MediaServer即可。
2)、配置rtsp地址,将我们摄像机的rtsp拉流地址配置到服务器,由服务器向IPC拉流,然后通过播放端使用VLC向服务器拉流。这样不管有多少个播放端,都不需要直接向IPC拉流了,降低了IPC的负载。
http://127.0.0.1/index/api/addStreamProxy?vhost=__defaultVhost__&app=live&stream=test1&url=rtsp://admin:123456@192.168.31.66/media/video2&rtp_type=0
3)、VLC拉流。VLC中,媒体->打开网络串流,输入拉流地址rtsp://127.0.0.1/live/test1,点击播放。
推流
/index/api/getMediaList
- 功能:获取流列表
- 参数:
参数 | 是否必选 | 说明 |
---|---|---|
secret | Y | api操作密钥 |
schema | N | 筛选协议,比如rtsp、rtmp |
vhost | N | 筛选虚拟主机,例如__defaultVhost__ |
app | N | 应用名,比如live |
stream | N | 流ID |
支持webrtc
什么是webrtc
WebRTC 是 Web Real Time Communication 的缩写,也被称为网络实时通信,是由 Google 和其他一些大公司推动的一个开源项目,它通过 Javascript API 来实现无插件的实时通信。WebRTC 促进了浏览器到浏览器的语音呼叫、视频聊天和文件共享应用的大力发展。目前大多数浏览器已经支持了 webRTC 。
架构图如下:
- 最上层的 web app,是 Web 开发者自己开发的程序,主要利用的是 javascript 的
web api
web api
,WebRTC 标准的 API (javascript 版),由 w3c 来维护
- 媒体层,笼统来讲,它是
WebRTC
的底层核心部分,包括了音频和视频数据的采集、编码、传输,除此之外,还有会话的管理、点对点的链接等,采用的 C++ 语言编写
实践
(1) 依赖
- 安装 openssl,ubuntu 18.04 对应的 openssl 版本是 1.1.1
sudo apt-get install libssl-dev
- 如果你的操作系统版本比较老的话,也可以从源码开始安装 openssl,命令如下
git clone https://github.com/openssl/openssl.git
cd openssl
./config
make
sudo make install
- 然后是安装 libsrtp,即 Secure Realtime Transport Protocol
git clone https://github.com/cisco/libsrtp.git
cd libsrtp
./configure --enable-openssl
make
sudo make install
(2)重新编译ZLMediaKit
cd ZLMediaKit
mkdir build
cd build
# 加入webrtc的编译选项
cmake .. -DENABLE_WEBRTC=on
make
- 在 cmake 的时候注意看看输出信息,确保 webrtc 功能已开启
- 编译成功后,生成的可执行文件在 release/linux/下,有一个MediaServer
(3)接下来,就可以启动服务了
sudo ./MediaServer -d
- 然后,使用 ffmpeg 推送一个本地视频文件到服务器
ffmpeg -re -i test.mp4 -vcodec h264 -acodec aac -f flv rtmp://127.0.0.1/live/test
-
完成后,我们打开 chrome 浏览器,输入
http://192.168.0.59
,这个 ip 地址是 MediaServer 服务器的地址
-
选择
6 webrtc
,这里我们没有证书,所以忽略掉https
的警告
-
设置下分辨率,点击开始,上方的播放器就开始播放推送的视频了
支持webhook
- 简单来说,webhook是一个HTTP回调,在大多数情况下,用于系统之间的通信。当系统中的某个事件发生时,会以
HTTP POST
的方式告诉其他系统,以此来达到实时通知的效果 - 即:ZLMediaKit可以把内部的一些事件通过HTTP POST第三方HTTP服务器的方式通知出去
- webhook 通常的数据传输格式是 json 或者 xml,使用的 http 请求方法是 POST
- 以下是相关的默认配置:
[hook]
enable=1 // 是否开启http hook,如果选择关闭,ZLMediaKit将采取默认动作(例如不鉴权等)
admin_params=secret=035c73f7-bb6b-4889-a715-d9eb2d1925cc //超级管理员的url参数,如果访问者url参数与此一致,那么rtsp/rtmp/hls/http-flv/ws-flv播放或推流将无需鉴权。该选项用于开发者调试用。
timeoutSec=10 // 事件触发http post超时时间。
on_flow_report=https://127.0.0.1/index/hook/on_flow_report
on_http_access=https://127.0.0.1/index/hook/on_http_access
on_play=https://127.0.0.1/index/hook/on_play
on_publish=https://127.0.0.1/index/hook/on_publish
on_record_mp4=https://127.0.0.1/index/hook/on_record_mp4
on_rtsp_auth=https://127.0.0.1/index/hook/on_rtsp_auth
on_rtsp_realm=https://127.0.0.1/index/hook/on_rtsp_realm
on_shell_login=https://127.0.0.1/index/hook/on_shell_login
on_stream_changed=https://127.0.0.1/index/hook/on_stream_changed
on_stream_none_reader=https://127.0.0.1/index/hook/on_stream_none_reader
on_stream_not_found=https://127.0.0.1/index/hook/on_stream_not_found
on_server_started=https://127.0.0.1/index/hook/on_server_started
on_server_keepalive=https://127.0.0.1/index/hook/on_server_keepalive
- 如果是鉴权事件,且访问IP是127.0.0.1或者鉴权url参数与admin_params一致,那么会直接鉴权成功(不会触发鉴权web hook)。
关于事件
(1)on_flow_report
- 解释:流量统计事件,播放器或者推流器断开时并且耗用流量超过特定阈值时会触发此事件,阈值通过配置文件 general.flowThreshold配置,此事件对回复不敏感
- 触发请求:
POST /index/hook/on_flow_report HTTP/1.1
Accept: */*
Accept-Language: zh-CN,zh;q=0.8
Connection: keep-alive
Content-Length: 298
Content-Type: application/json
Host: 127.0.0.1
Tools: ZLMediaKit
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
{
"mediaServerId" : "your_server_id",
"app" : "live", //流应用名
"duration" : 6, //tcp连接持续时间,单位是秒
"params" : "token=1677193e-1244-49f2-8868-13b3fcc31b17", //推流或播放URL参数
"player" : false, //true为播放器,false为推流器
"schema" : "rtmp", //播放或者推流的协议,可能是rtsp、rtmp、http
"stream" : "obs", // 流ID
"totalBytes" : 1508161, //耗费上下行流量总和,单位字节
"vhost" : "__defaultVhost__", //流虚拟主机
"ip" : "192.168.0.21", //客户端IP
"port" : 55345, // 客户端端口号
"id" : "140259799100960" // 服务器id,通过配置文件设置
}
默认回复:
POST /index/hook/on_http_access HTTP/1.1
Accept: */*
Accept-Language: zh-CN,zh;q=0.8
Connection: keep-alive
Content-Length: 583
Content-Type: application/json
Host: 127.0.0.1
Tools: ZLMediaKit
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
{
"mediaServerId" : "your_server_id",
"header.Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"header.Accept-Encoding" : "gzip, deflate",
"header.Accept-Language" : "en-US,en;q=0.5",
"header.Cache-Control" : "max-age=0",
"header.Connection" : "keep-alive",
"header.Host" : "10.0.17.132",
"header.Upgrade-Insecure-Requests" : "1",
"header.User-Agent" : "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0",
"id" : "140259799100960",
"ip" : "10.0.17.132",
"is_dir" : true,
"params" : "",
"path" : "/live/",
"port" : 65073
}
(2)on_http_access
- 解释:访问HTTP文件服务器上HLS之外的文件时触发
(3)on_play
- 解释:播放器鉴权事件,rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件;
- 如果流不存在,那么先触发on_play事件然后触发on_stream_not_found事件。
- 播放rtsp流时,如果该流启动了rtsp专属鉴权(on_rtsp_realm)那么将不再触发on_play事件。
(4)on_publish
- 解释:rtsp/rtmp/rtp推流鉴权事件
分析
端口分析
- 554 rtsp:rtsp服务器监听地址
- 322 rtsps:rtsps服务器监听地址
- 1935 rtmp:rtmp服务器监听地址
- 19350 rtmps:rtmps服务器监听地址
- 80 http:http服务器监听端口
- 443 https:https服务器监听端口
- 9000 telnet:调试telnet服务器监听端口
- 10000 proxy:udp和tcp代理服务器,支持rtp(必须是ts或ps类型)代理
submodule
cat .gitmodules
[submodule "ZLToolKit"]
path = 3rdpart/ZLToolKit
url = ../ZLToolKit
[submodule "3rdpart/media-server"]
path = 3rdpart/media-server
url = ../media-server
CMakeLists.txt分析
加载自定义模块
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
Dockerfile分析
需要安装的库
libssl-dev \
libmysqlclient-dev \
libx264-dev \
libfaac-dev \
libmp4v2-dev && \
测试中增加了
ffmpeg \
目录结构分析
- 3rdpart:第三方库
- jsoncpp:json库
- media-server:媒体服务器