Chrome浏览器支持播放.avi视频的探索

前言

最近碰到一个bug,客户上传的avi格式视频不能在Chrome浏览器播放,让支持播放。代码直接用的video标签播放,搜索一番了解到是浏览器本身不支持avi格式的播放,于是让后端在视频上传时将avi转为mp4保存,但是客户不满意,客户爸爸的话就是圣旨,就只能让前端想办法兼容一下。

探索思路

Chrome浏览器支持avi的播放,针对该问题,经过思考与搜索,得到了三种解决思路:

  • 播放器:代码中用的是video标签,而电脑自带的多媒体播放器就能打开.avi格式的视频,如果有支持播放avi格式的播放器依赖,我直接下载引入,简单快捷。
  • 格式转换:将avi格式转为浏览器支持播放的格式,如mp4格式,相当于把刚开始后端的工作放到前端,这样直接使用video标签即可。
  • 源码修改:chrome浏览器底层是用FFmpeg去解码播放的,底层代码配置项不包含avi格式,这也就是不兼容的原因。可以找到源码去添加配置项,重新编译,将编译好的文件替换旧文件,就能播放avi格式了。
    上述思路,果断去掉第三种,该方法自己的浏览器可以尝试一下,剩下两种我们一个个去尝试。

plyr播放器

播放器的思路是找到支持播放avi格式的播放器,先去npm用video+avi格式搜索了一下,搜索结果更多是转换格式的库,于是问了一下ai,提到了plry的库,该库是一个简洁功能强大的音频视频播放器,视频支持画中画、字幕等功能。选定好了库,写一个简单的demo看能不能播放avi格式。 新建一个html文档,用cdn方式引入plry,plry的样式也需要引入。

js 复制代码
   <link rel="stylesheet" href="https://cdn.plyr.io/3.7.8/plyr.css" />
   <script src="https://cdn.plyr.io/3.7.8/plyr.js"></script>

plry在网页端应用很简单,直接new一个对象去绑定video元素即可。

js 复制代码
    <video id="player" control> 
    <source src="./123.avi" type="video/avi"></source>
    </video>
     <script>
        const player = new Plyr('#player');
      </script>

字幕画中画等功能我们按照官方给出的配置项做对应的配置即可,这里我们就直接绑定不搞花里胡哨,打开页面,不能播放。

该样式要比原生video样式好看,但就是不支持播放avi格式,我就去搜了下issue,作者提到了是浏览器本身不支持,也就是思路三提到的。看来plyr只是对video标签进行了功能添加与样式修改,本质上没有对视频格式进行兼容出来。到此我觉得播放器大多应该是对功能的支持,具体格式还是受限于浏览器自身,只能尝试格式转换。

格式转换

将avi转为mp4肯定能兼容浏览器,问了下后端转换方法是使用FFmpeg相关的库,谷歌也是用的FFmpeg,前端转换看来也是要用FFmpeg,站内搜索了FFmpeg,有好几篇大佬介绍FFmpeg相关的文章,就决定使用ffmpeg.wasm,接下来开整。

格式转换播放思路很明确,借助库将avi格式转为mp4格式,然后用createObjectURL 创建一个url,用video去播放该url。该库不支持cdn方式引入,官网给出了解释: 我当时试的时候还有cdn引入的例子,也用cdn方式写了demo,运行不起来,现在文档直接取消并解释了,很好的团队。

该依赖有两大版本,具体的api跟node版本的支持有所区别,我们可以根据需要安装合适的版本。

  • 0.11x版本,该版本创建实例api为createFFmpeg
  • 0.12+版本,创建实例api为 new FFmpeg(),该版本node需要大于等于18.17.0
    详细对比可以查看官网文档,因为公司项目node版本达不到18以上,就安装了0.11x版本。
js 复制代码
   <template>
  <div>
    <video ref="videoRef" controls></video>
  </div>
</template>
<script setup lang="ts">
import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'
import { ref, onMounted } from 'vue'
const videoRef = ref<HTMLVideoElement | null>(null)
const ffmpeg = createFFmpeg({ log: true })
const load = async () => {
  // 加载
  await ffmpeg.load()
  // 写入文件
  ffmpeg.FS(
    'writeFile',
    'test.avi',
    await fetchFile('/video/test.avi'),
  )
  // 执行 格式转换 命令
  await ffmpeg.run('-i', 'test.avi', 'test.mp4')
  // 读取mp4文件
  const data = ffmpeg.FS('readFile', 'test.mp4')
  //
  if (videoRef.value) {
    videoRef.value.src = URL.createObjectURL(
      new Blob([data.buffer], { type: 'video/mp4' }),
    )
  }
}
onMounted(() => {
  load()
})
</script>

ffmpeg加载过程要使用await ,等待所需资源加载完。运行完毕打开页面会有一个报错,SharedArrayBuffer is not defined,Chrome安全策略的变更导致这一错误,这个错误在60-91的版本不会存在。解决的办法也很简单,在vite.config,ts中添加给响应头添加两个属性。

js 复制代码
headers: {
        'Cross-Origin-Opener-Policy': 'same-origin',
        'Cross-Origin-Embedder-Policy': 'require-corp',
      },

再次运行等待一会,我们就能看到video加载出来视频了,在console页面也能看到转换过程。

该库实现的转换会比较慢,10M的视频转换了3分钟,这个结果客户肯定不满意。官网也提到了慢的问题,并建议使用mt多线程版本,但是多线程需要兼容SharedArrayBuffer 。除此之外,如果想要上线还要进行一些配置,具体操作可以看大佬的ffmpeg实现web在线转码播放,简单来说,ffmpeg.wasm在加载过程中会加载放到unpkg上的工具包,客户一般往往会有内网需求,所以需要配置。

总结

以上就是探索过程,最终实现效果不太理想,也勉强算是实现了,在这个过程中也学到了一些知识。如果客户不介意转换速度,可以尝试用ffmpeg.wasm库兼容avi视频的播放;如果浏览器版本支持多线程的话,可以用多线程加快转换过程。

相关推荐
也无晴也无风雨1 小时前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
Martin -Tang2 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
阮少年、5 小时前
java后台生成模拟聊天截图并返回给前端
java·开发语言·前端
郝晨妤6 小时前
鸿蒙ArkTS和TS有什么区别?
前端·javascript·typescript·鸿蒙
AvatarGiser6 小时前
《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明
前端·vue.js·elementui
喝旺仔la6 小时前
vue的样式知识点
前端·javascript·vue.js
别忘了微笑_cuicui6 小时前
elementUI中2个日期组件实现开始时间、结束时间(禁用日期面板、控制开始时间不能超过结束时间的时分秒)实现方案
前端·javascript·elementui