Flutter多媒体处理插件media_kit_fork的使用

发布于 1周前 作者 eggper 来自 Flutter

Flutter多媒体处理插件media_kit_fork的使用

介绍

package:media_kit_fork 是一个用于 Flutter 和 Dart 的跨平台视频播放器和音频播放器库。

Discord

安装

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_videomedia_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 可以是一个 MediaPlaylist

  • 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);

注意:

  1. 默认情况下,这将自动开始播放 playable。这可以通过以下方式禁用:
await player.open(
  playable,
  play: false,
);
  1. 默认情况下,播放列表将从索引 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 方法可用于停止当前打开的 MediaPlaylist 的播放。

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,你已在 Playeropen 了。

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 小部件以自定义字幕。代码更容易理解:

  • 可以提供 TextStyleTextAlignEdgeInsetsGeometry
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 --&gt; 00:00:05.000 D:vertical A:start
Everyone wants the most from life

2
00:00:06.000 --&gt; 00:00:09.000 A:start
Like internet experiences that are rich &lt;b&gt;and&lt;/b&gt; entertaining

3
00:00:11.000 --&gt; 00:00:14.000 A:end
Phone conversations where people truly &lt;c.highlight&gt;connect&lt;/c&gt;

4
00:00:14.500 --&gt; 00:00:18.000
Your favourite TV programmes ready to watch at the touch of a button

5
00:00:19.000 --&gt; 00:00:24.000
Which is why we are bringing TV, internet and phone together in &lt;c.highlight&gt;one&lt;/c&gt; super package

6
00:00:24.500 --&gt; 00:00:26.000
&lt;c.highlight&gt;One&lt;/c&gt; simple way to get everything

7
00:00:26.500 --&gt; 00:00:27.500 L:12%
UPC

8
00:00:28.000 --&gt; 00:00:30.000 L:75%
Simply for &lt;u&gt;everyone&lt;/u&gt;
''',
    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

1 回复

更多关于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});
}

注意事项

  1. 插件版本与API:上述代码是基于假设的API调用,实际使用时请查阅media_kit_fork的官方文档以获取正确的API调用方法和参数。
  2. 权限处理:处理本地媒体文件可能需要额外的权限,确保在Android和iOS平台上正确配置权限。
  3. 错误处理:在真实应用中,应添加更详细的错误处理逻辑,以提高应用的健壮性。

希望这个示例能帮助你开始使用media_kit_fork插件进行多媒体处理。如果有任何进一步的问题或需要更具体的帮助,请查阅插件的官方文档或寻求社区支持。

回到顶部