IOS H5页面中 HLS视频无法正常播放,使用hls.插件

news/2024/11/16 9:21:59/

IOS H5页面中 HLS视频无法正常播放,使用hls.插件

HLS.js依靠 HTML5 视频和 MediaSource Extensions 进行播放。

所有 iPhone 浏览器 (iOS) 都没有可用的 MediaSourceExtension,因此Hls.js将不起作用。如果您在 iPhone 上检查 Hls.isSupported() ,您会看到该函数返回 false

  if (Hls.isSupported()) {var hls = new Hls();hls.loadSource(videoSrc);hls.attachMedia(video);} else if (video.canPlayType('application/vnd.apple.mpegurl')) {video.src = videoSrc;}

iOS 可以使用普通的 <video><source></video> HTML,因为 Safari 具有原生 HLS 支持。初始化 Hls.js <video> 将阻止本机 HLS 功能根本无法工作。

Hls.isSupported return true

但这个解决方案对我不起作用,因为Hls.isSupported 总是返回 true。我做了以下调整以使其正常工作:

React:

import Hls from "hls.js";
import { forwardRef, useEffect, useImperativeHandle, useRef } from "react";interface PlayerProps {src?: string;poster: string;onPlay(): void;onPlayFailed(): void;
}export const Player = forwardRef<{}, PlayerProps>(({ src, poster, onPlay, onPlayFailed }, ref) => {const videoRef = useRef<HTMLVideoElement | null>(null);const hlsRef = useRef<Hls | null>(null);useEffect(() => {if (!src || !videoRef.current) return;const supportHLS = Boolean(videoRef.current.canPlayType("application/vnd.apple.mpegurl"));if (supportHLS) {videoRef.current.src = src;videoRef.current.play().then(onPlay).catch(onPlayFailed);} else {hlsRef.current = new Hls();const hls = hlsRef.current;hls.on(Hls.Events.MEDIA_ATTACHED, function () {videoRef.current!.play().then(onPlay).catch(onPlayFailed);});hls.loadSource(src);hls.attachMedia(videoRef.current);return () => {hls.destroy();};}}, [src]);useImperativeHandle(ref, () => videoRef.current!, []);return (<video className="w-full h-full object-cover" playsInline ref={videoRef} poster={poster}><source src={src} type="application/x-mpegURL"></source></video>);
});

Vue:

然后,你可以在 Vue 组件中这样使用它:

<template>  <video  class="w-full h-full object-cover"  playsinline  :poster="poster"  @play="onPlay"  @error="onPlayFailed"  ref="videoElement"  >  <source :src="src" type="application/x-mpegURL"></source>  </video>  
</template>  <script>  
import Hls from 'hls.js';  export default {  props: {  src: {  type: String,  default: ''  },  poster: {  type: String,  required: true  }  },  data() {  return {  hlsInstance: null  };  },  mounted() {  this.initializePlayer();  },  beforeDestroy() {  if (this.hlsInstance) {  this.hlsInstance.destroy();  this.hlsInstance = null;  }  },  methods: {  initializePlayer() {  if (!this.src || !this.$refs.videoElement) return;  const supportsHLS = this.$refs.videoElement.canPlayType('application/vnd.apple.mpegurl');  if (supportsHLS) {  this.$refs.videoElement.src = this.src;  this.$refs.videoElement.play().then(this.onPlay).catch(this.onPlayFailed);  } else {  this.hlsInstance = new Hls();  const hls = this.hlsInstance;  hls.on(Hls.Events.MEDIA_ATTACHED, () => {  this.$refs.videoElement.play().then(this.onPlay).catch(this.onPlayFailed);  });  hls.loadSource(this.src);  hls.attachMedia(this.$refs.videoElement);  }  },  onPlay() {  this.$emit('onPlay');  },  onPlayFailed() {  this.$emit('onPlayFailed');  }  },  watch: {  src() {  this.initializePlayer();  }  }  
};  
</script>  <style scoped>  
/* Add your styles here */  
</style>

在这个 Vue 组件中,我们使用了 Vue 的生命周期钩子 mounted 来初始化播放器,并在 beforeDestroy 钩子中销毁 hls.js 实例以避免内存泄漏。data 对象用来存储 hls.js 的实例。methods 包含了初始化播放器的方法以及处理播放和播放失败的方法。

此外,我们使用 watch 选项来监听 src 属性的变化,如果它变化了,我们重新初始化播放器。

最后,我们通过 $refs 访问到 DOM 元素,这和 React 中的 useRef 类似。我们还通过 $emit 触发自定义事件,以便父组件可以监听这些事件。

注意:在模板中,我们使用 :src="src":poster="poster" 来绑定属性,这和 React 中的属性绑定类似。

确保在父组件中监听 onPlayonPlayFailed 事件,就像这样:

<template>  <Player :src="videoSrc" :poster="videoPoster" @onPlay="handlePlay" @onPlayFailed="handlePlayFailed"></Player>  
</template>  <script>  
import Player from './Player.vue';  export default {  components: {  Player  },  data() {  return {  videoSrc: 'your-video-source-url',  videoPoster: 'your-poster-image-url'  };  },  methods: {  handlePlay() {  // 处理播放事件  },  handlePlayFailed() {  // 处理播放失败事件  }  }  
};  
</script>

画面为初始页面,视频进度会走,有声音

但使用之后,发现项目中的hls视频加载成功,可以播放,但是播放只有声音,画面为初始的画面,调查打断点之后,发现解决方案

<template><div class="hls-video-player"><videoclass="videoElement"ref="videoElement"autoplaymutedpreload="true"playsinline="true" webkit-playsinline="true"@loadedmetadata="onLoadedMetadata"controls><source :src="hlsUrl" type="application/x-mpegURL"/></video></div>
</template><script>
import Hls from 'hls.js'
export default {name: 'HlsVideoPlayer',props: {hlsUrl: {type: String,required: true}},data () {return {hlsInstance: null}},mounted () {this.initializePlayer()},beforeDestroy () {if (this.hlsInstance) {this.hlsInstance.destroy()this.hlsInstance = null}},methods: {onLoadedMetadata () {console.log('Video metadata loaded')},initializePlayer () {if (!this.hlsUrl || !this.$refs.videoElement) returnconst supportsHLS = this.$refs.videoElement.canPlayType('application/vnd.apple.mpegurl')console.log(Hls.isSupported(), supportsHLS, 'hls.isSupported', 'supportsHLS')// if (supportsHLS) {//   this.$refs.videoElement.src = this.hlsUrl//   this.$refs.videoElement.play().then(this.onPlay).catch(this.onPlayFailed)// } else {//   this.hlsInstance = new Hls()//   const hls = this.hlsInstance//   hls.on(Hls.Events.MEDIA_ATTACHED, () => {//     this.$refs.videoElement.play().then(this.onPlay).catch(this.onPlayFailed)//   })//   hls.loadSource(this.hlsUrl)//   hls.attachMedia(this.$refs.videoElement)// }if (Hls.isSupported()) {// 如果支持 hls.js(MediaSource Extensions)this.hlsInstance = new Hls()const hls = this.hlsInstancehls.on(Hls.Events.MEDIA_ATTACHED, () => {this.$refs.videoElement.play().then(this.onPlay).catch(this.onPlayFailed)})hls.loadSource(this.hlsUrl)hls.attachMedia(this.$refs.videoElement)} else if (supportsHLS) {// 如果支持原生播放// video.src = url// // 自动播放// video.addEventListener('canplay', function () {//   video.play()// })this.$refs.videoElement.src = this.hlsUrlthis.$refs.videoElement.play().then(this.onPlay).catch(this.onPlayFailed)}},onPlay () {console.log('onPlay')// this.$emit('onPlay')},onPlayFailed () {console.log('onPlayFailed')// this.$emit('onPlayFailed')}},watch: {hlsUrl () {this.initializePlayer()}}
}
</script><style scoped>
.hls-video-player {width: 100%;max-width: 600px; /* 或其他你需要的宽度 */margin: 0 auto;display: flex;margin: 0 auto;justify-content: center;align-items: center;
}
.videoElement{width: 100%;
}
</style>

http://www.ppmy.cn/news/1423104.html

相关文章

LeetCode-热题100:230. 二叉搜索树中第K小的元素

题目描述 给定一个二叉搜索树的根节点 root &#xff0c;和一个整数 k &#xff0c;请你设计一个算法查找其中第 k 个最小元素&#xff08;从 1 开始计数&#xff09;。 示例 1&#xff1a; 输入&#xff1a; root [3,1,4,null,2], k 1 输出&#xff1a; 1 示例 2&#…

Android 性能优化(七):APK安装包体积优化

包体积优化重要性 移动 App 特别关注投放转化率指标&#xff0c;而 App 包体积是影响用户新增的重要因素&#xff0c;而 App 的包体积又是影响投放转化率的重要因素。 Google 2016 年公布的研究报告显示&#xff0c;包体积每上升 6MB 就会带来下载转化率降低 1%&#xff0c; …

Java双列集合

Map集合 Java Map集合是一种用于存储键值对的数据结构&#xff0c;它提供了从键到值的映射。其特点和常用操作如下&#xff1a; 唯一性&#xff1a;Map中的键&#xff08;key&#xff09;必须是唯一的&#xff0c;这意味着不能有两个相同的键存在于同一个Map集合中。这是为了…

Android 应用分配的内存大小是多少

Android应用给定的内存大小可以因设备而异&#xff0c;主要受设备的硬件配置和操作系统的限制。不同的设备&#xff0c;尤其是有着不同RAM大小的设备&#xff0c;可能会为应用分配不同的最大内存数量。此外&#xff0c;同一个设备上&#xff0c;不同版本的Android操作系统也可能…

k8s中修复mongodb启动失败

背景 同事反馈 dev环境的yapi不能登录&#xff0c;看了一下是同事两年前用helm搭建的。单副本使用。 排查发现是后端数据库mongodb数据库挂掉。 rootdev-k8s-master03:~# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mo…

Unity让地图素材遮挡人物

点击编辑/项目设置/图形&#xff0c;透明度排序模式设置自定义轴&#xff0c;透明度排序轴Y设置为1其他为0。 此时人物和地图素材的图层排序相等&#xff0c;当人物的高度大于地图素材时&#xff0c;人物则被遮挡。

如何清除Magento Cache

本周有一个客户&#xff0c;购买Hostease的虚拟主机&#xff0c;询问我们的在线客服&#xff0c;如何清除Magento的Cache。我们为用户提供教程&#xff0c;用户很快完成了设置。在此&#xff0c;我们分享这个操作教程&#xff0c;希望可以对您有帮助。 缓存是存储以供以后使用的…

Pandas数据分析学习笔记

前言 开刷Pandas数据分析&#xff0c;看起来很好理解&#xff0c;不过没做笔记没敲代码心里总是不安稳&#xff0c;所以复现下课程代码并演示其中遇到的问题&#xff0c;顺便水一水笔记好了 参考资料&#xff1a; 课程视频链接&#xff1a;Pandas数据分析从入门到实战 数据…