微信公众号流媒体视频处理方案

uniapp yekong

微信公众号外包 项目开发中遇到一例要求页面可以播放流媒体,一开始的视频格式是flv mp4和m3u8格式的,但是开发中遇到了问题,

视频格式选择

mp4格式

在pc上可以播放但是放在手机上就无法播放了,于是和后端沟通后改为使用flv格式。

flv格式

使用flvjs实现了在pc和安卓手机上播放,都没有问题以为没问题了?我真是天真,苹果手机不支持flv。
查询后得到的答案是:

由于依赖Media Source Extensions,目前所有i0S和Android4.4.4以下里的浏览器都不支持,也 就是说目前对于移动端flv.js基本是不能用的。

m3u8格式

和后端沟通改用m3u8格式的,这次应该没问题了吧.
通过使用videojs来渲染播放器,首先ios测试没问题,正常播放视频,安卓正常播放没问题,pc谷歌浏览器播放报错了:报了一个_createClass2 is not defined错误,我是愣没查到是怎么来的,也没找到解决方案。还能不能好好相处了,咋这么多坑呢?

_createClass2 is not defined

最后实在是没办法了采用了一个折中的办法,弄两个播放器,判断终端如果是ios就使用videojs播放器,其他就使用flv.js播放器。

开发环境

uniapp h5

终端判断组件

<template>
	<view class="coverImg">
		<!-- 判断是否是苹果 -->
		<view class="attachments" v-if="platform == 'ios'">
			<videojs :isCover="isCover" v-if="hlsUrl" :src="hlsUrl"></videojs>
		</view>
		<view class="attachments" v-else>
			<flv :isCover="isCover" v-if="flvUrl" :src="flvUrl"></flv>
		</view>
	</view>
</template>

<script>
	import {
		playstart
	} from '@/config/api.js'
	import flv from '@/components/flv.vue'
	import videojs from '@/components/videojs.vue'
	import configs from '@/config/config.js'
	export default {
		components: {
			flv,
			videojs
		},
		data() {
			return {
				configs,
				platform: ''
			}
		},
		props: {
			flvUrl: {
				type: String,
				default () {
					return ''
				}
			},
			isCover: {
				type: Boolean,
				default () {
					return true
				}
			},
			hlsUrl: {
				type: String,
				default () {
					return ''
				}
			},
		},
		mounted() {
			this.platform = uni.getSystemInfoSync().platform
		},
		watch: {},
		methods: {}
	}
</script>
<style scoped lang="scss">
	.attachments {
		width: 100%;
		height: 100%;
		position: relative;
	}

	.coverImg {
		width: 100%;
		height: 100%;
		position: relative;
	}
</style>

flvjs实现

/**
* @Author: 858834013@qq.com
* @Name: flvjs组件
* @Date: 2023年02月09日20:15:28
* @Desc: uniapp使用flvjs播放视频
*/
<template>
	<div class="videoBody" ref="videoElement" id="videoElement">
	</div>
</template>

<script>
	import flvjs from 'flv.js'
	import imgs from '@/static/message/shipinimg.png'
	export default {
		name: "flv",
		components: {
			imgs
		},
		props: {
			src: {
				type: String,
				default () {
					return '';
				}
			},
			isCover: {
				type: Boolean,
				default () {
					return true
				}
			},
		},
		data() {
			return {
				flvPlayer: null,
				isPlay: false,
			}
		},
		watch: {
			src() {
				this.getPlay()
			}
		},
		mounted() {
			this.getPlay()
		},
		methods: {
			getPlay() {
				var that = this;
				console.log(flvjs)
				if (flvjs.isSupported()) {
					let video = document.createElement('video');
					video.id = 'video';
					video.style = 'width: 100%; height: 100%;';
					video.controls = that.isCover ? false : true;
					video.preload = "auto"
					// video.poster = imgs
					video.autoplay = that.isCover ? false : true
					video.muted = that.isCover ? false : true
					video.setAttribute('playsinline', that.isCover ? false : true) //IOS微信浏览器支持小窗内播放
					video.setAttribute("crossOrigin", "anonymous");
					video.setAttribute('webkit-playsinline', true)
					//这个bai属性是ios 10中设置可以让视频在小du窗内播放,也就是不是全zhi屏播放的video标签的一个属性
					video.setAttribute('x5-video-player-type', 'h5') //安卓 声明启用同层H5播放器 可以在video上面加东西
					let source = document.createElement('source');
					source.src = that.src;
					// return
					that.$refs.videoElement.appendChild(video);
					that.flvPlayer = flvjs.createPlayer({
						type: 'flv',
						url: that.src
					})
					that.flvPlayer.attachMediaElement(video)
					that.flvPlayer.load()
					if (!that.isCover) {
						setTimeout(() => {
							that.flvPlayer.play()
						}, 1000)
					}
				}
			},
			play() {
				this.isPlay = true
				this.flvPlayer.play()
			},
			pause() {
				this.isPlay = false
				this.flvPlayer.pause()
			},
		}
	}
</script>

<style lang="scss" scoped>
	.videoBody {
		position: relative;
		z-index: 100;
		width: 100%;
		height: 100%;
	}
</style>

videojs实现

/**
* @Author: 858834013@qq.com
* @Name: videojs组件
* @Date: 2023年02月09日20:15:28
* @Desc: uniapp使用videojs播放视频
*/
<template>
	<div class="video-js" ref="videos" style="width: 100%;height: 100%;">
	</div>
</template>

<script>
	import configs from '@/config/config.js'
	export default {
		data() {
			return {
				configs
			}
		},
		props: {
			src: {
				type: String,
				default () {
					return '';
				}
			},
			isCover: {
				type: Boolean,
				default () {
					return true
				}
			},
		},
		watch: {
			src() {
				this.getPlay()
			}
		},
		mounted() {
			var that = this;
			that.getPlay()
			uni.$on('onShow', function(data) {
				that.getPlay()
			});
		},
		methods: {
			getPlay() {
				var that = this;
				let video = document.createElement('video');
				video.id = 'video';
				video.style = 'width: 100%; height: 100%;';
				video.controls = that.isCover ? false : true;
				video.preload = "auto"
				// video.poster = imgs
				video.autoplay = that.isCover ? false : true
				video.muted = that.isCover ? false : true
				video.setAttribute('playsinline', that.isCover ? false : true) //IOS微信浏览器支持小窗内播放
				video.setAttribute("crossOrigin", "anonymous");
				video.setAttribute('webkit-playsinline', true)
				let source = document.createElement('source');
				source.src = this.src;
				video.appendChild(source);
				// return
				this.$refs.videos.appendChild(video);
				let player = this.$video('video', {
					poster: '', // 视频封面图地址
					playbackRates: [0.7, 1.0, 1.5, 2.0], //播放速度
					autoDisable: true,
					preload: that.isCover ? 'meta' :
					'auto', //auto - 当页面加载后载入整个视频 meta - 当页面加载后只载入元数据 none - 当页面加载后不载入视频
					language: 'zh-CN',
					fluid: true, // 自适应宽高
					muted: that.isCover ? false : true, //  是否静音
					aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
					controls: that.isCover ? false :
					true, //是否拥有控制条 【默认true】,如果设为false ,那么只能通过api进行控制了。也就是说界面上不会出现任何控制按钮
					autoplay: true, //如果true,浏览器准备好时开始回放。 autoplay: "muted", // //自动播放属性,muted:静音播放
					loop: true, // 导致视频一结束就重新开始。 视频播放结束后,是否循环播放
					controlBar: {
						volumePanel: { //声音样式
							inline: false // 不使用水平方式
						},
						timeDivider: true, // 时间分割线
						// durationDisplay: true, // 总时间
						// progressControl: true, // 进度条
						remainingTimeDisplay: true, //当前以播放时间
						fullscreenToggle: true, //全屏按钮
						pictureInPictureToggle: true, //画中画
					}
				}, function() {
					this.on('error', function(err) { //请求数据时遇到错误
						console.log("请求数据时遇到错误", err)
					});
					this.on('stalled', function(stalled) { //网速失速
						console.log("网速失速", stalled)
					});
					this.on('play', function() { //开始播放
						console.log("开始播放")
						player.pause()
						// var rotateBtn = player.controlBar.addChild('button')
						// rotateBtn.addClass('icon_jianji')
						// rotateBtn.on('click', function() {})

					});
					this.on('pause', function() { //暂停
						console.log("暂停")
					});

					// this.on('timeupdate', function(timeupdate) {
					// 	// console.log(timeupdate)
					// })
				});
			},
		}
	}
</script>

<style scoped lang="scss">
	.video-js {
		position: relative;
		width: 100%;
		height: 100%;

		video {
			position: relative;
			width: 100%;
			height: 100%;
		}
	}
</style>

喜欢