开发者文档

目录

1 简介

本文档主要关注 FFmpeg 本身的开发。有关在其他程序中使用 FFmpeg 库的信息,请参见其他地方,例如

有关在外部程序中使用 FFmpeg 的更详细的法律信息,请阅读源代码树中的 LICENSE 文件,并查阅 https://ffmpeg.cpp.org.cn/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 示例

以下是一些值得注意的示例来说明 FFmpeg 中常见的代码样式

  • 赋值运算符周围和 if/do/while/for 关键字后有空格
    // Good
    if (condition)
        av_foo();
    
    // Good
    for (size_t i = 0; i < len; i++)
        av_bar(i);
    
    // Good
    size_t size = 0;
    

    但是,除非它有助于复杂条件的可读性,否则括号和条件之间没有空格,因此不应执行以下操作

    // Bad style
    if ( condition )
        av_foo();
    
  • 没有不必要的括号,除非它有助于可读性
    // Good
    int fields = ilace ? 2 : 1;
    
  • 单行块周围没有花括号
    // Good
    if (bits_pixel == 24)
        avctx->pix_fmt = AV_PIX_FMT_BGR24;
    else if (bits_pixel == 8)
        avctx->pix_fmt = AV_PIX_FMT_GRAY8;
    else {
        av_log(avctx, AV_LOG_ERROR, "Invalid pixel format.\n");
        return AVERROR_INVALIDDATA;
    }
    
  • 在有意义的情况下,避免在条件中赋值
    // Good
    video_enc->chroma_intra_matrix = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64)
    if (!video_enc->chroma_intra_matrix)
        return AVERROR(ENOMEM);
    
    // Bad style
    if (!(video_enc->chroma_intra_matrix = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64)))
        return AVERROR(ENOMEM);
    
    // Ok
    while ((entry = av_dict_iterate(options, entry)))
        av_log(ctx, AV_LOG_INFO, "Item '%s': '%s'\n", entry->key, entry->value);
    
  • 当声明指针变量时,* 与变量一起使用,而不是与类型一起使用
    // Good
    AVStream *stream;
    
    // Bad style
    AVStream* stream;
    

如果您处理的文件不一致地遵循这些指南,请更改您正在编辑的部分以遵循这些指南,但不要在文件中进行不相关的更改以使其符合这些指南。

2.2.2 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.3 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' 则不是。

Struct、union、enum 和 typedef 的类型名称必须使用 CamelCase。所有结构和联合都应该 typedef 为与 struct/union 标记相同的名称,例如 typedef struct AVFoo { ... } AVFoo;。枚举通常不 typedef。

枚举常量和宏必须大写,除非宏伪装成函数,否则应该使用函数命名约定。

库中的所有标识符都应按如下方式进行命名空间

  • 没有针对文件和较低范围的标识符(例如,局部变量、静态函数)以及结构和联合成员的命名空间,
  • ff_ 前缀必须用于文件范围之外可见的变量和函数,但只能在单个库内部使用,例如 'ff_w64_demuxer'。这可以防止在静态链接 FFmpeg 时发生名称冲突。
  • 对于在文件作用域之外可见,且在多个库内部使用的变量和函数,请使用 avpriv_ 作为前缀,例如 ‘avpriv_report_missing_feature’。
  • 所有其他内部标识符,如私有类型或宏名称,应仅进行命名空间划分,以避免可能的内部冲突。例如,H264_NAL_SPSHEVC_NAL_SPS
  • 除了常用的 av_ 之外,每个库都有其自己的公共符号前缀(avformat_ 用于 libavformat,avcodec_ 用于 libavcodec,swr_ 用于 libswresample 等)。请查看现有代码并相应地选择名称。
  • 其他公共标识符(结构体、联合体、枚举、宏、类型名称)必须使用其库的公共前缀(AVSwsSwr)。

此外,不应侵犯为系统保留的命名空间。以 _t 结尾的标识符由 POSIX 保留。 还要避免以 ___ 后跟大写字母开头的名称,因为它们由 C 标准保留。以 _ 开头的名称在文件级别保留,不能用于外部可见的符号。如果存疑,请完全避免使用以 _ 开头的名称。

2.5 其他约定

  • 应仅在必要时使用强制类型转换。如果括号没有使代码更容易理解,也应避免使用不必要的括号。

3 开发策略

3.1 代码行为

正确性

代码必须是有效的。它不能崩溃、中止、访问无效指针、泄漏内存、导致数据竞争或有符号整数溢出,或者以其他方式导致未定义的行为。应检查错误代码,并在适用时将其转发给调用者。

线程和库安全

我们的库可能会被同一进程中的多个独立调用者调用。这些调用可能发生在任意数量的线程中,并且不同的调用站点可能彼此不知道 - 例如,用户程序可能直接调用我们的库,并且使用一个或多个也调用我们库的库。代码必须在这种情况下正确运行。

健壮性

代码必须将从调用者接收或从文件、网络等读取的任何字节流视为不受信任的。当向其发送任意数据时,它不能出现异常行为 - 通常,当遇到无效输入数据时,它应该打印错误消息并返回 AVERROR_INVALIDDATA

内存分配

代码必须使用来自 libavutil/mem.hav_malloc() 系列函数来执行所有内存分配,除非在特殊情况下(例如,当与需要使用特定分配器的外部库交互时)。

应检查所有分配,并在失败时返回 AVERROR(ENOMEM)。一个常见的错误是错误路径会泄漏内存 - 请确保不会发生这种情况。

stdio

我们的库不能直接访问 stdio 流 stdin/stdout/stderr(例如,通过 printf() 系列函数),因为这不安全。对于日志记录,请使用 av_log()

3.2 补丁/提交

补丁的许可证必须与 FFmpeg 兼容。

贡献应根据 LGPL 2.1 (包括“或任何后续版本”条款)进行许可,或者,如果您喜欢礼物式许可,则使用 ISCMIT 许可证。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 的缩进保持一致(许多项目强制使用给定的缩进风格 - 我们不这样做)。如果您确实需要进行缩进更改(尽量避免这种情况),请将它们与实际更改严格分开。

注意:如果您必须在一段很大的代码块(> 5 行)上放置 if(){ .. },则不要更改内部部分的缩进(不要将其向右移动)!或者在一个单独的提交中这样做

注明补丁的作者。

确保正确设置提交的作者。(请参阅 git commit –author)如果您应用了补丁,请发送回复给 ffmpeg-devel(或您获取补丁的任何位置),说明您已应用了该补丁。

感谢所有研究人员

如果提交/补丁修复了某些研究人员发现的问题,请始终在提交消息中感谢该研究人员发现/报告该问题。

在推送更改之前,请始终等待足够长的时间

未经许可,请勿提交对他人积极维护的代码的更改。请将补丁发送至 ffmpeg-devel。如果在合理的时间范围内(构建失败和安全修复为 12 小时,小更改为 3 天,大补丁为 1 周)无人回应,则如果您认为补丁没问题,请提交您的补丁。另请注意,维护者可以简单地要求更多时间来审查!

3.3 代码

如果别无选择,可以禁用正确代码的警告。

编译器警告指示潜在的错误或风格不良的代码。如果某种类型的警告总是指向正确且干净的代码,则应禁用该警告,而不是更改代码。因此,剩余的警告要么是错误,要么是正确的代码。如果是错误,则必须修复该错误。如果不是,则应更改代码以不生成警告,除非这会导致速度下降或使代码难以理解。

3.4 库的公共接口

FFmpeg 中的每个库都在其安装的头文件中提供一组公共 API,这些头文件是在该库的 Makefile 中的变量 HEADERS 中列出的。在这些头文件中定义的所有标识符(除非另有明确说明)以及从编译的共享或静态库导出的相应符号都被视为公共接口,并且必须符合本节中描述的 API 和 ABI 兼容性规则。

公共 API 必须在给定的主要版本内向后兼容。也就是说,任何使用给定库版本编译并运行的有效用户代码,只要主版本号不变,就必须仍然能够编译并运行在任何更高版本上。此处“有效用户代码”是指以文档记录和/或预期的方式调用我们 API,并且不依赖任何未定义行为的代码。增加主版本可能会破坏向后兼容性,但仅限于 主版本号的增加 中描述的程度。

我们还保证共享和静态库的向后 ABI 兼容性。也就是说,应该可以用任何更高版本的库的构建版本(在静态情况下重新链接用户二进制文件)替换我们的库的共享或静态构建,而不会破坏任何有效的用户二进制文件,只要主版本号保持不变。

3.4.1 添加新接口

安装的头文件中的任何新的公共标识符都被认为是新的 API - 这包括新的函数、结构体、宏、枚举值、类型定义、现有结构体中的新字段、新的安装头文件等。在添加新的 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。如果您要添加新的结构体 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,您应该向我们的用户发出信号,表明他们应该停止使用它。例如,如果您打算删除结构成员或函数,您应该使用 attribute_deprecated 标记它们。当无法执行此操作时,可能会在运行时检测到已弃用 API 的使用并打印警告(但要注意不要打印太多次)。您还应该在相关的 Doxygen 文档块中记录弃用(以及替换,如果适用)。

最后,您应该在 libavbar/version_major.hlibavutil 的情况下为 version.h)中定义一个类似于 #define FF_API_<FOO> (LIBAVBAR_VERSION_MAJOR < XX) 的弃用保护(其中 XX 是将删除 API 的主版本)。然后将弃用 API 的所有使用包装在 #if FF_API_<FOO> .... #endif 中,以便一旦主版本达到 XX,代码将自动被禁用。您还可以使用 FF_DISABLE_DEPRECATION_WARNINGSFF_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-patchgit send-email。我们无法读取其他差异 :-)。

另外,请不要提交包含多个不相关更改的补丁。将其拆分为单独的、自包含的部分。这并不意味着按文件拆分。相反,在保持补丁尽可能小的同时,仍保持其为一个包含单个更改的逻辑单元,即使它跨越多个文件。这使我们更容易审查您的补丁,并大大增加了您的补丁被应用的机会。

使用 FFmpeg 的 patcheck 工具检查您的补丁。该工具位于 tools 目录中。

在提交补丁之前运行回归测试,以验证它不会导致意外问题。

如果您告诉我们补丁的作用(例如“将 lrint 替换为 lrintf”)以及原因(例如“*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 [email protected] -1 1a2b3c4d

现在您只需要使用电子邮件应用程序打开 eml 文件并执行“发送”。

审查

您的补丁将在邮件列表上进行审查。您可能会被要求进行一些更改,并期望您发送改进版本,其中包含审查中的请求。此过程可能会经历多次迭代。一旦您的补丁被认为足够好,一些开发人员将将其拾取并提交到官方 FFmpeg 树。

请给我们几天时间来做出反应。但是,如果过了一段时间没有反应,请通过电子邮件发送提醒。您的补丁最终应该会被处理。

5 新的编解码器或格式清单

  1. 您是否对编解码器初始化和关闭函数使用了 av_cold?
  2. 您是否在 NULL_IF_CONFIG_SMALL 下向 AVCodec 或 AVInputFormat/AVOutputFormat 结构体添加了 long_name?
  3. 您是否在 libavcodec/version.hlibavformat/version.h 中提升了次版本号(并重置了微版本号)?
  4. 您是否在 allcodecs.callformats.c 中注册了它?
  5. 您是否将 AVCodecID 添加到 codec_id.h?添加新的编解码器 ID 时,还要在 libavcodec/codec_desc.c 中的编解码器描述符列表中添加一个条目。
  6. 如果它有 FourCC,您是否将其添加到 libavformat/riff.c 中,即使它只是一个解码器?
  7. 您是否在 Makefile 中添加了规则以编译相应的 文件?请记住,即使您只是将格式添加到已经被其他规则编译的文件中(例如原始解复用器),也要执行此操作。
  8. 您是否在 doc/general_contents.texi 中支持的格式或编解码器表中添加了一个条目?
  9. 您是否在 Changelog 中添加了一个条目?
  10. 如果它依赖于解析器或库,您是否在配置中添加了该依赖项?
  11. 您是否在提交之前 git add 了相应的文件?
  12. 您是否确保它可以独立编译,即使用 configure --disable-everything --enable-decoder=foo(或 --enable-demuxer 或您的组件是什么)?

6 补丁提交清单

  1. 应用补丁后 make fate 是否通过?
  2. 补丁是否使用 git format-patch 或 send-email 生成?
  3. 您是否签署了您的补丁? (git commit -s) 有关签署的含义,请参阅 签署您的工作
  4. 您是否提供了清晰的 git 提交日志消息?
  5. 该补丁是否基于最新的 FFmpeg git master 分支?
  6. 您是否订阅了 ffmpeg-devel 邮件列表?(由于垃圾邮件问题,该列表仅限订阅者)
  7. 您是否已检查所做的更改是否为最小化,即是否无法通过更小的补丁和/或更简洁的最终代码来实现相同的功能?
  8. 如果更改是为了加速关键代码,您是否对其进行了基准测试?
  9. 如果您进行了任何基准测试,您是否在邮件中提供了这些测试结果?
  10. 您是否已检查该补丁是否引入了缓冲区溢出或其他安全问题?
  11. 您是否针对损坏的数据测试了您的解码器或解复用器?如果没有,请参阅 tools/trasher、噪声比特流过滤器和 zzuf。您的解码器或解复用器在输入损坏的数据时,不应崩溃、陷入(接近)无限循环或分配过多的内存。
  12. 您是否针对样本文件测试了您的解码器或解复用器?样本可以在 https://samples.ffmpeg.org 获取。
  13. 该补丁是否没有混杂功能性更改和表面性更改?
  14. 您是否在代码中添加了制表符或尾随空格?这两者都是禁止的。
  15. 补丁是否作为附件添加到您发送的邮件中?
  16. 补丁的 MIME 类型是否正确?它应该是 text/x-diff 或 text/x-patch,或者至少是 text/plain,而不是 application/octet-stream。
  17. 如果补丁修复了一个错误,您是否提供了关于该错误的详细分析?
  18. 如果补丁修复了一个错误,您是否提供了足够的信息(包括示例),以便可以重现该错误并验证修复?请注意,不要将大于 100k 的样本附加到邮件中,而是提供一个 URL,您可以上传到 https://streams.videolan.org/upload/
  19. 您是否提供了关于补丁所做的更改的详细摘要?
  20. 您是否提供了关于补丁为何如此更改的详细解释?
  21. 您是否提供了关于应用该补丁后用户可见的优点和缺点的详细摘要?
  22. 您是否提供了一个示例,以便我们可以轻松验证该补丁添加的新功能?
  23. 如果您添加了一个新文件,您是否添加了许可证头?它应该从 FFmpeg 中获取,而不是从其他地方随机复制粘贴。
  24. 您应该在按字母顺序排列的列表中保持字母顺序,只要这样做不会破坏 API/ABI 兼容性。
  25. 当垂直对齐具有相似内容的行可以提高可读性时,应该垂直对齐它们。
  26. 考虑为您的代码添加回归测试。所有新模块都应进行测试。这包括解复用器、复用器、解码器、编码器、过滤器、比特流过滤器、解析器。如果无法做到这一点,请在您的补丁集中添加解释说明原因,如果有理由不进行测试是可以的。
  27. 如果您添加了 NASM 代码,请检查在禁用 –disable-x86asm 的情况下,事情是否仍然正常工作。
  28. 使用 valgrind 和/或 Address Sanitizer 测试您的代码,以确保它没有内存泄漏、数组越界访问等问题。

7 补丁审查流程

所有发布到 ffmpeg-devel 的补丁都将进行审核,除非它们包含明确的说明,表明该补丁不是针对 git master 分支的。审核和评论将作为邮件列表中对补丁的回复发布。然后,补丁提交者必须处理每一条评论,可以通过重新提交更改后的补丁或通过讨论进行处理。重新提交的补丁将像任何其他补丁一样进行审核。如果在某个时候补丁通过审核且没有评论,则该补丁将被批准,对于简单的小补丁,这可能会立即发生,而大的补丁通常必须经过多次更改和审核才能被批准。补丁获得批准后,将被提交到存储库。

我们将审核所有提交的补丁,但有时我们非常忙,因此特别是对于大型补丁,这可能需要几周的时间。

如果您觉得审核过程太慢,并且您愿意尝试接管您更改的代码区域的维护工作,那么只需克隆 git master 并在那里维护代码区域。我们将从最佳维护的地方合并每个区域。

重新提交补丁时,请不要进行任何与审核期间收到的评论无关的重大更改。此类补丁将被拒绝。相反,请将重大更改或新功能作为单独的补丁提交。

欢迎大家审核补丁。此外,如果您正在等待审核您的补丁,请考虑帮助审核其他补丁,这是让每个人的补丁更快得到审核的好方法。

8 回归测试

在提交补丁(或提交到存储库)之前,您至少应测试您是否没有破坏任何东西。

运行“make fate”即可完成此操作,请参阅 fate.html 了解详细信息。

[当然,某些补丁可能会更改回归测试的结果。在这种情况下,应相应地修改回归测试的参考结果。]

8.1 向 fate-suite 数据集添加文件

如果您需要上传示例,请发送邮件至 samples-request。

当没有可用的复用器或编码器来为特定测试生成测试媒体时,该媒体必须包含在 fate-suite 中。首先,请确保示例文件尽可能小,以充分测试相应的解码器或解复用器。大型文件会增加网络带宽和磁盘空间需求。一旦您有了可用的 fate 测试和 fate 示例,请在提交消息或您发布到 ffmpeg-devel 邮件列表的补丁系列的介绍性消息中,提供下载示例媒体的直接链接。

8.2 可视化测试覆盖率

FFmpeg 构建系统允许使用覆盖率工具 gcov/lcov 以简单的方式可视化测试覆盖率。这涉及以下步骤

  1. 配置为启用插桩编译:configure --toolchain=gcov
  2. 手动或通过 FATE 运行您的测试用例。这可以是完整的 FATE 回归套件,也可以是 FFmpeg 提供的任何前端工具的任意调用组合。
  3. 运行 make lcov 以生成 HTML 格式的覆盖率数据。
  4. 在您首选的 HTML 查看器中查看 lcov/index.html

您可以使用命令 make lcov-reset 重置覆盖率测量。运行新的测试后,您需要重新运行 make lcov

8.3 使用 Valgrind

configure 脚本提供了一个使用 valgrind 来发现与内存处理相关的错误的快捷方式。只需在您的 configure 行中添加选项 --toolchain=valgrind-memcheck--toolchain=valgrind-massif,就会为在 valgrind 套件的 memcheckmassif 工具的监督下运行 FATE 设置合理的默认值。

如果您需要更精细地控制 valgrind 的调用方式,请在您的 configure 行中使用 --target-exec='valgrind <your_custom_valgrind_options> 选项代替。

9 维护流程

9.1 维护者

维护代码库每个部分的开发人员在 MAINTAINERS 中列出。在 MAINTAINERS 中列出,使您有权对特定存储库拥有 git 写入权限。

9.2 成为维护者

人们通过像提交其他代码更改一样发送补丁来将自己添加到 MAINTAINERS 中。这些补丁会像其他任何补丁一样由社区审查。如果有人对新的维护者有异议,则需要公开实名提出异议,并愿意接管该领域的维护工作。

10 发布流程

FFmpeg 维护一系列发布分支,这些分支是系统集成商和发行商(如 Linux 发行版等)推荐的交付物。在固定的时间,发布管理员会准备、测试并在 https://ffmpeg.cpp.org.cn 网站上发布 tar 包。

发布版本有两种类型

  1. 主要版本始终包含最新、最强大的功能。
  2. 点发布版本发布分支切割而来,发布分支命名为 release/X,其中 X 是发布版本号。

请注意,我们向用户承诺,任何 FFmpeg 版本的共享库都不会破坏针对同一发布系列的早期版本编译的程序!

然而,我们有时会进行 API 更改,这需要在应用程序中进行调整。此类更改仅允许在(新的)主要版本中进行,并且需要进一步的步骤,例如增加库版本号和/或调整符号版本控制文件。请及时在 ffmpeg-devel 邮件列表中讨论此类更改,以便进行提前规划。

10.1 小版本发布的标准

符合以下标准的更改是包含在点发布版本中的有效候选

  1. 修复安全问题,最好是通过 http://cve.mitre.org/ 发布的 CVE 编号进行标识。
  2. 修复 https://trac.ffmpeg.org 中记录的错误。
  3. 改进包含的文档。
  4. 与同一发布分支的先前点发布版本保持源代码和二进制兼容性。

检查规则的顺序是 (1 或 2 或 3) 且 4。

10.2 发布清单

发布过程包括以下步骤

  1. 确保 RELEASE 文件包含即将发布的版本的版本号。
  2. https://trac.ffmpeg.org/admin/ticket/versions 中添加发布版本。
  3. 向邮件列表宣布发布意图。
  4. 确保所有相关的安全修复程序都已反向移植。请参阅 https://ffmpeg.cpp.org.cn/security.html
  5. 确保 FATE 回归测试套件在至少 i386amd64 上的发布分支中仍然通过(参见 回归测试)。
  6. 准备 bz2gz 格式的发布 tar 包,并补充包含 gpg 签名的文件
  7. 将 tar 包发布到 https://ffmpeg.cpp.org.cn/releases。创建并推送一个形如 nX 的带注释的标签,其中 X 包含版本号。
  8. ffmpeg-devel 邮件列表提交并发送一个包含网站新闻条目的补丁。
  9. 发布新闻条目。
  10. 向邮件列表发送公告。

本文档于2025 年 1 月 21 日使用 makeinfo 生成。

托管服务由 telepoint.bg 提供