voxa_beauty 0.2.2 copy "voxa_beauty: ^0.2.2" to clipboard
voxa_beauty: ^0.2.2 copied to clipboard

Real-time beauty filters for VoxaRTC — skin smoothing, tone and warmth on the camera capture path, entirely on the GPU. No licence, no subscription.

example/lib/main.dart

// Beauty filtering on a live VoxaRTC camera.
//
// Everything here runs on the capture path, before the encoder, so the room
// sees it — this is not a local preview overlay.
//
// Nothing needs a licence key or an account. Smoothing is a shader, and the
// face model for lipstick ships inside the package.
import 'package:flutter/material.dart';
import 'package:voxa_beauty/voxa_beauty.dart';
import 'package:voxa_rtc_engine/voxa_rtc_engine.dart';

/// Your VoxaRTC app id.
const appId = 'YOUR_APP_ID';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MaterialApp(home: BeautyDemo()));
}

class BeautyDemo extends StatefulWidget {
  const BeautyDemo({super.key});

  @override
  State<BeautyDemo> createState() => _BeautyDemoState();
}

class _BeautyDemoState extends State<BeautyDemo> {
  // Lazy initialisers rather than assignments after an await. build() runs the
  // moment this mounts, long before the engine finishes starting, and the UI
  // below reads _beauty — assigning it later would render an error for the
  // first seconds. Both constructors are synchronous and cheap.
  late final RtcEngine _engine = createAgoraRtcEngine();
  late final VoxaBeauty _beauty = VoxaBeauty(_engine);

  VideoViewController? _preview;
  bool _on = false;

  @override
  void initState() {
    super.initState();
    _start();
  }

  Future<void> _start() async {
    await _engine.initialize(const RtcEngineContext(appId: appId));
    await _engine.enableVideo();
    await _engine.startPreview();
    setState(() {
      _preview = VideoViewController(
          rtcEngine: _engine, canvas: const VideoCanvas(uid: 0));
    });
  }

  Future<void> _toggle() async {
    if (_on) {
      await _beauty.disable();
    } else {
      await _beauty.enable();
    }
    setState(() => _on = _beauty.isEnabled);
  }

  @override
  void dispose() {
    // The native filter outlives this engine, so leaving it enabled would keep
    // it attached the next time any camera starts.
    _beauty.disable();
    _engine.release();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final preview = _preview;
    // Gate on isSupported rather than assuming: a control that always fails is
    // worse than no control.
    final ready = preview != null && _beauty.isSupported;

    return Scaffold(
      backgroundColor: Colors.black,
      body: Stack(children: [
        if (preview != null)
          Positioned.fill(child: AgoraVideoView(controller: preview)),
        Positioned(
          left: 16,
          right: 16,
          bottom: 40,
          child: Column(mainAxisSize: MainAxisSize.min, children: [
            if (_on) ...[
              _Slider(
                label: 'Smoothing',
                value: _beauty.smoothing,
                onChanged: (v) async {
                  await _beauty.setSmoothing(v);
                  setState(() {});
                },
              ),
              // Above zero this starts face tracking — the one thing here that
              // is not free, which is why it stays off until asked for.
              _Slider(
                label: 'Lipstick',
                value: _beauty.lipstick,
                onChanged: (v) async {
                  await _beauty.setLipstick(v);
                  setState(() {});
                },
              ),
            ],
            const SizedBox(height: 8),
            ElevatedButton(
              onPressed: ready ? _toggle : null,
              child: Text(_on ? 'Turn beauty off' : 'Turn beauty on'),
            ),
          ]),
        ),
      ]),
    );
  }
}

class _Slider extends StatelessWidget {
  const _Slider({
    required this.label,
    required this.value,
    required this.onChanged,
  });

  final String label;
  final double value;
  final ValueChanged<double> onChanged;

  @override
  Widget build(BuildContext context) {
    return Row(children: [
      SizedBox(
        width: 90,
        child: Text(label, style: const TextStyle(color: Colors.white)),
      ),
      Expanded(child: Slider(value: value, onChanged: onChanged)),
      SizedBox(
        width: 40,
        child: Text(value.toStringAsFixed(2),
            style: const TextStyle(color: Colors.white70, fontSize: 12)),
      ),
    ]);
  }
}
1
likes
0
points
348
downloads

Publisher

verified publishervoxartc.com

Weekly Downloads

Real-time beauty filters for VoxaRTC — skin smoothing, tone and warmth on the camera capture path, entirely on the GPU. No licence, no subscription.

Homepage

License

unknown (license)

Dependencies

flutter, voxa_rtc_engine

More

Packages that depend on voxa_beauty

Packages that implement voxa_beauty