Skip to main content
SDK 2.0.0. Hook Facebetter into a third-party SDK’s custom video preprocess callback: on that SDK’s OpenGL ES thread, run processImage on an external texture, then return the output texture. Full texture rules: Implement Beauty · External texture. Room join, publish, and permissions belong in the vendor’s docs — this page only covers the Facebetter hookup.

Shared contract

Facebetter does not accept GL_TEXTURE_EXTERNAL_OES for createWithTexture. If the vendor defaults to OES, switch to Texture2D / RGB per their docs, or blit to GL_TEXTURE_2D first.

Shared helper

Reuse this on every vendor GL callback (must run on the GL thread):
Create the engine (also on the GL thread):
Credentials: Subscription, Auth & License.

TRTC (Tencent)

Hook: TRTCCloud.setLocalVideoProcessListener. Use pixel format Texture_2D and buffer type TEXTURE. Create Facebetter in onGLContextCreated, process in onProcessVideoFrame and set dstFrame.texture.textureId, release() in onGLContextDestory.
Release the engine after removing the listener or leaving the room. See Tencent’s third-party beauty guide for the latest TRTC details. For Flutter, use Flutter · Third-party Integration (FacebetterPlugin.processTexture, not this Java API).

Agora

Hook: RtcEngine.registerVideoFrameObserver (Video SDK 4.x). You need to:
  1. Return PROCESS_MODE_READ_WRITE from getVideoFrameProcessMode()
  2. Prefer a TextureBuffer with type RGB (GL_TEXTURE_2D)
  3. Run Facebetter in onCaptureVideoFrame (or your chosen observe position), then write the processed texture back into the VideoFrame
How you inject a new textureId back into Agora’s VideoFrame depends on their TextureBuffer helpers and differs across major versions. Facebetter only produces a new GL_TEXTURE_2D; the write-back step must follow Agora’s video frame observer / API Reference.
Unregister the observer and beautyEngine.release() before destroying RtcEngine.

LiveKit

Hook: pass an org.webrtc.VideoProcessor (or equivalent track processor) when creating the local video track. Process textures in onFrameCaptured, then deliver via sink.onFrame(...).
You can also implement a custom VideoCapturer, run processTexture after capture, then call capturerObserver.onFrameCaptured. Official processors (for example virtual background) live in LiveKit’s livekit-android-track-processors module.

Troubleshooting