在 Godot 4 中播放 Tencent VAP v2 透明 MP4,并支持 VAPX 动态头像、图片和文字融合。
| 功能 | 状态 | 说明 |
|---|---|---|
| 普通 VAP | ✅ | 从 MP4 中拆分 rgbFrame 和 aFrame,GPU 合成透明画面 |
| VAPX 动态融合 | ✅ | 运行时替换头像、图片和文字 |
| 内嵌配置 | ✅ | 自动读取 MP4 顶层 vapc JSON box |
| 外部配置 | ✅ | 支持显式 JSON、同目录 vapc.json、<video>.json |
| 遮罩动画 | ✅ | 支持 frame、mFrame、mt=0/90、z |
| 资源适配 | ✅ | 支持 fitXY、centerFull、文字颜色和粗体 |
| 运行时更新 | ✅ | 播放途中可再次设置昵称或头像 |
| 音频 | ✅ | 可选,默认关闭,加载前设置 enable_audio = true |
VAPPlayer
├── addons/godot_vap/vap_player.gd 读取 vapc、校验配置、控制播放、公共 API
├── addons/godot_vap/vap_fusion_manager.gd 动态资源、逐帧位置、遮罩和层级
├── addons/godot_vap/shaders RGB + Alpha 合成和 VAPX 遮罩
└── VideoPlayback / GoZen FFmpeg H.264 解码、YUV 纹理上传
Godot 4 本身不能直接把 H.264 MP4 当作通用视频流播放,因此本项目使用上游 GDE GoZen 9.7 作为解码后端。video_playback.gd、yuv_to_rgb*.gdshader 及其 UID 都属于 GoZen 插件原文件;项目没有在这些文件里追加 VAP 逻辑。VAP 格式解析、透明合成和动态融合全部位于 addons/godot_vap。
- Godot
4.3+;当前已在 Godot4.6.1验证。 - 当前交付二进制:Windows x86_64。
addons/gde_gozen/bin已包含 GoZen Windows debug/release GDExtension。- 使用 GoZen/FFmpeg 时须保留其
LICENSE。 - VAP 视频通常为 H.264/yuv420p;GoZen 负责 YUV 转换,本插件只在输出纹理上拆分 RGB/Alpha 区域。
将 godot_vap_godot4_windows.zip 解压到目标项目根目录,得到:
addons/
├── godot_vap/
└── gde_gozen/
然后打开 Project → Project Settings → Plugins,启用:
gde_gozenGodot VAP 4
首次添加 GDExtension 后建议重启一次编辑器。
必须同时复制以下两个目录,不能只复制 godot_vap:
godot_vap/addons/godot_vap
godot_vap/addons/gde_gozen
addons/godot_vap 已包含播放器、融合管理器、shader、插件声明和可复用的
vap_player.tscn,不再引用源码工程根目录中的实现。addons/gde_gozen 是
Windows MP4/H.264 解码依赖,因此目标项目仍需同时携带这两个 addon。
可以直接把 addons/godot_vap/vap_player.tscn 拖入场景;也可以给一个
Control 节点挂载 addons/godot_vap/vap_player.gd,或在脚本中实例化:
const VAP_PLAYER := preload("res://addons/godot_vap/vap_player.gd")
func _ready() -> void:
var player := VAP_PLAYER.new()
player.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
add_child(player)
player.animation_ready.connect(func(_config): player.play())
player.animation_error.connect(push_error)
player.load_vap_video("D:/assets/gift.mp4")传给解码器的路径应是本机绝对路径。项目资源可以用:
var path := ProjectSettings.globalize_path("res://effects/gift.mp4")
player.load_vap_video(path)必须在 load_vap_video() 前连接资源请求:
func _ready() -> void:
$VAPPlayer.fusion_resource_needed.connect(_on_fusion_resource_needed)
$VAPPlayer.animation_ready.connect(func(_config): $VAPPlayer.play())
$VAPPlayer.load_vap_video("D:/assets/gift_vapx.mp4")
func _on_fusion_resource_needed(resource_id: String, resource_type: String) -> void:
match resource_type:
"txt":
$VAPPlayer.set_fusion_resource(resource_id, "玩家昵称")
"img":
var avatar: Texture2D = load("res://ui/avatar.png")
$VAPPlayer.set_fusion_resource(resource_id, avatar)播放过程中也可热更新:
$VAPPlayer.set_fusion_resource("nickname", "新的昵称")
$VAPPlayer.set_fusion_resource("avatar", new_avatar_texture)资源 ID 来自 vapc.src[].srcId。如果不确定设计文件使用了什么 ID:
var source := $VAPPlayer.get_fusion_source_config(resource_id)
print(source)| API | 用途 |
|---|---|
load_vap_video(video_path, config_path = "") -> bool |
读取配置并打开视频 |
play() / pause() / resume() / stop() |
播放控制 |
seek_to_frame(frame) |
跳到指定帧 |
set_fusion_resource(id, String|Texture2D|Image) |
设置动态文字或图片 |
get_fusion_source_config(id) -> Dictionary |
获取资源声明 |
get_playback_info() -> Dictionary |
查询播放状态和视频信息 |
主要信号:
animation_ready(config)animation_startedanimation_finishedanimation_error(message)frame_changed(frame_number)fusion_resource_needed(resource_id, resource_type)fusion_resource_ready(resource_id)
音频默认关闭,业务需要时显式开启:
$VAPPlayer.enable_audio = true
$VAPPlayer.load_vap_video(video_path)当前 GoZen 9.7 使用 AudioStreamFFmpeg 单独打开音轨并持续流式解码,不会先把整条音轨预载到内存;视频播放和音频流各自维护读取状态,不在同一个顺序读取器上抢帧。
Windows 导出时需要同时包含 addons/gde_gozen/bin 下对应的 release GDExtension。
test_video/video.mp4:普通 VAP,1136×1632,24 fps。test_video/vapx.mp4:VAPX,动态图片和文字遮罩。- 已验证 Godot 4.6.1 下普通 VAP、VAPX 和 MP4 流式音频。
运行项目主场景后,可在左侧“演示素材”中直接切换普通 VAP 和 VAPX。 选择 VAPX 后,约第 140 帧会出现动态昵称和头像;修改输入框并点击 “更新文字”,可以在播放过程中更新融合文字。
- 当前预编译包只交付 Windows x86_64;其他平台需要对应 GoZen 二进制。
- 播放器不负责 HTTP 下载头像,业务层下载完成后传入
Image或Texture2D。 - 文字由 Godot
SystemFont渲染;字体外观可能随操作系统变化。 - VAPX 配置仅接受当前已实现的 Tencent VAP v2 字段和
mt=0/90。