uniapp + Vite + ffmpeg-wasm 0.12.x 集成示例

安装依赖

复制代码
pnpm add @ffmpeg/ffmpeg@0.12.15 @ffmpeg/util@0.12.1 @ffmpeg/core@0.12.6

查看依赖是否安装成功

将esm下的ffmpeg-core.js和ffmpeg-core.wasm 拷贝到static静态目录,并确保能访问

在vite.config.ts中配置 optimizeDeps.exclude

复制代码
optimizeDeps: {
	    exclude: ['@ffmpeg/ffmpeg', '@ffmpeg/core', '@ffmpeg/util'],
	  },

编写页面测试

复制代码
<template>
	<view>
		333
	</view>
</template>

<script setup>
	import { onLoad, onUnload } from '@dcloudio/uni-app'
	import { FFmpeg } from '@ffmpeg/ffmpeg'
	import { fetchFile } from '@ffmpeg/util'
	
	const ffmpeg = new FFmpeg()
	
	onLoad(async (options) => {
		await ffmpeg.load({
		    coreURL: `http://192.168.1.166:9000/shanqiapph/static/ffmpeg/ffmpeg-core.js`,//必须传,不然默认umd
		  });
		
		console.log('✅ FFmpeg ',ffmpeg.loaded)
		
		
		const videoData = await fetchFile("http://192.168.1.166:9000/shanqiapph/static/ffmpeg/test.mp4")
		
		await ffmpeg.writeFile('input.mp4', videoData)
		console.log('✅ 视频已写入 ffmpeg 环境')
		
		// 监听 ffmpeg 日志输出
		  ffmpeg.on('log', ({ message }) => {
			console.log(message)
		  })
		  
		await ffmpeg.exec(['-i', 'input.mp4'])  
	})
</script>

<style>
	       
</style>

结果

以上ffmpeg-wasm已集成完成

下面是封装一些接口,可在H5环境直接使用

ffmpegUtil.js

复制代码
import {
	FFmpeg
} from '@ffmpeg/ffmpeg'
import {
	fetchFile
} from '@ffmpeg/util'


export async function init() {
	const ffmpeg = new FFmpeg()
	await ffmpeg.load({
	    coreURL: `${window.location.origin}${import.meta.env.VITE_APP_PUBLIC_BASE}static/ffmpeg/ffmpeg-core.js`,//必须传,不然默认umd
	  });
	  
	ffmpeg.on('log', ({ message }) => {
		console.log(message)
	})  
	
	const rootPath = '/generateVideo'; 
	 
	//创建合成视频根,目录  
	await ffmpeg.createDir(rootPath)
	  
	  
	/**
	 * 查询指定路径下的所有文件
	 */  
	async function listMemfsFiles (dirPath = rootPath){
		const entries = await ffmpeg.listDir(dirPath)
		 const result = []
		
		 for (const name of entries) {
		   // 跳过当前目录和上级目录的伪条目(如果存在)
		   if (name.name === '.' || name.name === '..') continue
		
		   if(name.isDir == true){
			   const subFiles = await listMemfsFiles(`${dirPath}/${name.name}`)
			   if (subFiles.length > 0) {
			     result.push(...subFiles)
			   } else {
			     // 空目录也记录一下
			     result.push({
			       path: dirPath,
			       fullPath:`${dirPath}/${name.name}`,
			       size: 0,
			       sizeFormatted: '[空目录]',
			       type: 'dir'
			     })
			   }
		   }else {
			   // 尝试读取,成功则为文件
			   const data = await ffmpeg.readFile(`${dirPath}/${name.name}`)
			   const size = data.length || data.byteLength
			   		
			   result.push({
			     path: dirPath,
			     fullPath:`${dirPath}/${name.name}`,
			     size,
			     sizeFormatted: formatBytes(size),
			     type: 'file'
			   })
		   }
		 }
		 return result
	}
	
	/**
	 * 单位转换
	 * @param {Object} bytes
	 */
	function formatBytes(bytes){
	 if (bytes === 0) return '0 B'
	 const k = 1024
	 const sizes = ['B', 'KB', 'MB', 'GB']
	 const i = Math.floor(Math.log(bytes) / Math.log(k))
	 return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
	}
	
	
	/**
	 * 将url对应的文件写入到ffmpeg环境中
	 * @param {Object} fileUrl
	 * @param {Object} filePath
	 */
	async function writeFileByUrl (fileUrl,filePath){
		const fileData = await fetchFile(fileUrl)
		await ffmpeg.writeFile(rootPath+'/'+filePath, fileData)
	}
	
	/**
	 * 写入指定字符串到指定文件
	 * @param {Object} content
	 * @param {Object} filePath
	 */
	async function writeTxtByContent (content,filePath){
		await ffmpeg.writeFile(rootPath+'/'+filePath, content)
	}
	
	/**
	 * 读取指定文件为文本
	 * @param {Object} filePath
	 */
	async function readTxtByFilePath (filePath){
		const data999 = await ffmpeg.readFile(rootPath+'/'+filePath)
		const text = new TextDecoder().decode(data999)
		return text;
	}
	
	//执行命令
	async function exec (commandArray){
		await ffmpeg.exec(commandArray)
	}
	
	/**
	 * 下载ffmpeg合成结果视频
	 * @param {Object} filePath
	 * @param {Object} fileName
	 */
	async function downloadFile (filePath,fileName){
		// 3. 读取输出文件
		const data66 = await ffmpeg.readFile(filePath)
		const blob = new Blob([data66.buffer], { type: 'video/quicktime' })
		
		// 4. 生成下载链接或播放 URL
		const url = URL.createObjectURL(blob)
		console.log('✅ 转换完成:', url)
		
		// 5. 自动触发下载
		const link = document.createElement('a')
		link.href = url
		link.download = fileName  // 下载后的文件名
		document.body.appendChild(link)
		link.click()
		
		// 6. 清理(重要!防止内存泄漏)
		document.body.removeChild(link)
		URL.revokeObjectURL(url)
		
		console.log('✅ 文件已下载到本地')
	}
	
	/**
	 * 删除指定目录下的所有文件
	 * @param {Object} dirPath
	 */
	async function deleteFile (dirPath){
		const entries = await ffmpeg.listDir(dirPath)
		
		 for (const name of entries) {
		   // 跳过当前目录和上级目录的伪条目(如果存在)
		   if (name.name === '.' || name.name === '..') continue
		
		   if(name.isDir == true){
			   const subFiles = await deleteFile(`${dirPath}/${name.name}`)
		   }else {
			   await ffmpeg.deleteFile(`${dirPath}/${name.name}`)
		   }
		 }
	}
	
	return {
		listMemfsFiles,
		writeFileByUrl,
		writeTxtByContent,
		readTxtByFilePath,
		exec,
		downloadFile,
		deleteFile
	}
}

使用示例

复制代码
<template>
	<view>
		333
	</view>
</template>

<script setup>
	import { onLoad, onUnload } from '@dcloudio/uni-app'

	import { init } from '@/utils/ffmpegUtil'
	
	onLoad(async (options) => {
		var ffmpegUtil = await init();
		
		//写入资源文件
		await ffmpegUtil.writeFileByUrl("http://192.168.1.166:9000/shanqiapph/static/ffmpeg/test.mp4","input.mp4");
		
		//写入文本到文件
		await ffmpegUtil.writeTxtByContent("45666","test.txt");
		var textA = await ffmpegUtil.readTxtByFilePath("test.txt");
		console.log(textA);
		
		//执行命令
		await ffmpegUtil.exec(['-i', '/generateVideo/input.mp4', '-c', 'copy', '/generateVideo/output.mov'])
		
		//下载合成结果
		//await ffmpegUtil.downloadFile('/generateVideo/output.mov','测试转换视频下载.mov');
		
		//删除文件
		await ffmpegUtil.deleteFile("/generateVideo");
		
		//查看所有文件
		var fileListA =  await ffmpegUtil.listMemfsFiles();
		console.table(fileListA);
	})
</script>

<style>
	       
</style>
相关推荐
可乐鸡翅yeah_4 小时前
HLS 业务 Referer‑Policy 网页元标签引发播放异常排错
前端·javascript·网络·ffmpeg·php·音视频
今年下半年6 小时前
【微信小程序】uni-app + Vue3 + Vite 的小程序项目实现「进入指定范围才能打卡」的考勤功能
微信小程序·uni-app·定位·考勤
开开心心就好1 天前
本地文件搜索工具推荐,占用小速度还快
智能手机·ffmpeg·ocr·word·音视频·网络攻击模型·安全架构
我科绝伦(Huanhuan Zhou)1 天前
oracle坏块导致备份不了
数据库·oracle·ffmpeg
RS迷途小书童1 天前
Python+FFmpeg提取大疆无人机MP4内嵌mov_text遥测SRT字幕并做完整性校验
python·ffmpeg·大疆·srt字幕·dji
开开心心就好1 天前
视频压缩工具推荐,画质效果很能打
智能手机·ffmpeg·ocr·word·排序算法·音视频·散列表
可乐鸡翅yeah_2 天前
业务中 M3U8 水印相关坑,硬水印和动态水印区别
前端·网络·数据库·ffmpeg·m3u8在线
redfred2 天前
HyperFrames 部署教程:5.6 万 Star 开源「写 HTML 出视频」框架,Windows 从零上手(CLI 三条命令 + 7 个避坑)
ffmpeg·开源·自动化·html·音视频
Arcai10242 天前
PostgreSQL数据备份和恢复完全指南
数据库·postgresql·ffmpeg·备份一体机·备份软件·smartstor·智备科技
可乐鸡翅yeah_3 天前
FFmpeg 生成 HLS 独立分片 independent‑segments 参数到底有什么用
javascript·ffmpeg·音视频·safari·m3u8