In my work, I need wechat mini program to record 15s videos and upload them. Some users feedback that they can’t record videos, so I would like to summarize my experience here

The picture below is a manifestation of the problem. When users of some models release the shooting, they are reminded that the shooting is not completed, so the video cannot be uploaded.

The problem above is use

wx.chooseVideo({
  sourceType: ['camera'].maxDuration: 60.camera: 'back'.success(res) {
    console.log(res.tempFilePath)
  }
})
Copy the code

Wx. ChooseVideo is an official interface provided by wechat, which does not require user authorization and can be directly called to return the video address after shooting. However, the above problems may occur when some models use this interface, resulting in failure to complete shooting.

Solution: Use wx.createcameraconText () to define your own recording method.

Points to note:

  • To use this method, you need to authorize camera and microphone permissions, and handle unauthorized situations
  • The startRecord and stopRecord methods pay attention to the call timing. They cannot be called continuously, and need to deal with the user’s continuous click behavior

The code is as follows:

index.wxml

<view class="video">
    <video wx:if="{{video}}" src="{{video}}" style="width: 100%; display: block;"></video>
    <button type="primary" bindtap="checkSetting">Recording a Video Demo</button>
</view>
Copy the code

index.js

const app = getApp()
Page({
	data: {
		video: null
	},
	onShow() {
		/** * Every time you enter the page to check whether there is a local video recording address, if there is, clear */
		if (wx.getStorageSync('auth_video')) {
			this.setData({
				video: wx.getStorageSync('auth_video')
			})
			wx.removeStorageSync('auth_video')}},/** * Since the video page uses the camera label, the camera permission must be obtained when using this label, otherwise the picture cannot be captured * so every time you enter the page, check whether the user has authorized the camera permission */
	checkSetting() {
		wx.getSetting({
			success: (res) = > {
				console.log(res)
				let authSetting = res.authSetting
				/ * * * authSetting. HasOwnProperty (' scope. The camera ') = = true indicating the user is not authorized for the first time * authSetting [' scope. Camera] = = false shows that users are not allowed to authorize * You need to prompt the user to enable authorization */ only when both conditions are met
				if (authSetting.hasOwnProperty('scope.camera') && !authSetting['scope.camera']) {
					wx.showModal({
						content: 'Detected that you are not currently enabled with camera permissions and will not be able to use camera functions'.confirmText: 'Go open'.success: (res) = > {
							if (res.confirm) {
								console.log('User hits OK')
								wx.openSetting({
									success(res) {
										console.log(res.authSetting)
									}
								});
							} else if (res.cancel) {
								console.log('User hit Cancel')}}})}else {
					wx.navigateTo({
						url: ".. /camera/camera"})}}})Copy the code

camera.wxml

<view class="video">
    <view wx:if="{{! video_url}}" style="position: relative;">
        <cover-view class="time-container" wx:if="{{isRecording}}">
            <cover-view class="time">Recording {{time}}s</cover-view>
        </cover-view>
        <cover-view class="change-btn" wx:else bindtap="changePosition">
            <cover-view>Click toggle {{devicePosition=='front'? 'Back ':' front '}} camera</cover-view>
        </cover-view>
        <camera binderror="getError" device-position="{{devicePosition}}" style="width: 100vw; height: 100vh;"></camera>
        <cover-view class="btn-container">
            <cover-view class="btn-item" bindtap="back" style="background-color: #ddd;">return</cover-view>
            <cover-view class="btn-item" bindtap="record">{{isRecording? 'End recording ':' Click record '}}</cover-view>
        </cover-view>
    </view>
    <view wx:else style="position: fixed; width: 100vw; height: 100vh;">
        <video src="{{video_url}}" style="width: 100%; height: 100%;" autoplay="{{true}}" loop="{{true}}" controls="{{false}}"></video>
        <cover-view class="btn-container">
            <cover-view class="btn-item" bindtap="recordAgain">re-recording</cover-view>
            <cover-view class="btn-item" bindtap="sureVideo">Confirm the choice</cover-view>
        </cover-view>
    </view>
</view>
Copy the code

camera.wxss


.time-container{
	position: absolute;
	width: 100%;
	left:0;
	top: 0;
	height: 240rpx;
	display: flex;
	justify-content: center;
	align-items: center;
	background-color: rgba(0.0.0.0.4);
	z-index: 100;
}
.change-btn{
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	display: flex;
	align-items: center;
	height: 100rpx;
	color: #fff;
	font-size: 30rpx;
	padding: 0 50rpx;
	border-radius: 50rpx;
	z-index: 100;
	background-color: rgba(0.0.0.0.5);
}
.time{
	font-size: 30rpx;
	color: red;
	padding: 0 20rpx;
	margin-top: 30rpx;
}
.btn-container{
	position: absolute;
	width: 100%;
	padding: 0 80rpx;
	box-sizing: border-box;
	bottom: 160rpx;
	display: flex;
	justify-content: space-between;
	z-index: 100;
}
.btn-item{
	padding: 30rpx 0;
	border-radius: 45rpx;
	background-color: #FF6685;
	color: #fff;
	font-size: 32rpx;
	text-align: center;
	width: 240rpx;
}
Copy the code

camera.js

const app = getApp()
Page({
	data: {
		ctx: null.isRecording: false.video_url: null.time: 0.min_time:5.// Minimum duration for recording a video
		timer: null.devicePosition: "back".// Camera orientation
		isStart:false.// Record the state when the user clicks start recording
		isStop:false // Record the user click to end recording status
	},
	onLoad(options) {
		const ctx = wx.createCameraContext()
		this.setData({
			ctx
		})
	},
	onUnload() {
		clearInterval(this.data.timer)
	},
	// Switch the front/rear camera
	changePosition() {
		this.setData({
			devicePosition: this.data.devicePosition == 'back' ? 'front' : 'back'})},checkSetting() {
		// Define a state isStart to record the user clicking to start recording, and restore the state after the startRecord interface request is successful
		if(this.data.isStart){
			return
		}
		this.data.isStart = true
		/** * The wx.createcameracontext ().startRecord() method needs to obtain the user's microphone permission, otherwise it cannot be called and video cannot be recorded * so each time you enter the page, check whether the user has the microphone permission */
		wx.getSetting({
			success: (res) = > {
				console.log(res)
				let authSetting = res.authSetting
				/** * The same principle as checking camera permissions */
				if (authSetting.hasOwnProperty('scope.record') && !authSetting['scope.record']) {
					wx.showModal({
						content: 'Detected that you do not currently have microphone permission enabled and will not be able to record video'.confirmText: 'Go open'.success: (res) = > {
							if (res.confirm) {
								console.log('User hits OK')
								wx.openSetting({
									success(res) {
										console.log(res.authSetting)
									}
								});
							} else if (res.cancel) {
								console.log('User hit Cancel')
								// this.back()}}})}else {
					this.startRecord()
				}
			}
		})
	},
	// This method is triggered when the user clicks "Do not allow authorization" when entering the page for authorization. This method will be triggered every time after the user enters the page for authorization
	getError() {
		console.log("User is not authorized to use the camera.")
		this.back()
	},
	// Click start recording/end recording
	record() {
		if (this.data.isRecording) {
			console.log("End of recording video")
			this.stopRecord()
		} else {
			console.log("Start recording video")
			this.checkSetting()
		}
	},
	// Start recording
	startRecord() {
		this.data.ctx.startRecord({
			timeoutCallback: (res) = > {
				/** * wechat official limit * Use this method to record a video maximum of 30 seconds, after 30 seconds automatically stop recording * stop recording timing */
				console.log("Automatically stop recording after 30 seconds.")
				console.log(res)
				clearInterval(this.data.timer)
				this.setData({
					video_url: res.tempVideoPath,
					isRecording: false})},success: (res) = > {
				console.log(res)
				this.timing()
				this.setData({
					isRecording: true
				})
				this.data.isStart = false
			},
			fail:(err) = >{
				console.log(err)
				this.data.isStart = false}})},// End recording
	stopRecord() {
		// The stopRecord method cannot be called consecutively, otherwise recording cannot be stopped
		// Define a state isStop to record the user click to end the recording behavior, and restore the state after the stopRecord interface request is successful
		if(this.data.isStop){
			return
		}
		if(this.data.time<this.data.min_time){
			wx.showToast({
				title:"Video duration less than"+this.data.min_time+"Seconds".icon:"none"
			})
			return
		}
		wx.showLoading({
			title:"One moment, please."
		})
		this.data.isStop = true
		this.data.ctx.stopRecord({
			//compressed: false, // Whether to compress the finished video
			success: (res) = > {
				console.log(res)
				clearInterval(this.data.timer)
				this.setData({
					video_url: res.tempVideoPath,
					isRecording: false
				})
				this.data.isStop = false
				wx.hideLoading()
			},
			fail(err){
				console.log(err)
				this.data.isStop = false
				wx.hideLoading()
			}
		})
	},
	/ / timing
	timing() {
		let time = 0
		// Reset the time on the page to 0 before each time
		this.setData({
			time
		})
		let self = this
		let timer = setInterval(function() {
			time++
			console.log(time)
			self.setData({
				time
			})
		}, 1000)
		this.setData({
			timer
		})
	},
	// Re-record
	recordAgain() {
		this.setData({
			video_url: null})},// return to the previous page
	back() {
		wx.navigateBack()
	},
	// Confirm the selection
	sureVideo() {
		/** * Save the address of the recorded video locally, return to the previous page in the onShow to check whether the address of the recorded video exists */
		wx.setStorageSync('auth_video'.this.data.video_url)
		wx.navigateBack()
	}
})
Copy the code

Effect: