Skip to main content

Choose FrameType

Set ImageFrame.type before processImage. There is no extra mode argument. FrameType.VIDEO (default)
  • Camera preview, video calls, live streaming
  • Lower latency
FrameType.IMAGE
  • Gallery photos, export, capture stills
  • Higher quality, more cost per frame

Large stills (preview vs export)

Do not feed full-resolution pixels into processImage on every slider change, and do not throw the original away after scaling. When the photo opens, keep the full Bitmap and build one preview frame (long edge about 1280–1440). Slider changes call processImage on the preview (FrameType.IMAGE). Export calls processImage on a full-resolution frame with the same setters. Output size matches the input frame — do not upscale the preview. Camera preview stays capture resolution + FrameType.VIDEO.

Parameter ranges

Start low; raise after you confirm face detection and FPS. Live preview (example):
Enable setBeautySkinOnly(true) when you do not want smoothing on hair / clothes / background. Preset names: Parameter enums.

Memory

Use direct ByteBuffers when creating frames from pixel data:
Release native frames:
  • One engine per process / GL context; do not create per frame
  • Interactive stills: scale a copy for preview; keep the original Bitmap for export. See Large stills
  • convert() allocates a new frame — release it

OpenGL ES

When externalContext = true:
  • Construct the engine on the GL thread with a current context
  • Keep input texture, processImage, and output texture on that same context
  • Recreate the engine after context loss
  • Read the result with output.getTexture(), not a CPU download, when you stay on GPU
See Implement Beauty.

One engine, application context

Hold a single BeautyEffectEngine. Use getApplicationContext() so the engine outlives an Activity, and still release() when the session ends.
Always release() the engine when the session is done. ImageFrame objects also need release().

Off the UI thread

Run processImage on a camera / GL / dedicated thread. Post results to the main looper only for UI.
Do not share one ImageFrame across threads without your own lock. The demo camera path processes the latest frame on the render thread.

Filters and stickers from assets

Keep .fbd files in assets/ and pass byte[] (or copy to filesDir and pass a path). Call setFilter / setSticker once when the user picks an effect, not every frame. Adjust mix with setFilterIntensity. GPU upload happens on the next processImage.

Monitor with getStats

If avgProcessTimeMs stays above ~33 ms on a live 30 FPS preview, drop resolution, use FrameType.VIDEO, or reduce simultaneous reshape / makeup / VB.

Persist user sliders

Store intensities yourself (SharedPreferences). Re-apply with setSmoothing, setReshape, setLipstick, … after the engine is created — the SDK does not persist UI state.

Lifecycle

  • onResume / onPause: start and stop the camera; keep the engine if you will resume soon
  • onDestroy / onDetach: engine.release() if this owner created it
  • externalContext: create / destroy on the GL thread

Tests

Instrument tests need a valid license (licenseToken or reachable /facebetter/v2/auth plus a bound package name).