12 |
13 |
14 |
15 |
16 | ## Installation
17 |
18 | ### iOS
19 |
20 | If you're unable to view media loaded from an external source, you should also add the following:
21 | ```xml
22 | NSAppTransportSecurity
23 |
24 | NSAllowsArbitraryLoads
25 |
26 |
27 | ```
28 | For more information, or for more granular control over your App Transport Security (ATS) restrictions, you should
29 | [read Apple's documentation](https://developer.apple.com/documentation/bundleresources/information_property_list/nsapptransportsecurity/nsallowsarbitraryloads).
30 |
31 | Make sure that following line in `/ios/Podfile` uncommented:
32 |
33 | `platform :ios, '9.0'`
34 |
35 | > NOTE: While the Flutter `video_player` is not functional on iOS Simulators, this package (`flutter_vlc_player`) **is**
36 | > fully functional on iOS simulators.
37 |
38 | To enable vlc cast functionality for external displays (chromecast), you should also add the following:
39 |
40 | ```xml
41 | NSLocalNetworkUsageDescription
42 | Used to search for chromecast devices
43 | NSBonjourServices
44 |
45 | _googlecast._tcp
46 |
47 | ```
48 |
49 |
50 |
51 | ### Android
52 | To load media/subitle from an internet source, your app will need the `INTERNET` permission.
53 | This is done by ensuring your `/android/app/src/main/AndroidManifest.xml` file contains a `uses-permission`
54 | declaration for `android.permission.INTERNET`:
55 | ```xml
56 |
57 | ```
58 |
59 | As Flutter includes this permission by default, the permission is likely already declared in the file.
60 |
61 | Note that if you got "Cleartext HTTP traffic to * is not permitted"
62 | you need to add the `android:usesClearTextTraffic="true"` flag in the AndroidManifest.xml file, or define a new "Network Security Configuration" file. For more information, check https://developer.android.com/training/articles/security-config
63 |
64 |
65 |
66 | In order to load media/subtitle from internal device storage, you should put the storage permissions as follows:
67 | ```xml
68 |
69 |
70 | ```
71 | In some cases you also need to add the `android:requestLegacyExternalStorage="true"` flag to the Application tag in AndroidManifest.xml file to avoid acess denied errors. Android 10 apps can't acess storage without that flag. [reference](https://stackoverflow.com/a/60917774/14919621)
72 |
73 | After that you can access the media/subtitle file by
74 |
75 | "/storage/emulated/0/{FilePath}"
76 | "/sdcard/{FilePath}"
77 |
78 |
79 |
80 | #### Android build configuration
81 |
82 | 1. In `android/app/build.gradle`:
83 | ```groovy
84 | android {
85 | packagingOptions {
86 | // Fixes duplicate libraries build issue,
87 | // when your project uses more than one plugin that depend on C++ libs.
88 | pickFirst 'lib/**/libc++_shared.so'
89 | }
90 |
91 | buildTypes {
92 | release {
93 | minifyEnabled true
94 | proguardFiles getDefaultProguardFile(
95 | 'proguard-android-optimize.txt'),
96 | 'proguard-rules.pro'
97 | }
98 | }
99 | }
100 | ```
101 |
102 | 2. Create `android/app/proguard-rules.pro`, add the following lines:
103 | ```proguard
104 | -keep class org.videolan.libvlc.** { *; }
105 | ```
106 |
107 |
108 |
109 | ## Quick Start
110 | To start using the plugin, copy this code or follow the example project in 'flutter_vlc_player/example'
111 |
112 | ```dart
113 | import 'package:flutter/material.dart';
114 | import 'package:flutter_vlc_player/flutter_vlc_player.dart';
115 |
116 | void main() {
117 | runApp(MyApp());
118 | }
119 |
120 | class MyApp extends StatelessWidget {
121 | // This widget is the root of your application.
122 | @override
123 | Widget build(BuildContext context) {
124 | return MaterialApp(
125 | title: 'Flutter Demo',
126 | theme: ThemeData(
127 | visualDensity: VisualDensity.adaptivePlatformDensity,
128 | ),
129 | home: MyHomePage(),
130 | );
131 | }
132 | }
133 |
134 | class MyHomePage extends StatefulWidget {
135 | MyHomePage({Key key}) : super(key: key);
136 |
137 | @override
138 | _MyHomePageState createState() => _MyHomePageState();
139 | }
140 |
141 | class _MyHomePageState extends State {
142 | VlcPlayerController _videoPlayerController;
143 |
144 | @override
145 | void initState() {
146 | super.initState();
147 |
148 | _videoPlayerController = VlcPlayerController.network(
149 | 'https://media.w3.org/2010/05/sintel/trailer.mp4',
150 | hwAcc: HwAcc.full,
151 | autoPlay: false,
152 | options: VlcPlayerOptions(),
153 | );
154 | }
155 |
156 | @override
157 | void dispose() async {
158 | super.dispose();
159 | await _videoPlayerController.stopRendererScanning();
160 | await _videoPlayerController.dispose();
161 | }
162 |
163 | @override
164 | Widget build(BuildContext context) {
165 | return Scaffold(
166 | appBar: AppBar(),
167 | body: Center(
168 | child: VlcPlayer(
169 | controller: _videoPlayerController,
170 | aspectRatio: 16 / 9,
171 | placeholder: Center(child: CircularProgressIndicator()),
172 | ),
173 | ),
174 | );
175 | }
176 | }
177 | ```
178 |
179 |
180 | ### Recording feature
181 | To start/stop video recording, you have to call the `startRecording(String saveDirectory)` and `stopRecording()` methods, respectively. By calling the stop method you can get the path of recorded file from `vlcPlayerController.value.recordPath`.
182 |
183 |
184 |
185 | ## Upgrade instructions
186 |
187 | ### Version 5.0 Upgrade For Existing Apps
188 | To upgrade to version 5.0 first you need to migrate the existing project to swift.
189 |
190 | 1. Clean the repo:
191 |
192 | ```git clean -xdf```
193 |
194 | 2. Delete existing ios folder from root of flutter project. If you have some custom changes made to the iOS app - rename it or copy somewhere outside the project.
195 |
196 | 3. Re-create the iOS app: This command will create only ios directory with swift support. See https://stackoverflow.com/questions/52244346/how-to-enable-swift-support-for-existing-project-in-flutter
197 |
198 |
199 | ```flutter create -i swift .```
200 |
201 |
202 |
203 | 4. Make sure to update the project according to warnings shown by the flutter tools. (Update Info.plist, Podfile).
204 |
205 | If you have some changes made to the iOS app, recreate the app using above method and copy in the changed files.
206 |
207 | Be sure to follow instructions above after
208 |
209 |
210 |
211 | ### Breaking Changes (from V4 to V5)
212 | Entire platform has been refactored in v5. It will require a refactor of your app to follow v5.
213 |
214 |
215 |
216 | ## Known Issues
217 | 1) The video recording feature is problematic in iOS/Android: if the video reaches its end while you're recording it, the underlying `vlckit`/`libvlc` library fails to finalize the recording process, and we cannot retrieve the recorded file.
218 | The issue is reported and tracked here:
219 |
220 | [https://code.videolan.org/videolan/VLCKit/-/issues/394](https://code.videolan.org/videolan/VLCKit/-/issues/394) (see last comment from September 22, 2020)
221 |
222 |
223 |
224 | ## Current issues
225 | Current issues list [is here](https://github.com/solid-software/flutter_vlc_player/issues).
226 | Found a bug? [Open the issue](https://github.com/solid-software/flutter_vlc_player/issues/new).
227 |
--------------------------------------------------------------------------------
/flutter_vlc_player/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.lock
4 | *.log
5 | *.pyc
6 | *.swp
7 | .DS_Store
8 | .atom/
9 | .buildlog/
10 | .history
11 | .svn/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # Visual Studio Code related
20 | .classpath
21 | .project
22 | .settings/
23 | .vscode/
24 |
25 | # Flutter repo-specific
26 | /bin/cache/
27 | /bin/mingit/
28 | /dev/benchmarks/mega_gallery/
29 | /dev/bots/.recipe_deps
30 | /dev/bots/android_tools/
31 | /dev/docs/doc/
32 | /dev/docs/flutter.docs.zip
33 | /dev/docs/lib/
34 | /dev/docs/pubspec.yaml
35 | /dev/integration_tests/**/xcuserdata
36 | /dev/integration_tests/**/Pods
37 | /packages/flutter/coverage/
38 | version
39 |
40 | # packages file containing multi-root paths
41 | .packages.generated
42 |
43 | # Flutter/Dart/Pub related
44 | **/doc/api/
45 | .dart_tool/
46 | .flutter-plugins
47 | .flutter-plugins-dependencies
48 | .packages
49 | .pub-cache/
50 | .pub/
51 | build/
52 | flutter_*.png
53 | linked_*.ds
54 | unlinked.ds
55 | unlinked_spec.ds
56 |
57 | # Android related
58 | **/android/**/gradle-wrapper.jar
59 | **/android/.gradle
60 | **/android/captures/
61 | **/android/gradlew
62 | **/android/gradlew.bat
63 | **/android/local.properties
64 | **/android/**/GeneratedPluginRegistrant.java
65 | **/android/key.properties
66 | *.jks
67 |
68 | # iOS/XCode related
69 | **/ios/**/*.mode1v3
70 | **/ios/**/*.mode2v3
71 | **/ios/**/*.moved-aside
72 | **/ios/**/*.pbxuser
73 | **/ios/**/*.perspectivev3
74 | **/ios/**/*sync/
75 | **/ios/**/.sconsign.dblite
76 | **/ios/**/.tags*
77 | **/ios/**/.vagrant/
78 | **/ios/**/DerivedData/
79 | **/ios/**/Icon?
80 | **/ios/**/Pods/
81 | **/ios/**/.symlinks/
82 | **/ios/**/profile
83 | **/ios/**/xcuserdata
84 | **/ios/.generated/
85 | **/ios/Flutter/App.framework
86 | **/ios/Flutter/Flutter.framework
87 | **/ios/Flutter/Flutter.podspec
88 | **/ios/Flutter/Generated.xcconfig
89 | **/ios/Flutter/app.flx
90 | **/ios/Flutter/app.zip
91 | **/ios/Flutter/flutter_assets/
92 | **/ios/Flutter/flutter_export_environment.sh
93 | **/ios/ServiceDefinitions.json
94 | **/ios/Runner/GeneratedPluginRegistrant.*
95 |
96 | # macOS
97 | **/macos/Flutter/GeneratedPluginRegistrant.swift
98 | **/macos/Flutter/Flutter-Debug.xcconfig
99 | **/macos/Flutter/Flutter-Release.xcconfig
100 | **/macos/Flutter/Flutter-Profile.xcconfig
101 |
102 | # Temporary Files
103 | **/._*
104 |
105 | # Coverage
106 | coverage/
107 |
108 | # Symbols
109 | app.*.symbols
110 |
111 | # Exceptions to above rules.
112 | !**/ios/**/default.mode1v3
113 | !**/ios/**/default.mode2v3
114 | !**/ios/**/default.pbxuser
115 | !**/ios/**/default.perspectivev3
116 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
117 | !/dev/ci/**/Gemfile.lock
118 | /example/ios/Runner.xcodeproj/project.pbxproj
119 |
--------------------------------------------------------------------------------
/flutter_vlc_player/.metadata:
--------------------------------------------------------------------------------
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: 5391447fae6209bb21a89e6a5a6583cac1af9b4b
8 | channel: stable
9 |
10 | project_type: plugin
11 |
--------------------------------------------------------------------------------
/flutter_vlc_player/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 7.4.3
2 | * Bumped minimum Flutter SDK requirement to 3.22.0 and Dart SDK requirement to 3.4.0. The minimum supported Android version is now 5.0 (API level 21)
3 | * [Android] updated libvlc
4 | * [Android] set Java compatibility to 11 instead of 8
5 | * [ios] updated MobileVLCKit
6 | * updated exmaple
7 |
8 | ## 7.4.2
9 | * fixed getVolume #486
10 | Credits to pinpong (https://github.com/pinpong)
11 | * updated MobileVLCKit & libvlc
12 | Credits to pinpong (https://github.com/pinpong)
13 | * Fix: Unable to replay when status is stopped #449
14 | Credits to Virczz (https://github.com/Virczz)
15 |
16 | ## 7.4.1
17 | * Add support for Flutter 3.16
18 | Credits to thearaks (https://github.com/thearaks)
19 |
20 | ## 7.4.0
21 | * Important change: Removed [AutomaticKeepAliveClientMixin](https://api.flutter.dev/flutter/widgets/AutomaticKeepAliveClientMixin-mixin.html) from plugin widget
22 | * Mobile VLC update to 3.6.0-eap9
23 | * Allow background playback
24 | Credits to Oliver Nitzschke (https://github.com/pinpong)
25 | * fix instructions for proguard
26 | Credits to Luiz Fernando Baldo Marques (https://github.com/luizbaldo)
27 |
28 | ## 7.3.1
29 | * Restore Flutter 3.3-3.7 compatibility
30 | Credits to Yang Fang (https://github.com/yangsfang)
31 |
32 | ## 7.3.0
33 | * Fix http-user-agent & reuse options on iOS
34 | Credits to Afriza N. Arief (https://github.com/afriza)
35 | * Update to Dart 3 and Flutter 3.13
36 | Credits to romain.gyh (https://github.com/romaingyh)
37 |
38 | ## 7.2.0
39 | * Update to latest VLCKit sdks
40 | Credits to Mitch Ross (https://github.com/mitchross)
41 |
42 | ## 7.1.5
43 | * Fix plugin destructor (https://github.com/solid-software/flutter_vlc_player/issues/237)
44 |
45 | ## 7.1.4
46 | * Interim release to fix Flutter 3 issues
47 |
48 | ## 7.1.3
49 | * Added support for multi-window mode in Android.
50 | Credits to Andy Chentsov (https://github.com/andyduke).
51 |
52 | ## 7.1.2
53 | * Add Hybrid composition support for Android.
54 |
55 | ## 7.1.1
56 | * Fixed to work on Android 6-.
57 | Credits to Yury Kostov (https://github.com/kostov).
58 |
59 | ## 7.1.0
60 | * Upgrade iOS and Android Lib VLC libraries to address performance issues. https://code.videolan.org/videolan/vlc-ios/-/issues/1240
61 | Credits to Mitch Ross (https://github.com/mitchross)
62 |
63 | ## 7.0.1
64 | * Improve formatting
65 | * Modify LICENSE to use template so it parsed automatically.
66 |
67 | ## 7.0.0
68 | * **Breaking Change**: Refactored enum parameters to follow dart naming convention
69 | * Fixed control overlay issue after upgrading to Flutter 2.8
70 | * Fixed Dart analysis warnings
71 | * Removed unnecessary initialization delay
72 | Credits to Alireza Setayesh (https://github.com/alr2413), Mitch Ross (https://github.com/mitchross), Illia Romanenko (https://github.com/illia-romanenko) and Yurii Prykhodko (https://github.com/solid-yuriiprykhodko).
73 |
74 | ## 6.0.5
75 | * Fix issue with options applying (Android)
76 | * Update VLCKit for iOS and Android
77 | Credits to Vladislav Murashko (https://github.com/mrvancor).
78 |
79 | ## 6.0.4
80 | * Added VLC http options
81 | Credits to Alireza Setayesh (https://github.com/alr2413).
82 |
83 | ## 6.0.3
84 | * Added VLC recording feature
85 | Credits to Alireza Setayesh (https://github.com/alr2413).
86 |
87 | ## 6.0.2
88 | * Fix issue with VLC error event
89 | * Added onInit & onRenderer listeners
90 | Credits to Alireza Setayesh (https://github.com/alr2413) and solid-vovabeloded (https://github.com/solid-vovabeloded).
91 |
92 | ## 6.0.1
93 | * Fix issue with black screen / offstage
94 | Credits to Mitch Ross (https://github.com/mitchross)
95 |
96 | ## 6.0.0
97 | * Support Flutter V2 Null Safety
98 | Credits to Mitch Ross (https://github.com/mitchross)
99 |
100 | ## 5.0.5
101 | * Added VLC Subtitle Styling.
102 | * Split ios swift code into multiple files for better readability.
103 | Credits to Alireza Setayesh (https://github.com/alr2413) and Yurii Prykhodko (https://github.com/solid-yuriiprykhodko).
104 |
105 | ## 5.0.4
106 | * Added isSeekable method
107 | Credits to Alireza Setayesh (https://github.com/alr2413), Mitch Ross (https://github.com/mitchross).
108 |
109 | ## 5.0.3
110 | * Fix memory leak.
111 | Credits to Alireza Setayesh (https://github.com/alr2413), Mitch Ross (https://github.com/mitchross).
112 |
113 | ## 5.0.2
114 | * Fix homepage link.
115 |
116 | ## 5.0.1
117 | * Fix pub.dev image links.
118 |
119 | ## 5.0.0
120 | * Entire rewrite of Flutter VLC Player.
121 | * Updates to Android v2 plugin.
122 | * Adds Platform interface.
123 | * Adds Pigeon for type safe method calls.
124 | Credits to Alireza Setayesh (https://github.com/alr2413), Mitch Ross (https://github.com/mitchross) and Yurii Prykhodko (https://github.com/solid-yuriiprykhodko).
125 |
126 | ## 4.0.3
127 | * Update VLCKit for iOS and Android. Cleanup example Pod file. Clean up example gradle.
128 | * Removed dispose calls on VlcPlayerController from VlcPlayer.
129 | * Fix argument-less functions throwing FlutterMethodNotImplemented.
130 | Credits to Mitch Ross (https://github.com/mitchross).
131 |
132 | ## 4.0.2
133 | * Update Cocoapods version for VLCkit on iOS. This fixes issues with iOS 12 and Simulators.
134 | Credits to Mitch Ross (https://github.com/mitchross).
135 |
136 | ## 4.0.1
137 | * Improved documentation.
138 |
139 | ## 4.0.0
140 | * Improved structure (see example for breaking changes). Example code updated also.
141 | * Fix android black screen issue
142 | * Support playing local media/subtitle file
143 | * Support casting media to external device
144 | * Updated changing audio/subtitle method
145 | * Support audio/subtitle delay
146 | credits to Alireza Setayesh (https://github.com/alr2413) and Mitch Ross (https://github.com/mitchross)
147 |
148 | ## 3.0.7
149 | * Updates MobileVLC to allow for changing of subtitles and adding subtiles .
150 | credits to @rikaweb(https://github.com/rikaweb) and Mitch Ross (https://github.com/mitchross)
151 |
152 | ## 3.0.6
153 | * Updates MobileVLC to allow for handling of vlc error.
154 | credits to Alireza Setayesh (https://github.com/alr2413)
155 |
156 | ## 3.0.5
157 | * Updates MobileVLC to allow for changing of volume. Example Updated Also.
158 | credits to Mitch Ross (https://github.com/mitchross)
159 |
160 | ## 3.0.4
161 | * Updates MobileVLC to allow for options as flags and hardware acceleration/
162 | credits to pharshdev (https://github.com/pharshdev) and Mitch Ross (https://github.com/mitchross)
163 |
164 | ## 3.0.3
165 | * Updates MobileVLC to fix a bug on iOS with Seek Time. See (https://github.com/solid-software/flutter_vlc_player/issues/72). Also adds seek bar to example player for demonstration purposes.
166 | credits to Mitch Ross (https://github.com/mitchross)
167 |
168 | ## 3.0.2
169 | * Updates MobileVLC to fix a bug on iOS with HLS Streaming on VLCKit itself. See (https://code.videolan.org/videolan/VLCKit/-/issues/368),
170 | credits to Mitch Ross (https://github.com/mitchross)
171 |
172 | ## 3.0.1
173 | * Fix a bug on Android with URL parsing. See (https://github.com/solid-software/flutter_vlc_player/issues/52),
174 | credits to pharshdev (https://github.com/pharshdev) and Mitch Ross (https://github.com/mitchross)
175 |
176 | ## 3.0.0
177 | * Migrated to Swift, thanks to Mitch Ross (https://github.com/mitchross),
178 | Amadeu Cavalcante (https://github.com/amadeu01) and pharshdev (https://github.com/pharshdev).
179 |
180 | ## 2.0.0
181 | * Improved structure (see example for braking changes), add aspect ratio and payback controls
182 | support thanks to John Harker (https://github.com/NBTX) and Mitch Ross (https://github.com/mitchross).
183 |
184 | ## 1.0.0
185 | * Added multiple players support thanks to Kraig Spear (https://github.com/kraigspear)
186 |
187 | ## 0.0.2
188 | * Android X support added thanks to Javi Hurtado (https://github.com/ja2375)
189 |
190 | ## 0.0.1
191 |
192 | * initial flutter vlc plugin (not working with android x)
193 |
--------------------------------------------------------------------------------
/flutter_vlc_player/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2022, Solid Software LLC
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/flutter_vlc_player/README.md:
--------------------------------------------------------------------------------
1 | # VLC Player Plugin
2 | [](https://pub.dev/packages/solid_lints)
3 | [](https://nokycucwgzweensacwfy.supabase.co/functions/v1/get_project_url?projectId=148)
4 |
5 |
6 | A VLC-powered alternative to Flutter's video_player that supports iOS and Android.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ## Installation
17 |
18 | ### iOS
19 |
20 | If you're unable to view media loaded from an external source, you should also add the following:
21 | ```xml
22 | NSAppTransportSecurity
23 |
24 | NSAllowsArbitraryLoads
25 |
26 |
27 | ```
28 | For more information, or for more granular control over your App Transport Security (ATS) restrictions, you should
29 | [read Apple's documentation](https://developer.apple.com/documentation/bundleresources/information_property_list/nsapptransportsecurity/nsallowsarbitraryloads).
30 |
31 | Make sure that following line in `/ios/Podfile` uncommented:
32 |
33 | `platform :ios, '9.0'`
34 |
35 | > NOTE: While the Flutter `video_player` is not functional on iOS Simulators, this package (`flutter_vlc_player`) **is**
36 | > fully functional on iOS simulators.
37 |
38 | To enable vlc cast functionality for external displays (chromecast), you should also add the following:
39 |
40 | ```xml
41 | NSLocalNetworkUsageDescription
42 | Used to search for chromecast devices
43 | NSBonjourServices
44 |
45 | _googlecast._tcp
46 |
47 | ```
48 |
49 |
50 |
51 | ### Android
52 | To load media/subitle from an internet source, your app will need the `INTERNET` permission.
53 | This is done by ensuring your `/android/app/src/main/AndroidManifest.xml` file contains a `uses-permission`
54 | declaration for `android.permission.INTERNET`:
55 | ```xml
56 |
57 | ```
58 |
59 | As Flutter includes this permission by default, the permission is likely already declared in the file.
60 |
61 | Note that if you got "Cleartext HTTP traffic to * is not permitted"
62 | you need to add the `android:usesClearTextTraffic="true"` flag in the AndroidManifest.xml file, or define a new "Network Security Configuration" file. For more information, check https://developer.android.com/training/articles/security-config
63 |
64 |
65 |
66 | In order to load media/subtitle from internal device storage, you should put the storage permissions as follows:
67 | ```xml
68 |
69 |
70 | ```
71 | In some cases you also need to add the `android:requestLegacyExternalStorage="true"` flag to the Application tag in AndroidManifest.xml file.
72 |
73 | After that you can access the media/subtitle file by
74 |
75 | "/storage/emulated/0/{FilePath}"
76 | "/sdcard/{FilePath}"
77 |
78 |
79 |
80 | #### Android build configuration
81 |
82 | 1. In `android/app/build.gradle`:
83 | ```groovy
84 | android {
85 | packagingOptions {
86 | // Fixes duplicate libraries build issue,
87 | // when your project uses more than one plugin that depend on C++ libs.
88 | pickFirst 'lib/**/libc++_shared.so'
89 | }
90 |
91 | buildTypes {
92 | release {
93 | minifyEnabled true
94 | proguardFiles getDefaultProguardFile(
95 | 'proguard-android-optimize.txt'),
96 | 'proguard-rules.pro'
97 | }
98 | }
99 | }
100 | ```
101 |
102 | 2. Create `android/app/proguard-rules.pro`, add the following lines:
103 | ```proguard
104 | -keep class org.videolan.libvlc.** { *; }
105 | ```
106 |
107 |
108 | #### Android multi-window support
109 |
110 | To enable multi-window support in your Android application, you need to make changes to `AndroidManifest.xml`, add the `android:resizeableActivity` key for the main activity, as well as the `android.allow_multiple_resumed_activities` metadata for application:
111 | ```xml
112 |
113 |
114 |
116 | ...
117 |
118 | ...
119 |
122 |
123 |
124 | ```
125 |
126 |
127 |
128 | ## Quick Start
129 | To start using the plugin, copy this code or follow the example project in 'flutter_vlc_player/example'
130 |
131 | ```dart
132 | import 'package:flutter/material.dart';
133 | import 'package:flutter_vlc_player/vlc_player_flutter.dart';
134 |
135 | void main() {
136 | runApp(MyApp());
137 | }
138 |
139 | class MyApp extends StatelessWidget {
140 | // This widget is the root of your application.
141 | @override
142 | Widget build(BuildContext context) {
143 | return MaterialApp(
144 | title: 'Flutter Demo',
145 | theme: ThemeData(
146 | visualDensity: VisualDensity.adaptivePlatformDensity,
147 | ),
148 | home: MyHomePage(),
149 | );
150 | }
151 | }
152 |
153 | class MyHomePage extends StatefulWidget {
154 | MyHomePage({Key key}) : super(key: key);
155 |
156 | @override
157 | _MyHomePageState createState() => _MyHomePageState();
158 | }
159 |
160 | class _MyHomePageState extends State {
161 | VlcPlayerController _videoPlayerController;
162 |
163 | Future initializePlayer() async {}
164 |
165 | @override
166 | void initState() {
167 | super.initState();
168 |
169 | _videoPlayerController = VlcPlayerController.network(
170 | 'https://media.w3.org/2010/05/sintel/trailer.mp4',
171 | hwAcc: HwAcc.FULL,
172 | autoPlay: false,
173 | options: VlcPlayerOptions(),
174 | );
175 | }
176 |
177 | @override
178 | void dispose() async {
179 | super.dispose();
180 | await _videoPlayerController.stopRendererScanning();
181 | await _videoViewController.dispose();
182 | }
183 |
184 | @override
185 | Widget build(BuildContext context) {
186 | return Scaffold(
187 | appBar: AppBar(),
188 | body: Center(
189 | child: VlcPlayer(
190 | controller: _videoPlayerController,
191 | aspectRatio: 16 / 9,
192 | placeholder: Center(child: CircularProgressIndicator()),
193 | ),
194 | ));
195 | }
196 | }
197 |
198 | ```
199 |
200 |
201 |
202 | ### Recording feature
203 | To start/stop video recording, you have to call the `startRecording(String saveDirectory)` and `stopRecording()` methods, respectively. By calling the stop method you can get the path of recorded file from `vlcPlayerController.value.recordPath`.
204 |
205 |
206 |
207 | ## Upgrade instructions
208 |
209 | ### Version 5.0 Upgrade For Existing Apps
210 | To upgrade to version 5.0 first you need to migrate the existing project to swift.
211 |
212 | 1. Clean the repo:
213 |
214 | ```git clean -xdf```
215 |
216 | 2. Delete existing ios folder from root of flutter project. If you have some custom changes made to the iOS app - rename it or copy somewhere outside the project.
217 |
218 | 3. Re-create the iOS app: This command will create only ios directory with swift support. See https://stackoverflow.com/questions/52244346/how-to-enable-swift-support-for-existing-project-in-flutter
219 |
220 |
221 | ```flutter create -i swift .```
222 |
223 |
224 |
225 | 4. Make sure to update the project according to warnings shown by the flutter tools. (Update Info.plist, Podfile).
226 |
227 | If you have some changes made to the iOS app, recreate the app using above method and copy in the changed files.
228 |
229 | Be sure to follow instructions above after
230 |
231 |
232 |
233 | ### Breaking Changes (from V4 to V5)
234 | Entire platform has been refactored in v5. It will require a refactor of your app to follow v5.
235 |
236 |
237 |
238 | ## Known Issues
239 | 1) The video recording feature is problematic in iOS/Android: if the video reaches its end while you're recording it, the underlying `vlckit`/`libvlc` library fails to finalize the recording process, and we cannot retrieve the recorded file.
240 | The issue is reported and tracked here:
241 |
242 | [https://code.videolan.org/videolan/VLCKit/-/issues/394](https://code.videolan.org/videolan/VLCKit/-/issues/394) (see last comment from September 22, 2020)
243 |
244 |
245 |
246 | ## Current issues
247 | Current issues list [is here](https://github.com/solid-software/flutter_vlc_player/issues).
248 | Found a bug? [Open the issue](https://github.com/solid-software/flutter_vlc_player/issues/new).
249 |
--------------------------------------------------------------------------------
/flutter_vlc_player/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:solid_lints/analysis_options.yaml
2 |
3 | dart_code_metrics:
4 | metrics:
5 | cyclomatic-complexity: 30
6 |
7 | linter:
8 | rules:
9 | lines_longer_than_80_chars: false
10 | comment_references: false
11 | public_member_api_docs: false
12 | avoid_positional_boolean_parameters: false
13 |
--------------------------------------------------------------------------------
/flutter_vlc_player/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | /vlc-android
10 |
--------------------------------------------------------------------------------
/flutter_vlc_player/android/build.gradle:
--------------------------------------------------------------------------------
1 | group 'software.solid.fluttervlcplayer'
2 | version '1.0-SNAPSHOT'
3 |
4 | buildscript {
5 | ext.kotlin_version = "1.8.22"
6 | repositories {
7 | google()
8 | mavenCentral()
9 | }
10 |
11 | dependencies {
12 | classpath("com.android.tools.build:gradle:8.7.0")
13 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | mavenCentral()
21 | }
22 | }
23 |
24 | apply plugin: "com.android.library"
25 | apply plugin: "kotlin-android"
26 |
27 | android {
28 | namespace = "software.solid.fluttervlcplayer"
29 |
30 | compileSdk = 35
31 |
32 | compileOptions {
33 | sourceCompatibility = JavaVersion.VERSION_11
34 | targetCompatibility = JavaVersion.VERSION_11
35 | }
36 |
37 | kotlinOptions {
38 | jvmTarget = JavaVersion.VERSION_11
39 | }
40 |
41 | sourceSets {
42 | main.java.srcDirs += "src/main/kotlin"
43 | test.java.srcDirs += "src/test/kotlin"
44 | }
45 |
46 | defaultConfig {
47 | minSdk = 21
48 | }
49 |
50 | dependencies {
51 | testImplementation("org.jetbrains.kotlin:kotlin-test")
52 | testImplementation("org.mockito:mockito-core:5.0.0")
53 | implementation 'org.videolan.android:libvlc-all:3.6.0-eap14'
54 | implementation 'androidx.appcompat:appcompat:1.7.0'
55 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
56 | implementation 'androidx.annotation:annotation:1.9.1'
57 | }
58 |
59 | testOptions {
60 | unitTests.all {
61 | useJUnitPlatform()
62 |
63 | testLogging {
64 | events "passed", "skipped", "failed", "standardOut", "standardError"
65 | outputs.upToDateWhen { false }
66 | showStandardStreams = true
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/flutter_vlc_player/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'flutter_vlc_player'
2 |
--------------------------------------------------------------------------------
/flutter_vlc_player/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/flutter_vlc_player/android/src/main/java/software/solid/fluttervlcplayer/Enums/DataSourceType.java:
--------------------------------------------------------------------------------
1 | package software.solid.fluttervlcplayer.Enums;
2 |
3 | public enum DataSourceType {
4 | ASSET,
5 | NETWORK,
6 | FILE
7 | }
8 |
--------------------------------------------------------------------------------
/flutter_vlc_player/android/src/main/java/software/solid/fluttervlcplayer/Enums/HwAcc.java:
--------------------------------------------------------------------------------
1 | package software.solid.fluttervlcplayer.Enums;
2 |
3 | public enum HwAcc {
4 | AUTOMATIC,
5 | DISABLED,
6 | DECODING,
7 | FULL
8 | }
9 |
--------------------------------------------------------------------------------
/flutter_vlc_player/android/src/main/java/software/solid/fluttervlcplayer/FlutterVlcPlayerBuilder.java:
--------------------------------------------------------------------------------
1 | package software.solid.fluttervlcplayer;
2 |
3 | import android.content.Context;
4 | import android.util.LongSparseArray;
5 |
6 | import androidx.annotation.NonNull;
7 | import androidx.annotation.Nullable;
8 |
9 | import java.util.ArrayList;
10 | import java.util.HashMap;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | import io.flutter.plugin.common.BinaryMessenger;
15 | import io.flutter.view.TextureRegistry;
16 | import software.solid.fluttervlcplayer.Enums.DataSourceType;
17 | import software.solid.fluttervlcplayer.Enums.HwAcc;
18 |
19 | public class FlutterVlcPlayerBuilder implements Messages.VlcPlayerApi {
20 |
21 | private final LongSparseArray vlcPlayers = new LongSparseArray<>();
22 | private FlutterVlcPlayerFactory.KeyForAssetFn keyForAsset;
23 | private FlutterVlcPlayerFactory.KeyForAssetAndPackageName keyForAssetAndPackageName;
24 |
25 | void startListening(BinaryMessenger messenger) {
26 | Messages.VlcPlayerApi.setUp(messenger, this);
27 | }
28 |
29 | void stopListening(BinaryMessenger messenger) {
30 | // disposeAllPlayers();
31 | Messages.VlcPlayerApi.setUp(messenger, null);
32 | }
33 |
34 | FlutterVlcPlayer build(int viewId, Context context, BinaryMessenger binaryMessenger, TextureRegistry textureRegistry, FlutterVlcPlayerFactory.KeyForAssetFn keyForAsset, FlutterVlcPlayerFactory.KeyForAssetAndPackageName keyForAssetAndPackageName) {
35 | this.keyForAsset = keyForAsset;
36 | this.keyForAssetAndPackageName = keyForAssetAndPackageName;
37 | // only create view for player and attach channel events
38 | FlutterVlcPlayer vlcPlayer = new FlutterVlcPlayer(viewId, context, binaryMessenger, textureRegistry);
39 | vlcPlayers.append(viewId, vlcPlayer);
40 | return vlcPlayer;
41 | }
42 |
43 | private void disposeAllPlayers() {
44 | for (int i = 0; i < vlcPlayers.size(); i++) {
45 | vlcPlayers.valueAt(i).dispose();
46 | }
47 | vlcPlayers.clear();
48 | }
49 |
50 | private FlutterVlcPlayer getPlayer(@NonNull Long playerId) {
51 | if (vlcPlayers.get(playerId) == null) {
52 | throw new Messages.FlutterError("player_not_found", "Player with id " + playerId + " not found", null);
53 | }
54 |
55 | return vlcPlayers.get(playerId);
56 | }
57 |
58 | @Override
59 | public void initialize() {
60 | // disposeAllPlayers();
61 | }
62 |
63 | @Override
64 | public void create(@NonNull Messages.CreateMessage arg) {
65 | FlutterVlcPlayer player = getPlayer(arg.getPlayerId());
66 |
67 | ArrayList options = new ArrayList<>();
68 | if (!arg.getOptions().isEmpty())
69 | options.addAll(arg.getOptions());
70 | player.initialize(options);
71 |
72 | var mediaMessage = new Messages.SetMediaMessage();
73 | mediaMessage.setPlayerId(arg.getPlayerId());
74 | mediaMessage.setUri(arg.getUri());
75 | mediaMessage.setType(arg.getType());
76 | mediaMessage.setAutoPlay(arg.getAutoPlay());
77 | mediaMessage.setHwAcc(arg.getHwAcc());
78 | mediaMessage.setPackageName(arg.getPackageName());
79 |
80 | setStreamUrl(mediaMessage);
81 | }
82 |
83 | @Override
84 | public void dispose(@NonNull Long playerId) {
85 | FlutterVlcPlayer player = getPlayer(playerId);
86 | player.dispose();
87 | vlcPlayers.remove(playerId);
88 | }
89 |
90 | @Override
91 | public void setStreamUrl(@NonNull Messages.SetMediaMessage arg) {
92 | var player = getPlayer(arg.getPlayerId());
93 |
94 | String mediaUrl;
95 | boolean isAssetUrl;
96 | if (arg.getType() == DataSourceType.ASSET.ordinal()) {
97 | String assetLookupKey;
98 | if (arg.getPackageName() != null)
99 | assetLookupKey = keyForAssetAndPackageName.get(arg.getUri(), arg.getPackageName());
100 | else
101 | assetLookupKey = keyForAsset.get(arg.getUri());
102 | mediaUrl = assetLookupKey;
103 | isAssetUrl = true;
104 | } else {
105 | mediaUrl = arg.getUri();
106 | isAssetUrl = false;
107 | }
108 |
109 | if (arg.getHwAcc() == null) {
110 | arg.setHwAcc((long) HwAcc.AUTOMATIC.ordinal());
111 | }
112 |
113 | player.setStreamUrl(mediaUrl, isAssetUrl, arg.getAutoPlay(), arg.getHwAcc());
114 | }
115 |
116 | @Override
117 | public void play(@NonNull Long playerId) {
118 | var player = getPlayer(playerId);
119 | player.play();
120 | }
121 |
122 | @Override
123 | public void pause(@NonNull Long playerId) {
124 | var player = getPlayer(playerId);
125 | player.pause();
126 | }
127 |
128 | @Override
129 | public void stop(@NonNull Long playerId) {
130 | var player = getPlayer(playerId);
131 | player.stop();
132 | }
133 |
134 | @NonNull
135 | @Override
136 | public Boolean isPlaying(@NonNull Long playerId) {
137 | return getPlayer(playerId).isPlaying();
138 | }
139 |
140 | @NonNull
141 | @Override
142 | public Boolean isSeekable(@NonNull Long playerId) {
143 | return getPlayer(playerId).isSeekable();
144 | }
145 |
146 | @Override
147 | public void setLooping(@NonNull Long playerId, @NonNull Boolean isLooping) {
148 | var player = getPlayer(playerId);
149 | player.setLooping(isLooping);
150 | }
151 |
152 | @Override
153 | public void seekTo(@NonNull Long playerId, @NonNull Long position) {
154 | var player = getPlayer(playerId);
155 | player.seekTo(position);
156 | }
157 |
158 | @NonNull
159 | @Override
160 | public Long position(@NonNull Long playerId) {
161 | return getPlayer(playerId).getPosition();
162 | }
163 |
164 | @NonNull
165 | @Override
166 | public Long duration(@NonNull Long playerId) {
167 | return getPlayer(playerId).getDuration();
168 | }
169 |
170 | @NonNull
171 | @Override
172 | public Long getVolume(@NonNull Long playerId) {
173 | return (long) getPlayer(playerId).getVolume();
174 | }
175 |
176 | @Override
177 | public void setVolume(@NonNull Long playerId, @NonNull Long volume) {
178 | var player = getPlayer(playerId);
179 | player.setVolume(volume.intValue());
180 | }
181 |
182 | @Override
183 | public void setPlaybackSpeed(@NonNull Long playerId, @NonNull Double speed) {
184 | var player = getPlayer(playerId);
185 | player.setPlaybackSpeed(speed);
186 | }
187 |
188 | @NonNull
189 | @Override
190 | public Double getPlaybackSpeed(@NonNull Long playerId) {
191 | return (double) getPlayer(playerId).getPlaybackSpeed();
192 | }
193 |
194 | @Nullable
195 | @Override
196 | public String takeSnapshot(@NonNull Long playerId) {
197 | return getPlayer(playerId).getSnapshot();
198 | }
199 |
200 | // Subtitles
201 |
202 | @NonNull
203 | @Override
204 | public Long getSpuTracksCount(@NonNull Long playerId) {
205 | return (long) getPlayer(playerId).getSpuTracksCount();
206 | }
207 |
208 | @NonNull
209 | @Override
210 | public Map getSpuTracks(@NonNull Long playerId) {
211 | Map tracks = getPlayer(playerId).getSpuTracks();
212 |
213 | Map convertedTracks = new HashMap<>();
214 | for (Map.Entry entry : tracks.entrySet()) {
215 | convertedTracks.put(entry.getKey().longValue(), entry.getValue());
216 | }
217 |
218 | return convertedTracks;
219 | }
220 |
221 | @NonNull
222 | @Override
223 | public Long getSpuTrack(@NonNull Long playerId) {
224 | return (long) getPlayer(playerId).getSpuTrack();
225 | }
226 |
227 | @Override
228 | public void setSpuTrack(@NonNull Long playerId, @NonNull Long spuTrackNumber) {
229 | var player = getPlayer(playerId);
230 | player.setSpuTrack(spuTrackNumber.intValue());
231 | }
232 |
233 | @Override
234 | public void setSpuDelay(@NonNull Long playerId, @NonNull Long delay) {
235 | var player = getPlayer(playerId);
236 | player.setSpuDelay(delay.intValue());
237 | }
238 |
239 | @NonNull
240 | @Override
241 | public Long getSpuDelay(@NonNull Long playerId) {
242 | return getPlayer(playerId).getSpuDelay();
243 | }
244 |
245 | @Override
246 | public void addSubtitleTrack(Messages.AddSubtitleMessage arg) {
247 | var player = getPlayer(arg.getPlayerId());
248 | player.addSubtitleTrack(arg.getUri(), arg.getIsSelected());
249 | }
250 |
251 | // Audio tracks
252 |
253 | @NonNull
254 | @Override
255 | public Long getAudioTracksCount(@NonNull Long playerId) {
256 | return (long) getPlayer(playerId).getAudioTracksCount();
257 | }
258 |
259 | @NonNull
260 | @Override
261 | public Map getAudioTracks(@NonNull Long playerId) {
262 | Map tracks = getPlayer(playerId).getAudioTracks();
263 |
264 | Map convertedTracks = new HashMap<>();
265 | for (Map.Entry entry : tracks.entrySet()) {
266 | convertedTracks.put(entry.getKey().longValue(), entry.getValue());
267 | }
268 |
269 | return convertedTracks;
270 | }
271 |
272 | @Override
273 | public void setAudioTrack(@NonNull Long playerId, @NonNull Long audioTrackNumber) {
274 | var player = getPlayer(playerId);
275 | player.setAudioTrack(audioTrackNumber.intValue());
276 | }
277 |
278 | @NonNull
279 | @Override
280 | public Long getAudioTrack(@NonNull Long playerId) {
281 | return (long) getPlayer(playerId).getAudioTrack();
282 | }
283 |
284 | @Override
285 | public void setAudioDelay(@NonNull Long playerId, @NonNull Long delay) {
286 | var player = getPlayer(playerId);
287 | player.setAudioDelay(delay);
288 | }
289 |
290 | @NonNull
291 | @Override
292 | public Long getAudioDelay(@NonNull Long playerId) {
293 | return getPlayer(playerId).getAudioDelay();
294 | }
295 |
296 | @Override
297 | public void addAudioTrack(Messages.AddAudioMessage arg) {
298 | var player = getPlayer(arg.getPlayerId());
299 | player.addAudioTrack(arg.getUri(), arg.getIsSelected());
300 | }
301 |
302 | // Video tracks
303 |
304 |
305 | @NonNull
306 | @Override
307 | public Long getVideoTracksCount(@NonNull Long playerId) {
308 | return (long) getPlayer(playerId).getVideoTracksCount();
309 | }
310 |
311 | @NonNull
312 | @Override
313 | public Map getVideoTracks(@NonNull Long playerId) {
314 | Map tracks = getPlayer(playerId).getVideoTracks();
315 |
316 | Map convertedTracks = new HashMap<>();
317 | for (Map.Entry entry : tracks.entrySet()) {
318 | convertedTracks.put(entry.getKey().longValue(), entry.getValue());
319 | }
320 |
321 | return convertedTracks;
322 | }
323 |
324 | @Override
325 | public void setVideoTrack(@NonNull Long playerId, @NonNull Long videoTrackNumber) {
326 | var player = getPlayer(playerId);
327 | player.setVideoTrack(videoTrackNumber.intValue());
328 | }
329 |
330 | @NonNull
331 | @Override
332 | public Long getVideoTrack(@NonNull Long playerId) {
333 | return (long) getPlayer(playerId).getVideoTrack();
334 | }
335 |
336 | // Video properties
337 |
338 |
339 | @Override
340 | public void setVideoScale(@NonNull Long playerId, @NonNull Double scale) {
341 | var player = getPlayer(playerId);
342 | player.setVideoScale(scale.floatValue());
343 | }
344 |
345 | @NonNull
346 | @Override
347 | public Double getVideoScale(@NonNull Long playerId) {
348 | return (double) getPlayer(playerId).getVideoScale();
349 | }
350 |
351 | @Override
352 | public void setVideoAspectRatio(@NonNull Long playerId, @NonNull String aspectRatio) {
353 | var player = getPlayer(playerId);
354 | player.setVideoAspectRatio(aspectRatio);
355 | }
356 |
357 | @NonNull
358 | @Override
359 | public String getVideoAspectRatio(@NonNull Long playerId) {
360 | return getPlayer(playerId).getVideoAspectRatio();
361 | }
362 |
363 | // Cast
364 |
365 |
366 | @NonNull
367 | @Override
368 | public List getAvailableRendererServices(@NonNull Long playerId) {
369 | return getPlayer(playerId).getAvailableRendererServices();
370 | }
371 |
372 | @Override
373 | public void startRendererScanning(@NonNull Long playerId, @NonNull String rendererService) {
374 | var player = getPlayer(playerId);
375 | player.startRendererScanning(rendererService);
376 | }
377 |
378 | @Override
379 | public void stopRendererScanning(@NonNull Long playerId) {
380 | var player = getPlayer(playerId);
381 | player.stopRendererScanning();
382 | }
383 |
384 | @NonNull
385 | @Override
386 | public Map getRendererDevices(@NonNull Long playerId) {
387 | return getPlayer(playerId).getRendererDevices();
388 | }
389 |
390 | @Override
391 | public void castToRenderer(@NonNull Long playerId, @NonNull String rendererId) {
392 | var player = getPlayer(playerId);
393 | player.castToRenderer(rendererId);
394 | }
395 |
396 | // Recording
397 |
398 |
399 | @NonNull
400 | @Override
401 | public Boolean startRecording(@NonNull Long playerId, @NonNull String saveDirectory) {
402 | var player = getPlayer(playerId);
403 | return player.startRecording(saveDirectory);
404 | }
405 |
406 | @NonNull
407 | @Override
408 | public Boolean stopRecording(@NonNull Long playerId) {
409 | var player = getPlayer(playerId);
410 | return player.stopRecording();
411 | }
412 | }
413 |
--------------------------------------------------------------------------------
/flutter_vlc_player/android/src/main/java/software/solid/fluttervlcplayer/FlutterVlcPlayerFactory.java:
--------------------------------------------------------------------------------
1 | package software.solid.fluttervlcplayer;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.annotation.NonNull;
6 |
7 | import io.flutter.plugin.common.BinaryMessenger;
8 | import io.flutter.plugin.common.StandardMessageCodec;
9 | import io.flutter.plugin.platform.PlatformView;
10 | import io.flutter.plugin.platform.PlatformViewFactory;
11 | import io.flutter.view.TextureRegistry;
12 |
13 | public class FlutterVlcPlayerFactory extends PlatformViewFactory {
14 |
15 | public interface KeyForAssetFn {
16 | String get(String asset);
17 | }
18 |
19 | public interface KeyForAssetAndPackageName {
20 | String get(String asset, String packageName);
21 | }
22 |
23 | private final BinaryMessenger messenger;
24 | private final TextureRegistry textureRegistry;
25 | private final KeyForAssetFn keyForAsset;
26 | private final KeyForAssetAndPackageName keyForAssetAndPackageName;
27 | //
28 | private final FlutterVlcPlayerBuilder flutterVlcPlayerBuilder;
29 |
30 | public FlutterVlcPlayerFactory(BinaryMessenger messenger, TextureRegistry textureRegistry, KeyForAssetFn keyForAsset, KeyForAssetAndPackageName keyForAssetAndPackageName) {
31 | super(StandardMessageCodec.INSTANCE);
32 | this.messenger = messenger;
33 | this.textureRegistry = textureRegistry;
34 | this.keyForAsset = keyForAsset;
35 | this.keyForAssetAndPackageName = keyForAssetAndPackageName;
36 | //
37 | flutterVlcPlayerBuilder = new FlutterVlcPlayerBuilder();
38 | }
39 |
40 | @NonNull
41 | @Override
42 | public PlatformView create(Context context, int viewId, Object args) {
43 | // Map params = (Map) args;
44 | return flutterVlcPlayerBuilder.build(viewId, context, messenger, textureRegistry, keyForAsset, keyForAssetAndPackageName);
45 | }
46 |
47 | public void startListening() {
48 | flutterVlcPlayerBuilder.startListening(messenger);
49 | }
50 |
51 | public void stopListening() {
52 | flutterVlcPlayerBuilder.stopListening(messenger);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/flutter_vlc_player/android/src/main/java/software/solid/fluttervlcplayer/FlutterVlcPlayerPlugin.java:
--------------------------------------------------------------------------------
1 | package software.solid.fluttervlcplayer;
2 |
3 | import android.os.Build;
4 |
5 | import androidx.annotation.NonNull;
6 | import androidx.annotation.RequiresApi;
7 |
8 | import io.flutter.FlutterInjector;
9 | import io.flutter.embedding.engine.plugins.FlutterPlugin;
10 | import io.flutter.embedding.engine.plugins.activity.ActivityAware;
11 | import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
12 |
13 | public class FlutterVlcPlayerPlugin implements FlutterPlugin, ActivityAware {
14 |
15 | private static FlutterVlcPlayerFactory flutterVlcPlayerFactory;
16 | private FlutterPluginBinding flutterPluginBinding;
17 |
18 | private static final String VIEW_TYPE = "flutter_video_plugin/getVideoView";
19 |
20 | public FlutterVlcPlayerPlugin() {
21 | }
22 |
23 | @Override
24 | public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
25 | flutterPluginBinding = binding;
26 |
27 | //
28 | if (flutterVlcPlayerFactory == null) {
29 | final FlutterInjector injector = FlutterInjector.instance();
30 | //
31 | flutterVlcPlayerFactory =
32 | new FlutterVlcPlayerFactory(
33 | flutterPluginBinding.getBinaryMessenger(),
34 | flutterPluginBinding.getTextureRegistry(),
35 | injector.flutterLoader()::getLookupKeyForAsset,
36 | injector.flutterLoader()::getLookupKeyForAsset
37 | );
38 | flutterPluginBinding
39 | .getPlatformViewRegistry()
40 | .registerViewFactory(
41 | VIEW_TYPE,
42 | flutterVlcPlayerFactory
43 | );
44 | //
45 | }
46 | startListening();
47 | }
48 |
49 | @Override
50 | public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
51 | stopListening();
52 | //
53 |
54 | flutterPluginBinding = null;
55 | }
56 |
57 | @RequiresApi(api = Build.VERSION_CODES.N)
58 | @Override
59 | public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
60 | }
61 |
62 | @Override
63 | public void onDetachedFromActivityForConfigChanges() {
64 | }
65 |
66 | @RequiresApi(api = Build.VERSION_CODES.N)
67 | @Override
68 | public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
69 | }
70 |
71 | @Override
72 | public void onDetachedFromActivity() {
73 | }
74 |
75 | // extra methods
76 |
77 | private static void startListening() {
78 | if (flutterVlcPlayerFactory != null)
79 | flutterVlcPlayerFactory.startListening();
80 | }
81 |
82 | private static void stopListening() {
83 | if (flutterVlcPlayerFactory != null) {
84 | flutterVlcPlayerFactory.stopListening();
85 | flutterVlcPlayerFactory = null;
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/flutter_vlc_player/android/src/main/java/software/solid/fluttervlcplayer/QueuingEventSink.java:
--------------------------------------------------------------------------------
1 | package software.solid.fluttervlcplayer;
2 |
3 | import java.util.ArrayList;
4 |
5 | import io.flutter.plugin.common.EventChannel;
6 |
7 | /**
8 | * And implementation of {@link EventChannel.EventSink} which can wrap an underlying sink.
9 | *
10 | *
It delivers messages immediately when downstream is available, but it queues messages before
11 | * the delegate event sink is set with setDelegate.
12 | *
13 | *
This class is not thread-safe. All calls must be done on the same thread or synchronized
14 | * externally.
15 | */
16 | final class QueuingEventSink implements EventChannel.EventSink {
17 | private EventChannel.EventSink delegate;
18 | private final ArrayList