更新记录

1.2.0(2026-09-06)

  • feat: 新增鸿蒙平台(HarmonyOS NEXT / uni-app x)支持
  • feat: 鸿蒙端支持音视频命令行执行(execFFmpeg)与多任务管理(cancelcancelAlllistJobsisRunning
  • 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 插件,提供 ffmpegffprobe 的执行能力。

平台

  • Android: √(仅 arm64-v8a
  • iOS: √(deploymentTarget=13)
  • Harmony: √(HarmonyOS 5.0+ / API 12+,仅 arm64-v8a

安装

将本插件放到项目的 uni_modules/hans-ffmpeg/(或通过插件市场安装)。 Android 侧已配置远程依赖,直接通过 HBuilderX 打包即可,无需手动放置依赖包。

使用

设计为 jobId 句柄式(不返回 Task/类实例),避免跨桥序列化问题。
默认 collectOutput=truecollectLogs=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/+faststart
  • extractAudio({ 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, ... }):调整音量(volume filter),视频流直拷不重编码;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 并显式传入路径。
  • 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() 中断正在执行的任务。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

本插件调用本地音视频处理能力;默认不申请额外权限(使用外部存储/相册/相机等取决于你的业务与输入输出路径)。

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

本插件不采集用户数据。

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。