> 技术文档 > uniapp实现H5、APP、微信小程序播放.m3u8监控视频_uniapp 播放m3u8

uniapp实现H5、APP、微信小程序播放.m3u8监控视频_uniapp 播放m3u8

       

目录

1.APP播放.m3u8监控视频

2.H5播放.m3u8监控视频

3.微信小程序播放.m3u8监控视频


       最近在写一个uniapp实现h5、app、微信小程序兼容三端的播放监控视频功能,我原本以为一套代码多处运行,但事实并非如此,h5可以运行,微信小程序不一定可以运行,APP也是如此。上网查阅很多资料,最终3端效果实现成功。

1.APP播放.m3u8监控视频

APP对原生支持比较好,可以直接使用uniapp官网的video组件,本人亲自试过正常播放。

video地址:uni-app官网

代码实现如下:

   

代码还是比较简单的,将videoUrl替换成自己的.m3u8格式Url即可。

2.H5播放.m3u8监控视频

       这里一开始我也以为直接使用上面的代码就可以,但是uniapp运行起来发现根本播放不出来,虽然 HTML5 视频播放器支持多种视频格式,但并不是所有的浏览器都支持 .m3u8 格式的视频流。确保您使用的浏览器支持 HLS。我上网查阅资料最终效果实现成功!

实现代码:

export default { data() { return { videoUrl: \'\', // H5 相关状态 player: null, visibilityChange: null, hidden: null, } }, mounted() { // 动态加载video.js CDN资源 this.loadScript(\'https://vjs.zencdn.net/7.21.2/video.min.js\', () => { this.loadStyle(\'https://vjs.zencdn.net/7.21.2/video-js.min.css\'); // 设置页面可见性API的兼容性处理 this.setupVisibilityAPI(); // 等待资源加载完成 setTimeout(() => { this.setupVideoPlayer(); }, 300); }); },beforeDestroy() { // 组件销毁时移除事件监听 document.removeEventListener(this.visibilityChange, this.handleVisibilityChange); // 销毁播放器 if (this.player) { this.player.dispose(); this.player = null; }}, methods: { loadScript(src, callback) { const script = document.createElement(\'script\'); script.src = src; script.onload = callback; document.body.appendChild(script); }, loadStyle(href) { const link = document.createElement(\'link\'); link.href = href; link.rel = \'stylesheet\'; document.head.appendChild(link); }, setupVisibilityAPI() { // 设置页面可见性API的兼容性处理 if (typeof document.hidden !== \"undefined\") { this.hidden = \"hidden\"; this.visibilityChange = \"visibilitychange\"; } else if (typeof document.msHidden !== \"undefined\") { this.hidden = \"msHidden\"; this.visibilityChange = \"msvisibilitychange\"; } else if (typeof document.webkitHidden !== \"undefined\") { this.hidden = \"webkitHidden\"; this.visibilityChange = \"webkitvisibilitychange\"; } // 添加事件监听 document.addEventListener(this.visibilityChange, this.handleVisibilityChange.bind(this), false); }, handleVisibilityChange() { if (!this.player) return; if (document[this.hidden]) { // 页面不可见时暂停播放 this.player.pause(); } else { // 页面重新可见时恢复播放 this.player.play().catch(e => { console.log(\'自动播放失败:\', e); }); } }, setupVideoPlayer() { if (!window.videojs) { console.error(\'video.js未加载成功\'); return; } let video = document.createElement(\'video\'); video.id = \'video\'; video.className = \'video-js vjs-default-skin\'; video.preload = \"auto\"; video.setAttribute(\'playsinline\', true); video.setAttribute(\'webkit-playsinline\', true); video.setAttribute(\'x5-video-player-type\', \'h5\'); let source = document.createElement(\'source\'); source.src = this.videoUrl; video.appendChild(source); this.$refs.videos.appendChild(video); this.player = window.videojs( \'video\', { autoDisable: true, preload: \'none\', language: \'zh-CN\', fluid: true, muted: false, aspectRatio: \'16:9\', controls: true, autoplay: false, loop: true, controlBar: { volumePanel: { inline: true }, timeDivider: true, durationDisplay: true, progressControl: true, remainingTimeDisplay: true, fullscreenToggle: true, pictureInPictureToggle: false, } }, function() { this.on(\'error\', function(err) { console.log(\"请求数据时遇到错误\", err); }); this.on(\'stalled\', function(stalled) { console.log(\"网速失速\", stalled); }); } ); } }}#app1 { width: 100vw; height: 95vh; background: #000; display: flex; justify-content: center; align-items: center; } /* 视频播放器主体 */ .video-js { width: 90%; max-width: 1200px; height: auto; aspect-ratio: 16/9; border-radius: 8px; overflow: hidden; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);margin-top: -200px; } /* 控制栏整体样式 */ .video-js .vjs-control-bar { background: rgba(20, 20, 20, 0.8); height: 3.5em; padding: 0 10px; } /* 按钮样式 */ .video-js .vjs-control { width: 2.5em; height: 2.5em; margin: 0 2px; color: #fff; transition: all 0.3s; } .video-js .vjs-control:hover { color: #00a1d6; transform: scale(1.1); } /* 进度条样式 */ .video-js .vjs-progress-control { position: absolute; top: -1em; width: 100%; height: 0.5em; } .video-js .vjs-progress-holder { height: 100%; background: rgba(255, 255, 255, 0.2); } .video-js .vjs-play-progress { background: #00a1d6; } /* 音量控制 */ .video-js .vjs-volume-panel { order: 4; } /* 时间显示 */ .video-js .vjs-time-control { min-width: 3em; padding: 0 5px; font-size: 1.1em; } /* 全屏按钮 */ .video-js .vjs-fullscreen-control { order: 5; } /* 加载动画 */ .video-js .vjs-loading-spinner { border-color: rgba(0, 161, 214, 0.7); } /* 大播放按钮 */ .video-js .vjs-big-play-button { width: 2.5em; height: 2.5em; line-height: 2.5em; border-radius: 50%; border: none; background: rgba(0, 161, 214, 0.8); top: 50%; left: 50%; transform: translate(-50%, -50%); transition: all 0.3s; } .video-js .vjs-big-play-button:hover { background: rgba(0, 161, 214, 1); transform: translate(-50%, -50%) scale(1.1); } /* 响应式调整 */ @media (max-width: 768px) { .video-js { width: 100%; border-radius: 0; } .video-js .vjs-control-bar { height: 2.5em; } }

本人亲自实践,电脑浏览器,与手机浏览器访问,都可以成功。

3.微信小程序播放.m3u8监控视频

     在这里我是卡的最久的,因为直接使用video组件播放,在微信开发者工具中可以正常播放,但是在真机调试,小程序查看就是一直黑屏转圈圈,有时候可以播放成功,但是几秒中过后就是又是一直转圈圈,最后就会报错。有大佬会的可以在下方留言,最后采用web-view组件,实现播放,直接页面跳转。但是使用web-view跳转监控视频,又会有另一个问题,本地测试正常,但是上线,线上微信小程序就会出现提示不支持打开该页面。一定得在微信开发者后台校验文件才可以打开,因为这是微信小程序的强制规则,这个校验文件必须放在对应服务器才可以成功,假如我是调整萤石云的监控,那按照微信的说法,就要将校验文件放入萤石云服务器的后台,这样显然不现实,所以这里有两种方案,第一使用代理,第二自己在写一个页面部署到自己的服务器,通过web-view跳转到自己写的页面中,将监控视频url一并传入页面,即可完成播放。

实现代码:

 

注意,这里跳转必须是https,在这里viderUrl是视频监控的链接,cameraTitle是标题,比如你播放的是那个监控,可加可不加,我这边是加上了。

跳转playeer.html页面代码实现:
其实下面的代码保存,videoUrl替换即可播放,我只不过写了两套,你们可以选择一套使用。

   监控播放器  body { margin: 0; padding: 270px 0px 0px 0px; font-family: Arial, sans-serif; background: #000; } } /* 容器样式 */ #app1 { background: #000; display: flex; justify-content: center; align-items: center; } /* 视频播放器主体 */ .video-js { width: 100%; max-width: 1200px; height: auto; aspect-ratio: 16/9; border-radius: 8px; overflow: hidden; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); }  
function getQueryParam(name) { const query = window.location.search.substring(1); const vars = query.split(\'&\'); for (let i = 0; i { this.loadStyle(\'https://vjs.zencdn.net/7.21.2/video-js.min.css\'); // 设置页面可见性API的兼容性处理 this.setupVisibilityAPI(); // 等待资源加载完成 setTimeout(() => { this.setupVideoPlayer(); }, 300); }); }, loadScript: function(src, callback) { const script = document.createElement(\'script\'); script.src = src; script.onload = callback; document.body.appendChild(script); }, loadStyle: function(href) { const link = document.createElement(\'link\'); link.href = href; link.rel = \'stylesheet\'; document.head.appendChild(link); }, setupVisibilityAPI: function() { // 设置页面可见性API的兼容性处理 if (typeof document.hidden !== \"undefined\") { this.hidden = \"hidden\"; this.visibilityChange = \"visibilitychange\"; } else if (typeof document.msHidden !== \"undefined\") { this.hidden = \"msHidden\"; this.visibilityChange = \"msvisibilitychange\"; } else if (typeof document.webkitHidden !== \"undefined\") { this.hidden = \"webkitHidden\"; this.visibilityChange = \"webkitvisibilitychange\"; } // 添加事件监听 document.addEventListener(this.visibilityChange, this.handleVisibilityChange.bind(this), false); }, handleVisibilityChange: function() { if (!this.player) return; if (document[this.hidden]) { // 页面不可见时暂停播放 this.player.pause(); } else { // 页面重新可见时恢复播放 this.player.play().catch(e => { console.log(\'自动播放失败:\', e); }); } }, setupVideoPlayer: function() { if (!window.videojs) { console.error(\'video.js未加载成功\'); return; } let video = document.createElement(\'video\'); video.id = \'video\'; video.className = \'video-js vjs-default-skin\'; video.preload = \"auto\"; video.setAttribute(\'playsinline\', true); video.setAttribute(\'webkit-playsinline\', true); video.setAttribute(\'x5-video-player-type\', \'h5\'); let source = document.createElement(\'source\'); source.src = videoUrl ; video.appendChild(source); document.getElementById(\'videos\').appendChild(video); this.player = window.videojs( \'video\', { autoDisable: true, preload: \'none\', language: \'zh-CN\', fluid: true, muted: false, aspectRatio: \'16:9\', controls: true, autoplay: false, loop: true, controlBar: { volumePanel: { inline: true }, timeDivider: true, durationDisplay: true, progressControl: true, remainingTimeDisplay: true, fullscreenToggle: true, pictureInPictureToggle: false, } }, function() { this.on(\'error\', function(err) { console.log(\"请求数据时遇到错误\", err); }); this.on(\'stalled\', function(stalled) { console.log(\"网速失速\", stalled); }); } ); } }; // 初始化应用 app.init(); });

本人亲自测试,3端都可以播放,有问题可以在下方评论留言。