起因
正在做视频上传功能,其中视频压制这方面使用了ffmpeg.wasm,就在前端做掉了。还需要截取视频的缩略图thumbnails。
项目使用的播放器是DPlayer,DPlayer的文档在thumbnails这边是这样写的并提供了DPlayer-thumbnails。
通过这个工具可以得到如下的雪碧图。
阅读了下DPlayer-thumbnails的代码,也是通过ffmpeg。然后又测试了一下,它是无论是什么长度的视频都取100张的缩略图,然后制成雪碧图。
(一开始我以为是每秒截一张,这个方案很好,在进度条上显示缩略图时就计算百分比就好了。)
既然这样,是否可以一样使用ffmpeg.wasm在前端进行同样的操作。得出100张缩略图,可以供用户选择视频封面,并且制成雪碧图上传它。
经过
先用ffmpeg测试一下
//既然是在视频总长中截取100张图片,那么就是视频总时长/100
//我的这个测试视频是160秒,至于读取不同视频的时长那后面再说吧。
ffmpeg -i ../../test.mp4 -vf fps=1/(160/100) ../../thumbnail/thumbnail%d.png
能得出以下内容
好啊,很好啊。但是要怎么把他们取出来呢。
ffmpeg.wasm的文档是这样的
//Browser
<body>
<video id="player" controls></video>
<input type="file" id="uploader">
<script src="ffmpeg.min.js"></script>
<script>
const { createFFmpeg, fetchFile } = FFmpeg;
const ffmpeg = createFFmpeg({ log: true });
const transcode = async ({ target: { files } }) => {
const { name } = files[0];
await ffmpeg.load();
ffmpeg.FS('writeFile', name, await fetchFile(files[0]));
await ffmpeg.run('-i', name, 'output.mp4');
const data = ffmpeg.FS('readFile', 'output.mp4');
const video = document.getElementById('player');
video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
}
document
.getElementById('uploader').addEventListener('change', transcode);
</script>
</body>
//Node.JS
const fs = require('fs');
const { createFFmpeg, fetchFile } = require('@ffmpeg/ffmpeg');
const ffmpeg = createFFmpeg({ log: true });
(async () => {
await ffmpeg.load();
ffmpeg.FS('writeFile', 'test.avi', await fetchFile('./test.avi'));
await ffmpeg.run('-i', 'test.avi', 'test.mp4');
await fs.promises.writeFile('./test.mp4', ffmpeg.FS('readFile', 'test.mp4'));
process.exit(0);
})();
单个文件是可以取出来的(比如只压制一个视频),但像这里生成了很多图片,是多个文件该怎么取出来呢?
问题
截取缩略图这块我是这样写的
var in_name = "upload.mp4";
var out_name = "thumbnail%d.png";
(async () => {
await ffmpeg.load();
ffmpeg.FS('writeFile', in_name, await fetchFile(original_video_file));
await ffmpeg.run('-i', in_name, '-vf' , 'fps=1/(160/100)' , out_name);
var new_file = ffmpeg.FS('readFile', out_name);
var thumbnail = new Blob([new_file.buffer], { type: 'image/png' });
console.log(thumbnail);
})();
报了以下错误
想了想原因,应该就是这个写法不能读取多个文件的原因,报错也在ffmpeg.FS这里看看下文档吧。可惜没有给出这样的写法。
然后又去稍稍的了解了下emscripten(毕竟文档里有这个链接),可惜头都看的大了都没找着。
https://emscripten.org/docs/api_reference/Filesystem-API.html
各位大神是否有办法呢!如果网络上有这方面的讲解或者这个问题的其他解法,请麻烦告诉我也可以节省时间重复回答。辛苦了!
找到办法了,实际是读取文件问题。
按照原本的代码的输出的文件会存到MEMFS的工作根目录,而读取这些文件也应该是像这样。
那么可以先新建个目录,指定输出到这里
ffmpeg.FS('mkdir','/thumbnails');
我一开始是不知道这些文件存到哪里去了,头大... 到处问了一遍,没什么结果看看作者博客吧。看到了这个,是可以读取指定目录中的文件的。

一开始想着读取到了这些文件就可以读出来了,后来一想这文件名在输出时就固定了,知道路径文件名就可以直接读了,套个循环就可以拿出来。
能读到第一张那后面的也不成问题了。