在Next.js中引用ffmpeg.wasm
近期遇到一个需求,要在next.js里面使用ffmpeg的wasm版本来对上传的视频文件进行转码
但是按照官方的demo在next.js里引用就是会有很多报错,属实是整不明白了
下面是一个小案例,要是有更聪明的办法请告知
官方文档:https://github.com/ffmpegwasm/ffmpeg.wasm
步骤
初始化一个Next.js项目
我是使用的typescript开发,仅使用的JavaScript的小伙伴应该不影响观看
yarn create next-app --typescript
按照官方的demo将ffmpeg引到项目中
官方demo:https://ffmpegwasm.netlify.app/#installation
先安装依赖包,我使用的是yarn,使用npm的可以直接看官方demo,这个要是安装不下来多半要科学上网
yarn add @ffmpeg/ffmpeg @ffmpeg/core
直接按照官方的demo改写了pages/index.tsx
文件
import type { NextPage } from 'next'
import Head from 'next/head'
import styles from '../styles/Home.module.css'
import { useRef, useState } from 'react'
// 引入ffmpeg
import { FFmpeg, createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'
const Home: NextPage = () => {
const [message, setMessage] = useState<string>('')
const video = useRef<HTMLVideoElement | null>(null)
// 此处是记录了一个ffmpeg的实例
const ffmpeg = useRef<FFmpeg | null>(null)
// 转码逻辑函数
async function transcode(files: FileList | null) {
if (!ffmpeg.current) {
ffmpeg.current = createFFmpeg({
corePath: '/ffmpeg-core.js', // 这一步一定要加,不然会报错,此外还有一个步骤要往下看
log: true // 控制台输出转码log,可以去掉
})
}
if (!files) return
const { name } = files[0]
setMessage('Loading ffmpeg-core.js')
// 加载ffmpeg实例
if (!ffmpeg.current.isLoaded()) {
await ffmpeg.current.load()
}
// 读取文件
ffmpeg.current.FS('writeFile', name, await fetchFile(files[0]))
setMessage('Start transcoding')
// 开始转码
await ffmpeg.current.run('-i', name, 'output.mp4')
setMessage('Complete transcoding')
// 读取转码后的文件
const data = ffmpeg.current.FS('readFile', 'output.mp4')
// 转码后的文件挂载到video上可直接播放
if (video.current) {
video.current.src = URL.createObjectURL(
new Blob([data.buffer], { type: 'video/mp4' })
)
}
}
return (
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<h3>Upload a video to transcode to mp4 (x264) and play!</h3>
<video
ref={video}
width={800}
height={460}
id="output-video"
controls
></video>
<br />
{/* 在上传文件的input绑定上方transcode转码函数 */}
<input
type="file"
id="uploader"
onChange={e => transcode(e.target.files)}
/>
<p>{message}</p>
</div>
)
}
export default Home
将几个文件复制到public
文件夹中
重要的一步!这一步就是我感觉有点蠢的地方,因为是直接把第三方包中的文件直接复制到public
文件夹中,虽然但是,这就不报错了可以正常使用了
这一步是为了解决上方创建ffmpeg实例时配置的corePath: '/ffmpeg-core.js'
,如果不配置会报错,报错原因就是找不到目标文件,这一步是参考了ffmpeg.wasm官方文档以及Next.js官方文档,可以点击链接查看知识点
- 找到
node_modules/@ffmpeg/core/dist
文件夹,复制下面的三个文件ffmpeg-core.js
、ffmpeg-core.wasm
、ffmpeg-core.worker.js
- 将上方复制的三个文件粘贴到项目中的
public
文件夹
配置运行时的server环境
这步也很重要,不然也会报错
在项目根目录下新建一个文件server.js
const http = require('http')
const next = require('next')
const app = next({
dir: './',
dev: true
})
const handle = app.getRequestHandler()
app
.prepare()
.then(() => {
const port = 3000
const server = http.createServer((req, res) => {
// 这一步非常有必要
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
handle(req, res)
})
server.listen(port)
})
.catch(err => {
console.trace(err)
})
上面的setHeader
操作是不可或缺的,具体原因是因为这样,参考ffmpeg.wasm官方文档,与SharedArrayBuffer
有关
SharedArrayBuffer is only available to pages that are cross-origin isolated. So you need to host your own server with Cross-Origin-Embedder-Policy: require-corp and Cross-Origin-Opener-Policy: same-origin headers to use ffmpeg.wasm.
然后更改package.json
的scripts
的dev
字段
"scripts": {
"dev": "node server.js",
"build": "next build",
"start": "next start",
"lint": "next lint"
}
运行yarn dev
启动项目即可,跑起来了跑起来了!