更新记录
1.2.0(2026-09-06)
- feat: 新增鸿蒙平台(HarmonyOS NEXT / uni-app x)支持
- feat: 鸿蒙端支持音视频命令行执行(
execFFmpeg)与多任务管理(cancel、cancelAll、listJobs、isRunning) - feat: 鸿蒙端支持获取音视频媒体信息(
getMediaInfo) - feat: 鸿蒙端支持视频压缩、裁剪、变速、拼接、加水印、抽音频、导出 GIF 等全量音视频处理封装函数(Recipes)
1.1.1(2026-08-29)
- fix: 对齐 Android/iOS 任务取消行为,
cancel(jobId)支持取消指定任务,cancelAll()支持取消全部任务 - fix: 修复音频混音、媒体信息获取及临时文件处理问题
- change: 优化 Android 存储路径与 ABI 配置,提升 uni-app 和 uni-app x 兼容性
1.0.1(2026-06-16)
- fix(android): 改为使用远程 Maven 仓库解析
ffmpeg-kit,避免本地 AAR 导致云打包体积超限
平台兼容性
uni-app(4.87)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | - | - | - | - | √ | √ | √ |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
uni-app x(4.87)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| - | - | √ | √ | √ | - |
hans-ffmpeg
基于 FFmpegKit (full-gpl) 封装的 uni-app / uni-app x UTS 插件,提供 ffmpeg 与 ffprobe 的执行能力。
平台
- Android: √(仅
arm64-v8a) - iOS: √(deploymentTarget=13)
- Harmony: √(HarmonyOS 5.0+ / API 12+,仅
arm64-v8a)
安装
将本插件放到项目的 uni_modules/hans-ffmpeg/(或通过插件市场安装)。
Android 侧已配置远程依赖,直接通过 HBuilderX 打包即可,无需手动放置依赖包。
使用
设计为 jobId 句柄式(不返回 Task/类实例),避免跨桥序列化问题。
默认collectOutput=true、collectLogs=true,长任务可能产生日志/输出大字符串,注意内存占用。 以下示例面向 uni-app x 的<script setup lang="uts">。调用本插件时,建议像 playground 一样显式声明 Options、回调参数、返回结果和任务集合类型,避免对象字面量被推导为UTSJSONObject;官方uni.*API 不要求额外声明类型。
import {
setLogEnabled, getVersion, getWorkDir, execFFmpeg, execFFprobe,
cancel, cancelAll, isRunning, listJobs, dispose,
compressVideo, extractAudio, snapshot, trimVideo, remux, replaceAudio, probeMediaInfoJson,
concatVideos, convertFormat, removeAudio, exportGif, setSpeed, adjustVolume,
rotateVideo, cropRegion, addImageWatermark, addTextWatermark, mixAudio, getMediaInfo,
HansFFmpegExecOptions, HansFFprobeExecOptions,
HansFFmpegExecResult, HansFFprobeExecResult, HansFFmpegFail,
HansFFmpegLogEvent, HansFFmpegProgressEvent,
HansFFmpegCompressVideoOptions, HansFFprobeMediaInfoJsonOptions,
HansFFmpegConcatVideosOptions, HansFFmpegGetMediaInfoOptions,
HansFFmpegMediaInfo
} from '@/uni_modules/hans-ffmpeg'
公开类型与函数都从 @/uni_modules/hans-ffmpeg 导入,不要直接引用 utssdk/interface.uts 或平台目录。
getVersion(): HansFFmpegKitVersion
返回 FFmpegKit 与 FFmpeg 版本信息。
getWorkDir(): string
返回一个可写目录(Android App 私有 files/hans-ffmpeg / iOS Library/Caches),便于在 demo 中构造输入输出路径。Android 目录不会被经典运行时的 cache 清理移除,卸载 App 或清除应用数据时会删除。
setLogEnabled(options: HansFFmpegSetLogEnabledOptions): void
插件内部日志开关(默认关闭)。开启后会在关键节点输出 console.info,便于排查问题。
execFFmpeg(options: HansFFmpegExecOptions): string
options.args: string[]:参数数组(不需要自己拼 command string)- 回调:
onLog({jobId, level, message})onProgress({jobId, timeMs, size, bitrate, speed, videoFrameNumber})success(res)/fail(err)/complete(any)
- 可选流控:
logIntervalMs/progressIntervalMs(>0 时按间隔节流回调)
execFFprobe(options: HansFFprobeExecOptions): string
建议使用 -print_format json 并在 success(res.output) 中解析 JSON。
cancel(jobId: string) / cancelAll() / isRunning(jobId: string) / listJobs() / dispose(jobId: string)
cancel: 请求取消指定任务(Android/iOS 均按对应 FFmpegKit session 取消)cancelAll: 取消全部运行中的任务isRunning: 是否运行中listJobs: 当前跟踪的任务列表{ jobId, state, isRunning }[];dispose后不再出现dispose: 清理内部句柄
API 与类型对照
基础 API
| API | 参数类型 | 返回类型 |
|---|---|---|
setLogEnabled(options) |
HansFFmpegSetLogEnabledOptions |
void |
getVersion() |
无 | HansFFmpegKitVersion |
getWorkDir() |
无 | string |
execFFmpeg(options) |
HansFFmpegExecOptions |
string(jobId) |
execFFprobe(options) |
HansFFprobeExecOptions |
string(jobId) |
cancel(jobId) |
string |
boolean |
cancelAll() |
无 | boolean |
isRunning(jobId) |
string |
boolean |
listJobs() |
无 | HansFFmpegJobListItem[] |
dispose(jobId) |
string |
boolean |
Recipes API
所有异步 recipe 仍返回 string 类型的 jobId。
| API | Options 类型 | success 参数类型 |
|---|---|---|
compressVideo |
HansFFmpegCompressVideoOptions |
HansFFmpegExecResult |
extractAudio |
HansFFmpegExtractAudioOptions |
HansFFmpegExecResult |
snapshot |
HansFFmpegSnapshotOptions |
HansFFmpegExecResult |
trimVideo |
HansFFmpegTrimVideoOptions |
HansFFmpegExecResult |
remux |
HansFFmpegRemuxOptions |
HansFFmpegExecResult |
replaceAudio |
HansFFmpegReplaceAudioOptions |
HansFFmpegExecResult |
probeMediaInfoJson |
HansFFprobeMediaInfoJsonOptions |
HansFFprobeExecResult |
concatVideos |
HansFFmpegConcatVideosOptions |
HansFFmpegExecResult |
convertFormat |
HansFFmpegConvertFormatOptions |
HansFFmpegExecResult |
removeAudio |
HansFFmpegRemoveAudioOptions |
HansFFmpegExecResult |
exportGif |
HansFFmpegExportGifOptions |
HansFFmpegExecResult |
setSpeed |
HansFFmpegSetSpeedOptions |
HansFFmpegExecResult |
adjustVolume |
HansFFmpegAdjustVolumeOptions |
HansFFmpegExecResult |
rotateVideo |
HansFFmpegRotateVideoOptions |
HansFFmpegExecResult |
cropRegion |
HansFFmpegCropRegionOptions |
HansFFmpegExecResult |
addImageWatermark |
HansFFmpegAddImageWatermarkOptions |
HansFFmpegExecResult |
addTextWatermark |
HansFFmpegAddTextWatermarkOptions |
HansFFmpegExecResult |
mixAudio |
HansFFmpegMixAudioOptions |
HansFFmpegExecResult |
getMediaInfo |
HansFFmpegGetMediaInfoOptions |
HansFFmpegMediaInfo |
公共回调类型
| 回调 | 参数类型 |
|---|---|
onLog |
HansFFmpegLogEvent |
onProgress |
HansFFmpegProgressEvent |
FFmpeg success |
HansFFmpegExecResult |
FFprobe success |
HansFFprobeExecResult |
getMediaInfo success |
HansFFmpegMediaInfo |
fail |
HansFFmpegFail |
complete |
any |
常用封装(recipes)
这层 API 仍然是 jobId 句柄式,并复用
execFFmpeg/execFFprobe的回调能力(onLog//success/fail/complete等)。 除特别说明外,输出为 mp4/mov/m4v/m4a 时默认追加-movflags +faststart;视频重编码默认libx264 + veryfast + crf28 + yuv420p,音频默认aac 128k。 参数校验失败(如空路径、非法枚举值)时统一走空 args 执行,回调收到 errCode=9020101(invalid args)。
compressVideo({ input, output, ... }):常用压缩/转码(默认 H.264 + AAC),支持crf/preset/scale/fps/+faststartextractAudio({ input, output, ... }):抽取音频(默认 aac;输出为 mp3/wav 会自动选 codec)snapshot({ input, output, timeMs, ... }):截帧生成封面图trimVideo({ input, output, startMs, durationMs|endMs, copyCodec, ... }):裁剪片段(默认copyCodec=true)remux({ input, output, ... }):转封装(-c copy)replaceAudio({ videoInput, audioInput, output, ... }):替换音轨(默认视频流 copy)probeMediaInfoJson({ input, ... }):输出媒体信息 JSON(等价于常用的ffprobe -print_format json -show_format -show_streams)
v1.1.0 新增
concatVideos({ inputs: string[], output, copyCodec, withAudio, ... }):拼接多段视频copyCodec=true(默认):concat demuxer + stream copy,要求各输入编码参数一致(否则可能花屏);插件会写一个临时 list 文件并在结束后自动清理copyCodec=false:concat filter 重编码,任意输入可拼;withAudio=false可拼接无音轨输入
convertFormat({ input, output, ... }):格式转换(按输出扩展名推断 codec:.webm→libvpx+libopus、.avi→mpeg4+mp3、其余 libx264+aac)removeAudio({ input, output, ... }):去音轨(-an -c:v copy,秒级完成)exportGif({ input, output, startMs, durationMs, fps=10, width=480, loop=0, ... }):导出 GIF(palettegen/paletteuse 两段式调色板,单条命令完成)setSpeed({ input, output, speed: 0.25~4.0, muteAudio, ... }):变速(setpts+atempo链式拆分),需要重编码视频adjustVolume({ input, output, volume, ... }):调整音量(volumefilter),视频流直拷不重编码;volume=0即静音rotateVideo({ input, output, degrees: 90|180|270, ... }):旋转画面,同时清除容器旋转 metadata 避免播放器二次旋转cropRegion({ input, output, x, y, width, height, ... }):画面区域裁剪(宽高自动向下取偶数保证 yuv420p 兼容)addImageWatermark({ input, watermarkImage, output, x=12, y=12, scalePercent=0, opacity=1.0, ... }):图片水印(overlay,支持透明度与等比缩放;原音轨保留)addTextWatermark({ input, text, output, fontPath?, fontSize=24, fontColor='white', x?, y?, ... }):文字水印(drawtext,text 自动转义:'\%)- fontfile:不传
fontPath时依赖 FFmpeg fontconfig;Android 可使用系统字体,iOS 已在 FFmpegKit 环境验证可直接执行。若需稳定覆盖中文或指定字形,仍建议随应用打包 ttf 并显式传入路径。
- fontfile:不传
mixAudio({ audioInputA, audioInputB, output, volumeA=1.0, volumeB=1.0, durationPolicy='longest'|'shortest'|'first', ... }):双路音频混音(amix,normalize=0保持各自增益)-
getMediaInfo({ input, success(res) }):获取结构化媒体信息(包含时长、分辨率、码率、流信息等):type HansFFmpegMediaInfoVideoStream = { codec: string; width: number; height: number; fps: number; pixelFormat: string; rotation: number; bitrateK: number; }; type HansFFmpegMediaInfoAudioStream = { codec: string; sampleRate: number; channels: number; bitrateK: number; }; type HansFFmpegMediaInfo = { jobId: string; durationMs: number; sizeBytes: number; bitrateK: number; containerName: string; video: HansFFmpegMediaInfoVideoStream | null; audioList: HansFFmpegMediaInfoAudioStream[]; rawJson: string; };解析是 best-effort:字段缺失落回零值,
rawJson始终可用。
示例(playground 推荐用例)
生成 1 秒测试视频(无需外部输入文件)
const outputPath: string = getWorkDir() + '/hans-ffmpeg-test.mp4'
const options: HansFFmpegExecOptions = {
args: ['-y', '-f', 'lavfi', '-i', 'testsrc=size=320x240:rate=25', '-t', '1', '-pix_fmt', 'yuv420p', outputPath],
onLog: (event: HansFFmpegLogEvent) => console.log(event.message),
: (event: HansFFmpegProgressEvent) => console.log('timeMs', event.timeMs),
success: (res: HansFFmpegExecResult) => console.log('ok', res.returnCode, res.output ?? ''),
fail: (err: HansFFmpegFail) => console.error(err.errCode, err.errMsg, JSON.stringify(err.data)),
}
const currentJobId: string = execFFmpeg(options)
ffprobe 输出 JSON
const probeOptions: HansFFprobeExecOptions = {
args: ['-v', 'error', '-print_format', 'json', '-show_format', '-show_streams', outputPath],
success: (res: HansFFprobeExecResult) => console.log(res.output ?? ''),
fail: (err: HansFFmpegFail) => console.error(err.errCode, err.errMsg),
}
const probeJobId: string = execFFprobe(probeOptions)
使用封装函数(示例)
const inputPath: string = outputPath
const compressedPath: string = getWorkDir() + '/hans-ffmpeg-compressed.mp4'
const compressOptions: HansFFmpegCompressVideoOptions = {
input: inputPath,
output: compressedPath,
maxWidth: 720,
crf: 28,
preset: 'veryfast',
: (event: HansFFmpegProgressEvent) => console.log('timeMs', event.timeMs),
success: (res: HansFFmpegExecResult) => console.log('ok', res.returnCode),
fail: (err: HansFFmpegFail) => console.error(err.errCode, err.errMsg),
}
const compressJobId: string = compressVideo(compressOptions)
const mediaJsonOptions: HansFFprobeMediaInfoJsonOptions = {
input: compressedPath,
success: (res: HansFFprobeExecResult) => console.log(res.output ?? ''),
fail: (err: HansFFmpegFail) => console.error(err.errCode, err.errMsg),
}
const mediaJsonJobId: string = probeMediaInfoJson(mediaJsonOptions)
结构化媒体信息与拼接(v1.1.0)
const mediaInfoOptions: HansFFmpegGetMediaInfoOptions = {
input: inputPath,
success: (info: HansFFmpegMediaInfo) => {
const videoWidth: number = info.video?.width ?? 0
const videoFps: number = info.video?.fps ?? 0
console.log(info.durationMs, videoWidth, videoFps, info.audioList.length)
},
fail: (err: HansFFmpegFail) => console.error(err.errCode, err.errMsg),
}
const mediaInfoJobId: string = getMediaInfo(mediaInfoOptions)
const clipPaths: string[] = [inputPath, inputPath]
const mergedPath: string = getWorkDir() + '/hans-ffmpeg-merged.mp4'
const concatOptions: HansFFmpegConcatVideosOptions = {
inputs: clipPaths,
output: mergedPath,
copyCodec: true, // stream copy 要求输入文件的编码参数一致
success: (res: HansFFmpegExecResult) => console.log('ok', res.returnCode),
fail: (err: HansFFmpegFail) => console.error(err.errCode, err.errMsg),
}
const concatJobId: string = concatVideos(concatOptions)
注意事项
args需要按 token 传入(例如['-i', input, '-c:v', 'libx264', output]),不要自己拼整条字符串命令。- 长任务建议根据需要关闭
collectOutput/collectLogs,避免内存占用过大。 trimVideo参数名为copyCodec(避免 iOS 侧与copy产生 selector 冲突)。- 本插件 Android / iOS 依赖
FFmpegKit full-gpl,发布/分发前请确认许可证合规要求。 - 鸿蒙平台说明:
- 支持架构:仅支持
arm64-v8a(需在真机或 ARM64 模拟器上运行,不支持 x86 模拟器); - 系统版本要求:HarmonyOS 5.0+(API 12+);
- 路径规范:输入和输出路径支持普通应用文件路径与
file://URI; - 媒体信息:在鸿蒙端推荐使用
getMediaInfo获取视频/音频参数信息; - 任务控制:支持通过
cancel(jobId)或cancelAll()中断正在执行的任务。
- 支持架构:仅支持

收藏人数:
购买源码授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 392
赞赏 0
下载 12592701
赞赏 1949
赞赏
京公网安备:11010802035340号