You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 12:45:23