Skip to content

Commit 6c5a0d5

Browse files
authored
linux(pi): implement unity_video_player_flutter (#194)
2 parents bd9d308 + 93dc124 commit 6c5a0d5

File tree

14 files changed

+396
-48
lines changed

14 files changed

+396
-48
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ flutter build [linux|windows|macos|android|ios]
162162

163163
The automated build process is done using GitHub Actions. You may find the workflow [here](.github/workflows/main.yml). The workflow builds the app for all supported platforms & uploads the artifacts to the release page.
164164

165-
On Linux, a Flutter executable with different environment variables is used to build the app for different distributions. This tells the app how the system is configured and how it should install updates. To run for Linux, you need to provide the following environment variables based on your system, where `[DISTRO_ENV]` can be `appimage` (AppImage), `deb` (Debian), `rpm` (RedHat) or `tar.gz` (Tarball).
165+
On Linux, a Flutter executable with different environment variables is used to build the app for different distributions. This tells the app how the system is configured and how it should install updates. To run for Linux, you need to provide the following environment variables based on your system, where `[DISTRO_ENV]` can be `appimage` (AppImage), `deb` (Debian), `rpm` (RedHat), `tar.gz` (Tarball) or `pi` (Raspberry Pi).
166166

167167
```bash
168168
flutter run --dart-define-from-file=linux/env/[DISTRO_ENV].json

macos/Flutter/GeneratedPluginRegistrant.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import screen_brightness_macos
1919
import screen_retriever
2020
import system_date_time_format
2121
import url_launcher_macos
22+
import video_player_avfoundation
2223
import wakelock_plus
2324
import window_manager
2425

@@ -37,6 +38,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
3738
ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
3839
SystemDateTimeFormatPlugin.register(with: registry.registrar(forPlugin: "SystemDateTimeFormatPlugin"))
3940
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
41+
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
4042
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
4143
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
4244
}

packages/unity_video_player/unity_video_player/CHANGELOG.md

Lines changed: 0 additions & 3 deletions
This file was deleted.

packages/unity_video_player/unity_video_player/LICENSE

Lines changed: 0 additions & 1 deletion
This file was deleted.

packages/unity_video_player/unity_video_player/pubspec.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ dependencies:
1414
sdk: flutter
1515
unity_video_player_main:
1616
path: ../unity_video_player_main
17+
unity_video_player_flutter:
18+
path: ../unity_video_player_flutter
1719

1820
dev_dependencies:
1921
flutter_test:
@@ -30,6 +32,8 @@ flutter:
3032
macos:
3133
default_package: unity_video_player_main
3234
linux:
33-
default_package: unity_video_player_main
35+
default_package: unity_video_player_flutter
3436
windows:
3537
default_package: unity_video_player_main
38+
web:
39+
default_package: unity_video_player_main
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Miscellaneous
2+
*.class
3+
*.log
4+
*.pyc
5+
*.swp
6+
.DS_Store
7+
.atom/
8+
.buildlog/
9+
.history
10+
.svn/
11+
migrate_working_dir/
12+
13+
# IntelliJ related
14+
*.iml
15+
*.ipr
16+
*.iws
17+
.idea/
18+
19+
# The .vscode folder contains launch configuration and tasks you configure in
20+
# VS Code which you may wish to be included in version control, so this line
21+
# is commented out by default.
22+
#.vscode/
23+
24+
# Flutter/Dart/Pub related
25+
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
26+
/pubspec.lock
27+
**/doc/api/
28+
.dart_tool/
29+
build/
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# This file tracks properties of this Flutter project.
2+
# Used by Flutter tool to assess capabilities and perform upgrades etc.
3+
#
4+
# This file should be version controlled and should not be manually edited.
5+
6+
version:
7+
revision: "6cf9ab02baecddfa3daf0c1498e62b9dc617970d"
8+
channel: "master"
9+
10+
project_type: package
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
`unity_video_player` imeplementation with `video_player`.
2+
3+
This was created to be used in the Raspberry Pi, but it should work on any platform.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
include: package:flutter_lints/flutter.yaml
2+
3+
# Additional information about this file can be found at
4+
# https://dart.dev/guides/language/analysis-options
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
library unity_video_player_flutter;
2+
3+
import 'dart:async';
4+
import 'dart:io';
5+
6+
import 'package:flutter/foundation.dart';
7+
import 'package:flutter/material.dart';
8+
import 'package:flutterpi_gstreamer_video_player/flutterpi_gstreamer_video_player.dart';
9+
import 'package:unity_video_player_main/unity_video_player_main.dart';
10+
import 'package:video_player/video_player.dart';
11+
import 'package:unity_video_player_platform_interface/unity_video_player_platform_interface.dart';
12+
13+
class UnityVideoPlayerFlutterInterface extends UnityVideoPlayerInterface {
14+
/// Registers this class as the default instance of [UnityVideoPlayerInterface].
15+
static void registerWith() {
16+
if ('pi' case const String.fromEnvironment('linux_environment')) {
17+
UnityVideoPlayerInterface.instance = UnityVideoPlayerFlutterInterface();
18+
return;
19+
}
20+
UnityVideoPlayerInterface.instance = UnityVideoPlayerMediaKitInterface();
21+
}
22+
23+
@override
24+
Future<void> initialize() async {
25+
FlutterpiVideoPlayer.registerWith();
26+
}
27+
28+
@override
29+
UnityVideoPlayer createPlayer({
30+
int? width,
31+
int? height,
32+
bool enableCache = false,
33+
RTSPProtocol? rtspProtocol,
34+
VoidCallback? onReload,
35+
String? title,
36+
}) {
37+
final player = UnityVideoPlayerFlutter(
38+
width: width,
39+
height: height,
40+
enableCache: enableCache,
41+
title: title,
42+
);
43+
UnityVideoPlayerInterface.registerPlayer(player);
44+
return player;
45+
}
46+
47+
@override
48+
Widget createVideoView({
49+
Key? key,
50+
required covariant UnityVideoPlayerFlutter player,
51+
UnityVideoFit fit = UnityVideoFit.contain,
52+
UnityVideoPaneBuilder? paneBuilder,
53+
UnityVideoBuilder? videoBuilder,
54+
Color color = const Color(0xFF000000),
55+
}) {
56+
videoBuilder ??= (context, video) => video;
57+
58+
return Builder(builder: (context) {
59+
return Stack(children: [
60+
Positioned.fill(
61+
child: videoBuilder!(
62+
context,
63+
ColoredBox(
64+
color: color,
65+
child: player.player == null
66+
? const SizedBox.expand()
67+
: VideoPlayer(player.player!),
68+
),
69+
),
70+
),
71+
if (paneBuilder != null)
72+
Positioned.fill(
73+
child: Material(
74+
type: MaterialType.transparency,
75+
child: paneBuilder(context, player),
76+
),
77+
),
78+
]);
79+
});
80+
}
81+
}
82+
83+
class UnityVideoPlayerFlutter extends UnityVideoPlayer {
84+
VideoPlayerController? player;
85+
86+
final _videoStream = StreamController<VideoPlayerValue>.broadcast();
87+
88+
UnityVideoPlayerFlutter({
89+
super.width,
90+
super.height,
91+
bool enableCache = false,
92+
RTSPProtocol? rtspProtocol,
93+
String? title,
94+
});
95+
96+
@override
97+
String? get dataSource => player?.dataSource;
98+
99+
@override
100+
Stream<String> get onError => _videoStream.stream
101+
.where((v) => v.errorDescription != null)
102+
.map((e) => e.errorDescription!);
103+
104+
@override
105+
Duration get duration => player?.value.duration ?? Duration.zero;
106+
107+
@override
108+
Stream<Duration> get onDurationUpdate =>
109+
_videoStream.stream.map((_) => duration);
110+
111+
@override
112+
Duration get currentPos => player?.value.position ?? Duration.zero;
113+
114+
@override
115+
Stream<Duration> get onCurrentPosUpdate =>
116+
_videoStream.stream.map((_) => currentPos);
117+
118+
@override
119+
bool get isBuffering => player?.value.isBuffering ?? false;
120+
121+
@override
122+
Duration get currentBuffer =>
123+
player?.value.buffered.last.end ?? Duration.zero;
124+
125+
@override
126+
Stream<Duration> get onBufferUpdate =>
127+
_videoStream.stream.map((_) => currentBuffer);
128+
129+
@override
130+
bool get isSeekable => duration > Duration.zero;
131+
132+
@override
133+
Stream<bool> get onBufferStateUpdate =>
134+
_videoStream.stream.map((_) => isBuffering);
135+
136+
@override
137+
bool get isPlaying => player?.value.isPlaying ?? false;
138+
139+
@override
140+
Stream<bool> get onPlayingStateUpdate =>
141+
_videoStream.stream.map((_) => isPlaying);
142+
143+
@override
144+
Future<void> setDataSource(String url, {bool autoPlay = true}) async {
145+
if (url == dataSource) return Future.value();
146+
debugPrint('Playing $url');
147+
148+
if (player != null) {
149+
await player?.dispose();
150+
}
151+
152+
player = VideoPlayerController.networkUrl(Uri.parse(url));
153+
await player!.initialize();
154+
notifyListeners();
155+
player!.addListener(() {
156+
_videoStream.add(player!.value);
157+
});
158+
if (autoPlay) {
159+
await player!.play();
160+
}
161+
}
162+
163+
@override
164+
Future<void> setMultipleDataSource(List<String> url, {bool autoPlay = true}) {
165+
throw UnsupportedError(
166+
'setMultipleDataSource is not supported on this platform',
167+
);
168+
}
169+
170+
// Volume in media kit goes from 0 to 100
171+
@override
172+
Future<void> setVolume(double volume) async =>
173+
await player?.setVolume(volume);
174+
175+
@override
176+
double get volume => (player?.value.volume ?? 0.0);
177+
178+
@override
179+
Stream<double> get volumeStream => _videoStream.stream.map((_) => volume);
180+
181+
@override
182+
double get fps => 0.0;
183+
@override
184+
Stream<double> get fpsStream =>
185+
throw UnsupportedError('Fps is not implemented on this platform');
186+
187+
@override
188+
double get aspectRatio => player?.value.aspectRatio ?? 1.0;
189+
190+
@override
191+
Future<void> setSpeed(double speed) async =>
192+
await player?.setPlaybackSpeed(speed);
193+
@override
194+
Future<void> seekTo(Duration position) async =>
195+
await player?.seekTo(position);
196+
197+
@override
198+
Future<void> setSize(Size size) => Future.value();
199+
200+
@override
201+
Future<void> start() async => await player?.play();
202+
203+
@override
204+
Future<void> pause() async => await player?.pause();
205+
206+
@override
207+
Future<void> release() async {
208+
if (!kIsWeb && Platform.isLinux) {
209+
await pause();
210+
await Future.delayed(const Duration(milliseconds: 150));
211+
}
212+
}
213+
214+
@override
215+
Future<void> reset() async {
216+
await pause();
217+
await seekTo(Duration.zero);
218+
}
219+
220+
@override
221+
Future<void> resetCrop() => crop(-1, -1, -1);
222+
223+
/// Crops the current video into a box at the given row and column
224+
@override
225+
Future<void> crop(int row, int col, int size) async {
226+
throw UnsupportedError('Cropping is not implemented on this platform');
227+
}
228+
229+
@override
230+
bool get isCropped {
231+
throw UnsupportedError('Cropping is not implemented on this platform');
232+
}
233+
234+
@override
235+
Future<void> dispose() async {
236+
await release();
237+
await super.dispose();
238+
await _videoStream.close();
239+
UnityVideoPlayerInterface.unregisterPlayer(this);
240+
}
241+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: unity_video_player_flutter
2+
description: "unity_video_player implementation with video_player"
3+
version: 0.0.1
4+
homepage:
5+
6+
publish_to: "none"
7+
8+
environment:
9+
sdk: '>=3.3.0-149.0.dev <4.0.0'
10+
flutter: ">=1.17.0"
11+
12+
dependencies:
13+
flutter:
14+
sdk: flutter
15+
unity_video_player_platform_interface:
16+
path: ../unity_video_player_platform_interface/
17+
unity_video_player_main:
18+
path: ../unity_video_player_main
19+
video_player: ^2.8.1
20+
flutterpi_gstreamer_video_player: ^0.1.1+1
21+
22+
dev_dependencies:
23+
flutter_test:
24+
sdk: flutter
25+
flutter_lints: ^3.0.0
26+
27+
flutter:

packages/unity_video_player/unity_video_player_main/LICENSE

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)