flv.js 报错断开重连,手动调节音量、控制全屏

npm i flv.js --save
<template>
  <div class="container">
    <!-- 正常播放 -->
    <video class="player" muted v-show="!isError"></video>
    <!-- 播放失败显示图片 -->
    <img src="@/assets/img/video_err.png" v-show="isError" width="100%" height="100%" />
    <!-- 控制栏 -->
    <div class="video-control">
      <!-- 调节音量 -->
      <el-slider v-model="audioNum" style="width:70px;margin-right:15px;" :min="0" :max="100" @input="changeAudio"></el-slider>
      <!-- 控制全屏 -->
      <i class="control-btn fa fa-arrows-alt" v-if="!isFullScreen" @click.stop="fullscreen(true)"></i>
      <i class="control-btn fa fa-compress" v-else @click.stop="fullscreen(false)"></i>
    </div>
  </div>
</template>
 
<script>
import flvjs from 'flv.js/dist/flv.min.js';

export default {
  data() {
    return {
      livePlayer: null,
      isError: false,
      isFullScreen: false,
      audioNum: 0, // 播放音量值
      videoUrl: "http://xxx.flv"
    };
  },
  mounted() {
    // 监听全屏
    document.addEventListener('fullscreenchange', this.changeFullscreen);
    this.createPlayVideo();
  },
  beforeDestroy() {
    document.removeEventListener('fullscreenchange', this.changeFullscreen);
    this.destroyPlayer();
  },
  methods: {
    fullscreen(value) {
      let dom = document.querySelector('.container');
      this.$nextTick(() => {
        if (value) {
          dom.requestFullscreen();
        } else {
          document.exitFullscreen();
        }
      });
    },
    changeFullscreen() {
      this.isFullScreen = !this.isFullScreen;
      let dom = document.querySelector('.container');
      this.$nextTick(() => {
        if (this.isFullScreen) {
          dom.requestFullscreen();
        } else {
          document.exitFullscreen();
        }
      });
    },
    createPlayVideo() {
      this.isError = false;
      let that = this;
      let videoElement = document.querySelector(".player");
      if (flvjs.isSupported() && videoElement) {
        this.livePlayer = flvjs.createPlayer({
          type: 'flv',
          url: this.videoUrl,
          isLive: true,
        });
        this.livePlayer.attachMediaElement(videoElement);
        this.livePlayer.load();
        this.livePlayer.play();
        this.livePlayer.on(flvjs.Events.ERROR, (errorType, errorDetail, errorInfo) => {
          that.isError = true;
          if (that.livePlayer && that.livePlayer != null && errorDetail == "UnrecoverableEarlyEof") {
            that.livePlayer.pause();
            that.livePlayer.unload();
            that.livePlayer.detachMediaElement();
            that.livePlayer.destroy();
            that.livePlayer = null;
            // 视频出错后销毁重建
            that.$nextTick(() => {
              that.createPlayVideo();
            })
          }
        });
      }
    },
    destroyPlayer() {
      if (this.livePlayer && this.livePlayer !== null) {
        try {
          this.livePlayer.pause();
          this.livePlayer.unload();
          this.livePlayer.detachMediaElement();
          this.livePlayer.destroy();
          this.livePlayer = null;
        } catch (err) {
          console.log(err)
        }
      }
    },
    // 改变音量
    changeAudio() {
      setTimeout(() => {
        if (this.livePlayer.volume || this.livePlayer.volume == 0) {
          this.livePlayer.volume = this.audioNum / 100;
          if (this.livePlayer.volume == 0) {
            this.livePlayer.muted = true;
          } else {
            this.livePlayer.muted = false;
          }
        }
      }, 200);
    },
  },
};
</script>
 
<style lang="stylus" scoped>
.container {
  width: 800px;
  height: 450px;
  position: relative;

  .player {
    width: 100%;
    height: 100%;
  }

  .video-control {
    width: 100%;
    height: 30px;
    position: absolute;
    bottom: 0;
    left: 0;
    background: #333333;
    display: flex;
    justify-content: flex-end;
    align-items: center;
    box-sizing: border-box;
    padding: 0 10px;
  }

  .control-btn {
    color: #dbdbdb;
    font-size: 16px;
    cursor: pointer;
    margin-right: 10px;
    cursor: pointer;
  }
}
</style>

<think>我们正在解决flv.js中出现的TypeError: Cannot read properties of undefined (reading 'pause')错误。这个错误通常发生在尝试调用一个未定义对象的方法时。在flv.js的上下文中,这很可能意味着我们试图在播放器对象尚未正确初始化或已经被销毁时调用`pause()`方法。 ### 错误原因分析 1. **播放器对象未初始化**:在调用`player.pause()`之前,播放器实例可能还没有创建成功。 2. **播放器对象已被销毁**:在调用`pause()`方法之前,可能已经调用了`player.destroy()`,导致播放器对象被释放。 3. **异步问题**:可能在播放器初始化完成之前就尝试调用`pause()`方法。 4. **DOM元素问题**:播放器所绑定的DOM元素(如video标签)可能不存在或已被移除。 ### 解决方法 #### 步骤1: 确保播放器已正确初始化 在调用任何播放器方法(如`play()`, `pause()`)之前,必须确保播放器实例已经成功创建。 ```javascript // 创建flv播放器实例 var flvPlayer = flvjs.createPlayer({ type: 'flv', url: 'http://example.com/live.flv' }); flvPlayer.attachMediaElement(videoElement); flvPlayer.load(); // 注意:在load()之后,播放器并不会立即准备好,需要监听事件 flvPlayer.on(flvjs.Events.READY, function() { // 此时播放器已准备好,可以调用pause等方法 flvPlayer.pause(); }); ``` #### 步骤2: 避免在销毁后调用方法 如果已经调用了`destroy()`方法,那么播放器实例将不再可用。因此,在调用`pause()`之前,需要确保播放器没有被销毁。 ```javascript // 销毁播放器 flvPlayer.destroy(); // 之后任何调用都会导致错误 // flvPlayer.pause(); // 这行会抛出错误 // 解决方法:在销毁后,将flvPlayer置为null,并在调用前检查 flvPlayer = null; // 在需要调用pause的地方 if (flvPlayer) { flvPlayer.pause(); } ``` #### 步骤3: 处理异步初始化 如果初始化是异步的(例如,在某个事件回调中创建播放器),那么在其他地方调用播放器方法时,需要确保初始化已经完成。 ```javascript let flvPlayer = null; function initPlayer() { flvPlayer = flvjs.createPlayer({ ... }); flvPlayer.attachMediaElement(videoElement); flvPlayer.load(); flvPlayer.on(flvjs.Events.READY, function() { // 设置一个标志表示播放器已准备好 window.isPlayerReady = true; }); } // 在另一个事件中(比如按钮点击)调用pause function pausePlayer() { if (flvPlayer && window.isPlayerReady) { flvPlayer.pause(); } else { console.log('播放器未准备好'); } } ``` #### 步骤4: 确保DOM元素存在 在初始化播放器时,要确保传入的video元素是存在的。 ```javascript var videoElement = document.getElementById('myVideo'); if (videoElement) { // 初始化播放器 } else { console.error('video元素不存在'); } ``` #### 步骤5: 错误捕获 使用try-catch来捕获可能的错误,避免整个程序崩溃。 ```javascript try { if (flvPlayer) { flvPlayer.pause(); } } catch (e) { console.error('暂停失败:', e); } ``` ### 完整示例代码 ```html <video id="videoElement" controls></video> <button id="pauseBtn">暂停</button> <script src="flv.min.js"></script> <script> var videoElement = document.getElementById('videoElement'); var flvPlayer = null; // 初始化播放器 if (flvjs.isSupported()) { flvPlayer = flvjs.createPlayer({ type: 'flv', url: 'http://example.com/live.flv' }); flvPlayer.attachMediaElement(videoElement); flvPlayer.load(); flvPlayer.on(flvjs.Events.READY, function() { console.log('播放器已准备好'); }); } // 暂停按钮事件 document.getElementById('pauseBtn').addEventListener('click', function() { if (flvPlayer) { try { flvPlayer.pause(); } catch (e) { console.error('暂停失败:', e); } } }); // 在页面卸载时销毁播放器 window.addEventListener('beforeunload', function() { if (flvPlayer) { flvPlayer.destroy(); flvPlayer = null; } }); </script> ``` ### 常见问题总结 1. **播放器未初始化完成就调用方法**:确保在`READY`事件回调中或之后调用方法。 2. **播放器被销毁后调用方法**:在销毁后不要再调用方法,并置为`null`。 3. **video元素不存在或已被移除**:确保DOM元素存在。 ### 注意事项 - 使用最新版本的flv.js,因为旧版本可能存在已知问题。 - 在复杂的单页应用(SPA)中,注意在组件销毁时销毁播放器,并避免在组件未挂载时操作播放器。 通过以上步骤,应该能够解决`TypeError: Cannot read properties of undefined (reading 'pause')`错误。 §§相关问题§§ 1. 如何解决flv.js播放时的卡顿问题? 2. flv.js如何实现直播流的实时播放? 3. 如何优化flv.js的内存使用? 4. flv.js支持哪些格式的视频流?</think>### 解决 flv.js 中 `TypeError: Cannot read properties of undefined (reading 'pause')` 错误 这个错误通常发生在尝试调用未初始化的播放器对象或已被销毁的播放器实例上。以下是系统化的解决方案,按优先级排序: --- #### 1. **检查播放器初始化状态**(最常见原因) 错误原因:在 `flvPlayer` 对象初始化完成前调用了 `.pause()` 解决方法: ```javascript // ✅ 正确做法:确保在 READY 事件后操作 const flvPlayer = flvjs.createPlayer(/* config */); flvPlayer.attachMediaElement(videoElement); flvPlayer.load(); // 关键:等待初始化完成 flvPlayer.on(flvjs.Events.READY, () => { // 此时可安全调用 pause() flvPlayer.pause(); }); // ❌ 错误示例(直接调用) flvPlayer.pause(); // 此时 player 尚未就绪 ``` --- #### 2. **验证 DOM 元素生命周期** 错误原因:Video 元素被提前移除或未挂载 解决方法: ```javascript // 确保 video 元素存在于 DOM 中 const videoElement = document.getElementById('video'); if (!videoElement) { console.error("Video element not found!"); return; } // 在移除元素前销毁播放器 function cleanup() { if (flvPlayer) { flvPlayer.pause(); // 先暂停 flvPlayer.destroy(); // 再销毁 flvPlayer = null; // 清除引用 } videoElement.remove(); } ``` --- #### 3. **处理异步销毁问题** 错误原因:在 `destroy()` 后仍尝试操作播放器 解决方案: ```javascript let flvPlayer = null; // 销毁时置引用 function destroyPlayer() { if (flvPlayer) { flvPlayer.destroy(); flvPlayer = null; // 关键:解除引用 } } // 调用 pause 前检查状态 function safePause() { if (flvPlayer && !flvPlayer._destroyed) { flvPlayer.pause(); } else { console.warn("Player is destroyed or undefined"); } } ``` --- #### 4. **版本兼容性修复** 错误原因:FLV.js 版本存在已知 Bug 解决方法: 1. 升级到最新稳定版: ```bash npm install flv.js@latest ``` 2. 或回退到稳定版本: ```bash npm install flv.js@1.6.2 # 2023年验证稳定的版本 ``` --- #### 5. **防御性编程强化** 添加全局状态保护: ```javascript // 创建播放器包装器 const createSafePlayer = () => { let player = null; let isReady = false; return { init(config) { player = flvjs.createPlayer(config); player.on(flvjs.Events.READY, () => (isReady = true)); return player; }, pause() { if (player && isReady) player.pause(); else console.error("Player not ready"); }, destroy() { if (player) player.destroy(); player = null; isReady = false; } }; }; // 使用示例 const safePlayer = createSafePlayer(); safePlayer.init({ type: "flv", url: "stream.flv" }); safePlayer.pause(); // 自动处理状态 ``` --- ### 错误发生场景模拟与修复 ```javascript // 🚫 错误场景:组件卸载时未正确处理 function VideoComponent() { const [player, setPlayer] = useState(null); useEffect(() => { const p = flvjs.createPlayer(/*...*/); setPlayer(p); return () => { // ❌ 危险:可能在其他地方调用 pause() p.destroy(); }; }, []); // 修复:使用 ref 跟踪状态 const isMounted = useRef(true); useEffect(() => { return () => { isMounted.current = false; player?.destroy(); // 安全销毁 }; }, []); const handlePause = () => { if (isMounted.current && player) { player.pause(); // ✅ 安全操作 } }; } ``` --- ### 关键注意事项 1. **事件监听顺序**:确保 `load()` 在 `attachMediaElement()` 之后调用 2. **内存泄漏预防**:在 SPA 应用中用 `beforeunload` 事件销毁播放器: ```javascript window.addEventListener('beforeunload', () => { flvPlayer?.destroy(); }); ``` 3. **错误监控**:添加全局错误捕获 ```javascript flvPlayer.on(flvjs.Events.ERROR, (errType, errDetail) => { console.error(`FLV Error: ${errType} - ${errDetail}`); }); ``` 通过以上方法可彻底解决此错误,核心要点是:**确保操作前播放器已完成初始化且未被销毁**。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值