体验升级!Beauty AR SDK 4.0全新功能,带来更流畅、更炫酷的AR效果!

使用美颜处理视频

概述

ArRecorderSdk 是 SDK 2.0.3 起新增的离线美颜能力,用于对已有的 mp4 文件或在线视频 URL 二次处理,加美颜、特效、滤镜等效果,并导出一份新的 mp4 文件。与实时模式的 ArSdk 不同,ArRecorderSdk 特点如下:
不依赖摄像头/直播流,处理本地或远端的录播 mp4。
串行 await 每一帧,不丢帧,处理时长视设备性能,性能越好处理越快。
音频原样透传,不解码不重编码。
视频走 WebCodecs 硬解硬编(不做软解兜底)。

使用场景

UGC 视频上传前的本地美颜.
对已经录制好的 mp4 批量增加滤镜或贴纸特效。
实现"先录制再美颜"的工作流。

注意事项

浏览器要求

必须支持 WebCodecs(VideoEncoder / VideoDecoder):
Chrome 102+ 或 Edge 102+。
Safari、移动端浏览器不满足要求。
大文件输出(> 200 MB)建议浏览器支持 File System Access API(Chrome / Edge 桌面版),否则会回退到内存模式,超过 ~1.5 GB 可能 OOM。

使用注意

不可与 ArSdk 共存:同页面同时实例化 ArSdkArRecorderSdk 会因共享 AROptionsManager 单例发生状态污染。如需在两者间切换,务必先 destroy() 已有实例。
导出期间锁定参数process() 进行中调用 setBeautify / setEffect / setFilter 会报错。如需在导出第一帧前完成参数设置,请监听 beforeRun 事件并在 handler 里 await 设置:
recorder.on('beforeRun', async ({ mode }) => {
await recorder.setEffect({ id: 'xxx', intensity: 0.5 })
})
首次调用懒加载:构造时如果未传 beautify,运行期首次 setBeautify / setEffect 会触发管线懒加载(mediapipe + wasm,约 2-3 秒)。如希望第一帧立即带特效,请在构造时传 beautify,让 init() 阶段一并预热。
WebCodecs 错误兜底:浏览器不支持 VideoEncoder / VideoDecoder 时,构造阶段会通过 error 事件抛出 ENVIRAONMENT_NOT_COMPATIBLE,请提前用环境检测屏蔽。
音频不重编码:源视频音频会原样透传到输出 mp4,处理过程中不重新编码。

Demo 下载

完整 Demo 参考 recorder-demo.zip

引入方式

ArRecorderSdkArSdk 同源同包,从同一个 npm 包按需引入即可:
import { ArRecorder } from 'tencentcloud-webar'

const recorder = new ArRecorder.ArRecorderSdk({
auth: { licenseKey, appId, authFunc },
beautify: { whiten: 0.3, dermabrasion: 0.5 },
})
注意:
同一个页面不要同时实例化 ArSdkArRecorderSdk,否则会互相污染状态。可以先 destroy() 一个再实例化另一个。

完整示例

import { ArRecorder } from 'tencentcloud-webar'

async function processVideo(file) {
const recorder = new ArRecorder.ArRecorderSdk({
auth: {
licenseKey: 'YOUR_LICENSE_KEY',
appId: 'YOUR_APP_ID',
authFunc: yourAuthFunc, // 与 ArSdk 同样的鉴权回调
},
beautify: {
whiten: 0.3,
dermabrasion: 0.5,
},
})

// 1. 鉴权 + 预热处理管线
await recorder.init()

// 2. 运行期可继续设置美颜/特效/滤镜
await recorder.setBeautify({ whiten: 0.5, lift: 0.2 })
await recorder.setEffect({ id: 'effectId', intensity: 0.7 })
await recorder.setFilter('filterId', 0.5)

// 3. 处理
const result = await recorder.process(file, {
onProgress: (current, total) => {
console.log(`已处理 ${current}/${total} 帧`)
},
})

// 4. 拿到结果
if (result.mode === 'in-memory') {
const url = URL.createObjectURL(result.blob)
document.querySelector('video').src = url
} else {
// file 模式:已直接写入用户选择的磁盘文件
const file = await result.fileHandle.getFile()
}

// 5. 清理资源
recorder.destroy()
}

构造参数

new ArRecorder.ArRecorderSdk(options) 接受以下配置:
参数
说明
类型
是否必传
auth
鉴权参数,结构同 ArSdk
{
licenseKey: string
appId: string
sdkAppId?: string
authFunc: () => Promise<{ signature, timestamp }>
language?: string
}
beautify
美颜参数,结构同 ArSdk 的 BeautifyOptions。
不传时 init 阶段不会预热 detect+render 链路(节省加载时间),但运行期首次调用 setBeautify / setEffect 会触发懒加载(约 2-3 秒)。
BeautifyOptions
module
模块配置,结构同 ArSdk 的 ModuleConfig。
Recorder 当前实际消费 faceDetectModel 字段;其余字段(segmentation / handLandmark 等)保留同样字段名以便迁移配置,但不会生效。
{
faceDetectModel?: 'short' | 'full'
// 其它 ArSdk 同名字段保留兼容,但不消费
}
output
输出 mp4 编码配置
{
codec?: 'avc' // 当前仅支持 H.264
bitrate?: number | 'auto' // bps,'auto' 跟随源视频
fps?: number | 'auto' // 'auto' 跟随源视频
}
initReport
是否初始化日志上报模块
Boolean
否,默认 true

对象方法

接口
参数
返回
说明
async init()
-
Promise
鉴权 + 预热处理管线。构造时传了 beautify 时一并预热 detect+render 链路,第一帧不会再卡 2-3 秒。
async process(source, options?)
source:Blob | File | string,本地文件或在线 URL(CORS 必须允许)
options:见"process 参数"
Promise
对源视频做离线美颜处理,导出新的 mp4。处理过程中禁止再调 set* 接口。
async setBeautify(options)
BeautifyOptions(同 ArSdk)
Promise
热更新美颜参数,下一帧立即生效。导出期间(process 进行中)禁止调用。
async setEffect(input)
input:特效 ID | Effect 对象 | (特效 ID | Effect 对象) 数组 | 空数组(清空)
参数风格同 ArSdk 的 setEffect
Promise
设置/切换/清空特效(滤镜 / 贴纸 / 美妆 / 3D 试戴)。导出期间禁止调用。
async setFilter(id?, intensity?)
id:滤镜 ID。缺省 / '' / 'none' 等于清除当前滤镜
intensity:滤镜强度 0-1,默认 1
Promise
独立设置滤镜,与 setEffect 走不同通道(互斥滤镜)。导出期间禁止调用。
startPreview(source)
source:HTMLVideoElement | MediaStream
MediaStream
启动实时预览,返回处理后的 MediaStream,业务方设置到 `.srcObject` 即可。源视频 element 的播放/暂停/拖动会自动同步到预览。
stopPreview()
-
-
停止预览循环并释放资源。process() 执行前会自动调用
destroy()
-
-
销毁实例,释放 detector / renderer / GPU 资源。同页面切换到 ArSdk 之前必须先 destroy。

process 参数

process(source, options)options 字段:
参数
说明
类型
signal
AbortSignal,用于业务方主动取消。
AbortSignal
onProgress
编码进度回调。current 为已编码完成的帧数,total 为总帧数。回调在编码完成时触发,避免出现"100% 后还要再等几分钟" 的卡死错觉。
(current: number, total: number) => void
onDownloadProgress
URL 输入时的下载进度。total = -1 表示服务端未返回 Content-Length。
(loaded: number, total: number) => void
stallTimeoutMs
URL 模式下,超过该毫秒数未收到新字节判定为网络卡死,主动 abort。默认 30000,设为 0 关闭检测。
Number
mode
输出模式:
'in-memory':内存中累积整个 mp4,finalize 时返回 Blob。受 V8 单 buffer 上限(~1.5-2 GB)。
'file':流式写入用户磁盘文件,需要 File System Access API(仅 Chrome / Edge 桌面)。
'auto'(默认):按估算输出大小自动切换。
'in-memory' \| 'file' \| 'auto'
autoFileModeThreshold
'auto' 模式下切到 'file' 的字节数阈值,默认 200 MB。
Number
suggestedName
'file' 模式下浏览器保存对话框的默认文件名。
String
fileHandle
'file' / 'auto' 模式下推荐由业务方在 click handler 里同步调用 window.showSaveFilePicker() 拿到的 FileSystemFileHandle,避免 user activation 失效(详见下文)。
FileSystemFileHandle
process() 返回 ProcessResult
{
blob: Blob | null, // in-memory 模式下为完整 mp4 Blob;file 模式下为 null
fileHandle: FileSystemFileHandle | null, // file 模式下保存的文件句柄;in-memory 下为 null
mode: 'in-memory' | 'file', // 实际使用的模式(auto 解析后的具体值)
durationMs: number, // 处理耗时
frameCount: number, // 处理的视频帧数
}

输出模式选择

in-memory 模式(默认小文件)

适合小于 200 MB 的视频。process() 返回的 Blob 可直接 URL.createObjectURL(blob) 用于预览或上传。

file 模式(推荐大文件)

适合大于 200 MB 的视频,避免内存爆掉。必须在浏览器的 user gesture(如按钮点击)同步路径上调用 window.showSaveFilePicker() 拿到 fileHandle,再传给 process()
button.onclick = async () => {
const fileHandle = await window.showSaveFilePicker({
suggestedName: 'output.mp4',
types: [{ description: 'MP4 Video', accept: { 'video/mp4': ['.mp4'] } }],
})
const result = await recorder.process(file, {
mode: 'file',
fileHandle,
})
}
注意:
经过 await input.open() 等异步步骤后,user activation 已过期,SDK 内部弹出保存对话框会失败。请务必在 click 事件回调的同步开头先调用 showSaveFilePicker()

auto 模式(默认)

source.bitrate × duration / 8 估算输出大小,超过 autoFileModeThreshold(默认 200 MB)切换到 file 模式;浏览器不支持 File System Access API 时回退到 in-memory 并打印 warning。