Skip to content

Commit

Permalink
⚡️ 视频支持倍速播放
Browse files Browse the repository at this point in the history
  • Loading branch information
BTMuli committed May 2, 2024
1 parent 9bf32dd commit ad66988
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 2 deletions.
143 changes: 143 additions & 0 deletions lib/controller/app/video_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Flutter imports:
import 'package:flutter/material.dart' as material;

// Package imports:
import 'package:fluent_ui/fluent_ui.dart';
import 'package:media_kit_video/media_kit_video.dart';
import 'package:pasteboard/pasteboard.dart';

// Project imports:
import '../../components/app/app_infobar.dart';
import '../../tools/file_tool.dart';

class BtcVideo extends StatefulWidget {
/// controller
final VideoController controller;

/// 构造函数
const BtcVideo(this.controller, {super.key});

@override
State<BtcVideo> createState() => _BtcVideoState();
}

class _BtcVideoState extends State<BtcVideo>
with material.AutomaticKeepAliveClientMixin {
/// 控制器
VideoController get controller => widget.controller;

/// fileTool
final BTFileTool fileTool = BTFileTool();

/// 当前播放速度
double speed = 1.0;

/// 速度的flyout
final FlyoutController speedFlyout = FlyoutController();

@override
bool get wantKeepAlive => true;

@override
void dispose() {
speedFlyout.dispose();
super.dispose();
}

/// 根据速度获取对应文本
String getSpeedLabel(double val) {
if (val == 2.0) return '2.0倍速';
if (val == 1.5) return '1.5倍速';
if (val == 1.25) return '1.25倍速';
if (val == 1.0) return '1.0倍速';
return '${val.toStringAsFixed(2)}倍速';
}

/// 显示速度flyout
void showSpeedFlyout() {
speedFlyout.showFlyout(
barrierDismissible: true,
dismissOnPointerMoveAway: true,
dismissWithEsc: true,
builder: (context) {
return MenuFlyout(items: [
buildSpeedButton(2.0),
buildSpeedButton(1.5),
buildSpeedButton(1.25),
buildSpeedButton(1.0),
]);
},
);
}

/// 构建速度按钮
MenuFlyoutItem buildSpeedButton(double value) {
return MenuFlyoutItem(
leading: value == speed ? const Icon(material.Icons.check) : null,
text: Text(getSpeedLabel(value)),
onPressed: () async {
speed = value;
setState(() {});
await controller.player.setRate(value);
},
);
}

/// 控制栏的数据构建
MaterialDesktopVideoControlsThemeData buildControls() {
var base = FluentTheme.of(context).accentColor;
return MaterialDesktopVideoControlsThemeData(
seekBarThumbColor: base.lighter,
seekBarPositionColor: base.darker,
bottomButtonBar: [
const MaterialDesktopPlayOrPauseButton(),
const MaterialDesktopPositionIndicator(),
const MaterialDesktopVolumeButton(),
const Spacer(),
IconButton(
onPressed: () async {
await controller.player.pause();
var res = await controller.player.screenshot();
if (res == null) {
if (mounted) await BtInfobar.error(context, '截图失败');
await controller.player.play();
return;
}
var ts = DateTime.now().millisecondsSinceEpoch ~/ 1000;
var imagePath = await fileTool.writeTempImage(res, ts.toString());
// 提前写个空白文件,以防粘贴把之前的文本带上
// todo 详见 https://github.com/MixinNetwork/flutter-plugins/issues/335
Pasteboard.writeText('');
var check = await Pasteboard.writeFiles([imagePath]);
if (!check) {
if (mounted) await BtInfobar.error(context, '截图失败');
await controller.player.play();
return;
}
if (mounted) await BtInfobar.success(context, '截图已复制到剪贴板');
await controller.player.play();
},
icon: const Icon(FluentIcons.camera, size: 24),
),
FlyoutTarget(
controller: speedFlyout,
child: IconButton(
icon: const Icon(material.Icons.fast_forward, size: 24),
onPressed: showSpeedFlyout,
),
),
const MaterialDesktopFullscreenButton(),
],
);
}

@override
Widget build(BuildContext context) {
super.build(context);
return MaterialDesktopVideoControlsTheme(
normal: buildControls(),
fullscreen: buildControls(),
child: material.Scaffold(body: Video(controller: controller)),
);
}
}
3 changes: 2 additions & 1 deletion lib/pages/app/play_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:media_kit/media_kit.dart';
import 'package:media_kit_video/media_kit_video.dart';

// Project imports:
import '../../controller/app/video_controller.dart';
import '../../store/nav_store.dart';
import '../../store/play_store.dart';

Expand Down Expand Up @@ -141,7 +142,7 @@ class _PlayPageState extends ConsumerState<PlayPage>
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(child: Video(controller: controller)),
Expanded(child: BtcVideo(controller)),
const SizedBox(width: 8),
buildList(),
],
Expand Down
10 changes: 10 additions & 0 deletions lib/tools/file_tool.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Dart imports:
import 'dart:io';
import 'dart:typed_data';

// Package imports:
import 'package:path/path.dart' as path;
Expand Down Expand Up @@ -90,4 +91,13 @@ class BTFileTool {
await Process.run('explorer', [dirPath]);
return true;
}

/// 将unit8list写入文件并返回文件路径
Future<String> writeTempImage(Uint8List data, String name) async {
var dir = path.join(await getAppDataDir(), 'screenshots');
await createDir(dir);
var file = File(path.join(dir, '$name.jpeg'));
await file.writeAsBytes(data);
return file.path;
}
}
2 changes: 2 additions & 0 deletions macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import macos_window_utils
import media_kit_libs_macos_video
import media_kit_video
import package_info_plus
import pasteboard
import path_provider_foundation
import screen_brightness_macos
import screen_retriever
Expand All @@ -33,6 +34,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin"))
MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin"))
ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
Expand Down
8 changes: 8 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.0"
pasteboard:
dependency: "direct main"
description:
name: pasteboard
sha256: "1c8b6a8b3f1d12e55d4e9404433cda1b4abe66db6b17bc2d2fb5965772c04674"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.0"
path:
dependency: "direct main"
description:
Expand Down
3 changes: 2 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,10 @@ dependencies:
local_notifier: ^0.1.6
logger: ^2.2.0
media_kit: ^1.1.10+1
media_kit_video: ^1.2.4
media_kit_libs_video: ^1.0.4
media_kit_video: ^1.2.4
package_info_plus: ^7.0.0
pasteboard: ^0.2.0
path: ^1.9.0
path_provider: ^2.1.3
provider: ^6.1.2
Expand Down
3 changes: 3 additions & 0 deletions windows/flutter/generated_plugin_registrant.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <local_notifier/local_notifier_plugin.h>
#include <media_kit_libs_windows_video/media_kit_libs_windows_video_plugin_c_api.h>
#include <media_kit_video/media_kit_video_plugin_c_api.h>
#include <pasteboard/pasteboard_plugin.h>
#include <screen_brightness_windows/screen_brightness_windows_plugin.h>
#include <screen_retriever/screen_retriever_plugin.h>
#include <system_theme/system_theme_plugin.h>
Expand All @@ -35,6 +36,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi"));
MediaKitVideoPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("MediaKitVideoPluginCApi"));
PasteboardPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PasteboardPlugin"));
ScreenBrightnessWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin"));
ScreenRetrieverPluginRegisterWithRegistrar(
Expand Down
1 change: 1 addition & 0 deletions windows/flutter/generated_plugins.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
local_notifier
media_kit_libs_windows_video
media_kit_video
pasteboard
screen_brightness_windows
screen_retriever
system_theme
Expand Down

0 comments on commit ad66988

Please sign in to comment.