SWF 视频编码:H.263、Screen Video 与 VP6
老 SWF 也能直接塞视频:从 H.263、Screen Video 到 VP6,顺便看看它和馆内 AV1 预览有什么不同。
Flash 保存计划 · 最近整理于 2026年7月30日
老 Flash 作品里的运动画面,大多由时间轴、矢量和位图组成,不过 SWF 也能直接塞进压缩视频。作品页上的 h263、screen、vp6、vp6alpha、screen2,就是视频流里的 codec ID 翻成的名称。它说的是帧数据怎样解码,不是 MP4、FLV、F4V 那样的容器格式。
这套做法从 Flash Player 6 开始:先用 DefineVideoStream 建立一个视频角色,再由一连串 VideoFrame 送入压缩帧。帧就夹在 SWF 时间轴的其他标签之间,文件还没下载完,播放便可以开始。
本站顺着标签往下读。碰到 DefineVideoStream(编号 60),就把视频资源数加一,标记 media.has_video,再把其中的 CodecID 换成上面这些短名称;不认识的编号记作 unknown。
media.video_codec 目前只留一个值,所以一只 SWF 若有多条视频流,页面会显示最后读到的那种。这里也不会真的解码 VideoFrame,画质、码率、关键帧和时长都要等实际播放才知道。ActionScript 临时从网上加载的 FLV / F4V,则根本没装在这只 SWF 里。
五种 codec ID 对照
| 本馆字段 | SWF CodecID | 名称 | 典型时期 | 核心特点 |
|---|---|---|---|---|
h263 |
2 | Sorenson H.263 / Sorenson Spark | SWF 6、Player 6 起 | 面向一般视频的有损运动压缩,是对 H.263v1 的 Flash 变体 |
screen |
3 | Screen Video | SWF 7、Player 7 起 | 面向屏幕录制的分块、无损、zlib 压缩帧 |
vp6 |
4 | On2 TrueMotion VP6 | 嵌入式 codec ID 为 SWF 8 时代;Player 8 起 | 同码率下通常比 Sorenson Spark 质量更好,解码成本也更高 |
vp6alpha |
5 | VP6 with alpha | SWF 8、Player 8 起 | 一条颜色 VP6 流加一条 alpha VP6 流,可与舞台内容合成 |
screen2 |
6 | Screen Video Version 2 | Player 8 起 | Screen Video 的扩展,支持局部更新、调色板和改进的分块压缩 |
这些年代说的是 codec 何时进入 Flash。今天能不能顺利播放,还要看帧本身和播放器带了哪套解码器。
Sorenson H.263(h263)
Codec ID 2 是 Sorenson H.263,Adobe 的产品文档也常叫它 Sorenson Spark。它从 1996 年版 ITU H.263 演变而来,但码流是 Flash 自己的变体:去掉 GOB 层和 PB 帧,加入可丢弃帧、任意画面尺寸、始终启用的 unrestricted motion vector 和去块提示,画面层与宏块层头部也另有安排。
这是 SWF 6 最早提供的内嵌视频格式,很有当年低带宽网页视频的气质。后来 VP6 已经出现,Adobe 仍把 Spark 留作兼容 Player 6 / 7 和较旧电脑的选择:更省解码力,代价是同码率下画质通常逊色一些。
顺带一提,h263 不是 H.264 的简写,两者是不同代的编码。这个小写词只是本站给 CodecID = 2 的固定名称。
Screen Video(screen)
Codec ID 3 是第一代 Screen Video,出现在 SWF / Player 7。它的舞台不是摄像机实拍,而是软件演示和桌面录屏:大块像素经常不动,文字与窗口边缘又很锐利。
每帧被划成 16–256 像素见方或长方形的网格块:
- 关键帧为每个块提供像素;
- 后续帧可令未变化块的
DataSize为零; - 有变化的块保存 B、G、R 三字节像素,并分别使用 zlib 压缩。
这是一种带分块帧间更新的无损连续位图。“无损”说的是像素不经过有损量化,可不保证文件小;拿它装实拍画面或全屏快速变化,体积照样会上去。
On2 TrueMotion VP6(vp6)
Codec ID 4 是 On2 TrueMotion VP6,也是 Player 8 时代更讲究画质的选择。同码率下,它通常比 Sorenson Spark 清楚;编码更慢,观众的电脑也要多出一点力。
内嵌 VP6 属于 SWF 8 时代,不过早期 SWF 也能借脚本加载外部 VP6,只要实际运行的是 Player 8。本站写下 vp6 时,只数文件本体 DefineVideoStream 里的 codec ID 4。
普通 VP6 帧只有颜色画面。若需要逐像素透明度,SWF 使用另一个 codec ID。
VP6 with alpha(vp6alpha)
Codec ID 5 是带 alpha 通道的 VP6。每帧保存两段码流:
- 第一条 VP6 流表示预乘 ARGB 的颜色通道;
- 第二条 VP6 流把 8 位 alpha 值编码进亮度分量;
VP6SWFALPHAVIDEOPACKET开头的 24 位OffsetToAlpha指出第二段数据从哪里开始。
解码时,两条流重新合成带透明度的像素,于是人物、烟雾、抠像素材便能叠在矢量或位图场景上。为了还能正常 seek,颜色流遇到关键帧时,alpha 流在同一点也要有关键帧。
这份 alpha 只属于视频帧,不会顺手把整个 SWF 舞台变透明。最后看到什么,还要看角色怎么摆、背景是什么,以及播放器怎样合成。
Screen Video Version 2(screen2)
Codec ID 6 是 Screen Video Version 2。它保留第一代的分块屏幕录制思路,并加入几项减少块数据量的机制:
- 块可以只更新连续的部分扫描行,而不是每次给出完整块;
- 可利用当前或上一画面的块作为 zlib“预热”数据;
- 除 24 位 RGB 外,还可使用 15/7 位混合色彩空间;
- 混合色彩空间可引用 128 色调色板,码流可随时给出新调色板,否则使用规范的默认表;
- 帧可组合 keyblock 与依赖其他画面的 interblock。
这些办法很适合颜色有限、只在局部变化的界面画面,解码自然也比第一代麻烦。Ruffle 目前的软件后端有 H.263、VP6、VP6 alpha 和 Screen Video 的分支,但 Screen Video 解码器标着“V1 only”,也找不到 ScreenVideoV2 分支。于是本站认得 screen2 这个编号,实际播放仍可能停在这里。
DefineVideoStream 与 VideoFrame 怎样配合
接下来看看它在文件里怎样串起来。DefineVideoStream 先把视频角色写进 SWF 字典,同时留下:
CharacterID:其他显示列表标签引用的视频角色 ID;NumFrames:这条流声明包含多少个VideoFrame;Width、Height:视频像素尺寸;- 去块等级和缩放平滑开关;
CodecID:本页讨论的压缩格式编号。
后面的 VideoFrame(编号 61)各带一个 StreamID、流内 FrameNum 和压缩负载。StreamID 像线头一样,把这些帧牵回刚才定义的视频角色。
不过,帧数据到齐了,还得由 SWF 时间轴把画面安排上舞台:
- 播放节奏取决于 SWF 帧率,视频负载自身的计时信息被忽略;
- 不是每一个 SWF 帧都要配一个
VideoFrame; VideoFrame只给流内帧号装入数据,不会自动出现在舞台上;- 要显示它,时间轴通常通过
PlaceObject2或PlaceObject3的Ratio选择视频帧。
这样一来,NumFrames、VideoFrame 条数、SWF 总帧数和观众真正看到的画面数自然不会总是一样。音频也另有去处:内嵌影片要出声,还得配合 SWF 声音标签或外部媒体。
从 Player 6 到现代模拟器
Player 6 带来 SWF 视频标签和 Sorenson H.263;Player 7 加上 Screen Video,也让 NetStream.play 可以直接加载 FLV;Player 8 又迎来 VP6、VP6 alpha 与 Screen Video 2。此后 FLV、F4V 和 H.264 等外部媒体路径继续生长,已经是 DefineVideoStream 那五个 ID 之外的另一段历史。
到了 Ruffle,流程还是先认出 codec ID,再把数据交给随构建启用的解码器。若帧有缺口、前置关键帧丢了、时间轴没把角色摆上舞台,或者脚本仍在等一份网络资源,页面认出了编码,画面也可能迟迟不来。
与本馆 AV1 动态预览的区别
本站页面有时还有一段 MP4 / AV1 动态预览。那是把整只 SWF 播放一遍、重新抓取画面得到的,和 media.video_codec 说的不是同一层东西:
| 项目 | SWF 内嵌视频 codec | 本馆 AV1 预览 |
|---|---|---|
| 数据来源 | 原始 SWF 的 DefineVideoStream.CodecID 与 VideoFrame |
本馆在隔离渲染环境中播放整个 SWF 后抓取画面 |
| 是否属于原始文件 | 是 | 否,是可重建的派生展示资源 |
| 表示范围 | 某个内嵌视频角色 | 整个舞台的最终输出,包括矢量动画、位图、文字和视频 |
| 编码 | H.263、Screen Video、VP6 等旧 Flash codec | 使用 AV1 编码并装入页面可播放的 MP4 预览 |
| 档案身份 | 原始 SWF 内部事实 | 为浏览与缩略展示生成,不替代归档主文件 |
所以,“视频:无”的作品仍可能有动态预览——矢量补间、逐帧绘制、影片剪辑和脚本一样会动。反过来,原文件含 vp6 也未必能产出预览;它得先顺利播放,还得真的产生足够的画面变化。
最后解释一下名字里的“Stream”:这里说的是内嵌帧沿时间轴分布、可以渐进下载,不是 RTMP 直播。SWF 内嵌视频、RTMP 和 NetStream 加载外部 FLV,本来就是三条不同的路。