day122:MoFang:OSSRS流媒體直播伺服器&基於APICloud的acLive直播推流模組實現RTMP直播推流
- 2021 年 1 月 11 日
- 筆記
- PythonS31-筆記, Python全棧31期-筆記
2.基於APICloud的acLive直播推流模組實現RTMP直播推流
1. 通過第三方介面來實現.
可以申請阿里雲,騰訊雲,網易雲,七牛雲的直播介面,根據文檔,下載集成SDK到項目中,在第三方用戶平台上, 創建直播流[就是一個管道].有了直播流以後, 在客戶端中集成一個推流[就是基於rtmp協議把影片攝影機採集到的資訊push到直播伺服器]的播放器或者第三放模組
在另一個客戶端中, 集成支援播放rtmp影片資訊的播放器插件,基於這個插件向第三方直播伺服器獲取直播影片.
2. 自己部署搭建直播伺服器.
nginx+nginx-rtmp-module+ffmpeg
ossrs
官方文檔://github.com/ossrs/srs/wiki
SRS定位是運營級的互聯網直播伺服器集群,追求更好的概念完整性和最簡單實現的程式碼。SRS提供了豐富的接入方案將RTMP流接入SRS,包括推送RTMP到SRS、推送RTSP/UDP/FLV到SRS、拉取流到SRS。 SRS還支援將接入的RTMP流進行各種變換,譬如將RTMP流轉碼、流截圖、轉發給其他伺服器、轉封裝成HTTP-FLV流、轉封裝成HLS、 轉封裝成HDS、轉封裝成DASH、錄製成FLV/MP4。SRS包含支大規模集群如CDN業務的關鍵特性,譬如RTMP多級集群、源站集群、VHOST虛擬伺服器 、 無中斷服務Reload、HTTP-FLV集群。此外,SRS還提供豐富的應用介面,包括HTTP回調、安全策略Security、HTTP API介面、 RTMP測速。SRS在源站和CDN集群中都得到了廣泛的應用Applications。
2.OSSRS安裝
1.創建自定義網路
sudo docker network create --driver bridge --subnet 172.0.0.0/16 srs_network # sudo docker network ls
2.創建配置文件
# 使用阿里雲鏡像安裝啟動srs sudo docker run -p 1935:1935 -p 1985:1985 -p 8080:8080 --name srs registry.cn-hangzhou.aliyuncs.com/ossrs/srs:v4.0.34 # 把容器中的配置文件複製出來 sudo mkdir -p /home/docker/srs4 sudo docker cp -a srs:/usr/local/srs/conf /home/docker/srs4/conf # 把容器中的日誌文件複製出來 sudo docker cp -a srs:/usr/local/srs/objs /home/docker/srs4/objs # 刪除容器 sudo docker rm -f srs
3.掛載配置文件並啟動
sudo docker run --restart=always -p 1935:1935 -p 1985:1985 -p 8080:8080 --name srs --network srs_network --ip 172.0.0.35 -v /home/docker/srs4/conf/:/usr/local/srs/conf/ -v /home/docker/srs4/objs/:/usr/local/srs/objs/ -d registry.cn-hangzhou.aliyuncs.com/ossrs/srs:v4.0.34
通過//127.0.0.1:1935/live/自定義直播流名稱
進行直播推流
生成APPLoader,並安裝到手機[注意:推流必須依賴於攝影機,而前面我們使用的Android模擬器是沒有辦法完成攝影機調用的。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body style="background-color:#fff"> <br><br><br><br> <br><br><br><br> <button id="liver">我是主播</button> <button id="viewer">我是觀眾</button> <script> apiready = function(){ document.getElementById("viewer").onclick = function(){ } document.getElementById("liver").onclick = function(){ var acLive = api.require('acLive'); // 打開攝影機採集影片資訊 acLive.open({ camera:0, // 1為前置攝影機, 0為後置攝影機,默認1 rect : { // 採集畫面的位置和尺寸 x : 0, y : 0, w : 'auto', h : 'auto', } },(ret, err)=>{ alert(JSON.stringify(ret)); // 開啟美顏 acLive.beautyFace(); // 開始推流 acLive.start({ url:'rtmp://192.168.20.251:1935/live/t1' // t1 就是流名稱,可以理解為直播的房間號 },function(ret, err){ alert(JSON.stringify(ret)); // 狀態如果為2則表示連接成功,其他都表示不成功 }); }); } } </script> </body> </html>
3.直播流管理
cd application/apps/
python ../../manage.py blue -nlive
from application.utils.models import BaseModel,db class LiveStream(BaseModel): """直播流管理""" __tablename__ = "mf_live_stream" name = db.Column(db.String(255), unique=True, comment="流名稱") room_name = db.Column(db.String(255), default="房間名稱") user = db.Column(db.Integer, comment="房主") class LiveRoom(BaseModel): """直播間""" __tablename__ = "mf_live_room" stream_id = db.Column(db.Integer, comment="直播流ID") user = db.Column(db.Integer, comment="用戶ID")
INSTALLED_APPS = [ "application.apps.home", "application.apps.users", "application.apps.orchard", "application.apps.live", ]
from application.utils import include urlpatterns = [ include("","home.urls"), include("/users","users.urls"), include("/orchard","orchard.urls"), include("/live","live.urls"), ]
服務端提供創建直播流的API介面,程式碼:
from application import jsonrpc,db from message import ErrorMessage as message from status import APIStatus as status from flask_jwt_extended import jwt_required,get_jwt_identity from application.apps.users.models import User from .models import LiveStream,LiveRoom from datetime import datetime import random @jsonrpc.method("Live.stream") @jwt_required # 驗證jwt def live_stream(room_name): """創建直播流""" current_user_id = get_jwt_identity() # get_jwt_identity 用於獲取載荷中的數據 user = User.query.get(current_user_id) # 申請創建直播流 stream_name = "room_%06d%s%06d" % (user.id, datetime.now().strftime("%Y%m%d%H%M%S"), random.randint(100,999999)) stream = LiveStream.query.filter(LiveStream.user==user.id).first() if stream is None: stream = LiveStream( name=stream_name, user=user.id, room_name=room_name ) db.session.add(stream) db.session.commit() else: stream.room_name = room_name # 進入房間 room = LiveRoom.query.filter(LiveRoom.user==user.id,LiveRoom.stream_id==stream.id).first() if room is None: room = LiveRoom( stream_id=stream.id, user=user.id ) db.session.add(room) db.session.commit() return { "errno": status.CODE_OK, "errmsg": message.ok, "data":{ "stream_name": stream_name, "room_name": room_name, "room_owner": user.id, "room_id": "%04d" % stream.id, } }
前端live_list.html程式碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="format-detection" content="telephone=no,email=no,date=no,address=no"> <link rel="stylesheet" href="../static/css/main.css"> <script src="../static/js/vue.js"></script> <script src="../static/js/axios.js"></script> <script src="../static/js/main.js"></script> <script src="../static/js/uuid.js"></script> <script src="../static/js/settings.js"></script> </head> <body> <div class="app" id="app"> <br><br><br><br> <br><br><br><br> <button @click="liver">創建直播間</button> <button @click="start_live">我要開播</button> <button id="viewer">我是觀眾</button> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { music_play:true, // stream_name:"", // 直播流名稱 prev:{name:"",url:"",params:{}}, // current:{name:"live",url:"live_list.html","params":{}}, // } }, methods:{ liver(){ var token = this.game.get("access_token") || this.game.fget("access_token"); this.axios.post("",{ "jsonrpc": "2.0", "id": this.uuid(), "method": "Live.stream", "params": { "room_name": "愛的直播間" } },{ headers:{ Authorization: "jwt " + token, } }).then(response=>{ var message = response.data.result; if(parseInt(message.errno)==1005){ this.game.goWin("user","login.html", this.current); } if(parseInt(message.errno)==1000){ this.stream_name = message.data.stream_name; }else{ this.game.print(response.data); } }).catch(error=>{ // 網路等異常 this.game.print(error); }); }, start_live(){ // 開始直播 var acLive = api.require('acLive'); // 打開攝影機採集影片資訊 acLive.open({ camera:0, // 1為前置攝影機, 0為後置攝影機,默認1 rect : { // 採集畫面的位置和尺寸 x : 0, y : 0, w : 'auto', h : 'auto', } },(ret, err)=>{ alert(JSON.stringify(ret)); // 開啟美顏 acLive.beautyFace(); // 開始推流 alert(this.settings.live_stream_server+this.stream_name) acLive.start({ url: this.settings.live_stream_server+this.stream_name // t1 就是流名稱,可以理解為直播的房間號 },function(ret, err){ alert(JSON.stringify(ret)); // 狀態如果為2則表示連接成功,其他都表示不成功 }); }); } } }) } </script> </body> </html>