Flutter多媒体处理插件media_kit_fork的使用
Flutter多媒体处理插件media_kit_fork的使用
介绍
package:media_kit_fork 是一个用于 Flutter 和 Dart 的跨平台视频播放器和音频播放器库。
安装
package:media_kit_fork 被拆分为多个包以提高模块化并减少包的大小。
对于需要视频播放的应用:
dependencies:
  media_kit_fork: ^1.1.11 # 主要包。
  media_kit_video: ^1.2.5 # 视频渲染。
  media_kit_libs_video: ^1.0.5 # 原生视频依赖。
对于需要音频播放的应用:
dependencies:
  media_kit_fork: ^1.1.11 # 主要包。
  media_kit_libs_audio: ^1.0.5 # 原生音频依赖。
注意:
- 如果需要同时支持视频和音频,应选择视频库。
 media_kit_libs_video和media_kit_libs_audio包不应混合使用。- 在“发布”模式下的性能显著高于“调试”模式。
 - 在 Android 上启用 
--split-per-abi或使用 app bundle(而不是 APK)。 
支持的平台
| 平台 | 视频 | 音频 | 备注 | Demo | 
|---|---|---|---|---|
| Android | ✅ | ✅ | Android 5.0或以上 | 下载 | 
| iOS | ✅ | ✅ | iOS 9或以上 | 下载 | 
| macOS | ✅ | ✅ | macOS 10.9或以上 | 下载 | 
| Windows | ✅ | ✅ | Windows 7或以上 | 下载 | 
| GNU/Linux | ✅ | ✅ | 任何现代的GNU/Linux发行版 | 下载 | 
| Web | ✅ | ✅ | 任何现代的网页浏览器 | 访问 | 
快速使用示例
// 确保在 pubspec.yaml 中添加以下包:
// * media_kit_fork
// * media_kit_video
// * media_kit_libs_video
import 'package:flutter/material.dart';
import 'package:media_kit_fork/media_kit_fork.dart';                      // 提供 [Player], [Media], [Playlist] 等。
import 'package:media_kit_video/media_kit_video.dart';          // 提供 [VideoController] 和 [Video] 等。
void main() {
  WidgetsFlutterBinding.ensureInitialized();
  // 对 package:media_kit_fork 进行必要的初始化。
  MediaKit.ensureInitialized();
  runApp(
    const MaterialApp(
      home: MyScreen(),
    ),
  );
}
class MyScreen extends StatefulWidget {
  const MyScreen({Key? key}) : super(key: key);
  @override
  State<MyScreen> createState() => MyScreenState();
}
class MyScreenState extends State<MyScreen> {
  // 创建一个 [Player] 来控制播放。
  late final player = Player();
  // 创建一个 [VideoController] 来处理来自 [Player] 的视频输出。
  late final controller = VideoController(player);
  @override
  void initState() {
    super.initState();
    // 播放一个 [Media] 或 [Playlist]。
    player.open(Media('https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4'));
  }
  @override
  void dispose() {
    player.dispose();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Center(
      child: SizedBox(
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.width * 9.0 / 16.0,
        // 使用 [Video] 小部件来显示视频输出。
        child: Video(controller: controller),
      ),
    );
  }
}
注意: 可能需要添加所需的权限到项目中。
初始化
在使用该包之前必须调用 MediaKit.ensureInitialized 方法:
void main() {
  WidgetsFlutterBinding.ensureInitialized();
  // 确保将所需包添加到 pubspec.yaml 中:
  // * https://github.com/media-kit/media-kit#installation
  // * https://pub.dev/packages/media_kit_fork#installation
  MediaKit.ensureInitialized();
  runApp(const MyApp());
}
该方法也有一些可选参数以自定义全局行为。为处理任何初始化错误,这可以由 try/catch 包围。
创建一个 Player
Player 实例用于开始并控制媒体源(如 URL 或文件)的播放。
final Player player = Player();
在一般情况下,你可能永远不需要提供构造函数中的 configuration 参数。
final Player player = Player(
  configuration: PlayerConfiguration(
    // 提供你的选项:
    title: '我的 awesome package:media_kit_fork 应用',
    ready: () {
      print('初始化完成。');
    },
  ),
);
释放 Player
重要的是要释放分配给系统的资源:
await player.dispose();
打开一个 Media 或 Playlist
Playable 可以是一个 Media 或 Playlist。
Media: 单个播放源(文件或 URL)。Playlist: 播放源队列(文件或 URL)。
使用 Player.open 方法加载并开始播放。
Media
final playable = Media('https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4');
await player.open(playable);
Playlist
final playable = Playlist(
  [
    Media('https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373709-603a7a89-2105-4e1b-a5a5-a6c3567c9a59.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373716-76da0a4e-225a-44e4-9ee7-3e9006dbc3e3.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373718-86ce5e1d-d195-45d5-baa6-ef94041d0b90.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4'),
  ],
);
await player.open(playable);
注意:
- 默认情况下,这将自动开始播放 
playable。这可以通过以下方式禁用: 
await player.open(
  playable,
  play: false,
);
- 默认情况下,播放列表将从索引 
0开始。这可以通过以下方式更改: 
final playable = Playlist(
  [
    Media('https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373709-603a7a89-2105-4e1b-a5a5-a6c3567c9a59.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373716-76da0a4e-225a-44e4-9ee7-3e9006dbc3e3.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373718-86ce5e1d-d195-45d5-baa6-ef94041d0b90.mp4'),
    Media('https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4'),
  ],
  // 声明起始位置。
  index: 0,
);
await player.open(playable);
播放、暂停或播放/暂停
有三种方法:
await player.play();
await player.pause();
await player.playOrPause();
停止
stop 方法可用于停止当前打开的 Media 或 Playlist 的播放。
await player.stop();
它不会释放分配给系统的资源(不像 dispose),并且 Player 仍然可用。
查找
向 Player.seek 方法提供最终位置作为 Duration:
await player.seek(
  const Duration(
    minutes: 6,
    seconds: 9,
  ),
);
循环或重复
有三个 PlaylistMode:
PlaylistMode.none: 到达播放列表末尾后停止播放。PlaylistMode.single: 不断循环播放播放列表中的当前文件。PlaylistMode.loop: 循环播放播放列表,并在到达末尾时从头开始重新播放。
await player.setPlaylistMode(PlaylistMode.single);
设置音量、速度或音高
设置音量
这控制音频输出的响度。最大音量为 100.0。
await player.setVolume(50.0);
设置速度
这控制播放速度。
await player.setRate(1.5);
设置音高
这控制音频输出的音高。
await player.setPitch(1.2);
注意: 这需要在 PlayerConfiguration 中的 pitch 参数为 true。
处理播放事件
你可以访问或订阅 Player 的状态变化。
事件处理是媒体播放的重要部分,用于在 UI 中显示更改,处理错误,检测播放/暂停、文件结束、位置更新等的发生。
Player.stream.*: 提供对Player的状态作为Stream的访问。Player.state.*: 直接提供对Player的状态的访问(用于即时访问)。
一个典型的例子将是:
player.stream.playing.listen(
  (bool playing) {
    if (playing) {
      // 正在播放。
    } else {
      // 已暂停。
    }
  },
);
player.stream.position.listen(
  (Duration position) {
    setState(() {
      // 更新 UI。
    });
  },
);
可用的状态如下:
| 类型 | 名称 | 描述 | 
|---|---|---|
Stream<Playlist> | 
playlist | 
当前打开的媒体源。 | 
Stream<bool> | 
playing | 
是否正在播放。 | 
Stream<bool> | 
completed | 
当前播放的媒体源是否已到达结尾。 | 
Stream<Duration> | 
position | 
当前播放位置。 | 
Stream<Duration> | 
duration | 
当前播放持续时间。 | 
Stream<double> | 
volume | 
当前音量。 | 
Stream<double> | 
rate | 
当前播放速率。 | 
Stream<double> | 
pitch | 
当前音高。 | 
Stream<bool> | 
buffering | 
是否正在缓冲。 | 
Stream<Duration> | 
buffer | 
当前缓冲位置。这表示流已被解码和缓存了多少。 | 
Stream<PlaylistMode> | 
playlistMode | 
当前播放列表模式。 | 
Stream<AudioParams> | 
audioParams | 
当前播放的媒体源的音频参数,例如采样率、通道数等。 | 
Stream<VideoParams> | 
videoParams | 
当前播放的媒体源的视频参数,例如宽度、高度、旋转等。 | 
Stream<double?> | 
audioBitrate | 
当前播放的媒体源的音频比特率。 | 
Stream<AudioDevice> | 
audioDevice | 
当前选择的音频设备。 | 
Stream<List<AudioDevice>> | 
audioDevices | 
当前可用的音频设备。 | 
Stream<Track> | 
track | 
当前选择的视频、音频和字幕轨道。 | 
Stream<Tracks> | 
tracks | 
当前可用的视频、音频和字幕轨道。 | 
Stream<int> | 
width | 
当前播放视频的宽度。 | 
Stream<int> | 
height | 
当前播放视频的高度。 | 
Stream<int> | 
subtitle | 
当前显示的字幕。 | 
Stream<PlayerLog> | 
log | 
内部日志。 | 
Stream<String> | 
error | 
错误消息。这可以用于处理并向用户显示错误。 | 
混淆队列
你可能会发现需要像某些音乐播放器一样混淆 Playlist,你已在 Player 中 open 了。
await player.setShuffle(true);
注意: 这个选项将在下一个 Player.open 调用时重置。
使用 HTTP 头
在 Media 构造函数中声明 httpHeaders 参数。它接受 HTTP 头作为 Map<String, String>。
final playable = Media(
  'https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4',
  httpHeaders: {
    'Foo': 'Bar',
    'Accept': '*/*',
    'Range': 'bytes=0-',
  },
);
使用 extras 存储媒体的额外数据
extras 参数可以用来以 Map<String, dynamic> 的形式存储 Media 的额外数据。
final playable = Media(
  'https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4',
  extras: {
    'track': '9',
    'year': '2012',
    'title': 'Courtesy Call',
    'artist': 'Thousand Foot Krutch',
    'album': 'The End Is Where We Begin',
  },
);
修改 Player 的队列
可以在已经播放的 Playlist 中添加或删除(等)一个 Media:
添加
向队列末尾添加一个新的 Media:
await player.add(Media('https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4'));
删除
从队列中删除任何项目:
await player.remove(0);
移动
将队列中的任何项目从一个位置移动到另一个位置:
await player.move(6, 9);
转到队列中的下一曲、上一曲或其他位置
跳转到下一曲
await player.next();
跳转到上一曲
await player.previous();
跳转到其他曲目
await player.jump(5);
选择视频、音频或字幕轨道
媒体源可能包含多个视频、音频或字幕轨道,例如为多种语言。可用的视频、音频或字幕轨道通过 Player 的状态通知。有关相关信息,请参见“处理播放事件”部分。
默认情况下,视频、音频和字幕轨道会自动选择,即 VideoTrack.auto()、AudioTrack.auto() 和 SubtitleTrack.auto()。
自动选择
await player.setVideoTrack(VideoTrack.auto());
await player.setAudioTrack(AudioTrack.auto());
await player.setSubtitleTrack(SubtitleTrack.auto());
禁用轨道
这可以用于禁用视频输出、禁用音频输出或停止字幕渲染等。
await player.setVideoTrack(VideoTrack.no());
await player.setAudioTrack(AudioTrack.no());
await player.setSubtitleTrack(SubtitleTrack.no());
选择自定义轨道
- 检索当前可用的轨道:
 
List<VideoTrack> videos = player.state.tracks.video;
List<AudioTrack> audios = player.state.tracks.audio;
List<SubtitleTrack> subtitles = player.state.tracks.subtitle;
// 作为 [Stream] 获取通知:
player.stream.tracks.listen((event) {
  List<VideoTrack> videos = event.video;
  List<AudioTrack> audios = event.audio;
  List<SubtitleTrack> subtitles = event.subtitle;
});
- 选择轨道:
 
await player.setVideoTrack(videos[0]);
await player.setAudioTrack(audios[1]);
await player.setSubtitleTrack(subtitles[2]);
- 获取当前选择的轨道的通知:
 
VideoTrack video = player.state.track.video;
AudioTrack audio = player.state.track.audio;
SubtitleTrack subtitle = player.state.track.subtitle;
// 作为 [Stream] 获取通知:
player.stream.track.listen((event) {
  VideoTrack video = event.video;
  AudioTrack audio = event.audio;
  SubtitleTrack subtitle = event.subtitle;
});
选择音频设备
当前可用的音频设备通过 Player 的状态通知。有关相关信息,请参见“处理播放事件”部分。
默认情况下,音频设备会自动选择,即 AudioDevice.auto()。
默认选择
await player.setAudioDevice(AudioDevice.auto());
禁用音频输出
await player.setAudioDevice(AudioDevice.no());
选择自定义音频设备
- 检索当前可用的音频设备:
 
List<AudioDevice> devices = player.state.audioDevices;
// 作为 [Stream] 获取通知:
player.stream.audioDevices.listen((event) {
  List<AudioDevice> devices = event;
});
- 选择音频设备:
 
await player.setAudioDevice(devices[1]);
- 获取当前选择的音频设备的通知:
 
AudioDevice device = player.state.audioDevice;
// 作为 [Stream] 获取通知:
player.stream.audioDevice.listen((event) {
  AudioDevice device = event;
});
显示视频
现有的“TL;DR 示例”应该为你提供更好的想法。
为了在 Flutter UI 中显示视频,你必须:
- 创建 
VideoController- 传递你已经有的 
Player。 
 - 传递你已经有的 
 - 创建 
Video小部件- 传递你已经有的 
VideoController。 
 - 传递你已经有的 
 
代码更容易理解:
class _MyScreenState extends State<MyScreen> {
  late final Player player = Player();
  late final VideoController controller = VideoController(player);
  @override
  void dispose() {
    player.dispose();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Video(
        controller: controller,
      ),
    );
  }
}
视频播放使用硬件加速,即默认使用 GPU。
可以使用 configuration 参数在构造函数中提供附加选项。在一般情况下,你永远不会需要这个。
final VideoController player = VideoController(
  player,
  configuration: const VideoControllerConfiguration(
    // 提供你的选项:
    enableHardwareAcceleration: true,      // 默认值:true
    width: 640,                            // 默认值:null
    height: 480,                           // 默认值:null
    // 注释是最好的了解这些选项的地方:
    // https://github.com/media-kit/media-kit/blob/main/media_kit_video/lib/src/video_controller/video_controller.dart
  ),
);
截图
screenshot 方法获取当前视频帧的快照并返回编码图像字节作为 Uint8List。
final Uint8List? screenshot = await player.screenshot();
此外,可以指定 format 参数以更改编码格式。支持以下格式:
image/jpeg: 返回 JPEG 编码的图像。image/png: 返回 PNG 编码的图像。null: 返回 BGRA 像素缓冲区。
自定义字幕
可以将 SubtitleViewConfiguration 传递给 Video 小部件以自定义字幕。代码更容易理解:
- 可以提供 
TextStyle、TextAlign和EdgeInsetsGeometry。 
Video(
  controller: controller,
  subtitleViewConfiguration: const SubtitleViewConfiguration(
    style: TextStyle(
      height: 1.4,
      fontSize: 24.0,
      letterSpacing: 0.0,
      wordSpacing: 0.0,
      color: Color(0xffffffff),
      fontWeight: FontWeight.normal,
      backgroundColor: Color(0xaa000000),
    ),
    textAlign: TextAlign.center,
    padding: EdgeInsets.all(24.0),
  ),
);
加载外部字幕轨道
可以使用 SubtitleTrack.uri 构造函数加载带 URI 的外部字幕轨道(例如 SRT、WebVTT 等)。代码更容易理解:
await player.setSubtitleTrack(
  SubtitleTrack.uri(
    'https://www.iandevlin.com/html5test/webvtt/upc-video-subtitles-en.vtt',
    title: 'English',
    language: 'en',
  ),
);
可以使用 SubtitleTrack.data 构造函数加载带数据的外部字幕轨道(例如 SRT、WebVTT 等)。代码更容易理解:
player.setSubtitleTrack(
  SubtitleTrack.data(
    '''WEBVTT FILE
1
00:00:03.500 --> 00:00:05.000 D:vertical A:start
Everyone wants the most from life
2
00:00:06.000 --> 00:00:09.000 A:start
Like internet experiences that are rich <b>and</b> entertaining
3
00:00:11.000 --> 00:00:14.000 A:end
Phone conversations where people truly <c.highlight>connect</c>
4
00:00:14.500 --> 00:00:18.000
Your favourite TV programmes ready to watch at the touch of a button
5
00:00:19.000 --> 00:00:24.000
Which is why we are bringing TV, internet and phone together in <c.highlight>one</c> super package
6
00:00:24.500 --> 00:00:26.000
<c.highlight>One</c> simple way to get everything
7
00:00:26.500 --> 00:00:27.500 L:12%
UPC
8
00:00:28.000 --> 00:00:30.000 L:75%
Simply for <u>everyone</u>
''',
    title: 'English',
    language: 'en',
  ),
);
加载外部音频轨道
可以使用 AudioTrack.uri 构造函数加载带 URI 的外部音频轨道。代码更容易理解:
await player.setAudioTrack(
  AudioTrack.uri(
    'https://www.iandevlin.com/html5test/webvtt/v/upc-tobymanley.mp4',
    title: 'English',
    language: 'en',
  ),
);
视频控件
package:media_kit_fork 提供了高度可定制的预构建视频控件。
除了主题外,布局可以自定义,按钮的位置可以修改,还可以创建自定义按钮。默认情况下还支持必要功能,如全屏、键盘快捷键和基于滑动的控件。
| 控件 | 图片 | 
|---|---|
<tt>MaterialDesktopVideoControls</tt> | 
![]()  | 
<tt>MaterialVideoControls</tt> | 
![]()  | 
Video小部件提供controls参数以显示并自定义视频控件。- 默认情况下,使用 
<a href="#adaptivevideocontrols"><code>AdaptiveVideoControls</code></a>。 
类型
| 类型 | 描述 | 
|---|---|
<a href="#adaptivevideocontrols"><code>AdaptiveVideoControls</code></a> | 
根据平台选择 <a href="#materialvideocontrols"><code>MaterialVideoControls</code></a>、<a href="#cupertinovideocontrols"><code>CupertinoVideoControls</code></a> 等。 | 
<a href="#materialvideocontrols"><code>MaterialVideoControls</code></a> | 
<a href="https://material.io/" rel="ugc">Material Design</a> 视频控件。 | 
<a href="#materialdesktopvideocontrols"><code>MaterialDesktopVideoControls</code></a> | 
<a href="https://material.io/" rel="ugc">Material Design</a> 视频控件适用于桌面。 | 
<a href="#cupertinovideocontrols"><code>CupertinoVideoControls</code></a> | 
<a href="https://developer.apple.com/design/human-interface-guidelines/designing-for-ios" rel="ugc">iOS-style</a> 视频控件。 | 
<a href="#novideocontrols"><code>NoVideoControls</code></a> | 
禁用视频控件(即仅渲染视频输出)。 | 
| 自定义 | 提供自定义 <code>builder</code> 用于视频控件。 | 
选择现有视频控件
修改 controls 参数。有关高级主题化现有视频控件的信息,请参阅“主题化和修改视频控件”部分。
Scaffold(
  body: Video(
    controller: controller,
    // 选择 `[MaterialVideoControls]`。
    controls: MaterialVideoControls,
  ),
);
Scaffold(
  body: Video(
    controller: controller,
    // 选择 `[CupertinoVideoControls]`。
    controls: CupertinoVideoControls,
  ),
);
构建自定义视频控件
将自定义构建器 <code>Widget Function(BuildContext, VideoController)</code> 作为 controls 参数传递。
Scaffold(
  body: Video(
    controller: controller,
    // 提供自定义构建器用于控件。
    controls: (state) {
      return Center(
        child: IconButton(
          onPressed: () {
            state.widget.controller.player.playOrPause();
          },
          icon: StreamBuilder(
            stream: state.widget.controller.player.stream.playing,
            builder: (context, playing) => Icon(
              playing.data == true ? Icons.pause : Icons.play_arrow,
            ),
          ),
          // 不一定需要使用 `[StreamBuilder]` 或使用 `[Player]` 和 `[VideoController]` 从 `[state]`。
          // `[StreamSubscription]` 可以在该小部件的 `[initState]` 中制作。
        ),
      );
    },
  ),
);
使用和修改视频控件
<code>AdaptiveVideoControls</code>
- 根据平台选择 
<a href="#materialvideocontrols"><code>MaterialVideoControls</code></a>、<a href="#cupertinovideocontrols"><code>CupertinoVideoControls</code></a>等。 - 主题化:
- 根据以下部分的主题化特定控件。
 
 
<code>MaterialVideoControls</code>
<a href="https://material.io/" rel="ugc">Material Design</a>视频控件。- 主题化:
- 使用 
<code>MaterialVideoControlsTheme</code>小部件。 <code>Video</code>小部件(在<code>child</code>树中)将遵循指定的主题:
 - 使用 
 
// 将 `[Video]` 小部件包装在 `[MaterialVideoControlsTheme]` 中。
MaterialVideoControlsTheme(
  normal: MaterialVideoControlsThemeData(
    // 修改主题选项:
    buttonBarButtonSize: 24.0,
    buttonBarButtonColor: Colors.white,
    // 修改顶部按钮栏:
    topButtonBar: [
      const Spacer(),
      MaterialDesktopCustomButton(
        onPressed: () {
          debugPrint('Custom "Settings" button pressed.');
        },
        icon: const Icon(Icons.settings),
      ),
    ],
  ),
  fullscreen: const MaterialVideoControlsThemeData(
    // 修改主题选项:
    displaySeekBar: false,
    automaticallyImplySkipNextButton: false,
    automaticallyImplySkipPreviousButton: false,
  ),
  child: Scaffold(
    body: Video(
      controller: controller,
    ),
  ),
);
- 相关小部件(可在 
<code>primaryButtonBar</code>、<code>topButtonBar</code>和<code>bottomButtonBar</code>中使用):<code>MaterialPlayOrPauseButton</code><code>MaterialSkipNextButton</code><code>MaterialSkipPreviousButton</code><code>MaterialFullscreenButton</code><code>MaterialCustomButton</code><code>MaterialPositionIndicator</code>
 
<code>MaterialDesktopVideoControls</code>
<a href="https://material.io/" rel="ugc">Material Design</a>视频控件适用于桌面。- 主题化:
- 使用 
<code>MaterialDesktopVideoControlsTheme</code>小部件。 <code>Video</code>小部件(在<code>child</code>树中)将遵循指定的主题:
 - 使用 
 
// 将 `[Video]` 小部件包装在 `[MaterialDesktopVideoControlsTheme]` 中。
MaterialDesktopVideoControlsTheme(
  normal: MaterialDesktopVideoControlsThemeData(
    // 修改主题选项:
    seekBarThumbColor: Colors.blue,
    seekBarPositionColor: Colors.blue,
    toggleFullscreenOnDoublePress: false,
    // 修改顶部按钮栏:
    topButtonBar: [
      const Spacer(),
      MaterialDesktopCustomButton(
        onPressed: () {
          debugPrint('Custom "Settings" button pressed.');
        },
        icon: const Icon(Icons.settings),
      ),
    ],
    // 修改底部按钮栏:
    bottomButtonBar: const [
      Spacer(),
      MaterialDesktopPlayOrPauseButton(),
      Spacer(),
    ],
  ),
  fullscreen: const MaterialDesktopVideoControlsThemeData(),
  child: Scaffold(
    body: Video(
      controller: controller,
    ),
  ),
);
- 相关小部件(可在 
<code>primaryButtonBar</code>、<code>topButtonBar</code>和<code>bottomButtonBar</code>中使用):<code>MaterialDesktopPlayOrPauseButton</code><code>MaterialDesktopSkipNextButton</code><code>MaterialDesktopSkipPreviousButton</code><code>MaterialDesktopFullscreenButton</code><code>MaterialDesktopCustomButton</code><code>MaterialDesktopVolumeButton</code><code>MaterialDesktopPositionIndicator</code>
 - 可以使用 
<code>keyboardShortcuts</code>参数修改键盘快捷键。默认的如下: 
| 快捷键 | 动作 | 
|---|---|
| 媒体播放按钮 | 播放 | 
| 媒体暂停按钮 | 暂停 | 
| 媒体播放/暂停按钮 | 播放/暂停 | 
| 媒体下一曲按钮 | 下一首 | 
| 媒体上一曲按钮 | 上一首 | 
| 空格键 | 播放/暂停 | 
| J | 后退 10秒 | 
| I | 前进 10秒 | 
| 左箭头键 | 后退 2秒 | 
| 右箭头键 | 前进 2秒 | 
| 上箭头键 | 音量增加 5% | 
| 下箭头键 | 音量减少 5% | 
| F | 进入/退出全屏 | 
| Esc | 退出全屏 | 
<code>CupertinoVideoControls</code>
<a href="https://developer.apple.com/design/human-interface-guidelines/designing-for-ios" rel="ugc">iOS-style</a>视频控件。- 主题化:
- 使用 
<code>CupertinoVideoControlsTheme</code>小部件。 <code>Video</code>小部件(在<code>child</code>树中)将遵循指定的主题:
 - 使用 
 
// 将 `[Video]` 小部件包装在 `[CupertinoVideoControlsTheme]` 中。
CupertinoVideoControlsTheme(
  normal: const CupertinoVideoControlsThemeData(
    // W.I.P.
  ),
  fullscreen: const CupertinoVideoControlsThemeData(
    // W.I.P.
  ),
  child: Scaffold(
    body: Video(
      controller: controller,
    ),
  ),
);
更多关于Flutter多媒体处理插件media_kit_fork的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter多媒体处理插件media_kit_fork的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,关于media_kit_fork这个Flutter插件的使用,以下是一个基本的代码案例,展示了如何在Flutter项目中集成和使用该插件进行多媒体处理。请注意,由于media_kit_fork可能是一个社区维护的分支或特定版本,确保你的pubspec.yaml文件中正确引用了该插件。
1. 在pubspec.yaml中添加依赖
首先,你需要在pubspec.yaml文件中添加media_kit_fork依赖。请注意,这里假设插件名称确实为media_kit_fork,如果实际名称不同,请相应调整。
dependencies:
  flutter:
    sdk: flutter
  media_kit_fork: ^x.y.z  # 替换为实际的版本号
然后运行flutter pub get来安装依赖。
2. 导入插件并使用其功能
以下是一个简单的示例,展示了如何使用media_kit_fork插件来处理音频或视频文件。由于media_kit_fork的具体API和功能可能因版本而异,这里提供一个假设性的使用案例,具体API调用需参考插件的官方文档。
import 'package:flutter/material.dart';
import 'package:media_kit_fork/media_kit_fork.dart';
void main() {
  runApp(MyApp());
}
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
  String _result = '';
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Media Kit Fork Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('Result: $_result'),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: _processMedia,
                child: Text('Process Media'),
              ),
            ],
          ),
        ),
      ),
    );
  }
  Future<void> _processMedia() async {
    // 假设有一个本地音频或视频文件路径
    String mediaPath = 'path/to/your/media/file.mp4';
    try {
      // 初始化MediaKitFork
      final MediaKitFork mediaKit = MediaKitFork();
      // 假设这里有一个方法用于处理媒体文件,如获取媒体信息
      MediaInfo info = await mediaKit.getMediaInfo(mediaPath);
      
      // 根据获取的媒体信息更新UI
      setState(() {
        _result = 'Duration: ${info.duration.inSeconds}s, Width: ${info.width}, Height: ${info.height}';
      });
      // 其他可能的操作,如转码、剪辑等,这里仅作为示例
      // String transcodedPath = await mediaKit.transcode(mediaPath, outputPath: 'path/to/output/file.mp4');
      // ...
    } catch (e) {
      // 处理错误
      setState(() {
        _result = 'Error: $e';
      });
    }
  }
}
// 假设的MediaInfo类,实际使用时需根据插件文档调整
class MediaInfo {
  final Duration duration;
  final int width;
  final int height;
  MediaInfo({required this.duration, required this.width, required this.height});
}
注意事项
- 插件版本与API:上述代码是基于假设的API调用,实际使用时请查阅
media_kit_fork的官方文档以获取正确的API调用方法和参数。 - 权限处理:处理本地媒体文件可能需要额外的权限,确保在Android和iOS平台上正确配置权限。
 - 错误处理:在真实应用中,应添加更详细的错误处理逻辑,以提高应用的健壮性。
 
希望这个示例能帮助你开始使用media_kit_fork插件进行多媒体处理。如果有任何进一步的问题或需要更具体的帮助,请查阅插件的官方文档或寻求社区支持。
        
      
            
            
            


