最近由於項目上需要一個攝像頭在線預覽的功能,於是便琢磨了一個小玩意出來分享分享。項目是在win上,合作的人懂js,基於這樣的情況,我只選擇nodejs作為開發。並未使用php相關。
一開始做這個,我並不感到陌生,因為我以前使用過開源的解碼器FFmpeg,所以我知道使用它就可以實現攝像頭的rtsp流轉hls,只要轉成hls了,我就可以使用開源的video-js-control-hls來播放m3u8文件了,而且我司用了海康的軟件產品,它們就是開放接口,通過請求接口獲取在線播放文件。思路是很清晰的,那我有了這樣的思路,並開始在npmjs.com里面找輪子
經過一番的查找,最后我選定了幾個輪子。首先是fluent-ffmpeg這個操作ffmpeg的中間件,然后就是hls-server這個http服務,它過濾所有和hls無法的資源,只保留.m3u8和.ts資源。那這樣的話,輪子有了,那下面就是去熟悉一下理論知識(音視頻轉碼、ffmpeg等)
瀏覽了大概的理論知識后,那再接着就是細節的優化了。細節問題我在做之前發了一個思否的提問(鏈接:做一個海康攝像頭轉hls然后使用h5方式播放的細節問題),心寒的是,平名無法被人看到,知識就是力量,力量不夠就有問題,所以我開始自己的琢磨(基本上那幾天晚上都在想)。
琢磨了幾天后,我找到了幾個關鍵點:
什么時候開始轉碼(服務啟動就轉碼還是接口發送后收到轉碼通知在轉碼) | 當然是接口發送后收到轉碼通知在轉碼 |
什么時候沒人看了,關閉轉碼服務,清理播放文件 | 用戶觀看的時間作為更新時間,服務端建立一個心跳檢測,當超過設置時間沒人看,就治理ffmpeg進程和播放文件 |
如果生成的播放文件,一直沒人看,那也要關閉轉碼服務,清理播放文件 | 記錄播放文件觀看的時間,如果有人看,就更新這個時間,服務端建立一個心跳檢測,當超這個時間超過過設置時間沒人看,就治理ffmpeg進程和播放文件 |
是否加入緩存 | 一開始沒加,每次請求都生成新的播放文件,后面考慮到我們是應用層開發,不是c++這些,所以還是加緩存,當關閉轉碼服務,清理播放文件的條件滿足時,同時也清理緩存的url |
當我完成了這個版本后,我發現不夠好,為什么不夠好呢,因為開始轉碼到生成播放文件,我在我的電腦和服務器上測試的平均時間是在11秒左右,最好的時候是3秒。我們在保證服務器配置的同時應該在思考有沒有優化的空間。我這個版本就是api請求,然后使用fluent-ffmpeg的方法去創建ffmpeg進程,fluent-ffmpeg使用pipe向進程輸入命令。那我就想了,我能否預先的生成ffmpeg進程並讓它掛起(就是做ffmpeg進程池),然后api請求,我從進程池里面拿一個出來用,當自動清理時,我不再關閉進程,而是使用信號暫停進程。我想這樣的方式,應該會加快生成播放文件的時間,減少api等待的時間。
目前的話,我開始研究fluent-ffmpeg的源碼,感覺從它這里還沒找到方法,我於是自己操作了一個示例,我在啟動tcp后,使用
-
child_process.spawn建立ffmpeg進程,參考代碼:
-
server.on("listening", () => { console.log('listening'); const args = ['-i', 'pipe:0', '-f', 'mp3', '-ac', '2', '-ab', '128k', '-acodec', 'libmp3lame', 'pipe:1']; for (let i = 0; i < 10; i++) { const ffmpeg = spawn('ffmpeg', args); pools[i] = ffmpeg; } });
理論上是可以的了,而且這樣創建的進程是掛起的,我后續在關鍵參數加管道,后面應該就可以實現了吧,暫時在研究中,如果研究成功,我會發布第二版本。
最后,我附上一個git地址給大家吧,代碼寫的不咋樣,見笑了:hk-hls