Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docs/guide/advanced/video-codecs.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,28 @@ for (VideoCodecInfo codec : new DefaultVideoEncoderFactory().getSupportedCodecs(
}
```

### Hardware Encoding

`HardwareVideoEncoderFactory` offers the same codecs as `DefaultVideoEncoderFactory`, but encodes on the GPU where the platform supports it:

```java
PeerConnectionFactory factory = PeerConnectionFactory.builder()
.setVideoEncoderFactory(new HardwareVideoEncoderFactory())
.build();
```

| Platform | Hardware encoding |
|---|---|
| Windows | H.264 through the Media Foundation encoder of the GPU driver (NVIDIA, AMD, Intel) |
| macOS | H.264 through VideoToolbox, as with `DefaultVideoEncoderFactory` |
| Linux | Not yet; encoding is in software |

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`.

Which encoder a stream uses shows in the `encoderImplementation` statistic of its `outbound-rtp` stats, e.g. `MediaFoundation (AMDh264Encoder)` or `OpenH264`.

### Native Codecs

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.

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

For the full API, see the JavaDoc of the `dev.onvoid.webrtc.media.video.codec` package.
2 changes: 2 additions & 0 deletions webrtc-jni/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ file(GLOB SOURCES_MEDIA_AUDIO "src/media/audio/*.cpp")
file(GLOB SOURCES_MEDIA_AUDIO_OS "src/media/audio/${SOURCE_TARGET}/*.cpp")
file(GLOB SOURCES_MEDIA_VIDEO "src/media/video/*.cpp")
file(GLOB SOURCES_MEDIA_VIDEO_CODEC "src/media/video/codec/*.cpp")
file(GLOB SOURCES_MEDIA_VIDEO_CODEC_OS "src/media/video/codec/${SOURCE_TARGET}/*.cpp")
file(GLOB SOURCES_MEDIA_VIDEO_DESKTOP "src/media/video/desktop/*.cpp")
file(GLOB SOURCES_MEDIA_VIDEO_DESKTOP_OS "src/media/video/desktop/${SOURCE_TARGET}/*.cpp")
file(GLOB SOURCES_MEDIA_VIDEO_OS "src/media/video/${SOURCE_TARGET}/*.cpp")
Expand All @@ -71,6 +72,7 @@ list(APPEND SOURCES
${SOURCES_MEDIA_AUDIO_OS}
${SOURCES_MEDIA_VIDEO}
${SOURCES_MEDIA_VIDEO_CODEC}
${SOURCES_MEDIA_VIDEO_CODEC_OS}
${SOURCES_MEDIA_VIDEO_DESKTOP}
${SOURCES_MEDIA_VIDEO_DESKTOP_OS}
${SOURCES_MEDIA_VIDEO_OS}
Expand Down
36 changes: 36 additions & 0 deletions webrtc-jni/src/main/cpp/include/JNI_HardwareVideoEncoderFactory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2026 Alex Andres
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <jni.h>
/* Header for class dev_onvoid_webrtc_media_video_codec_HardwareVideoEncoderFactory */

#ifndef _Included_dev_onvoid_webrtc_media_video_codec_HardwareVideoEncoderFactory
#define _Included_dev_onvoid_webrtc_media_video_codec_HardwareVideoEncoderFactory
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: dev_onvoid_webrtc_media_video_codec_HardwareVideoEncoderFactory
* Method: getSupportedCodecsInternal
* Signature: ()[Ldev/onvoid/webrtc/media/video/codec/VideoCodecInfo;
*/
JNIEXPORT jobjectArray JNICALL Java_dev_onvoid_webrtc_media_video_codec_HardwareVideoEncoderFactory_getSupportedCodecsInternal
(JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ namespace jni
// software, or on macOS those of WebRTC's default Objective-C factories,
// which use VideoToolbox.
std::unique_ptr<webrtc::VideoEncoderFactory> CreateDefaultVideoEncoderFactory();

// The default encoders, with the encoders of the GPU in front of them
// where the platform has them, falling back to the software ones. On
// macOS the default encoders already use VideoToolbox.
std::unique_ptr<webrtc::VideoEncoderFactory> CreateHardwareVideoEncoderFactory();
std::unique_ptr<webrtc::VideoDecoderFactory> CreateDefaultVideoDecoderFactory();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2026 Alex Andres
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef JNI_WEBRTC_MEDIA_VIDEO_CODEC_FALLBACK_VIDEO_ENCODER_H_
#define JNI_WEBRTC_MEDIA_VIDEO_CODEC_FALLBACK_VIDEO_ENCODER_H_

#include "api/video/video_frame.h"
#include "api/video_codecs/video_codec.h"
#include "api/video_codecs/video_encoder.h"

#include <memory>
#include <optional>
#include <vector>

namespace jni
{
// Encodes with a hardware encoder, and switches to a software encoder of
// the same codec when the hardware one fails to initialize, or gives up
// while encoding by returning WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE. The
// switch is for good; the software encoder starts with a key frame.
//
// WebRTC has such a wrapper too, but it is not part of the WebRTC
// library this library links.
class FallbackVideoEncoder : public webrtc::VideoEncoder
{
public:
FallbackVideoEncoder(std::unique_ptr<webrtc::VideoEncoder> hardware,
std::unique_ptr<webrtc::VideoEncoder> software);
~FallbackVideoEncoder() override = default;

int32_t InitEncode(const webrtc::VideoCodec * codecSettings, const Settings & settings) override;
int32_t RegisterEncodeCompleteCallback(webrtc::EncodedImageCallback * callback) override;
int32_t Release() override;
int32_t Encode(const webrtc::VideoFrame & frame, const std::vector<webrtc::VideoFrameType> * frameTypes) override;
void SetRates(const RateControlParameters & parameters) override;
void OnPacketLossRateUpdate(float packetLossRate) override;
void OnRttUpdate(int64_t rttMs) override;
EncoderInfo GetEncoderInfo() const override;

private:
// Initializes the software encoder with the settings the hardware
// one was given. Returns whether it is ready.
bool StartSoftware();

webrtc::VideoEncoder * Active() const;

private:
const std::unique_ptr<webrtc::VideoEncoder> hardware;
const std::unique_ptr<webrtc::VideoEncoder> software;

bool useSoftware;
bool initialized;

std::optional<webrtc::VideoCodec> codecSettings;
std::optional<Settings> encoderSettings;
std::optional<RateControlParameters> rates;
webrtc::EncodedImageCallback * callback;
};
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2026 Alex Andres
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef JNI_WEBRTC_MEDIA_VIDEO_CODEC_HARDWARE_VIDEO_ENCODER_FACTORY_H_
#define JNI_WEBRTC_MEDIA_VIDEO_CODEC_HARDWARE_VIDEO_ENCODER_FACTORY_H_

#include "api/environment/environment.h"
#include "api/video_codecs/sdp_video_format.h"
#include "api/video_codecs/video_encoder.h"
#include "api/video_codecs/video_encoder_factory.h"

#include <memory>
#include <vector>

namespace jni
{
// Puts hardware encoders in front of software ones. A codec both have is
// encoded in hardware, inside a wrapper that switches to the software
// encoder when the hardware one fails to initialize or gives up while
// encoding, for example once a GPU runs out of encoder sessions. A codec
// only one of them has is encoded by that one.
class HardwareVideoEncoderFactory : public webrtc::VideoEncoderFactory
{
public:
HardwareVideoEncoderFactory(std::unique_ptr<webrtc::VideoEncoderFactory> hardware,
std::unique_ptr<webrtc::VideoEncoderFactory> software);
~HardwareVideoEncoderFactory() override = default;

std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override;
std::unique_ptr<webrtc::VideoEncoder> Create(const webrtc::Environment & env,
const webrtc::SdpVideoFormat & format) override;

private:
const std::unique_ptr<webrtc::VideoEncoderFactory> hardware;
const std::unique_ptr<webrtc::VideoEncoderFactory> software;
};

// Returns a factory for the hardware encoders of the platform, or null if
// the platform has none this library supports, or no device that can
// encode. Defined per platform.
std::unique_ptr<webrtc::VideoEncoderFactory> CreatePlatformHardwareVideoEncoderFactory();
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,15 @@ namespace jni

jclass nativeEncoderClass;
jfieldID nativeEncoderCodecInfo;
jfieldID nativeEncoderHardwareAcceleration;
};

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

std::vector<webrtc::SdpVideoFormat> supportedFormats;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2026 Alex Andres
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef JNI_WEBRTC_MEDIA_VIDEO_CODEC_MF_ENCODER_UTILS_H_
#define JNI_WEBRTC_MEDIA_VIDEO_CODEC_MF_ENCODER_UTILS_H_

#include <mfapi.h>
#include <mfidl.h>
#include <wrl/client.h>

#include <string>
#include <vector>

namespace jni
{
// Lists the hardware H.264 encoder transforms that take NV12, best
// first. Media Foundation has to be started.
HRESULT EnumerateHardwareH264Encoders(std::vector<Microsoft::WRL::ComPtr<IMFActivate>> & encoders);

// Returns the name the driver gives a transform, e.g. "AMDh264Encoder".
std::string GetTransformName(IMFActivate * activate);
}

#endif
Loading
Loading