Skip to content

Commit 8c10f32

Browse files
committed
feat: add a hardware video encoder factory, with Media Foundation H.264
HardwareVideoEncoderFactory puts the encoders of the GPU in front of the built-in ones where the platform has them. On Windows, H.264 is encoded by the Media Foundation encoder the GPU driver provides (NVIDIA, AMD, Intel), driven through its asynchronous event model, with frames passed in system memory as NV12. Low-latency mode, no B-frames, CBR, forced IDR frames on request and bitrate changes while encoding are set through ICodecAPI; the parameter sets are put in front of every key frame. The hardware encoder takes over only formats the software encoder has too (H.264 Constrained Baseline and Baseline, packetization mode 1), so the factory offers the same codecs as DefaultVideoEncoderFactory and hardware never changes what is negotiated. A FallbackVideoEncoder switches to the software encoder when the hardware one fails to start or gives up while encoding, and restarts the stream with a key frame. WebRTC's own fallback wrapper is not part of the linked WebRTC library. Hardware encoding is opt-in: DefaultVideoEncoderFactory, and a PeerConnectionFactory without an encoder factory, encode as before. Linux has no hardware encoder yet; on macOS both factories use VideoToolbox.
1 parent e56f7a7 commit 8c10f32

26 files changed

Lines changed: 2187 additions & 10 deletions

‎docs/guide/advanced/video-codecs.md‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,28 @@ for (VideoCodecInfo codec : new DefaultVideoEncoderFactory().getSupportedCodecs(
1414
}
1515
```
1616

17+
### Hardware Encoding
18+
19+
`HardwareVideoEncoderFactory` offers the same codecs as `DefaultVideoEncoderFactory`, but encodes on the GPU where the platform supports it:
20+
21+
```java
22+
PeerConnectionFactory factory = PeerConnectionFactory.builder()
23+
.setVideoEncoderFactory(new HardwareVideoEncoderFactory())
24+
.build();
25+
```
26+
27+
| Platform | Hardware encoding |
28+
|---|---|
29+
| Windows | H.264 through the Media Foundation encoder of the GPU driver (NVIDIA, AMD, Intel) |
30+
| macOS | H.264 through VideoToolbox, as with `DefaultVideoEncoderFactory` |
31+
| Linux | Not yet; encoding is in software |
32+
33+
On Windows, the hardware encoder takes over H.264 Constrained Baseline and Baseline with packetization mode 1, formats the software encoder offers too, so encoding in hardware never changes what is negotiated. When the hardware encoder fails to start, for example because the GPU has no encoder sessions left, or fails while encoding, the stream switches to the software encoder and continues with a key frame. On a machine without a hardware encoder, the factory encodes like `DefaultVideoEncoderFactory`.
34+
35+
Which encoder a stream uses shows in the `encoderImplementation` statistic of its `outbound-rtp` stats, e.g. `MediaFoundation (AMDh264Encoder)` or `OpenH264`.
36+
37+
### Native Codecs
38+
1739
The encoders and decoders these factories create are `NativeVideoEncoder`s and `NativeVideoDecoder`s. They are placeholders that make WebRTC create the built-in codec, which then runs entirely inside WebRTC, so their methods are not to be called from Java.
1840

1941
## Setting the Factories
@@ -163,6 +185,7 @@ Whatever an encoder, decoder or factory method throws is logged and treated as `
163185
- `VideoEncoderFactory`, `VideoDecoderFactory` — create the codecs of a factory.
164186
- `VideoEncoder`, `VideoDecoder`, `EncodedImage` — codecs implemented in Java.
165187
- `DefaultVideoEncoderFactory`, `DefaultVideoDecoderFactory` — the built-in codecs.
188+
- `HardwareVideoEncoderFactory` — the built-in encoders, on the GPU where possible.
166189
- `RTCRtpTransceiver.setCodecPreferences()` — chooses among the negotiated codecs.
167190

168191
For the full API, see the JavaDoc of the `dev.onvoid.webrtc.media.video.codec` package.

‎webrtc-jni/src/main/cpp/CMakeLists.txt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ file(GLOB SOURCES_MEDIA_AUDIO "src/media/audio/*.cpp")
5656
file(GLOB SOURCES_MEDIA_AUDIO_OS "src/media/audio/${SOURCE_TARGET}/*.cpp")
5757
file(GLOB SOURCES_MEDIA_VIDEO "src/media/video/*.cpp")
5858
file(GLOB SOURCES_MEDIA_VIDEO_CODEC "src/media/video/codec/*.cpp")
59+
file(GLOB SOURCES_MEDIA_VIDEO_CODEC_OS "src/media/video/codec/${SOURCE_TARGET}/*.cpp")
5960
file(GLOB SOURCES_MEDIA_VIDEO_DESKTOP "src/media/video/desktop/*.cpp")
6061
file(GLOB SOURCES_MEDIA_VIDEO_DESKTOP_OS "src/media/video/desktop/${SOURCE_TARGET}/*.cpp")
6162
file(GLOB SOURCES_MEDIA_VIDEO_OS "src/media/video/${SOURCE_TARGET}/*.cpp")
@@ -71,6 +72,7 @@ list(APPEND SOURCES
7172
${SOURCES_MEDIA_AUDIO_OS}
7273
${SOURCES_MEDIA_VIDEO}
7374
${SOURCES_MEDIA_VIDEO_CODEC}
75+
${SOURCES_MEDIA_VIDEO_CODEC_OS}
7476
${SOURCES_MEDIA_VIDEO_DESKTOP}
7577
${SOURCES_MEDIA_VIDEO_DESKTOP_OS}
7678
${SOURCES_MEDIA_VIDEO_OS}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2026 Alex Andres
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <jni.h>
18+
/* Header for class dev_onvoid_webrtc_media_video_codec_HardwareVideoEncoderFactory */
19+
20+
#ifndef _Included_dev_onvoid_webrtc_media_video_codec_HardwareVideoEncoderFactory
21+
#define _Included_dev_onvoid_webrtc_media_video_codec_HardwareVideoEncoderFactory
22+
#ifdef __cplusplus
23+
extern "C" {
24+
#endif
25+
/*
26+
* Class: dev_onvoid_webrtc_media_video_codec_HardwareVideoEncoderFactory
27+
* Method: getSupportedCodecsInternal
28+
* Signature: ()[Ldev/onvoid/webrtc/media/video/codec/VideoCodecInfo;
29+
*/
30+
JNIEXPORT jobjectArray JNICALL Java_dev_onvoid_webrtc_media_video_codec_HardwareVideoEncoderFactory_getSupportedCodecsInternal
31+
(JNIEnv *, jclass);
32+
33+
#ifdef __cplusplus
34+
}
35+
#endif
36+
#endif

‎webrtc-jni/src/main/cpp/include/media/video/codec/DefaultVideoCodecFactories.h‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ namespace jni
2828
// software, or on macOS those of WebRTC's default Objective-C factories,
2929
// which use VideoToolbox.
3030
std::unique_ptr<webrtc::VideoEncoderFactory> CreateDefaultVideoEncoderFactory();
31+
32+
// The default encoders, with the encoders of the GPU in front of them
33+
// where the platform has them, falling back to the software ones. On
34+
// macOS the default encoders already use VideoToolbox.
35+
std::unique_ptr<webrtc::VideoEncoderFactory> CreateHardwareVideoEncoderFactory();
3136
std::unique_ptr<webrtc::VideoDecoderFactory> CreateDefaultVideoDecoderFactory();
3237
}
3338

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2026 Alex Andres
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef JNI_WEBRTC_MEDIA_VIDEO_CODEC_FALLBACK_VIDEO_ENCODER_H_
18+
#define JNI_WEBRTC_MEDIA_VIDEO_CODEC_FALLBACK_VIDEO_ENCODER_H_
19+
20+
#include "api/video/video_frame.h"
21+
#include "api/video_codecs/video_codec.h"
22+
#include "api/video_codecs/video_encoder.h"
23+
24+
#include <memory>
25+
#include <optional>
26+
#include <vector>
27+
28+
namespace jni
29+
{
30+
// Encodes with a hardware encoder, and switches to a software encoder of
31+
// the same codec when the hardware one fails to initialize, or gives up
32+
// while encoding by returning WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE. The
33+
// switch is for good; the software encoder starts with a key frame.
34+
//
35+
// WebRTC has such a wrapper too, but it is not part of the WebRTC
36+
// library this library links.
37+
class FallbackVideoEncoder : public webrtc::VideoEncoder
38+
{
39+
public:
40+
FallbackVideoEncoder(std::unique_ptr<webrtc::VideoEncoder> hardware,
41+
std::unique_ptr<webrtc::VideoEncoder> software);
42+
~FallbackVideoEncoder() override = default;
43+
44+
int32_t InitEncode(const webrtc::VideoCodec * codecSettings, const Settings & settings) override;
45+
int32_t RegisterEncodeCompleteCallback(webrtc::EncodedImageCallback * callback) override;
46+
int32_t Release() override;
47+
int32_t Encode(const webrtc::VideoFrame & frame, const std::vector<webrtc::VideoFrameType> * frameTypes) override;
48+
void SetRates(const RateControlParameters & parameters) override;
49+
void OnPacketLossRateUpdate(float packetLossRate) override;
50+
void OnRttUpdate(int64_t rttMs) override;
51+
EncoderInfo GetEncoderInfo() const override;
52+
53+
private:
54+
// Initializes the software encoder with the settings the hardware
55+
// one was given. Returns whether it is ready.
56+
bool StartSoftware();
57+
58+
webrtc::VideoEncoder * Active() const;
59+
60+
private:
61+
const std::unique_ptr<webrtc::VideoEncoder> hardware;
62+
const std::unique_ptr<webrtc::VideoEncoder> software;
63+
64+
bool useSoftware;
65+
bool initialized;
66+
67+
std::optional<webrtc::VideoCodec> codecSettings;
68+
std::optional<Settings> encoderSettings;
69+
std::optional<RateControlParameters> rates;
70+
webrtc::EncodedImageCallback * callback;
71+
};
72+
}
73+
74+
#endif
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2026 Alex Andres
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef JNI_WEBRTC_MEDIA_VIDEO_CODEC_HARDWARE_VIDEO_ENCODER_FACTORY_H_
18+
#define JNI_WEBRTC_MEDIA_VIDEO_CODEC_HARDWARE_VIDEO_ENCODER_FACTORY_H_
19+
20+
#include "api/environment/environment.h"
21+
#include "api/video_codecs/sdp_video_format.h"
22+
#include "api/video_codecs/video_encoder.h"
23+
#include "api/video_codecs/video_encoder_factory.h"
24+
25+
#include <memory>
26+
#include <vector>
27+
28+
namespace jni
29+
{
30+
// Puts hardware encoders in front of software ones. A codec both have is
31+
// encoded in hardware, inside a wrapper that switches to the software
32+
// encoder when the hardware one fails to initialize or gives up while
33+
// encoding, for example once a GPU runs out of encoder sessions. A codec
34+
// only one of them has is encoded by that one.
35+
class HardwareVideoEncoderFactory : public webrtc::VideoEncoderFactory
36+
{
37+
public:
38+
HardwareVideoEncoderFactory(std::unique_ptr<webrtc::VideoEncoderFactory> hardware,
39+
std::unique_ptr<webrtc::VideoEncoderFactory> software);
40+
~HardwareVideoEncoderFactory() override = default;
41+
42+
std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override;
43+
std::unique_ptr<webrtc::VideoEncoder> Create(const webrtc::Environment & env,
44+
const webrtc::SdpVideoFormat & format) override;
45+
46+
private:
47+
const std::unique_ptr<webrtc::VideoEncoderFactory> hardware;
48+
const std::unique_ptr<webrtc::VideoEncoderFactory> software;
49+
};
50+
51+
// Returns a factory for the hardware encoders of the platform, or null if
52+
// the platform has none this library supports, or no device that can
53+
// encode. Defined per platform.
54+
std::unique_ptr<webrtc::VideoEncoderFactory> CreatePlatformHardwareVideoEncoderFactory();
55+
}
56+
57+
#endif

‎webrtc-jni/src/main/cpp/include/media/video/codec/VideoEncoderFactoryWrapper.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,15 @@ namespace jni
5959

6060
jclass nativeEncoderClass;
6161
jfieldID nativeEncoderCodecInfo;
62+
jfieldID nativeEncoderHardwareAcceleration;
6263
};
6364

6465
private:
6566
const JavaGlobalRef<jobject> factory;
6667
const std::shared_ptr<JavaVideoEncoderFactoryClass> javaClass;
68+
// The built-in encoders, and those with the GPU's in front.
6769
const std::unique_ptr<webrtc::VideoEncoderFactory> defaultFactory;
70+
const std::unique_ptr<webrtc::VideoEncoderFactory> hardwareFactory;
6871

6972
std::vector<webrtc::SdpVideoFormat> supportedFormats;
7073
};
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2026 Alex Andres
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef JNI_WEBRTC_MEDIA_VIDEO_CODEC_MF_ENCODER_UTILS_H_
18+
#define JNI_WEBRTC_MEDIA_VIDEO_CODEC_MF_ENCODER_UTILS_H_
19+
20+
#include <mfapi.h>
21+
#include <mfidl.h>
22+
#include <wrl/client.h>
23+
24+
#include <string>
25+
#include <vector>
26+
27+
namespace jni
28+
{
29+
// Lists the hardware H.264 encoder transforms that take NV12, best
30+
// first. Media Foundation has to be started.
31+
HRESULT EnumerateHardwareH264Encoders(std::vector<Microsoft::WRL::ComPtr<IMFActivate>> & encoders);
32+
33+
// Returns the name the driver gives a transform, e.g. "AMDh264Encoder".
34+
std::string GetTransformName(IMFActivate * activate);
35+
}
36+
37+
#endif

0 commit comments

Comments
 (0)