From dc3a0a4e9087501bb72d40d1446bc2d07c7a4153 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Thu, 15 Oct 2026 02:05:55 +0200 Subject: [PATCH] feat: encode VP9 with VA-API on Linux without turning it on webrtc.hardware.vp9Encoder now only turns on the Media Foundation VP9 encoder on Windows, which is still untested. --- docs/guide/advanced/video-codecs.md | 2 +- .../include/media/video/codec/HardwareCodecOptions.h | 7 ++++--- .../video/codec/linux/VaapiVideoEncoderFactory.h | 7 +++---- .../codec/linux/LinuxHardwareVideoCodecFactories.cpp | 6 +----- .../video/codec/linux/VaapiVideoEncoderFactory.cpp | 11 ++++------- .../video/codec/HardwareVideoEncoderFactory.java | 9 ++++----- .../webrtc/HardwareVideoEncoderIntegrationTest.java | 4 ++-- 7 files changed, 19 insertions(+), 27 deletions(-) diff --git a/docs/guide/advanced/video-codecs.md b/docs/guide/advanced/video-codecs.md index 0338fcb8..8be01343 100644 --- a/docs/guide/advanced/video-codecs.md +++ b/docs/guide/advanced/video-codecs.md @@ -32,7 +32,7 @@ PeerConnectionFactory factory = PeerConnectionFactory.builder() Hardware encoders produce a single layer. A stream that asks for SVC, such as an AV1 stream with a scalability mode like `L1T3`, is encoded in software. -VP9 can be encoded in hardware too, with the VP9 encoder of the GPU driver, which Intel GPUs have: through Media Foundation on Windows and VA-API on Linux. It is off by default, since it has not been tested on such a GPU yet; turn it on with a system property before the factory is created: +VP9 can be encoded in hardware too, with the VP9 encoder of the GPU driver, which Intel GPUs have: through VA-API on Linux, and through Media Foundation on Windows. On Windows it is off by default, since it has not been tested on such a GPU yet; turn it on with a system property before the factory is created: ```java System.setProperty("webrtc.hardware.vp9Encoder", "true"); diff --git a/webrtc-jni/src/main/cpp/include/media/video/codec/HardwareCodecOptions.h b/webrtc-jni/src/main/cpp/include/media/video/codec/HardwareCodecOptions.h index 2b60dcd3..a1fb4ac3 100644 --- a/webrtc-jni/src/main/cpp/include/media/video/codec/HardwareCodecOptions.h +++ b/webrtc-jni/src/main/cpp/include/media/video/codec/HardwareCodecOptions.h @@ -19,9 +19,10 @@ namespace jni { - // The Java system property that turns on hardware VP9 encoding, which is - // off by default: only Intel GPUs encode VP9, and the encoder has not been - // tested on one. + // The Java system property that turns on hardware VP9 encoding on + // Windows, which is off by default: only Intel GPUs encode VP9, and the + // Media Foundation encoder has not been tested on one. VA-API encodes VP9 + // on Linux regardless. constexpr const char * kHardwareVp9EncoderProperty = "webrtc.hardware.vp9Encoder"; // Whether hardware VP9 encoding is turned on: the Java system property diff --git a/webrtc-jni/src/main/cpp/include/media/video/codec/linux/VaapiVideoEncoderFactory.h b/webrtc-jni/src/main/cpp/include/media/video/codec/linux/VaapiVideoEncoderFactory.h index 101afd51..29919bf9 100644 --- a/webrtc-jni/src/main/cpp/include/media/video/codec/linux/VaapiVideoEncoderFactory.h +++ b/webrtc-jni/src/main/cpp/include/media/video/codec/linux/VaapiVideoEncoderFactory.h @@ -32,15 +32,14 @@ namespace jni // Creates VA-API encoders on the GPU whose driver encodes H.264, as Intel // and AMD drivers do. It offers H.264 in the profiles WebRTC's software // encoder offers too, and only with packetization mode 1: mode 0 needs - // each NAL unit to fit a packet. It offers H.265 Main as well where the - // driver encodes it, and VP9 profile 0 where the driver encodes it and - // hardware VP9 encoding is turned on. + // each NAL unit to fit a packet. It offers H.265 Main and VP9 profile 0 + // as well where the driver encodes them. class VaapiVideoEncoderFactory : public webrtc::VideoEncoderFactory { public: // Returns a factory, or null if no GPU driver encodes H.264 // through VA-API. - static std::unique_ptr Create(bool vp9Enabled); + static std::unique_ptr Create(); ~VaapiVideoEncoderFactory() override = default; diff --git a/webrtc-jni/src/main/cpp/src/media/video/codec/linux/LinuxHardwareVideoCodecFactories.cpp b/webrtc-jni/src/main/cpp/src/media/video/codec/linux/LinuxHardwareVideoCodecFactories.cpp index 3b05a400..1591e2ca 100644 --- a/webrtc-jni/src/main/cpp/src/media/video/codec/linux/LinuxHardwareVideoCodecFactories.cpp +++ b/webrtc-jni/src/main/cpp/src/media/video/codec/linux/LinuxHardwareVideoCodecFactories.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include "media/video/codec/HardwareCodecOptions.h" #include "media/video/codec/HardwareVideoDecoderFactory.h" #include "media/video/codec/HardwareVideoEncoderFactory.h" #include "media/video/codec/linux/VaapiVideoDecoderFactory.h" @@ -33,10 +32,7 @@ namespace jni if (auto nvenc = NvencVideoEncoderFactory::Create()) { factories.push_back(std::move(nvenc)); } - // VP9 only if asked for: it has not been tested on an Intel GPU yet. - auto vaapi = VaapiVideoEncoderFactory::Create(IsHardwareVp9EncoderEnabled()); - - if (vaapi) { + if (auto vaapi = VaapiVideoEncoderFactory::Create()) { factories.push_back(std::move(vaapi)); } diff --git a/webrtc-jni/src/main/cpp/src/media/video/codec/linux/VaapiVideoEncoderFactory.cpp b/webrtc-jni/src/main/cpp/src/media/video/codec/linux/VaapiVideoEncoderFactory.cpp index d4bd2df0..9e3ca2ed 100644 --- a/webrtc-jni/src/main/cpp/src/media/video/codec/linux/VaapiVideoEncoderFactory.cpp +++ b/webrtc-jni/src/main/cpp/src/media/video/codec/linux/VaapiVideoEncoderFactory.cpp @@ -27,7 +27,7 @@ namespace jni { - std::unique_ptr VaapiVideoEncoderFactory::Create(bool vp9Enabled) + std::unique_ptr VaapiVideoEncoderFactory::Create() { VaapiLibrary * library = VaapiLibrary::Get(); @@ -39,13 +39,10 @@ namespace jni const bool h265 = library->EncodeEntrypoint(VAProfileHEVCMain, &h265Entrypoint); VAEntrypoint vp9Entrypoint = VAEntrypointEncSlice; - const bool vp9 = vp9Enabled && library->EncodeEntrypoint(VAProfileVP9Profile0, &vp9Entrypoint); + const bool vp9 = library->EncodeEntrypoint(VAProfileVP9Profile0, &vp9Entrypoint); - RTC_LOG(LS_INFO) << "VA-API (" << library->Vendor() << ") H.265 encoding: " << h265; - - if (vp9Enabled) { - RTC_LOG(LS_INFO) << "VA-API (" << library->Vendor() << ") VP9 encoding: " << vp9; - } + RTC_LOG(LS_INFO) << "VA-API (" << library->Vendor() << ") H.265 encoding: " << h265 << ", VP9 encoding: " + << vp9; return std::unique_ptr( new VaapiVideoEncoderFactory(*library, h265, h265Entrypoint, vp9, vp9Entrypoint)); diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/codec/HardwareVideoEncoderFactory.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/codec/HardwareVideoEncoderFactory.java index 638191ac..50adfc14 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/codec/HardwareVideoEncoderFactory.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/codec/HardwareVideoEncoderFactory.java @@ -41,11 +41,10 @@ * stream that asks for SVC is encoded in software. H.265 (Main profile) is * encoded with NVENC or Media Foundation on GPUs that have an H.265 encoder. * VP9 (profile 0) is encoded on GPUs that have a VP9 encoder, which are - * Intel's, with Media Foundation on Windows and VA-API on Linux, but only - * with the system property - * {@code webrtc.hardware.vp9Encoder} set to {@code true} when the factory is - * created: the encoder has not been tested on such a GPU yet. Without it, VP9 - * is encoded with libvpx. On Linux, H.265 is encoded with NVENC on NVIDIA + * Intel's: with VA-API on Linux, and with Media Foundation on Windows only + * with the system property {@code webrtc.hardware.vp9Encoder} set to + * {@code true} when the factory is created, since that encoder has not been + * tested on such a GPU yet. Otherwise VP9 is encoded with libvpx. On Linux, H.265 is encoded with NVENC on NVIDIA * GPUs and with VA-API on the GPUs of Intel and AMD whose driver encodes it. * A hardware encoder that fails to start, for example because the GPU has no * encoder sessions left, or fails while encoding, is replaced by the next one diff --git a/webrtc/src/test/java/dev/onvoid/webrtc/HardwareVideoEncoderIntegrationTest.java b/webrtc/src/test/java/dev/onvoid/webrtc/HardwareVideoEncoderIntegrationTest.java index 4c2bd3e5..9d73eea6 100644 --- a/webrtc/src/test/java/dev/onvoid/webrtc/HardwareVideoEncoderIntegrationTest.java +++ b/webrtc/src/test/java/dev/onvoid/webrtc/HardwareVideoEncoderIntegrationTest.java @@ -275,8 +275,8 @@ private PeerConnectionFactory hardwareCallFactory() { @Test void vp9HardwareEncodingIsOptIn() throws Exception { - assumeTrue(OS.contains("win") || OS.contains("linux"), - "hardware encoders are implemented on Windows and Linux only"); + // On Linux, VA-API encodes VP9 without it. + assumeTrue(OS.contains("win"), "hardware VP9 encoding is opt-in on Windows only"); assumeTrue(System.getProperty(VP9_ENCODER_PROPERTY) == null, VP9_ENCODER_PROPERTY + " is set"); PeerConnectionFactory hardware = hardwareFactory();