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>

<think>首先,用户的问题是关于在UniApp中集成和使用live-pusher组件进行视频录制。他们要求提供教程。 从系统级指令中,我需要: - 所有行内数学表达式使用$...$格式(但用户的问题不涉及数学,所以可能不需要)。 - 独立公式使用$$...$$格式(同样,可能不适用)。 - LaTeX语法正确(不适用)。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾添加引用标识,如[^1]。 用户可见层的要求: - 回答结构清晰,逐步解决问题。 - 保证回答真实可靠。 参考站内引用: - 引用[1]:提到了媒体组件,包括live-pusher- 引用[2]:是关于在UniApp使用自定义相机拍照的代码示例。 用户的问题是基于引用[1]中的live-pusher组件,所以我的回答应该聚焦于此。 我的回答结构: 1. **介绍live-pusher组件**:解释它是什么,用于什么。 2. **集成步骤**:如何在UniApp项目中添加和使用live-pusher。 3. **代码示例**:提供一个简单的示例代码。 4. **配置和属性**:解释关键属性和事件。 5. **常见问题和注意事项**:解决可能遇到的问题。 6. **生成相关问题**:在最后添加相关问题。 确保引用正确: - 引用[1]提到live-pusher用于实时音视频录制。 - 引用[2]是关于camera组件的示例,但live-pusher类似,我可以参考其结构。 步骤: - **步骤1:创建页面**:添加一个页面来使用live-pusher- **步骤2:添加组件**:在模板中使用<live-pusher>标签。 - **步骤3:配置属性**:如url、mode等。 - **步骤4:控制录制**:使用事件和方法如start、stop。 - **步骤5:处理数据**:获取录制的视频数据。 代码示例: - 基于引用[2]的样式,但针对live-pusher- 使用Vue语法,因为UniApp基于Vue。 注意事项: - live-pusher需要在小程序平台上使用,如微信小程序。 - 需要配置权限等。 生成相关问题: - 在最后,添加3-5个相关问题,如优化方法、问题解决等。 完整回答: - 用中文。 - 结构清晰:分步骤。 - 添加引用标识:在引用参考的地方添加[^1]。 - 结束时添加相关问题。</think>### UniApp集成live-pusher组件实现视频录制教程 在UniApp中,`live-pusher`组件用于实时音视频录制(即直播推流),支持在小程序平台(如微信小程序)上捕获摄像头视频流并推送到指定服务器[^1]。下面我将逐步指导你如何集成和使用组件,确保代码结构清晰、可运行。本教程基于UniApp官方文档和常见实践,避免不必要的复杂性。 #### 步骤1: 创建新页面并添加live-pusher组件 首先,在UniApp项目中创建一个新页面(如`live-pusher.vue`),用于放置视频录制功能。在模板中添加`<live-pusher>`标签,并配置基本属性: - `url`: 推流服务器地址(必填,需从直播服务商获取)。 - `mode`: 视频方向(可选,如`SD`或`HD`)。 - `autopush`: 是否自动推流(建议设为`false`,手动控制)。 ```html <!-- pages/live-pusher/live-pusher.vue --> <template> <view> <!-- 视频预览区域 --> <live-pusher ref="pusher" :url="pushUrl" mode="SD" :autopush="false" @statechange="onStateChange" @error="onError" style="width: 100%; height: 400rpx;" ></live-pusher> <!-- 控制按钮 --> <view class="controls"> <button @tap="startPush">开始录制</button> <button @tap="stopPush">停止录制</button> </view> <!-- 预览录制结果 --> <view v-if="videoPath" class="preview"> <video :src="videoPath" controls style="width: 100%; height: 300rpx;"></video> </view> </view> </template> ``` #### 步骤2: 设置数据和事件处理 在脚本部分,定义状态变量和方法: - `pushUrl`: 推流地址(需替换为你的服务器URL)。 - `videoPath`: 存储录制后的视频路径。 - 使用`ref`获取组件实例,调用`start`和`stop`方法控制录制。 - 处理状态变化和错误事件,确保稳定性。 ```javascript <script> export default { data() { return { pushUrl: 'rtmp://your-stream-server-url/live/streamkey', // 替换为实际推流地址 videoPath: '', // 存储录制后的视频路径 }; }, methods: { // 开始录制 startPush() { const pusher = this.$refs.pusher; if (pusher) { pusher.start(); // 启动推流 uni.showToast({ title: '录制开始', icon: 'none' }); } }, // 停止录制 stopPush() { const pusher = this.$refs.pusher; if (pusher) { pusher.stop(); // 停止推流 uni.showToast({ title: '录制结束', icon: 'none' }); // 模拟获取视频路径(实际需从服务器回调中获取) this.videoPath = 'https://example.com/recorded-video.mp4'; // 替换为实际路径 } }, // 状态变化事件 onStateChange(e) { console.log('状态变化:', e.detail); if (e.detail.code === 1004) { // 推流成功代码 uni.showModal({ title: '提示', content: '推流已连接' }); } }, // 错误处理 onError(e) { console.error('推流错误:', e.detail); uni.showModal({ title: '错误', content: `录制失败: ${e.detail.errMsg}` }); }, }, }; </script> ``` #### 步骤3: 配置页面样式和权限 添加基本样式,确保布局合理: ```html <style scoped> .controls { margin-top: 20rpx; display: flex; justify-content: space-around; } .preview { margin-top: 30rpx; border: 1rpx solid #eee; padding: 10rpx; } </style> ``` #### 步骤4: 配置项目权限(重要) 在`manifest.json`中添加小程序权限,否则组件无法工作: ```json { "mp-weixin": { "appid": "your-weixin-appid", "permission": { "scope.camera": { "desc": "需要摄像头权限" }, "scope.record": { "desc": "需要麦克风权限" } } } } ``` #### 步骤5: 运行和测试 1. **编译运行**:在HBuilderX中,选择微信小程序平台编译,扫描二维码在真机上测试(模拟器可能不支持摄像头)。 2. **测试流程**: - 点击“开始录制”按钮,摄像头启动并推流。 - 停止录制后,预览区域显示视频(实际应用中需通过服务器回调获取URL)。 3. **注意事项**: - **推流地址**:必须从直播服务商(如腾讯云直播)获取有效的RTMP URL[^1]。 - **平台限制**:`live-pusher`仅支持小程序平台,不支持H5或App- **错误处理**:常见错误包括权限未授权或URL无效,需在`onError`中处理。 - **性能优化**:在高分辨率下可能卡顿,建议`mode`设为`SD`。 #### 常见问题解决 - **权限问题**:如果无法启动摄像头,检查小程序设置中的权限授权。 - **推流失败**:确保URL格式正确(如`rtmp://domain/app/stream`)。 - **视频预览**:录制后的视频需从服务器下载,本示例使用模拟路径;实际集成时,需结合后端API存储视频。 通过以上步骤,你可以在UniApp中快速实现视频录制功能。`live-pusher`组件简化了实时流处理,适用于直播、在线教育等场景[^1]。如果有更多需求,参考UniApp官方文档或服务商API。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张大娃笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值