1 简介
本文涉及 FFmpeg 本身的开发。有关在其他程序中使用 FFmpeg 库的信息可以在其他地方找到,例如:
- 已安装的头文件
- 从头文件生成的 Doxygen 文档
- doc/examples 下的示例
有关在外部程序中使用 FFmpeg 的更多详细法律信息,请阅读源代码树中的 LICENSE 文件并查阅 https://ffmpeg.org/legal.html。
如果您根据自己的使用情况修改 FFmpeg 代码,我们强烈建议您将更改提交给我们,并使用本文档作为指南。这样做既有务实的理由,也有意识形态上的理由:
- 维护外部更改以跟上上游开发既耗时又容易出错。如果您的代码位于主树中,它将由 FFmpeg 开发人员维护。
- FFmpeg 开发人员包括该领域的顶尖专家,他们可以在您的代码中发现错误或设计缺陷。
- 通过支持您认为有用的项目,您可以确保它继续得到维护和开发。
所有提议的代码更改都应提交给开发邮件列表进行审查,如提交补丁一章中更详细地描述的那样。代码应符合开发政策并遵循编码规则。提交的开发人员和作者应对他们的更改负责,并应尝试修复提交导致的问题。
2 编码规则
2.1 语言
FFmpeg 主要使用 ISO C11 语言编写,但公共头文件必须与 C99 兼容。
可以有充分理由使用特定于编译器的扩展,但不能依赖它,即代码仍必须能够编译并与缺少扩展的编译器一起使用。
代码库中的任何地方都不得使用以下 C99 功能:
- 可变长度数组;
- 复数;
- 混合语句和声明。
2.1.1 SIMD/DSP
由于现代编译器无法从纯 C 生成高效的 SIMD 或其他性能关键型 DSP 代码,因此使用手写汇编。通常,此类代码被隔离在单独的函数中。然后,标准方法是编写此函数的多个版本 - 一个可以在任何地方运行并且可能对调试有用的纯 C 版本,以及多个特定于架构的优化实现。然后,初始化代码在运行时选择最佳可用版本并将其加载到函数指针中;然后始终通过此指针调用相关函数。
用于编写汇编的特定语法是:
- x86 上的 NASM;
- ARM 和 RISC-V 上的 GAS。
用于汇编的单元测试框架 checkasm 位于 tests/checkasm 下。所有新汇编都应附带 checkasm 测试;强烈建议为缺少这些测试的现有汇编添加测试。
2.1.2 其他语言
在特殊情况下可以使用 C 以外的其他语言:
- 当相关代码无法以 SIMD/DSP 部分中描述的标准方式编写时,使用编译器内在函数或内联汇编。这通常适用于需要内联的代码。
- 需要与 macOS 特定接口交互的 Objective-C。
2.2 代码格式约定
关于文件中的缩进,有以下准则:
- 缩进大小为 4。
- Makefile 之外禁止使用 TAB 字符,任何形式的尾随空格也是如此。包含这两种字符的提交将被 git 存储库拒绝。
- 您应该尝试将代码行限制为 80 个字符;但是,只有当这样做可以提高可读性时才这样做。
- 使用 K&R 编码风格。
该演示受“indent -i4 -kr -nut”的启发。
2.2.1 Vim 配置
为了将 Vim 配置为遵循 FFmpeg 格式约定,请将以下代码片段粘贴到您的 .vimrc 中:
" indentation rules for FFmpeg: 4 spaces, no tabs
set expandtab
set shiftwidth=4
set softtabstop=4
set cindent
set cinoptions=(0
" Allow tabs in Makefiles.
autocmd FileType make,automake set noexpandtab shiftwidth=8 softtabstop=8
" Trailing whitespace and tabs are forbidden, so highlight them.
highlight ForbiddenWhitespace ctermbg=red guibg=red
match ForbiddenWhitespace /\s\+$\|\t/
" Do not highlight spaces at the end of line while typing on that line.
autocmd InsertEnter * match ForbiddenWhitespace /\t\|\s\+\%#\@<!$/
2.2.2 Emacs 配置
对于 Emacs,请将这些大致等效的行添加到您的 .emacs.d/init.el 中:
(c-add-style "ffmpeg"
'("k&r"
(c-basic-offset . 4)
(indent-tabs-mode . nil)
(show-trailing-whitespace . t)
(c-offsets-alist
(statement-cont . (c-lineup-assignments +)))
)
)
(setq c-default-style "ffmpeg")
2.3 注释
使用 JavaDoc/Doxygen 格式(参见下面的示例),以便可以自动生成代码文档。所有非平凡函数都应在其上方有一个注释,解释该函数的作用,即使只有一句话。所有结构及其成员变量也应记录在案。
避免使用 Qt 风格和类似的 Doxygen 语法!在其中,即用 /// 和类似符号替换 //!。此外,标记命令应使用 @ 语法,即使用 @param 而不是 \param。
/**
* @file
* MPEG codec.
* @author ...
*/
/**
* Summary sentence.
* more text ...
* ...
*/
typedef struct Foobar {
int var1; /**< var1 description */
int var2; ///< var2 description
/** var3 description */
int var3;
} Foobar;
/**
* Summary sentence.
* more text ...
* ...
* @param my_parameter description of my_parameter
* @return return value description
*/
int myfunc(int my_parameter)
...
2.4 命名约定
函数、变量和结构成员的名称必须小写,使用下划线 (_) 分隔单词。例如,“avfilter_get_video_buffer”是可接受的函数名称,而“AVFilterGetVideo”则不是。
结构、联合、枚举和类型定义类型名称必须使用驼峰命名法。所有结构和联合都应使用与结构/联合标记相同的类型定义名称,例如 typedef struct AVFoo { ... } AVFoo;。枚举通常不使用类型定义。
枚举常量和宏必须大写,但伪装成函数的宏除外,这些宏应使用函数命名约定。
库中的所有标识符都应按以下方式命名:
- 文件和较低范围的标识符(例如局部变量、静态函数)以及结构和联合成员无需命名空间,
- ff_ 前缀必须用于文件范围之外可见的变量和函数,但只能在单个库内部使用,例如“ff_w64_demuxer”。这可防止 FFmpeg 静态链接时发生名称冲突。
- 对于在文件范围之外可见的变量和函数,在多个库内部使用,请使用 avpriv_ 作为前缀,例如“avpriv_report_missing_feature”。
- 所有其他内部标识符(如私有类型或宏名称)应仅使用命名空间,以避免可能的内部冲突。例如 H264_NAL_SPS 与 HEVC_NAL_SPS。
- 除了常用的 av_(libavformat 的 avformat_、libavcodec 的 avcodec、libswresample 的 swr_ 等)之外,每个库都有自己的公共符号前缀。检查现有代码并相应地选择名称。
- 其他公共标识符(结构、联合、枚举、宏、类型名称)必须使用其库的公共前缀(AV、Sws 或 Swr)。
此外,不应侵占为系统保留的名称空间。以 _t 结尾的标识符由 POSIX 保留。还应避免使用以 __ 或 _ 开头的名称,后跟大写字母,因为它们由 C 标准保留。以 _ 开头的名称在文件级别保留,不得用于外部可见符号。如有疑问,请完全避免使用以 _ 开头的名称。
2.5 其他约定
- 应仅在必要时使用强制类型转换。如果不必要的括号无法使代码更易于理解,也应避免使用。
3 开发政策
3.1 代码行为
正确性
代码必须有效。它不得崩溃、中止、访问无效指针、泄漏内存、导致数据争用或有符号整数溢出,或导致未定义的行为。应检查错误代码,并在适用时转发给调用者。
线程和库安全
我们的库可能由同一进程中的多个独立调用者调用。这些调用可能来自任意数量的线程,并且不同的调用站点可能彼此不知道 - 例如,用户程序可能直接调用我们的库,并使用一个或多个也调用我们库的库。代码必须在这种条件下正常运行。
稳健性
代码必须将从调用者收到的任何字节流或从文件、网络等读取的任何字节流视为不受信任。当向其发送任意数据时,它不得出现异常 - 通常它应该打印错误消息并在遇到无效输入数据时返回 AVERROR_INVALIDDATA。
内存分配
代码必须使用 libavutil/mem.h 中的 av_malloc() 函数系列来执行所有内存分配,特殊情况除外(例如,与需要使用特定分配器的外部库交互时)。
应检查所有分配,并在失败时返回 AVERROR(ENOMEM)。一个常见的错误是错误路径泄漏内存 - 确保不会发生这种情况。
stdio
我们的库不得直接访问 stdio 流 stdin/stdout/stderr(例如通过 printf() 函数系列),因为这对库不安全。对于日志记录,请使用 av_log()。
3.2 补丁/提交
补丁的许可证必须与 FFmpeg 兼容。
贡献内容应根据 LGPL 2.1 获得许可,包括“或任何后续版本”条款,或者,如果您更喜欢礼品式许可,则应根据 ISC 或 MIT 许可。包括“或任何后续版本”条款的 GPL 2 也是可以接受的,但 LGPL 是首选。如果您添加新文件,请为其提供适当的许可标头。不要从随机位置复制和粘贴,请使用现有文件作为模板。
您不得提交破坏 FFmpeg 的代码!
这意味着未完成的代码已启用并破坏了编译,或者编译但不工作/破坏了回归测试。在某些情况下,可能会允许使用未完成但已禁用的代码,例如缺少示例或具有一小部分功能的实现。在推送之前,请务必检查邮件列表中是否有任何有问题的审阅者并测试 FATE。
提交消息
提交消息是告知其他开发人员特定更改的作用及其原因的重要工具。每次提交都必须有正确填写的提交消息,格式如下:
area changed: short 1 line description
details describing what and why and giving references.
如果提交解决了我们错误跟踪器上已知的错误或其他外部问题(例如 CVE),则提交消息应包含相关的错误 ID 或其他外部标识符。请注意,这应该在适当的解释之外进行,而不是代替它。不接受诸如“已修复!”或“已更改”之类的评论。
当应用邮件列表中已详细讨论过的补丁时,请在提交消息中引用该线程。
测试必须充分但不能过度。
如果它对您和其他人有效并且通过了 FATE,那么提交它应该是可以的,只要它符合其他提交标准。您不必担心过度测试。如果您的代码有问题(可移植性、触发编译器错误、异常环境等),它们将被报告并最终修复。
不要一起提交不相关的更改。
应该将它们拆分成独立的部分。另外,不要忘记,如果 B 部分依赖于 A 部分,但 A 不依赖于 B,那么 A 可以而且应该首先提交并与 B 分开。将更改拆分成独立的部分,可以更轻松地在提交日志邮件列表中查看和理解它们。这也有助于以后进行调试。此外,如果您对拆分或不拆分有疑问,请随时在开发人员邮件列表中询问/讨论。
外观变化应保存在单独的补丁中。
如果源代码缩进和其他外观更改与功能更改混在一起,我们将拒绝这些更改,此类提交将被拒绝并删除。每个开发人员都有自己的缩进样式,您不应更改它。当然,如果您(重新)编写了某些内容,您可以使用自己的样式,尽管我们更希望整个 FFmpeg 的缩进保持一致(许多项目强制使用给定的缩进样式 - 我们不这样做。)。如果您确实需要进行缩进更改(尽量避免这种情况),请将它们与实际更改严格分开。
注意:如果您必须将 if(){ .. } 放在一大段(> 5 行)代码上,那么不要更改内部部分的缩进(不要将其向右移动)!或者在单独的提交中执行此操作
感谢补丁的作者。
确保提交的作者设置正确。 (参见 git commit –author)如果您应用了补丁,请向 ffmpeg-devel(或您从哪里获得补丁)发送答复,说明您应用了该补丁。
感谢任何研究人员
如果提交/补丁修复了某些研究人员发现的问题,请始终在提交消息中感谢研究人员发现/报告该问题。
在推送更改之前始终等待足够长的时间
请勿未经许可提交由他人积极维护的代码。将补丁发送到 ffmpeg-devel。如果在合理的时间范围内没有人回答(构建失败和安全修复需要 12 小时,小更改需要 3 天,大补丁需要 1 周),然后提交您的补丁(如果您认为没问题)。另请注意,维护者可以简单地要求更多时间进行审查!
3.3 代码
如果没有其他选项,可以禁用正确代码警告。
编译器警告表示潜在的错误或代码风格不良。如果某种类型的警告始终指向正确且干净的代码,则应禁用该警告,而不是更改代码。因此,其余的警告可以是错误,也可以是正确代码。如果是错误,则必须修复该错误。如果不是,则应更改代码以不生成警告,除非这会导致速度变慢或使代码混淆。
3.4 库公共接口
FFmpeg 中的每个库都在其安装的标头中提供了一组公共 API,这些 API 在该库的 Makefile 中的变量 HEADERS 中列出。这些标头中定义的所有标识符(除非另有明确记录的标识符)以及从编译的共享或静态库导出的相应符号都被视为公共接口,并且必须遵守本节中描述的 API 和 ABI 兼容性规则。
公共 API 必须在给定的主要版本内向后兼容。即只要主版本号不变,任何编译并适用于给定库版本的有效用户代码都必须仍可编译并适用于任何更高版本。此处的“有效用户代码”是指以记录和/或预期的方式调用我们的 API 且不依赖任何未定义行为的代码。增加主版本可能会破坏向后兼容性,但仅限于主版本升级中描述的程度。
我们还保证共享库和静态库的向后 ABI 兼容性。即,只要主版本号保持不变,就应该能够用任何更高版本的构建替换我们库的共享或静态构建(在静态情况下重新链接用户二进制文件),而不会破坏任何有效的用户二进制文件。
3.4.1 添加新接口
已安装标头中的任何新公共标识符都被视为新 API - 包括新函数、结构、宏、枚举值、typedef、现有结构中的新字段、新安装的标头等。添加新 API 时请考虑以下准则。
动机
虽然可以相对轻松地添加新 API,但由于上述兼容性要求,更改或删除它们要困难得多。然后,您应该仔细考虑您添加的功能是否真的需要作为新的公共 API 向我们的调用者公开。
您的新 API 应该至少有一个库之外的完善用例,而现有 API 无法轻易实现。FFmpeg 中的每个库也有一个定义的范围 - 您的新 API 必须适合它。
替换现有 API
如果您的新 API 正在替换现有 API,则它应该严格优于现有 API,以便使用新 API 的优势超过调用者更改代码的成本。添加新 API 后,您应该弃用旧 API 并将其安排为删除,如删除接口中所述。
如果您认为现有 API 存在缺陷并希望修复它,在大多数情况下,首选方法是添加不同名称的替换并弃用现有 API,而不是修改它。重要的是让调用者看到更改(例如通过编译或运行时弃用警告),并明确说明如何过渡到新 API(例如在 Doxygen 文档或 wiki 中)。
API 设计
FFmpeg 库被各种调用者用来执行各种多媒体相关的处理任务。因此,您应该在合理范围内尝试为最广泛的可行用例设计新的 API,避免不必要地将其限制为特定类型的调用者(例如,仅媒体播放或仅转码)。
一致性
检查 FFmpeg 中是否已经存在类似的 API。如果存在,请尝试以它们为模型来构建新添加的 API,以实现更好的整体一致性。
新标识符的命名应遵循命名约定,并与其他类似 API 保持一致(如果适用)。
可扩展性
您还应该考虑将来如何以向后兼容的方式扩展 API。如果您要添加新的结构 AVFoo,标准方法是要求调用者始终通过构造函数(通常名为 av_foo_alloc())分配它。这样,可以在不破坏 ABI 兼容性的情况下将新字段添加到结构的末尾。通常,您还需要一个析构函数 - av_foo_free(AVFoo**),它释放间接提供的对象(及其内容,如果适用)并将 NULL 写入提供的指针,从而消除调用者内存中潜在的悬空指针。
如果您要添加新函数,请考虑是否可能需要在将来调整其行为 - 您可能希望添加一个标志参数,即使它最初未使用。
文档
所有新 API 都必须以 Doxygen 格式的注释形式记录在您添加到公共标头的标识符上方。您还应该在 doc/APIchanges 中简要提及更改。
提升版本
向后不兼容的 API 或 ABI 更改需要增加(增加)主版本号,如主版本增加中所述。主版本增加是按计划发生的重大事件 - 因此如果您的更改严格要求进行一次,则应将其添加到 #if 预处理器保护下,以禁用它,直到下一次主版本增加发生。
可以在不破坏 API 或 ABI 兼容性的情况下添加的新 API 需要增加次版本号。
增加第三个(微)版本组件意味着值得注意的二进制兼容更改(例如,对解码器很重要的编码器错误修复)。第三个组件始终从 100 开始,以区分 FFmpeg 和 Libav。
3.4.2 删除接口
由于上述兼容性保证,删除 API 是一个复杂的过程,只有在有充分理由的情况下才应进行。通常,缺陷、限制或其他不充分的 API 会被更优的 API 取代,但有时我们也会删除某个 API 而不进行任何替换(例如,当它提供的功能被认为不值得维护、超出项目范围、存在根本缺陷等时)。
删除分为两个步骤 - 首先,API 已弃用并计划删除,但仍存在并可正常运行。第二步是实际删除 API - 这在主要版本更新中进行了描述。
要弃用 API,您应该向我们的用户发出信号,告知他们应停止使用该 API。例如,如果您打算删除结构成员或函数,则应使用 attribute_deprecated 标记它们。如果无法做到这一点,可以在运行时检测已弃用的 API 的使用并打印警告(但请注意不要打印得太频繁)。您还应该在相关的 Doxygen 文档块中记录弃用(以及替换,如果适用)。
最后,您应该在 libavbar/version_major.h(对于 libavutil,则为 version.h)中定义一个弃用保护,类似于 #define FF_API_<FOO> (LIBAVBAR_VERSION_MAJOR < XX)(其中 XX 是将删除 API 的主要版本)。然后将弃用 API 的所有使用包装在 #if FF_API_<FOO> 中.... #endif,这样一旦主版本达到 XX,代码就会自动被禁用。您还可以使用 FF_DISABLE_DEPRECATION_WARNINGS 和 FF_ENABLE_DEPRECATION_WARNINGS 来抑制这些保护内的编译器弃用警告。您应该测试代码是否编译并与保护宏一起计算为 true 和 false。
3.4.3 主要版本升级
主要版本升级表示 API 和/或 ABI 兼容性中断。为了减少对需要调整其代码的调用者的负面影响,主要升级期间的向后不兼容更改应仅限于:
- 删除以前弃用的 API。
- 执行 ABI 但不破坏 API 的更改,例如重新排序结构内容。
3.5 文档/其他
订阅 ffmpeg-devel 邮件列表。
订阅 ffmpeg-devel 邮件列表非常重要。几乎所有非平凡补丁都会发送到那里进行审查。其他开发人员可能会对您的贡献发表评论。我们希望您看到这些评论,并根据要求进行改进。(注意:经验丰富的提交者有其他渠道,有时可能会跳过对平凡修复的审查。)此外,此处关于其他开发人员的错误修复和 FFmpeg 改进的讨论可能对您有帮助。最后,作为列表订阅者,您的贡献将立即发布到列表中,而不会像非订阅者那样遇到审核保留。
但是,对于项目来说,我们收到您的补丁比您订阅 ffmpeg-devel 列表更重要。如果您有补丁,但不想订阅和讨论该补丁,请无论如何将其发送到列表。
订阅 ffmpeg-cvslog 邮件列表。
所有提交的差异都会发送到 ffmpeg-cvslog 邮件列表。一些开发人员会阅读此列表以查看来自所有来源的所有代码库更改。订阅此列表不是强制性的。
保持文档为最新。
如果您更改行为或添加功能,请更新文档。如果您不确定如何最好地执行此操作,请将补丁发送到 ffmpeg-devel,文档维护者将审查并提交您的内容。
重要的讨论应该对所有人都开放。
尝试将重要的讨论和请求(也)保留在公共开发人员邮件列表中,以便所有开发人员都能从中受益。
检查 MAINTAINERS 中的条目。
确保您维护的代码库的任何部分都没有在 MAINTAINERS 文件中缺失。如果您想要维护的某些内容缺失,请在其后添加您的姓名。如果您在某个时候不再想维护某些代码,请帮助寻找新的维护者,并且不要忘记更新 MAINTAINERS 文件。
我们认为我们的规则并不太严格。如果您有任何意见,请联系我们。
4 提交补丁
首先,如果您还没有阅读上面的编码规则,请阅读,特别是有关补丁提交的规则。
提交补丁时,请使用 git format-patch 或 git send-email。我们无法读取其他差异 :-)。
另外,请不要提交包含多个不相关更改的补丁。将其拆分为单独的、自成一体的部分。这并不意味着逐个文件拆分。相反,应尽可能缩小补丁,同时仍将其作为包含单个更改的逻辑单元,即使它跨越多个文件。这样可以让我们更轻松地审查您的补丁,并大大增加您的补丁应用的机会。
使用 FFmpeg 的 patcheck 工具检查您的补丁。该工具位于 tools 目录中。
在提交补丁之前运行回归测试,以验证它不会导致意外问题。
如果您告诉我们补丁的作用(例如“用 lrintf 替换 lrint”)以及原因(例如“*BSD 不符合 C99 且没有 lrint()”),也会有很大帮助。
如果您发送多个补丁,请将每个补丁作为单独的邮件发送,不要将多个不相关的补丁附加到同一封邮件中。
补丁应发布到 ffmpeg-devel 邮件列表。尽可能使用 git send-email,因为它可以正确发送补丁而无需额外注意。如果不能,请将补丁作为 base64 编码的附件发送,这样您的补丁就不会在传输过程中被丢弃。还要确保使用正确的 mime 类型(text/x-diff 或 text/x-patch 或至少 text/plain),并且每封邮件只有一个补丁是内联的或附加的。您可以检查 https://patchwork.ffmpeg.org,如果您的补丁没有出现,它的 mime 类型可能是错误的。
如何设置 git send-email?
请参阅 https://git-send-email.io/。对于 gmail,还请参阅 https://shallowsky.com/blog/tech/email/gmail-app-passwds.html。
从电子邮件客户端发送补丁
使用 git send-email 可能并不适合所有人。以下技巧允许以安全的方式通过电子邮件客户端发送补丁。它已在 Outlook 和 Thunderbird(带有 X-Unsent 扩展)上进行了测试,并且可能适用于其他应用程序。
像这样创建您的补丁:
git format-patch -s -o "outputfolder" --add-header "X-Unsent: 1" --suffix .eml --to ffmpeg-devel@ffmpeg.org -1 1a2b3c4d
现在您只需使用电子邮件应用程序打开 eml 文件并执行“发送”。
评论
您的补丁将在邮件列表中进行审查。您可能会被要求进行一些更改,并希望发送一个包含审查请求的改进版本。这个过程可能会经过几次迭代。一旦您的补丁被认为足够好,一些开发人员就会选择它并将其提交到官方 FFmpeg 树。
给我们几天时间做出反应。但如果过了一段时间仍未得到回应,请通过电子邮件发送提醒。您的补丁最终应该会得到处理。
5 新编解码器或格式检查表
- 您是否使用 av_cold 进行编解码器初始化和关闭函数?
- 您是否在 AVCodec 或 AVInputFormat/AVOutputFormat 结构中的 NULL_IF_CONFIG_SMALL 下添加了 long_name?
- 您是否在 libavcodec/version.h 或 libavformat/version.h 中增加了次版本号(并重置了微版本号)?
- 您是否在 allcodecs.c 或 allformats.c 中注册了它?
- 您是否将 AVCodecID 添加到 codec_id.h?添加新的编解码器 ID 时,还要在 libavcodec/codec_desc.c 中的编解码器描述符列表中添加一个条目。
- 如果它有 FourCC,您是否将其添加到 libavformat/riff.c,即使它只是一个解码器?
- 您是否在 Makefile 中添加了规则来编译相应的文件?即使您只是向已经由其他规则编译的文件添加格式,例如原始解复用器,也请记住执行此操作。
- 您是否在 doc/general_contents.texi 中向支持的格式或编解码器表添加了条目?
- 您是否在变更日志中添加了条目?
- 如果它依赖于解析器或库,您是否在 configure 中添加了该依赖项?
- 您是否在提交之前通过 git 添加了相应的文件?
- 您是否确保它可以独立编译,即使用 configure --disable-everything --enable-decoder=foo(或 --enable-demuxer 或您的组件)?
6 补丁提交清单
- 补丁应用后是否顺利通过?
- 补丁是用 git format-patch 还是 send-email 生成的?
- 您是否签署了补丁?(git commit -s)请参阅签署您的工作以了解签署的含义。
- 您是否提供了清晰的 git 提交日志消息?
- 补丁是否针对最新的 FFmpeg git master 分支?
- 您是否订阅了 ffmpeg-devel?(由于垃圾邮件,列表仅限订阅者)
- 您是否检查过这些更改是否微不足道,以至于无法通过较小的补丁和/或更简单的最终代码实现相同的效果?
- 如果更改是为了加快关键代码的速度,您是否对其进行了基准测试?
- 如果您进行了任何基准测试,您是否在邮件中提供了它们?
- 您是否检查过补丁是否不会导致缓冲区溢出或其他安全问题?
- 您是否针对损坏的数据测试过解码器或解复用器?如果没有,请参阅 tools/trasher、噪声比特流过滤器和 zzuf。您的解码器或解复用器在输入损坏数据时不应崩溃、以(接近)无限循环结束或分配大量内存。
- 您是否针对示例文件测试过解码器或解复用器?示例可在 https://samples.ffmpeg.org 获取。
- 补丁是否没有混合功能和外观更改?
- 您是否在代码中添加了制表符或尾随空格?两者都是被禁止的。
- 您发送的电子邮件中是否附有补丁?
- 补丁的 mime 类型是否正确?它应该是 text/x-diff 或 text/x-patch 或至少是 text/plain,而不是 application/octet-stream。
- 如果补丁修复了一个错误,您是否提供了该错误的详细分析?
- 如果补丁修复了一个错误,您是否提供了足够的信息(包括示例),以便可以重现错误并验证修复?请注意,请不要在邮件中附加超过 100k 的示例,而是提供一个 URL,您可以上传到 https://streams.videolan.org/upload/。
- 您是否提供了关于补丁更改内容的详细摘要?
- 您是否提供了详细的解释,说明为什么它会做出这样的改变?
- 您是否提供了详细的摘要,说明如果应用了该补丁,用户可见的优点和缺点是什么?
- 您是否提供了示例,以便我们轻松验证补丁添加的新功能?
- 如果您添加了新文件,您是否插入了许可证标头?它应该取自 FFmpeg,而不是随机复制并粘贴自其他地方。
- 您应该在按字母顺序排列的列表中保持字母顺序,只要这样做不会破坏 API/ABI 兼容性。
- 当这样做可以提高可读性时,具有相似内容的行应该垂直对齐。
- 考虑为您的代码添加回归测试。所有新模块都应通过测试覆盖。这包括解复用器、复用器、解码器、编码器过滤器、比特流过滤器、解析器。如果无法做到这一点,请在您的补丁集中添加解释,如果有原因,可以不测试。
- 如果您添加了 YASM 代码,请检查 –disable-yasm 是否仍能正常工作。
- 使用 valgrind 和/或 Address Sanitizer 测试您的代码,以确保其没有泄漏、数组访问错误等。
7 补丁审查流程
发布到 ffmpeg-devel 的所有补丁都将接受审查,除非它们明确说明该补丁不适用于 git master 分支。评论和意见将作为对邮件列表中补丁的回复发布。然后,补丁提交者必须处理每条意见,可以通过重新提交更改的补丁或通过讨论来处理。重新提交的补丁本身将像任何其他补丁一样接受审查。如果某个时候补丁通过了审查而没有意见,那么它就会被批准,对于简单和小型补丁,这可能会立即发生,而大型补丁通常必须经过多次更改和审查才能获得批准。补丁获得批准后,它将提交到存储库。
我们会审查所有已提交的补丁,但有时我们非常忙,因此,特别是对于大型补丁,这可能需要数周时间。
如果您觉得审查过程太慢,并且您愿意尝试接管您更改的代码区域的维护工作,那么只需克隆 git master 并在那里维护代码区域。我们会将每个区域从维护得最好的地方合并。
重新提交补丁时,请不要进行任何与审查期间收到的评论无关的重大更改。此类补丁将被拒绝。相反,请将重大更改或新功能作为单独的补丁提交。
欢迎所有人审查补丁。此外,如果您正在等待您的补丁被审查,请考虑帮助审查其他补丁,这是让每个人的补丁尽快得到审查的好方法。
8 回归测试
在提交补丁(或提交到存储库)之前,您至少应该测试您没有破坏任何东西。
运行 ’make fortune’ 即可完成此操作,详情请参阅fate.html。
[当然,某些补丁可能会改变回归测试的结果。在这种情况下,回归测试的参考结果应作相应修改]。
8.1 将文件添加到fate-suite数据集
如果您需要上传样本,请发送邮件至samples-request。
如果没有可用的多路复用器或编码器来为特定测试生成测试媒体,则必须将媒体包含在命运套件中。首先,请确保示例文件尽可能小,以便充分测试相应的解码器或解复用器。大文件会增加网络带宽和磁盘空间要求。一旦您有了有效的命运测试和命运样本,请在您发布到 ffmpeg-devel 邮件列表的补丁系列的提交消息或介绍消息中提供下载示例媒体的直接链接。
8.2 可视化测试覆盖率
FFmpeg 构建系统允许使用覆盖率工具 gcov/lcov 以简单的方式可视化测试覆盖率。这涉及以下步骤:
- 配置为在启用检测的情况下进行编译:configure --toolchain=gcov。
- 手动或通过 FATE 运行您的测试用例。这可以是完整的 FATE 回归套件,也可以是 FFmpeg 提供的任何前端工具的任意调用,以任意组合形式。
- 运行 make lcov 以生成 HTML 格式的覆盖率数据。
- 在您首选的 HTML 查看器中查看 lcov/index.html。
您可以使用命令 make lcov-reset 重置覆盖率测量。运行新测试后,您需要重新运行 make lcov。
8.3 使用 Valgrind
configure 脚本提供了使用 valgrind 发现与内存处理相关的错误的快捷方式。只需将选项 --toolchain=valgrind-memcheck 或 --toolchain=valgrind-massif 添加到您的 configure 行中,就会在 valgrind 套件的 memcheck 或 massif 工具的监督下为运行 FATE 设置合理的默认值。
如果您需要更好地控制 valgrind 的调用方式,请在配置行中使用 --target-exec='valgrind <your_custom_valgrind_options> 选项。
9 发布流程
FFmpeg 维护一组发布分支,这些分支是系统集成商和分销商(如 Linux 发行版等)的推荐交付物。发布经理会定期准备、测试并在 https://ffmpeg.org 网站上发布 tarball。
有两种发布:
- 主要发布始终包含最新和最好的特性和功能。
- 点发布是从发布分支中剪切出来的,名为 release/X,其中 X 是发布版本号。
请注意,我们向用户承诺,任何 FFmpeg 版本的共享库都不会破坏针对同一版本系列的先前版本编译的程序!
但是,我们有时会进行 API 更改,需要在应用程序中进行调整。此类更改仅允许在(新的)主要版本中,并且需要进一步的步骤,例如增加库版本号和/或调整符号版本文件。请及时在 ffmpeg-devel 邮件列表中讨论此类更改,以便进行前瞻性规划。
9.1 定点版本的标准
符合以下标准的更改是纳入定点版本的有效候选者:
- 修复安全问题,最好通过 http://cve.mitre.org/ 发布的 CVE 编号进行标识。
- 修复了 https://trac.ffmpeg.org 中记录的一个错误。
- 改进了所包含的文档。
- 保留了与同一发布分支的先前点版本的源代码和二进制兼容性。
检查规则的顺序为 (1 或 2 或 3) 和 4。
9.2 发布检查表
发布过程涉及以下步骤:
- 确保 RELEASE 文件包含即将发布的版本的版本号。
- 在 https://trac.ffmpeg.org/admin/ticket/versions 添加版本。
- 向邮件列表宣布发布意图。
- 确保所有相关的安全修复都已反向移植。请参阅 https://ffmpeg.org/security.html。
- 确保 FATE 回归套件至少在 i386 和 amd64 上仍然通过发布分支(参见回归测试)。
- 准备 bz2 和 gz 格式的发布 tarball,以及包含 gpg 签名的补充文件
- 在 https://ffmpeg.org/releases 发布 tarball。创建并推送 nX 形式的带注释的标签,其中 X 包含版本号。
- 提议并将补丁连同网站新闻条目一起发送到 ffmpeg-devel 邮件列表。
- 发布新闻条目。
- 向邮件列表发送公告。