Skip to main content

Integration

Engine construction throws or never becomes ready

  • IllegalArgumentException: EngineConfig needs a non-empty licenseToken, or both appId and appKey
  • Bind the application package name in the Dashboard to this app
  • For online auth, confirm network access to /facebetter/v2/auth
  • Listen for EngineEventCode.LICENSE_VALIDATION_FAILED / INITIALIZATION_FAILED
  • Call setLogConfig before new BeautyEffectEngine(...)
Auth: Auth & License.

Compile: cannot resolve net.pixpark.facebetter

  • Maven: implementation 'net.pixpark:facebetter:2.0.0'
  • Local AAR: implementation files('libs/facebetter.aar') and Sync
  • Clean / Rebuild

UnsatisfiedLinkError

  • Device ABI must be arm64-v8a or armeabi-v7a
  • Keep libfacebetter.so if you shrink/obfuscate; keep Facebetter native methods in ProGuard / R8
  • Confirm the AAR / Maven artifact is complete

Effects

Beauty looks weak

  • Raise intensities in [0, 1] (setSmoothing, setWhitening, makeup, …)
  • Reshape uses [-1, 1] — a value near 0 is almost off
  • Confirm INITIALIZATION_COMPLETE and that processImage returns a non-null frame
  • Check landmarks via onFaceLandmarks (empty list = no face)

Face looks warped

  • Lower setReshape magnitudes; opposite sign reverses the direction
  • Avoid stacking many reshape knobs at high absolute values
  • Use FrameType.IMAGE for still export if live VIDEO looks softer, not stronger

Virtual background does nothing

  • Call setVirtualBackgroundBlur(level) with level > 0, or setVirtualBackground(path|bytes)
  • setVirtualBackgroundBlur(0) clears the effect
  • Image path must be a readable PNG/JPG; empty path returns ErrorCode.INVALID_ARGUMENT
  • Green screen: setChromaKey(ChromaKeyColor.GREEN) plus a fill (blur or image)
  • clearChromaKey() only restores the portrait mask; it does not remove the fill

Filter or sticker does not appear

  • Pass a .fbd path or bytes to setFilter / setSticker (no register API)
  • Upload happens on the next processImage on the GL thread
  • With externalContext = true, that call must run with a current GL context
  • setFilterIntensity(0) makes a LUT invisible

Performance and memory

Preview is slow

  • input.type = ImageFrame.FrameType.VIDEO
  • Lower capture resolution
  • Fewer simultaneous reshape / makeup / VB effects
  • processImage off the main thread (camera or GL thread)
  • Watch engine.getStats().avgProcessTimeMs
  • Large gallery stills: build a smaller preview frame when the photo opens; export the original once. See Best practices

Memory climbs or native crash

  • release() every ImageFrame, including convert() results and processImage output
  • Use ByteBuffer.allocateDirect
  • One engine instance; call engine.release() in onDestroy

ANR

  • Do not run processImage on the UI thread for HD video
  • Do not load large .fbd / JPEG files on the main thread

Image and camera

How do I change pixel format?

Use ImageFrame.convert(Format) (returns a new frame):
Packed pixels: getData(). Planar YUV: getDataY() / getDataU() / getDataV() or getDataUV().

Camera2 preview

  1. Image from YUV_420_888
  2. ImageFrame.createWithAndroid420(...)
  3. rotate / mirror for sensor + front camera
  4. input.type = FrameType.VIDEO
  5. processImage(input)
  6. Convert or getTexture() for display

Rotation

rotate(ImageFrame.Rotation.ROTATION_90) (0 / 90 / 180 / 270, clockwise) mutates the frame.

Permissions

Online auth:
Camera preview: CAMERA (runtime request on API 23+). File logs outside app storage may need storage permissions on older APIs.

Debugging

Enable logs before creating the engine:
Setters return 0 on success. -1 = invalid argument, -2 = not initialized. Full list: Error Handling.

Compatibility

  • Android 7.0 (API 24)+
  • ABIs: arm64-v8a, armeabi-v7a
  • Maven: net.pixpark:facebetter:2.0.0
To upgrade: bump the Maven / AAR version, Clean, rebuild, and retest license + camera + stills.