# SyFfmpeg **Repository Path**: txbhcml/sy-ffmpeg ## Basic Information - **Project Name**: SyFfmpeg - **Description**: uniapp ffmpeg - **Primary Language**: Unknown - **License**: GPL-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2026-03-12 - **Last Updated**: 2026-03-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SyFfmpegDemo - UniApp FFmpeg 音视频处理应用 SyFfmpegDemo 是一个基于 UniApp 框架开发的移动应用,集成了原生 FFmpeg 功能,提供强大的音视频处理能力。通过 SY-Ffmpeg 原生插件,实现了跨平台(Android/iOS)的音视频编辑、转换、压缩等操作。 ## 功能特性 ### 音频处理功能 (`pages/ffmpeg-cmd/audio-cmd/`) - **音频合并** - 将多个音频文件合并为一个 - **音频混音** - 同时播放多个音频并进行混合 - **音频转码** - 支持多种音频格式转换(MP3、AAC、WAV、OGG、FLAC) - **音频裁剪** - 按时间区间裁剪音频文件 ### 视频处理功能 (`pages/ffmpeg-cmd/video-cmd/`) - **视频压缩** - 智能压缩视频文件大小 - **视频转 GIF** - 将视频转换为动态 GIF - **视频镜像** - 水平和垂直镜像效果 - **视频拼接** - 多个视频文件合并为一个 - **添加水印** - 为视频添加图片或文字水印 ### 音频分割功能 (`pages/ffmpeg-cmd/audio-slice/`) - **静音检测** - 自动检测音频中的静音段落 - **智能分割** - 根据静音点自动分割音频文件 - **参数可调** - 支持自定义静音检测阈值和最小静音时长 ## 技术架构 ### 核心技术栈 - **框架**: UniApp (Vue 3 + TypeScript) - **状态管理**: Pinia - **原生插件**: SY-Ffmpeg(基于 FFmpegKit) - **构建工具**: HBuilder X ### 项目结构 ``` SyFfmpegDemo/ ├── pages/ # UniApp 页面 │ ├── index/ # 主页面导航 │ └── ffmpeg-cmd/ # FFmpeg 功能页面 │ ├── audio-cmd/ # 音频操作页面 │ ├── video-cmd/ # 视频操作页面 │ └── audio-slice/ # 音频分割页面 ├── stores/ # Pinia 状态管理 │ └── ffmpeg.ts # FFmpeg 操作核心逻辑 ├── nativeplugins/ # 原生插件 │ └── SY-Ffmpeg/ # FFmpeg 原生插件 └── static/ # 静态资源 ``` ## 快速开始 ### 环境要求 - HBuilder X 最新版本 - Android 或 iOS 开发环境 - 已配置 SY-Ffmpeg 原生插件 ### 安装依赖 ```bash npm install ``` ### 开发运行 ```bash # 开发模式 npm run dev # 生产构建 npm run build # 平台特定构建 npm run build:app-plus # App 构建 npm run build:h5 # Web 构建 npm run build:mp-weixin # 微信小程序 ``` ## 核心功能详解 ### FFmpeg 操作商店 (stores/ffmpeg.ts) 核心 FFmpeg 功能封装在 `stores/ffmpeg.ts` 中,提供以下主要方法: ```typescript // 基本 FFmpeg 命令执行 const { execFFmpegAsync } = useFfmpegStore() const result = await execFFmpegAsync([ '-i', inputPath, '-c:a', 'libmp3lame', '-b:a', '192k', outputPath ]) // 带进度回调的 FFmpeg 执行 const { execFFmpegWithProgress } = useFfmpegStore() await execFFmpegWithProgress(args, (progress) => { console.log(`处理进度: ${progress}%`) }) // 静音检测专用方法 const { execSilencedetectLogFFmpegAsync } = useFfmpegStore() const result = await execSilencedetectLogFFmpegAsync([ '-i', inputPath, '-af', 'silencedetect=noise=-40dB:d=0.6', '-f', 'null', '-' ]) // 媒体信息获取 const { getMediaInfoAsync } = useFfmpegStore() const duration = await getMediaInfoAsync(inputPath) ``` ### 音频处理示例 #### 音频合并 ```typescript const mergeAudioFiles = async () => { const selectedFiles = musicList.value.filter(music => music.selected) const inputPaths = selectedFiles.map(music => music.path.startsWith('/static/') ? plus.io.convertLocalFileSystemURL('_www' + music.path) : music.path ) const outputPath = `${plus.io.convertLocalFileSystemURL('_doc/')}/merged_audio_${Date.now()}.mp3` // 构建 FFmpeg 命令参数 let args = [] inputPaths.forEach(path => { args.push('-i', path) }) const filterComplex = Array(selectedFiles.length).fill(0) .map((_, i) => `[${i}:a]`) .join('') + `concat=n=${selectedFiles.length}:v=0:a=1[a]` args = [...args, '-filter_complex', filterComplex, '-map', '[a]', '-y', outputPath] const result = await execFFmpegAsync(args) if (result.code === 0) { // 合并成功处理逻辑 } } ``` #### 音频混音 ```typescript const mixAudioFiles = async () => { const selectedFiles = musicList.value.filter(music => music.selected) const inputPaths = selectedFiles.map(music => music.path.startsWith('/static/') ? plus.io.convertLocalFileSystemURL('_www' + music.path) : music.path ) const outputPath = `${plus.io.convertLocalFileSystemURL('_doc/')}/mixed_audio_${Date.now()}.mp3` // 构建 amix filter,自动归一化音量 const filterComplex = Array(selectedFiles.length).fill(0) .map((_, i) => `[${i}:a]`) .join('') + `amix=inputs=${selectedFiles.length}:duration=longest:normalize=1[a]` const args = [...args, '-filter_complex', filterComplex, '-map', '[a]', '-y', outputPath] const result = await execFFmpegAsync(args) if (result.code === 0) { // 混音成功处理逻辑 } } ``` ### 视频处理示例 #### 视频压缩 ```typescript const onVideoCompressArgs = () => { const vi = videos.value[selectedIndex.value] const srcPath = vi.path const desPath = plus.io.convertLocalFileSystemURL("_doc/" + new Date().getTime() + ".mp4") const args = [ '-y', '-i', srcPath, '-c:v', 'libx264', '-preset', 'veryfast', '-crf', '28', '-vf', 'scale=-2:720', '-movflags', '+faststart', '-c:a', 'aac', '-b:a', '128k', desPath ] execFFmpegWithProgress(args, (progress) => { console.log('进度:' + progress) }).then((res) => { // 压缩成功处理逻辑 }) } ``` #### 视频转 GIF ```typescript const onVideoToGif = () => { const vi = videos.value[selectedIndex.value] const srcPath = vi.path // 1. 生成调色板 const palettePath = plus.io.convertLocalFileSystemURL("_doc/" + "palette.png") const paletteArgs = [ '-i', srcPath, '-vf', 'fps=5,scale=480:-1:flags=lanczos,palettegen=max_colors=64', palettePath ] // 2. 使用调色板生成 GIF const gifArgs = [ '-ss', '00:00:00', '-t', '3', '-i', srcPath, '-i', palettePath, '-filter_complex', 'fps=8,scale=480:-1:flags=lanczos[x];[x][1:v]paletteuse', '-y', desPath ] await execFFmpegAsync(paletteArgs) await execFFmpegAsync(gifArgs) } ``` ### 音频分割示例 #### 静音检测与分割 ```typescript const detectSilence = async (index) => { const music = musicList.value[index] const inputPath = music.path.startsWith('/static/') ? plus.io.convertLocalFileSystemURL('_www' + music.path) : music.path // 使用 silencedetect 滤镜检测静音段 const args = [ '-i', inputPath, '-af', `silencedetect=noise=${noiseDb.value}dB:d=${minSilenceDuration.value}`, '-f', 'null', '-' ] const result = await execSilencedetectLogFFmpegAsync(args) // 解析静音段信息 const output = result.silencedetectLog const silenceStartRegex = /silence_start: ([\d.]+)/g const silenceEndRegex = /silence_end: ([\d.]+)/g let match let starts = [] let ends = [] while ((match = silenceStartRegex.exec(output)) !== null) { starts.push(parseFloat(match[1])) } while ((match = silenceEndRegex.exec(output)) !== null) { ends.push(parseFloat(match[1])) } // 根据静音点分割音频 splitAudio(index, starts, ends) } const splitAudio = async (index, starts, ends) => { const music = musicList.value[index] const inputPath = music.path.startsWith('/static/') ? plus.io.convertLocalFileSystemURL('_www' + music.path) : music.path const segments = [] let lastEnd = 0 // 根据静音点创建分割段 for (let i = 0; i < Math.min(starts.length, ends.length); i++) { if (starts[i] > lastEnd) { segments.push({ start: lastEnd, end: starts[i] }) } lastEnd = ends[i] } // 分割每一段 for (let i = 0; i < segments.length; i++) { const segment = segments[i] const outputPath = `${plus.io.convertLocalFileSystemURL('_doc/')}/split_${Date.now()}_${i}.mp3` const args = [ '-i', inputPath, '-ss', segment.start.toString(), '-t', (segment.end - segment.start).toString(), '-c:a', 'copy', '-y', outputPath ] await execFFmpegAsync(args) } } ``` ## 文件路径处理 应用支持多种文件路径类型: ```typescript // 静态资源路径 const staticPath = '/static/audio.mp3' const fullPath = plus.io.convertLocalFileSystemURL('_www' + staticPath) // 设备文件路径 const devicePath = plus.io.convertLocalFileSystemURL('_doc/') + 'output.mp3' // 临时文件路径 const tempPath = res.tempFilePath // 从 uni.chooseVideo 等API获取 ``` ## 错误处理 所有 FFmpeg 操作都包含完整的错误处理机制: ```typescript try { const result = await execFFmpegAsync(args) if (result.code === 0) { // 成功处理 uni.showToast({ title: '操作成功', icon: 'success' }) } else { throw new Error(result.msg) } } catch (error) { console.error('FFmpeg 操作失败:', error) uni.showToast({ title: `操作失败: ${error.message || '未知错误'}`, icon: 'none', duration: 3000 }) } ``` ## 性能优化 1. **进度显示**: 使用 `execFFmpegWithProgress` 显示处理进度 2. **文件管理**: 及时清理临时文件,避免存储空间占用 3. **错误重试**: 对于关键操作实现重试机制 4. **内存优化**: 及时释放音频上下文和临时资源 ## 原生插件集成 应用通过 SY-Ffmpeg 原生插件集成 FFmpeg 功能: ```typescript // 初始化插件 const syModule = uni.requireNativePlugin('SY-Ffmpeg') // 插件支持的方法 syModule.execFFmpegAsync({ args }, callback, logCallback) syModule.getMediaInfoAsync({ inputPath }, callback) syModule.asyncVideoCompress({ inputPath, outputPath }, callback) ``` ## 开发注意事项 1. **平台差异**: Android 和 iOS 在文件路径处理和权限方面有差异 2. **性能考虑**: 大文件处理时注意内存使用和用户体验 3. **错误处理**: 所有 FFmpeg 操作都应包含完整的错误处理 4. **用户体验**: 长时间操作应提供进度反馈 ## 贡献 欢迎提交 Issue 和 Pull Request 来改进项目。 ## 联系方式 如有问题请通过项目 Issue 页面联系我们。 ## Android apk包 [SyFfmpegDemo](https://gitee.com/paupan/sy-ffmpeg/blob/main/unpackage/debug/android_debug.apk) ## [开源地址](https://gitee.com/paupan/sy-ffmpeg) ## 版本记录: ### 1.0 【FFmpeg 插件 for uni-app|v1.0.0 更新日志】 2025-10-29 1. 首版发布 - 基于 FFmpeg 6.0-1 GPL 全功能裁剪。 - 支持 H.264/H.265、AV1、MP3、AAC、OPUS 等 30+ 主流编解码。 - 提供同步 & 异步双端 API,一套代码同时跑在 App-Android、App-iOS。 2. 核心能力 - 音视频合成:多轨道拼接、精确到帧级裁剪(-ss/to)。 - 封面提取:获取任意时刻 JPEG/WEBP 缩略图。 - 水印 & 滤镜:支持文字、PNG、GIF 动态水印。 - 音频静音检测,分段分割; 3. uni-app 专属优化 - 原生插件自动集成,无需手动拷 so;云打包/离线打包均通过。 - 支持 vue3