当前位置:   article > 正文

纯前端使用ffmpeg实现视频压缩_ffmpeg.min.js

ffmpeg.min.js

实现需求 用户上传视频并压缩,并且可以选择压缩程度,搜索遍各大网站,最终选择了ffmpeg进行操作。本文包含具体如何实现加上过程中遇到的各种坑

 ffmpeg视频压缩转码

ffmpeg视频压缩代码使用很简单,上代码

html部分

  1. <h3>视频前端压缩</h3>
  2. <video id="output-video" controls></video><br/>
  3. <input type="file" id="uploader">
  4. <p id="message"></p>

 js部分

  1. // 引入ffmpeg.min.js
  2. <script src="https://unpkg.com/@ffmpeg/ffmpeg@0.9.5/dist/ffmpeg.min.js"></script>
  3. <script>
  4. const { createFFmpeg, fetchFile } = FFmpeg;
  5. const message = document.getElementById('message');
  6. const ffmpeg = createFFmpeg({
  7. log: true,
  8. progress: ({ ratio }) => {
  9. message.innerHTML = `完成率: ${(ratio * 100.0).toFixed(2)}%`;
  10. },
  11. });
  12. const transcode = async ({ target: { files } }) => {
  13. const { name } = files[0];
  14. message.innerHTML = '正在加载 ffmpeg-core.js';
  15. await ffmpeg.load();
  16. message.innerHTML = '开始压缩';
  17. ffmpeg.FS('writeFile', name, await fetchFile(files[0]));
  18. // '-b','2000000' 值越小 压缩率越大
  19. await ffmpeg.run('-i', name,'-b','2000000','output.mp4');
  20. message.innerHTML = '压缩完成';
  21. const data = ffmpeg.FS('readFile', 'output.mp4');
  22. const video = document.getElementById('output-video');
  23. video.src = URL.createObjectURL(new Blob([data.buffer], {
  24. type: 'video/mp4'
  25. }));
  26. }
  27. document.getElementById('uploader').addEventListener('change', transcode);
  28. </script>

这个ffmpeg大神处理好的cdn我也是找了好久才找到,之前找的各种版本这里就不展示了。

简单的几行代码使用,运行代码时看着打印的结果一行一行出来时,一度认为我要成功了,不出意外第一个问题来了。77f46c95b01148f0be26db3fc1cd72c6.png

解决SharedArrayBuffer报错:

背景:

1036837cecef4b8999f5e96782f9381e.png

 又是经过一顿搜索,找到以下几个方案。

1.SharedArrayBuffer 降级 ArrayBuffer

  1. if(!crossOriginIsolated) {
  2. SharedArrayBuffer = ArrayBuffer;
  3. }

检查跨域隔离是否生效,你可以检查 crossOriginIsolated 属性在窗口和 worker 上下文中是否可用:无法用就降级

使用这个确实解决了SharedArrayBuffer报错,但是又衍生了另一个错误

7ddcebaa4a2c497e997f52331318cb66.png

 error:bad memory    错误:内存不足

然后又是一顿找解决办法,太麻烦了解决不了,所以这个方法说了跟没说一样。浪费时间

 2.Chrome浏览器添加Chrome Origin Trials

1)注册页面获得 Token

        https://developer.chrome.com/origintrials/#/registration

 

2)Token 放置页面 meta 标签或者响应头 Origin-Trial

        http-equiv="origin-trial" content="注册后获得的Token"

        <meta http-equiv="origin-trial" content="注册后获得的Token">

 最后像这样:

eb6228c6641e43dab1426e0f1ee46549.png

这个方法就简单粗暴,但是只支持Chrome浏览器,其他浏览器一样还是报错

3.设置COOP和COEP头部

以下所有内容都是关于解决SharedArrayBuffer报错问题,内容有点多,废话也有点多。都是我遇到的问题,所以记录下来了。

SharedArrayBuffer - JavaScript | MDN (mozilla.org)https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer根据官网给出的解决方案:

a48be899da2846bbae616a9fe240e217.png

 由于我们项目是Think php的,加上我技术不怎么样,配置header真不知道在哪里配置。

一顿搜索,于是决定先在本地做测试。我用的是vue2,然后此次本地做的又是另外一个版本了,不过基本上类似。大差不差

1.npm下载ffmpeg资源包

2.上代码

  1. <template>
  2. <!-- tempalte部分 -->
  3. <h3>视频前端压缩</h3>
  4. <video id="output-video" controls :src="vedioSrc"></video><br/>
  5. <input type="file" id="uploader" @change="initFfmpeg">
  6. <h5 id="message">{{ message }}</h5>
  7. </template>
  1. <script>
  2. // @ is an alias to /src
  3. //引入
  4. import { createFFmpeg, fetchFile } from "@ffmpeg/ffmpeg";
  5. export default {
  6. name: "HelloWorld",
  7. components: {},
  8. data() {
  9. return {
  10. message: null,
  11. vedioSrc: '',
  12. };
  13. },
  14. methods: {
  15. //初始化
  16. initFfmpeg() {
  17. let file = document.querySelector("#uploader").files[0];
  18. console.log(file);
  19. const ffmpeg = createFFmpeg({
  20. corePath: "ffmpeg-core.js",
  21. log: true,
  22. });
  23. //设置进度条
  24. ffmpeg.setProgress(({ ratio }) => {
  25. console.log(ratio);
  26. this.percentage = Math.floor(ratio * 100);
  27. });
  28. //开始压缩
  29. const transcode = async (file) => {
  30. const { name } = file;
  31. this.message = "Loading ffmpeg-core.js";
  32. await ffmpeg.load();
  33. ffmpeg.FS("writeFile", name, await fetchFile(file));
  34. this.message = "Start transcoding";
  35. // '-b','2000000' 值越小 压缩率越大
  36. await ffmpeg.run("-i", name, "-b", "700000", "output.mp4");
  37. this.message = "压缩完成";
  38. const data = ffmpeg.FS("readFile", "output.mp4");
  39. this.fileBytes = data.byteLength;
  40. //把压缩后的视频进行回显
  41. this.vedioSrc = URL.createObjectURL(
  42. new Blob([data.buffer], { type: "video/mp4" })
  43. );
  44. };
  45. transcode(file);
  46. },
  47. },
  48. };
  49. </script>

3.这里走远了,我们还是要回到主题,解决SharedArrayBuffer问题

我们找到根目录下的vue.config.js文件

a8554cc427714a9fbcf570254fd7d750.png

这里就可以配置之前说的解决 SharedArrayBuffer的配置信息

  1. devServer: {
  2. headers: {
  3. "Cross-Origin-Opener-Policy": "same-origin",
  4. "Cross-Origin-Embedder-Policy": "require-corp",
  5. },
  6. }

然后我们运行代码 npm run serve...

不出意外,它真的没出意外。压缩成功

420eec25f17c439eab7e9adf74421d4a.png

edeg浏览器测试成功,报错问题解决视频从6M压缩到了3M,压缩效果还是非常不错的 ,基本上看不出来什么区别。压缩清晰度代码里可以通过 -b '2000000'去调节,最大就是2000000,值越大压缩率越大,最小多少不知道,这个可以自己去试。ffmpeg官网有很多使用的方法,功能非常强大。

怀着忐忑的心情去Chrome浏览器测试,不出意外,它真的没出意外。我哭死...

就这样所有浏览器都能成功压缩视频,高兴之余想到我是在本地做的,而且又是vue项目。上线之后谁也不知道还会有什么错。

之前我说的我们项目是think php的,我就一菜鸟前端,根本不知道怎么把本地写的和think php结合在一起,真的完全搞不懂。

想了半天,没在本地测试之前不就是解决SharedArrayBuffer它吗,只要解决了应该就没啥问题。然后我就开始搜索think php怎样配置header。下面是配置header时遇到的问题

4.配置header信息

1ecd23ad95b5475aaec0992c7a15a0db.png

第一次是在这个配置文件里面配置的,当然这也是搜索到的。

然后中间各种试错就不说了。结论就是这个方法不行

但是!!!今天试到个方法,它确实可以 

 

解决SharedArrayBuffer报错:

我们找到页面控制器,直接在这里面居然成功了,咱也不是后端咱也不懂

代码如下:

  1. header('Cross-Origin-Opener-Policy: same-origin');
  2. header('Cross-Origin-Embedder-Policy: require-corp');

5c4b7806285d4f05abee3d725cdc0b90.png

 这次是真的解决了报错问题,但是一样压缩不成功。原因是:

影响加载跨域资源,如iframe,script标签加载。你页面所有的资源将全部不生效。而我又是用的ffmpeg 的cdn,所以直接没法用。当我下载这个文件下来后,ffmpeg.min.js里面还有cdn链接。

差点奔溃了。

废话说了这么多,最后直接上最终解决办法。

 

**重点重点,最后实现方案!!!!**

那就是通过像本地测试时一样的方法,用npm下载ffmpeg包

在think php里面使用npm

  1. 确保你的开发环境已经安装了Node.js和npm。你可以在命令行中输入node -vnpm -v来检查它们的安装情况。
  2. 在ThinkPHP 5项目的根目录下,打开命令行或终端,确保当前目录位于ThinkPHP项目的根目录下。
  3. 运行以下命令安装Node.js的包管理器
    npm install
    
  4. 如果你需要安装其他特定的npm包,你可以在项目的根目录下创建一个package.json文件,并在其中的dependenciesdevDependencies字段中添加所需的依赖项。

  5. 我将本地测试时的package.json内容直接复制到项目根目录创建的package.json上

  6. 请注意,ThinkPHP 5本身并不直接与npm交互,而是通过使用前端资源的方式来实现与npm的集成。这意味着你需要在ThinkPHP项目的根目录下创建一个与前端项目相关的目录(例如public/static),并将前端资源放置在该目录下。然后,你可以在ThinkPHP的模板中使用这些前端资源。

最后就是运行npm install将包下载下来后,在你的代码中使用

<script type="text/javascript" src="/node_modules/@ffmpeg/ffmpeg/dist/ffmpeg.min.js"></script>

完整代码

html

  1. <h3>视频前端压缩</h3>
  2. <video id="output-video" controls></video><br/>
  3. <input type="file" id="uploader">
  4. <p id="message"></p>

js

  1. <script type="text/javascript" src="/node_modules/@ffmpeg/ffmpeg/dist/ffmpeg.min.js"></script>
  2. <script>
  3. const { createFFmpeg, fetchFile } = FFmpeg;
  4. const message = document.getElementById('message');
  5. const ffmpeg = createFFmpeg({
  6. log: true,
  7. progress: ({ ratio }) => {
  8. message.innerHTML = `完成率: ${(ratio * 100.0).toFixed(2)}%`;
  9. },
  10. });
  11. const transcode = async ({ target: { files } }) => {
  12. const { name } = files[0];
  13. message.innerHTML = '正在加载 ffmpeg-core.js';
  14. await ffmpeg.load();
  15. message.innerHTML = '开始压缩';
  16. ffmpeg.FS('writeFile', name, await fetchFile(files[0]));
  17. // '-b','2000000' 值越小 压缩率越大
  18. await ffmpeg.run('-i', name,'-b','2000000','output.mp4');
  19. message.innerHTML = '压缩完成';
  20. const data = ffmpeg.FS('readFile', 'output.mp4');
  21. const video = document.getElementById('output-video');
  22. video.src = URL.createObjectURL(new Blob([data.buffer], {
  23. type: 'video/mp4'
  24. }));
  25. }
  26. document.getElementById('uploader').addEventListener('change', transcode);
  27. </script>

最终解决了,还是需要配置header,无需其他任何的配置。任何浏览器都能成功

 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号