Repository navigation
feat: add custom video codec factories - #303
Merged
Merged
Conversation
WebRTC calls log sinks while it holds its global logging lock, and it is built without unwinding. The Java log sink bridge ended with ExceptionCheck(), which throws a C++ exception when the sink throws, and also when the code that logged had a Java exception pending, since no JNI call may be made then. That exception passed through WebRTC's frames without releasing the lock, and the next thread to log blocked forever, typically hanging RTCPeerConnection.close(). The bridge now sets a pending exception aside and restores it afterwards, reports what the sink throws, and never throws itself.
A PeerConnectionFactory can now be given its own video encoder and decoder factories, which decide what video codecs it sends and receives. PeerConnectionFactory.builder() sets them, along with everything the constructors take. The new package dev.onvoid.webrtc.media.video.codec has VideoEncoder and VideoDecoder, for codecs implemented in Java, their factories, and EncodedImage and VideoCodecInfo. DefaultVideoEncoderFactory and DefaultVideoDecoderFactory provide the built-in codecs, so a factory can add its own codec while keeping them; the NativeVideoEncoder and NativeVideoDecoder they hand out make WebRTC create the built-in codec natively. A codec name WebRTC does not know is negotiated and sent with the generic packetization. Native wrappers, ported from the Android SDK, run the Java codecs. Frames reach a Java encoder without a copy, encoded images a Java decoder as a read-only view; the callbacks a codec hands its output to reach the wrapper only until the codec is released. Whatever a Java codec or factory throws is logged and treated as an error, and never reaches WebRTC. Decoded frames may use any I420Buffer with direct buffers.
devopvoid
added this pull request to stack #311
September 30, 2026 00:20
This was referenced Sep 30, 2026
SendableMetatype
added a commit
to EduGeyser/webrtc-java
that referenced
this pull request
Oct 10, 2026
Brings in upstream 0.19.0 and the work after it: the FFmpeg-based webrtc-java-media module with its native extension API (devopvoid#291, devopvoid#292, devopvoid#299, devopvoid#300), encoded frame transforms (devopvoid#300), the remaining sender encoding parameters and RTCConfiguration fields (devopvoid#316, devopvoid#317), custom and hardware video codec factories (devopvoid#303, devopvoid#310 to devopvoid#315, devopvoid#318 to devopvoid#330), the log sink and 32-bit ARM stats fixes, and upstream's CI rework (devopvoid#294 to devopvoid#309). Fork-side adaptations: - The media module builds with Gradle, and only in the full variant: it needs audio and video. On Linux it links like the JNI library, since the Chromium sysroots no longer ship the static libgcc_eh.a. The sysroots carry stubs of glibc that no executable links against, so FFmpeg's configure links with lld and allows undefined symbols in shared libraries. - The data channels variant leaves out the new media sources, the codec factory setup and the hardware codec headers, and skips the new tests that need audio or video. - The module tests run on the module path with the test resources patched in, and the core tests open the internal package that NativeApi and NativeLoader are tested in. - The WebRTC checkout keeps this fork's sync, with upstream's checkout_instrumented_libraries setting. - CI builds all platforms from one reusable workflow, as upstream now does. The full variant also builds FFmpeg and tests the media module. The WebRTC and FFmpeg caches are saved as soon as their builds finish, and a release is prepared locally and pushed in one atomic push. - The Maven poms and upstream's Dependabot setup stay out, and the README is the fork's own; the rename script now leaves it alone.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A
PeerConnectionFactorycan now be given its own video encoder and decoder factories, which decide what video codecs it sends and receives. Until now the codecs were hard-coded inJNI_PeerConnectionFactory.cpp.API
PeerConnectionFactory.builder()sets the codec factories along with everything the constructors take (field trials, audio device module, audio processing). The constructors are unchanged.dev.onvoid.webrtc.media.video.codec, modelled on the Android SDK:VideoEncoderandVideoDecoder, for codecs implemented in JavaVideoEncoderFactoryandVideoDecoderFactoryEncodedImage,VideoCodecInfoandVideoCodecStatusDefaultVideoEncoderFactoryandDefaultVideoDecoderFactory, which provide the built-in codecs. A factory can add its own codec and delegate the rest to them. TheNativeVideoEncoderandNativeVideoDecoderthey hand out make WebRTC create the built-in codec natively, with no detour through Java.X-MYCODEC) is negotiated and sent with the generic RTP packetization.Native side
I420Bufferwith direct buffers, not onlyNativeI420Buffer.media/video/codec/DefaultVideoCodecFactories.cpp, with the macOS VideoToolbox path unchanged.Log sink fix (separate commit)
Found while testing: the Java log sink bridge let a C++ exception escape into WebRTC. This happened when a sink threw, or when a message was logged while a Java exception was pending. WebRTC calls sinks under its global logging lock and is built without unwinding, so the lock stayed held and the next thread to log blocked forever, typically in
RTCPeerConnection.close(). Because a log sink cannot be removed, a sink installed by one test class made this appear in later ones. The bridge now sets a pending exception aside, restores it afterwards, and never throws.VideoCodecFactoryTests.failingEncoderFactoryDoesNotCrashhangs without the fix.Testing
VideoCodecFactoryTests(10 tests):mvn -pl webrtc test: 194 tests pass.mvn -pl webrtc test -Pjni-check: 194 tests pass, with noFATAL ERROR in native method.Docs
New guide
docs/guide/advanced/video-codecs.md, linked from the sidebar, the guide index, the README and the landing page. The field trials guide mentions the builder.Not included
getEncoderSelector().