# FFVPX

This directory contains files used in gecko builds from FFmpeg
(http://ffmpeg.org). The current files are from FFmpeg as of
revision 9917308cc209a885c6870f0345905104c6ea8799

All source files match their path from the library's source archive.

Currently, we only use the vp8, vp9, av1 (via libdav1d), mp3, flac, vorbis (via
libvorbis), opus (via libopus) and PCM portion of the library. If this changes,
configuration files will most likely need to be updated. On Windows, we use d3d11va for vp9 and av1.

Decoding AV1 via libdav1d and libvorbis is supported, although the decoder
libraries are vendored separately, `ffvpx` only contains the code to use
those libraries through the `ffmpeg` API.

The ffmpeg project recommends to use ffmpeg's tip, not a particular release.

## Source files

This library only uses a small part of `ffmpeg`. To update the source tree run:

> rsync -av --existing ffmpeg-upstream/* ffmpeg-mozilla-dir

If the new version of ffmpeg requires source files we don't already package,
they will not be copied over by this rsync command and will have to be added
manually.

Then, make sure the files:

- `libavcodec/codec_list.c`
- `libavcodec/bsf_list.c`
- `libavcodec/parser_list.c`

include conditional compilation directives, by probably reverting them (or
reverting and adjusting them if new codecs are added).

Revert and adjust libavcodec `dovi_rpu.h` and `lcevcdec.h` so that they contain
just the necessary stubs to compile. We do this to avoid patent and other
restrictions. When ffmpeg is being upgraded, be on the lookout for other files
that may need to be stubbed out as well.

## Add headers for a new major ffmpeg version

For historical reasons, we package ffmpeg according to the libavcodec version.
Check `libavcodec/version_major.h`. The version number defined by
`LIBAVCODEC_VERSION_MAJOR` is the version number we will be using.

If a new major version of ffmpeg is being imported in the tree, it's necessary
to manually copy the new ffmpeg headers into
`dom/media/platforms/ffmpeg/ffmpegxx` where xx is the new ffmpeg major version
number. Copy only the header files necessary to compile.

Then, modify the dynamic linker wrapper in
`dom/media/platforms/dom/media/platforms/ffmpeg/{FFmpegLibWrapper.cpp,FFmpegRungtimeLinker.cpp}`
with the new version and the new API in this new version.

## `config.{h,asm}` generation

Each platform needs its own `config.h` file and some need a `config.asm` file as
well. For example, x86_64 Linux uses `config_unix64.h` and `config_unix64.asm`.
Ideally, the existing configuration files should be usable without any changes.
If changes are needed, it is preferable to update these files by hand.
If this is not possible and the files need to be regenerated entirely,
the `configure` script in the ffmpeg source directory can be used.
 The arguments used to create them can be found in the
`FFMPEG_CONFIGURATION` define in the existing header files.

For example, create `config.h` and `config.asm` for x86_64 Linux desktop by
running `./configure` with the arguments from `config_unix64.h`.

Then, copy the generated `config.h` and `config.asm` files over `config_unix64.h` and `config_unix64.asm`.

For Linux Desktop, there are a number of overrides in `config_common.h` for
VAAPI. We can't put them in `config_components.h` because this breaks the build.

`config_components.h` is common to all platforms, and then a specific config
file is included, based on the platform and architecture.
macOS and Android are similar to Linux Desktop. Windows needs a bit more setup.

# Windows

The general idea is to get an msys prompt with an msvc toolchain
configured, so that the configure script for ffmpeg can run successfully
with the thread flavor Gecko prefers on Windows (win32, not pthreads).

- Open Visual Studio (2019 when writing this)
- Tools → Command Line → Developer command prompt
- Check that compiling a small C program with cl.exe works
- Install msys2 from https://www.msys2.org/
- From the Visual Studio Developer Command Prompt, run the following:
    > C:\msys64\msys2_shell.cmd -msys2 -use-full-path
- This pops up a new shell window, with a 32-bits build environment
- Check that compiling a small C program with `cl.exe` works. You may need
  to install additional packages by running `pacman`, such as:
  `pacman -S nasm`, `pacman -S pkgconf`, `pacman -S diffutils`.
- Run ffmpeg's ./configure with the options needed from `config_win32.h`.

- Copy `config.h` and `config.asm` as `config_win32.h` and `config_win32.asm`
  in this directory
- Close the `msys2` window, go back to the `cmd.exe` window
- Run this command, maybe substituting the Visual Studio version:

> "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64

- This pops up a new shell window, now with a 64-bits build
  environment
- Check that compiling a small C program with `cl.exe` works
- Run ffmpeg's `./configure` with the options needed from `config_win64.h`.
- Copy `config.h` and `config.asm` as `config_win64.h` and `config_win64.asm`.

For `config_aarch64_win64.h`: You will need to install cpp (either using msys or
wsl), then run `configure` with the arguments from `config_aarch64_win64.h`.

Once all of the config files have been generated, run the following command:

> sed -i -E '/HAVE_(MALLOC_H|ARC4RANDOM|LOCALTIME_R|MEMALIGN|POSIX_MEMALIGN)/d' config.*

to avoid redefined macros.

# Build, fix errors

Missing files need to be added, and the patch to rename `time.h` to `fftime.h`
might need to be reapplied or extended to other files including `time.h`. The
issue being that it's included instead of the system header, causing all sorts
of issues.

Additionally, `jni.h` and `jni.c` in ffmpeg sources need to be renamed to
`fffjni.h` and `fffjni.c`, and `#include` to those files need to be updated.
This is because there are header collisions with the JDK.

`moz.build` files might need to be modified as well, in light of compilation
and link errors.

There are going to be a lot of changes in terms of symbols exported. Adjust
`libavutil/avutil.symbols` and `libavcodec/avcodec.symbols` by removing and
adding symbols until the build passes. You may also need to modify
`/config/external/gkcodecs/gkcodecs.symbols`.

Finally, apply the patches:
- no-unicode-stdio.patch to avoid passing the infity symbol in unicode to an
  stdio.h function, that causes bug 1879740 issue on Windows.
- opusenc-dtx.patch to allow enabling DTX in the opus encoder.
- libaomenc-svc.patch to allow configuring SVC in the libaom encoder.
- mediacodec_eos.patch to add a method to check definitely if a decoder has
  reached the end of stream on Android.
- mediacodec_drm.patch to add support for encrypted packets on Android.
- mediacodec_force_key_frames.patch to add support for forcing key frames when
  encoding via the frame pict_type on Android.
- mediacodec_h264.patch to remove the H264 extradata parsing that brings in
  encumbered code on Android.
- bug1603271-videodsp-pointer-overflow.patch to avoid a UBSan pointer-overflow
  by combining a two-step pointer adjustment into a single positive-offset step.
- vp9-get-format-rollback.patch to fix a VP9 decoder error handling issue.
- flac-alloc-failure.patch fix leak in flac decoder in case of alloc failure
- cbs_decoder_sync.patch to keep CBS and the decoder in sync
