Nodejs Web推流拉流實(shí)現(xiàn)直播功能

一薯嗤、服務(wù)器

這里使用egg做例子,Express,Koa大小異同

1.安裝node-media-server

npm install node-media-server --save

GitHub地址:https://github.com/illuspas/Node-Media-Server

2.node-media-server配置的參數(shù)

  const NodeMediaServerConfig = {
    rtmp: {
      port: 1935,
      chunk_size: 60000,
      gop_cache: true,
      ping: 30,
      ping_timeout: 60,
    },
    http: {
      port: 8000,
      allow_origin: '*',
    },
  };

3.運(yùn)行服務(wù)

  const NodeMediaServer = require('node-media-server');
  const nms = new NodeMediaServer(app.config.NodeMediaServerConfig);
  nms.run();

此時(shí)兩個(gè)端口的服務(wù)已經(jīng)跑起來了,根據(jù)配置文件曾雕,推流使用的是默認(rèn)的1935端口,當(dāng)使用rtmp協(xié)議時(shí)是不需要加端口號(hào)的。
無后端框架經(jīng)驗(yàn)的可以根據(jù)GitHub上文檔跑一個(gè)Node js文件就可以了

二艾栋、推流

node-media-server在文檔給出的推流工具是FFmpeg,可以下載該工具后進(jìn)行推流測試
http://ffmpeg.org/

ffmpeg -re -i INPUT_FILE_NAME -c copy -f flv rtmp://localhost/live/STREAM_NAME

這個(gè)工具是一個(gè)視頻處理的工具蛉顽,也有無需安裝而且功能強(qiáng)大的有點(diǎn)蝗砾,有興趣的可以了解,這個(gè)命令主要是把視頻文件當(dāng)流推到指定地址携冤,要實(shí)現(xiàn)直播效果繼續(xù)往下走吧

1.推流sdk

我這里推薦一個(gè)國內(nèi)比較齊全的推流sdk悼粮,可以在網(wǎng)站上找到android,window噪叙,mac矮锈,flutter等的Demo
大牛直播sdk
這里也是建議大家使用sdk,方便快捷功能齊全睁蕾,只要使用應(yīng)用Demo輸入服務(wù)器地址就可以內(nèi)網(wǎng)調(diào)試了苞笨,也完整的提供了sdk

2.Web端推流

這個(gè)真心不怎么推薦了,如果需要玩耍的可以實(shí)現(xiàn)一下
先了解下rtmp-streamer
另外子眶,F(xiàn)lashPlayer即將不再被各大瀏覽器支持了瀑凝,所以酌情玩耍就好
文檔提到

`rtmp-streamer` 遵循[AMD](http://requirejs.org/docs/whyamd.html)規(guī)范,可通過[`require.js`](http://requirejs.org/)等方式加載, 另外, 請(qǐng)確保在頁面中引入了`RtmpStreamer.swf`, 否則`rtmp-streamer`將無法正確載入

如果你使用webpack可以通過npm安裝并require

npm install rtmp-streamer --save
值得注意的是一個(gè)swf文件需要引入臭杰,并且載入后才可以調(diào)用推流的方法

在body加入<object>粤咪,引入swf文件

<object>
    <embed id="rtmp-streamer" src="../RtmpStreamer.swf" bgcolor="#999999" quality="high"
           width="320" height="240" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"></embed>
</object>

然后調(diào)用publish方法向服務(wù)器推視頻流

require(["rtmp-streamer"], function (RtmpStreamer) {
  var streamer = new RtmpStreamer(document.getElementById('rtmp-streamer'));
  streamer.publish(url, name);
});

在一般的html頁面里面引入需要引入requireJs
然后使用require引入rtmp-streamer

注意必須要swf插件引入完成后才可以使用推流方法,利用全局isReady變量可以判斷此狀態(tài)

這里先直接上我的代碼

<!doctype html>
<html lang="en">
<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <!-- 新 Bootstrap 核心 CSS 文件 -->
  <link  rel="stylesheet">

  <!-- jQuery文件渴杆。務(wù)必在bootstrap.min.js 之前引入 -->
  <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>

  <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
  <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
  <title>RTMP Web 推流Demo</title>
</head>

<body style="text-align: center;">
  <nav class="navbar navbar-light fixed-top rtc-primary-bg">
    <h5>基礎(chǔ)推流拉流</h5>
  </nav>
  <div class="panel panel-default">
    <div class="panel-heading">
      <h3 class="panel-title">
        推流
      </h3>
    </div>
    <br>
    <object>
      <embed id="rtmp-streamer" src="../public/rtmp-streamer/RtmpStreamer.swf" bgcolor="#999999" quality="low"
             width="320" height="240" allowScriptAccess="localhost" type="application/x-shockwave-flash"></embed>
    </object>
    <br>
    <div>
      <label for="url" class="col-sm-1 control-label">服務(wù)器地址</label>
      <div class="col-sm-10">
        <input type="text" class="form-control" id="url"
               value="localhost">
      </div>
      <br>
      <br>
      <label for="room" class="col-sm-1 control-label">房間號(hào)</label>
      <div class="col-sm-10">
        <input type="text" class="form-control" id="room"
               value="test">
      </div>
      <br>
      <br>
      <label for="width" class="col-sm-1 control-label">分辨率</label>
      <div class="col-sm-1">
        <input type="text" class="form-control" id="width"
               value="320">
        *<input type="text" class="form-control" id="height"
               value="240">
      </div>
    </div>
    <br><br><br>
    <br><br>
    <button type="button" class="btn btn-info" onclick="startPush()">開始推流</button>
    <button type="button" class="btn btn-warning" onclick="disconnectPush()">停止推流</button>
    <br><br>
  </div>
  <br>
  <hr>
  <div class="panel panel-default">
    <div class="panel-heading">
      <h3 class="panel-title">
        拉流
      </h3>
    </div>
    <br>
    <video id="videoElement" style="background:#eeeef3;"></video>
    <br>
    <div>
      <label for="playUrl" class="col-sm-1 control-label">服務(wù)器地址</label>
      <div class="col-sm-10">
        <input type="text" class="form-control" id="playUrl"
               value="localhost:8000">
      </div>
      <br>
      <br>
    </div>
    <button type="button" class="btn btn-info" onclick="videoPlay()">開始播放</button>
    <br><br>
  </div>

  <script src="https://cdn.bootcss.com/flv.js/1.5.0/flv.min.js"></script>

  <script type="text/javascript" src="../public/require.js"></script>
  <script type="text/javascript">
    let streamer = {};
      const RtmpStreamerObj = document.getElementById('rtmp-streamer');
      require.config({
        paths:{
          "rtmp-streamer":'../public/rtmp-streamer/rtmp-streamer'
        }
      });
      require(["rtmp-streamer"], RtmpStreamer=> {
        streamer = new RtmpStreamer(RtmpStreamerObj);
        console.log(streamer);
      });
      function disconnectPush() {
        streamer.disconnect();
      }
      function startPush(){
        if(isReady){
          let url = document.getElementById('url').value;
          let room = document.getElementById('room').value;
          let width = document.getElementById('width').value;
          let height = document.getElementById('height').value;
          if(url.length==0 || room.length==0 || width.length==0 || height.length==0){
            alert("請(qǐng)輸入配置信息");
            return false;
          }
          RtmpStreamerObj.width = width;
          RtmpStreamerObj.height = height;
          streamer.publish(`rtmp://${url}/live`,room);
          alert("已開始推流");
        }else{
          setTimeout(_=>{
            console.log('retry');
            startPush();
          },1000)
        }
      }
      function videoPlay() {
        if (flvjs.isSupported()) {
          const url = document.getElementById('playUrl').value;
          const videoElement = document.getElementById('videoElement');
          const flvPlayer = flvjs.createPlayer({
            type: 'flv',
            url
          });
          flvPlayer.attachMediaElement(videoElement);
          flvPlayer.load();
          flvPlayer.play();
          alert("已開始播放");
        }else{
          setTimeout(_=>{
            videoPlay();
          },1000)
        }
      }
  </script>
</body>
</html>

三寥枝、拉流

拉流相對(duì)來說支持的比較多,調(diào)試可以使用VLC播放器磁奖,十分強(qiáng)大囊拜,有興趣自行了解。
另外一般的都可以使用flv.js進(jìn)行播放

<script src="https://cdn.bootcss.com/flv.js/1.5.0/flv.min.js"></script>
if (flvjs.isSupported()) {
          const url = document.getElementById('playUrl').value;
          const videoElement = document.getElementById('videoElement');
          const flvPlayer = flvjs.createPlayer({
            type: 'flv',
            url
          });
          flvPlayer.attachMediaElement(videoElement);
          flvPlayer.load();
          flvPlayer.play();
          alert("已開始播放");
        }

另外在過程中了解到一個(gè)比較強(qiáng)大的js的video播放器比搭,集成了片頭廣告冠跷,片尾廣告,各種廣告位的國產(chǎn)播放,有興趣可以了解
ckplayer

整個(gè)過程感覺比較簡單蜜托,就簡單說說抄囚,本人造詣不深,僅供參考橄务,如有問題可以留言幔托,祝春節(jié)愉快

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市仪糖,隨后出現(xiàn)的幾起案子柑司,更是在濱河造成了極大的恐慌,老刑警劉巖锅劝,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蟆湖,居然都是意外死亡故爵,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門隅津,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诬垂,“玉大人,你說我怎么就攤上這事伦仍〗峋剑” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵充蓝,是天一觀的道長隧枫。 經(jīng)常有香客問我,道長谓苟,這世上最難降的妖魔是什么官脓? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮涝焙,結(jié)果婚禮上卑笨,老公的妹妹穿的比我還像新娘。我一直安慰自己仑撞,他們只是感情好赤兴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著隧哮,像睡著了一般桶良。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上近迁,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天艺普,我揣著相機(jī)與錄音,去河邊找鬼。 笑死歧譬,一個(gè)胖子當(dāng)著我的面吹牛岸浑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瑰步,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼矢洲,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了缩焦?” 一聲冷哼從身側(cè)響起读虏,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎袁滥,沒想到半個(gè)月后盖桥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡题翻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年揩徊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嵌赠。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡塑荒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出姜挺,到底是詐尸還是另有隱情齿税,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布炊豪,位于F島的核電站凌箕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏溜在。R本人自食惡果不足惜陌知,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望掖肋。 院中可真熱鬧仆葡,春花似錦、人聲如沸志笼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纫溃。三九已至腰涧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間紊浩,已是汗流浹背窖铡。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來泰國打工疗锐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人费彼。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓滑臊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親箍铲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子雇卷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容