vue2 直播地址播放 兼容浏览器

问题

在vue2项目中使用了xgplayer来进行播放视频,但是只有谷歌浏览器!可以,火狐和edg/360都没有法播放
请添加图片描述

新的插件-Jessibuca

除了谷歌其他浏览器用Jessibuca

项目根目录

├── public/

│ └── jessibuca/ # [关键] Jessibuca 播放器核心文件

│ ├── jessibuca.js # 主程序

│ ├── decoder.js # 解码器 Worker

│ └── decoder.wasm # WASM 解码库 (H.265软解核心)

├── src/

│ └── views/

│ └── index.vue # 播放器页面主逻辑

:https://github.com/bosscheng/jessibuca-vue-demo/tree/pro-vue2这个地址可以下载Jessibuca ,注意 我是在dmeo/public里面找到的这3个文件的,且是放在自己项目public下的。

复制代码
<template>
  <div class="app">
    <h1>直播播放器演示</h1>
    <!-- 使用 xgplayer 容器 (Chrome/Edge 等默认模式) -->
    <div v-if="!useJessibuca" id="mse" class="xg-style"></div>
    <!-- Jessibuca 容器 (Firefox 兼容模式) -->
    <div v-else id="jessibuca-container" class="jessibuca-style"></div>

    <!-- 错误提示遮罩 -->
    <div v-if="errorMessage" class="error-mask">
      <div class="error-content">
        <i class="el-icon-warning" style="font-size: 40px; color: #ffba00; margin-bottom: 10px;"></i>
        <p>{{ errorMessage }}</p>
        <p v-if="useJessibuca" style="font-size: 12px; color: #999; margin-top: 5px;">
          软解码模式 (兼容模式) | <a href="#" @click.prevent="retryJessibuca" style="color: #409EFF">点击重试</a>
        </p>
      </div>
    </div>
  </div>
</template>

<script>
import Player from "xgplayer";
import FlvPlugin from "xgplayer-flv";
import "xgplayer/dist/index.min.css";

export default {
  name: 'App',
  
  data() {
    return {
      player: null,
      jessibucaPlayer: null,
      streamId: '34020000001110000003_51070300001310000002',
      errorMessage: '',
      useJessibuca: false // 替换原有的 isFirefox,避免歧义
    }
  },
  
  mounted() {
    // 策略:仅 Google Chrome 浏览器使用 xgplayer (硬解码),其他所有浏览器使用 Jessibuca (软解码)
    const ua = navigator.userAgent;
    
    // 判断是否为 Google Chrome (排除 Edge, Opera 等也包含 Chrome 关键字的浏览器)
    const isChrome = ua.indexOf("Chrome") > -1 && ua.indexOf("Edg") === -1 && ua.indexOf("OPR") === -1;
    
    // 如果不是 Chrome,就使用 Jessibuca
    this.useJessibuca = !isChrome;
    
    this.$nextTick(() => {
      if (this.useJessibuca) {
        // 非 Chrome 浏览器: 加载 Jessibuca
        this.initJessibuca();
      } else {
        // Chrome: 加载 xgplayer
        this.initPlayer();
      }
    });
  },

  beforeDestroy() {
    if (this.player) {
      this.player.destroy();
      this.player = null;
    }
    if (this.jessibucaPlayer) {
      this.jessibucaPlayer.destroy();
      this.jessibucaPlayer = null;
    }
  },

  methods: {
    retryJessibuca() {
        this.errorMessage = '';
        this.initJessibuca();
    },

    // 初始化 Jessibuca (用于 Firefox H.265 软解)
    initJessibuca() {
      const host = window.location.host;
      const url = `http://${host}/proxy/sms/local/live/34020000001110000003_51070300001310000002.flv?expired=20260212190637`;

      // 使用本地文件加载 Jessibuca (您已下载到 public/jessibuca 目录)
      const localScriptUrl = "/jessibuca/jessibuca.js";
      const localDecoderUrl = "/jessibuca/decoder.js";

      if (!window.Jessibuca) {
        const script = document.createElement('script');
        script.src = localScriptUrl; 
        script.onload = () => {
          this.createJessibuca(url, localDecoderUrl);
        };
        script.onerror = () => {
          this.errorMessage = '加载本地 Jessibuca 播放器失败。请确认 public/jessibuca/jessibuca.js 文件存在。';
        };
        document.body.appendChild(script);
      } else {
        this.createJessibuca(url, localDecoderUrl);
      }
    },

    createJessibuca(url, decoderUrl) {
      if (this.jessibucaPlayer) {
        this.jessibucaPlayer.destroy();
        this.jessibucaPlayer = null;
      }

      try {
        this.jessibucaPlayer = new window.Jessibuca({
          container: document.getElementById('jessibuca-container'),
          videoBuffer: 1, // 增加缓存到 1秒
          isResize: false,
          loadingText: "正在加载 H.265 视频...",
          debug: true,
          useMSE: false, // 强制关闭 MSE,使用软解码
          useWCS: false,
          decoder: decoderUrl, // 引用 decoder.js 本地地址
          forceNoOffscreen: true, // 兼容性设置
          hasAudio: true, // 尝试开启音频
          showBandwidth: true, // 显示网速以便调试
          operateBtns: {
            fullscreen: true,
            screenshot: true,
            play: true,
          },
        });

        this.jessibucaPlayer.on('error', (error) => {
          console.error('Jessibuca error:', error);
          // 忽略 fetchError 如果流还在继续 (有时候是虚假报错)
          if (error === 'fetchError') {
              console.warn('Ignored fetchError, retrying internally...');
              return;
          }
          this.errorMessage = '播放出错: ' + JSON.stringify(error);
        });
        
        this.jessibucaPlayer.on('start', () => {
            console.log('Jessibuca started playing');
            this.errorMessage = '';
        });

        this.jessibucaPlayer.play(url);
      } catch (e) {
        console.error(e);
        this.errorMessage = '初始化 Jessibuca 失败: ' + e.message;
      }
    },

    initPlayer() {
      const host = window.location.host;
      // 使用硬编码的 HTTP-FLV 地址 (走本地代理)
      const url = `http://${host}/proxy/sms/local/live/34020000001110000003_51070300001310000002.flv?expired=20260212190637`;
      
      console.log('Initializing xgplayer with URL:', url);

      if (this.player) {
        this.player.destroy();
        this.player = null;
      }

      this.player = new Player({
        id: 'mse',
        url: url,
        isLive: true,
        autoplay: true,
        autoplayMuted: true, // 自动静音播放,防止浏览器策略阻止
        width: '100%',
        height: '600px',
        volume: 0.6, // 默认音量
        plugins: [FlvPlugin], // 启用 FLV 插件
        flv: {
          retryCount: 3,
          retryDelay: 1000,
          loadTimeout: 10000,
          fetchOptions: {
            mode: "cors",
          },
          // 尝试开启 worker 以提升 H.265 软解性能 (如果支持)
          enableWorker: true,
          enableStashBuffer: false
        },
        // 错误处理
        error: (err) => {
            console.error('xgplayer error:', err);
        }
      });
      
      // 监听错误事件
      this.player.on('error', (err) => {
          console.error('Player Error Event:', err);
          // 捕获 H.265 不支持的错误 (MediaSource error)
          if (err.errorType === 'media' && err.errorCode === 5200) {
              this.errorMessage = '该视频格式 (H.265) 在当前浏览器中不受支持。';
              if (this.player) {
                  this.player.destroy(); // 销毁播放器防止持续报错
                  this.player = null;
              }
          } else {
             this.errorMessage = '播放出错,请检查网络或刷新重试';
          }
      });
    }
  }
}
</script>

<style scoped>
.app {
  padding: 20px;
  max-width: 1200px;
  margin: 0 auto;
  position: relative;
}

.xg-style {
  width: 100%;
  background-color: black;
}

.jessibuca-style {
  width: 100%;
  height: 600px;
  background-color: black;
  position: relative;
}

.error-mask {
  position: absolute;
  top: 100px; /* 调整位置使其在播放器区域内 */
  left: 0;
  right: 0;
  height: 600px;
  background: rgba(0, 0, 0, 0.8);
  display: flex;
  justify-content: center;
  align-items: center;
  color: white;
  z-index: 100;
}

.error-content {
  text-align: center;
}
</style>

实现文档如下

复制代码
# 视频播放器功能实现文档

## 1. 功能概述
本项目实现了在不同浏览器(Chrome、Edge、Firefox 等)下兼容播放 **H.265 (HEVC)** 编码的 HTTP-FLV 直播流。
由于部分浏览器(如 Firefox、Edge)原生不支持或支持不完善 H.265 硬解码,我们采用了 **"双核"策略**:
- **Google Chrome**: 使用 `xgplayer` (硬解码,性能最佳)。
- **其他浏览器 (Firefox / Edge / Opera 等)**: 使用 `Jessibuca` (WASM 软解码,兼容性最佳)。

## 2. 核心文件结构

项目根目录

├── public/

│ └── jessibuca/ # [关键] Jessibuca 播放器核心文件

│ ├── jessibuca.js # 主程序

│ ├── decoder.js # 解码器 Worker

│ └── decoder.wasm # WASM 解码库 (H.265软解核心)

├── src/

│ └── views/

│ └── index.vue # 播放器页面主逻辑

复制代码
## 3. 实现逻辑流程

### 3.1 初始化流程 (Mounted)
1.  **浏览器检测**: 通过 `navigator.userAgent` 精确判断浏览器类型。
    - 判断逻辑:是否包含 "Chrome" 且 **不包含** "Edg" (Edge) 和 "OPR" (Opera)。
2.  **分支处理**:
    - **是 Google Chrome**: 调用 `initPlayer()` (xgplayer)。
    - **是 其他浏览器**: 调用 `initJessibuca()` (Jessibuca)。

### 3.2 Chrome 模式 (xgplayer)
- **依赖库**: `xgplayer`, `xgplayer-flv`。
- **特点**: 利用浏览器原生 MSE (Media Source Extensions) 进行硬解码。
- **配置**: 开启 CORS 模式,自动静音播放。

### 3.3 兼容模式 (Jessibuca)
- **适用对象**: Firefox, Edge, Opera, Safari 等。
- **依赖文件**: `public/jessibuca/*`。
- **原理**:
    1.  动态加载 `jessibuca.js`。
    2.  创建播放器实例,指定 `decoder: '/jessibuca/decoder.js'`。
    3.  设置 `useMSE: false` 强制关闭硬解码,启用 WASM 软解码。
- **注意**: 软解码会消耗更多 CPU 资源,但能确保在不支持 H.265 的浏览器上出画面。

## 4. 常见问题排查

### Q1: 播放器提示 "初始化 Jessibuca 失败"
- **原因**: `public/jessibuca/` 目录下缺少文件,或者服务器无法访问该目录。
- **解决**: 确保 `jessibuca.js`, `decoder.js`, `decoder.wasm` 三个文件都存在且可访问。

### Q2: 画面黑屏但有网速
- **原因**: 可能是音频编码不支持或 CSS 样式冲突。
- **解决**: 代码中已设置 `hasAudio: true` (尝试支持音频);确保容器 `div` 有明确的宽高(如 `height: 600px`)。

### Q3: 跨域错误 (CORS)
- **原因**: 视频流地址不支持跨域。
- **解决**: 代码中使用了本地代理 (`/proxy/...`) 转发请求,确保 `vue.config.js` 中配置了正确的 `proxy` 规则。

## 5. 维护指南
如果将来需要升级播放器:
1.  **xgplayer**: 直接 `npm update xgplayer`。
2.  **Jessibuca**: 需要手动下载新版文件替换 `public/jessibuca/` 下的内容。

此文档是记录,方便下次使用

相关推荐
克喵的水银蛇36 分钟前
Flutter 布局实战:掌握 Row/Column/Flex 弹性布局
前端·javascript·flutter
哆啦A梦158842 分钟前
60 订单页选择收货地址
前端·javascript·vue.js·node.js
Hilaku1 小时前
利用 link rel="prefetch":如何让用户的页面秒开?
前端·javascript·性能优化
youyu-youyu1 小时前
h5 签名 vue
javascript·vue.js·ecmascript
Apifox1 小时前
如何通过抓包工具快速生成 Apifox 接口文档?
前端·后端·测试
没事多睡觉6661 小时前
JavaScript 中 this 指向教程
开发语言·前端·javascript
苏打水com1 小时前
浏览器与HTTP核心考点全解析(字节高频)
前端·http
用户99045017780091 小时前
ruoyi集成camunda-前端篇
前端
Aerelin1 小时前
scrapy的介绍与使用
前端·爬虫·python·scrapy·js