VUE 集成H265web.js播放器實現webpack自動化構建

2024年2月6日 22点热度 0人点赞

一、項目說明

1. H265web.js 簡介

H265web.js 是一個用於在 Web 瀏覽器中播放 H.265 視頻的 JavaScript 播放器。它支持在瀏覽器中直接解碼 H.265 編碼的視頻流,提供了高效的視頻播放體驗。在 Element UI 項目中集成 H265web.js 可以讓我們輕松實現 H.265 視頻的播放功能。

H265web.js 開源地址:

https://github.com/numberwolf/h265web.js

文檔地址:

https://github.com/numberwolf/h265web.js?tab=readme-ov-file

目前vue裡集成H265web.js 還有一定的復雜度,本文作以詳細介紹。

2. 準備環境

  • 一個 準備好的 element-ui 項目和開發環境
  • 本文基於VUE2.0

二、項目配置

1. 下載 H265web.js

我們采用直接下載 dist 的方式,而不是使用 npm 安裝,據說npm對wasm不太友好(我沒有實證)。
到官網找到最新版本的 releasae或者接下載整個項目:


後面需要使用的是
dist/ 目錄的內容。
本文參考了官方目錄 example_vue2/ 裡的實現代碼,主要加入了對 npm 自動化構建的支持。

2. 在vue項目裡引入 H265web

首先在 vue 項目裡新建一個 template 目錄,按如下方式組織文件:


即把 H265web.js 的dist目錄,拷到 template/libs/h265web下。

index.html 是構建vue項目時使用的模板文件,內容如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Your App Title</title>
  <script type="text/javascript" src="static/js/missile.js"></script>
  <script src="static/js/h265webjs-v20221106.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>

使用npm命令構建時,默認情況會在目錄的 public/ 目錄自動生成 index.html 文件。但是我們需要在 index.html 裡引入 h265web.js 的文件,構建後再去添加引用就有些繁瑣,所以自定義了此模板頁方便構建。

3. 設置 vue.config.js

本步驟的目的是在 npm 構建時,自動將 h265 的庫文件拷貝到構建的目標目錄 。
這裡重點是使用了 copy-webpack-plugin 和 html-webpack-plugin 兩個構建的插件。

vue.config.js 設置

// 這一句定義在 module.exports 之前
const CopyWebpackPlugin = require('copy-webpack-plugin')
// 定義模板頁位置
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 在 module.exports ,加入
module.exports = {
  configureWebpack: {
    // provide the app's title in webpack's name field, so that
    // it can be accessed in index.html to inject the correct title.
    name: name,
    resolve: {
      alias: {
        '@': resolve('src')
      }
    },
    plugins: [
      new HtmlWebpackPlugin({
        template: 'template/index.html'
      }),
      new CopyWebpackPlugin([
        {
          from: 'template/libs/h265web',
          to: './static/js/'
        }
      ])
    ]
  }
}

這樣在執行 npm run devnpm run build:prod時, h265web的庫文件會拷到目標的 static/js 目錄下。

執行構建命令的效果如下:

三、代碼引用

1. 參照官方demo , 創建 executor.js

路徑可按自己需要放置,我這裡放到了src/utils下:


內容:

const PRESET_CONFIG = {
  player: 'glplayer',
  width: 960,
  height: 540,
  token: 'base64:QXV0aG9yOmNoYW5neWFubG9uZ3xudW1iZXJ3b2xmLEdpdGh1YjpodHRwczovL2dpdGh1Yi5jb20vbnVtYmVyd29sZixFbWFpbDpwb3JzY2hlZ3QyM0Bmb3htYWlsLmNvbSxRUTo1MzEzNjU4NzIsSG9tZVBhZ2U6aHR0cDovL3h2aWRlby52aWRlbyxEaXNjb3JkOm51bWJlcndvbGYjODY5NCx3ZWNoYXI6bnVtYmVyd29sZjExLEJlaWppbmcsV29ya0luOkJhaWR1',
  extInfo: {
    moovStartFlag: true,
    coreProbePart: 0.1,
    ignoreAudio: 0,
    autoPlay: true,
    core: 1
  }
}
// FYI. the Player class is a wrapper container provide the init and destory methods.
// you should destory the player instance at the page unshift time.
// By the way if you want to impl a progress bar you should view the normal_example.
// It's a  full example. This demo only provide a minimalist case.
// Why use class? Convenient der is enough :)
// Should I registry the instnace at a microTask? Of course.
// Pay attention to index.html. vite boy. Don't forget import the static source code :)
export class Player {
  #config = {};
  instance;
  constructor(opt = {}) {
    const { presetConfig = PRESET_CONFIG } = opt
    if (presetConfig) Object.assign(this.#config, presetConfig)
  }
  init(url) {
    this.instance = window.new265webjs(url, this.#config)
  }
}

2. 在 vue 頁面裡引用

html 模板

              <!-- video player content -->
              <div class="player-container">
                <div id="glplayer" class="glplayer"></div>
              </div>

js

這裡是用在 dialog 裡的, 在watch 的 $nextTick() 中來創建播放器, 可視需要在其它事件中使用。

import { Player } from '@/utils/executor'
watch: {
    show() {
      const that = this
      this.mrl = this.mediaObject.flv
      if (that.visible) {
        this.$nextTick(() => {
          console.info(TAG, '初始化播放器', this.show)
          const player = new Player()
          player.init(this.mrl)
          that.instance = player.instance
          player.instance.onLoadFinish = () => {
            const mediaInfo = player.instance.mediaInfo()
            console.log(TAG, 'onLoadFinish', mediaInfo)
          }
          player.instance.onPlayFinish = () => {
            console.log(TAG, 'onPlayFinish')
          }
          player.instance.do()
        })
      }
    }
  },

其它地方使用,調用 player.instance 相關的方法即可。
運行效果: