【免费下载链接】filmcraft
An open-source, clean-room reimplementation of Adobe Premiere Pro built in pure Rust.
本篇技术指南围绕 filmcraft 仓库中的filmcraft-apvcrate(crates/apv/README.md)展开:它严格按照 IETF RFC 9924(《Advanced Professional Video》,2026 年 2 月,ISSN 2070-1721)做了 clean-room 的 APV(Advanced Professional Video)解码器与编码器实现。读完本文,你将掌握 APV 码流的 Access Unit / PBU / 帧头 / Tile 组织结构、自适应 Golomb-Rice 熵解码与 8×8 整数逆变换的精确算法、编码器 QP 率控制与APVDecoderConfigurationRecord的生成逻辑,以及如何复现该 crate 用 FFmpeg 作为外部 oracle 验证"100% 位精确(bit-exact)"的测试方法。
一、定位与工程约束:一个 Layer L0 的纯 Rust 编解码核心
APV 是一种面向专业制作场景的高比特深度视频编码格式,filmcraft 将其作为媒体管线中的一等编解码。filmcraft-apv在仓库的分层体系中属于Layer L0(Cargo.toml),其依赖面被刻意压到最小:
- 运行时依赖只有 filmcraft-bitstream(位读写原语)、
thiserror(错误类型),以及可选的rayon; - 功能开关为
default = ["threads"],threads特性对应dep:rayon,关闭后 crate 仍可独立编译; - 按 README 声明,crate 可构建到
wasm32-unknown-unknown,且unsafe_code = "forbid",即整个编解码核心不包含任何unsafe代码; - src/lib.rs 上还有一条 lint 级别的自我约束:非测试代码中
denyclippy::unwrap_used / expect_used / panic / unimplemented / todo / unreachable,从静态层面禁止隐式 panic。
公共 API 面在 lib.rs 一次性导出:解码侧的decode_frame/decode_frame_with/decode_frame_into/probe,编码器Encoder与EncoderConfig,以及码流工具split_raw_bitstream/unwrap_au/FrameHeader。
二、码流组织:从aPv1签名到 PBU 列表
2.1 Access Unit 与raw_bitstream_access_unit
RFC 9924 定义了两层封装(README 的 API 一节):
use filmcraft_apv::*; // 解码一个 APV Access Unit(或带 32 位 au_size 前缀的裸码流 AU) let frame: Frame = decode_frame(&au)?; let f8 = decode_frame_with(&au, &DecodeOptions { bit_depth: Some(8), threads: true })?; decode_frame_into(&au, &DecodeOptions::default(), &mut frame_buf)?; let hdr: FrameHeader = probe(&au)?; // 切分多 AU 的 .apv 裸码流(RFC 9924 Appendix A) let aus: Vec<&[u8]> = split_raw_bitstream(&raw_apv_bytes)?;实现位于 header.rs:
- 每个 Access Unit 以四字符签名
'aPv1'开头(AU_SIGNATURE,header.rs#L9); unwrap_au(header.rs#L85-L101)同时接受两种输入:直接以'aPv1'起始的 AU,或带 32 位大端au_size前缀的raw_bitstream_access_unit()包(ISOBMFFapv1/ MKVV_APV封装中即为此形态)。au_size == 0xFFFF_FFFF或小于 4 均被判为非法;split_raw_bitstream(header.rs#L105-L134)按 Appendix A 循环读取au_size,把整个.apv裸码流切成若干 AU 切片;若缓冲直接以'aPv1'开头,则整个缓冲视为单个 AU。
2.2 PBU 类型与"静默忽略"规则
AU 内部是由pbu_size(4 字节大端)+pbu_header(1 字节类型 + 2 字节 group_id + 1 字节保留位)+ 负载组成的 PBU 序列。header.rs#L12-L19 定义了全部 PBU 类型常量,与 README 的 Specification Coverage 一一对应:
| PBU 类型 | 值 | 语义 |
|---|---|---|
PBU_PRIMARY_FRAME | 1 | 主帧 |
PBU_NON_PRIMARY_FRAME | 2 | 非主帧 |
PBU_PREVIEW_FRAME | 25 | 预览帧 |
PBU_DEPTH_FRAME | 26 | 深度帧(常量已定义) |
PBU_ALPHA_FRAME | 27 | 辅助 alpha 帧 |
PBU_AU_INFO | 65 | AU 信息 |
PBU_METADATA | 66 | HDR 静态元数据 |
PBU_FILLER | 67 | 填充 |
解码器对 PBU 的"静默忽略"策略直接来自规范:parse_au_pbus(header.rs#L138-L172)中,凡reserved_zero_8bits > 0的 PBU 依 RFC 9924 §5.3.3必须被忽略(continue),而group_id == 0xFFFF或类型 ≤ 64 且group_id == 0则视为非法直接报错。parse_frame_header中若reserved_zero_5bits/fi_reserved_8/fh_reserved_8_a任一非零,返回Ok(None)表示"忽略该帧 PBU"(header.rs#L202-L206),而不是报错——这与 README 中"reserved fields are ignored per §5.3.3 and §5.3.5"的表述一致。
三、frame_header():尺寸、色彩、量化矩阵与 Tile 网格
FrameHeader(header.rs#L28-L54)是解码/编码共用的几何与参数载体,其位级解析在parse_frame_header(header.rs#L187-L322)。按 RFC 9924 §5.3.5–5.3.8 的顺序依次为:
- frame_info():
profile_idc(8b)、level_idc(8b)、band_idc(3b)、reserved_zero_5bits(5b)、width/height(各 24b)、chroma_format_idc(4b)、bit_depth_minus8(4b,合法范围2..=8,即编码位深 10–16)、capture_time_distance(8b)、reserved_zero_8bits(8b); - 色彩描述:
color_description_present_flag为 0 时采用 ITU-R BT.709 类默认值(primaries/transfer/matrix = 2,2,2,full_range = false,见 lib.rs#L243-L248 的ColorInfo::default()); - 量化矩阵(§5.3.7):
use_q_matrix为 1 时按分量顺序读入num_comps组 8×8 矩阵(每分量 64 字节,光栅序y*8+x);任一条目为 0 属保留值,报错。未启用时各分量统一为平面值16(DEFAULT_Q_MATRIX_VAL,tables.rs#L25); - tile_info()(§5.3.8):
tile_width_in_mbs/tile_height_in_mbs(各 20b,以 16×16 宏块为单位),由帧的宏块尺寸向上取整推出tile_cols/tile_rows,并预生成col_starts/row_starts光采样坐标数组(长度为 tile 数 + 1)。可选的tile_size_present_in_fh_flag携带每 tile 32 位精确字节数,供解码时交叉校验。
健壮性护栏(README §Robustness 的落点)包括:
- 帧尺寸上限
MAX_DIMENSION = 16384(header.rs#L22),防御恶意分配; - 每轴 Tile 数上限:规范 §9.4.1 要求 ≤ 20,但解码器放宽到
MAX_TILE_DIM = 64以"为健壮性留出余量"(header.rs#L24-L25,注释原文明确了这一点); - 4:2:2 帧强制偶数宽度(header.rs#L212-L214)。
FrameHeader::qp_bd_offset()给出QpBdOffset = (bit_depth - 8) * 6(header.rs#L69-L71),用于限制每 Tile QP 上限51 + QpBdOffset。
四、解码核心:自适应 VLC 熵解码与整数逆变换
4.1 熵解码:h(v)自适应 Golomb-Rice / Exp-Golomb
APV 不使用哈夫曼表,而是用 RFC 9924 §7.1.4 的自适应变长码h(v)编码三个符号(README 的 Entropy Decoding 一节):abs_dc_coeff_diff、coeff_zero_run、abs_ac_coeff_minus1,参数k由块间/分量间维护的状态自适应更新。
read_vlc(decode.rs#L30-L58)是解码侧实现:先读 1–3 个前缀位决定落入哪一段,之后或继续 Exp-Golomb 展开(k逐位递增,上限 28 位,超限报Invalid("VLC codeword exceeds maximum length")),或补k个信息位。注意u64累加与最终的u32::try_from溢出检查——VLC 符号越界是 fuzz 测试重点覆盖的输入形态之一。
分量解码主循环decode_tile_comp(decode.rs#L368-L465)的逐块流程:
- DC 差值:
k_dc = min(prev_dc_diff >> 1, 5),读abs_dc_coeff_diff;非零时再读 1 位符号;dc = prev_dc + diff必须落在-32768..=32767,否则报CorruptTile; - AC run-level 扫描:在 64 个扫描位置(
ZIGZAG_8X8,tables.rs#L4-L7)上循环:k_run = min(prev_run >> 2, 2)读coeff_zero_run;若未到第 64 个位置,再读abs_ac_coeff_minus1(k_lvl = min(prev_level >> 2, 4))与 1 位符号,绝对值abs_ac_minus1 + 1后检查 ±32767 界;系数写入coeff[ZIGZAG_8X8[scan_pos]]; - 状态追踪:
PrevDC、PrevDcDiff(初始 20)、Prev1stAcLevel(初始 0)、PrevLevel、PrevRun(初始 0)在宏块的 8×8 块之间传递,与 README 中"state tracking across the 8×8 blocks of each macroblock"完全对应; - 每个 tile 分量末尾调用
read_byte_alignment(header.rs#L175-L183),要求所有填充位为零——tile 之间是独立字节对齐的熵分区,这正是多 tile 可并行解码的前提。
4.2 精确整数逆变换:levelScale 与 transMatrix
反量化与 8×8 逆 DCT 全部为精确整数运算(dct.rs),这是 APV 能做到"任意合规解码器位精确"的关键:
- 反量化(
scale_and_idct8x8,dct.rs#L63-L77):scaled = ((c * qm[idx] * levelScale[qp % 6]) << (qp / 6) + round) >> (bit_depth - 2),其中levelScale = [40, 45, 51, 57, 64, 71](tables.rs#L22),bdShift = BitDepth - 2,结果 clamp 到 ±32767。这与 README 中"Exact integer dequantization"的表述一致; - 二维可分离逆变换:对每列先做 1 维
idct_1d(dct.rs#L8-L38),系数35/84/89/75/50/18直接来自 RFC 9924 §6.3.2.3 Figure 25 的transMatrix(完整 8×8 矩阵见 tables.rs#L10-L19)。这里有一个值得注意的转置陷阱,README 专门作了说明:transMatrix[m][n]的行m是频率索引(第 0 行是[64; 8]),列n才是空间采样索引,因此 1 维逆变换计算sum_j transMatrix[j][i] * x[j]。idct_1d用偶/奇蝶形分解手工展开该求和,每路输出加舍入(sum + round) >> shift; - DC-only 快速路径:当块内 AC 全零时走
scale_and_idct8x8_dc_only(dct.rs#L42-L58),整个块输出同一采样值。idct_1d内部同样有 AC 全零的捷径(dct.rs#L9-L12); - 最终采样值经
+ (1 << (bit_depth - 1))偏移并 clamp 到0..=(2^bit_depth - 1)。
4.3 输出位深重缩放与并行 Tile 解码
DecodeOptions(decode.rs#L15-L26)提供两个开关:
bit_depth: Option<u8>:None保留码流编码位深(10–16),指定时必须在8..=16(README:output depth rescaling 8..=16)。逐块重缩放由rescale_block(decode.rs#L468-L484)完成:降位深为round = 1 << (shift-1)的加性舍入后右移并钳位;升位深则左移并用低位回填高位(| (v >> (fill_shift - shift))),避免纯移位造成的色带;threads: bool:多 tile 时用rayon的into_par_iter并行解码(decode.rs#L190-L196),单 tile 或关闭特性时顺序执行。
合成阶段有一个零拷贝优化:单 tile 且尺寸恰好等于整帧时,直接把解码出的平面std::mem::take给输出帧(decode.rs#L223-L236);多 tile 时按copy_tile_comp把各 tile 重建样本裁剪复制进全帧平面。
4.4 alpha PBU 与 HDR 静态元数据
- 主帧无第 4 分量、且存在尺寸匹配的
pbu_type == 27辅助 alpha 帧 PBU 时,解码器把其亮度平面作为Frame::alpha输出(decode.rs#L136-L147)——这支撑了 README 提到的 4:4:4:4 与辅助 alpha 场景; pbu_type == 66的 metadata PBU 由parse_metadata_pbu(header.rs#L375-L427)解析,按 RFC 9924 §8 提取两类 HDR 静态元数据:- MDCV(
payloadType == 5,24 字节):RGB 三主色与白点用 1/65536 定点,max_luminance为 24.8 定点 cd/m²、min_luminance为 18.14 定点,映射到 lib.rs#L260-L266 的MasteringDisplay; - CLL(
payloadType == 6,4 字节):max_cll/max_fall(cd/m²); payloadType == 10(filler)必须全0xFF,否则报错;未识别类型依 §10不得尝试处理,直接跳过。
- MDCV(
4.5 快速探测
probe(decode.rs#L61-L71)只解析 PBU 列表并解析第一个可解码帧 PBU(primary / non-primary / preview)的frame_header(),不解码任何 tile——在播放列表扫描、封装器 mux 前的尺寸探测等场景中避免整帧解码开销。
五、编码器:全 Profile 渐进帧内编码
5.1 Encoder 与 EncoderConfig
// 编码渐进帧内帧 let mut enc = Encoder::new(Profile::P422_10, 1920, 1080)?; let au: Vec<u8> = enc.encode(&frame)?; // 'aPv1' 开头的 Access Unit let raw_au: Vec<u8> = enc.encode_raw_au(&frame)?; // 带 32 位 au_size 前缀(ISOBMFF apv1 / .apv) let apvc: Vec<u8> = enc.decoder_config_record(); // APVDecoderConfigurationRecord 负载EncoderConfig(encode.rs#L57-L82)的关键字段与约束:
| 字段 | 说明 |
|---|---|
profile / chroma / bit_depth | 必须满足Profile::supports(chroma, bit_depth)(§9.3,见下节矩阵) |
qp: Option<u8> | 固定 QP(上限51 + QpBdOffset);None时启用帧预算率控制 |
target_frame_bytes | qp == None时的目标帧字节数,默认profile.nominal_frame_bytes(w, h) |
tile_width_in_mbs / tile_height_in_mbs | RFC 9924 §9.4.1 要求>= 16/>= 8;编码侧强制 Tile 网格<= 20×20(encode.rs#L160-L162) |
q_matrix: Option<[[u8; 64]; 4]> | 自定义每分量 8×8 量化矩阵,条目必须非零(encode.rs#L180-L186) |
write_tile_sizes_in_fh | 在frame_header()中写入tile_size_in_fh数组 |
mastering_display / content_light | 可选 MDCV / CLL,写入 metadata PBU |
EncoderConfig::new(encode.rs#L85-L115)的默认值推导值得学习:按"HD/4K 下约 4–8 个 tile"的目标启发式取ceil(w_mbs/4).max(16)作为 tile 宽(宏块数),同时用ceil(w_mbs/20)兜底以满足 ≤ 20 网格上限;level_idc/band_idc由select_level_and_band按 30 fps 的亮度采样率与目标码率查表得出。
5.2 前向变换、量化与位精确估算
编码路径在 encode.rs 中严格镜像解码路径:
prepare_tiles对每个 tile 各分量做 8×8 前向整数 DCT(fdct8x8,dct.rs#L135-L168),输入先做sample - (1 << (bit_depth - 1))中心化;输入位深与编码位深不一致时逐采样scale_sample重缩放;quantize8x8(dct.rs#L172-L194)以den = (qm * levelScale) << (qp/6)为分母做带死区的整数除法:DC 偏移den/2,AC 偏移3*den/8,级值钳位 32767;- VLC 生成
write_vlc(encode.rs#L12-L39)与read_vlc逐位对偶,自适应状态(prev_dc_diff等)更新逻辑与解码侧完全一致。
帧预算率控制(README:"binary-search frame-budget rate control over forward-transformed tiles")在select_qp(encode.rs#L416-L452):因为前向变换已完成,估计某个 QP 的成帧字节数只需"量化 + 统计 VLC 位长",而不用真正落位流——vlc_bit_len(encode.rs#L43-L53)给出h(v)的精确位长,estimate_comp_bits按与真实编码相同的扫描/状态逻辑累加。随后在[0, max_qp]上做二分,取满足frame_bytes_at(qp) <= target_frame_bytes的最小 QP;若 QP=0 已达标则直接返回 0。tile 准备与估计均可走rayon并行。
encode()输出aPv1AU(primary 帧 PBU,group_id = 1,group_id = 0依规范保留),encode_raw_au()再补 32 位大端au_size前缀,形成可直接写入.apv或apv1box 的裸码流 AU。
5.3 APVDecoderConfigurationRecord(apvC)
decoder_config_record(encode.rs#L311-L333)生成 ISOBMFFapvC/ Matroska CodecPrivate 所需的解码配置记录:configurationVersion = 1、1 个配置条目(pbu_type = 1、number_of_frame_info = 1)、标志字节(color_description_present→ bit1,capture_time_distance_ignored→ bit0)、profile/level/band、大端宽高、(chroma_idc << 4) | (bit_depth_minus8 & 0x0F)打包字节,以及可选的 BT.2020 等色彩三元组与full_range高位标志。
六、Profile 与 Level/Band 体系(RFC 9924 §9)
lib.rs#L113-L227 完整实现了 §9.3 的七个标准 Profile:
| Profile | profile_idc | 色彩采样 | 编码位深 |
|---|---|---|---|
P422_10 | 33 | 4:2:2 | 10-bit |
P422_12 | 44 | 4:2:2 | 10–12-bit |
P444_10 | 55 | 4:2:2–4:4:4 | 10-bit |
P444_12 | 66 | 4:2:2–4:4:4 | 10–12-bit |
P4444_10 | 77 | 4:2:2–4:4:4:4 | 10-bit |
P4444_12 | 88 | 4:2:2–4:4:4:4 | 10–12-bit |
P400_10 | 99 | 4:0:0 单色 | 10-bit |
Profile::supports(lib.rs#L194-L206)把"位深以 8 为基的偏移 + 采样格式 idc 集合"编码为逐 Profile 的匹配规则(例如4444-12接受 idc 2–4 的采样格式与 10–12-bit),编码初始化与解码校验都复用它。同文件的nominal_frame_bytes(lib.rs#L209-L221)给出各 Profile 的标称每帧字节数(bpp 从 400-10 的 1.5 到 4444-12 的 6.2),是默认target_frame_bytes的来源。
Level/Band 侧,tables.rs#L29-L44 内置了 §9.4.2 Table 4 的 14 个等级(level_idc30–213,每级 4 个 band 的码率上限,单位 Mbit/s),select_level_and_band取满足采样率与码率的最低合规等级,超出全部上限时回落到(213, 3)。
Frame(lib.rs#L275-L293)是编解码共用帧模型:planaru16采样、无行填充,携带ColorInfo(内置BT709/BT2020_PQ/BT2020_HLG常量,lib.rs#L251-L253)、profile/level/band 与 HDR 元数据;ChromaFormat(idc 0/2/3/4)提供sub_width_c/sub_height_c等派生几何(lib.rs#L42-L111)。
七、准确性与健壮性的双重验证
7.1 FFmpeg 外部 oracle:全 Profile 位精确
tests/oracle.rs 是 README "Accuracy (vs FFmpeg as an External Oracle)" 一节的实证,三组测试覆盖了规范的主要维度:
all_profiles_bit_exact_with_ffmpeg(oracle.rs#L103-L133):对全部 7 个 Profile 合成 320×192 测试图案(渐变 + 棋盘 + 高频混合),固定qp = 12编码成.apv落盘,用ffmpeg -v error -xerror -f apv -i解出计划u16采样,与decode_frame逐采样比较,断言max_diff == 0——即 README 所宣称的"100% bit-exact with FFmpeg's APV decoder across every profile and test case";同时要求 Y 平面 PSNR > 45 dB 作为主观质量下限。测试在无 FFmpeg 的环境会自动跳过(filmcraft_testkit::ffmpeg_or_skip);odd_dimensions_and_multi_tile_bit_exact_with_ffmpeg(oracle.rs#L135-L178):奇数尺寸(334×202、333×201)、多 tile、MDCV + CLL 元数据回读断言(ours.mastering_display == src.mastering_display),并额外验证单线程解码与默认多线程解码输出完全一致;custom_q_matrix_and_fh_tile_sizes_bit_exact_with_ffmpeg(oracle.rs#L181-L230):444-12 +故意不对称的量化矩阵(qm[y*8+x] = 10 + c*3 + y*5 + x*2,用于暴露transMatrix/矩阵 (x,y) 方向弄反这类 bug),启用write_tile_sizes_in_fh与 16×8 宏块 tile,另验证 8-bit / 16-bit 重缩放输出。
这套"自编码 → 外部参考解码 → 逐采样全等"的测试方法,正是 README 能在 100% 位精确上立论的原因:APV 的整数逆变换是规范唯一确定的,任何合规实现之间不应存在差异。
7.2 健壮性 fuzz:数千次变异不得 panic
tests/fuzz.rs 对应 README 的 Robustness(§10)条目。它先以 5 个 Profile 生成正常 AU 种子流,然后做 3000 轮定向变异:随机位翻转、随机字节覆写、截断、头部字段破坏、tile 负载区破坏、随机字节拼接(fuzz.rs#L55-L98),每轮在 8/16-bit 重缩放与线程开关四种组合下调用decode_frame_with、probe、split_raw_bitstream,并用catch_unwind断言永不 panic(允许返回错误)。另有 2000 轮纯随机字节输入。这解释了源码中那些"先检查、后分配/移位"的细节:所有 size 字段用checked_add边界裁剪、tile 坐标经col_starts/row_starts间接校验、系数与 DC 强制-32768..=32767、VLC 长度封顶 28 位。
八、在 filmcraft 中的集成位置
从源码结构看,filmcraft-apv通过 crates/codecs/src/apv.rs 被接入统一媒体层:该模块用filmcraft_apv::probe解析首个 AU 的帧头以获取尺寸/采样格式,并用Profile::from_idc建立 codec 描述;容器侧,crates/codecs/src/mp4.rs 处理apv1/apvC配置(ISOBMFF),crates/codecs/src/mkv.rs 处理V_APV与 CodecPrivate(内部同样先解析ApvConfig再映射 Profile)。也就是说,本文介绍的 AU 拆分、apvC记录、位深重缩放在 filmcraft 的 MP4/MKV 解码链路里都会实际走到。
九、快速上手
在仓库根目录以该 crate 为入口开发或测试:
# 运行全部测试(oracle 测试依赖本机 ffmpeg,缺失时自动跳过) cargo test -p filmcraft-apv # 仅健壮性 fuzz 测试 cargo test -p filmcraft-apv --test fuzz # 无 rayon 的单线程构建(wasm 目标可用) cargo build -p filmcraft-apv --no-default-features --target wasm32-unknown-unknown最小解码示例(假定已拿到一个aPv1起始的 AU 字节切片):
use filmcraft_apv::{decode_frame, split_raw_bitstream, DecodeOptions}; let aus = split_raw_bitstream(&raw_apv_bytes)?; // 多 AU 裸 .apv 码流 let hdr = filmcraft_apv::probe(aus[0])?; // 只解析 frame_header println!("{}x{} {} {}", hdr.width, hdr.height, hdr.chroma, hdr.bit_depth); let frame = decode_frame_with(aus[0], &DecodeOptions { bit_depth: Some(8), threads: true })?;要点回顾:decode_frame接受aPv1AU 或带au_size前缀的裸 AU 两种形态;bit_depth限定8..=16且None时保留编码位深;threads仅在启用threads特性且多 tile 时产生并行收益;编码器输出可直接进入 MP4(apv1)或 MKV(V_APV)封装,配合decoder_config_record()写入的apvC即可完成容器层的自描述。
十、小结
filmcraft-apv的价值在于把一个"整数算术完全确定"的专业视频格式做成了可验证的参考实现:位级解析严格对应 RFC 9924 §5.3 的语法结构,levelScale/transMatrix的整数变换保证了解码可重复性,编码器以"前向变换 + 精确位长估算 + QP 二分"实现合规的帧预算率控制,而 oracle 与 fuzz 两套测试分别回答了"结果对不对"与"输入坏时会不会崩"两个问题。对需要 APV 解码、转码或封装集成的开发者,可直接复用split_raw_bitstream/probe/decode_frame_with与Encoder::decoder_config_record这一组 API,无需接触内部比特流细节。
【免费下载链接】filmcraft
An open-source, clean-room reimplementation of Adobe Premiere Pro built in pure Rust.
相关推荐
filmcraft-prores:基于 SMPTE RDD 36 的纯 Rust ProRes 解码器与编码器深度解析
filmcraft prores:基于 SMPTE RDD 36 的纯 Rust ProRes 解码器与编码器深度解析 本篇围绕 crates/prores/R
filmcraft-ac3 深度解析:基于 ATSC A/52 的纯 Rust AC-3(Dolby Digital)解码器
filmcraft ac3 深度解析:基于 ATSC A/52 的纯 Rust AC 3(Dolby Digital)解码器 filmcraft 的 filmc
Filmcraft 的纯 Rust DNxHD / DNxHR (VC-3) 编解码器:基于 SMPTE ST 2019-1 的 Clean-room 实现解析
Filmcraft 的纯 Rust DNxHD / DNxHR VC 3 编解码器:基于 SMPTE ST 2019 1 的 Clean room 实现解析 f
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考