首頁>科技>

前言:

由於自己有一個IM類的應用,為了完善它所以決定也加上直播和短視訊功能。做直播目前有兩種方法,一是直接對接第三方的直播服務產品,二是自己搭服務再開發。所以這裡也從這兩個方法推薦簡單的實現方式,阿里雲和騰訊雲之類的大廠產品就不安利了。

選型:

1. 第三方,PHP+Uni-App+LiveQing

2. 自己開發,PHP+Uni-app+Nginx-rtmp-module

實現流程:

1. 客戶端採集視訊流。(開攝像頭,錄屏等)

2. 客戶端推流到rtmp伺服器上。

3. rtmp推流到某個特定埠。

4. 其他客戶端再對該視訊流進行拉流,實現直播。

一、第三方方式

第三方這次推薦的是一個叫LiveQing的平臺,優點是搭建快捷方便,功能完善。在伺服器上運行了他們的包後除了能實現主流業務場景的直播,而且還提供短視訊的點播服務。還包括API呼叫,通過介面實現直播的建立,刪除,直播資料統計。但是是要收費,該軟體包在一臺物理機或雲伺服器上只能免費試用一個月。

1. 找到該官網,選擇rtmp直播點播流媒體,下載試用把對應系統解壓到自己伺服器。

2. 目錄如下,將start.sh授權為777。然後./start.sh 執行該檔案。

3. 執行前可以開啟liveqing.ini進行設定,比如後臺登入密碼,埠號等。

4. 預設需要開啟10080和10085,所以需要用防火牆放行,操作如下。

systemctl start firewalld.service // 開啟防火牆firewall-cmd add-port=10080/tcp --permanentfirewall-cmd add-port=10082/tcp --permanentfirewall-cmd --reload // 重啟firewall-cmd --list-ports // 檢視放行的所有埠

5. 埠放行,然後在執行start.sh出現下面圖標表示成功。

6. 瀏覽器輸入伺服器的網路IP:10080,就可以進入控制面板了。

7. 建立一個直播,設定名稱和ID,然後選擇編輯獲取推流地址。

9. 同樣為了方便可以使用VLS軟體進行拉流或者wowza線上網站測試直播。

二、程式碼實現

不使用第三方的話,就需要搭建rtmp服務,配置Nginx,APP視訊採集推流,拉流等等。如果是大型平臺,需要進行分流叢集等。流媒體伺服器依賴的服務,1.nginx 伺服器;2.nginx伺服器安裝需要依賴的服務 OpenSSL、pcre、zlib、 c++、gcc等,伺服器環境是Centos 7.3 64 位。

1. 進入根目錄,mkdir source #建立原始碼目錄,後面的原始碼都放在這個目錄。cd source進入該目錄。

2. 下載git,yum -y install git,然後通過網路下載需要的包。

git clone https://github.com/nginx/nginx.git \t\t\t\t#從github伺服器上將nginx的原始碼下載下來git clone https://github.com/arut/nginx-rtmp-module.git \t#將rtmp模組的原始碼下載下來wget https://www.openssl.org/source/openssl-1.1.0.tar.gz \t#下載OpenSSL原始碼包wget https://ftp.pcre.org/pub/pcre/pcre-8.39.tar.gz \t\t#下載pcre原始碼包wget http://www.zlib.net/zlib-1.2.11.tar.gz \t\t\t\t#下載zlib包原始碼

3. tar -zxvf 包名 #解壓各個包原始碼

4. 在將nginx和需要的包編譯前需要先安裝gcc,安裝過可以省過。

yum -y install gcc \t\t\t#確保依賴的gcc安裝yum -y install gcc-c++ \t\t#確保依賴的c++已經安裝

5. 然後cd命令進入source下的nginx目錄,輸入下面命令。

./auto/configure --prefix=/usr/local/nginx \\ --with-pcre=../pcre-8.39 \\ --with-openssl=../openssl-1.1.0 \\ --with-zlib=../zlib-1.2.11 \\ --with-http://127.0.0.1/vhost/conf/img_echo.php?w=640&h=599&src=http_v2_module \\ --with-http://127.0.0.1/vhost/conf/img_echo.php?w=640&h=599&src=http_flv_module \\ --with-http://127.0.0.1/vhost/conf/img_echo.php?w=640&h=599&src=http_mp4_module \\ --add-module=../nginx-rtmp-module/

6. 檢查成功會出現如下,然後make編譯一下。

7. make install 安裝

8. 以上操作後表示Nginx編譯安裝完成,然後cd到根目錄,/usr/local/nginx/sbin,如果要測試Nginx是否可以訪問。先放行80埠重啟防火牆,在sbin下輸入./nginx啟動Nginx服務。瀏覽器訪問IP地址:80,出現以下表示成功。

9. 在nginx配置檔案中配置rtmp服務,記住rtmp服務是和http服務是平級,所以我們需要在和http配置平級的位置另起rtmp服務。

vi /usr/local/nginx/conf/nginx.conf #修改配置檔案rtmp { server { listen 1935; chunk_size 4096; application live { live on; record off; } application live2 { live on; record off; } application vod { play /var/flvs; } application vod_http { play http://伺服器的ip/vod; } application hls { live on; hls on; hls_path /tmp/hls; } }}/usr/local/nginx/sbin/nginx -s reload #修改配置檔案重啟nginx服務

10. 上面rtmp服務的埠是1935,所以也需要按之前方法給1935埠放行,檢查雲伺服器的安全組是否也放行,然後再重啟防火牆。

11. 本地電腦測試1935是否開啟,可以cmd命令telnet 伺服器IP地址 埠號,如果出現一下介面說明埠已經通了 。

12. 接下來也可以通過OBS推流到該地址,然後用WOWZA拉流進行測試。

rtmp://你的伺服器ip:埠(1935)/live #URL填寫流的地址

13. 接下來演示uni-app的推流寫法。

<template> <view class="content">\t\t\t\t<view class="butlist">\t\t\t<view @click="back" class="buticon martp10">\t\t\t\t<image src="../../static/zhiwen-livepush/back2.png"></image>\t\t\t\t\t<view class="mar10">返回</view>\t\t\t\t\t\t\t</view>\t\t\t<view @click="switchCamera" class="buticon martp10">\t\t\t\t<image src="../../static/zhiwen-livepush/reversal.png"></image>\t\t\t\t\t<view class="mar10">翻轉</view>\t\t\t\t\t\t\t</view>\t\t\t<view class=" buticon" @click="startPusher">\t\t\t\t<view class="x_f"></view>\t\t\t\t<view :class="begin==true?'givebegin':'give'" >{{contTime}}</view>\t\t\t\t<view class="pulse" v-if="begin"></view>\t\t\t</view>\t\t\t<view class="buticon martp10">\t\t\t\t<image src="../../static/zhiwen-livepush/beautiful.png"></image>\t\t\t\t\t<view class="mar10">美化</view>\t\t\t\t\t\t\t</view>\t\t\t<view class="buticon martp10" v-if="begin==false">\t\t\t\t<picker :value="index" @change="bindPickerChange" :range="array" range-key='cont'>\t\t\t\t\t<image src="../../static/zhiwen-livepush/countdown.png"></image>\t\t\t\t\t\t<view class="mar10">倒計時</view>\t\t\t\t</picker>\t\t\t\t</view>\t\t\t<view @click="upload" class="buticon martp10" v-if="begin">\t\t\t\t<image src="../../static/zhiwen-livepush/yes.png"></image>\t\t\t\t\t<view class="mar10">完成</view>\t\t\t\t\t\t\t</view>\t\t\t\t\t</view>\t\t\t\t </view></template><script> export default {\t\tdata() {\t\t\treturn {\t\t\t begin:false,//開始錄製\t\t\t\tcomplete:false,//錄製完畢\t\t\t\tpause:false,//暫停推流\t\t\t\tcurrentWebview:null,\t\t\t\tpusher:null,\t\t\t\tlivepushurl:'rtmp://106.52.216.244:10089/hls/1', //這裡修改自己的推流地址就可以了\t\t\t\tlogininfokey:'',//登入驗證加密串,\t\t\t\thomeworkcont:'',//作業資訊\t\t\t\tjiexititle:'',//作業解析標題\t\t\t\tindex: 0,//定時\t\t\t\tindextu:0,//是否開啟定時\t\t\t\tcontTime:'',\t\t\t\tarray: [{//話題標籤\t\t\t\t\t\t"id": 1,\t\t\t\t\t\t"cont": "10秒",\t\t\t\t\t\t"time": 10\t\t\t\t\t}, {\t\t\t\t\t\t"id": 2,\t\t\t\t\t\t"cont": "20秒",\t\t\t\t\t\t"time": 20\t\t\t\t\t}, {\t\t\t\t\t\t"id": 3,\t\t\t\t\t\t"cont": "30秒",\t\t\t\t\t\t"time": 30\t\t\t\t\t}, {\t\t\t\t\t\t"id": 4,\t\t\t\t\t\t"cont": "40秒",\t\t\t\t\t\t"time": 40\t\t\t\t\t},{\t\t\t\t\t\t"id": 5,\t\t\t\t\t\t"cont": "50秒",\t\t\t\t\t\t"time": 50\t\t\t\t\t},\t\t\t\t\t{\t\t\t\t\t\t"id": 6,\t\t\t\t\t\t"cont": "60秒",\t\t\t\t\t\t"time": 60\t\t\t\t\t}],\t\t\t}\t\t},\t\t \t\tonShow() {\t\t\t uni.getNetworkType({\t\t\t\tsuccess: function (res) {\t\t\t\t\tconsole.log(res.networkType);\t\t\t\t\tif(res.networkType != 'wifi'){\t\t\t\t\t\tuni.showModal({ //提醒使用者更新\t\t\t\t\t\t\ttitle: '溫馨提示',\t\t\t\t\t\t\tcontent: '當前非Wifi網路,請注意您的流量是否夠用',\t\t\t\t\t\t\tsuccess: (res) => {\t\t\t\t\t\t\t\t \t\t\t\t\t\t\t}\t\t\t\t\t\t})\t\t\t\t\t}\t\t\t\t}\t\t\t});\t\t\tuni.onNetworkStatusChange(function (res) {\t\t\t\tconsole.log(res.isConnected);\t\t\t\tconsole.log(res.networkType);\t\t\t\tif(res.networkType != '4g' && res.networkType != 'wifi'){\t\t\t\t\tuni.showModal({ //提醒使用者更新\t\t\t\t\t\ttitle: '溫馨提示',\t\t\t\t\t\tcontent: '當前網路品質差,請切換為4G網路或Wifi網路',\t\t\t\t\t\tsuccess: (res) => {\t\t\t\t\t\t\t \t\t\t\t\t\t}\t\t\t\t\t})\t\t\t\t}\t\t\t});\t\t/* \tplus.key.addEventListener("backbutton",()=>{\t\t\t\tconsole.log("BackButton Key pressed!" );\t\t\t\t//this.back()\t\t\t\treturn false\t\t\t}); */\t\t},\t\t onBackPress(){\t\t\t\tthis.back()\t\t\t console.log("BackButton Key pressed!" );\t\t\t\treturn true;\t\t }, onLoad(res) {\t\t\tconsole.log(res)\t\t\tthis.jiexititle=res.title\t\t\tuni.getStorage({\t\t\t\tkey: 'logininfokey',\t\t\t\tsuccess:(res) =>{\t\t\t\t\tconsole.log(res.data);\t\t\t\t\tthis.logininfokey=res.data\t\t\t\t\tconsole.log(this.logininfokey)\t\t\t\t}\t\t\t});\t\t\tuni.getStorage({\t\t\t\tkey: 'clickworkcont',\t\t\t\tsuccess:(res) =>{\t\t\t\t\tconsole.log(res.data);\t\t\t\t\tthis.homeworkcont=res.data\t\t\t\t\t//console.log(this.logininfokey)\t\t\t\t}\t\t\t});\t\t\t\t\t\tuni.getStorage({\t\t\t\tkey: 'livepushurl',\t\t\t\tsuccess:(res) =>{\t\t\t\t\tconsole.log(res.data);\t\t\t\t\tthis.livepushurl=res.data\t\t\t\t}\t\t\t});\t\t\tconsole.log(this.livepushurl)\t this.getwebview()//獲取webview },\t\tmethods: {\t\t\t//倒計時\t\t\tbindPickerChange: function(e) {\t\t\t console.log('picker傳送選擇改變,攜帶值為', e.target.value)\t\t\t this.index = e.target.value\t\t\t\t// this.indexs = e.target.value\t\t\t\tthis.contTime=this.array[e.target.value].time\t\t\t\tuni.showToast({\t\t\t\t\ttitle: '請點選紅色按鈕,開始進入倒計時',\t\t\t\t\ticon:'none',\t\t\t\t\tduration: 4000,\t\t\t\t\t \t\t\t\t});\t\t\t},\t\t\t\t\t\t/**\t\t\t * 返回\t\t\t */\t\t\tback(){\t\t\t\tuni.showModal({\t\t\t\t\ttitle: '提示',\t\t\t\t\tcontent: '返回後未上傳的視訊需要重新錄製哦',\t\t\t\t\tsuccess: function (res) {\t\t\t\t\t\tif (res.confirm) {\t\t\t\t\t\t\t/* this.currentWebview=null;\t\t\t\t\t\t\tthis.pusher=null */\t\t\t\t\t\t\tuni.redirectTo({\t\t\t\t\t\t\t\turl:'../user/issue'\t\t\t\t\t\t\t})\t\t\t\t\t\t\t//this.currentWebview=null\t\t\t\t\t\t} else if (res.cancel) {\t\t\t\t\t\t\tconsole.log('使用者點選取消');\t\t\t\t\t\t}\t\t\t\t\t}\t\t\t\t});\t\t\t\t\t\t\t},\t\t\t/**\t\t\t * 獲取當前顯示的webview\t\t\t */\t\t\tgetwebview(){\t\t\t\tvar pages = getCurrentPages();\t\t\t\tvar page = pages[pages.length - 1];\t\t\t\t// #ifdef APP-PLUS\t\t\t\tvar getcurrentWebview = page.$getAppWebview();\t\t\t\tconsole.log(this.pages)\t\t\t\tconsole.log(this.page)\t\t\t\tconsole.log(JSON.stringify(page.$getAppWebview()))\t\t\t\tthis.currentWebview=getcurrentWebview;\t\t\t\t// #endif\t\t\t\tthis.plusReady()//建立LivePusher物件\t\t\t},\t\t\t/**\t\t\t * 建立LivePusher物件 即推流物件\t\t\t */ \t\t\tplusReady(){\t\t\t\t\t\t\t\t// 建立直播推流控制元件\t\t\t\tthis.pusher =new plus.video.LivePusher('pusher',{\t\t\t\t\turl:'',\t\t\t\t\ttop:'0',\t\t\t\t\tleft:'0px',\t\t\t\t\twidth: '100%',\t\t\t\t\theight: uni.getSystemInfoSync().windowHeight-15 + 'px',\t\t\t\t\t\t\t\t\tposition: 'absolute',//static靜態佈局模式,如果頁面存在滾動條則隨視窗內容滾動,absolute絕對佈局模式,如果頁面存在滾動條不隨視窗內容滾動; 預設值為"static"\t\t\t\t\tbeauty:'0',//美顏 0-off 1-on \t\t\t\t\twhiteness:'0',//0、1、2、3、4、5,0不使用美白,值越大美白程度越大。\t\t\t\t\taspect:'9:16',\t\t\t\t\t \t\t\t\t});\t\t\t\tconsole.log(JSON.stringify(this.pusher))\t\t\t\tconsole.log(JSON.stringify(this.currentWebview))\t\t\t\t//將建立的物件 追加到webview中\t\t\t\tthis.currentWebview.append(this.pusher);\t\t\t\t// 監聽狀態變化事件 \t\t\t\tthis.pusher.addEventListener('statechange',(e)=>{\t\t\t\t\tconsole.log('statechange: '+JSON.stringify(e));\t\t\t\t}, false);\t\t\t},\t\t\t\t\t\t//美顏\t\t\tbeautiful(){\t\t\t\tconsole.log(JSON.stringify(this.pusher))\t\t\t\tthis.pusher.options.beauty=1\t\t\t\tthis.plusReady()//建立LivePusher物件\t\t\t},\t\t\t// 開始推流\t\t\tstartPusher(){\t\t\t\t//判斷是否倒計時開始\t\t\t\tif(this.contTime!=''){\t\t\t\t\tif(this.indextu!=1){\t\t\t\t\t\tthis.conttimejs()\t\t\t\t\t}\t\t\t\t}else{\t\t\t\t\tthis.beginlivepush()\t\t\t\t}\t\t\t},\t\t\tconttimejs(){\t\t\t\tif(this.contTime!=''){\t\t\t\t\tthis.indextu=1;//開啟計時\t\t\t\t\tif(this.contTime==1){\t\t\t\t\t\tconsole.log("開始")\t\t\t\t\t\tthis.contTime=""\t\t\t\t\t\tthis.beginlivepush()\t\t\t\t\t\treturn false\t\t\t\t\t}\t\t\t\t\tthis.contTime--\t\t\t\t\tsetTimeout(()=>{\t\t\t\t\t\tthis.conttimejs()\t\t\t\t\t},1000)\t\t\t\t}\t\t\t},\t\t\tbeginlivepush() {\t\t\t\tthis.indextu=0;//關閉計時\t\t\t\tif(this.begin==false){//未開啟推流\t\t\t\t\tthis.begin=true;//顯示錄製動畫\t\t\t\t\t// 設定推流伺服器 ***此處需要通過ajax向後端獲取\t\t\t\t\tthis.pusher.setOptions({\t\t\t\t\t\turl:this.livepushurl //推流地址********************************* 此處設定推流地址\t\t\t\t\t});\t\t\t\t\tthis.pusher.start();//推流開啟\t\t\t\t\tuni.showToast({\t\t\t\t\t\ttitle: '開始錄製',\t\t\t\t\t\ticon:'none',\t\t\t\t\t\tduration: 2000,\t\t\t\t\t \t\t\t\t\t});\t\t\t\t}else{\t\t\t\t\tif(this.pause==true){//暫停推流狀態\t\t\t\t\t\tthis.begin=true;//顯示錄製動畫\t\t\t\t\t\tthis.pause=false;//推流開關置為預設狀態\t\t\t\t\t\tthis.pusher.resume();//恢復推流\t\t\t\t\t\tuni.showToast({\t\t\t\t\t\t\ttitle: '開始錄製',\t\t\t\t\t\t\ticon:'none',\t\t\t\t\t\t\tduration: 2000,\t\t\t\t\t \t\t\t\t\t\t});\t\t\t\t\t}else{\t\t\t\t\t\tthis.begin=false;//關閉錄製動畫\t\t\t\t\t\tthis.pause=true;//推流暫停\t\t\t\t\t\tthis.pusher.pause();;//暫停推流\t\t\t\t\t\tuni.showToast({\t\t\t\t\t\t\ttitle: '暫停錄製',\t\t\t\t\t\t\ticon:'none',\t\t\t\t\t\t\tduration: 2000,\t\t\t\t\t \t\t\t\t\t\t});\t\t\t\t\t\t//提示是否上傳\t\t\t\t\t\tthis.upload()\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\t\t\t\t}\t\t\t},\t\t\t/**\t\t\t * 切換攝像頭\t\t\t */ \t\t\tswitchCamera() {\t\t\t\tthis.pusher.switchCamera();\t\t\t},\t\t\t/**\t\t\t * 完成錄製\t\t\t */\t\t\tupload(){\t\t\t\t uni.showModal({\t\t\t\t \ttitle: '提示',\t\t\t\t \tcontent: '確定儲存嗎',\t\t\t\t \tsuccess:(res)=> {\t\t\t\t \t\tif (res.confirm) {\t\t\t\t \t\t\t console.log('使用者點選完成');\t\t\t\t\t\t\t this.pusher.pause();;//暫停推流\t\t\t\t\t\t\t this.endlivepush()\t\t\t\t\t\t\t \t\t\t\t\t\t\t/* setTimeout(()=>{\t\t\t\t\t\t\t\t this.endlivepush()\t\t\t\t\t\t\t },1000) */\t\t\t\t \t\t} else if (res.cancel) {\t\t\t\t \t\t\tconsole.log('使用者點選取消');\t\t\t\t \t\t}\t\t\t\t \t}\t\t\t\t });\t\t\t}, \t\t\t//結束推流,此處需要呼叫後臺介面向雲服務商提交結束狀態\t\t\tendlivepush(){\t\t\t\t\tuni.showToast({\t\t\t\t\ticon:'loading',\t\t\t\t\ttitle: '結束...',\t\t\t\t\tduration: 5000\t\t\t\t});\t\t\t\treturn false\t\t\t\tuni.request({\t\t\t\t\t\turl: "", \t\t\t\t\t \tmethod: 'POST',\t\t\t\t\t\t// dataType:'JSON',\t\t\t\t data:{},\t\t\t\t success:(res)=>{\t\t\t\t\t\t console.log(JSON.parse(res.data))\t\t\t\t\t\t console.log(JSON.stringify(res.data))\t\t\t\t\t\t\tuni.showToast({\t\t\t\t\t\t\t\ticon:'loading',\t\t\t\t\t\t\t\ttitle: '視訊上傳中...',\t\t\t\t\t\t\t\tduration: 5000\t\t\t\t\t\t\t});\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetTimeout(()=>{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tuni.showToast({\t\t\t\t\t\t\t\t\ticon:'none',\t\t\t\t\t\t\t\t\ttitle: '上傳完成',\t\t\t\t\t\t\t\t\tduration: 2000\t\t\t\t\t\t\t\t});\t\t\t\t\t\t\t},5000)\t\t\t\t\t\t\tsetTimeout(()=>{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tuni.redirectTo({\t\t\t\t\t\t\t\t\turl: 'setvideotit?id='+this.homeworkcont.id,\t\t\t\t\t\t\t\t});\t\t\t\t\t\t\t},7000)\t\t\t\t },\t\t\t\t error: (data)=>{\t\t\t\t \t//alert(JSON.stringify(data)+'錯誤')\t\t\t \t\t\t\t }\t\t\t\t });\t\t\t},\t\t\t \t\t},\t\tcomponents:{\t\t\t\t} }</script><style>\t.content{\t\tbackground: #000;\t\toverflow: hidden;\t}\t.butlist{\t\theight: 140upx;\t\tposition: absolute;\t\tbottom: 0;\t\tdisplay: flex;\t\twidth: 100%;\t\tjustify-content: space-around;\t padding-top: 20upx;\t\tborder-top: 1px solid #fff;\t\tbackground: #000;\t}\t.buticon{\t\theight: 120upx;\t\twidth: 120upx;\t\tcolor: #fff;\t\tposition: relative;\t\ttext-align: center;\t\tmargin-bottom: 20upx;\t}\t.buticon image{\t\theight: 64upx;\t\twidth: 64upx;\t}\t.buticon .mar10{\t\tmargin-top: -20upx;\t}\t.martp10{\t\tmargin-top: 10upx;\t}\t.give {\t\twidth: 90upx;\t\theight: 90upx;\t\tbackground: #F44336;\t\t\tborder-radius: 50%;\t\tbox-shadow: 0 0 22upx 0 rgb(252, 94, 20);\t \t position: absolute; \t\tleft:15upx;\t\ttop:15upx; \t\t font-size: 44upx; line-height: 90upx;\t}\t.givebegin {\t\twidth: 60upx;\t\theight: 60upx;\t\tbackground: #F44336;\t\t\tborder-radius: 20%;\t\tbox-shadow: 0 0 22upx 0 rgb(252, 94, 20);\t \t position: absolute; \t\tleft:30upx;\t\ttop:30upx; \t}\t.x_f{\t\t/* border: 6upx solid #F44336; */\t\twidth: 120upx;\t\theight: 120upx;\t\tbackground: #fff;\t\tborder-radius: 50%;\t\tposition: absolute;\t\ttext-align: center;\t\ttop:0;\t\tleft: 0;\t box-shadow: 0 0 28upx 0 rgb(251, 99, 24);\t}\t\t/* 產生動畫(向外擴散變大)的圓圈 */\t.pulse {\t\twidth: 160upx;\t\theight: 160upx;\t\tposition: absolute;\t border: 12upx solid #F44336;\t border-radius: 100%;\t z-index: 1;\t opacity: 0;\t -webkit-animation: warn 2s ease-out;\t animation: warn 2s ease-out;\t -webkit-animation-iteration-count: infinite;\t animation-iteration-count: infinite;\t left: -28upx;\t top: -28upx;\t}\t\t\t\t/**\t * 動畫\t */\t@keyframes warn {\t0% {\t\ttransform: scale(0);\t\topacity: 0.0;\t}\t25% {\t\ttransform: scale(0);\t\topacity: 0.1;\t}\t50% {\t\ttransform: scale(0.1);\t\topacity: 0.3;\t}\t75% {\t\ttransform: scale(0.5);\t\topacity: 0.5;\t}\t100% {\t\ttransform: scale(1);\t\topacity: 0.0;\t}}\t\t </style>

14. 拉流演示程式碼。

<template class='fullscreen'>\t<view class='fullscreen'>\t\t<view v-if="beCalling" class="backols">\t\t\t<view class='becalling-text'>對方邀請你開始視訊聊天</view>\t\t\t<view class="butlist2">\t\t\t\t<view @click="rejectCallHandler" class="buticon2 martp10">\t\t\t\t\t<image src="../../static/img/netcall-reject.png"></image>\t\t\t\t\t</view>\t\t\t\t\t<view @click="acceptCallHandler" class="buticon2 martp10">\t\t\t\t\t\t<image src="../../static/img/netcall-accept.png"></image>\t\t\t\t\t\t</view>\t\t\t\t</view>\t\t</view>\t\t<view v-else class="butlist">\t\t\t\t<view @click="switchaudio" class="buticon martp10">\t\t\t\t\t<image src="../../static/img/netcall-call-voice.png"></image>\t\t\t\t\t\t\t\t\t</view>\t\t\t\t<view @click="switchCamera" class="buticon martp10">\t\t\t\t\t<image src="../../static/img/netcall-revert-camera.png"></image>\t\t\t\t\t\t\t\t\t\t\t</view>\t\t\t\t<view @click="close" class="buticon martp10">\t\t\t\t\t<image src="../../static/img/netcall-reject.png"></image>\t\t\t\t\t</view>\t\t\t \t\t\t</view>\t</view>\t\t</template><script>\texport default {\t\t data() {\t\t\t return{\t\t\t\tbeCalling: true,\t\t\t\tvideourl:'',\t\t\t\twidth:'',\t\t\t\tcurrentWebview:null,\t\t\t\tpushers:'',\t\t\t\tvideo :''\t\t }\t\t},\t\t\t\tonLoad: function (options) {\t\t\t\t this.getwebview()//獲取webview\t\t},\t\tonUnload() {\t\t\t\t},\t\tmethods: {\t\t\t\tclose(){\t\t\t\t\t\t this.pusher.pause();//暫停推流\t\t\t\t\t\tthis.pusher.close()//關閉推流控制元件\t\t\t\t\t\tuni.switchTab({\t\t\t\t\t\t\turl:''\t\t\t\t\t\t})\t\t\t\t},\t\t\t\tgetwebview(){\t\t\t\t\tvar pages = getCurrentPages();\t\t\t\t\tvar page = pages[pages.length - 1];\t\t\t\t\t// #ifdef APP-PLUS\t\t\t\t\tvar getcurrentWebview = page.$getAppWebview();\t\t\t\t\tconsole.log(this.pages)\t\t\t\t\tconsole.log(this.page)\t\t\t\t\tconsole.log(JSON.stringify(page.$getAppWebview()))\t\t\t\t\tthis.currentWebview=getcurrentWebview;\t\t\t\t\t// #endif\t\t\t\t\tthis.plusReady()//建立LivePusher物件\t\t\t\t},\t\t\t\t \t\t\t\tplusReady(){\t\t\t\t\t\t\t\t\t\t\t\t\tthis.pushers =new plus.video.VideoPlayer('video',{\t\t\t\t\t\t// src:self.userlist[0].url,\t\t\t\t\t\tsrc:"rtmp://58.200.131.2:1935/livetv/hunantv", //這裡替換自己的拉流地址\t\t\t\t\t\ttop:'0px',\t\t\t\t\t\tleft:'0px',\t\t\t\t\t\tcontrols:false,\t\t\t\t\t\twidth: '100%',\t\t\t\t\t\theight: uni.getSystemInfoSync().windowHeight-150 + 'px',\t\t\t\t\t\tposition: 'static'\t\t\t\t\t\t\t});\t\t\t\t \t\t\t\t\tthis.currentWebview.append(this.pushers);\t\t\t\t this.pushers.play()\t\t\t\t},\t\t \t\t \t\t /**\t\t\t * 切換攝像頭\t\t\t */ \t\t\tswitchCamera() {\t\t\t\tthis.pusher.switchCamera();\t\t\t},\t\t\tswitchaudio() {\t\t\t\tconsole.log('點選了');\t\t\t}\t\t\t\t\t\t}\t\t}\t</script><style>\t\t.backols{\t background: rgba(0, 0, 0, 0.74); height: 100%; position: absolute; width: 100%;\t}\tuni-page{\t\tbackground:#000000;\t}\t.butlist{\t\theight: 140upx;\t\tposition: absolute;\t\tbottom: 0;\t\tdisplay: flex;\t\twidth: 100%;\t\tjustify-content: space-around;\t padding-top: 20upx;\t\tborder-top: 1px solid #fff;\t}\t.buticon{\t\theight: 120upx;\t\twidth: 120upx;\t\tcolor: #fff;\t\tposition: relative;\t\ttext-align: center;\t\tmargin-bottom: 20upx;\t}\t.buticon image{\t\theight: 90upx;\t\twidth: 90upx;\t}\t.buticon .mar10{\t\tmargin-top: -20upx;\t}\t.martp10{\t\tmargin-top: 10upx;\t\t}\t.becalling-text{\t\ttext-align: center;\t\tcolor: #FFFFFF;\t\tfont-size: 28upx;\t\tpadding: 60upx;\t\tmargin-top: 40%;\t}\t.butlist2{\t\theight: 140upx;\t\tposition: absolute;\t\tbottom: 5%;\t\tdisplay: flex;\t\twidth: 100%;\t\tjustify-content: space-around;\t padding-top: 20upx;\t \t}\t.buticon2{\t\theight: 120upx;\t\twidth: 120upx;\t\tcolor: #fff;\t\tposition: relative;\t\ttext-align: center;\t\tmargin-bottom: 20upx;\t}\t.buticon2 image{\t\theight: 110upx;\t\twidth: 110upx;\t} \t.container {\t width: 100%;\t height: 100%;\t}\t/* 被叫 */\t.becalling-wrapper {\t position: relative;\t width:100%;\t height:800upx;\t background-color:#777;\t color:#fff;\t font-size:40rpx;\t}\t.becalling-wrapper .becalling-text {\t position: absolute;\t top:400rpx;\t left:50%;\t margin-left:-220rpx;\t}\t.becalling-wrapper .becalling-button-group {\t position: absolute;\t width:100%;\t box-sizing:border-box;\t bottom: 100rpx;\t padding: 0 40rpx;\t display: flex;\t flex-direction: row;\t justify-content: space-between;\t}\t.becalling-button-group .button {\t width:220rpx;\t height:80rpx;\t border-radius:10rpx;\t justify-content:center;\t display:flex;\t align-items:center;\t font-size:33rpx;\t color:#000;\t}\t.becalling-button-group .reject-button {\t background-color:#f00;\t}\t.becalling-button-group .accept-button {\t background-color:rgb(26, 155, 252);\t}\t\t.calling-coverview {\t width:100%;\t height:100rpx;\t background-color:#ccc;\t color:#fff;\t font-size:40rpx;\t text-align:center;\t line-height:100rpx;\t}\t/* 視訊容器 */\t.video-wrapper {\t width: 100%;\t height: 100%;\t padding-bottom: 100rpx;\t box-sizing: border-box;\t position: relative;\t background-color: #000;\t}\t.control-wrapper {\t width: 100%;\t box-sizing: border-box;\t position: absolute;\t bottom: 0;\t}\t.calling-voerview {\t background-color:#ccc;\t color:#fff;\t height: 160rpx;\t font-size: 40rpx;\t text-align: center;\t line-height: 160rpx;\t}\t.control-wrapper {\t position: fixed;\t bottom: 18px;\t left:0;\t display: flex;\t width: 100%;\t box-sizing: border-box;\t flex-direction:row;\t justify-content: space-between;\t padding: 0 42rpx;\t height: 200rpx;\t}\t.control-wrapper .item{\t width: 92rpx;\t height: 92rpx;\t margin-top: 100rpx;\t}\t.netcall-time-text {\t position:absolute;\t bottom:160rpx;\t width:100%;\t height: 40rpx;\t color:#fff;\t font-size:40rpx;\t text-align:center;\t left:0;\t}\t\t\t.fullscreen{\t\tdisplay: flex;\t\tbackground: #000000;\t\theight: 100%;\t\twidth: 100%;\t\tposition: absolute;\t}\t</style>

15. uni-app模組許可權如下。

654

Nginx

Git

最新評論
  • 1 #

    這才是籃球該有的樣子,this is why we love,this is why we play !

  • 2 #

    這個流媒體是老套的flash,在網頁端播放需要flash外掛,目前會導致各種瀏覽器警告。

  • 整治雙十一購物亂象,國家再次出手!該跟這些套路說再見了
  • EMUI10.1系統來臨,華為公佈升級名單,15款機型有你的嗎?