更新记录
1.0.0(2026-11-11)
1.0.0(2026-11-11)
- 首次发布:uni-app x 双端本地视频合成插件
- 支持花字、字幕渲染(关键词高亮、描边、背景)
- 支持画中画图片叠加
- 支持片头封面(静态图或首帧定格 1 秒)
- 支持背景音乐混音与淡入淡出
- 支持 480p / 720p / 1080p 按短边缩放导出 MP4
- 支持合成进度回调、取消合成
- Android 基于 MediaCodec / MediaMuxer,iOS 基于 AVFoundation,无需 ffmpeg、无需自定义基座
平台兼容性
synthetic-video 本地视频合成
uni-app x 原生 UTS 插件,用于在 App 端本地完成视频合成:花字、字幕、画中画、片头封面、背景音乐混音、分辨率缩放,最终导出 H.264 MP4。
- Android:
MediaCodec+MediaMuxer硬编硬解 - iOS:
AVFoundation+AVAssetExportSession - 零第三方依赖,不需要 ffmpeg,不需要服务端参与
- 只读写 App 沙盒临时文件,不申请相册权限
平台兼容性
| 平台 | 支持 | 说明 |
|---|---|---|
| uni-app x / App-Android | √ | 5.24 及以上 |
| uni-app x / App-iOS | √ | 5.24 及以上 |
| Web / H5 | × | 返回 9100402 |
| 小程序 | × | 不支持 |
| 传统 uni-app(Vue2 / Vue3) | × | 仅支持 uni-app x |
安装
- 将
synthetic-video目录放入项目的uni_modules下。 - 确认项目的 uni-app x 版本不低于
5.24(见package.json的engines)。 - 不需要在
manifest.json中额外声明权限。
快速开始
import { probeVideo, composeVideo, cancelCompose } from '@/uni_modules/synthetic-video'
// 1. 读取视频信息
const info = await probeVideo({ filePath: videoPath })
if (info.errorCode != 0) {
console.log('读取失败', info.errorMessage)
}
// 2. 合成
let taskId = ''
const result = await composeVideo({
videoPath,
texts: [
{
text: '标题文字',
style: titleStyle,
startSec: 0,
durationSec: 5,
isTitle: true
}
],
overlays: [],
keywords: ['关键词'],
canvasWidth: 720,
canvasHeight: 1280,
bgmPath: null,
bgmVolume: 20,
introCoverPath: null,
resolution: '720p',
outputPath: null,
onStart: (id : string) => {
taskId = id
},
onProgress: (p) => {
console.log(p.stage, p.percent)
}
})
if (result.errorCode == 0) {
console.log('成片路径', result.filePath)
} else {
console.log('合成失败', result.errorCode, result.errorMessage)
}
// 3. 取消(可选)
// await cancelCompose({ taskId })
选择素材时建议使用
uni.chooseVideo({ compressed: false })。默认的compressed: true会先生成 360p / 540p 的临时文件,再合成也无法恢复清晰度。
API
所有 API 均返回 Promise,结果对象包含 errorCode 和 errorMessage,errorCode == 0 表示成功。业务失败通过 errorCode 返回,不会主动 reject。
probeVideo
读取视频宽高与时长,宽高已按旋转元数据校正。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| filePath | string | 是 | 本地视频路径,支持 file:// 前缀或沙盒绝对路径 |
返回 ProbeVideoResult:
| 字段 | 类型 | 说明 |
|---|---|---|
| errorCode | number | 0 表示成功 |
| errorMessage | string | 错误信息 |
| width | number | 视频宽(像素) |
| height | number | 视频高(像素) |
| durationSec | number | 时长(秒,保留 3 位小数) |
renderTextImage
渲染单张透明花字 PNG,用于页面实时预览。样式与成片共用同一套绘制逻辑。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| text | string | 是 | 文字内容 |
| style | ComposeTextStyle | 是 | 花字样式 |
| canvasWidth | number | 是 | 目标画布宽,用于字号换算与断行 |
| canvasHeight | number | 是 | 目标画布高,用于位置换算 |
| keywords | string[] | 是 | 高亮关键词,仅影响着色 |
| outputPath | string | null | 否 | 输出 PNG 路径,null 时输出到临时目录 |
返回 RenderTextImageResult:
| 字段 | 类型 | 说明 |
|---|---|---|
| errorCode | number | 0 表示成功 |
| errorMessage | string | 错误信息 |
| filePath | string | 生成的透明 PNG 绝对路径 |
| width | number | PNG 宽 |
| height | number | PNG 高 |
| x | number | PNG 左上角在画布中的横坐标 |
| y | number | PNG 左上角在画布中的纵坐标 |
| canvasWidth | number | 所属画布宽 |
| canvasHeight | number | 所属画布高 |
composeVideo
执行完整本地合成:渲染花字 → 叠加画中画 → 缩放 → 混音 → 插入片头 → 导出。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| videoPath | string | 是 | 正片本地路径 |
| texts | ComposeTextItem[] | 是 | 花字数组,可为空数组 |
| overlays | UTSJSONObject[] | 是 | 画中画叠加层,可为空数组 |
| keywords | string[] | 是 | 高亮关键词,可为空数组 |
| canvasWidth | number | 是 | 输出画布宽,必须大于 0 |
| canvasHeight | number | 是 | 输出画布高,必须大于 0 |
| bgmPath | string | null | 否 | 背景音乐本地路径,null 表示不混音 |
| bgmVolume | number | 否 | BGM 音量档:15 / 20 / 25 / 30,默认 20 |
| introCoverPath | string | null | 否 | 片头封面路径,null 时使用正片首帧定格 1 秒 |
| resolution | string | 是 | 480p / 720p / 1080p,仅做档位校验与日志 |
| outputPath | string | null | 否 | 输出路径,null 时输出到 App 临时目录 |
| onStart | (taskId: string) => void | null | 否 | 任务启动回调,返回 taskId |
| onProgress | (res: ComposeProgress) => void | null | 否 | 进度回调 |
ComposeTextItem:
| 字段 | 类型 | 说明 |
|---|---|---|
| text | string | 文字内容 |
| style | ComposeTextStyle | 样式 |
| startSec | number | 出现时间(秒,相对正片起点) |
| durationSec | number | 持续时长(秒) |
| isTitle | boolean | 是否为标题 |
ComposeTextStyle:
| 字段 | 类型 | 说明 |
|---|---|---|
| enabled | boolean | 是否渲染该条花字 |
| font | string | yahei / simhei / kaiti / simsun / youyuan / lisu / alimama |
| position | string | top / center(字幕)/ bottom |
| color | string | 字色,形如 #FFFFFF |
| font_gradient | boolean | 是否启用字体渐变 |
| font_color2 | string | 渐变结束色 |
| keyword_effect | boolean | 是否高亮关键词 |
| highlight_color | string | 关键词高亮色 |
| font_size | number | 设计字号,以 720 宽为基准等比换算 |
| vertical_offset | number | 垂直微调,-15 ~ 15(画面高度百分比) |
| show_seconds | number | 显示时长(秒),0 表示按时间轴/整片显示 |
| effect | string | fade / slide / none |
| background | string | 背景色 |
| bg_effect | string | none / translucent / solid |
| bg_gradient | boolean | 是否启用背景渐变 |
| bg_color2 | string | 背景渐变结束色 |
| outline | string | 描边色,空字符串表示按字色自动取对比色 |
| outline_width | number | 描边粗细 0 ~ 8,0 表示关闭 |
| shadow | number | 阴影强度 0 ~ 8,0 表示关闭 |
overlays 每项字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| filePath | string | 图片或视频的本地路径 |
| type | string | image / video,默认 image |
| startSec | number | 出现时间(秒,相对正片起点) |
| durationSec | number | 持续时长(秒) |
| aspect | number | 宽高比 width / height,用于等比计算高度 |
层级顺序:正片 → 画中画 → 花字。
ComposeProgress:
| 字段 | 类型 | 说明 |
|---|---|---|
| stage | string | prepare / renderTexts / composeVideo / mixAudio / intro / alignAudio / finalize |
| percent | number | 0 ~ 100 |
返回 ComposeVideoResult:
| 字段 | 类型 | 说明 |
|---|---|---|
| errorCode | number | 0 表示成功 |
| errorMessage | string | 错误信息 |
| filePath | string | 成片绝对路径 |
| durationSec | number | 成片时长(秒,含片头) |
| width | number | 成片宽 |
| height | number | 成片高 |
| hasIntro | boolean | 是否插入了片头 |
| hasBgm | boolean | 是否混入了背景音乐 |
cancelCompose
取消正在进行的合成,取消后插件会清理临时文件。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| taskId | string | 是 | composeVideo 的 onStart 回调返回的 taskId |
返回 CancelComposeResult:errorCode、errorMessage、ok(是否成功发出取消指令)。
compressVideo
本地受控压缩,用于上传前把素材压成统一规格。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| filePath | string | 是 | 本地视频路径 |
| maxLongSide | number | 是 | 目标长边上限(像素),<= 0 不限制 |
| bitrate | number | 是 | 目标码率(bps),<= 0 由插件自动估算 |
| fps | number | 是 | 目标帧率,<= 0 跟随源视频 |
| keepAudio | boolean | 是 | 是否保留音轨 |
| outputPath | string | null | 否 | 输出路径,null 时输出到临时目录 |
| onStart | (taskId: string) => void | null | 否 | 任务启动回调 |
| onProgress | (res: ComposeProgress) => void | null | 否 | 进度回调 |
返回 CompressVideoResult:errorCode、errorMessage、filePath、width、height、durationSec、sizeBytes。
错误码
| 错误码 | 常量 | 说明 |
|---|---|---|
| 9100101 | COMPOSE_ERR_VIDEO_NOT_FOUND | 输入视频不存在或不可读 |
| 9100102 | COMPOSE_ERR_INVALID_PARAMS | 参数非法 |
| 9100201 | COMPOSE_ERR_RENDER_TEXT_FAILED | 花字渲染失败 |
| 9100202 | COMPOSE_ERR_FONT_LOAD_FAILED | 字体加载失败 |
| 9100301 | COMPOSE_ERR_COMPOSE_FAILED | 合成失败 |
| 9100302 | COMPOSE_ERR_CANCELED | 已取消 |
| 9100303 | COMPOSE_ERR_OUTPUT_WRITE_FAILED | 输出写入失败 |
| 9100304 | COMPOSE_ERR_TIMEOUT | 合成超时 |
| 9100305 | COMPOSE_ERR_COMPRESS_FAILED | 压缩失败 |
| 9100401 | COMPOSE_ERR_IOS_NOT_IMPLEMENTED | 历史保留错误码 |
| 9100402 | COMPOSE_ERR_PLATFORM_NOT_SUPPORTED | 当前平台不支持 |
注意事项
- 输出尺寸以画布为准:
resolution只做合法性校验;实际输出宽高由canvasWidth/canvasHeight决定。 - 不放大低分辨率素材:画布大于源视频时按 1 倍处理,不会插值放大。
- BGM 是混音,不是替换:填入
bgmPath后原声仍然保留,BGM 按bgmVolume增益叠加,并带淡入淡出。当前版本没有“静音原声”参数。 - BGM 路径必须真实存在:路径错误或解码失败时会跳过 BGM,保留原声。
- 片头规则:
introCoverPath为null时使用正片首帧定格 1 秒;传入封面时按封面图生成 1 秒片头。 - 不自动保存相册:
outputPath为null时成片在 App 临时目录,需要调用方自行调用uni.saveVideoToPhotosAlbum。 - Android 码率:按
宽 × 高 × 帧率 × 0.2计算,限制在 2 ~ 24 Mbps;1080p30 约 12.4 Mbps。 - iOS 导出:使用
AVAssetExportPresetHighestQuality,由系统决定码率,通常高于 Android。 - 临时文件:取消或失败时插件会尽力清理本次任务的临时文件,页面侧可定期清理缓存目录。
- H5 / 小程序:不支持本地合成,调用返回
9100402。
更新日志
1.0.0(2026-11-11)
- 首次发布
- 支持花字、字幕渲染(关键词高亮、描边、背景)
- 支持画中画图片 / 视频叠加
- 支持片头封面(静态图或首帧定格 1 秒)
- 支持背景音乐混音与淡入淡出
- 支持
480p/720p/1080p导出 - 支持合成进度回调与取消
- 支持本地受控压缩
compressVideo

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 6
赞赏 1
下载 12757563
赞赏 1959
赞赏
京公网安备:11010802035340号