uniapp nvue使用live-pusher组件以及腾讯云实现直播推拉流


前言

uniapp nvue使用live-pusher组件以及腾讯云实现直播推流,使用video组件实现直播拉流观看,不使用第三方原生sdk,完整示例已兼容ios和安卓


效果预览

即将开始预览

一、推流使用live-pusher组件

<live-pusher :beauty="beauty" :style="{
       
       width: width + 'px',height:height + 'px'}" id="livePusher" :url="url" mode="FHD"></live-pusher>

二、拉流使用video组件

<video id="myVideo" v-if="mark===1" @error="error" :src="url" style="width: 750rpx;" :style="{
       
       height : height + 'px'}" :autoplay="true" :controls="false"></video>

三、前端推流核心代码

this.context = uni.createLivePusherContext('livePusher', this);
var secretdate = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'; //这是需要在腾讯云获取直播的密钥
let date = Date.parse(new Date()) / 1000 + 21600;
//这是需要在腾讯云配置推流的地址,这里采用的是flv的视频格式
this.url = 'rtmp://xxxxxx.livepush.myqcloud.com/live/' + this.live_id + '?txSecret=' + md5(secretdate + this.live_id + date.toString(16).toUpperCase()) + '&txTime=' + date.toString(16).toUpperCase();

四、推流完整示例(包含美颜/相机切换/结束直播反馈效果)

<template>
	<div>
		<view>

			<view class="arrow-boxs">
				<image class="user-img" src="../../static/images/logo.png"></image>
				<view class="jieshao">
					<text class="id">账号:{
    
    {
    
    accountNum}} </text>
				</view>
			</view>
			<view @click="showClose=true" class="arrow-box">
				<image class="tui-img" src="../../static/images/tuichu.png"></image>
			</view>

			<live-pusher :beauty="beauty" :style="{width: width + 'px',height:height + 'px'}" id="livePusher" :url="url" mode="FHD"></live-pusher>

			<!-- 这是功能按钮 -->
			<view :style="{width: width + 'px'}" class="but">
				<!-- <view class="commodyti-box" :style="{width: width*0.3333 + 'px'}">
					<view @click="openMark(0)" class="meiyanbut" >
						<image class="but-img" src="../../static/img/zhiboshop2.png" style="height: 40rpx;"></image>
					</view>
				</view> -->
				<view class="commodyti-box" :style="{width: width*0.3333 + 'px'}">
					<view @click="openmeiyan" class="meiyanbut">
						<image class="but-img" v-if="beauty==0" src="../../static/images/meiyan.png"></image>
						<image class="but-img" v-else src="../../static/images/selecr-my.png"></image>
					</view>
				</view>
				<view class="commodyti-box" :style="{width: width*0.3333 + 'px'}">
					<view @click="switchCamera" class="meiyanbut">
						<image class="but-img" v-if="!Camera" src="../../static/images/qiehuan.png"></image>
						<image class="but-img" v-else src="../../static/images/select-chang.png"></image>
					</view>
				</view>
			</view>
			<view class="model" v-if="showClose">
				<view class="model-pup" @click="showClose=false"></view>
				<view class="model-body">
					<view class="model-cont">
						<text>您确定要结束当前直播吗?</text>
					</view>
					<view class="model-bot">
						<view class="model-btn" @click="showClose=false">
							<text>取消</text>
						</view>
						<view class="model-btn1" @click="navback()">
							<text style="color: white;">确定</text>
						</view>
					</view>
				</view>
			</view>
		</view>

	</div>
</template>

<script>
	import md5 from '@/js_sdk/md5.js';
	var app = getApp();
	var liveApi = require('../../utils/live.js');
	export default {
    
    
		data() {
    
    
			return {
    
    
				type: "",
				scrollTop: 0,
				Camera: true,
				width: '',
				height: '',
				accountNum: '',
				scrollTops: 0,
				url: '',
				live_id: '', //这是推流id,用于生成推流地址,拉流能用到
				context: null,
				markact: true,
				arr: [],
				livegood: [],
				beauty: 9, //美颜等级
				showClose: false,
				toback: false
			};
		},
		onLoad(option) {
    
    
			let res = uni.getSystemInfoSync()
			this.width = res.windowWidth;
			this.height = res.windowHeight;
			let userInfo = uni.getStorageSync('userInfo');
			this.accountNum = userInfo.nickName;
			this.live_id = option.liveBroadcastRecordId;
		},

		onReady() {
    
    
			uni.showLoading({
    
    
				title: '准备中'
			})
			this.context = uni.createLivePusherContext('livePusher', this);
			let that = this;
			setTimeout(() => {
    
    
				that.startLive(1);
				uni.hideLoading();
			}, 1500)
		},
		onUnload: function() {
    
    

		},
		onHide: function() {
    
    

		},
		onShow() {
    
    
			this.context = uni.createLivePusherContext('livePusher', this);
			var secretdate = 'xxxxxxxxxxxxxxxxxxxx'; //这是需要在腾讯云获取直播的密钥
			let date = Date.parse(new Date()) / 1000 + 21600;
			//这是需要在腾讯云配置推流的地址,这里采用的是flv的视频格式
			this.url = 'rtmp://xxxxxxx.livepush.myqcloud.com/live/' + this.live_id + '?txSecret=' + md5(secretdate + this.live_id + date.toString(16).toUpperCase()) + '&txTime=' + date.toString(16).toUpperCase();
			setTimeout(() => {
    
    
				this.startLive(0);
			}, 1000)
			app._post(liveApi.startLiveBroadcast, {
    
    
					liveBroadcastRecordId: this.live_id,
					appUserId: app.globalData.userInfo.appUserId
				},
				function(e) {
    
    
					console.log(e);
				}
			)
		},
		onBackPress(e) {
    
    
			if (this.toback) {
    
    
				return false;
			}
			// 这里可以自定义返回逻辑,比如下面跳转其他页面
			this.showClose = true;
			// return true 表示禁止默认返回
			return true
		},
		methods: {
    
    
			navback() {
    
    
				var that = this;
				app._post(liveApi.endLiveBroadcast, {
    
    
						liveBroadcastRecordId: this.live_id,
						appUserId: app.globalData.userInfo.appUserId
					},
					function(e) {
    
    
						console.log(e);
						that.toback = true;
						uni.navigateBack()
					}
				)
			},
			zengMark(type) {
    
    
				this.$refs.popupr.close();
				this.type = type;
				this.$refs.popupr.open()
			},
			openmeiyan() {
    
    
				// this.$refs.popup.open()
				if (this.beauty == 0) {
    
    
					this.beauty = 9
				} else {
    
    
					this.beauty = 0
				}
			},
			startLive(type) {
    
    
				let self = this;
				this.context.start({
    
    
					success: a => {
    
    
						// console.log("livePusher.start:" + JSON.stringify(a));
						self.markact = false;
					},
					fail: a => {
    
    }
				});
			},
			stopLive() {
    
    
				this.context.stop({
    
    
					success: a => {
    
    }
				});
			},
			switchCamera() {
    
    
				this.context.switchCamera({
    
    
					success: (a) => {
    
    
						this.Camera = !this.Camera;
						console.log("livePusher.switchCamera:" + JSON.stringify(a));
					}
				});
			}
		}
	}
</script>

<style>
	.shop-list-list {
    
    
		position: relative;
		margin-top: 25rpx;
		padding-top: 10rpx;
		padding-bottom: 10rpx;
		align-items: flex-start;
		flex-direction: row;
		border-bottom-width: 1rpx;
		border-style: solid;
		border-color: #F7F7F7;
	}

	.shop-list-but-box {
    
    
		position: absolute;
		bottom: 26px;
		right: 10px;
		align-items: center;
		justify-content: flex-end;
		flex-direction: row;
	}

	.shop-list-but {
    
    
		color: white;
		border-radius: 20px;
		font-size: 13px;
		background-color: rgba(255, 65, 0, 1);
		padding: 10rpx 20rpx;
		margin-right: 10px;
	}


	.shop-list-img {
    
    
		margin-right: 20rpx;
		margin-left: 20rpx;
		width: 150rpx;
		height: 150rpx;
	}

	.shop-list-title {
    
    
		font-size: 16px;
		margin-bottom: 10rpx;
		color: rgba(51, 51, 51, 1);
		/* color: #333333; */
	}

	.shop-list-price {
    
    
		font-size: 16px;
		color: #FF4100;
		line-height: 30px;
	}

	.scroll-Ys {
    
    
		background-color: #ffffff;
		height: 650rpx;
		width: 100%;
	}

	.scroll-Yss {
    
    
		background-color: #ffffff;
		height: 800rpx;
		width: 100%;
	}

	.shop-list-box {
    
    
		position: relative;
		background-color: white;
		width: 100%;
		height: 380px;
		border-radius: 10rpx;
	}

	.mark-title {
    
    
		height: 80rpx;
		font-size: 20px;
		align-items: flex-start;
		justify-content: center;
	}

	.mark-tui {
    
    
		/* position:relative; */
		height: 20rpx;
		font-size: 20px;
		line-height: 100rpx;
		right: 0;
		border-bottom-width: 1rpx;
		border-style: solid;
		border-color: #F7F7F7;
	}

	.fanhui {
    
    
		width: 30rpx;
		height: 30rpx;
		margin-top: 40rpx;
		text-align: center;
		margin-right: 25rpx;
	}

	.zengjia {
    
    
		width: 40rpx;
		height: 40rpx;
		margin-left: 30rpx;
		margin-top: 34rpx;
		margin-bottom: 10px;
	}

	.add-shop {
    
    
		font-size: 16px;
		color: #333333;
		left: 20rpx;
		z-index: 10;
		margin-left: 5px;
	}

	.meiyanbut {
    
    

		height: 80rpx;
		width: 80rpx;
		flex-direction: row;
		align-items: center;
		justify-content: center;
		border-radius: 50%;
		background-color: rgba(0, 0, 0, 0.2);
		text-align: center;

	}

	.but-img {
    
    
		width: 38rpx;
		height: 34rpx;
	}

	.id {
    
    
		font-size: 14px;
		color: white;
	}

	.text-box {
    
    
		font-size: 12px;
		color: white;
	}

	.mark-text {
    
    
		color: white;
		font-size: 20px;
	}

	.mark {
    
    
		position: fixed;
		top: 0px;
		background-color: #9FA3A7;
		align-items: center;
		justify-content: center;
		flex-direction: column;
	}

	.but {
    
    
		position: fixed;
		bottom: 0px;
		flex-direction: row;
		align-items: center;
		justify-content: center;
		height: 160rpx;
	}

	.commodyti-box {
    
    
		align-items: center;
		justify-content: center;
	}

	.tui {
    
    
		width: 200px;
		height: 200px;

	}

	.arrow-box {
    
    
		position: fixed;
		top: 80rpx;
		right: 30rpx;
		z-index: 10;
		border-radius: 50%;
		background-color: rgba(0, 0, 0, 0.2);
		height: 80rpx;
		width: 80rpx;
		align-items: center;
		justify-content: center;
	}

	.tui-img {
    
    
		width: 36rpx;
		height: 36rpx;

	}

	.arrow-boxs {
    
    
		padding: 1%;
		align-items: center;
		flex-direction: row;
		position: fixed;
		padding-right: 20rpx;
		top: 80rpx;
		left: 30rpx;
		z-index: 10;
		border-radius: 30px;
		background-color: rgba(0, 0, 0, 0.2);
		/* background-color: #FFFFFF; */
	}

	.user-img {
    
    
		margin-right: 5px;
		width: 35px;
		height: 35px;
		border-radius: 50%;
	}

	.jieshao {
    
    
		flex-direction: column;
	}

	.jiesu {
    
    
		padding: 10px 20px 10px 20px;
		color: white;
		font-size: 16px;
	}

	.arrow {
    
    
		width: 15px;
		height: 15px;
	}

	.model {
    
    
		position: fixed;
		top: 0;
		left: 0;
		bottom: 0;
		right: 0;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		z-index: 10;
	}

	.model-pup {
    
    
		background-color: rgba(0, 0, 0, 0.5);
		position: absolute;
		top: 0;
		right: 0;
		left: 0;
		bottom: 0;
		z-index: 100;
	}

	.model-body {
    
    
		width: 550rpx;
		padding: 30rpx;
		background-color: white;
		border-radius: 20rpx;
	}

	.model-cont {
    
    
		font-size: 35rpx;
		color: #333333;

	}

	.model-bot {
    
    
		flex-direction: row;
		align-items: center;
		justify-content: space-between;
		margin-top: 30rpx;
	}

	.model-btn {
    
    
		width: 200rpx;
		height: 80rpx;
		flex-direction: row;
		align-items: center;
		justify-content: center;
		background-color: #F8F8F8;
		border-width: 1rpx;
		border-color: #E6E6E6;
		border-style: solid;
		border-radius: 40rpx;
	}

	.model-btn1 {
    
    
		width: 200rpx;
		height: 80rpx;
		flex-direction: row;
		align-items: center;
		justify-content: center;
		background-color: #0462E8;
		border-width: 1rpx;
		border-color: #E6E6E6;
		border-style: solid;
		border-radius: 40rpx;
	}
</style>


五. 拉流完整示例(包含回放暂停/播放/预告效果)

<template>
	<view>
		<view class="head-pop">
			<view class="arrow-boxs">
				<image class="user-img" :src="headImg"></image>
				<view class="jieshao">
					<text class="id">{
    
    {
    
    policeName}} </text>
				</view>
			</view>
			<view @click="toShare()" class="share-box">
				<image class="share-img" src="../../static/images/toshare.png"></image>
			</view>
		</view>
		<view @click="navback()" class="arrow-box">
			<image class="tui-img" src="../../static/images/tuichu.png"></image>
		</view>
		<text v-if="mark===2" class="text" :style="{width : width + 'px'}">直播即将开始</text>
		<text v-if="mark===3" class="text" :style="{width : width + 'px'}">直播已结束</text>
		<view style="height: 200rpx;margin: 40rpx;" v-if="mark!==1">
			<view class="btn" @click="navback()">
				<text style="color: white;">返回</text>
			</view>
		</view>
		<video id="myVideo" v-if="mark===1" @error="error" :src="url" style="width: 750rpx;" :style="{height : height + 'px'}"
		 :autoplay="true" :controls="false"></video>
		<view class="ym-popup" @click="toPause" v-if="showPop">
			<view class="ym-popup-bg" v-if="playVideo">
				<image src="../../static/images/play.png" style="width: 120rpx;height: 120rpx;" mode=""></image>
			</view>
		</view>
	</view>
</template>
<script>
	var app = getApp();
	var liveApi = require('../../utils/live.js');
	export default {
    
    
		data() {
    
    
			return {
    
    
				height: '',
				width: '',
				mark: 1,
				bottom: 10,
				liveBroadcastRecordId: 0,
				url: '',
				policeName: '用户昵称',
				headImg: '../../static/images/logo.png',
				showPop: false,
				playVideo: false,
			}
		},
		onLoad(option) {
    
    
			let params = JSON.parse(decodeURIComponent(option.params));
			console.log(params);
			this.policeName = params.policeName;
			this.headImg = params.headImg;
			this.liveBroadcastRecordId = params.liveBroadcastRecordId;
			if (params.type === 1) {
    
    
				this.mark = 1;
				//这是需要在腾讯云配置拉流的地址,加上
				this.url = 'http://xxxx.xxx.xxx/live/' + params.liveBroadcastRecordId + '.flv';
				console.log(this.url);
				//进入观看回调
				app._post(liveApi.watchLiveBroadcast, {
    
    
						liveBroadcastRecordId: params.liveBroadcastRecordId,
						appUserId: app.globalData.userInfo.appUserId
					},
					function(e) {
    
    
						console.log(e);

					}
				)
			} else if (params.type === 2) {
    
    
				this.mark = 2;
			} else {
    
    
				this.showPop = true;
				if (params.livePlaybackUrl) {
    
    
					this.mark = 1;
					this.url = params.livePlaybackUrl;
				} else {
    
    
					this.mark = 3;
				}
			}
			let res = uni.getSystemInfoSync()
			this.height = res.windowHeight;
			this.width = res.windowWidth;
		},
		methods: {
    
    
			error(e) {
    
    
				if (e) {
    
    
					this.mark = 3;
				}
			},
			navback() {
    
    
				uni.navigateBack();
			},
			toPause() {
    
    
				this.videoContext = uni.createVideoContext('myVideo');
				if (this.playVideo) {
    
    
					this.videoContext.play();
					this.playVideo = false;
				} else {
    
    
					this.videoContext.pause();
					this.playVideo = true;
				}
			},
			toShare(){
    
    
				console.log('share')
			}
		}
	}
</script>

<style>
	.mark {
    
    
		align-items: center;
		justify-content: center;
		flex-direction: column;
		background-color: #FFFFFF;
	}

	.mark-text {
    
    
		padding-right: 75px;
		font-size: 20px;
		color: #333333;
	}

	.mark-texts {
    
    
		line-height: 20px;
		line-height: 10px;
		font-size: 14px;
		height: 50px;
		width: 300px;
		color: white;
		background-color: #D4237A;
	}

	.text {
    
    
		text-align: center;
		padding-top: 400px;
		padding-bottom: 50px;
	}

	.arrow-box {
    
    
		position: fixed;
		top: 80rpx;
		right: 30rpx;
		z-index: 10;
		border-radius: 50%;
		background-color: rgba(0, 0, 0, 0.2);
		height: 80rpx;
		width: 80rpx;
		align-items: center;
		justify-content: center;
	}

	.tui-img {
    
    
		width: 36rpx;
		height: 36rpx;

	}
	.head-pop{
    
    
		padding: 1%;
		align-items: center;
		flex-direction: row;
		position: fixed;
		padding-right: 20rpx;
		top: 80rpx;
		left: 30rpx;
		z-index: 10;
		border-radius: 30px;
	}
	.arrow-boxs {
    
    
		align-items: center;
		flex-direction: row;
		border-radius: 30px;
		background-color: rgba(0, 0, 0, .2);
		padding-right: 20rpx;
	}

	.user-img {
    
    
		margin-right: 5px;
		width: 35px;
		height: 35px;
		border-radius: 50%;
	}

	.jieshao {
    
    
		flex-direction: column;
	}

	.id {
    
    
		font-size: 14px;
		color: white;
	}

	.btn {
    
    
		/* display: flex; */
		flex-direction: row;
		align-items: center;
		justify-content: center;
		width: 650rpx;
		height: 100rpx;
		background-color: #0462E8;
		border-radius: 50rpx;
	}

	.ym-popup {
    
    
		position: absolute;
		left: 0;
		right: 0;
		bottom: 0;
		top: 0;
	}

	.ym-popup-bg {
    
    
		position: absolute;
		left: 0;
		right: 0;
		bottom: 0;
		top: 0;
		background-color: rgba(0, 0, 0, 0.5);
		flex-direction: row;
		align-items: center;
		justify-content: center;
	}

	.share-box {
    
    
		margin-left: 30rpx;
		border-radius: 50%;
		background-color: rgba(0, 0, 0, 0.2);
		height: 80rpx;
		width: 80rpx;
		align-items: center;
		justify-content: center;
	}

	.share-img {
    
    
		width: 40rpx;
		height: 40rpx;
	}
</style>

猜你喜欢

转载自blog.csdn.net/weixin_38333426/article/details/112878404
今日推荐