一、綜述
引用自知乎 作為程序員,你有哪些正在做的個(gè)人項(xiàng)目?
從今年年初開(kāi)始,公司就沒(méi)什么事了,混吃等死,總琢磨著寫(xiě)點(diǎn)玩意兒,在github上閑逛,偶爾發(fā)現(xiàn)些bug,能解的就解了。這兩年直播不是挺火么?我就用RTSP,RTMP等搜了下相關(guān)的開(kāi)源項(xiàng)目,找到兩個(gè):srs(simple-rtmp-server)和nginx-rtmp-module。
前者是國(guó)人楊成立發(fā)起的,國(guó)內(nèi)使用它的廠商很多,遺憾的是3.x版已經(jīng)閉源。而后者是一個(gè)俄羅斯人發(fā)起的,遺憾的是作者已經(jīng)多年不更新了。后來(lái)發(fā)現(xiàn)nginx-rtmp-module不支持HTTP方式播放直播流,而這是很多廠商支持的,況且Nginx本身就是個(gè)優(yōu)秀的Web服務(wù)器,對(duì)HTTP協(xié)議支持得很好,那為什么不在nginx-rtmp-module上支持HTTP方式播放直播流呢?說(shuō)干就干,于是從5月開(kāi)始加功能,一直到7月底,基本把HTTP直播播放的功能加上了:https://github.com/winshining/nginx-http-flv-module
以下參考nginx-http-flv-module作者的
基于nginx-rtmp-module模塊實(shí)現(xiàn)的HTTP-FLV直播模塊nginx-http-flv-module(一)
基于nginx-rtmp-module模塊實(shí)現(xiàn)的HTTP-FLV直播模塊nginx-http-flv-module(二)
基于nginx-rtmp-module模塊實(shí)現(xiàn)的HTTP-FLV直播模塊nginx-http-flv-module(三)
近幾年直播行業(yè)火爆,開(kāi)源的直播軟件解決方案有SRS(Simple-RTMP-Server)和nginx-rtmp-module,前者是國(guó)人發(fā)起的一個(gè)優(yōu)秀的開(kāi)源項(xiàng)目,目前國(guó)內(nèi)很多公司都使用它作為直播解決方案,由C++編寫(xiě);后者依賴Nginx,以第三方模塊的方式提供直播功能,由C編寫(xiě)。
SRS采用多線程方式(經(jīng)網(wǎng)友提醒更正:是單線程+協(xié)程方式),性能優(yōu)秀,經(jīng)受住了眾多場(chǎng)景的考驗(yàn),但是SRS3已經(jīng)閉源(更正:是有一段時(shí)間閉源了,現(xiàn)在又開(kāi)源了);
nginx-rtmp-module是采用多進(jìn)程方式,Nginx的性能優(yōu)秀,但是據(jù)網(wǎng)友測(cè)試,同為單進(jìn)程條件下,nginx-rtmp-module的性能不如SRS,并且nginx-rtmp-module的作者已經(jīng)很久沒(méi)有更新版本了,支持的功能也有限,例如不支持HTTP方式的FLV直播,而這是國(guó)內(nèi)直播行業(yè)普遍采用的方式;再如推流不支持upstream,無(wú)法分布式部署功能;還有飽受詬病的播放響應(yīng)延遲時(shí)間很長(zhǎng)的問(wèn)題(即俗稱的不能秒播)等。
我在nginx-rtmp-module的基礎(chǔ)上實(shí)現(xiàn)了基于HTTP方式的FLV直播功能,支持GOP緩存,減少了首屏?xí)r間;支持流式和chunked兩種HTTP響應(yīng)格式;修復(fù)nginx-rtmp-module沒(méi)有l(wèi)isten配置項(xiàng)時(shí),推拉流失敗的問(wèn)題;解決nginx-rtmp-module已知的bug,見(jiàn)nginx-http-flv-module,歡迎下載測(cè)試和反饋bug,也歡迎提PR。有問(wèn)題或者建議,可以加Q群:711969608詳聊,注意:進(jìn)群請(qǐng)先查看群說(shuō)明和群公告,編譯問(wèn)題(除了一些確實(shí)是因?yàn)榧嫒輪?wèn)題不能編譯的),能通過(guò)README和wiki解決的配置問(wèn)題請(qǐng)優(yōu)先自行解決,回復(fù)問(wèn)題不是群友的義務(wù),因?yàn)榻^大多數(shù)群友有自己的工作。
目前已經(jīng)有很多個(gè)人和廠商準(zhǔn)備將本模塊商用。據(jù)網(wǎng)友反饋,國(guó)外已經(jīng)有直播網(wǎng)站在使用這個(gè)模塊。國(guó)內(nèi)準(zhǔn)備商用的廠商有華為,中興(網(wǎng)友告知,未確認(rèn))等。另外據(jù)網(wǎng)友反饋,EasyDSS和EasyNVR也集成了本模塊的功能。網(wǎng)友和廠商陸續(xù)反饋過(guò)不少bug,修復(fù)后功能已經(jīng)越來(lái)越穩(wěn)定,在此表示感謝。

二、SRS部分資料
參考
SRS大神楊成立
SRS(simple-rtmp-server)直播點(diǎn)播服務(wù)器
SRS Github
SRS HTTP FLV
CRtmpServer轉(zhuǎn)推流到Nginx Rtmp及SRS(SimpleRtmpServer)的經(jīng)歷
通讀SRS后的總結(jié)文檔以及搭建直播平臺(tái)的初次嘗試
SRS/3.0,OuXuli,是一個(gè)流媒體集群,支持RTMP/HLS/FLV,高效、穩(wěn)定、易用,簡(jiǎn)單而快樂(lè)。
三、nginx-rtmp-module搭建
參考
Nginx - Windows下Nginx初入門(mén)
Windows下Nginx的啟動(dòng)、停止等命令
在Windows下搭建基于nginx的視頻直播和點(diǎn)播系統(tǒng)
Linux&Windows搭建基于nginx的視頻點(diǎn)播服務(wù)器
在windows下搭建、配置nginx流媒體服務(wù)器,并進(jìn)行rtmp流的推流、拉流測(cè)試
在nginx官網(wǎng)上下載的nginx是不帶rtmp模塊的。如果只是做點(diǎn)播,Nginx本身不需要任何額外的模塊就支持flv和mp4格式的點(diǎn)播,也支持拖動(dòng)進(jìn)度條.
所幸,已經(jīng)有大神做好了nginx的編譯,而且集成了很多nginx模塊,其中就已經(jīng)包括了nginx-rtmp-module。
下載地址:http://nginx-win.ecsds.eu/,詳細(xì)說(shuō)明可參見(jiàn):Readme nginx-win version.txt
我下載的是nginx 1.7.11.3 Gryphon這個(gè)版本。

1.nginx常用命令
start nginx
nginx -s reload
nginx -s stop
nginx -c 指定一個(gè)配置文件。默認(rèn)的路徑是安裝目錄下的conf/nginx.conf
nginx -t 檢查配置文件是否正確
修改conf/nginx.conf配置文件,然后在nginx.exe路徑下命令行(PowerShell不行)運(yùn)行nginx -s reload重新加載配置。
如果報(bào)錯(cuò)nginx: [error] OpenEvent("Global\ngx_reload_38192") failed (2: The system cannot find the file specified),則說(shuō)明nginx服務(wù)器未啟動(dòng)成功。
啟動(dòng)nginx成功的另一個(gè)標(biāo)志是在nginx 1.7.11.3 Gryphon文件夾的logs目錄下生成nginx.pid文件,如下圖所示:

該nginx.pid文件存放的是當(dāng)前nginx主進(jìn)程的ID號(hào),打開(kāi)該文件后可以看到里面存放著“3980”這個(gè)數(shù)字,這個(gè)數(shù)字就是本次啟動(dòng)nginx主進(jìn)程的ID號(hào)(每次啟動(dòng)的數(shù)字都會(huì)不同的)

我們可以在任務(wù)管理器中查詢到該進(jìn)程,則表示nginx啟動(dòng)成功了。

2.配置rtmp及點(diǎn)播
參考配置如下
worker_processes 1; #Nginx進(jìn)程數(shù),建議設(shè)置為等于CPU總核數(shù)
events {
worker_connections 1024; #工作模式與連接數(shù)上限
}
rtmp_auto_push on;
#RTMP服務(wù)
rtmp{
server{
listen 1935; #服務(wù)端口
chunk_size 4096; #數(shù)據(jù)傳輸塊的大小
application vod{
play ./vod; #視頻文件存放位置
}
application live{
live on; #開(kāi)啟直播
hls on; #開(kāi)啟hls直播。這個(gè)參數(shù)把直播服務(wù)器改造成實(shí)時(shí)回放服務(wù)器
#wait_key on; #對(duì)視頻切片進(jìn)行保護(hù),這樣就不會(huì)產(chǎn)生馬賽克了
hls_path ./m3u8File; #切片視頻文件存放位置(HLS,m3u8文件存放位置)
hls_fragment 2s; #每個(gè)視頻切片的時(shí)長(zhǎng)
hls_playlist_length 16s;
recorder myRecord{
record all manual;
record_suffix _.flv;
record_path ./rec;
}
#hls_continuous on; #連續(xù)模式
#hls_cleanup on; #對(duì)多余的切片進(jìn)行刪除
#hls_nested on; #嵌套模式
}
}
}
#HTTP服務(wù)
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
location /live_hls{
types{
#m3u8 type設(shè)置
application/vnd.apple.mpegurl m3u8;
#ts分片文件設(shè)置
video/mp2t ts;
}
#指向訪問(wèn)m3u8文件目錄
alias ./m3u8File;
add_header Cache-Control no-cache; #禁止緩存
}
location /control{
rtmp_control all;
}
location /stat{
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl{
root ./nginx-rtmp-module-master;
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
3.關(guān)于使用FFmpeg推流時(shí),live目錄的理解
在nginx.conf中
#RTMP 直播流配置
application live{
live on;
record off;
}
使用“ ffmpeg -i "D:\nginx1.7\vod\jay.flv" -f flv rtmp://127.0.0.1/live/test1”中推流。“ live ”其實(shí)是一個(gè)虛擬目錄,這個(gè)目錄和windows中傳統(tǒng)的目錄是不一樣的,可以理解為推流到的流媒體服務(wù)器的模塊路徑或者虛擬路徑,但是實(shí)際在流媒體服務(wù)器中是不會(huì)存在這個(gè)目錄的,因?yàn)樗翘摂M的。這個(gè)目錄其實(shí)是用來(lái)區(qū)分流的,表示要推流到的地址;推流地址為多少,拉流地址就得為多少。比如推流指令為“ ffmpeg -i video3.mp4 -f flv rtmp://127.0.0.1/live/test1 ”,使用ffplay進(jìn)行拉流的指令就得為“ ffplay rtmp://127.0.0.1/live/test1”,可以看到推流地址和拉流地址是對(duì)應(yīng)的。
這里推流很快就結(jié)束了,然后就無(wú)法播放了??梢约右幌聄e參數(shù)
"-re":按視頻幀率的速度讀取輸入
"-c copy":輸出流使用和輸入流相同的編解碼器
"-f flv":指定輸出流封裝格式為flv
4.直播狀態(tài)監(jiān)控
location /stat{
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl{
root ./nginx-rtmp-module;
}
然后我們?cè)跒g覽器中輸入http://127.0.0.1/stat。如下圖所示,在下面的頁(yè)面中我們就可以進(jìn)行直播狀態(tài)監(jiān)聽(tīng)了。

5.點(diǎn)播
上面這個(gè)配置就是點(diǎn)播了:
application vod{
play ./vod; #視頻文件存放位置
}
使用VLC播放rtmp://127.0.0.1/vod/jay.flv即可。
當(dāng)然點(diǎn)播不使用RTMP插件nginx自身也是可以實(shí)現(xiàn)點(diǎn)播服務(wù)的。那就是配置http的location部分:
server {
listen 80;
server_name localhost;
location /01.mp4 {
root vod;
}
location /jay.flv {
root vod;
}
location /265.mp4 {
root vod;
}
現(xiàn)在使用http://127.0.0.1/jay.flv也可以點(diǎn)播了
6.配置hls
參考在windows下配置nginx流媒體服務(wù)器,使其支持hls協(xié)議的直播和rtmp點(diǎn)播
這里我還是把hls從live配置中剝離出來(lái),單獨(dú)做了一個(gè)配置
rtmp{
server{
listen 1935;
application vod {
play ./vod; #這是一個(gè)目錄的名稱,如果是linux,則寫(xiě)具體位置如/opt/video
}
#直播流配置
application live{
live on;
recorder myRecord{
record all manual;
record_suffix _.flv;
record_path ./rec;
}
}
application hls {
live on;
hls on;
hls_path ./m3u8File;
hls_fragment 5s;
}
}
}
然后http配置:
location /hls {
types {
application/vnd.apple.mpegurl m3u8;#m3u8 type設(shè)置
video/mp2t ts;#ts分片文件設(shè)置
}
alias ./m3u8File;
expires -1;
add_header Cache-Control no-cache;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept";
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
}
推流
ffmpeg -re -i "D:\nginx1.7\vod\jay.flv" -vcodec copy -acodec copy -f flv rtmp://127.0.0.1:1935/hls/cctv1
可以在m3u8File文件夾下看到許多TS文件和m3u8文件,并且一直在更新。
此時(shí)在VLC中播放http://127.0.0.1:80/hls/cctv1.m3u8即可看到畫(huà)面,注意剛開(kāi)始推流時(shí)可能還無(wú)法播放,要延遲幾秒等m3u8生成后才能播放。
四、nginx-http-flv-module搭建
參考
https://github.com/winshining/nginx-http-flv-module/blob/master/README.CN.md
注意nginx-http-flv-module 包含了 nginx-rtmp-module 所有的功能,所以不要將 nginx-http-flv-module 和 nginx-rtmp-module 一起編譯。
只是做測(cè)試的話,還是找WINDOWS版本的省事兒。感謝csdn的博主bugNotBug,提供不需要積分的下載鏈接nginx-1.19.6_nginx-http-flv-module(64位),這里可以參考此博主另一個(gè)鏈接nginx-1.19.3_nginx-http-flv-module.rar,把里面的http-flv.conf復(fù)制過(guò)去。
推流:
ffmpeg -re -i "D:\nginx1.7\vod\jay.flv" -vcodec copy -acodec copy -f flv rtmp://127.0.0.1:1935/myapp/cctv1
拉h(huán)ttp-flv流
http://127.0.0.1:80/live?port=1935&app=myapp&stream=cctv1
拉rtmp流
rtmp://127.0.0.1/myapp/cctv1
當(dāng)然這個(gè)模塊參照上面HLS的設(shè)置,也是可以提供HLS直播的,不過(guò)要另推hls流
ffmpeg -re -i "D:\nginx1.7\vod\jay.flv" -vcodec copy -acodec copy -f flv rtmp://127.0.0.1:1935/hls/cctv1