uniapp视频播放器(h5+app)

关于uniapp视频播放器遇到的一些问题,mark下。

中途遇到了很多问题,如果有相同的伙伴遇到了类似的,欢迎交流

  • 官方的video播放器在app上不友好,有以下功能不支持。
  1. @loadedmetadata、@controlstoggle不支持导致只能手写控制层。
  1. 不支持外挂字幕,因为video在app上运行时,是采用的ijkplayer 库来实现的,ijkplayer目前也不支持外挂字幕
  1. 使用subNVues或者cover-view来自定义绘制视频界面覆盖(因为cover-view不支持嵌套,所以最后采用使用subNVues)
  1. video在h5需要播放时采用的是html的video标签,但是不支持m3u8格式,最后采用的是dplayer播放器+hls来实现的m3u8播放(也可以通过m3u8格式转换后再进行播放)

我这边的想要的是自定义绘制视频界面,这样做的话就需要将video原有的control相关的功能重写(播放、暂停、快进、快退、全屏、音量等),全屏和非全屏两套样式,通过官方提供的uni.createVideoContext(videoId, this)可以获取到video的实例,然后通过实例调用video的api,比如play、pause等。

最终我这边实现后的播放器支持以下功能:

  1. app端自定义界面,播放、暂停、快进、快退、全屏、音量、选集、倍速、清晰度切换、手势(快进、后退、亮度调节、音量调节)。
  2. h5采用的是dplayer播放器+hls支持m3u8格式播放。
  3. 支持外挂字幕(SRT通过)
    下面说下具体的实现和遇到的问题:

1. 配置subNVues子窗体

  1. 这里注意的一点是path路径是从根目录开始的,不是对应的父窗体的相对路径。

  2. 文件格式一定是要nvue格式。

    配置完之后子窗体就会在对应的页面上显示。


2.配置video播放界面

  1. 因为我们需要自定义界面所以video的controls需设置为false
  1. 全屏和非全屏后界面有些许差异,比如全屏后才可以选集等其他功能,那需要设计出两套样式。

    通过ref拿到video实例

javascript 复制代码
videoCTX = this.$refs.video

全屏和取消全屏事件

javsscript 复制代码
  // 全屏/退出全屏
  fullOrExitScreen() {
    if (this.fullScreenStatus) {
      videoCTX.exitFullScreen()
    } else {
      videoCTX.requestFullScreen()
    }
  },

3. 设置手势操作

手势操作分为向上向下向左向右四个方位

  • 向左向右:快进、后退
  • 屏幕左侧上下滑动:亮度调节
  • 屏幕右侧上下滑动:音量调节

使用touchStart、touchMove、touchend来实现此功能

touchStart时存储首次的坐标点

javascript 复制代码
this.oldTouchs = e.changedTouches[0]

我这边定义的touchType为三种类型,currentTime进度、luminance亮度、volume音量

  1. 首先先判断是否为上下滑动,如果上下的话就只能是亮度和音量调节,接着获取屏幕的宽度,判断手势移动的x坐标是否大于屏幕宽度的1/2,如果是就为音量调节,否则为亮度调节。
  1. 如果为进度条的话则先保存当前进度,视频暂停,通过x轴移动的距离计算出当前进度,然后通过video的seek方法跳转到当前进度。

然后再touchEnd设置video进度

  1. 音量调节也是一样的 算出滑动的距离后通过plus.device.setVolume设置
  1. 亮度调节也是一样的 算出滑动的距离后通过plus.screen.setBrightness设置

4. 配置字幕

  1. 如果是VVT格式可以采用video中track标签实现,.vtt 格式文件属于 Web Video Text Tracks Format(WebVTT),是一种基于文本 UTF-8 编码的格式,为 Web 媒体元素提供字幕数据文件。WebVTT 的 MIME 格式是 text/vtt。
  2. 我这边项目中是用的是SRT格式的,但是video无法解析出来,所以想到的办法是将SRT字幕格式转换成js可以解析的json格式。

下面是SRT原格式

  1. 通过以下函数将数据转换为数组

    javascript 复制代码
    createSrtArr(srt) {
       let arr = srt.split(/\n\n|\r\r|\r\n\r\n/)
       let result = []
       arr.forEach(item => {
         let srtObj = {}
         let containArr = item.split(/\n/)
    
         if (containArr[1]) {
           //此处正则用于取出00:00:00,213 --> 00:00:00,213这种结构,防止可能存在于此行的x,y坐标对后续处理造成影响
           var reg = /^(\d{2}):(\d{2}):(\d{2})[\.,](\d{1,3}) --\> (\d{2}):(\d{2}):(\d{2})[\.,](\d{1,3})/g
           let regResult = reg.exec(containArr[1])
           if (regResult) {
             let timeSplit = regResult[0].split(' --> ')
             srtObj.from = this.getSeconds(timeSplit[0])
             srtObj.to = this.getSeconds(timeSplit[1])
             //这里的两个replace主要是将srt中可能携带的font标签转化为易用的span,当时遇到了如果是font标签的话没办法继承父元素的字体大小的问题,题外话:本次字母字体大小采用了媒体查询进行设置
             srtObj.htmlText = containArr.slice(2).join(`\n`).replace(/\<font/g, '<span').replace(/\<\/font/g,
               '</span')
             result.push(srtObj)
           }
         }
       })
       return result
     }

转换后的数据格式如下

  1. 通过currentTime时长 和获取到的subtitlesArray字幕数组获取到对应时间的字幕。
javascript 复制代码
  getSubtitle(currentTime, arr) {
      let left = 0;
      let right = arr.length - 1;
      while (left <= right) {
        let mid = Math.floor((left + right) / 2);
        if (currentTime >= arr[mid].from && currentTime <= arr[mid].to) {
            return arr[mid].htmlText;
        } else if (currentTime < arr[mid].from) {
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }
    return null; // 如果未找到匹配的时间段,则返回null或者其他您认为合适的值
  }

PS: 这个里有注意事项,因为我这边是需要兼容h5和app端,通过时长获取到的字幕数据有可能携带标签,所以需要富文本展示,h5和app上均需要做处理。

html 复制代码
  <!-- #ifdef H5 -->
		<view class="subtitles" v-html='subtitles'></view>
	<!-- #endif -->
	<!-- #ifdef APP-PLUS -->
		<rich-text class="subtitles" :nodes="nodes" :style="videoBox">
	<!-- #endif -->
	</rich-text>
javascript 复制代码
  const res = this.getSubtitle(value,this.subtitlesArray) || ''
  if (this.subtitlesArray.length) {
    // #ifdef APP-PLUS
    this.nodes[0].children[0].text =res
    // #endif
    // #ifdef H5
    this.subtitles = res
    // #endif
  }

这里先简单记录下,因为时间有限,代码已上传到线上,有需要的伙伴可以下载下来参考下。传送门

相关推荐
尚梦40 分钟前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
我喜欢就喜欢5 小时前
基于qt vs下的视频播放
开发语言·qt·音视频
安步当歌6 小时前
【WebRTC】视频采集模块中各个类的简单分析
音视频·webrtc·视频编解码·video-codec
EasyGBS7 小时前
国标GB28181公网直播EasyGBS国标GB28181软件管理解决方案
大数据·网络·音视频·媒体·视频监控·gb28181
尚学教辅学习资料7 小时前
基于SSM+uniapp的营养食谱系统+LW参考示例
java·uni-app·ssm·菜谱
Bessie2347 小时前
微信小程序eval无法使用的替代方案
微信小程序·小程序·uni-app
Johnstons9 小时前
AnaTraf | 网络性能监控系统保障音视频质量的秘籍
网络·音视频·网络流量监控·网络流量分析·npmd
lrlianmengba9 小时前
推荐一款非常好用的视频编辑软件:Movavi Video Editor Plus
音视频
SZ1701102319 小时前
ffplay 实现视频流中音频的延迟
音视频·延迟
LNTON羚通11 小时前
CPU算法分析LiteAIServer视频智能分析平台视频智能分析:抖动、过亮与过暗检测技术
大数据·目标检测·音视频·视频监控