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

server/2024/12/23 0:12:21/

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/server/7238.html

相关文章

excel多sheet导出工具类——java

excel多sheet导出工具类 1、多个sheet导出工具类&#xff1a; import org.apache.commons.lang3.StringUtils; import org.apache.poi.hssf.usermodel.*; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.user…

最全!2024腾讯春招Spring Circuit Breaker面试题大全,附详解和技巧,必备收藏!

面对2024年腾讯春季招聘&#xff0c;准备充分的技术面试答案至关重要&#xff0c;尤其是在微服务架构和高可用性设计方面。Spring Circuit Breaker作为维持微服务稳定性和可靠性的关键技术&#xff0c;了解其工作原理和实际应用对于任何希望在当今技术驱动的环境中取得成功的软…

Web3与社会契约:去中心化治理的新模式

在数字化时代&#xff0c;技术不断为我们提供新的可能性&#xff0c;而Web3技术作为一种基于区块链的创新&#xff0c;正在引领着互联网的下一波变革。它不仅改变了我们的经济模式和商业逻辑&#xff0c;还对社会契约和权力结构提出了全新的挑战和思考。本文将深入探讨Web3的基…

解读我国最新网络安全运维与数据处理安全规范:强化数字化时代安全基石

近日&#xff0c;全国网络安全标准化技术委员会秘书处公布了一系列重要的网络安全与数据安全相关技术规范草案&#xff0c;包括《网络安全技术 网络安全运维实施指南》、《网络安全技术 信息系统灾难恢复规范》以及《数据安全技术 政务数据处理安全要求》。这些规范旨在应对当前…

动手写sql 《牛客网80道sql》

第1章&#xff1a;SQL编写基础逻辑和常见问题 基础逻辑 SELECT语句: 选择数据表中的列。FROM语句: 指定查询将要从哪个表中检索数据。WHERE语句: 过滤条件&#xff0c;用于提取满足特定条件的记录。GROUP BY语句: 对结果进行分组。HAVING语句: 对分组后的结果进行条件过滤。O…

【Java EE】Spring核心思想(一)——IOC

文章目录 &#x1f38d;Spring 是什么&#xff1f;&#x1f384;什么是IoC呢&#xff1f;&#x1f338;传统程序开发&#x1f338;传统程序开发的缺陷&#x1f338;如何解决传统程序的缺陷&#xff1f;&#x1f338;控制反转式程序开发&#x1f338;对比总结 &#x1f332;理解…

Github2024-04-15 开源项目周报 Top15

根据Github Trendings的统计,本周(2024-04-15统计)共有15个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目8TypeScript项目5C项目2C++项目2Go项目1Rust项目1JavaScript项目1Shell项目1Git - 快速、可扩展、分布式的版本控制系统 创建周期:5…

mysql 面试题

事务是什么 事务是数据库管理系统&#xff08;DBMS&#xff09;中的一个重要概念&#xff0c;用于管理对数据库进行读写操作的一组相关操作。事务是一个原子性、一致性、隔离性和持久性&#xff08;ACID&#xff09;的工作单元。 具体来说&#xff0c;事务具有以下四个特性&a…