*************************************************************************************************************************************************html
注意:強烈建議使用srs3.0,srs2.0存在的問題(回調,跨域)等問題不須要修改源碼,並且能夠修改生成mp4視頻。java
回調:node
# SRS推流開始,結束 def live_publish(request): # 添加磁盤檢測 if not mounted(): return HttpResponse(1) params = str(request.body, encoding="utf-8") object = json.loads(params) l_uuid = object.get('stream') live = Live.objects.get(uuid=l_uuid) live.status = 'living' live.save() return HttpResponse(0)
跨域:python
沒測,一直用nginx代理linux
MP4:nginx
後期打算直接生成mp4,替換以前的flvgit
*************************************************************************************************************************************************github
直播:rtmp+jwplayer數據庫
點播:h5(mp4文件)npm
弊端:兼容性差,貌似跟系統版本,瀏覽器,瀏覽器版本都有關。還有就是rtmp推流生成的文件是flv格式,須要轉碼成mp4才能點播。
固然是兼容性大大提升了,在pc端谷歌,火狐均可以播放,手機端火狐能夠,谷歌不行,其餘沒測。
樣式什麼的沒添加,官方的demon 直接copy過來。
Github:https://github.com/Bilibili/flv.js
解壓後進入mater:
構建:
npm install npm install -g gulp gulp release
在dist下生成了咱們須要的js
flv.html:
<!DOCTYPE html> <html> <head> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> </head> <body> <script src="flv.min.js"></script> <video id="videoElement"></video> <script> if (flvjs.isSupported()) { var videoElement = document.getElementById('videoElement'); var flvPlayer = flvjs.createPlayer({ type: 'flv', url: 'http://192.168.2.192/live/video.flv' }); flvPlayer.attachMediaElement(videoElement); flvPlayer.load(); flvPlayer.play(); } </script> </body> </html>
type能夠是mp4,flv。url的類型要對應,能夠是服務器的文件,也能夠是rtmp推流的臨時文件。
在這一步能夠測試下點播是否正常,文件應該放在http服務器下以http協議訪問,不能是文件形式訪問。http服務器能夠是nginx,python,tomcat等均可以
Github : https://github.com/ossrs/srs/wiki/v2_CN_SampleHttpFlv
這篇文章介紹的比較詳細,下面是簡單記錄步驟:
假定你已經下載並編譯好了SRS,能夠參考:SRS服務器搭建,ffmpeg 本地推流
首先複製conf中的http.flv.live.conf爲my.http.flv.live.conf,內容:
# the config for srs to remux rtmp to flv live stream. # @see https://github.com/ossrs/srs/wiki/v2_CN_DeliveryHttpStream # @see full.conf for detail config. listen 1935; max_connections 1000; daemon off; srs_log_tank console; http_server { enabled on; listen 80; dir ./objs/nginx/html; } vhost __defaultVhost__ { http_remux { enabled on; mount [vhost]/[app]/[stream].flv; hstrs on; } dvr { # https://github.com/ossrs/srs/wiki/v2_CN_DVR enabled on; dvr_path ./objs/nginx/html/[app]/[stream].flv; dvr_plan session; dvr_duration 30; dvr_wait_keyframe on; time_jitter full; } }
這裏該了http的服務端口爲80,添加了保存rtmp流文件的配置,指定存儲路徑./objs/nginx/html/[app]/[stream].flv。
啓動SRS:
./objs/srs -c conf/my.http.flv.live.conf
接下來就是推流了。
假定你安裝了ffmpeg。
ffmpeg -re -i /root/Videos/video.flv -c copy -f flv rtmp://192.168.2.192/live/video
若是推流成功那就能夠在VLC中播放rtmp://192.168.2.192/live/video了,這樣以前的html中的url就是:http://192.168.2.192/live/video.flv,
把以前的html/js copy到SRS的/objs/nginx/html/ 下,訪問 http://ip/flv.html(這時的http服務由SRS提供,和以前的不同) ,注意ip要和html中的ip一致,不然會報跨域的錯。
至此整個直播點播服務的雛形就搭建成功!
但願在開始推流的時候srs請求python服務,修改資源的狀態爲正在直播,推流結束是再次回調,請求python服務,修改狀態爲中止直播
srs的配置:
# the config for srs to remux rtmp to flv live stream. # @see https://github.com/ossrs/srs/wiki/v2_CN_DeliveryHttpStream # @see full.conf for detail config. listen 1935; max_connections 1000; daemon off; srs_log_tank console; http_server { enabled on; listen 8080; dir ./objs/nginx/html; } vhost __defaultVhost__ { http_remux { enabled on; mount [vhost]/[app]/[stream].flv; hstrs on; } dvr { # https://github.com/ossrs/srs/wiki/v2_CN_DVR enabled on; dvr_path ./objs/nginx/html/[app]/[stream].flv; dvr_plan session; dvr_duration 30; dvr_wait_keyframe on; time_jitter full; } http_hooks { enabled on; on_publish http://localhost:8000/on_publish/; on_unpublish http://localhost:8000/on_unpublish/; } }
注意: on_publish的ip須要根據netstat -pantu 判斷,看看監聽在哪一個地址,好比127.0.0.1:8000,那麼就應該保持一致,
按理說寫localhost也應該能夠,在終端用crul localhos:8000 也是能夠訪問,可是回調時報錯:
[2017-11-30 03:08:22.478][error][20398][220][11] dns resolve server error, ip empty. ret=1029(Resource temporarily unavailable) [2017-11-30 03:08:22.478][warn][20398][220][11] http client failed, server=localhost, port=8000, timeout=30000000, ret=1029 [2017-11-30 03:08:22.478][warn][20398][220][11] http connect server failed. ret=1029 [2017-11-30 03:08:22.478][error][20398][220][11] http post on_publish uri failed. client_id=220, url=http://localhost:8000/on_publish/, request={"action":"on_publish","client_id":220,"ip":"192.168.2.151","vhost":"__defaultVhost__","app":"live","tcUrl":"rtmp://192.168.2.134:1935/live","stream":"f345f5b0d34a11e78008365426bed70e"}, response=, code=-147690992, ret=1029(Resource temporarily unavailable) [2017-11-30 03:08:22.478][error][20398][220][11] hook client on_publish failed. url=http://localhost:8000/on_publish/, ret=1029(Resource temporarily unavailable) [2017-11-30 03:08:22.478][error][20398][220][11] http hook on_publish failed. ret=1029(Resource temporarily unavailable) [2017-11-30 03:08:22.478][error][20398][220][11] stream service cycle failed. ret=1029(Resource temporarily unavailable)
因此仍是保持一致的好。
另外:uwsgi並不對外提供訪問服務,只由nginx轉發,因此服務不要監聽在0.0.0.0:8000,更不要寫內網ip如192.168.2.111這樣的,應爲不肯定下次啓動ip不變。
因此uwsgi最好仍是監聽在127.0.0.1:8000。
python:
# SRS推流開始,結束 def live_publish(request): params = str(request.body, encoding="utf-8") object = json.loads(params) l_uuid = object.get('stream') live = Live.objects.get(uuid=l_uuid) live.status = 'living' live.save() return HttpResponse(0) def live_unpublish(request): params = str(request.body, encoding="utf-8") object = json.loads(params) l_uuid = object.get('stream') live = Live.objects.get(uuid=l_uuid) live.status = 'stop' live.save() return HttpResponse(0)
官方文檔的說明:
https://github.com/ossrs/srs/wiki/v2_CN_HTTPCallback
根據:an int value specifies the error code(0 corresponding to success)
大概是說要返回一個0,不過我嘗試各類返回值0,「0「,{」code」:0}...都沒用
一返回srs就報錯:empty response
不知道爲毛srs接收不到。
沒辦法,改源碼:
在srs/trunk/src/app/srs_app_http_hooks.cpp
找到報錯的位置:
// should never be empty. res = SRS_HTTP_RESPONSE_OK; if (res.empty()) { ret = ERROR_HTTP_DATA_INVALID; srs_error("invalid empty response. ret=%d", ret); return ret; }
在進入判斷前先賦值:res = SRS_HTTP_RESPONSE_OK;
而後從新編譯安裝。
還能夠打包傳服務器上用。
./scripts/package.sh --x86-x64
固然這只是權宜之計,由於我不須要判斷用戶的權限來濾用戶,因此不用控制response返回值,但願往後搞明白說明緣由致使。
若是有讀者知道緣由,還請告知,謝謝。
剪切:
ffmpeg -ss 0:1:30 -t 0:0:20 -i input.avi -vcodec copy -acodec copy output.avi
-ss 開始時間,-t 持續時間
提取圖片:
ffmpeg –i test.avi –r 1 –f image2 image-%3d.jpeg
封裝:
ffmpeg –i video_file –i audio_file –vcodec copy –acodec copy output_file
flv快速添加關鍵幀(爲了拖動播放):
yamdi -i tmp.flv -o 51e714ded33a11e7889a365426bed70e.flv
~/Downloads/flazr-0.7-RC2# ./client.sh rtmp://192.168.2.134:1935/live/a54b2dceda5911e7a5b1365426bed70e -load 200
查看srs服務器的網卡信息:
ethtool eth0
查看 srs服務器的流量:
iftop
前段時間用以上方案搭建的直播點播系統測試結果仍是比較滿意的
筆記本(百兆網卡)網線直連開發板(千兆網卡):
子碼流(100-150併發)主碼流(10-20)
筆記本(千兆網卡)網線直連開發板(千兆網卡):
子碼流(沒測,不過不會超過1000,srs中有最大鏈接數設置)主碼流(100-200)(目標就是支持100人在線觀看)
可是前兩天用錄播主機推流到開發板,出現視頻流暢,聲音卡頓的現象。
以前懷疑過網絡不順暢通,視頻源有問題,錄播主機有問題,flv.js。
後來發現是flv.js在處理某些視頻流,或視頻文件(直播http-flv,點播xx.flv)會發生以上現象。
可是直接用VLC客戶端播放沒有聲音卡頓的現象。
沒辦法,只好改回JWPlayer(播放rtmp),Video(播放mp4)
這就須要將推流的臨時文件xxx.flv從新封裝成xxx.mp4。
但願flv.js的後續版本能夠解決這樣的問題。
測試幾天發現只有錄播設備播放文件通道的時候聲音會卡頓,直接將其餘電腦的音視頻接入沒有卡頓,可是隨着播放時間加長,會出現聲音延遲的現象。
├── CentOS-Base.repo ├── ffmpeg-3.4 ├── install.sh ├── my.http.flv.live.conf ├── nginx-1.12.2 ├── nohup.out ├── Python-3.5.0 ├── run.sh ├── SRS-Ubuntu12-armv7cpu-2.0.243 ├── stop.sh ├── touch ├── touch.conf ├── touch.ini └── yamdi-1.9
install.sh:
#!/bin/bash install_list='system python srs nginx deploy env ffmpeg yamdi' #install_list='ffmpeg yamdi' if [[ ${install_list} =~ system ]] then #替換yum源,更新系統 yum_path='/etc/yum.repos.d/' for file in ${yum_path}* do end_str=${file:0-3} if [ "${end_str}" != 'bak' ] then mv $file ${file}.bak fi done cp CentOS-Base.repo ${yum_path} yum update #安裝基本工具 yum install net-tools yum install nc else echo '>>>pass system' fi if [[ ${install_list} =~ "python" ]] then #Python3.5安裝 cd Python-3.5.0/ ./configure make make install pip3 install uwsgi cd .. else echo '>>>pass python' fi if [[ ${install_list} =~ "nginx" ]] then #nginx 安裝 yum -y install zlib zlib-devel openssl openssl--devel pcre pcre-devel cd nginx-1.12.2/ ./configure make make install cd .. else echo '>>>pass nginx' fi if [[ ${install_list} =~ "srs" ]] then #srs 安裝 yum install redhat-lsb -y cd SRS-Ubuntu12-armv7cpu-2.0.243/ ./INSTALL cd .. else echo '>>>pass srs' fi if [[ ${install_list} =~ "ffmpeg" ]] then #ffmpeg 安裝 cd ffmpeg-3.4/ #./configure make make install cd .. else echo '>>>pass ffmpeg' fi if [[ ${install_list} =~ "yamdi" ]] then #yamdi 安裝 cd yamdi-1.9/ make make install cd .. else echo '>>>pass yamdi' fi if [[ ${install_list} =~ "deploy" ]] then #部署項目 mkdir /opt/script/ cp my.http.flv.live.conf /usr/local/srs/conf/ cp touch.conf /usr/local/nginx/conf/ cp touch.ini /opt/script/ cp touch /opt/ mkdir /usr/local/nginx/html/images/ cp touch/tmp/* /usr/local/nginx/html/images/ else echo '>>>pass deploy' fi if [[ ${install_list} =~ "env" ]] then #安裝項目依賴 pip3 install django==1.9.8 pip3 install xadmin pip3 install future pip3 install django_crispy_forms pip3 install django-formtools pip3 install httplib2 pip3 install six pip3 install django_import_export pip3 install django-cors-headers pip3 install django-pure-pagination yum install python-devel zlib-devel libjpeg-turbo-devel -y pip3 install Pillow else echo '>>>pass env' fi
run.sh:
#!/bin/bash #啓動項目 #touch pkill -9 uwsgi cd /opt/ uwsgi --ini script/touch.ini & chmod 766 /opt/script/touchrnb.sock #nginx pkill -9 nginx cd /usr/local/nginx/ ./sbin/nginx -c conf/touch.conf & #srs pkill -9 srs cd /usr/local/srs/ ./objs/srs -c conf/my.http.flv.live.conf > /dev/null &
stop.sh:
#!/bin/bash #中止項目 #nginx pkill -9 nginx #srs pkill -9 srs #touch pkill -9 uwsgi
開機啓動:
編輯/etc/rc.d/rc.local,添加run.sh腳步路徑
十二、文件瘦身
strip objs/srs
(arm版本:arm-hisiv300-linux-strip)
能夠從7-8兆減到2-3兆
以前是nginx代理服務器和srs在同一臺機器上,可是公司考慮到嵌入式板的性能問題,須要提供更換直播服務器的功能,爲了不修改nginx配置的問題,因此
直播服務器地址由後臺配置,存到數據庫,而不使用nginx代理。可是這樣就有跨域的問題了,我使用的srs版本爲2.0,目前解決跨域的方法是修改源碼。
參考:https://github.com/ossrs/srs/issues/1002
修改 src/app/srs_app_http_stream.cpp
在486行添加 w->header()->set("Access-Control-Allow-Origin", "*");
從新編譯安裝便可
集羣很簡單參考:https://github.com/ossrs/srs/wiki/v3_CN_SampleHttpFlvCluster
負載均衡:
若是集羣較大推薦CDN,若是小集羣能夠用nginx
值得一提的是srs在接收nginx的轉發請求時不是用的相對路徑
nginx配置文件:
worker_processes 4; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; gzip on; client_max_body_size 4096m; upstream localhost{ ip_hash; server 127.0.0.1:8080; server 192.168.2.127:8080; } server { listen 80; server_name 192.168.2.192 ; charset utf-8; location / { add_header 'Access-Control-Allow-Origin' '*'; proxy_pass http://127.0.0.1:8000/; } # 指定靜態文件路徑 location /static/ { alias /root/GitClient/touch/static_all/; index index.html index.htm; } location /uwsgi_http/ { proxy_pass http://localhost/; } } }
若是upstream localhost 改成upstream aaa,瀏覽器訪問: http://127.0.0.1/uwsgi_http/live/123.flv
srs接收到的是:http://aaa/live/123.flv
因此srs服務器要配置hosts文件,使aaa指向127.0.0.1
這裏我直接命名爲localhost,這樣就能夠偷懶啦。
還有負載均衡策略指定ip_hash,由於源站和邊緣之間的視頻可能不一樣步,這樣能夠提升用戶體驗。
可是若是srs集羣的性能差別較大,仍是用weight策略好一點。
<script> if (flvjs.isSupported()) { var videoElement = document.getElementById("myplayer"); var flvPlayer = flvjs.createPlayer({ type: 'flv', isLive: true, url: '{{ LIVE_URL }}{{ current_live.uuid }}.flv', }, { enableWorker: false, enableStashBuffer: false, stashInitialSize: 1, lazyLoad: false, lazyLoadMaxDuration: 1, lazyLoadRecoverDuration: 1, deferLoadAfterSourceOpen: false, autoCleanupMaxBackwardDuration: 1, autoCleanupMinBackwardDuration: 1, statisticsInfoReportInterval: 1, fixAudioTimestampGap: false, }); flvPlayer.attachMediaElement(videoElement); flvPlayer.load(); flvPlayer.play(); } </script>
srs低延時配置:
vhost __defaultVhost__ { gop_cache off; queue_length 10; min_latency on; mr { enabled off; } mw_latency 100; tcp_nodelay on; }
video低延時:
videoElement.addEventListener('progress', function() { var range = 0; var bf = this.buffered; var time = this.currentTime; while(!(bf.start(range) <= time && time <= bf.end(range))) { range += 1; } this.currentTime = this.buffered.end(range) - 0.01; });
設置video低延時會觸發waiting事件,出現一個圓圈和下降屏幕亮度,有待處理...
這樣大概能夠把延時從2~3降到1秒左右。(環境不一樣可能有差異,在網線接交換機的狀況下會比連WiFi要好)
延時和流暢不可兼得,需求不一樣要設置不一樣參數。
參考:https://github.com/Bilibili/flv.js/issues/136
解決方法是 fixAudioTimestampGap: false,注意這個配置要在config的位置
官方文檔:https://github.com/ossrs/srs/wiki/v3_CN_SampleHLS
vhost __defaultVhost__ { ... hls { enabled on; hls_fragment 10; hls_window 60; hls_path ./objs/nginx/html; hls_m3u8_file [app]/[stream].m3u8; hls_ts_file [app]/[stream]-[seq].ts; hls_dispose 10; } }
存在的問題:同一地址第一次正常,後面推的都不能看,第一次生成ts切片正常,後面的ts切片會重複丟棄和生成。
參考: 轉hls輸出時出現的問題 #894:https://github.com/ossrs/srs/issues/894
在SrsHls::on_unpublish的時候設置SrsHls::aac_samples=0後正常。