lovoj_video_editor 0.5.0
lovoj_video_editor: ^0.5.0 copied to clipboard
Custom short video recording & editing SDK for Flutter — Camera2/MediaCodec (Android) + AVFoundation (iOS).
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:lovoj_video_editor/lovoj_video_editor.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await VideoEditorSdk.initialize();
runApp(const ExampleApp());
}
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Lovoj Video Editor',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Lovoj Video Editor SDK')),
body: ListView(
padding: const EdgeInsets.all(24),
children: [
const Icon(Icons.videocam, size: 72, color: Colors.deepPurple),
const SizedBox(height: 16),
const Text(
'Full-featured short video SDK',
style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
const Text(
'Recording · Filters · AR · Music · Multi-clip · Trim · Speed · Text · Voice-over',
textAlign: TextAlign.center,
),
const SizedBox(height: 32),
_FeatureTile(icon: Icons.timer, title: 'Countdown timer', subtitle: '3 sec before record'),
_FeatureTile(icon: Icons.filter_vintage, title: 'Real-time filters', subtitle: 'Beauty, warm, cool, vintage…'),
_FeatureTile(icon: Icons.face_retouching_natural, title: 'AR face stickers', subtitle: 'Cat ears, glasses, crown…'),
_FeatureTile(icon: Icons.music_note, title: 'Music during recording', subtitle: 'Background track + mix'),
_FeatureTile(icon: Icons.video_library, title: 'Multi-clip merge', subtitle: 'Sequential clips auto-merged'),
const SizedBox(height: 24),
FilledButton.icon(
onPressed: () => _openRecording(context),
icon: const Icon(Icons.fiber_manual_record),
label: const Text('Start Recording'),
),
const SizedBox(height: 12),
OutlinedButton.icon(
onPressed: () => _showApiSnippet(context),
icon: const Icon(Icons.code),
label: const Text('View API'),
),
],
),
);
}
void _openRecording(BuildContext context) {
Navigator.of(context).push<String>(
MaterialPageRoute(
builder: (_) => RecordingScreen(
config: const RecordingConfig(
countdownSec: 3,
enableCountdown: true,
autoMergeClips: true,
maxClipDurationSec: 60,
arEffect: ArEffect(type: ArEffectType.none),
),
onRecordingComplete: (path) {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => EditorScreen(videoPath: path)),
);
},
),
),
);
}
void _showApiSnippet(BuildContext context) {
showDialog<void>(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('Quick Start'),
content: const SingleChildScrollView(
child: Text('''
await VideoEditorSdk.initialize();
// Recording
RecordingScreen(config: RecordingConfig(
countdownSec: 3,
autoMergeClips: true,
arEffect: ArEffect(type: ArEffectType.glasses),
))
// Editing
final session = VideoEditorSdk.instance.editVideo(path);
session.trimClip(0, startMs: 0, endMs: 30000);
session.setClipSpeed(0, 2.0);
session.addTextOverlay(TextOverlay(...));
session.setArEffect(ArEffect(type: ArEffectType.catEars));
await session.export();
'''),
),
actions: [
TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('Close')),
],
),
);
}
}
class _FeatureTile extends StatelessWidget {
const _FeatureTile({required this.icon, required this.title, required this.subtitle});
final IconData icon;
final String title;
final String subtitle;
@override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(icon, color: Colors.deepPurple),
title: Text(title),
subtitle: Text(subtitle),
);
}
}