前言
最近公司因為業務需要,研究做直播功能,查閱了大量網友寫的demo,最侄訓是被很多問題絆倒了,由于現在chrom已經屏蔽flash了,咱們要換種解決辦法,但咱們是面向csdn等技術交流平臺編程,所以問題不大,
總共分為兩部分,一篇是針對uniapp+vue,另一篇是ngxin直播服務器的搭建,傳送門在結尾,
UniApp(推流)/ OBS(推流)+ Vue(拉流)/ VLC(拉流)
目前有很多關于直播的教程哈,但是都比較單一,不夠全面,所以本篇文章經過自己動手實踐和整合,搞出來了這一套教程,沒有做過直播的同學或者做過出現問題的同學可以詳細的看下這篇文章,或許對你有所幫助,
一、先看效果
- vue拉流

- uniapp推流

二、uniapp篇
這里用的是官方給的基礎代碼,具體引數請參考官方:
https://uniapp.dcloud.io/component/live-player
- 創建uniapp專案
- 在pages–>index–>新建live.nvue頁面
重點:后綴是nvue,不了解可以自行百度
這里我們用的軟體是hbuilderx,連接手機后直接運動uniapp專案,可以方便測驗攝像頭等功能,如果做完這個專案要發布的話,必須在發布前,修改manifest.json檔案:
在hbuilderx中,雙擊你專案中manifest.json檔案,左側選單找到App模塊配置,勾選 LivePusher(直播推流) 這一選項
- 無需廢話,這是app直播主要頁面,上代碼😁:
<template>
<view>
<view class="account-form">
<view class="uni-form-item">
<view class="uni-input-wrapper">
<view class="uni-label uni-label-must">直播間標題</view>
<input class="uni-input" placeholder="請輸入直播間標題" :value="form.liveroomTitle" @input="changeInput($event,'liveroomTitle')"/>
</view>
</view>
</view>
<button class="cu-btn bg-red margin-tb-sm lg" v-if="!startState" @click="saveForm">開始直播</button>
<button class="cu-btn bg-red margin-tb-sm lg" v-if="startState" @click="downcast">關閉直播</button>
<button class="cu-btn bg-red margin-tb-sm lg" @click="switchCamera">切換攝像頭</button>
<live-pusher
id="livePusher"
ref="livePusher"
:style="pusherCalss"
class="livePusher"
url="rtmp://192.168.1.171:17002/live/huahua"
mode="FHD"
:muted="false"
:enable-camera="true"
:auto-focus="true"
:beauty="1"
whiteness="2"
aspect="9:16"
@statechange="statechange"
@netstatus="netstatus"
@error="error"
></live-pusher>
// 官方給的一些按鈕,具體呼叫在下面
//<button class="btn" @click="start">開始推流</button>
//<button class="btn" @click="pause">暫停推流</button>
//<button class="btn" @click="resume">resume</button>
//<button class="btn" @click="stop">停止推流</button>
//<button class="btn" @click="snapshot">快照</button>
//<button class="btn" @click="startPreview">開啟攝像頭預覽</button>
//<button class="btn" @click="stopPreview">關閉攝像頭預覽</button>
//<button class="btn" @click="switchCamera">切換攝像頭</button> -->
</view>
</template>
<script>
export default {
data() {
return {
// 視頻寬高
pusherCalss: {
width: '200px',
height: '300px'
},
// form本人測驗請求的引數,不發請求可以不加
form: {
liveroomTitle: null, // 標題
equipmentType: 1 // 設備型別(1.手機 2.電腦)
},
// 控制開啟,關閉直播按鈕的顯示
startState: false,// 直播狀態(false 關閉)
};
},
onReady() {
// 注意:需要在onReady中 或 onl oad 延時
this.context = uni.createLivePusherContext('livePusher', this);
},
onLoad() {
// 獲取可視區域高度,減去固定高度
this.pusherCalss.width = wx.getSystemInfoSync().windowWidth;
this.pusherCalss.height = wx.getSystemInfoSync().windowHeight;
},
mounted() {
// 一進頁面,先呼叫攝像頭,保證攝像頭是打開狀態,不加也可以,手動開啟,參考上面官方給出的那些按鈕
this.startPreview();
},
methods: {
// 下面的這些方法,可以參考官網,具體查看每個方法的意義
statechange(e) {
console.log('statechange:' + JSON.stringify(e));
},
netstatus(e) {
console.log('netstatus:' + JSON.stringify(e));
},
error(e) {
console.log('error:' + JSON.stringify(e));
},
start: function() {
this.context.start({
success: a => {
this.startState = true;
console.log('livePusher.start:' + JSON.stringify(a));
}
});
},
close: function() {
this.context.close({
success: a => {
console.log('livePusher.close:' + JSON.stringify(a));
}
});
},
snapshot: function() {
this.context.snapshot({
success: e => {
console.log(JSON.stringify(e));
}
});
},
resume: function() {
this.context.resume({
success: a => {
console.log('livePusher.resume:' + JSON.stringify(a));
}
});
},
pause: function() {
this.context.pause({
success: a => {
console.log('livePusher.pause:' + JSON.stringify(a));
}
});
},
stop: function() {
this.context.stop({
success: a => {
this.startState = false;
console.log(JSON.stringify(a));
}
});
},
switchCamera: function() {
this.context.switchCamera({
success: a => {
console.log('livePusher.switchCamera:' + JSON.stringify(a));
}
});
},
startPreview: function() {
this.context.startPreview({
success: a => {
console.log('livePusher.startPreview:' + JSON.stringify(a));
}
});
},
stopPreview: function() {
this.context.stopPreview({
success: a => {
console.log('livePusher.stopPreview:' + JSON.stringify(a));
}
});
},
// 輸入框改變(沒有介面可以忽略,這里就是發送請求時起一個直播間的名字)
changeInput: function(e, name) {
this.form[name] = e.detail.value;
},
// 開始直播
saveForm() {
if(this.form.liveroomTitle == null || this.form.liveroomTitle == ""){
return;
}
// 這里是我自己的測驗請求,因為需要和vue資料同步,做一個開播關播的資料互動,大家如果用不到的話可以直接呼叫 this.start();
getApp().$util.requestUrl(`/test/live/createLiveRecord?anchorId=2&liveroomTitle=${this.form.liveroomTitle}&equipmentType=${this.form.equipmentType}`).then(res => {
console.log(res)
if (res.status == 200) {
this.start();
}
});
},
// 關閉直播
downcast(){
// 同樣,用不到介面只簡單測驗,呼叫this.stop();
// vue的工具類等呼叫是this.$util;
// uniapp使用getApp().$util
getApp().$util.requestUrl(`/test/live/downcast?anchorId=2`).then(res => {
console.log(res)
if (res.status == 200) {
this.stop();
}
});
}
}
};
</script>
三、vue篇
- 需要安裝兩個組件😄:
npm install vue-video-player -S
npm install videojs-flash --save
- 然后在你需要直播的頁面,參考組件:
import ‘video.js/dist/video-js.css’;
import ‘vue-video-player/src/custom-theme.css’;
import { videoPlayer } from ‘vue-video-player’;
import ‘videojs-contrib-hls’;
import ‘videojs-flash’;
- 別急,上代碼🤭,這是vue直播的核心頁面:
<template>
<a-card class="card">
<div style="overflow: hidden; display: flex;">
<!-- 直播間資訊區 -->
<div class="live">
<div class="live-avatar">
<a-avatar shape="square" :size="64" icon="user" />
<p style="margin-left: 10px;"><b>二大爺的三蹦子</b></p>
</div>
<!-- 視頻區 -->
// ---------這里是我們本次直播教程的主要關注區域 START-----------
<div class="video-class">
<videoPlayer
class="vjs-custom-skin videoPlayer"
:options="playerOptions"
@play="onPlayerPlay($event)"
@pause="onPlayerPause($event)"
@ended="onPlayerEnded($event)"
@loadeddata="onPlayerLoadeddata($event)"
@waiting="onPlayerWaiting($event)"
@playing="onPlayerPlaying($event)"
@timeupdate="onPlayerTimeupdate($event)"
@canplay="onPlayerCanplay($event)"
@canplaythrough="onPlayerCanplaythrough($event)"
@ready="playerReadied"
@statechanged="playerStateChanged($event)"
></videoPlayer>
</div>
// -----------------主要關注區域 END-------------
</div>
<!-- 彈幕區 -->
<div class="chat"><p>這里是彈幕區</p></div>
</div>
</a-card>
</template>
<script>
import 'video.js/dist/video-js.css';
import 'vue-video-player/src/custom-theme.css';
import { videoPlayer } from 'vue-video-player';
import 'videojs-contrib-hls';
import 'videojs-flash';
export default {
name: '',
components: { videoPlayer },
data() {
return {
// ---------這里是我們本次直播教程的主要關注區域 START-----------
playerOptions: {
// height: '300',//播放器高度
language: 'zh-CN',
muted: false, //默認情況下將會消除任何音頻,
aspectRatio: '16:9', // 將播放器置于流暢模式,并在計算播放器的動態大小時使用該值,值應該代表一個比例 - 用冒號分隔的兩個數字(例如"16:9"或"4:3")
fluid: true, // 當true時,Video.js player將擁有流體大小,換句話說,它將按比例縮放以適應其容器,
sources: [
{
type: ['application/x-mpegURL', 'rtmp/flv','video/x-flv','rtmp/mp4'], //視頻流協議,如果是hls,需要后端開啟跨域
src: 'http://192.168.1.171:17001/live/huahua/index.m3u8' ,//拉流地址
}
],
autoplay: true, //自動播放
controls: true, //編輯器控制元件
notSupportedMessage: "此視頻暫無法播放,請稍后再試", // 允許覆寫Video.js無法播放媒體源時顯示的默認資訊,
controlBar: {
timeDivider: true,
durationDisplay: true,
remainingTimeDisplay: false,
fullscreenToggle: true // 全屏按鈕
},
flash: { hls: { withCredentials: false }},
html5: { hls: { withCredentials: false }},
}
// -----------------主要關注區域 END-------------
};
},
mounted() {},
computed: {},
methods: {
// 以下的這些方法,都是針對視頻組件的監聽,可以移步百度哈
// 播放回呼
onPlayerPlay(player) {
console.log('player play!', player)
},
// 暫停回呼
onPlayerPause(player) {
console.log('player pause!', player)
},
// 視頻播完回呼
onPlayerEnded(player) {
console.log('player ended!', player)
},
// DOM元素上的readyState更改導致播放停止
onPlayerLoadeddata(player) {
console.log('player Loadeddata!', player)
},
// 已開始播放回呼
onPlayerWaiting(player) {
console.log('player Waiting!', player)
},
// 當播放器在當前播放位置下載資料時觸發
onPlayerPlaying(player) {
console.log('player Playing!', player)
},
// 當前播放位置發生變化時觸發
onPlayerTimeupdate(player) {
// console.log('player Timeupdate!', player.currentTime())
},
// 媒體的readyState為HAVE_FUTURE_DATA或更高
onPlayerCanplay(player) {
console.log('player Canplay!', player)
},
// 媒體的readyState為HAVE_ENOUGH_DATA或更高,這意味著可以在不緩沖的情況下播放整個媒體檔案,
onPlayerCanplaythrough(player) {
console.log('player Canplaythrough!', player)
},
// 播放狀態改變回呼
playerStateChanged(playerCurrentState) {
// console.log('player current update state', playerCurrentState)
},
//將偵聽器系結到組件的就緒狀態,與事件監聽器的不同之處在于,如果ready事件已經發生,它將立即觸發該函式
playerReadied(player) {
var hls = player.tech({ IWillNotUseThisInPlugins: true }).hls
player.tech_.hls.xhr.beforeRequest = function(options) {
return options
}
},
}
};
</script>
<style scoped="scoped" less>
// 這是頁面的基本幾個樣式,可以先不要,自己寫,無非就是畫幾個框框,
// 確定一下布局,我們這里主要關注的是直播視頻區,不寫樣式也無所謂,之間渲染,那就看上面的<!-- 視頻區 -->部分
.select_btn {
float: right;
position: absolute;
right: 10%;
top: 27px;
}
.live {
width: 70%;
height: 800px;
border: 1px solid #bfbfbf;
padding: 10px;
}
/deep/ .live-avatar {
padding: 5px;
overflow: hidden;
display: flex;
border-bottom: 1px solid #bfbfbf;
}
.live /deep/ .video-class {
height: 90%;
border: 1px solid #bfbfbf;
}
.chat {
width: 30%;
height: 800px;
border: 1px solid #bfbfbf;
text-align: center;
line-height: 50;
}
</style>
- 至此,你可以在data里playerOptions—>sources中的src替換下面這個地址,測驗一下組件是否存在問題:
- http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8
解釋一下為什么文章中拉流用到的地址格式是:http://192.168.1.171:17001/live/huahua/index.m3u8,而網上部分文章中格式是:rtmp://58.200.131.2:1935/livetv/cctv1
我們服務器中將直播流錄制成 ts 視頻片段, 然后再把直播流完整錄制成flv視頻檔案,最后客戶端通過http去獲取切好的視頻片段,具體詳見末尾的Nginx直播流媒體搭建連接!
我們要做的是:
圖片來源:https://blog.csdn.net/qq_37306786/article/details/103956190
四、說明
- 對于以上頁面中的 推流/拉流 地址沒有特殊說明,不過不要著急,現在基礎的頁面已經完成了,接下來就是配置,回到我們標題里說的:uniapp(推流)+vue(拉流)+nginx+OBS實作簡單直播,那么現在還有nginx沒有配置,下面請移步 [Nginx使用rtmp搭建流媒體服務器,實作hls直播]會對地址進行說明
- Nginx使用rtmp搭建流媒體服務器,實作hls直播
五、如果這兩篇文章你都看完了,相信你一定能搭建出一個基本的直播平臺!!!
- 有問題請在下方留言,盡量解答!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/289541.html
標籤:其他



