<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          基于nginx+ffmpeg+vue3+TypeScript在網(wǎng)頁上顯示監(jiān)控的實(shí)時(shí)畫面

          共 11808字,需瀏覽 24分鐘

           ·

          2024-04-17 08:49

          大廠技術(shù)  高級(jí)前端  Node進(jìn)階

          點(diǎn)擊上方 程序員成長指北,關(guān)注公眾號(hào)

          回復(fù)1,加入高級(jí)Node交流群

          一、心路歷程


          寫在前面

          最近在忙比賽的項(xiàng)目,項(xiàng)目有一個(gè)實(shí)時(shí)預(yù)覽監(jiān)控?cái)z像頭的畫面的需求。按道理說我一個(gè)臭前端不負(fù)責(zé)這一塊的東西,但是沒辦法,時(shí)間緊任務(wù)重,只好硬著頭皮上了。剛做到這一塊的業(yè)務(wù)的時(shí)候,毫無頭緒,因?yàn)閿z像頭用的是海康的,然后就四處查閱文檔,四處碰壁。并且對(duì)攝像頭這一塊完全不了解,花了三天時(shí)間才做出一個(gè)「demo」。如果你的攝像頭配置比較好,如果可以通過各大攝像頭廠商給demo連接上,那就會(huì)省下很多麻煩事。一定一定在做之前看攝像頭的配置,支持什么,不支持什么?。?!因?yàn)闀r(shí)間肥腸的寶貴。



          一些必要的認(rèn)知

          • 一些常見的流媒體傳輸協(xié)議:「RTSP、RTMP、HLS、HTTP-FLV」

          當(dāng)時(shí)我查閱文檔的時(shí)候也很蒙b,這些都是什么啊,這么多協(xié)議,而且都用來干啥的。反正就是一臉懵逼,

          經(jīng)過好多番的學(xué)習(xí)。我這邊提供的攝像頭是支持「RTSP」取流的,所以打算在服務(wù)器上通過「ffmpeg」進(jìn)行取流,然后推流到「Nginx」上,「Nginx」將流處理成對(duì)前端友好的傳輸格式「HLS」(「m3u8」格式的文件),然后前端再拉流就行了。這里實(shí)現(xiàn)的流程是這樣的


          什么你說什么拉流推流,根本聽不懂誒!

          說實(shí)話,我也不懂,我三天的摸索下來,似乎還不能正確的理解推流和拉流。最后我是這么理解的:
          「推流」:女主播把畫面推到服務(wù)器上
          「拉流」:我點(diǎn)開女主播的直播間,看女主播跳舞(doge)



          RTSP協(xié)議

          當(dāng)然沒這么簡單,媒體文件的傳輸肯定是要基于某個(gè)協(xié)議進(jìn)行傳輸。由于這里攝像頭提供了RTSP協(xié)議的地址(很多監(jiān)控?cái)z像頭廠商都有的),手機(jī)移動(dòng)攝像頭我不懂。
          RTSP協(xié)議,RTSP(實(shí)時(shí)流傳輸協(xié)議)是一個(gè)網(wǎng)絡(luò)控制協(xié)議,用于在線實(shí)時(shí)觀看和控制流媒體服務(wù)器。它的作用類似于流媒體服務(wù)器的遠(yuǎn)程控制 (https://zhuanlan.zhihu.com/p/478736595)這里說的比較清楚。

          調(diào)試工具

          學(xué)習(xí)了這些知識(shí),我對(duì)視頻流的傳輸漸漸有了一些理解,上文提到我們監(jiān)控?cái)z像機(jī)提供了RTSP流的地址常見攝像機(jī)廠商RTSP地址格式,我們可以通過一些工具去播放這個(gè)流,比如VLC、potPlayer播放器。這里建議使用VLC,因?yàn)樗娴暮茌p量!potPlayers也行,兩個(gè)都是究極好用的媒體播放器
          VLC:打開軟件**-->「媒體」-->**打開網(wǎng)絡(luò)串流

          potPlayer:瀏覽器-->打開鏈接

          這里把他們當(dāng)作調(diào)試工具用就行啦,因?yàn)椴还苁荝TSP流、RTMP流、FLV流、HLS流都能播放。在搭建服務(wù)之前得保證自己的攝像機(jī)正常的在工作。


          然后就是重頭戲了,「nginx」「ffmpeg」。疊個(gè)甲,對(duì)ffmpeg我是第一次用,nginx也僅限于了解,平時(shí)部署項(xiàng)目是寶塔面板一鍵部署的。

          ffmpeg

          這個(gè)就不多說了(因?yàn)槲艺f不來哈哈哈),是一個(gè)開源的程序庫,通過命令行的方式來使用他的功能,就專門用來處理媒體文件的,這里掛一個(gè)官網(wǎng)的下載地址。如果使用的是寶塔面板,軟件商店就有,一鍵安裝就行。什么?命令行的方式?當(dāng)然,我想,你在找文檔,而且最好是中文文檔。這里也準(zhǔn)備好了ffmpeg中文文檔。
          把他當(dāng)作一個(gè)中間工具就行了。



          Nginx

          這位才是重量級(jí),真正讓服務(wù)跑起來的還得是nginx,因?yàn)椴皇欤緛聿淮蛩阕哌@條路(原本想用Node來搭),到頭來還是避不開Nginx(踩坑過后,嗯Nginx真香)

          很重要的一點(diǎn)!一定要給nginx添加rtmp模塊,在這里踩了很多坑,什么模塊安裝不上、配置文件不生效....em反正就踩了很多坑。

          二、實(shí)戰(zhàn)


          RTSP地址

          這邊老師給提供的是海康威視的攝像頭,地址格式是rtsp://攝像頭用戶名:攝像頭密碼@攝像頭ip:rtsp端口號(hào)/h264/ch1/main/av_stream

          畫面測(cè)試

          有了上文的地址,可以先在vlc和potPlayer里看一看,畫面是否能正常預(yù)覽畫面,這里放一個(gè)正常取流的結(jié)果

          安裝ffpemg

          這里給出了兩種方式安裝

          • 「寶塔面板」

          我是用寶塔面板安裝的,因?yàn)榉奖懵铮?br>

          • 「手動(dòng)安裝」

          來到ffmpeg中文官網(wǎng),選擇靜態(tài)構(gòu)建

          點(diǎn)擊sorce

          下載第一個(gè)就行

          下載完了之后把他扔到服務(wù)器上面去
          這里先不著急,ffmpeg安裝還依賴一些東西,nasm

          同樣也是下載完了扔到服務(wù)器上就行

          萬事俱備,解壓編譯安裝

          先是解壓nasm

          tar -xvf /www/server/mypack/nasm-2.16.01.tar.gz #解壓到當(dāng)前目錄
          # tar -xvf /www/server/mypack/nasm-2.16.01.tar.gz -C /指定目錄

          這里我解壓到了/www/server/nasm目錄下

          「進(jìn)入該目錄后」配置makeFile然后進(jìn)行編譯安裝

          ./configure --prefix=[你的安裝路徑]
          make && make install

          nasm安裝完了之后就可以安裝ffmpeg了
          還是一樣,解壓,配置makeFile,編譯,安裝即可
          tips我習(xí)慣給安裝的軟件配置一個(gè)軟鏈接(它很像windows中的快捷方式),方便全局使用,一般是這樣的

          ln -s [軟件安裝目錄下的bin目錄或者sbin] [自己機(jī)器的sbin]

          以nasm為例,我的nasm是安裝在/usr/local/nasm下面

          因?yàn)槲疫@里已經(jīng)配置過了,所以whereis顯示/usr/local/sbin/nasm
          來看看/usr/local/nasm目錄下有什么,一個(gè)bin目錄(用于存放該軟件的指令,有些軟件是sbin)

          命令如下:

          ln -s /usr/local/nasm/sbin /usr/local/sbin/nasm

          這里我已經(jīng)建立過了,所以會(huì)顯示文件已經(jīng)存在

          照葫蘆畫瓢,ffmpeg也是如此安裝


          安裝完了并建立了軟鏈接,使用ffmpeg -version檢查是否安裝上了。

          安裝Nginx

          到這里開始踩坑了,nginx-rtmp-module模塊的安裝,因?yàn)槲业臋C(jī)器原本就安裝了nginx,按道理說這并不麻煩,不就是添加一個(gè)功能模塊嘛,嘗試過各種辦法老是裝不上。這里有兩種情況,這兩種情況都是要下載rtmp和nginx-http-flv模塊的,先下載它吧,有可能會(huì)出現(xiàn)一些「網(wǎng)絡(luò)」問題,這里自己解決啦

          git clone https://github.com/arut/nginx-rtmp-module.git 模塊存放路徑/默認(rèn)當(dāng)前
          git clone https://gitcode.com/winshining/nginx-http-flv-module.git 模塊存放路徑/默認(rèn)當(dāng)前
          • 「機(jī)器沒有nginx」

          沒有就裝唄,這里我就不寫了,因?yàn)椴煌腖inux發(fā)行版包管理工具都不一樣
          這里給出Centos7的安裝歷程

          1. 安裝一些依賴
          yum install -y gcc-c++ #因?yàn)橐ㄟ^編譯安裝nginx,所以這里要安裝c/c++編譯器
          yum install -y pcre pcre-devel #nginx的http模塊需要使用pcre來解析正則表達(dá)式
          yum install -y zlib zlib-devel #nginx使用zlib對(duì)http包的內(nèi)容進(jìn)行g(shù)zip
          yum install -y openssl openssl-devel #可以在你的應(yīng)用程序中使用 OpenSSL 提供的加密功能
          1. 下載nginx

          下載nginx有很多方式,你可以在windows上下載,然后再扔到Linux上,也可以用包管理工具安裝,這里選擇前者。

          找個(gè)工具扔上去就行

          # 這里選擇解壓到/usr/local目錄下
          tar -xvf nginx-1.14.0.tar.gz -C /usr/local

          ls /usr/local/查看解壓出來的nginx

          發(fā)現(xiàn)已經(jīng)解壓好了,然后進(jìn)入該目錄
          cd /usr/local/nginx-1.24.0
          配置./configure 腳本

          ./configure \
          --prefix=/usr/local/nginx \
          --pid-path=/var/run/nginx/nginx.pid \
          --lock-path=/var/lock/nginx.lock \
          --error-log-path=/var/log/nginx/error.log \
          --http-log-path=/var/log/nginx/access.log \
          --with-http_gzip_static_module \
          --http-client-body-temp-path=/var/temp/nginx/client \
          --http-proxy-temp-path=/var/temp/nginx/proxy \
          --http-fastcgi-temp-path=/var/temp/nginx/fastcgi \
          --http-uwsgi-temp-path=/var/temp/nginx/uwsgi \
          --http-scgi-temp-path=/var/temp/nginx/scgi \
          --with-http_stub_status_module \
          --with-http_ssl_module \
          --with-file-aio \
          --with-http_realip_module \
          --add-module=/www/server/nginx-http-flv-module # 指定添加flv模塊

          「后期實(shí)踐證明,壓根不需要rtmp模塊,要http-flv模塊就行了,昨晚復(fù)盤的時(shí)候發(fā)現(xiàn)不裝nginx-rtmp-module也能跑通」
          mmp,特別像這根水管一樣,去網(wǎng)上找各種文章,然后東拼西湊,居然能跑起來,你就說能不能用吧


          編譯安裝nginx

          make && make install #如果你想看編譯是否通過,建議是make和make install分開執(zhí)行

          安裝完并且軟連接建立,nginx -t檢查

          nginx默認(rèn)對(duì)應(yīng)的是80端口,在啟動(dòng)nginx之前檢查一下自己的防火墻,看看80端口有沒有放行

          firewall-cmd --list-ports

          如果沒有放行

          #  --zone #作用域    --add-port=80/tcp #添加端口,格式為:端口/通訊協(xié)議
          # --permanent #永久生效,沒有此參數(shù)重啟后失效
          firewall-cmd --zone=public --add-port=80/tcp --permanent
          # reload一下防火墻
          firewall-cmd --reload

          這個(gè)時(shí)候啟動(dòng)nginx

          nginx

          打開瀏覽器,輸入你的服務(wù)器ip就能看到這個(gè)默認(rèn)界面了,要是出現(xiàn)其他的錯(cuò)誤,仔細(xì)看終端的錯(cuò)誤信息。

          nginx配置

          編輯nginx的配置文件nginx.conf

          內(nèi)容如下


          #user nobody;
          worker_processes 1;

          error_log logs/error.log;
          #error_log logs/error.log notice;
          #error_log logs/error.log info;

          pid logs/nginx.pid;


          events {
          worker_connections 1024;
          }


          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;
          }

          error_page 500 502 503 504 /50x.html;
          location = /50x.html {
          root html;
          }
          }
          server {
          listen 8888;

          location /stat { # http://ip:1000/stat, 監(jiān)控流的地址
          rtmp_stat all;
          rtmp_stat_stylesheet stat.xsl;
          }
          location /hls { # http拉流的地址,http://ip:1000/hls/密鑰.m3u8
          # Serve HLS fragments
          types {
          application/vnd.apple.mpegurl m3u8;
          video/mp2t ts;
          }
          root /www/tmp;
          expires -1;
          add_header Cache-Control no-cache;
          add_header Access-Control-Allow-Origin *;
          }
          }
          }
          rtmp {
          server {
          listen 1935;
          ping 30s;
          chunk_size 4000;
          notify_method get;

          application live { # 推流地址rtmp://ip:1935/live/密鑰,同拉流播放地址
          live on;
          record all; # 是否開啟記錄 alloff, all,用于錄制直播視頻以便回放重播
          record_unique on; # 記錄值唯一
          record_max_size 200M; # 記錄文件大小
          record_path "/www/tmp/video"; # 記錄文件位置
          record_suffix -%Y-%m-%d-%H_%M_%S.flv; # 記錄文件命名
          # on_publish http://127.0.0.1:8686/auth; # 開始推流的回調(diào)地址
          #on_done 'http://when live stop call this url'; # 結(jié)束推流的回調(diào)地址
          #on_play http://127.0.0.1:8686/auth; # 開始播放的回調(diào)地址
          }

          application hls { # 推流地址rtmp://ip:1935/hls/密鑰,開啟HLS協(xié)議進(jìn)行m3u8直播
          live on;
          hls on; # 開啟hls, hls的推流會(huì)產(chǎn)生一個(gè)m3u8的ts視頻文件索引,同時(shí)保存一個(gè)個(gè)視頻片段緩存,可以拿到再次播放。
          hls_path /www/tmp/hls; # 視頻切片ts文件存放的位置
          hls_sync 100ms;
          hls_fragment 5s; # 視頻切片的大小,ts文件大小
          hls_cleanup on; #對(duì)多余的切片進(jìn)行刪除
          hls_playlist_length 60s; #保存m3u8列表長度時(shí)間,默認(rèn)是30秒
          }

          #application vod { # 用于視頻點(diǎn)播flv/mp4
          # play /www/tmp/videos; # 本地視頻MP4文件存放地址,作為流播放視頻: rtmp://ip:1935/vod/視頻名稱.mp4
          #}
          #application vod_http { # 播放遠(yuǎn)程http鏈接的視頻,rtmp://ip:1935/vod_http/視頻名稱.mp4
          # play http://localhost:8080/vod/;
          #}
          }
          }


          使用ffpemg進(jìn)行拉流轉(zhuǎn)碼

          tips如果拉流轉(zhuǎn)碼的服務(wù)不在本機(jī)上運(yùn)行,命令會(huì)有一些改動(dòng)。具體怎么改請(qǐng)查閱ffmpeg的官方文檔

          ffmpeg -re -rtsp_transport tcp -i rtsp://admin:123456@ip:port/h264/ch1/main/av_stream -c copy -f hls -hls_time 10 -hls_list_size 0 /www/tmp/hls/test.m3u8

          跑起來是這樣的

          不用擔(dān)心ts片段會(huì)堆滿你的磁盤,因?yàn)橹耙呀?jīng)在nginx的nginx.conf文件配置過了,多余的ts片段會(huì)直接丟掉。

          測(cè)試

          要是沒什么問題那么現(xiàn)在用VLC訪問http://ip:8888/hls/test.m3u8是可以看到監(jiān)控畫面的,
          要是有問題 那多半是對(duì)應(yīng)的端口沒放行

          成功!

          有了這個(gè)hls流的地址,就可以很方便的將監(jiān)控畫面放進(jìn)移動(dòng)端頁面,網(wǎng)頁端頁面了,這里我就不過多的介紹了,

          vue3中使用

          用的video.js這個(gè)插件,這個(gè)自行學(xué)習(xí)安裝了

          <script setup lang="ts">
          import {onMounted, onUnmounted, ref} from 'vue'
          import 'video.js/dist/video-js.css'
          import videojs from 'video.js'

          const src = ref('http://ip:8888/hls/test.m3u8')
          const player = ref<any>(null)
          const videoRef = ref('')
          const videoInit = () => {
          if(player.value) {
          return
          }
          player.value = videojs(videoRef.value, {
          autoplay: false,
          controls: true,
          fluid: true, // 自適應(yīng)寬高
          sources: [
          {
          src: src.value,
          type: 'application/x-mpegURL'
          }
          ]
          }, () => {
          console.log('player init success')
          })
          }
          onMounted(() => {
          videoInit()
          })
          onUnmounted(() => {
          if (player.value) {
          player.value.dispose()
          console.log('player dispose success')
          }
          })
          </script>
          <template>
          <video
          ref="videoRef"
          id="my-video"
          class="video-js vjs-default-skin vjs-big-play-centered vjs-16-9"
          controls
          >
          <source :src="src"/>
          </video>
          </template>

          <style scoped lang="scss">
          </style>

          結(jié)果:

          三、總結(jié)

          幾天的試驗(yàn)與探索,收獲很多,我也想過為什么不能讓rtsp流直接在web網(wǎng)頁中顯示,那得具體的問問研究流媒體傳輸協(xié)議的大佬了,究其原因還是瀏覽器不支持直接播放rtsp流。所以沒辦法還是要轉(zhuǎn)碼,轉(zhuǎn)碼就會(huì)花時(shí)間,延遲自然就出現(xiàn)了。而且這個(gè)demo轉(zhuǎn)碼是直接在本機(jī)進(jìn)行的,并不需要再推流到服務(wù)器上了,實(shí)際情況可能轉(zhuǎn)碼和流媒體服務(wù)器是分開的,延遲會(huì)更高,假設(shè)又拋一個(gè)回放的需求....要回放XXXX年XX月XX日,某某時(shí)間段的錄像,好了我的服務(wù)器已經(jīng)宕機(jī)了。有錯(cuò)誤的地方請(qǐng)指正

          性能問題(實(shí)際環(huán)境中)

          我的機(jī)器比較垃圾,一個(gè)ffmpeg進(jìn)程已經(jīng)負(fù)載累累了,還有一個(gè)問題是畫面延遲,hls方案延遲會(huì)比較高,我沒做過其他的解決方案。這個(gè)demo的延遲大概10S這樣
          平均負(fù)載

          IO

          暫時(shí)沒有想到優(yōu)化的解決方案。如果有好的優(yōu)化方案可以聊一聊,我也想學(xué)!

          ffmpeg后臺(tái)24小時(shí)運(yùn)行

          這個(gè)應(yīng)該很簡單了,我就直接把指令貼出來了

          ffmpeg -nostdin -re -rtsp_transport tcp -i rtsp://admin:123456@ip:554/h264/ch1/main/av_stream -c copy -f hls -hls_time 10 -hls_list_size 0 /www/tmp/hls/test.m3u8 2> /dev/null &

          為了防止拉流轉(zhuǎn)碼服務(wù)掛掉,可以寫一個(gè)shell腳本,每隔一段時(shí)間去檢查一下ffmpeg進(jìn)程是否還在,不在重啟就可以了
          重啟腳本restart.sh

          ffmpeg -nostdin -re -rtsp_transport tcp -i rtsp://admin:123456@ip:554/h264/ch1/main/av_stream -c copy -f hls -hls_time 10 -hls_list_size 0 /www/tmp/hls/test.m3u8 2> /dev/null &

          檢查腳本check.sh這里我沒有在腳本中寫定時(shí)器,而是通過寶塔面板計(jì)劃任務(wù)去實(shí)現(xiàn)的,方便嘛

          #!/bin/bash  
            
          #
           定義一個(gè)函數(shù)來檢查并重啟ffmpeg進(jìn)程  
          check_and_restart_ffmpeg() {  
              # 使用pgrep查找ffmpeg進(jìn)程的PID,如果不存在則返回空  
              ffmpeg_pids=$(pgrep -f ffmpeg)  
                
              # 如果沒有找到ffmpeg進(jìn)程,則執(zhí)行重啟腳本  
              if [ -z "$ffmpeg_pids" ]; then  
                  echo "$(date): No ffmpeg processes found, restarting..."  
                  /root/restart.sh  
              else  
                  echo "$(date): ffmpeg processes are running with PIDs: $ffmpeg_pids"  
              fi  
          }  
          check_and_restart_ffmpeg

          最后

          Node 社群

             


          我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對(duì)Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。

             “分享、點(diǎn)贊、在看” 支持一下

          瀏覽 170
          10點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          10點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品内射婷婷一级二 | 丁香五月在线视频 | 蜜桃视频欧美一区二区 | 亚洲精品69 | 国产黄色一级大片 |