uni app 使用live-pusher录制视频

需求背景

当客户发货或者收货时 需要上传开箱或者封箱视频,直接选择相册视频上传速度太慢,现在随便一个视频都是几百M的,流量费很贵,所以就选择使用 直播推流的方式 实现视频上传。

app开发,推荐使用nvue做直播,比使用vue的优势有:

  1. nvue也可一套代码编译多端。
  2. nvue的cover-view比vue的cover-view更强大,在视频上绘制元素更容易。如果只考虑App端的话,不用cover-view,任意组件都可以覆盖live-pusher组件,因为nvue没有层级问题。
  3. 若需要视频内嵌在swiper里上下滑动(类抖音、映客首页模式),App端只有nvue才能实现 当然nvue相比vue的坏处是css写法受限,如果只开发微信小程序,不考虑App,那么使用vue页面也是一样的。
  • 创建 live-pusher 上下文 livePusherContext 对象
		onReady() {
			// 注意:需要在onReady中 或 onLoad 延时
			this.context = uni.createLivePusherContext('livePusher', this);
			//获取手机信息,并设置高度和宽度
			try {
				const res = uni.getSystemInfoSync();
				this.width = res.windowWidth;
				this.height = res.windowHeight;
			} catch (e) {
				throw Error(e)
			}
		},
  • 获取请求url宽高自适应全屏 注:安卓手机需要主动启动摄像头
		onShow() {
			//开启预览
			uni.getStorage({
				key: 'livepushurl',
				success:(res) =>{
					const { url,id} = res.data
					this.livepushurl= url
					this.id = id
				}
			});
			if(systemInfo.platform == 'android'){
				this.startPreview();
			}
			this.startTime()
		},
  • onHide 处理 当用户切屏出去时 live-pusher会有bug 黑屏等问题,需要进行处理,当前处理3秒以内不保存页面后退。3秒以上进行保存页面后台
onHide() {
			if(!this.showTime){
				if (this.count <= 3) {
					var page = getCurrentPages();
					var prevPage = page[page.length - 2];
					prevPage.$vm.closePusher(this.id);
					uni.navigateBack({
					  delta: 1,
					});
				}else{
					this.stop()
					var page = getCurrentPages();
					var prevPage = page[page.length - 2];
					prevPage.$vm.finishPusher(this.id);
					uni.navigateBack({
					  delta: 1,
					});
				}
			}
		},
  • HTML 代码块  nvue 设置class样式不生效 使用style 行内样式 (width height)
	<view class="content">
		<live-pusher 
			id="livePusher" 
			ref="livePusher" 
			:style="{width: width + 'px',height:height + 'px'}" 
			:url="livepushurl"
			:mode="mode" 
			:muted="false"
			:enable-camera="true" 
			:auto-focus="true" 
			:beauty="beauty" 
			:whiteness="whiteness" 
			aspect="9:16" 
			enable-mic="true"
			device-position="back"
			@statechange="statechange" 
			@netstatus="netstatus" 
			@error="error">
		</live-pusher>
		<view class="timekeeping" style="width: 200rpx;" :style="{ top: iStatusBarHeight + 'px'}">
			<text class="timekeeping-time" style="color: #FFFFFF;">{{time}}</text>
		</view>
		<view class="pusher-handle">
			<view class="pusher-handle-btn" @click="switchCamera">
				<image style="width: 68rpx;height: 68rpx;" src="../../static/images/live-pusher-switch.png" resize="cover"></image>
			</view>
			<view class="pusher-handle-btn pusher-handle-center" @click="showConfirmModal">
				<image style="width: 112rpx;height: 112rpx;"  src="../../static/images/live-pusher-finish.png" resize="cover"></image>
			</view>
			<view class="pusher-handle-btn" @click="canceLlivePusher">
				<image style="width: 68rpx;height: 68rpx;"  src="../../static/images/live-pusher-close.png" resize="cover"></image>
			</view>
		</view>
		<view class="countdown" v-if="showTime">
			<text class="countdown-text">{{count}}</text>
		</view>
	</view>
  • 完成代码
let systemInfo = uni.getSystemInfoSync();
	export default {
		data() {
			return {
				width: '350px',
				height: '1500px',
				mode: 'FHD', //流视频模式,可取值:SD(标清), HD(高清), FHD(超清)
				beauty: 1, //美颜,取值范围 0-9(iOS取值范围为1) ,0 表示关闭
				whiteness: 2, // 美白,取值范围 0-9(iOS取值范围为1) ,0 表示关闭
				context: [],
				livepushurl: '',
				url: '',
				showTime: true,
				confirmContent: '是否确认上传当前录制?',
				cancleContent: '是否确认退出当前录制?',
				showConfirm: false,
				showCancel: false,
				id: null,
				time: '00:00:00',
				iStatusBarHeight: 32,
				count: 0,
			};
		},
		onReady() {
			// 注意:需要在onReady中 或 onLoad 延时
			this.context = uni.createLivePusherContext('livePusher', this);
			//获取手机信息,并设置高度和宽度
			try {
				const res = uni.getSystemInfoSync();
				this.width = res.windowWidth;
				this.height = res.windowHeight;
			} catch (e) {
				throw Error(e)
			}
		},
		onLoad() {
			
		},
		onShow() {
			//开启预览
			uni.getStorage({
				key: 'livepushurl',
				success:(res) =>{
					const { url,id} = res.data
					this.livepushurl= url
					this.id = id
				}
			});
			if(systemInfo.platform == 'android'){
				this.startPreview();
			}
			this.startTime()
		},
		onHide() {
			if(!this.showTime){
				if (this.count <= 3) {
					var page = getCurrentPages();
					var prevPage = page[page.length - 2];
					prevPage.$vm.closePusher(this.id);
					uni.navigateBack({
					  delta: 1,
					});
				}else{
					this.stop()
					var page = getCurrentPages();
					var prevPage = page[page.length - 2];
					prevPage.$vm.finishPusher(this.id);
					uni.navigateBack({
					  delta: 1,
					});
				}
			}
		},
		methods: {
			async geturl() {
				try {
					const res = await getUrl({
						order_id: this.order_id,
						type: this.type
					})
					this.url = res.push.rtmp
					this.id = res.id
					this.startTime()
				} catch (e) {

				}
			},
			startTime() {
				const TIME_COUNT = 5;
				if (!this.timer) {
					this.count = TIME_COUNT;
					this.timer = setInterval(() => {
						if (this.count > 0 && this.count <= TIME_COUNT) {
							this.count--;
						} else {
							this.showTime = false;
							clearInterval(this.timer)
							this.timer = null;
							this.start()
							if(systemInfo.platform == 'ios'){
								this.switchCamera()
							}
							this.timekeeping()
						}
					}, 1000)
				}
			},
			timekeeping() {
				// var count = 0;
				if (!this.timerInter) {
					this.timerInter = setInterval(() => {
						var h = parseInt(this.count / 60 / 60);
						var m = parseInt(this.count / 60) % 60;
						var s = parseInt(this.count ) % 60;
						h = h < 10 ? '0' + h : h;
						m = m < 10 ? '0' + m : m;
						s = s < 10 ? '0' + s : s;
						this.time = h + ':' + m + ':' + s ;
						this.count += 1;
					}, 1000)
				}
			},
			statechange(e) {
				console.log('状态变化事件:' + JSON.stringify(e));
			},
			netstatus(e) {
				console.log('网络状态通知事件:' + JSON.stringify(e));
			},
			error(e) {
				console.log('渲染错误事件:' + JSON.stringify(e));
			},
			start() {
				this.context.start({
					success: a => {
						console.log('开始推流:' + JSON.stringify(a));
					},
					error: err => {
						console.log(err)
					}
				});
			},
			snapshot() {
				this.context.snapshot({
					success: e => {
						console.log('快照:' + JSON.stringify(e));
					}
				});
			},
			resume() {
				this.context.resume({
					success: a => {
						console.log('恢复推流:' + JSON.stringify(a));
					}
				});
			},
			pause() {
				this.context.pause({
					success: a => {
						console.log('暂停推流:' + JSON.stringify(a));
					}
				});
			},
			stop() {
				this.context.stop({
					success: a => {
						console.log('停止推流:' + JSON.stringify(a));
					}
				});
			},
			switchCamera() {
				this.context.switchCamera({
					success: a => {
						console.log('切换前后摄像头:' + JSON.stringify(a));
					}
				});
			},
			startPreview() {
				this.context.startPreview({
					success: a => {
						console.log('开启摄像头预览:' + JSON.stringify(a));
					}
				});
			},
			stopPreview() {
				this.context.stopPreview({
					success: a => {
						console.log('关闭摄像头预览:' + JSON.stringify(a));
					}
				});
			},
			showConfirmModal() {
				if (this.count <= 3) {
					uni.showToast({
						title: '上传视频不能低于3秒',
						icon: "none",
						duration: 2000,
					});
					return
				}
				uni.showModal({
				    title: '提示',
				    content: '是否确认上传当前录制?',
				    success: (res)=> {
							if (res.confirm) {
								clearInterval(this.timerInter);
								uni.showLoading({
									title: '提交中'
								})
								setTimeout(()=>{
									uni.hideLoading()
									this.stop()
									var page = getCurrentPages();
									var prevPage = page[page.length - 2];
									prevPage.$vm.finishPusher(this.id);
									uni.navigateBack({
									  delta: 1,
									});
								},2000)
							} else if (res.cancel) {
									console.log('用户点击取消');
							}
				    }
				});
				// this.showConfirm = true
			},
			canceLlivePusher(){
				uni.showModal({
				    title: '提示',
				    content: '是否确认退出当前录制?',
				    success:  (res)=> {
							if (res.confirm) {
								this.stop()
								var page = getCurrentPages();
								var prevPage = page[page.length - 2];
								prevPage.$vm.closePusher(this.id);
								uni.navigateBack({
								  delta: 1,
								});
							} else if (res.cancel) {
									console.log('用户点击取消');
							}
						},
				})
			}
		}
	};
  • 结尾

参数说明、回调方法可参考 文档

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
你好!要使用uniapplive-pusher组件录制视频,你需要按照以下步骤进行操作: 1. 在uniapp项目中的页面中引入live-pusher组件。可以在需要的页面的`<template>`标签中,添加如下代码: ```html <live-pusher id="live-pusher" url="{{pusherUrl}}" mode="{{mode}}" muted="{{muted}}" beauty="{{beauty}}" enable-camera="{{enableCamera}}" bindstatechange="pusherStateChange" bindnetstatus="pusherNetStatus"></live-pusher> ``` 2. 在相应的页面的`<script>`标签中,定义相关参数和方法。例如: ```javascript export default { data() { return { pusherUrl: '', // 推流地址 mode: 'RTC', muted: false, beauty: 6, enableCamera: true } }, methods: { pusherStateChange(e) { // 推流状态变化时的回调函数 console.log('推流状态变化:', e) }, pusherNetStatus(e) { // 推流网络状态变化时的回调函数 console.log('推流网络状态变化:', e) }, startPusher() { // 开始推流 const pusherContext = uni.createLivePusherContext('live-pusher', this) pusherContext.start() }, stopPusher() { // 停止推流 const pusherContext = uni.createLivePusherContext('live-pusher', this) pusherContext.stop() } } } ``` 3. 在页面中添加按钮或其他触发事件的元素,调用对应的方法。例如: ```html <button @tap="startPusher">开始录制</button> <button @tap="stopPusher">停止录制</button> ``` 这样就可以通过uniapplive-pusher组件来录制视频了。你可以根据自己的需求,调整相关参数和方法,以实现更多功能。希望能帮到你!如果还有其他问题,请随时提问。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值