You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit e2fd53e
Browse filesBrowse the repository at this point in the historyBrowse files
feat: decode HEVC and AV1 in hardware in the media player (#331)
* feat: decode HEVC and AV1 in hardware in the media player
The player decoded only H.264 and VP9 on the GPU. FFmpeg is now built with the
hardware decoders of HEVC and AV1 as well: Direct3D 11 and 12 on Windows,
NVDEC on Linux, VideoToolbox on macOS.
FFmpeg's own AV1 decoder has no software path, so AV1 gets dav1d as its
software decoder. It is a new submodule (1.5.4), built with Meson before FFmpeg
into a static library that is linked into libavcodec. On Windows that is with
the static C runtime, which is the one FFmpeg is built with. Its version and
options are recorded in components.txt, so changing them rebuilds on its own.
Meson and Ninja are new build prerequisites, installed by the CI preparation
steps. Cross targets get a Meson cross file made from the same variables
FFmpeg is configured with; only windows-x86_64 has been built so far.
FFmpeg prefers libdav1d to its native AV1 decoder, and only the native one has
hardware configurations, so VideoDecoder picks a decoder that has one when
hardware decoding is asked for, and otherwise keeps the preferred one.
The licence of dav1d and a notice go into the platform jar.
Tests compare every frame decoded in hardware with the software decoder for
HEVC and AV1, at 320x240 and 1080p. AV1 has its own property,
webrtc.test.hardwareAv1Decoding, since older GPUs cannot decode it.
* fix: give Meson an SDK when it builds dav1d on macOS
Meson finds the compiler by its path inside the Xcode toolchain, which skips
the /usr/bin/cc shim that points SDKROOT at an SDK, so on the macOS ARM64
runner it reported that the compiler cannot compile programs ("library
'System' not found"). The SDK is named for the Meson run now. FFmpeg's own
configure gets it from the shim, so SDKROOT is unset again before it runs.
* fix: record G.711 into Matroska
Matroska has no codec ID of its own for G.711, so avformat_query_codec
said no and the recorder left PCMU and PCMA tracks out of .mkv files,
although the docs, the error message and a comment all promise that
Matroska holds every codec WebRTC sends. The Matroska muxer writes G.711
all the same, in its compatibility mode for Windows audio codecs
(A_MS/ACM), as "ffmpeg -c copy" does, so the recorder now lets it.
The recorder tests can now send the call's audio in a chosen codec, and
record PCMU and PCMA into Matroska, reading them back as such.
* feat: decode HEVC in hardware only, never in software
The player decoded HEVC in software unless asked for hardware, and fell
back to software wherever the hardware had no decoder, did not take a
stream, or failed. HEVC is now decoded on the hardware only: a player
sends it there whether hardwareDecoding is set or not, and where the
hardware cannot decode it, creating the player fails with "Decoder not
found", or playback stops with an error. No path opens a software
decoder for it.
FFmpeg's hevc decoder stays in the build, because the HEVC hwaccels run
inside it (configure selects it for every one of them); it parses the
headers and hands the slices to the hardware, but VideoDecoder never
lets it decode a picture: no software open, no software pixel format,
no fall back.
The tests compared hardware HEVC with software decoding, which no
longer exists. They now compare with luma checksums the software
decoder gave before this change, which every conforming decoder
matches. A new test fault hides the hardware devices, so that a machine
without a GPU decoder is tested on every machine, CI included: HEVC
does not open there, while H.264 still falls back to software.
* docs: add an HEVC/H.265 disclaimer to the NOTICE files
HEVC is decoded through the hardware decoders of the platform only, and
the project bundles no software HEVC encoder. The disclaimer says so,
and that the FFmpeg libraries of the webrtc-java-media platform jars
contain FFmpeg's HEVC decoder, which the hardware decoding runs through,
and leaves the license for HEVC playback and encoding to end-users and
distributors. It goes into the root NOTICE and into the FFmpeg notice
each webrtc-java-media platform jar carries.
* build: leave FFmpeg's HEVC decoder to the hwaccels that need it
--enable-decoder=hevc put FFmpeg's HEVC decoder into every build, but
each HEVC hwaccel selects that decoder itself, so where there is one
the decoder comes along without it, and the line only made a difference
where there is none: on 32-bit ARM Linux it shipped an HEVC decoder that
VideoDecoder never lets decode. Without the line, that build has no HEVC
decoder at all, and the others are as before (CONFIG_HEVC_DECODER is
still 1 on Windows, through the D3D11 and D3D12 hwaccels).
The HEVC disclaimer in the NOTICE files now says which platform jars
contain the decoder: those that decode HEVC in hardware, all but 32-bit
ARM Linux.
Copy file name to clipboardExpand all lines: docs/guide/media/media-files.md
+11-9Lines changed: 11 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -15,21 +15,21 @@ Decoding happens entirely in native code. Frames never travel through Java: the
15
15
16
16
## Adding the Module
17
17
18
-
The module is part of the normal build, and it builds FFmpeg from a submodule pinned to a release tag, so the submodule has to be present:
18
+
The module is part of the normal build, and it builds FFmpeg and dav1d (the software decoder of AV1) from submodules pinned to release tags, so the submodules have to be present:
Building FFmpeg needs `make` and `nasm`. On Windows they come from MSYS2:
25
+
Building FFmpeg needs `make` and `nasm`, and building dav1d needs [Meson](https://mesonbuild.com) (`pip install meson`) and Ninja. On Windows `make` and `nasm` come from MSYS2:
26
26
27
27
```shell
28
28
winget install MSYS2.MSYS2
29
29
C:\msys64\usr\bin\bash -lc "pacman -S --needed make nasm diffutils pkgconf"
30
30
```
31
31
32
-
Maven still runs from an ordinary shell; the build enters MSYS2 and the Visual Studio environment on its own. The first build compiles FFmpeg, which takes a while; later builds reuse the install directory.
32
+
Maven still runs from an ordinary shell; the build enters MSYS2 and the Visual Studio environment on its own. The first build compiles FFmpeg and dav1d, which takes a while; later builds reuse the install directory.
33
33
34
34
Once installed, depend on it alongside `webrtc-java`. It takes two entries: one for the Java API, and one for the natives of the platform you are running on.
35
35
@@ -206,7 +206,7 @@ It also keeps the native side of the media sources it feeds alive until it is cl
206
206
207
207
## Decoding in Hardware
208
208
209
-
Decoding H.264 and VP9 takes a good part of a processor at high resolutions, and for every stream of a camera wall. A player can decode them on the media engine or GPU of the machine instead. It does so when asked to, with a flag on `MediaFileSource` or `MediaPlayer`:
209
+
Decoding H.264, H.265/HEVC, VP9 and AV1 takes a good part of a processor at high resolutions, and for every stream of a camera wall. A player can decode them on the media engine or GPU of the machine instead. It does so when asked to, with a flag on `MediaFileSource` or `MediaPlayer`:
210
210
211
211
```java
212
212
// A file whose video is decoded in hardware, where the platform can.
@@ -220,11 +220,13 @@ MediaPlayer player = new MediaPlayer(new MediaReader(path), videoSource, null, t
The pictures are the same ones software decoding gives; in the tests, every frame of H.264 and VP9 media is compared with its software counterpart. Hardware decoding is off unless asked for.
223
+
The pictures are the same ones software decoding gives; in the tests, every frame of media in each of these codecs is compared with its software counterpart (for HEVC, with checksums of the pictures FFmpeg's software decoder gave once). Hardware decoding is off unless asked for, except for H.265/HEVC.
224
+
225
+
**HEVC is decoded in hardware only.** A player decodes it on the media engine or GPU whether or not the flag is set, and never in software: `isHardwareDecoding()` is always `true` for it. Where the machine has no hardware decoder for HEVC, creating the player fails with an `IOException`; where the hardware does not take a stream (a profile it cannot decode) or fails while playing, playback stops with an error. The fallback below does not apply to it.
224
226
225
227
-**Platforms:** macOS through VideoToolbox, Windows through Direct3D 12 (Windows 10 version 2004 or later, with a driver that decodes video through it) and otherwise Direct3D 11, and Linux through NVDEC on NVIDIA GPUs (x86-64 and ARM64; the driver provides `libcuda.so.1` and `libnvcuvid.so.1`, which are loaded when a player asks for hardware). The flag is accepted everywhere; where the platform has no hardware decoder, or the FFmpeg build has none for it (32-bit ARM, VA-API on Intel and AMD GPUs), the video is decoded in software, and `isHardwareDecoding()` says so.
226
-
-**Codecs:** H.264 and VP9. VP8, MPEG-4, MJPEG and H.265/HEVC are decoded in software.
227
-
-**Fallback:** a stream the hardware does not take, such as a profile it cannot decode, is decoded in software without the player noticing more than `isHardwareDecoding()` turning `false`. If the hardware fails before its first picture, the packets it was sent are decoded again in software and none is lost; if it fails after one, decoding goes on in software from the next key frame. A damaged packet is not taken for a hardware failure after the first picture: as with software decoding, playback stops with an error, and the hardware keeps the stream.
228
+
-**Codecs:** H.264, H.265/HEVC, VP9 and AV1, where the GPU decodes them: a GPU that is a few years old may lack AV1, and on a Mac only an M3 or later has it. VP8, MPEG-4and MJPEG are decoded in software, and so is AV1 where there is no GPU decoder for it (it is decoded by dav1d, which is built into the FFmpeg libraries).
229
+
-**Fallback** (every codec but HEVC): a stream the hardware does not take, such as a profile it cannot decode, is decoded in software without the player noticing more than `isHardwareDecoding()` turning `false`. If the hardware fails before its first picture, the packets it was sent are decoded again in software and none is lost; if it fails after one, decoding goes on in software from the next key frame. A damaged packet is not taken for a hardware failure after the first picture: as with software decoding, playback stops with an error, and the hardware keeps the stream.
228
230
-**What it saves** is processor time, not the copy: a decoded picture is read back from the media engine into system memory, and converted to I420 as WebRTC wants it. On an Apple M2, a 1080p H.264 stream took 11.6 ms of processor time per frame in software and 1.4 ms in hardware, and a 4K stream 35.7 ms against 4.2 ms, about seven to eight times less. Per frame, software on all cores is faster on the clock, which does not matter at playback speed. Windows gains less: on an NVIDIA GeForce RTX 3080 through Direct3D 12, a 1080p H.264 stream took about 2.1 ms of processor time per frame against 3.6 ms in software, and a 4K stream 5.4 ms against 6.6 ms. Direct3D 11 reads the picture back more slowly and took more than software at 4K (12.4 ms), which is why Direct3D 12 comes first. These are figures for one machine each and for synthetic media, not a promise; try it on your own streams before relying on it.
229
231
230
232
## Playing a Live Stream
@@ -269,7 +271,7 @@ The FFmpeg build is deliberately small, and carries only what this module plays:
269
271
|||
270
272
| --- | --- |
271
273
|**Containers**| MP4 and MOV, Matroska and WebM, AVI, MPEG-TS, FLV, WAV, MP3, Ogg, FLAC, AAC |
272
-
|**Video**| H.264, H.265/HEVC, VP8, VP9, MPEG-4 (including Xvid and DivX), Microsoft MPEG-4 v1 to v3, MJPEG |
274
+
|**Video**| H.264, H.265/HEVC (hardware only), VP8, VP9, AV1, MPEG-4 (including Xvid and DivX), Microsoft MPEG-4 v1 to v3, MJPEG |
273
275
|**Audio**| AAC, MP3, MP2, AC-3, Opus, Vorbis, FLAC, PCM, MS and IMA ADPCM |
274
276
275
277
Audio of any rate or layout is resampled to what WebRTC takes, which is 48 kHz 16-bit PCM in mono or stereo. Video that decodes to I420 — almost all 8-bit H.264, VP8, VP9 and MPEG-4 — reaches the encoder without being copied; anything else is converted first.
Copy file name to clipboardExpand all lines: docs/guide/media/media-recording.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -48,6 +48,8 @@ The container follows the file name:
48
48
49
49
A name FFmpeg does not know gets Matroska. A track whose codec the file cannot hold, VP8 in MP4 for example, is left out and reported as a warning, and the rest is recorded.
50
50
51
+
Matroska has no codec ID of its own for G.711, so it is stored as Windows audio (`A_MS/ACM`), the way FFmpeg itself stores it. Players built on FFmpeg, such as VLC and mpv, play it; some others do not.
52
+
51
53
## Following a Recording
52
54
53
55
A `MediaRecorderListener` hears when the file begins, what was left out, and whether writing failed:
0 commit comments