写点什么

ffmpeg 实现 web 在线转码

作者:lo
  • 2022 年 4 月 01 日
  • 本文字数:1906 字

    阅读完需:约 6 分钟

ffmpeg实现web在线转码

前提: 公司项目中上传的视频编码格式不一,但是在浏览器播放中,却出现了黑屏(有声音)的情况,即使是 MP4 格式的视频,也存在无法播放,查询一番,了解到 chrome 浏览器的 video 标签仅对部分格式的视频支持播放


通常我们使用 MP4 格式,但是 MP4 又分为“1.MPEG4(DivX)”、“2.MPEG4(Xvid)”、“3.AVC(H264)”三种类型。其中只有 H264 类型的视频才能进行 html 播放

<video>标签所支持的视频格式和编码:

MP4 = MPEG 4 文件使用 H264 视频编解码器和 AAC 音频编解码器

WebM = WebM 文件使用 VP8 视频编解码器和 Vorbis 音频编解码器

Ogg = Ogg 文件使用 Theora 视频编解码器和 Vorbis 音频编解码器


注释:Internet Explorer 8 以及更早的版本不支持 video 标签。使用 FFMPEG 转码预览地址: https://642134542.github.io/vue-ffmpeg/


1、原理:

ffmpeg.wasm 是 FFmpeg 的纯 WebAssembly / JavaScript 端口。它支持在浏览器内录制、转换和流式传输视频和音频。Webassembly 的出现为前端转码提供可能


2、按照官网配置

npm 安装

npm install @ffmpeg/ffmpeg @ffmpeg/core
复制代码


<div>    <h3>Upload a video to transcode to mp4 (x264) and play!</h3>    <video id="output-video" controls ></video><br/>    <input type="file" id="uploader">    <p id="message"></p>  </div>
复制代码


js

const { createFFmpeg, fetchFile } = FFmpeg;const ffmpeg = createFFmpeg({    corePath: 'https://unpkg.com/@ffmpeg/core@0.8.5/dist/ffmpeg-core.js',    log: true, }); const transcode = async ({ target: { files } }) => {    const message = document.getElementById('message');     const { name } = files[0];      message.innerHTML = 'Loading ffmpeg-core.js';      await ffmpeg.load();      ffmpeg.FS('writeFile', 'name', await fetchFile(files[0]));      message.innerHTML = 'Start transcoding';      await ffmpeg.run('-i', 'name', 'output.mp4');      message.innerHTML = 'Complete transcoding';      const data = ffmpeg.FS('readFile', 'output.mp4');
const video = document.getElementById('output-video'); video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' })); } const elm = document.getElementById('uploader'); elm.addEventListener('change', transcode);
复制代码


3、结果


报错 ReferenceError: SharedArrayBuffer is not defined,


需要解决 SharedArrayBuffer 报错


经过一番百度和查看 issue, 是因为谷歌浏览器的安全策略机制改变了


2017.7 月(Chrome 60)引入 SharedArrayBuffer。

2021.7 月(Chrome 92)限制 SharedArrayBuffer 只能在 cross-origin isolated 页面使用。

Android Chrome 88 也进行了同样的限制。


所以在 60-91 的版本的浏览器是可以正常打开的那么 92 版本的呢我们可以再 vue.config.js 中配置 devServer: {headers: {"Cross-Origin-Opener-Policy": "same-origin","Cross-Origin-Embedder-Policy": "require-corp",},}


4、效果

在控制台中可以看到读取文件和转码进程,而且页面可以正常的显示视频并播放


5、优化:

1、createFFmpeg 中的 corePath 的地址是 cdn 在线的,这里我们需要换成自己的本地资源,使用 import 一直报错


估计是相关依赖并没有找到,npm install 还是不行


只好把包里的 ffmpeg-core.js、ffmpeg-core.wasm 和 ffmpeg-core.worker.js 放在 public 中



2、加载

读取文件和转码的时间比较长,所以我们需要增加加载层和进度条

ffmpeg.setProgress(({ ratio }) => {  console.log(ratio);  this.percentage = Math.floor(ratio * 100)  /*   * ratio is a float number between 0 to 1.   */});
复制代码

6、部署:

使用 ip 或者域名访问,依旧会报错 SharedArrayBuffer is not defined,


所以我们需要代理中配置请求头

add_header Cross-Origin-Opener-Policy same-origin;
add_header Cross-Origin-Embedder-Policy require-corp;

复制代码

但是还是存在报错信息


解决办法:

1、使用 https 代替 http

2、使用 chrome 60-91 版本访问


7、FAQ

1、caught (in promise) Error: Oops, something went wrong in FS operation


解决办法: 不要使用中文名称,将 name 可以进行转义


2、Error: ffmpeg.FS('readFile', 'output.mp4') error. Check if the path exists


解决办法:同问题 1


3、github page 无法设置 header 请求头,预览地址是如何解决 SharedArrayBuffer


报错的在 Stack Overflow 这个问题中 有个回答提供了解决方案

https://github.com/gzuidhof/coi-serviceworker, 开发者只需要将 coi-serviceworker.js 在 index.html 引入即可

<script src="coi-serviceworker.js"></script>
复制代码


发布于: 20 小时前阅读数: 34
用户头像

lo

关注

汝等ここに入るもの, 一切の望みを捨てる 2020.02.06 加入

学习,摸鱼两不误

评论

发布
暂无评论
ffmpeg实现web在线转码_4月月更_lo_InfoQ写作平台