Hi Marvin, Thanks for the review.
> There is no need to split this in two commands Good point I'll update the example to use git send-email directly against origin/master. > samples.ffmpeg.org is not the same thing as the FATE suite I'll correct the rsync URL to fate.ffmpeg.org/fate-suite/ and fix the surrounding prose. > This would not be a proper test as it always succeeds You're right the exit code needs to reflect the actual result. I'll fix the example to return 1 on failure. Will send a v2 shortly. Thanks, Marcos On Sat, 14 Mar 2026 at 19:43, Marvin Scholz via ffmpeg-devel < [email protected]> wrote: > > On 14 Mar 2026, at 20:17, marcos ashton via ffmpeg-devel wrote: > > > Add contributing.html covering building FFmpeg, submitting > > patches via Forgejo, the review process, and writing FATE > > tests for libavutil, libavfilter, and libavcodec. > > > > Sidebar nav left unchanged to avoid breaking bookmarks. > > > > Signed-off-by: marcos ashton <[email protected]> > > Some remarks inline below (not a full detailed review): > > > --- > > Makefile | 2 +- > > src/contributing | 410 +++++++++++++++++++++++++++++++++++++++++ > > src/contributing_js | 0 > > src/contributing_title | 1 + > > 4 files changed, 412 insertions(+), 1 deletion(-) > > create mode 100644 src/contributing > > create mode 100644 src/contributing_js > > create mode 100644 src/contributing_title > > > > diff --git a/Makefile b/Makefile > > index dd681e4..4f5c187 100644 > > --- a/Makefile > > +++ b/Makefile > > @@ -1,6 +1,6 @@ > > # ffmpeg.org HTML generation from source files > > > > -SRCS = about bugreports consulting contact donations documentation > download \ > > +SRCS = about bugreports consulting contact contributing donations > documentation download \ > > olddownload index legal shame security spi archive > > > > HTML_TARGETS = $(addsuffix .html,$(addprefix htdocs/,$(SRCS))) > > diff --git a/src/contributing b/src/contributing > > new file mode 100644 > > index 0000000..d68aab2 > > --- /dev/null > > +++ b/src/contributing > > @@ -0,0 +1,410 @@ > > +<p> > > + This page covers everything a first-time contributor needs to get > > + started: building FFmpeg, submitting patches, understanding code > review, > > + and writing tests. > > +</p> > > + > > +<p> > > + For the full developer reference, see > > + <a href="developer.html">Developer Documentation</a> and > > + <a href="git-howto.html">Using Git to Develop FFmpeg</a>. > > +</p> > > + > > +<br> > > + > > +<h3 id="BuildSetup"> > > + <span class="pull-right"> > > + <i class="fa fa-wrench"></i> > > + </span> > > + Building FFmpeg</h3> > > + > > +<p> > > + Clone the repository and build: > > +</p> > > + > > +<pre> > > +git clone https://git.ffmpeg.org/ffmpeg.git > > +cd ffmpeg > > +./configure > > +make -j$(nproc)</pre> > > + > > +<p> > > + This builds ffmpeg, ffplay, and ffprobe. Run > > + <code>./configure --help</code> to see all options. > > +</p> > > + > > +<p> > > + For development, you probably want debug symbols and test coverage: > > +</p> > > + > > +<pre> > > +./configure --toolchain=gcov --assert-level=2 > > +make -j$(nproc)</pre> > > + > > +<p> > > + Verify your build: > > +</p> > > + > > +<pre> > > +./ffmpeg -version</pre> > > + > > +<br> > > + > > +<h3 id="SubmittingPatches"> > > + <span class="pull-right"> > > + <i class="fa fa-code-fork"></i> > > + </span> > > + Submitting Patches</h3> > > + > > +<p> > > + The preferred way to submit patches is through > > + <a href="https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls">Forgejo</a> > > + at code.ffmpeg.org. You can also send patches to the > > + <a href="https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-devel/ > ">ffmpeg-devel</a> > > + mailing list using <code>git format-patch</code> or > > + <code>git send-email</code>. > > +</p> > > + > > +<p> > > + GitHub pull requests are not part of the review process and will be > ignored. > > +</p> > > + > > +<p><strong>Via Forgejo (recommended)</strong></p> > > + > > +<ol> > > + <li>Create an account at > > + <a href="https://code.ffmpeg.org">code.ffmpeg.org</a>.</li> > > + <li>Fork the FFmpeg repository.</li> > > + <li>Push your branch to your fork.</li> > > + <li>Open a pull request against the main FFmpeg repository.</li> > > +</ol> > > + > > +<p><strong>Via mailing list</strong></p> > > + > > +<p> > > + Generate and send patches: > > +</p> > > + > > +<pre> > > +git format-patch origin/master > > +git send-email *.patch --to [email protected]</pre> > > + > > There is no need to split this in two commands, you can just do: > > git send-email --to [email protected] origin/master > > and avoid the glob and possibly sending outdated patches again. > > > +<p> > > + Subscribe to ffmpeg-devel first. Patches from non-subscribers are held > > + for moderation and may be delayed. See > > + <a href="git-howto.html">Using Git to Develop FFmpeg</a> for > > + setup instructions. > > +</p> > > + > > +<p><strong>Commit message format</strong></p> > > + > > +<p> > > + The first line must follow this format: > > +</p> > > + > > +<pre> > > +area/component: short description of what changed</pre> > > + > > +<p> > > + Then a blank line, then the body explaining why the change is needed. > > + The diff shows what changed; the message should explain why. > > + End with a Signed-off-by line (<code>git commit -s</code>). > > +</p> > > + > > +<p> > > + Full example: > > +</p> > > + > > +<pre> > > +avcodec/libx264: fix memory leak in parameter parsing > > + > > +The options dictionary was not freed on the error path when > > +x264_param_parse() returned a failure code. > > + > > +Signed-off-by: Your Name <[email protected]></pre> > > + > > +<p> > > + Keep the first line under 72 characters. Each patch should be a single > > + logical change. Do not mix cosmetic changes with functional changes. > > + Run <code>tools/patcheck</code> on your patch before sending. > > +</p> > > + > > +<br> > > + > > +<h3 id="ReviewProcess"> > > + <span class="pull-right"> > > + <i class="fa fa-comments"></i> > > + </span> > > + The Review Process</h3> > > + > > +<p> > > + Every patch is reviewed by other developers, whether you submit via > > + Forgejo or the mailing list. Here is what to expect: > > +</p> > > + > > +<ol> > > + <li>A reviewer reads your patch and leaves comments. This may take > > + a few days. If you have not heard back after a week, send a > > + polite reminder or ask on <code>#ffmpeg-devel</code> on > > + <a href="https://libera.chat/">Libera Chat</a>.</li> > > + <li>Address every comment. If you disagree with a suggestion, explain > > + your reasoning. Ignoring review comments will stall your patch.</li> > > + <li>Submit a revised version. On Forgejo, push to your branch. On the > > + mailing list, send a new version with <code>[PATCH v2]</code> in > > + the subject.</li> > > + <li>Repeat until the reviewer is satisfied. Simple patches may land > > + after one round. Larger patches often go through several > > + revisions.</li> > > + <li>Once approved, a developer with commit access pushes it to > > + master.</li> > > +</ol> > > + > > +<p> > > + Reviewing other people's patches is one of the best ways to get your > > + own patches reviewed faster. Everyone is welcome to review. > > +</p> > > + > > +<br> > > + > > +<h3 id="BeforeYouSubmit"> > > + <span class="pull-right"> > > + <i class="fa fa-check-square-o"></i> > > + </span> > > + Before You Submit</h3> > > + > > +<p> > > + Run the FATE test suite to make sure nothing is broken: > > +</p> > > + > > +<pre> > > +make fate</pre> > > + > > +<p> > > + Many tests require sample media files that are not included in the > > + source tree. Download them from > > + <a href="https://samples.ffmpeg.org">samples.ffmpeg.org</a> (rsync > > + is the fastest method): > > +</p> > > samples.ffmpeg.org is not the same thing as the FATE suite, afaik. > > > + > > +<pre> > > +rsync -a --no-inc-recursive rsync://fate.ffmpeg.org/fate-suite/ > fate-suite/</pre> > > + > > +<p> > > + Then tell <code>./configure</code> where the samples live, either > > + at configure time: > > +</p> > > + > > +<pre> > > +./configure --samples=/path/to/fate-suite</pre> > > + > > +<p> > > + or as a make variable: > > +</p> > > + > > +<pre> > > +make fate SAMPLES=/path/to/fate-suite</pre> > > + > > +<p> > > + Without sample files, tests that depend on them are skipped rather > > + than failed, so your basic build will still pass. But if your patch > > + touches a codec, demuxer, or filter that has sample-based tests, run > > + with samples to make sure nothing regressed. > > +</p> > > + > > +<p> > > + If your patch changes expected output, update the reference files. > > + If your patch adds a new module (decoder, encoder, filter, muxer, > > + demuxer, parser, or bitstream filter), add a FATE test for it. > > +</p> > > + > > +<p> > > + Check your patch for common issues: > > +</p> > > + > > +<pre> > > +tools/patcheck your-patch.diff</pre> > > + > > +<p> > > + See the > > + <a href="developer.html#Patch-submission-checklist">Patch Submission > Checklist</a> > > + for the full list. > > +</p> > > + > > +<br> > > + > > +<h3 id="WritingFATETests"> > > + <span class="pull-right"> > > + <i class="fa fa-flask"></i> > > + </span> > > + Writing FATE Tests</h3> > > + > > +<p> > > + FATE (FFmpeg Automated Testing Environment) is the regression test > > + suite. Tests are defined in <code>tests/fate/*.mak</code> files. > > + Reference outputs live in <code>tests/ref/fate/</code>. There are > > + three common patterns. > > +</p> > > + > > +<p><strong>C unit tests (libavutil)</strong></p> > > + > > +<p> > > + For testing utility functions, write a standalone C program that > > + exercises the API and prints results to stdout. > > +</p> > > + > > +<p> > > + Create the test at <code>libavutil/tests/yourtest.c</code>: > > +</p> > > + > > +<pre> > > +#include "libavutil/yourheader.h" > > + > > +int main(void) > > +{ > > + /* call the functions you want to test */ > > + printf("some_function: %s\n", result ? "OK" : "FAIL"); > > + return 0; > > +}</pre> > > This would not be a proper test as it always succeeds from the PoV of > make, as the exit status is 0 regardless of the outcome. > > > + > > +<p> > > + Add it to <code>libavutil/Makefile</code>: > > +</p> > > + > > +<pre> > > +TESTPROGS += yourtest</pre> > > + > > +<p> > > + Register it in <code>tests/fate/libavutil.mak</code>: > > +</p> > > + > > +<pre> > > +FATE_LIBAVUTIL += fate-yourtest > > +fate-yourtest: libavutil/tests/yourtest$(EXESUF) > > +fate-yourtest: CMD = run libavutil/tests/yourtest$(EXESUF)</pre> > > + > > +<p> > > + Generate the reference output: > > +</p> > > + > > +<pre> > > +make fate-yourtest GEN=1</pre> > > + > > +<p> > > + This creates <code>tests/ref/fate/yourtest</code>. If your test only > > + checks exit codes and produces no meaningful stdout, add > > + <code>CMP = null</code>. > > +</p> > > + > > +<p><strong>Filter tests (libavfilter)</strong></p> > > + > > +<p> > > + Filter tests run a filter chain and compare per-frame CRC checksums > > + against a reference. They go in > > + <code>tests/fate/filter-audio.mak</code> or > > + <code>tests/fate/filter-video.mak</code>. > > +</p> > > + > > +<p> > > + Example for an audio filter: > > +</p> > > + > > +<pre> > > +FATE_AFILTER-$(call FILTERDEMDECENCMUX, YOURFILTER, WAV, PCM_S16LE, > PCM_S16LE, WAV) += fate-filter-yourfilter > > +fate-filter-yourfilter: tests/data/asynth-44100-2.wav > > +fate-filter-yourfilter: SRC = > $(TARGET_PATH)/tests/data/asynth-44100-2.wav > > +fate-filter-yourfilter: CMD = framecrc -i $(SRC) -af yourfilter</pre> > > + > > +<p> > > + The <code>FILTERDEMDECENCMUX</code> macro checks that all required > > + components are compiled in. The <code>framecrc</code> command computes > > + a CRC for each output frame. Generate the reference: > > +</p> > > + > > +<pre> > > +make fate-filter-yourfilter GEN=1</pre> > > + > > +<p> > > + This writes the reference to > > + <code>tests/ref/fate/filter-yourfilter</code>. To test multiple > > + format variants, add separate entries with suffixes like > > + <code>fate-filter-yourfilter-fltp</code>. > > +</p> > > + > > +<p><strong>Codec roundtrip tests (libavcodec)</strong></p> > > + > > +<p> > > + These encode audio or video with a codec, decode it back, and compare > > + the result against a reference. They live in > > + <code>tests/fate/acodec.mak</code>, > > + <code>tests/fate/vcodec.mak</code>, or a codec-specific > > + <code>.mak</code> file. > > +</p> > > + > > +<p> > > + The generic template in <code>tests/fate/acodec.mak</code> handles > > + most audio codecs. To use it, add a single line: > > +</p> > > + > > +<pre> > > +FATE_ACODEC_LOSSLESS-$(call ENCDEC, YOURCODEC, WAV) += yourcodec</pre> > > + > > +<p> > > + This encodes <code>tests/data/asynth-44100-2.wav</code>, decodes it > > + back to PCM, and compares against > > + <code>tests/ref/acodec/yourcodec</code>. > > +</p> > > + > > +<p> > > + For codecs that need custom options or lossy comparison: > > +</p> > > + > > +<pre> > > +FATE_ACODEC-$(call ENCDEC, YOURCODEC, WAV) += fate-acodec-yourcodec > > +fate-acodec-yourcodec: CMD = enc_dec_pcm yourformat wav s16le $(SRC) > -c:a yourcodec -b:a 128k > > +fate-acodec-yourcodec: REF = $(SRC) > > +fate-acodec-yourcodec: CMP = stddev > > +fate-acodec-yourcodec: CMP_TARGET = 500</pre> > > + > > +<p> > > + <code>CMP = stddev</code> allows lossy comparison. The > > + <code>CMP_TARGET</code> value is the maximum allowed standard > > + deviation between original and decoded samples. > > +</p> > > + > > +<br> > > + > > +<h3 id="GettingHelp"> > > + <span class="pull-right"> > > + <i class="fa fa-life-saver"></i> > > + </span> > > + Getting Help</h3> > > + > > +<div class="well"> > > + <div class="list-group"> > > + <a class="list-group-item" > href="irc://irc.libera.chat/ffmpeg-devel"> > > + <strong>#ffmpeg-devel on Libera Chat</strong><br> > > + Real-time discussion about FFmpeg development. Good for quick > > + questions and checking on patch status. > > + </a> > > + <a class="list-group-item" href=" > https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-devel/"> > > + <strong>ffmpeg-devel mailing list</strong><br> > > + Patch submission, review, and development discussion. > > + Subscribe before posting. > > + </a> > > + <a class="list-group-item" href="https://code.ffmpeg.org"> > > + <strong>Forgejo (code.ffmpeg.org)</strong><br> > > + The preferred platform for submitting pull requests. > > + </a> > > + <a class="list-group-item" href="https://trac.ffmpeg.org/wiki"> > > + <strong>FFmpeg Wiki</strong><br> > > + Community-maintained documentation, guides, and how-tos. > > + </a> > > + </div> <!-- list-group --> > > +</div> <!-- well --> > > + > > +<p> > > + See also: > > + <a href="developer.html">Developer Documentation</a>, > > + <a href="git-howto.html">Using Git to Develop FFmpeg</a>, and > > + <a href="fate.html">FATE</a>. > > +</p> > > diff --git a/src/contributing_js b/src/contributing_js > > new file mode 100644 > > index 0000000..e69de29 > > diff --git a/src/contributing_title b/src/contributing_title > > new file mode 100644 > > index 0000000..cde9230 > > --- /dev/null > > +++ b/src/contributing_title > > @@ -0,0 +1 @@ > > +Contributing to FFmpeg > > \ No newline at end of file > > -- > > 2.53.0 > > > > _______________________________________________ > > ffmpeg-devel mailing list -- [email protected] > > To unsubscribe send an email to [email protected] > _______________________________________________ > ffmpeg-devel mailing list -- [email protected] > To unsubscribe send an email to [email protected] > _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
