安装

cnpm install @ffmpeg/ffmpeg @ffmpeg/util

配置vite.config.ts

optimizeDeps: {
exclude: ['@ffmpeg/ffmpeg', '@ffmpeg/util']
},

使用

2024/06/16 更新

初始化(在线加载)

import { FFmpeg } from '@ffmpeg/ffmpeg'
import type { LogEvent } from '@ffmpeg/ffmpeg/dist/esm/types'
import { fetchFile, toBlobURL } from '@ffmpeg/util'

const baseURL = 'https://unpkg.com/@ffmpeg/core-mt@0.12.6/dist/esm'
const ffmpeg = new FFmpeg();

const initFFMpeg=async ()=>{
ffmpeg.on('log', (e) => {
console.log(e.message);
});

await ffmpeg.load({
coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),
workerURL: await toBlobURL(`${baseURL}/ffmpeg-core.worker.js`, 'text/javascript')
})
ElMessage.success('FFMpeg 已加载')
}

其中这里是通过网络加载FFMpeg的核心等等,开发环境下配置vite.config.ts可以正常加载,但是生产环境(打包后)将会无法加载

server: {
headers: {
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp'
}
}

原因:这里面要获取的wasm比较大(ps:获取两个js没问题),需要用到SharedArrayBuffer,而SharedArrayBuffer需要开启了跨域隔离才能正常使用(在控制台中输入 crossOriginIsolated 回车,为 false,则说明并没有开启跨域隔离),而上面的设置仅对开发环境有效,生产环境不起作用。或许在Nginx里面配置可以解决,但是这里不作研究了,因为我这里要做的是一个桌面应用程序,而不是网站

初始化(静态资源加载)

把加载过程中用到的三个文件放到public文件夹

img

然后加载就可以了

import { FFmpeg } from '@ffmpeg/ffmpeg'
import type { LogEvent } from '@ffmpeg/ffmpeg/dist/esm/types'
import { fetchFile, toBlobURL } from '@ffmpeg/util'

const ffmpeg = new FFmpeg();

const initFFMpeg=async ()=>{
ffmpeg.on('log', (e) => {
console.log(e.message);
});

await ffmpeg.load({
coreURL: await toBlobURL(`./ffmpeg-core.js`, 'text/javascript'),
wasmURL: await toBlobURL(`./ffmpeg-core.wasm`, 'application/wasm'),
workerURL: await toBlobURL(`./ffmpeg-core.worker.js`, 'text/javascript')
})
ElMessage.success('FFMpeg 已加载')
}

这么做的话开发环境和生产环境都没问题,只是打包后体积会变大一点

还有一个缺点的话,亲测如果非要部署到服务器上当一个网站来用,加载的时候会非 常 慢(但也总比获取不了wasm好(((

使用

const raw:File=audioList.value.find(obj=>obj.name===row.name)?.raw
await ffmpeg.writeFile(row.name, await fetchFile(raw))
await ffmpeg.exec(['-i',row.name,'-ar',row.sample,'-acodec',row.bit,exportName])
const data=await ffmpeg.readFile(exportName)
const exportPath=URL.createObjectURL(new Blob([(data as Uint8Array).buffer],{type:'audio/wav'}))

fetchFile里面可以传入File对象,也可以传入一个URL

execFFMpeg执行命令的函数,与平常使用差不多,但是这里是通过数组将参数分开的

已知问题

目前我在使用中遇到的问题有:

  • 转换视频时-s参数无效(或者说和改变分辨率参数相关的都无效,总之就是无法改变视频分辨率)
  • 转换视频时速度巨慢

这两个问题在使用真·FFMpeg时是没有问题的,可能是插件的bug吧~

2024/07/02更新:

编码速度慢这个问题,其实在官网的FAQ就有(

Why ffmpeg.wasm is so slow comparing to ffmpeg?

As of now, WebAssembly is still a lot slower than native, it is possible to further speed up using WebAssembly intrinsic, which is basically writing assembly code. It is something we are investigating and hope to introduce in the future.

If you are OK with more unstable version of ffmpeg.wasm, using ffmpeg.wasm multithread (mt) version can have around 2x speed comparing to single thread (but consume a lot more memory and cpu)

FFMpeg 常用命令

抽取音频

ffmpeg -i input.mp4 -vn -c:a copy output.aac

-vn表示no video,-c:acodec of audio的意思,copy是直接拷贝视频中的原始的音频,这里不会涉及音频的编解码,速度会很快。

也可以指定格式

ffmpeg -i input.mp4 -vn -b:a 128k -ar 44k -c:a mp3 output.mp3

抽取视频

ffmpeg -i input.mp4 -an -c:v copy output.mp4

-an表示no audio,其他关于视频的参数都可以使用

查看信息

主要用到ffprobe,但是这个插件似乎并没有提供

ffprobe video.mp4
ffprobe -show_format ~/Downloads/2018121051.mp4

上述命令可以输出格式信息format_name、时间长度duration、文件大小size、比特率bit_rate、流的数目nb_streams等。

ffprobe -print_format json -show_streams 2018121051.mp4

上述命令可以以JSON格式的形式输出具体每一个流最详细的信息,视频中会有视频的宽高信息、是否有b帧、视频帧的总数目、视频的编码格式、显示比例、比特率等信息,音频中会有音频的编码格式、表示格式、声道数、时间长度、比特率、帧的总数目等信息

转换编码

转换编码格式(transcoding)指的是, 将视频文件从一种编码转成另一种编码。比如转成 H.264 编码,一般使用编码器libx264,所以只需指定输出文件的视频编码器即可。

ffmpeg -i [input.file] -c:v libx264 output.mp4

转换容器

转换容器格式(transmuxing)指的是,将视频文件从一种容器转到另一种容器。下面是 mp4 转 webm 的写法。

ffmpeg -i input.mp4 -c copy output.webm

使用预设 -preset

–preset的参数主要调节编码速度和质量的平衡,有ultrafast(转码速度最快,视频往往也最模糊)、superfast、veryfast、faster、fast、medium、slow、slower、veryslow、placebo这10个选项,从快到慢。

音频常用命令

  • -ar[:stream_specifier] freq (input/output,per-stream)

设置音频采样频率。对于输出流,它默认设置为相应输入流的频率。对于输入流,此选项仅对音频抓取设备和原始解复用器有意义,并映射到相应的解复用器选项。

  • -aq q (output)

设置音频质量(特定于编解码器、VBR)。这是 -q:a 的别名。

  • -ac[:stream_specifier] channels (input/output,per-stream)

设置音频通道数。对于输出流,它默认设置为输入音频通道的数量。对于输入流,此选项仅对音频抓取设备和原始解复用器有意义,并映射到相应的解复用器选项。

  • -acodec codec (input/output)

设置音频编解码器。这是 -codec:a 的别名。

  • -sample_fmt[:stream_specifier] sample_fmt (output,per-stream)

设置音频样本格式。用于-sample_fmts获取支持的示例格式的列表。

视频常用命令

  • -r[:stream_specifier] fps (input/output,per-stream)

设置帧速率(Hz 值、分数或缩写)。

作为输入选项,忽略文件中存储的任何时间戳,而是假设恒定帧速率fps生成时间戳。这与-帧率用于某些输入格式的选项,如 image2 或 v4l2(在旧版本的 FFmpeg 中曾经是相同的)。如果有疑问,请使用-帧率而不是输入选项-r。

  • -fpsmax[:stream_specifier] fps (output,per-stream)

设置最大帧速率(Hz 值、分数或缩写)。

当输出帧率自动设置且高于此值时,钳位输出帧率。在批处理或输入帧速率被错误地检测为非常高时很有用。不能与 一起设置-r。在流复制期间它被忽略。

  • -s[:stream_specifier] size (input/output,per-stream)

设置帧大小。

作为输入选项,这是视频大小私有选项,被一些解复用器识别,其帧大小要么不存储在文件中,要么是可配置的——例如原始视频或视频采集器。

作为输出选项,这会将scale视频过滤器插入到 相应过滤器图的末尾。请直接使用scale过滤器将其插入开头或其他位置。

格式为 ‘宽x高’(默认 - 与源相同)。

  • -aspect[:stream_specifier] aspect (output,per-stream)

设置由aspect指定的视频显示宽高比。

spect可以是浮点数字符串,也可以是num : den形式的字符串,其中num和den是纵横比的分子和分母。例如,“4:3”、“16:9”、“1.3333”和“1.7777”是有效的参数值。

如果与一起使用-vcodec复制,它将影响存储在容器级别的宽高比,但不会影响存储在编码帧中的宽高比(如果存在)。

  • -vcodec codec (output)

设置视频编解码器。这是 -codec:v 的别名。

  • -b:v rate

主要是控制平均码率。

ffmpeg -i input.mp4 -b:v 2000k output.mp4

控制码率

除了-b:v,还有其他两种方法

  • -qp(constant quantizer恒定量化器模式)

所谓的量化器就是利用特殊算法将画质转化为数字,这样的话每一帧的画质都可以通过量化参数来判定。在qp模式下,画质被分为0…20…40…51个级别,0就是无损的画质。用qp压制视频,每一帧的画面都能达到该级别的质量,严格的遵循量化参数来编码,这么一来他的画质是最好的,体积也是最大的,大到你无法想象,所以我们都不采用这种码率控制模式。

ffmpeg -i input.mkv -vcodec libx264 -preset ultrafast -qp 0 output.mkv
  • -crf(constant rate factor恒定速率因子模式)

crf其实是一个浮动的qp模式,他按照特定的标准,根据人体肉眼的特点,给予每帧画面不同的量化参数,有些画面画质低一点,有些画面画质高一点其实人眼是很难识别的。所以我们可以降低一点码率,然后把这些码率用到视觉敏感的画面里,这么一来,画质的变化几乎看不出来,码率却降低了不少,文件体积自然也变小了.

在优先保证画面质量(也不太在乎转码时间)的情况下,使用-crf参数来控制转码是比较适宜的。这个参数的取值范围为0——51,其中0为无损模式,数值越大,画质越差,生成的文件却越小。从主观上讲,18——28是一个合理的范围。18被认为是视觉无损的(从技术角度上看当然还是有损的),它的输出视频质量和输入视频相当。

ffmpeg -i D:\src.mov -c:v libx264 -preset veryslow -crf 18 -c:acopy D:\dest1.mp4

参考链接

使用ffmpeg从视频中提取纯音频&纯视频_ffmpeg提取音频-CSDN博客

FFmpeg、FFprobe、FFplay命令行使用 - 简书 (jianshu.com)

FFmpeg 转码语句的preset、tune参数说明_ffmpeg preset-CSDN博客

ffmpeg 文档_ FFmpeg中文网 (github.net.cn)

FFmpeg 视频处理入门教程 - 阮一峰的网络日志 (ruanyifeng.com)

ffmpeg:码率控制模式、编码方式_ffmpeg bitrate-CSDN博客

[FFmpeg] ffmpeg 常用命令 - 晏过留痕 - 博客园 (cnblogs.com)

FFmpeg——在Vue项目中使用FFmpeg(安装、配置、使用、SharedArrayBuffer、跨域隔离、避坑…)_vue ffmpeg-CSDN博客

FAQ | ffmpeg.wasm (ffmpegwasm.netlify.app)