Flutter实时视频叠加:基于media_kit实现车辆帧同步框选方案咨询
Flutter实现带车辆高亮框的视频播放器
核心思路
通过视频播放组件+帧同步的自定义覆盖层实现:用media_kit播放视频,监听播放进度匹配你已有的车辆位置数据,在视频上层绘制对应的高亮框。
基于media_kit的具体实现步骤
1. 依赖配置
在pubspec.yaml中添加media_kit及对应平台的依赖(桌面端需参考官方文档完成额外配置):
dependencies: media_kit: ^1.1.10+1 media_kit_video: ^1.1.12 # 可选:用provider管理状态,简化进度与位置数据的同步 provider: ^6.1.1
2. 视频播放与进度监听
使用VideoController控制播放,监听播放进度(当前时间戳),匹配对应帧的车辆位置数据:
import 'package:media_kit/media_kit.dart'; import 'package:media_kit_video/media_kit_video.dart'; class VideoPlayerPage extends StatefulWidget { @override State<VideoPlayerPage> createState() => _VideoPlayerPageState(); } class _VideoPlayerPageState extends State<VideoPlayerPage> { late final Player player; late final VideoController controller; // 假设你已有的车辆位置数据:key为时间戳(毫秒),value为原始帧坐标的车辆Rect列表 final Map<int, List<Rect>> carPositions = {}; List<Rect> currentCarRects = []; @override void initState() { super.initState(); player = Player(); controller = VideoController(player); // 监听播放进度,实时匹配车辆位置 player.stream.position.listen((Duration position) { final timestamp = position.inMilliseconds; // 匹配最接近当前时间戳的车辆位置数据 final closestTimestamp = carPositions.keys.reduce((a, b) => (a - timestamp).abs() < (b - timestamp).abs() ? a : b); setState(() { currentCarRects = carPositions[closestTimestamp] ?? []; }); }); // 加载目标视频 player.open(Media('path/to/your/video.mp4')); } @override void dispose() { player.dispose(); controller.dispose(); super.dispose(); } }
3. 绘制高亮覆盖层
用Stack布局叠加视频播放器与自定义绘制层,注意坐标转换:视频显示尺寸可能与原始帧尺寸不同,需将原始帧坐标缩放适配当前显示区域:
@override Widget build(BuildContext context) { return Scaffold( body: Stack( children: [ // 视频播放器 Video(controller: controller), // 车辆高亮层 LayoutBuilder(builder: (context, constraints) { return CustomPaint( size: Size(double.infinity, double.infinity), painter: CarHighlightPainter( carRects: currentCarRects, videoSize: controller.size, // 原始视频帧尺寸 displaySize: constraints.biggest, // 当前视频组件显示尺寸 ), ); }), ], ), ); } // 自定义高亮框绘制器 class CarHighlightPainter extends CustomPainter { final List<Rect> carRects; final Size videoSize; final Size displaySize; CarHighlightPainter({ required this.carRects, required this.videoSize, required this.displaySize, }); @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = Colors.red.withOpacity(0.5) ..style = PaintingStyle.stroke ..strokeWidth = 2; // 计算缩放比例与偏移(保持视频原始比例) final scale = math.min( displaySize.width / videoSize.width, displaySize.height / videoSize.height, ); final offsetX = (displaySize.width - videoSize.width * scale) / 2; final offsetY = (displaySize.height - videoSize.height * scale) / 2; // 绘制每个车辆的高亮框 for (final rect in carRects) { final scaledRect = Rect.fromLTWH( rect.left * scale + offsetX, rect.top * scale + offsetY, rect.width * scale, rect.height * scale, ); canvas.drawRect(scaledRect, paint); } } @override bool shouldRepaint(covariant CarHighlightPainter oldDelegate) { return oldDelegate.carRects != carRects; } }
4. 优化同步精度
- 如果你的位置数据按帧索引存储,可通过视频帧率计算时间戳:
timestamp = frameIndex * (1000 / fps),匹配精度更高。 - 可尝试监听
player.stream.videoFrame(若media_kit支持)直接获取帧数据,进一步提升同步准确性。
替代第三方包推荐
- video_player:Flutter官方推荐的基础视频播放包,桌面端需额外配置
video_player_win/video_player_macos等平台插件,适合跨平台基础场景。 - chewie:基于
video_player的UI封装,提供现成的播放控制栏组件,可快速搭建播放器UI后叠加自定义覆盖层。
内容的提问来源于stack exchange,提问作者Fran
相关产品推荐
相关产品推荐

