├── .github └── workflows │ ├── code_check_for_flutter_vlc_player.yaml │ └── code_check_for_flutter_vlc_player_platform_interface.yaml ├── .gitignore ├── README.md ├── flutter_vlc_player ├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── build.gradle │ ├── settings.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── software │ │ └── solid │ │ └── fluttervlcplayer │ │ ├── Enums │ │ ├── DataSourceType.java │ │ └── HwAcc.java │ │ ├── FlutterVlcPlayer.java │ │ ├── FlutterVlcPlayerBuilder.java │ │ ├── FlutterVlcPlayerFactory.java │ │ ├── FlutterVlcPlayerPlugin.java │ │ ├── Messages.java │ │ ├── QueuingEventSink.java │ │ └── VLCTextureView.java ├── doc │ ├── multiple.jpg │ └── single.jpg ├── example │ ├── .gitignore │ ├── .metadata │ ├── README.md │ ├── android │ │ ├── .gitignore │ │ ├── app │ │ │ ├── build.gradle.kts │ │ │ └── src │ │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ │ ├── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── kotlin │ │ │ │ │ └── software │ │ │ │ │ │ └── solid │ │ │ │ │ │ └── example │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── res │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── values-night │ │ │ │ │ └── styles.xml │ │ │ │ │ └── values │ │ │ │ │ └── styles.xml │ │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ ├── build.gradle.kts │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ └── gradle-wrapper.properties │ │ └── settings.gradle.kts │ ├── assets │ │ └── sample.mp4 │ ├── ios │ │ ├── .gitignore │ │ ├── Flutter │ │ │ ├── .last_build_id │ │ │ ├── AppFrameworkInfo.plist │ │ │ ├── Debug.xcconfig │ │ │ └── Release.xcconfig │ │ ├── Podfile │ │ ├── Runner.xcodeproj │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata │ │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ │ └── WorkspaceSettings.xcsettings │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ ├── Runner.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── Runner │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ │ └── LaunchImage.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ └── README.md │ │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ │ ├── Info.plist │ │ │ └── Runner-Bridging-Header.h │ ├── lib │ │ ├── app.dart │ │ ├── controls_overlay.dart │ │ ├── main.dart │ │ ├── multiple_tab.dart │ │ ├── single_tab.dart │ │ ├── video_data.dart │ │ └── vlc_player_with_controls.dart │ ├── pubspec.yaml │ └── test │ │ └── widget_test.dart ├── ios │ ├── .gitignore │ ├── Assets │ │ └── .gitkeep │ ├── Classes │ │ ├── FlutterVlcPlayerPlugin.h │ │ ├── FlutterVlcPlayerPlugin.m │ │ ├── Messages.swift │ │ ├── SwiftFlutterVlcPlayerPlugin.swift │ │ ├── VlcViewBuilder.swift │ │ ├── VlcViewController.swift │ │ └── VlcViewFactory.swift │ └── flutter_vlc_player.podspec ├── lib │ ├── flutter_vlc_player.dart │ └── src │ │ ├── enums │ │ └── playing_state.dart │ │ ├── flutter_vlc_player.dart │ │ ├── vlc_app_life_cycle_observer.dart │ │ ├── vlc_player_controller.dart │ │ ├── vlc_player_platform.dart │ │ └── vlc_player_value.dart ├── pigeons │ └── messages.dart └── pubspec.yaml └── flutter_vlc_player_platform_interface ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── lib ├── flutter_vlc_player_platform_interface.dart └── src │ ├── enums │ ├── data_source_type.dart │ ├── hardware_acceleration.dart │ ├── media_event_type.dart │ ├── renderer_event_type.dart │ └── subtitles │ │ └── vlc_subtitle_text_direction.dart │ ├── events │ ├── media_event.dart │ └── renderer_event.dart │ ├── messages │ └── messages.dart │ ├── method_channel │ └── method_channel_vlc_player.dart │ ├── platform_interface │ └── vlc_player_platform_interface.dart │ └── utils │ ├── helpers │ └── subtitles │ │ ├── vlc_subtitle_color.dart │ │ └── vlc_subtitle_thickness.dart │ └── options │ ├── vlc_advanced_options.dart │ ├── vlc_audio_options.dart │ ├── vlc_http_options.dart │ ├── vlc_player_options.dart │ ├── vlc_rtp_options.dart │ ├── vlc_stream_output_options.dart │ ├── vlc_subtitle_options.dart │ └── vlc_video_options.dart └── pubspec.yaml /.github/workflows/code_check_for_flutter_vlc_player.yaml: -------------------------------------------------------------------------------- 1 | name: Library ON Push & PR DO Code check 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | code-check: 6 | runs-on: ubuntu-latest 7 | 8 | steps: 9 | - uses: actions/checkout@v1 10 | 11 | - name: Setup flutter 12 | uses: subosito/flutter-action@v2 13 | with: 14 | channel: 'stable' 15 | 16 | - name: Check flutter sdk version 17 | run: flutter --version 18 | 19 | - name: Get dependencies 20 | working-directory: ./flutter_vlc_player 21 | run: flutter pub get 22 | 23 | - name: Run Solid Lints 24 | working-directory: ./flutter_vlc_player 25 | run: dart analyze 26 | 27 | - name: Check formatting 28 | working-directory: ./flutter_vlc_player 29 | run: dart format . --set-exit-if-changed 30 | 31 | - name: Run tests 32 | run: | 33 | # run tests if `test` folder exists 34 | if [ -d test ] 35 | then 36 | flutter test -r expanded 37 | else 38 | echo "Tests not found." 39 | fi 40 | -------------------------------------------------------------------------------- /.github/workflows/code_check_for_flutter_vlc_player_platform_interface.yaml: -------------------------------------------------------------------------------- 1 | name: Interface ON Push & PR DO Code check 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | code-check: 6 | runs-on: ubuntu-latest 7 | 8 | steps: 9 | - uses: actions/checkout@v1 10 | 11 | - name: Setup flutter 12 | uses: subosito/flutter-action@v2 13 | with: 14 | channel: 'stable' 15 | 16 | - name: Check flutter sdk version 17 | working-directory: ./flutter_vlc_player_platform_interface 18 | run: flutter --version 19 | 20 | - name: Get dependencies 21 | working-directory: ./flutter_vlc_player_platform_interface 22 | run: flutter pub get 23 | 24 | - name: Run Solid Lints 25 | working-directory: ./flutter_vlc_player_platform_interface 26 | run: dart analyze 27 | 28 | - name: Check formatting 29 | working-directory: ./flutter_vlc_player_platform_interface 30 | run: dart format . --set-exit-if-changed 31 | 32 | - name: Run tests 33 | working-directory: ./flutter_vlc_player_platform_interface 34 | run: | 35 | # run tests if `test` folder exists 36 | if [ -d test ] 37 | then 38 | flutter test -r expanded 39 | else 40 | echo "Tests not found." 41 | fi 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter VLC Player Plugin 2 | [![Join the chat at https://discord.gg/mNY4fjVk](https://img.shields.io/discord/716939396464508958?label=discord)](https://discord.gg/mNY4fjVk) 3 | [![Support me on Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dsolidsoftwarehq%26type%3Dpatrons&style=flat)](https://patreon.com/solidsoftwarehq) 4 | [![flutter_vlc_player](https://nokycucwgzweensacwfy.supabase.co/functions/v1/get_project_badge?projectId=148)](https://nokycucwgzweensacwfy.supabase.co/functions/v1/get_project_url?projectId=148) 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 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 | [![style: solid](https://img.shields.io/badge/style-solid-orange)](https://pub.dev/packages/solid_lints) 3 | [![flutter_vlc_player](https://nokycucwgzweensacwfy.supabase.co/functions/v1/get_project_badge?projectId=148)](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 eventQueue = new ArrayList<>(); 19 | private boolean done = false; 20 | 21 | public void setDelegate(EventChannel.EventSink delegate) { 22 | this.delegate = delegate; 23 | maybeFlush(); 24 | } 25 | 26 | @Override 27 | public void endOfStream() { 28 | enqueue(new EndOfStreamEvent()); 29 | maybeFlush(); 30 | done = true; 31 | } 32 | 33 | @Override 34 | public void error(String code, String message, Object details) { 35 | enqueue(new ErrorEvent(code, message, details)); 36 | maybeFlush(); 37 | } 38 | 39 | @Override 40 | public void success(Object event) { 41 | enqueue(event); 42 | maybeFlush(); 43 | } 44 | 45 | private void enqueue(Object event) { 46 | if (done) { 47 | return; 48 | } 49 | eventQueue.add(event); 50 | } 51 | 52 | private void maybeFlush() { 53 | if (delegate == null) { 54 | return; 55 | } 56 | for (Object event : eventQueue) { 57 | if (event instanceof EndOfStreamEvent) { 58 | delegate.endOfStream(); 59 | } else if (event instanceof ErrorEvent) { 60 | ErrorEvent errorEvent = (ErrorEvent) event; 61 | delegate.error(errorEvent.code, errorEvent.message, errorEvent.details); 62 | } else { 63 | delegate.success(event); 64 | } 65 | } 66 | eventQueue.clear(); 67 | } 68 | 69 | private static class EndOfStreamEvent { 70 | } 71 | 72 | private static class ErrorEvent { 73 | String code; 74 | String message; 75 | Object details; 76 | 77 | ErrorEvent(String code, String message, Object details) { 78 | this.code = code; 79 | this.message = message; 80 | this.details = details; 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /flutter_vlc_player/android/src/main/java/software/solid/fluttervlcplayer/VLCTextureView.java: -------------------------------------------------------------------------------- 1 | package software.solid.fluttervlcplayer; 2 | 3 | import android.content.Context; 4 | import android.graphics.SurfaceTexture; 5 | import android.os.Handler; 6 | import android.os.Looper; 7 | import android.util.AttributeSet; 8 | import android.view.TextureView; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | 12 | import androidx.annotation.NonNull; 13 | 14 | import org.videolan.libvlc.MediaPlayer; 15 | import org.videolan.libvlc.interfaces.IVLCVout; 16 | 17 | import io.flutter.view.TextureRegistry; 18 | 19 | public class VLCTextureView extends TextureView implements TextureView.SurfaceTextureListener, View.OnLayoutChangeListener, IVLCVout.OnNewVideoLayoutListener { 20 | 21 | private MediaPlayer mMediaPlayer = null; 22 | private TextureRegistry.SurfaceTextureEntry mTextureEntry = null; 23 | protected Context mContext; 24 | private SurfaceTexture mSurfaceTexture = null; 25 | private boolean wasPlaying = false; 26 | 27 | private Handler mHandler; 28 | private Runnable mLayoutChangeRunnable = null; 29 | 30 | public VLCTextureView(final Context context) { 31 | super(context); 32 | mContext = context; 33 | initVideoView(); 34 | } 35 | 36 | public VLCTextureView(final Context context, final AttributeSet attrs) { 37 | super(context, attrs); 38 | mContext = context; 39 | initVideoView(); 40 | } 41 | 42 | public VLCTextureView(Context context, AttributeSet attrs, int defStyle) { 43 | super(context, attrs, defStyle); 44 | mContext = context; 45 | initVideoView(); 46 | } 47 | 48 | public void dispose() { 49 | setSurfaceTextureListener(null); 50 | removeOnLayoutChangeListener(this); 51 | 52 | if (mLayoutChangeRunnable != null) { 53 | mHandler.removeCallbacks(mLayoutChangeRunnable); 54 | mLayoutChangeRunnable = null; 55 | } 56 | 57 | if (mSurfaceTexture != null) { 58 | if (!mSurfaceTexture.isReleased()) { 59 | mSurfaceTexture.release(); 60 | } 61 | mSurfaceTexture = null; 62 | } 63 | mTextureEntry = null; 64 | mMediaPlayer = null; 65 | mContext = null; 66 | } 67 | 68 | private void initVideoView() { 69 | mHandler = new Handler(Looper.getMainLooper()); 70 | 71 | setFocusable(false); 72 | setSurfaceTextureListener(this); 73 | addOnLayoutChangeListener(this); 74 | } 75 | 76 | public void setMediaPlayer(MediaPlayer mediaPlayer) { 77 | if (mediaPlayer == null) { 78 | mMediaPlayer.getVLCVout().detachViews(); 79 | } 80 | 81 | mMediaPlayer = mediaPlayer; 82 | 83 | if (mMediaPlayer != null) { 84 | mMediaPlayer.getVLCVout().attachViews(this); 85 | } 86 | } 87 | 88 | public void setTextureEntry(TextureRegistry.SurfaceTextureEntry textureEntry) { 89 | this.mTextureEntry = textureEntry; 90 | this.updateSurfaceTexture(); 91 | } 92 | 93 | private void updateSurfaceTexture() { 94 | if (this.mTextureEntry != null) { 95 | final SurfaceTexture texture = this.mTextureEntry.surfaceTexture(); 96 | if (!texture.isReleased() && (getSurfaceTexture() != texture)) { 97 | setSurfaceTexture(texture); 98 | } 99 | } 100 | } 101 | 102 | @Override 103 | public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) { 104 | if (mSurfaceTexture == null || mSurfaceTexture.isReleased()) { 105 | mSurfaceTexture = surface; 106 | 107 | if (mMediaPlayer != null) { 108 | mMediaPlayer.getVLCVout().setWindowSize(width, height); 109 | if (!mMediaPlayer.getVLCVout().areViewsAttached()) { 110 | mMediaPlayer.getVLCVout().setVideoSurface(mSurfaceTexture); 111 | if (!mMediaPlayer.getVLCVout().areViewsAttached()) { 112 | mMediaPlayer.getVLCVout().attachViews(this); 113 | } 114 | mMediaPlayer.setVideoTrackEnabled(true); 115 | if (wasPlaying) { 116 | mMediaPlayer.play(); 117 | } 118 | } 119 | } 120 | 121 | wasPlaying = false; 122 | 123 | } else { 124 | if (getSurfaceTexture() != mSurfaceTexture) { 125 | setSurfaceTexture(mSurfaceTexture); 126 | } 127 | } 128 | 129 | } 130 | 131 | @Override 132 | public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) { 133 | setSize(width, height); 134 | } 135 | 136 | @Override 137 | public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) { 138 | if (mMediaPlayer != null) { 139 | wasPlaying = mMediaPlayer.isPlaying(); 140 | } 141 | 142 | if (mSurfaceTexture != surface) { 143 | if (mSurfaceTexture != null) { 144 | if (!mSurfaceTexture.isReleased()) { 145 | mSurfaceTexture.release(); 146 | } 147 | } 148 | mSurfaceTexture = surface; 149 | } 150 | 151 | return false; 152 | } 153 | 154 | @Override 155 | public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) { 156 | 157 | } 158 | 159 | @Override 160 | public void onNewVideoLayout(IVLCVout vlcVout, int width, int height, int visibleWidth, int visibleHeight, int sarNum, int sarDen) { 161 | if (width * height == 0) return; 162 | 163 | setSize(width, height); 164 | } 165 | 166 | @Override 167 | public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { 168 | if (left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom) { 169 | updateLayoutSize(view); 170 | } 171 | } 172 | 173 | public void updateLayoutSize(View view) { 174 | if (mMediaPlayer != null) { 175 | mMediaPlayer.getVLCVout().setWindowSize(view.getWidth(), view.getHeight()); 176 | updateSurfaceTexture(); 177 | } 178 | } 179 | 180 | private void setSize(int width, int height) { 181 | if (width * height <= 1) return; 182 | 183 | // Screen size 184 | int w = this.getWidth(); 185 | int h = this.getHeight(); 186 | 187 | // Size 188 | // TODO: fix this always false condition, it seems to reverse the width and height 189 | if (w > h && w < h) { 190 | int i = w; 191 | w = h; 192 | h = i; 193 | } 194 | 195 | float videoAR = (float) width / (float) height; 196 | float screenAR = (float) w / (float) h; 197 | 198 | if (screenAR < videoAR) { 199 | h = (int) (w / videoAR); 200 | } else { 201 | w = (int) (h * videoAR); 202 | } 203 | 204 | // Layout fit 205 | ViewGroup.LayoutParams lp = this.getLayoutParams(); 206 | lp.width = ViewGroup.LayoutParams.MATCH_PARENT; 207 | lp.height = h; 208 | this.setLayoutParams(lp); 209 | this.invalidate(); 210 | } 211 | 212 | } -------------------------------------------------------------------------------- /flutter_vlc_player/doc/multiple.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/doc/multiple.jpg -------------------------------------------------------------------------------- /flutter_vlc_player/doc/single.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/doc/single.jpg -------------------------------------------------------------------------------- /flutter_vlc_player/example/.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/app/.cxx 61 | **/android/captures/ 62 | **/android/gradlew 63 | **/android/gradlew.bat 64 | **/android/local.properties 65 | **/android/**/GeneratedPluginRegistrant.java 66 | **/android/key.properties 67 | *.jks 68 | 69 | # iOS/XCode related 70 | **/ios/**/*.mode1v3 71 | **/ios/**/*.mode2v3 72 | **/ios/**/*.moved-aside 73 | **/ios/**/*.pbxuser 74 | **/ios/**/*.perspectivev3 75 | **/ios/**/*sync/ 76 | **/ios/**/.sconsign.dblite 77 | **/ios/**/.tags* 78 | **/ios/**/.vagrant/ 79 | **/ios/**/DerivedData/ 80 | **/ios/**/Icon? 81 | **/ios/**/Pods/ 82 | **/ios/**/.symlinks/ 83 | **/ios/**/profile 84 | **/ios/**/xcuserdata 85 | **/ios/.generated/ 86 | **/ios/Flutter/App.framework 87 | **/ios/Flutter/Flutter.framework 88 | **/ios/Flutter/Flutter.podspec 89 | **/ios/Flutter/Generated.xcconfig 90 | **/ios/Flutter/app.flx 91 | **/ios/Flutter/app.zip 92 | **/ios/Flutter/flutter_assets/ 93 | **/ios/Flutter/flutter_export_environment.sh 94 | **/ios/ServiceDefinitions.json 95 | **/ios/Runner/GeneratedPluginRegistrant.* 96 | 97 | # macOS 98 | **/macos/Flutter/GeneratedPluginRegistrant.swift 99 | **/macos/Flutter/Flutter-Debug.xcconfig 100 | **/macos/Flutter/Flutter-Release.xcconfig 101 | **/macos/Flutter/Flutter-Profile.xcconfig 102 | 103 | # Temporary Files 104 | **/._* 105 | 106 | # Coverage 107 | coverage/ 108 | 109 | # Symbols 110 | app.*.symbols 111 | 112 | # Exceptions to above rules. 113 | !**/ios/**/default.mode1v3 114 | !**/ios/**/default.mode2v3 115 | !**/ios/**/default.pbxuser 116 | !**/ios/**/default.perspectivev3 117 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 118 | !/dev/ci/**/Gemfile.lock 119 | !/example/ios/Runner.xcodeproj/project.pbxproj -------------------------------------------------------------------------------- /flutter_vlc_player/example/.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: app 11 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/README.md: -------------------------------------------------------------------------------- 1 | # flutter_vlc_player_example 2 | 3 | Demonstrates how to use the flutter_vlc_player plugin. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.io/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.io/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.io/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | id("kotlin-android") 4 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. 5 | id("dev.flutter.flutter-gradle-plugin") 6 | } 7 | 8 | android { 9 | namespace = "software.solid.example" 10 | compileSdk = flutter.compileSdkVersion 11 | ndkVersion = "27.0.12077973" 12 | 13 | compileOptions { 14 | sourceCompatibility = JavaVersion.VERSION_11 15 | targetCompatibility = JavaVersion.VERSION_11 16 | } 17 | 18 | kotlinOptions { 19 | jvmTarget = JavaVersion.VERSION_11.toString() 20 | } 21 | 22 | defaultConfig { 23 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 24 | applicationId = "software.solid.example" 25 | // You can update the following values to match your application needs. 26 | // For more information, see: https://flutter.dev/to/review-gradle-config. 27 | minSdk = flutter.minSdkVersion 28 | targetSdk = flutter.targetSdkVersion 29 | versionCode = flutter.versionCode 30 | versionName = flutter.versionName 31 | } 32 | 33 | buildTypes { 34 | release { 35 | // TODO: Add your own signing config for the release build. 36 | // Signing with the debug keys for now, so `flutter run --release` works. 37 | signingConfig = signingConfigs.getByName("debug") 38 | } 39 | } 40 | } 41 | 42 | flutter { 43 | source = "../.." 44 | } 45 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 13 | 22 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 41 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/app/src/main/kotlin/software/solid/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package software.solid.example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() 9 | rootProject.layout.buildDirectory.value(newBuildDir) 10 | 11 | subprojects { 12 | val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) 13 | project.layout.buildDirectory.value(newSubprojectBuildDir) 14 | } 15 | subprojects { 16 | project.evaluationDependsOn(":app") 17 | } 18 | 19 | tasks.register("clean") { 20 | delete(rootProject.layout.buildDirectory) 21 | } 22 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip 6 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/android/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | val flutterSdkPath = run { 3 | val properties = java.util.Properties() 4 | file("local.properties").inputStream().use { properties.load(it) } 5 | val flutterSdkPath = properties.getProperty("flutter.sdk") 6 | require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } 7 | flutterSdkPath 8 | } 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id("dev.flutter.flutter-plugin-loader") version "1.0.0" 21 | id("com.android.application") version "8.7.0" apply false 22 | id("org.jetbrains.kotlin.android") version "1.8.22" apply false 23 | } 24 | 25 | include(":app") 26 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/assets/sample.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/assets/sample.mp4 -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Flutter/.last_build_id: -------------------------------------------------------------------------------- 1 | 9222a36532060fe7bdea079b78f0b0bd -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 3 | #include "Generated.xcconfig" 4 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 3 | #include "Generated.xcconfig" 4 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '14.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 53 | 55 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | example 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | 32 | NSBonjourServices 33 | 34 | _googlecast._tcp 35 | 36 | NSLocalNetworkUsageDescription 37 | Used to search for chromecast devices 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIMainStoryboardFile 41 | Main 42 | UISupportedInterfaceOrientations 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | UISupportedInterfaceOrientations~ipad 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationPortraitUpsideDown 52 | UIInterfaceOrientationLandscapeLeft 53 | UIInterfaceOrientationLandscapeRight 54 | 55 | UIViewControllerBasedStatusBarAppearance 56 | 57 | UIApplicationSupportsIndirectInputEvents 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/lib/app.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_vlc_player_example/multiple_tab.dart'; 3 | import 'package:flutter_vlc_player_example/single_tab.dart'; 4 | 5 | class App extends StatefulWidget { 6 | @override 7 | _AppState createState() => _AppState(); 8 | } 9 | 10 | class _AppState extends State { 11 | static const _tabCount = 2; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return DefaultTabController( 16 | length: _tabCount, 17 | child: Scaffold( 18 | appBar: AppBar( 19 | centerTitle: true, 20 | title: const Text('Vlc Player Example'), 21 | bottom: const TabBar( 22 | tabs: [ 23 | Tab(text: 'Single'), 24 | Tab(text: 'Multiple'), 25 | ], 26 | ), 27 | ), 28 | body: TabBarView( 29 | physics: const NeverScrollableScrollPhysics(), 30 | children: [ 31 | SingleTab(), 32 | MultipleTab(), 33 | ], 34 | ), 35 | ), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/lib/controls_overlay.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_vlc_player/flutter_vlc_player.dart'; 3 | 4 | class ControlsOverlay extends StatelessWidget { 5 | static const double _playButtonIconSize = 80; 6 | static const double _replayButtonIconSize = 100; 7 | static const double _seekButtonIconSize = 48; 8 | 9 | static const Duration _seekStepForward = Duration(seconds: 10); 10 | static const Duration _seekStepBackward = Duration(seconds: -10); 11 | 12 | static const Color _iconColor = Colors.white; 13 | 14 | final VlcPlayerController controller; 15 | 16 | const ControlsOverlay({ 17 | required this.controller, 18 | super.key, 19 | }); 20 | 21 | @override 22 | // ignore: cyclomatic_complexity 23 | Widget build(BuildContext context) { 24 | return AnimatedSwitcher( 25 | duration: const Duration(milliseconds: 50), 26 | reverseDuration: const Duration(milliseconds: 200), 27 | child: Builder( 28 | builder: (_) { 29 | if (controller.value.isEnded || controller.value.hasError) { 30 | return Center( 31 | child: FittedBox( 32 | child: IconButton( 33 | onPressed: _replay, 34 | color: _iconColor, 35 | iconSize: _replayButtonIconSize, 36 | icon: const Icon(Icons.replay), 37 | ), 38 | ), 39 | ); 40 | } 41 | 42 | switch (controller.value.playingState) { 43 | case PlayingState.initialized: 44 | case PlayingState.stopped: 45 | case PlayingState.paused: 46 | return SizedBox.expand( 47 | child: ColoredBox( 48 | color: Colors.black45, 49 | child: FittedBox( 50 | child: Row( 51 | mainAxisAlignment: MainAxisAlignment.spaceAround, 52 | children: [ 53 | IconButton( 54 | onPressed: () => _seekRelative(_seekStepBackward), 55 | color: _iconColor, 56 | iconSize: _seekButtonIconSize, 57 | icon: const Icon(Icons.replay_10), 58 | ), 59 | IconButton( 60 | onPressed: _play, 61 | color: _iconColor, 62 | iconSize: _playButtonIconSize, 63 | icon: const Icon(Icons.play_arrow), 64 | ), 65 | IconButton( 66 | onPressed: () => _seekRelative(_seekStepForward), 67 | color: _iconColor, 68 | iconSize: _seekButtonIconSize, 69 | icon: const Icon(Icons.forward_10), 70 | ), 71 | ], 72 | ), 73 | ), 74 | ), 75 | ); 76 | 77 | case PlayingState.buffering: 78 | case PlayingState.playing: 79 | return GestureDetector( 80 | onTap: _pause, 81 | child: Container( 82 | color: Colors.transparent, 83 | ), 84 | ); 85 | 86 | case PlayingState.ended: 87 | case PlayingState.error: 88 | return Center( 89 | child: FittedBox( 90 | child: IconButton( 91 | onPressed: _replay, 92 | color: _iconColor, 93 | iconSize: _replayButtonIconSize, 94 | icon: const Icon(Icons.replay), 95 | ), 96 | ), 97 | ); 98 | 99 | default: 100 | return const SizedBox.shrink(); 101 | } 102 | }, 103 | ), 104 | ); 105 | } 106 | 107 | Future _play() { 108 | return controller.play(); 109 | } 110 | 111 | Future _replay() async { 112 | await controller.stop(); 113 | await controller.play(); 114 | } 115 | 116 | Future _pause() async { 117 | // ignore: prefer_early_return 118 | if (controller.value.isPlaying) { 119 | await controller.pause(); 120 | } 121 | } 122 | 123 | /// Returns a callback which seeks the video relative to current playing time. 124 | Future _seekRelative(Duration seekStep) { 125 | return controller.seekTo(controller.value.position + seekStep); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_vlc_player_example/app.dart'; 3 | 4 | void main() { 5 | runApp( 6 | MaterialApp( 7 | home: App(), 8 | ), 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/lib/multiple_tab.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_vlc_player/flutter_vlc_player.dart'; 3 | import 'package:flutter_vlc_player_example/vlc_player_with_controls.dart'; 4 | 5 | class MultipleTab extends StatefulWidget { 6 | @override 7 | _MultipleTabState createState() => _MultipleTabState(); 8 | } 9 | 10 | class _MultipleTabState extends State { 11 | static const _heightWithControls = 400.0; 12 | static const _heightWithoutControls = 300.0; 13 | static const _networkCachingTime = 2000; 14 | 15 | List controllers = []; 16 | 17 | List urls = [ 18 | 'https://www.tomandjerryonline.com/Videos/Ford%20Mondeo%20-%20Tom%20and%20Jerry.mov', 19 | 'https://www.tomandjerryonline.com/Videos/TomAndJerryTales_HQ.wmv', 20 | 'https://www.tomandjerryonline.com/Videos/tjpb1.mov', 21 | ]; 22 | 23 | bool showPlayerControls = true; 24 | 25 | @override 26 | void initState() { 27 | super.initState(); 28 | for (var i = 0; i < urls.length; i++) { 29 | final controller = VlcPlayerController.network( 30 | urls[i], 31 | hwAcc: HwAcc.full, 32 | autoPlay: false, 33 | options: VlcPlayerOptions( 34 | advanced: VlcAdvancedOptions([ 35 | VlcAdvancedOptions.networkCaching(_networkCachingTime), 36 | ]), 37 | rtp: VlcRtpOptions([ 38 | VlcRtpOptions.rtpOverRtsp(true), 39 | ]), 40 | ), 41 | ); 42 | controllers.add(controller); 43 | } 44 | } 45 | 46 | @override 47 | Widget build(BuildContext context) { 48 | return ListView.separated( 49 | itemCount: controllers.length, 50 | separatorBuilder: (_, __) { 51 | return const Divider(height: 5, thickness: 5, color: Colors.grey); 52 | }, 53 | itemBuilder: (_, index) { 54 | return SizedBox( 55 | height: 56 | showPlayerControls ? _heightWithControls : _heightWithoutControls, 57 | child: VlcPlayerWithControls( 58 | controller: controllers[index], 59 | showControls: showPlayerControls, 60 | ), 61 | ); 62 | }, 63 | ); 64 | } 65 | 66 | @override 67 | Future dispose() async { 68 | for (final controller in controllers) { 69 | await controller.stopRendererScanning(); 70 | await controller.dispose(); 71 | } 72 | super.dispose(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/lib/single_tab.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: cyclomatic_complexity 2 | import 'dart:io'; 3 | 4 | import 'package:flutter/foundation.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter/services.dart'; 7 | import 'package:flutter_vlc_player/flutter_vlc_player.dart'; 8 | import 'package:flutter_vlc_player_example/video_data.dart'; 9 | import 'package:flutter_vlc_player_example/vlc_player_with_controls.dart'; 10 | import 'package:path_provider/path_provider.dart'; 11 | 12 | class SingleTab extends StatefulWidget { 13 | @override 14 | _SingleTabState createState() => _SingleTabState(); 15 | } 16 | 17 | class _SingleTabState extends State { 18 | static const _networkCachingMs = 2000; 19 | static const _subtitlesFontSize = 30; 20 | static const _height = 400.0; 21 | 22 | final _key = GlobalKey(); 23 | 24 | // ignore: avoid_late_keyword 25 | late final VlcPlayerController _controller; 26 | 27 | // 28 | List listVideos = [ 29 | const VideoData( 30 | name: 'Network Video 1', 31 | path: 32 | 'http://samples.mplayerhq.hu/MPEG-4/embedded_subs/1Video_2Audio_2SUBs_timed_text_streams_.mp4', 33 | type: VideoType.network, 34 | ), 35 | // 36 | const VideoData( 37 | name: 'Network Video 2', 38 | path: 'https://media.w3.org/2010/05/sintel/trailer.mp4', 39 | type: VideoType.network, 40 | ), 41 | // 42 | const VideoData( 43 | name: 'HLS Streaming Video 1', 44 | path: 45 | 'http://demo.unified-streaming.com/video/tears-of-steel/tears-of-steel.ism/.m3u8', 46 | type: VideoType.network, 47 | ), 48 | // 49 | const VideoData( 50 | name: 'File Video 1', 51 | path: 'System File Example', 52 | type: VideoType.file, 53 | ), 54 | // 55 | const VideoData( 56 | name: 'Asset Video 1', 57 | path: 'assets/sample.mp4', 58 | type: VideoType.asset, 59 | ), 60 | ]; 61 | 62 | int selectedVideoIndex = 0; 63 | 64 | Future _loadVideoToFs() async { 65 | final videoData = await rootBundle.load('assets/sample.mp4'); 66 | final videoBytes = Uint8List.view(videoData.buffer); 67 | final dir = (await getTemporaryDirectory()).path; 68 | final temp = File('$dir/temp.file'); 69 | temp.writeAsBytesSync(videoBytes); 70 | 71 | return temp; 72 | } 73 | 74 | @override 75 | void initState() { 76 | super.initState(); 77 | 78 | // 79 | final initVideo = listVideos[selectedVideoIndex]; 80 | switch (initVideo.type) { 81 | case VideoType.network: 82 | _controller = VlcPlayerController.network( 83 | initVideo.path, 84 | hwAcc: HwAcc.full, 85 | options: VlcPlayerOptions( 86 | advanced: VlcAdvancedOptions([ 87 | VlcAdvancedOptions.networkCaching(_networkCachingMs), 88 | ]), 89 | subtitle: VlcSubtitleOptions([ 90 | VlcSubtitleOptions.boldStyle(true), 91 | VlcSubtitleOptions.fontSize(_subtitlesFontSize), 92 | VlcSubtitleOptions.outlineColor(VlcSubtitleColor.yellow), 93 | VlcSubtitleOptions.outlineThickness(VlcSubtitleThickness.normal), 94 | // works only on externally added subtitles 95 | VlcSubtitleOptions.color(VlcSubtitleColor.navy), 96 | ]), 97 | http: VlcHttpOptions([ 98 | VlcHttpOptions.httpReconnect(true), 99 | ]), 100 | rtp: VlcRtpOptions([ 101 | VlcRtpOptions.rtpOverRtsp(true), 102 | ]), 103 | ), 104 | ); 105 | break; 106 | case VideoType.file: 107 | final file = File(initVideo.path); 108 | _controller = VlcPlayerController.file( 109 | file, 110 | ); 111 | break; 112 | case VideoType.asset: 113 | _controller = VlcPlayerController.asset( 114 | initVideo.path, 115 | options: VlcPlayerOptions(), 116 | ); 117 | break; 118 | case VideoType.recorded: 119 | break; 120 | } 121 | _controller.addOnInitListener(() async { 122 | await _controller.startRendererScanning(); 123 | }); 124 | _controller.addOnRendererEventListener((type, id, name) { 125 | // ignore: prefer_early_return 126 | if (!kReleaseMode) { 127 | debugPrint('OnRendererEventListener $type $id $name'); 128 | } 129 | }); 130 | } 131 | 132 | @override 133 | Widget build(BuildContext context) { 134 | return ListView( 135 | children: [ 136 | SizedBox( 137 | height: _height, 138 | child: VlcPlayerWithControls( 139 | key: _key, 140 | controller: _controller, 141 | onStopRecording: (recordPath) { 142 | setState(() { 143 | listVideos.add( 144 | VideoData( 145 | name: 'Recorded Video', 146 | path: recordPath, 147 | type: VideoType.recorded, 148 | ), 149 | ); 150 | }); 151 | ScaffoldMessenger.of(context).showSnackBar( 152 | const SnackBar( 153 | content: Text( 154 | 'The recorded video file has been added to the end of list.', 155 | ), 156 | ), 157 | ); 158 | }, 159 | ), 160 | ), 161 | ListView.builder( 162 | shrinkWrap: true, 163 | itemCount: listVideos.length, 164 | physics: const NeverScrollableScrollPhysics(), 165 | itemBuilder: (BuildContext context, int index) { 166 | final video = listVideos[index]; 167 | IconData iconData; 168 | switch (video.type) { 169 | case VideoType.network: 170 | iconData = Icons.cloud; 171 | break; 172 | case VideoType.file: 173 | iconData = Icons.insert_drive_file; 174 | break; 175 | case VideoType.asset: 176 | iconData = Icons.all_inbox; 177 | break; 178 | case VideoType.recorded: 179 | iconData = Icons.videocam; 180 | break; 181 | } 182 | 183 | return ListTile( 184 | dense: true, 185 | selected: selectedVideoIndex == index, 186 | selectedTileColor: Colors.black54, 187 | leading: Icon( 188 | iconData, 189 | color: 190 | selectedVideoIndex == index ? Colors.white : Colors.black, 191 | ), 192 | title: Text( 193 | video.name, 194 | overflow: TextOverflow.ellipsis, 195 | style: TextStyle( 196 | color: 197 | selectedVideoIndex == index ? Colors.white : Colors.black, 198 | ), 199 | ), 200 | subtitle: Text( 201 | video.path, 202 | overflow: TextOverflow.ellipsis, 203 | style: TextStyle( 204 | color: 205 | selectedVideoIndex == index ? Colors.white : Colors.black, 206 | ), 207 | ), 208 | onTap: () async { 209 | await _controller.stopRecording(); 210 | switch (video.type) { 211 | case VideoType.network: 212 | await _controller.setMediaFromNetwork( 213 | video.path, 214 | hwAcc: HwAcc.full, 215 | ); 216 | break; 217 | case VideoType.file: 218 | if (!mounted) break; 219 | ScaffoldMessenger.of(context).showSnackBar( 220 | const SnackBar( 221 | content: Text('Copying file to temporary storage...'), 222 | ), 223 | ); 224 | await Future.delayed(const Duration(seconds: 1)); 225 | final tempVideo = await _loadVideoToFs(); 226 | await Future.delayed(const Duration(seconds: 1)); 227 | if (!context.mounted) break; 228 | ScaffoldMessenger.of(context).showSnackBar( 229 | const SnackBar( 230 | content: Text('Now trying to play...'), 231 | ), 232 | ); 233 | await Future.delayed(const Duration(seconds: 1)); 234 | if (await tempVideo.exists()) { 235 | await _controller.setMediaFromFile(tempVideo); 236 | } else { 237 | if (!context.mounted) break; 238 | ScaffoldMessenger.of(context).showSnackBar( 239 | const SnackBar( 240 | content: Text('File load error.'), 241 | ), 242 | ); 243 | } 244 | break; 245 | case VideoType.asset: 246 | await _controller.setMediaFromAsset(video.path); 247 | break; 248 | case VideoType.recorded: 249 | final recordedFile = File(video.path); 250 | await _controller.setMediaFromFile(recordedFile); 251 | break; 252 | } 253 | setState(() { 254 | selectedVideoIndex = index; 255 | }); 256 | }, 257 | ); 258 | }, 259 | ), 260 | ], 261 | ); 262 | } 263 | 264 | @override 265 | Future dispose() async { 266 | await _controller.stopRecording(); 267 | await _controller.stopRendererScanning(); 268 | await _controller.dispose(); 269 | super.dispose(); 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/lib/video_data.dart: -------------------------------------------------------------------------------- 1 | class VideoData { 2 | final String name; 3 | final String path; 4 | final VideoType type; 5 | 6 | const VideoData({ 7 | required this.name, 8 | required this.path, 9 | required this.type, 10 | }); 11 | } 12 | 13 | enum VideoType { 14 | asset, 15 | file, 16 | network, 17 | recorded, 18 | } 19 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_vlc_player_example 2 | description: Demonstrates how to use the flutter_vlc_player plugin. 3 | publish_to: 'none' 4 | 5 | environment: 6 | sdk: ">=2.18.0 <4.0.0" 7 | 8 | dependencies: 9 | cupertino_icons: ^1.0.8 10 | 11 | flutter: 12 | sdk: flutter 13 | 14 | flutter_vlc_player: 15 | path: ../ 16 | 17 | path_provider: ^2.1.5 18 | 19 | dev_dependencies: 20 | flutter_test: 21 | sdk: flutter 22 | 23 | solid_lints: ^0.2.3 24 | 25 | # The following section is specific to Flutter. 26 | flutter: 27 | 28 | # The following line ensures that the Material Icons font is 29 | # included with your application, so that you can use the icons in 30 | # the material Icons class. 31 | uses-material-design: true 32 | 33 | # To add assets to your application, add an assets section, like this: 34 | assets: 35 | - assets/ 36 | # - images/a_dot_burr.jpeg 37 | # - images/a_dot_ham.jpeg 38 | 39 | # An image asset can refer to one or more resolution-specific "variants", see 40 | # https://flutter.io/assets-and-images/#resolution-aware. 41 | 42 | # For details regarding adding assets from package dependencies, see 43 | # https://flutter.io/assets-and-images/#from-packages 44 | 45 | # To add custom fonts to your application, add a fonts section here, 46 | # in this "flutter" section. Each entry in this list should have a 47 | # "family" key with the font family name, and a "fonts" key with a 48 | # list giving the asset and other descriptors for the font. For 49 | # example: 50 | # fonts: 51 | # - family: Schyler 52 | # fonts: 53 | # - asset: fonts/Schyler-Regular.ttf 54 | # - asset: fonts/Schyler-Italic.ttf 55 | # style: italic 56 | # - family: Trajan Pro 57 | # fonts: 58 | # - asset: fonts/TrajanPro.ttf 59 | # - asset: fonts/TrajanPro_Bold.ttf 60 | # weight: 700 61 | # 62 | # For details regarding fonts from package dependencies, 63 | # see https://flutter.io/custom-fonts/#from-packages 64 | -------------------------------------------------------------------------------- /flutter_vlc_player/example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | import 'package:flutter_vlc_player_example/app.dart'; 11 | 12 | void main() { 13 | testWidgets('Verify Platform version', (WidgetTester tester) async { 14 | // Build our app and trigger a frame. 15 | await tester.pumpWidget(App()); 16 | 17 | // Verify that platform version is retrieved. 18 | expect( 19 | find.byWidgetPredicate( 20 | (Widget widget) { 21 | if (widget is Text) { 22 | final data = widget.data; 23 | 24 | return data != null && data.startsWith('Running on:'); 25 | } 26 | 27 | return false; 28 | }, 29 | ), 30 | findsOneWidget, 31 | ); 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /flutter_vlc_player/ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /flutter_vlc_player/ios/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solid-software/flutter_vlc_player/fbdb1ccef0bbf698756c2b7f51973842affad477/flutter_vlc_player/ios/Assets/.gitkeep -------------------------------------------------------------------------------- /flutter_vlc_player/ios/Classes/FlutterVlcPlayerPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface FlutterVlcPlayerPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /flutter_vlc_player/ios/Classes/FlutterVlcPlayerPlugin.m: -------------------------------------------------------------------------------- 1 | #import "FlutterVlcPlayerPlugin.h" 2 | #if __has_include() 3 | #import 4 | #else 5 | // Support project import fallback if the generated compatibility header 6 | // is not copied when this plugin is created as a library. 7 | // https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 8 | #import "flutter_vlc_player-Swift.h" 9 | #endif 10 | 11 | @implementation FlutterVlcPlayerPlugin 12 | + (void)registerWithRegistrar:(NSObject*)registrar { 13 | [SwiftFlutterVlcPlayerPlugin registerWithRegistrar:registrar]; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /flutter_vlc_player/ios/Classes/SwiftFlutterVlcPlayerPlugin.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Flutter 3 | 4 | public class SwiftFlutterVlcPlayerPlugin: NSObject, FlutterPlugin { 5 | public static func register(with registrar: FlutterPluginRegistrar) { 6 | let vlcViewFactory = VLCViewFactory(registrar: registrar) 7 | registrar.register(vlcViewFactory, withId: "flutter_video_plugin/getVideoView") 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /flutter_vlc_player/ios/Classes/VlcViewBuilder.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import Foundation 3 | 4 | public class VLCViewBuilder: NSObject, VlcPlayerApi { 5 | var players = [Int: VLCViewController]() 6 | private var registrar: FlutterPluginRegistrar 7 | private var messenger: FlutterBinaryMessenger 8 | private var options: [String] 9 | 10 | init(registrar: FlutterPluginRegistrar) { 11 | self.registrar = registrar 12 | messenger = registrar.messenger() 13 | options = [] 14 | super.init() 15 | // 16 | VlcPlayerApiSetup.setUp(binaryMessenger: messenger, api: self) 17 | } 18 | 19 | public func build(frame: CGRect, viewId: Int64) -> VLCViewController { 20 | // 21 | var vlcViewController: VLCViewController 22 | vlcViewController = VLCViewController(frame: frame, viewId: viewId, messenger: messenger) 23 | players[viewId.int] = vlcViewController 24 | return vlcViewController 25 | } 26 | 27 | func getPlayer(id: Int64) throws -> VLCViewController { 28 | guard let player = players[id.int] else { 29 | throw PigeonError(code: "player_not_found", message: "Player with id \(id) not found", details: nil) 30 | } 31 | 32 | return player 33 | } 34 | 35 | public func initialize() throws {} 36 | 37 | func create(msg: CreateMessage) throws { 38 | let player = try getPlayer(id: msg.playerId) 39 | 40 | var isAssetUrl = false 41 | var mediaUrl = "" 42 | 43 | if DataSourceType(rawValue: msg.type.int) == DataSourceType.ASSET { 44 | var assetPath: String 45 | if let packageName = msg.packageName { 46 | assetPath = registrar.lookupKey(forAsset: msg.uri, fromPackage: packageName) 47 | } else { 48 | assetPath = registrar.lookupKey(forAsset: msg.uri) 49 | } 50 | mediaUrl = assetPath 51 | isAssetUrl = true 52 | } else { 53 | mediaUrl = msg.uri 54 | isAssetUrl = false 55 | } 56 | 57 | options = msg.options 58 | 59 | player.setMediaPlayerUrl( 60 | uri: mediaUrl, 61 | isAssetUrl: isAssetUrl, 62 | autoPlay: msg.autoPlay, 63 | hwAcc: msg.hwAcc?.int ?? HWAccellerationType.HW_ACCELERATION_AUTOMATIC.rawValue, 64 | options: options 65 | ) 66 | } 67 | 68 | func dispose(playerId: Int64) throws { 69 | let player = try getPlayer(id: playerId) 70 | 71 | player.dispose() 72 | players.removeValue(forKey: playerId.int) 73 | } 74 | 75 | func setStreamUrl(msg: SetMediaMessage) throws { 76 | let player = try getPlayer(id: msg.playerId) 77 | 78 | var isAssetUrl = false 79 | var mediaUrl = "" 80 | 81 | if DataSourceType(rawValue: msg.type.int) == DataSourceType.ASSET { 82 | var assetPath: String 83 | if let packageName = msg.packageName { 84 | assetPath = registrar.lookupKey(forAsset: msg.uri, fromPackage: packageName) 85 | } else { 86 | assetPath = registrar.lookupKey(forAsset: msg.uri) 87 | } 88 | mediaUrl = assetPath 89 | isAssetUrl = true 90 | } else { 91 | mediaUrl = msg.uri 92 | isAssetUrl = false 93 | } 94 | 95 | player.setMediaPlayerUrl( 96 | uri: mediaUrl, 97 | isAssetUrl: isAssetUrl, 98 | autoPlay: msg.autoPlay, 99 | hwAcc: msg.hwAcc?.int ?? HWAccellerationType.HW_ACCELERATION_AUTOMATIC.rawValue, 100 | options: options 101 | ) 102 | } 103 | 104 | func play(playerId: Int64) throws { 105 | let player = try getPlayer(id: playerId) 106 | 107 | player.play() 108 | } 109 | 110 | func pause(playerId: Int64) throws { 111 | let player = try getPlayer(id: playerId) 112 | 113 | player.pause() 114 | } 115 | 116 | func stop(playerId: Int64) throws { 117 | let player = try getPlayer(id: playerId) 118 | 119 | player.stop() 120 | } 121 | 122 | func isPlaying(playerId: Int64) throws -> Bool { 123 | return try getPlayer(id: playerId).isPlaying 124 | } 125 | 126 | func isSeekable(playerId: Int64) throws -> Bool { 127 | return try getPlayer(id: playerId).isSeekable 128 | } 129 | 130 | func setLooping(playerId: Int64, isLooping: Bool) throws { 131 | let player = try getPlayer(id: playerId) 132 | 133 | player.setLooping(isLooping: isLooping) 134 | } 135 | 136 | func seekTo(playerId: Int64, position: Int64) throws { 137 | let player = try getPlayer(id: playerId) 138 | 139 | player.seek(position: position) 140 | } 141 | 142 | func position(playerId: Int64) throws -> Int64 { 143 | return try getPlayer(id: playerId).position.int64 144 | } 145 | 146 | func duration(playerId: Int64) throws -> Int64 { 147 | return try getPlayer(id: playerId).duration.int64 148 | } 149 | 150 | func setVolume(playerId: Int64, volume: Int64) throws { 151 | let player = try getPlayer(id: playerId) 152 | player.setVolume(volume: volume) 153 | } 154 | 155 | func getVolume(playerId: Int64) throws -> Int64 { 156 | return try getPlayer(id: playerId).volume.int64 157 | } 158 | 159 | func setPlaybackSpeed(playerId: Int64, speed: Double) throws { 160 | let player = try getPlayer(id: playerId) 161 | 162 | player.setPlaybackSpeed(speed: speed.float) 163 | } 164 | 165 | func getPlaybackSpeed(playerId: Int64) throws -> Double { 166 | return try getPlayer(id: playerId).playbackSpeed.double 167 | } 168 | 169 | func takeSnapshot(playerId: Int64) throws -> String? { 170 | return try getPlayer(id: playerId).takeSnapshot() 171 | } 172 | 173 | // MARK: - Subtitle Tracks 174 | 175 | func getSpuTracksCount(playerId: Int64) throws -> Int64 { 176 | return try getPlayer(id: playerId).spuTracksCount.int64 177 | } 178 | 179 | func getSpuTracks(playerId: Int64) throws -> [Int64: String] { 180 | return try getPlayer(id: playerId).spuTracks.int64Dictionary 181 | } 182 | 183 | func setSpuTrack(playerId: Int64, spuTrackNumber: Int64) throws { 184 | let player = try getPlayer(id: playerId) 185 | 186 | player.setSpuTrack(spuTrackNumber: spuTrackNumber.int32) 187 | } 188 | 189 | func getSpuTrack(playerId: Int64) throws -> Int64 { 190 | return try getPlayer(id: playerId).spuTrack.int64 191 | } 192 | 193 | func setSpuDelay(playerId: Int64, delay: Int64) throws { 194 | let player = try getPlayer(id: playerId) 195 | 196 | player.setSpuDelay(delay: delay.int) 197 | } 198 | 199 | func getSpuDelay(playerId: Int64) throws -> Int64 { 200 | return try getPlayer(id: playerId).spuDelay.int64 201 | } 202 | 203 | func addSubtitleTrack(msg: AddSubtitleMessage) throws { 204 | let player = try getPlayer(id: msg.playerId) 205 | 206 | player.addSubtitleTrack(uri: msg.uri, isSelected: msg.isSelected) 207 | } 208 | 209 | // MARK: - Audio Tracks 210 | 211 | func getAudioTracksCount(playerId: Int64) throws -> Int64 { 212 | return try getPlayer(id: playerId).audioTracksCount.int64 213 | } 214 | 215 | func getAudioTracks(playerId: Int64) throws -> [Int64: String] { 216 | return try getPlayer(id: playerId).audioTracks.int64Dictionary 217 | } 218 | 219 | func setAudioTrack(playerId: Int64, audioTrackNumber: Int64) throws { 220 | let player = try getPlayer(id: playerId) 221 | 222 | player.setAudioTrack(audioTrackNumber: audioTrackNumber.int32) 223 | } 224 | 225 | func getAudioTrack(playerId: Int64) throws -> Int64 { 226 | return try getPlayer(id: playerId).audioTrack.int64 227 | } 228 | 229 | func getAudioDelay(playerId: Int64) throws -> Int64 { 230 | return try getPlayer(id: playerId).audioDelay.int64 231 | } 232 | 233 | func setAudioDelay(playerId: Int64, delay: Int64) throws { 234 | let player = try getPlayer(id: playerId) 235 | 236 | player.setAudioDelay(delay: delay.int) 237 | } 238 | 239 | func addAudioTrack(msg: AddAudioMessage) throws { 240 | let player = try getPlayer(id: msg.playerId) 241 | 242 | player.addAudioTrack(uri: msg.uri, isSelected: msg.isSelected) 243 | } 244 | 245 | // MARK: - Video Tracks 246 | 247 | func getVideoTracksCount(playerId: Int64) throws -> Int64 { 248 | return try getPlayer(id: playerId).videoTracksCount.int64 249 | } 250 | 251 | func getVideoTracks(playerId: Int64) throws -> [Int64: String] { 252 | return try getPlayer(id: playerId).videoTracks.int64Dictionary 253 | } 254 | 255 | func setVideoTrack(playerId: Int64, videoTrackNumber: Int64) throws { 256 | let player = try getPlayer(id: playerId) 257 | 258 | player.setVideoTrack(videoTrackNumber: videoTrackNumber.int32) 259 | } 260 | 261 | func getVideoTrack(playerId: Int64) throws -> Int64 { 262 | return try getPlayer(id: playerId).videoTrack.int64 263 | } 264 | 265 | // MARK: - Video properties 266 | 267 | func setVideoScale(playerId: Int64, scale: Double) throws { 268 | let player = try getPlayer(id: playerId) 269 | 270 | player.setVideoScale(scale: scale.float) 271 | } 272 | 273 | func getVideoScale(playerId: Int64) throws -> Double { 274 | return try getPlayer(id: playerId).videoScale.double 275 | } 276 | 277 | func setVideoAspectRatio(playerId: Int64, aspectRatio: String) throws { 278 | let player = try getPlayer(id: playerId) 279 | 280 | player.setVideoAspectRatio(aspectRatio: aspectRatio) 281 | } 282 | 283 | func getVideoAspectRatio(playerId: Int64) throws -> String { 284 | return try getPlayer(id: playerId).videoAspectRatio 285 | } 286 | 287 | func getAvailableRendererServices(playerId: Int64) throws -> [String] { 288 | return try getPlayer(id: playerId).availableRendererServices 289 | } 290 | 291 | // MARK: - Cast 292 | 293 | func startRendererScanning(playerId: Int64, rendererService: String) throws { 294 | let player = try getPlayer(id: playerId) 295 | 296 | player.startRendererScanning() 297 | } 298 | 299 | func stopRendererScanning(playerId: Int64) throws { 300 | let player = try getPlayer(id: playerId) 301 | 302 | player.stopRendererScanning() 303 | } 304 | 305 | func getRendererDevices(playerId: Int64) throws -> [String: String] { 306 | return try getPlayer(id: playerId).rendererDevices 307 | } 308 | 309 | func castToRenderer(playerId: Int64, rendererId: String) throws { 310 | let player = try getPlayer(id: playerId) 311 | 312 | player.cast(rendererDevice: rendererId) 313 | } 314 | 315 | // MARK: - Recording 316 | 317 | func startRecording(playerId: Int64, saveDirectory: String) throws -> Bool { 318 | let player = try getPlayer(id: playerId) 319 | 320 | return player.startRecording(saveDirectory: saveDirectory) 321 | } 322 | 323 | func stopRecording(playerId: Int64) throws -> Bool { 324 | let player = try getPlayer(id: playerId) 325 | 326 | return player.stopRecording() 327 | } 328 | } 329 | 330 | extension Int { 331 | var int64: Int64 { 332 | Int64(self) 333 | } 334 | 335 | var int32: Int32 { 336 | Int32(self) 337 | } 338 | } 339 | 340 | extension Int64 { 341 | var int: Int { 342 | Int(self) 343 | } 344 | 345 | var int32: Int32 { 346 | Int32(truncatingIfNeeded: self) 347 | } 348 | } 349 | 350 | extension Int32 { 351 | var int: Int { 352 | Int(self) 353 | } 354 | 355 | var int64: Int64 { 356 | Int64(truncatingIfNeeded: self) 357 | } 358 | } 359 | 360 | extension Double { 361 | var float: Float { 362 | Float(self) 363 | } 364 | } 365 | 366 | extension Float { 367 | var double: Double { 368 | Double(self) 369 | } 370 | } 371 | 372 | extension Dictionary where Key == Int { 373 | var int64Dictionary: [Int64: Value] { 374 | [Int64: Value](uniqueKeysWithValues: 375 | map { (Int64($0.key), $0.value) } 376 | ) 377 | } 378 | } 379 | -------------------------------------------------------------------------------- /flutter_vlc_player/ios/Classes/VlcViewFactory.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Flutter 3 | 4 | public class VLCViewFactory: NSObject, FlutterPlatformViewFactory { 5 | 6 | private var registrar: FlutterPluginRegistrar 7 | private var builder: VLCViewBuilder 8 | 9 | 10 | init(registrar: FlutterPluginRegistrar) { 11 | self.registrar = registrar 12 | self.builder = VLCViewBuilder(registrar: registrar) 13 | super.init() 14 | } 15 | 16 | public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView { 17 | 18 | // let arguments = args as? NSDictionary ?? [:] 19 | return builder.build(frame: frame, viewId: viewId) 20 | } 21 | 22 | public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol { 23 | return FlutterStandardMessageCodec.sharedInstance() 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /flutter_vlc_player/ios/flutter_vlc_player.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint flutter_vlc_player.podspec' to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'flutter_vlc_player' 7 | s.version = '3.0.3' 8 | s.summary = 'A new flutter plugin project.' 9 | s.description = <<-DESC 10 | A VLC-powered alternative to Flutter video_player. Supports multiple players on one screen. 11 | DESC 12 | s.homepage = 'https://github.com/solid-software/flutter_vlc_player' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'Classes/**/*' 17 | s.dependency 'Flutter' 18 | s.platform = :ios, '11.0' 19 | s.dependency 'MobileVLCKit', '~> 3.6.1b1' 20 | s.static_framework = true 21 | 22 | # Flutter.framework does not contain a i386 slice. 23 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } 24 | s.swift_version = '5.0' 25 | end 26 | -------------------------------------------------------------------------------- /flutter_vlc_player/lib/flutter_vlc_player.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | export 'package:flutter_vlc_player_platform_interface/flutter_vlc_player_platform_interface.dart' 5 | show 6 | HwAcc, 7 | VlcMediaEvent, 8 | VlcMediaEventType, 9 | VlcRendererEvent, 10 | VlcRendererEventType, 11 | VlcSubtitleColor, 12 | VlcSubtitleThickness, 13 | VlcSubtitleTextDirection, 14 | DataSourceType, 15 | VlcPlayerOptions, 16 | VlcAdvancedOptions, 17 | VlcAudioOptions, 18 | VlcHttpOptions, 19 | VlcRtpOptions, 20 | VlcStreamOutputOptions, 21 | VlcVideoOptions, 22 | VlcSubtitleOptions; 23 | 24 | export 'src/enums/playing_state.dart' show PlayingState; 25 | export 'src/flutter_vlc_player.dart' show VlcPlayer; 26 | export 'src/vlc_player_controller.dart' show VlcPlayerController; 27 | export 'src/vlc_player_value.dart' show VlcPlayerValue; 28 | -------------------------------------------------------------------------------- /flutter_vlc_player/lib/src/enums/playing_state.dart: -------------------------------------------------------------------------------- 1 | enum PlayingState { 2 | initializing, 3 | initialized, 4 | stopped, 5 | paused, 6 | ended, 7 | buffering, 8 | playing, 9 | recording, 10 | error, 11 | } 12 | -------------------------------------------------------------------------------- /flutter_vlc_player/lib/src/flutter_vlc_player.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:flutter_vlc_player/src/vlc_player_controller.dart'; 3 | import 'package:flutter_vlc_player/src/vlc_player_platform.dart'; 4 | 5 | // ignore: prefer_match_file_name 6 | class VlcPlayer extends StatefulWidget { 7 | final VlcPlayerController controller; 8 | final double aspectRatio; 9 | final Widget? placeholder; 10 | final bool virtualDisplay; 11 | 12 | const VlcPlayer({ 13 | /// The [VlcPlayerController] responsible for the video being rendered in 14 | /// this widget. 15 | required this.controller, 16 | 17 | /// The aspect ratio used to display the video. 18 | /// This MUST be provided, however it could simply be (parentWidth / parentHeight) - where parentWidth and 19 | /// parentHeight are the width and height of the parent perhaps as defined by a LayoutBuilder. 20 | required this.aspectRatio, 21 | 22 | /// Before the platform view has initialized, this placeholder will be rendered instead of the video player. 23 | /// This can simply be a [CircularProgressIndicator] (see the example.) 24 | this.placeholder, 25 | 26 | /// Specify whether Virtual displays or Hybrid composition is used on Android. 27 | /// iOS only uses Hybrid composition. 28 | this.virtualDisplay = true, 29 | super.key, 30 | }); 31 | 32 | @override 33 | _VlcPlayerState createState() => _VlcPlayerState(); 34 | } 35 | 36 | class _VlcPlayerState extends State { 37 | bool _isInitialized = false; 38 | 39 | //ignore: avoid_late_keyword 40 | late VoidCallback _listener; 41 | 42 | _VlcPlayerState() { 43 | _listener = () { 44 | if (!mounted) return; 45 | // 46 | final isInitialized = widget.controller.value.isInitialized; 47 | if (isInitialized != _isInitialized) { 48 | setState(() { 49 | _isInitialized = isInitialized; 50 | }); 51 | } 52 | }; 53 | } 54 | 55 | @override 56 | void initState() { 57 | super.initState(); 58 | _isInitialized = widget.controller.value.isInitialized; 59 | // Need to listen for initialization events since the actual initialization value 60 | // becomes available after asynchronous initialization finishes. 61 | widget.controller.addListener(_listener); 62 | } 63 | 64 | @override 65 | Widget build(BuildContext context) { 66 | return AspectRatio( 67 | aspectRatio: widget.aspectRatio, 68 | child: Stack( 69 | children: [ 70 | Offstage( 71 | offstage: _isInitialized, 72 | child: widget.placeholder ?? Container(), 73 | ), 74 | Offstage( 75 | offstage: !_isInitialized, 76 | child: vlcPlayerPlatform.buildView( 77 | widget.controller.onPlatformViewCreated, 78 | virtualDisplay: widget.virtualDisplay, 79 | ), 80 | ), 81 | ], 82 | ), 83 | ); 84 | } 85 | 86 | @override 87 | void didUpdateWidget(VlcPlayer oldWidget) { 88 | super.didUpdateWidget(oldWidget); 89 | if (oldWidget.controller != widget.controller) { 90 | oldWidget.controller.removeListener(_listener); 91 | _isInitialized = widget.controller.value.isInitialized; 92 | widget.controller.addListener(_listener); 93 | } 94 | } 95 | 96 | @override 97 | void deactivate() { 98 | super.deactivate(); 99 | widget.controller.removeListener(_listener); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /flutter_vlc_player/lib/src/vlc_app_life_cycle_observer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:flutter_vlc_player/src/vlc_player_controller.dart'; 3 | 4 | class VlcAppLifeCycleObserver extends Object with WidgetsBindingObserver { 5 | bool _wasPlayingBeforePause = false; 6 | final VlcPlayerController _controller; 7 | 8 | VlcAppLifeCycleObserver(this._controller); 9 | 10 | void initialize() { 11 | WidgetsBinding.instance.addObserver(this); 12 | } 13 | 14 | @override 15 | void didChangeAppLifecycleState(AppLifecycleState state) { 16 | switch (state) { 17 | case AppLifecycleState.paused: 18 | _wasPlayingBeforePause = _controller.value.isPlaying; 19 | _controller.pause(); 20 | case AppLifecycleState.resumed: 21 | if (_wasPlayingBeforePause) { 22 | _controller.play(); 23 | } 24 | default: 25 | } 26 | } 27 | 28 | void dispose() { 29 | WidgetsBinding.instance.removeObserver(this); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /flutter_vlc_player/lib/src/vlc_player_platform.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_vlc_player_platform_interface/flutter_vlc_player_platform_interface.dart'; 2 | 3 | final VlcPlayerPlatform vlcPlayerPlatform = 4 | VlcPlayerPlatform.instance 5 | // This will clear all open videos on the platform when a full restart is 6 | // performed. 7 | ..init(); 8 | -------------------------------------------------------------------------------- /flutter_vlc_player/lib/src/vlc_player_value.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/widgets.dart'; 4 | import 'package:flutter_vlc_player/src/enums/playing_state.dart'; 5 | 6 | /// The duration, current position, buffering state, error state and settings 7 | /// of a [VlcPlayerController]. 8 | class VlcPlayerValue { 9 | /// Define no error string 10 | static const String noError = ''; 11 | static const String unknownError = 'An Unknown Error Occurred!'; 12 | static const _maxVolume = 100; 13 | 14 | /// The total duration of the video. 15 | /// 16 | /// The duration is [Duration.zero] if the video hasn't been initialized. 17 | final Duration duration; 18 | 19 | /// The current playback position. 20 | final Duration position; 21 | 22 | /// The playing state of player 23 | final PlayingState playingState; 24 | 25 | /// True if the video is playing. False if it's paused or stopped. 26 | final bool isPlaying; 27 | 28 | /// True if the video is looping. 29 | final bool isLooping; 30 | 31 | /// True if the video is currently buffering. 32 | final bool isBuffering; 33 | 34 | /// True if the video is ended 35 | final bool isEnded; 36 | 37 | /// True if the video is recording. 38 | final bool isRecording; 39 | 40 | /// The current volume of the playback. 41 | final int volume; 42 | 43 | /// The buffer percent if the video is buffering. 44 | final double bufferPercent; 45 | 46 | /// The current speed of the playback. 47 | final double playbackSpeed; 48 | 49 | /// The video scale 50 | final double videoScale; 51 | 52 | /// The number of audio tracks in media 53 | final int audioTracksCount; 54 | 55 | /// The index of active audio track in media 56 | final int activeAudioTrack; 57 | 58 | /// The time delay of active audio track in millisecond 59 | final int audioDelay; 60 | 61 | /// The number of subtitle tracks in media 62 | final int spuTracksCount; 63 | 64 | /// The index of active subtitle track in media 65 | final int activeSpuTrack; 66 | 67 | /// The time delay of active subtitle track in millisecond 68 | final int spuDelay; 69 | 70 | /// The number of video tracks in media 71 | final int videoTracksCount; 72 | 73 | /// The index of active video track in media 74 | final int activeVideoTrack; 75 | 76 | /// The path of recorded file 77 | final String recordPath; 78 | 79 | /// A description of the error if present. 80 | /// 81 | /// If [hasError] is false this is [VlcPlayerValue.noError]. 82 | final String errorDescription; 83 | 84 | /// The [size] of the currently loaded video. 85 | /// 86 | /// The size is [Size.zero] if the video hasn't been initialized. 87 | final Size size; 88 | 89 | /// Indicates whether or not the vlc is ready to play. 90 | final bool isInitialized; 91 | 92 | /// Indicates whether or not the video is in an error state. If this is true 93 | /// [errorDescription] should have information about the problem. 94 | bool get hasError => errorDescription != VlcPlayerValue.noError; 95 | 96 | /// Returns [size.width] / [size.height] when the player is initialized, or `1.0.` when 97 | /// the player is not initialized or the aspect ratio would be less than or equal to 0.0. 98 | double get aspectRatio { 99 | if (!isInitialized || size.width == 0 || size.height == 0) { 100 | return 1.0; 101 | } 102 | final aspectRatio = size.width / size.height; 103 | if (aspectRatio <= 0) { 104 | return 1.0; 105 | } 106 | 107 | return aspectRatio; 108 | } 109 | 110 | /// Constructs a video with the given values. Only [duration] is required. The 111 | /// rest will initialize with default values when unset. 112 | VlcPlayerValue({ 113 | required this.duration, 114 | this.size = Size.zero, 115 | this.position = Duration.zero, 116 | this.playingState = PlayingState.initializing, 117 | this.isInitialized = false, 118 | this.isPlaying = false, 119 | this.isLooping = false, 120 | this.isBuffering = false, 121 | this.isEnded = false, 122 | this.isRecording = false, 123 | this.bufferPercent = 0.0, 124 | this.volume = _maxVolume, 125 | this.playbackSpeed = 1.0, 126 | this.videoScale = 1.0, 127 | this.audioTracksCount = 1, 128 | this.activeAudioTrack = 1, 129 | this.audioDelay = 0, 130 | this.spuTracksCount = 0, 131 | this.activeSpuTrack = -1, 132 | this.spuDelay = 0, 133 | this.videoTracksCount = 1, 134 | this.activeVideoTrack = 0, 135 | this.recordPath = '', 136 | this.errorDescription = VlcPlayerValue.noError, 137 | }); 138 | 139 | /// Returns an instance with a `null` [Duration]. 140 | factory VlcPlayerValue.uninitialized() { 141 | return VlcPlayerValue(duration: Duration.zero); 142 | } 143 | 144 | /// Returns an instance with the playing state error 145 | /// and the given [errorDescription]. 146 | factory VlcPlayerValue.erroneous(String? errorDescription) { 147 | return VlcPlayerValue( 148 | duration: Duration.zero, 149 | playingState: PlayingState.error, 150 | errorDescription: errorDescription ?? VlcPlayerValue.unknownError, 151 | ); 152 | } 153 | 154 | /// Returns a new instance that has the same values as this current instance, 155 | /// except for any overrides passed in as arguments to [copyWidth]. 156 | // ignore: number_of_parameters 157 | VlcPlayerValue copyWith({ 158 | Duration? duration, 159 | Size? size, 160 | Duration? position, 161 | PlayingState? playingState, 162 | bool? isInitialized, 163 | bool? isPlaying, 164 | bool? isLooping, 165 | bool? isBuffering, 166 | bool? isEnded, 167 | bool? isRecording, 168 | double? bufferPercent, 169 | int? volume, 170 | double? playbackSpeed, 171 | double? videoScale, 172 | int? audioTracksCount, 173 | int? activeAudioTrack, 174 | int? audioDelay, 175 | int? spuTracksCount, 176 | int? activeSpuTrack, 177 | int? spuDelay, 178 | int? videoTracksCount, 179 | int? activeVideoTrack, 180 | String? recordPath, 181 | String? errorDescription, 182 | }) { 183 | return VlcPlayerValue( 184 | duration: duration ?? this.duration, 185 | size: size ?? this.size, 186 | position: position ?? this.position, 187 | playingState: playingState ?? this.playingState, 188 | isInitialized: isInitialized ?? this.isInitialized, 189 | isPlaying: isPlaying ?? this.isPlaying, 190 | isLooping: isLooping ?? this.isLooping, 191 | isBuffering: isBuffering ?? this.isBuffering, 192 | isEnded: isEnded ?? this.isEnded, 193 | isRecording: isRecording ?? this.isRecording, 194 | bufferPercent: bufferPercent ?? this.bufferPercent, 195 | volume: volume ?? this.volume, 196 | playbackSpeed: playbackSpeed ?? this.playbackSpeed, 197 | videoScale: videoScale ?? this.videoScale, 198 | audioTracksCount: audioTracksCount ?? this.audioTracksCount, 199 | activeAudioTrack: activeAudioTrack ?? this.activeAudioTrack, 200 | audioDelay: audioDelay ?? this.audioDelay, 201 | spuTracksCount: spuTracksCount ?? this.spuTracksCount, 202 | activeSpuTrack: activeSpuTrack ?? this.activeSpuTrack, 203 | spuDelay: spuDelay ?? this.spuDelay, 204 | videoTracksCount: videoTracksCount ?? this.videoTracksCount, 205 | activeVideoTrack: activeVideoTrack ?? this.activeVideoTrack, 206 | recordPath: recordPath ?? this.recordPath, 207 | errorDescription: errorDescription ?? this.errorDescription, 208 | ); 209 | } 210 | 211 | @override 212 | String toString() { 213 | return 'VlcPlayerValue(' 214 | 'duration: $duration, ' 215 | 'size: $size, ' 216 | 'position: $position, ' 217 | 'playingState: $playingState, ' 218 | 'isInitialized $isInitialized, ' 219 | 'isPlaying: $isPlaying, ' 220 | 'isLooping: $isLooping, ' 221 | 'isBuffering: $isBuffering, ' 222 | 'isEnded: $isEnded, ' 223 | 'isRecording: $isRecording, ' 224 | 'bufferPercent: $bufferPercent, ' 225 | 'volume: $volume, ' 226 | 'playbackSpeed: $playbackSpeed, ' 227 | 'audioTracksCount: $audioTracksCount, ' 228 | 'activeAudioTrack: $activeAudioTrack, ' 229 | 'spuTracksCount: $spuTracksCount, ' 230 | 'activeSpuTrack: $activeSpuTrack, ' 231 | 'recordPath: $recordPath, ' 232 | 'errorDescription: $errorDescription)'; 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /flutter_vlc_player/pigeons/messages.dart: -------------------------------------------------------------------------------- 1 | import 'package:pigeon/pigeon.dart'; 2 | 3 | // to make changes effect, must run "dart run pigeon --input pigeons/messages.dart" 4 | @ConfigurePigeon( 5 | PigeonOptions( 6 | dartOut: 7 | '../flutter_vlc_player_platform_interface/lib/src/messages/messages.dart', 8 | swiftOut: 'ios/Classes/Messages.swift', 9 | javaOut: 10 | 'android/src/main/java/software/solid/fluttervlcplayer/Messages.java', 11 | javaOptions: JavaOptions(package: 'software.solid.fluttervlcplayer'), 12 | ), 13 | ) 14 | //ignore: prefer_match_file_name 15 | class CreateMessage { 16 | final int playerId; 17 | final String uri; 18 | final int type; 19 | final String? packageName; 20 | final bool autoPlay; 21 | final int? hwAcc; 22 | final List options; 23 | 24 | const CreateMessage({ 25 | required this.playerId, 26 | required this.uri, 27 | required this.type, 28 | required this.packageName, 29 | required this.autoPlay, 30 | required this.hwAcc, 31 | required this.options, 32 | }); 33 | } 34 | 35 | class SetMediaMessage { 36 | final int playerId; 37 | final String uri; 38 | final int type; 39 | final String? packageName; 40 | final bool autoPlay; 41 | final int? hwAcc; 42 | 43 | const SetMediaMessage({ 44 | required this.playerId, 45 | required this.uri, 46 | required this.type, 47 | required this.packageName, 48 | required this.autoPlay, 49 | required this.hwAcc, 50 | }); 51 | } 52 | 53 | class SpuTracksMessage { 54 | final int playerId; 55 | final Map subtitles; 56 | 57 | const SpuTracksMessage({required this.playerId, required this.subtitles}); 58 | } 59 | 60 | class AddSubtitleMessage { 61 | final int playerId; 62 | final String uri; 63 | final int type; 64 | final bool isSelected; 65 | 66 | const AddSubtitleMessage({ 67 | required this.playerId, 68 | required this.uri, 69 | required this.type, 70 | required this.isSelected, 71 | }); 72 | } 73 | 74 | class AddAudioMessage { 75 | final int playerId; 76 | final String uri; 77 | final int type; 78 | final bool isSelected; 79 | 80 | const AddAudioMessage({ 81 | required this.playerId, 82 | required this.uri, 83 | required this.type, 84 | required this.isSelected, 85 | }); 86 | } 87 | 88 | @HostApi(dartHostTestHandler: 'TestHostVlcPlayerApi') 89 | abstract class VlcPlayerApi { 90 | void initialize(); 91 | 92 | void create(CreateMessage msg); 93 | 94 | void dispose(int playerId); 95 | 96 | // general methods 97 | void setStreamUrl(SetMediaMessage msg); 98 | 99 | void play(int playerId); 100 | 101 | void pause(int playerId); 102 | 103 | void stop(int playerId); 104 | 105 | bool isPlaying(int playerId); 106 | 107 | bool isSeekable(int playerId); 108 | 109 | void setLooping(int playerId, bool isLooping); 110 | 111 | void seekTo(int playerId, int position); 112 | 113 | int position(int playerId); 114 | 115 | int duration(int playerId); 116 | 117 | void setVolume(int playerId, int volume); 118 | 119 | int getVolume(int playerId); 120 | 121 | void setPlaybackSpeed(int playerId, double speed); 122 | 123 | double getPlaybackSpeed(int playerId); 124 | 125 | String? takeSnapshot(int playerId); 126 | 127 | // captions & subtitles methods 128 | 129 | int getSpuTracksCount(int playerId); 130 | 131 | Map getSpuTracks(int playerId); 132 | 133 | void setSpuTrack(int playerId, int spuTrackNumber); 134 | 135 | int getSpuTrack(int playerId); 136 | 137 | void setSpuDelay(int playerId, int delay); 138 | 139 | int getSpuDelay(int playerId); 140 | 141 | void addSubtitleTrack(AddSubtitleMessage msg); 142 | 143 | // audios methods 144 | int getAudioTracksCount(int playerId); 145 | 146 | Map getAudioTracks(int playerId); 147 | 148 | void setAudioTrack(int playerId, int audioTrackNumber); 149 | 150 | int getAudioTrack(int playerId); 151 | 152 | void setAudioDelay(int playerId, int delay); 153 | 154 | int getAudioDelay(int playerId); 155 | 156 | void addAudioTrack(AddAudioMessage msg); 157 | 158 | // videos methods 159 | int getVideoTracksCount(int playerId); 160 | 161 | Map getVideoTracks(int playerId); 162 | 163 | void setVideoTrack(int playerId, int videoTrackNumber); 164 | 165 | int getVideoTrack(int playerId); 166 | 167 | void setVideoScale(int playerId, double scale); 168 | 169 | double getVideoScale(int playerId); 170 | 171 | void setVideoAspectRatio(int playerId, String aspectRatio); 172 | 173 | String getVideoAspectRatio(int playerId); 174 | 175 | // casts & renderers methods 176 | List getAvailableRendererServices(int playerId); 177 | 178 | void startRendererScanning(int playerId, String rendererService); 179 | 180 | void stopRendererScanning(int playerId); 181 | 182 | Map getRendererDevices(int playerId); 183 | 184 | void castToRenderer(int playerId, String rendererId); 185 | 186 | // recording methods 187 | bool startRecording(int playerId, String saveDirectory); 188 | 189 | bool stopRecording(int playerId); 190 | } 191 | -------------------------------------------------------------------------------- /flutter_vlc_player/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_vlc_player 2 | description: A VLC-powered alternative to Flutter's video_player. Supports multiple players on one screen. 3 | version: 7.4.3 4 | homepage: https://github.com/solid-software/flutter_vlc_player/ 5 | 6 | environment: 7 | sdk: ^3.7.0 8 | flutter: '>=3.3.0' 9 | 10 | flutter: 11 | plugin: 12 | platforms: 13 | android: 14 | package: software.solid.fluttervlcplayer 15 | pluginClass: FlutterVlcPlayerPlugin 16 | ios: 17 | pluginClass: FlutterVlcPlayerPlugin 18 | 19 | dependencies: 20 | flutter: 21 | sdk: flutter 22 | 23 | flutter_vlc_player_platform_interface: ^2.0.5 24 | meta: ^1.8.0 25 | 26 | dev_dependencies: 27 | flutter_test: 28 | sdk: flutter 29 | 30 | pigeon: ^25.2.0 31 | plugin_platform_interface: ^2.1.3 32 | solid_lints: ^0.3.0 33 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/.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_platform_interface/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.0.5 2 | 3 | - 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) 4 | - Update to Dart 3 and Flutter 3.13. Credits: @romaingyh 5 | 6 | ## 2.0.3 7 | 8 | - Fix http-user-agent. Credits: @afriza 9 | 10 | ## 2.0.2 11 | 12 | - Update dependencies 13 | 14 | ## 2.0.1 15 | 16 | - Add Hybrid composition support for Android 17 | 18 | ## 2.0.0 19 | 20 | - Fix Dart analysis warnings 21 | - Refactored enum parameters to follow dart naming convention 22 | 23 | ## 1.0.7 24 | 25 | - Add VLC http options 26 | 27 | ## 1.0.6 28 | 29 | - Added VLC recording feature 30 | 31 | ## 1.0.5 32 | 33 | - Upgrade to Null Safety 34 | 35 | ## 1.0.4 36 | 37 | - Add VLC subtitle options 38 | 39 | ## 1.0.3 40 | 41 | - Add isSeekable method to platform interface 42 | 43 | ## 1.0.2 44 | 45 | - Improve the interface to support more reliable memory management. 46 | 47 | ## 1.0.1 48 | 49 | - Add pedantic, fix build issues. 50 | 51 | ## 1.0.0 52 | 53 | - Initial open-source release. 54 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/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_platform_interface/README.md: -------------------------------------------------------------------------------- 1 | # fluttter_vlc_player_platform_interface 2 | 3 | A common platform interface for the [`vlc`][1] plugin. 4 | 5 | This interface allows platform-specific implementations of the `vlc` 6 | plugin, as well as the plugin itself, to ensure they are supporting the 7 | same interface. 8 | 9 | # Usage 10 | 11 | To implement a new platform-specific implementation of `vlc`, extend 12 | [`VlcPlatform`][2] with an implementation that performs the 13 | platform-specific behavior, and when you register your plugin, set the default 14 | `VlcPlatform` by calling 15 | `VlcPlatform.instance = MyPlatformVlc()`. 16 | 17 | # Note on breaking changes 18 | 19 | Strongly prefer non-breaking changes (such as adding a method to the interface) 20 | over breaking changes for this package. 21 | 22 | See https://flutter.dev/go/platform-interface-breaking-changes for a discussion 23 | on why a less-clean interface is preferable to a breaking change. 24 | 25 | [1]: ../vlc 26 | [2]: lib/vlc_platform_interface.dart -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:solid_lints/analysis_options.yaml 2 | 3 | dart_code_metrics: 4 | metrics: 5 | cyclomatic-complexity: 40 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 | 14 | analyzer: 15 | exclude: 16 | - "**/messages.dart" -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/flutter_vlc_player_platform_interface.dart: -------------------------------------------------------------------------------- 1 | export 'src/enums/data_source_type.dart'; 2 | export 'src/enums/hardware_acceleration.dart'; 3 | export 'src/enums/media_event_type.dart'; 4 | export 'src/enums/renderer_event_type.dart'; 5 | export 'src/enums/subtitles/vlc_subtitle_text_direction.dart'; 6 | export 'src/events/media_event.dart'; 7 | export 'src/events/renderer_event.dart'; 8 | export 'src/platform_interface/vlc_player_platform_interface.dart'; 9 | export 'src/utils/helpers/subtitles/vlc_subtitle_color.dart'; 10 | export 'src/utils/helpers/subtitles/vlc_subtitle_thickness.dart'; 11 | export 'src/utils/options/vlc_advanced_options.dart'; 12 | export 'src/utils/options/vlc_audio_options.dart'; 13 | export 'src/utils/options/vlc_http_options.dart'; 14 | export 'src/utils/options/vlc_player_options.dart'; 15 | export 'src/utils/options/vlc_rtp_options.dart'; 16 | export 'src/utils/options/vlc_stream_output_options.dart'; 17 | export 'src/utils/options/vlc_subtitle_options.dart'; 18 | export 'src/utils/options/vlc_video_options.dart'; 19 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/enums/data_source_type.dart: -------------------------------------------------------------------------------- 1 | enum DataSourceType { 2 | /// The video was included in the app's asset files. 3 | asset, 4 | 5 | /// The video was downloaded from the internet. 6 | network, 7 | 8 | /// The video was loaded off of the local filesystem. 9 | file, 10 | } 11 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/enums/hardware_acceleration.dart: -------------------------------------------------------------------------------- 1 | // ignore: prefer_match_file_name 2 | enum HwAcc { auto, disabled, decoding, full } 3 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/enums/media_event_type.dart: -------------------------------------------------------------------------------- 1 | // ignore: prefer_match_file_name 2 | enum VlcMediaEventType { 3 | opening, 4 | playing, 5 | paused, 6 | stopped, 7 | buffering, 8 | recording, 9 | timeChanged, 10 | mediaChanged, 11 | ended, 12 | unknown, 13 | error, 14 | } 15 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/enums/renderer_event_type.dart: -------------------------------------------------------------------------------- 1 | // ignore: prefer_match_file_name 2 | enum VlcRendererEventType { attached, detached, unknown } 3 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/enums/subtitles/vlc_subtitle_text_direction.dart: -------------------------------------------------------------------------------- 1 | enum VlcSubtitleTextDirection { ltr, rtl, auto } 2 | 3 | extension VlcSubtitleTextDirectionExtensionMap on VlcSubtitleTextDirection { 4 | static const valueMap = { 5 | VlcSubtitleTextDirection.ltr: 0, 6 | VlcSubtitleTextDirection.rtl: 1, 7 | VlcSubtitleTextDirection.auto: 2, 8 | }; 9 | int? get value => valueMap[this]; 10 | } 11 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/events/media_event.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter_vlc_player_platform_interface/src/enums/media_event_type.dart'; 4 | 5 | // ignore: prefer_match_file_name 6 | class VlcMediaEvent { 7 | /// The type of the event. 8 | final VlcMediaEventType mediaEventType; 9 | 10 | /// Size of the video. 11 | /// 12 | /// Only used if [eventType] is [VlcMediaEventType.buffering, VlcMediaEventType.playing]. 13 | final Size? size; 14 | 15 | /// Duration of the video. 16 | /// 17 | /// Only used if [eventType] is [VlcMediaEventType.buffering, VlcMediaEventType.playing]. 18 | final Duration? duration; 19 | 20 | /// Position of the video. 21 | /// 22 | /// Only used if [eventType] is [VlcMediaEventType.buffering]. 23 | final Duration? position; 24 | 25 | /// Playback speed of the video. 26 | /// 27 | /// Only used if [eventType] is [VlcMediaEventType.buffering, VlcMediaEventType.playing]. 28 | final double? playbackSpeed; 29 | 30 | /// The number of available audio tracks embedded in media except the original audio. 31 | /// 32 | /// Only used if [eventType] is [VlcMediaEventType.buffering, VlcMediaEventType.playing]. 33 | final int? audioTracksCount; 34 | 35 | /// The active audio track index. "-1" means audio is disabled. 36 | /// 37 | /// Only used if [eventType] is [VlcMediaEventType.buffering, VlcMediaEventType.playing]. 38 | final int? activeAudioTrack; 39 | 40 | /// Returns the number of available subtitle tracks embedded in media. 41 | /// 42 | /// Only used if [eventType] is [VlcMediaEventType.buffering, VlcMediaEventType.playing]. 43 | final int? spuTracksCount; 44 | 45 | /// Returns the active subtitle track index. "-1" means subtitle is disabled. 46 | /// 47 | /// Only used if [eventType] is [VlcMediaEventType.buffering, VlcMediaEventType.playing]. 48 | final int? activeSpuTrack; 49 | 50 | /// Returns the buffer percent of media. 51 | /// 52 | /// Only used if [eventType] is [VlcMediaEventType.buffering]. 53 | final double? bufferPercent; 54 | 55 | /// Returns the playing state of media. 56 | /// 57 | /// Only used if [eventType] is [VlcMediaEventType.buffering]. 58 | final bool? isPlaying; 59 | 60 | /// Returns the recording state of media. 61 | /// 62 | /// Only used if [eventType] is [VlcMediaEventType.playing, VlcMediaEventType.recording]. 63 | final bool? isRecording; 64 | 65 | /// Returns the recording path of media. 66 | /// 67 | /// Only used if [eventType] is [VlcMediaEventType.recording]. 68 | final String? recordPath; 69 | 70 | /// Creates an instance of [VlcMediaEvent]. 71 | /// 72 | /// The [mediaEventType] argument is required. 73 | /// 74 | /// Depending on the [mediaEventType], the [duration], [size] 75 | /// arguments can be null. 76 | VlcMediaEvent({ 77 | required this.mediaEventType, 78 | this.duration, 79 | this.size, 80 | this.position, 81 | this.playbackSpeed, 82 | this.audioTracksCount, 83 | this.activeAudioTrack, 84 | this.spuTracksCount, 85 | this.activeSpuTrack, 86 | this.bufferPercent, 87 | this.isPlaying, 88 | this.isRecording, 89 | this.recordPath, 90 | }); 91 | } 92 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/events/renderer_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_vlc_player_platform_interface/src/enums/renderer_event_type.dart'; 2 | 3 | // ignore: prefer_match_file_name 4 | class VlcRendererEvent { 5 | /// The type of the event. 6 | final VlcRendererEventType eventType; 7 | 8 | /// The identifier of renderer device 9 | final String? rendererId; 10 | 11 | /// The name of cast device 12 | final String? rendererName; 13 | 14 | /// Creates an instance of [VlcRendererEvent]. 15 | /// 16 | /// The [eventType] argument is required. 17 | /// 18 | /// Depending on the [eventType], the [rendererId], [rendererName] 19 | VlcRendererEvent({ 20 | required this.eventType, 21 | this.rendererId, 22 | this.rendererName, 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/platform_interface/vlc_player_platform_interface.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/services.dart'; 4 | import 'package:flutter/widgets.dart'; 5 | import 'package:flutter_vlc_player_platform_interface/flutter_vlc_player_platform_interface.dart'; 6 | import 'package:flutter_vlc_player_platform_interface/src/method_channel/method_channel_vlc_player.dart'; 7 | import 'package:plugin_platform_interface/plugin_platform_interface.dart'; 8 | 9 | // ignore_for_file: prefer_match_file_name 10 | 11 | /// The interface that implementations of vlc must implement. 12 | /// 13 | /// Platform implementations should extend this class rather than implement it as `vlc` 14 | /// does not consider newly added methods to be breaking changes. 15 | abstract class VlcPlayerPlatform extends PlatformInterface { 16 | static final Object _token = Object(); 17 | 18 | static VlcPlayerPlatform _instance = MethodChannelVlcPlayer(); 19 | 20 | /// The default instance of [VlcPlayerPlatform] to use. 21 | /// 22 | /// Defaults to [MethodChannelVlcPlayer]. 23 | static VlcPlayerPlatform get instance => _instance; 24 | 25 | /// Platform-specific plugins should set this with their own platform-specific 26 | /// class that extends [VlcPlayerPlatform] when they register themselves. 27 | static set instance(VlcPlayerPlatform instance) { 28 | PlatformInterface.verifyToken(instance, _token); 29 | _instance = instance; 30 | } 31 | 32 | /// Constructs a VlcPlayerPlatform. 33 | VlcPlayerPlatform() : super(token: _token); 34 | 35 | // ignore: avoid_returning_widgets 36 | /// Returns a widget displaying the video. 37 | Widget buildView( 38 | PlatformViewCreatedCallback onPlatformViewCreated, { 39 | bool virtualDisplay = true, 40 | }) { 41 | throw _unimplemented('buildView'); 42 | } 43 | 44 | /// Initializes the platform interface and disposes all existing players. 45 | /// 46 | /// This method is called when the plugin is first initialized 47 | /// and on every full restart. 48 | Future init() { 49 | throw _unimplemented('init'); 50 | } 51 | 52 | /// Clears one video. 53 | Future dispose(int viewId) { 54 | throw _unimplemented('dispose'); 55 | } 56 | 57 | /// Creates an instance of a vlc player 58 | Future create({ 59 | required int viewId, 60 | required String uri, 61 | required DataSourceType type, 62 | String? package, 63 | bool? autoPlay, 64 | HwAcc? hwAcc, 65 | VlcPlayerOptions? options, 66 | }) { 67 | throw _unimplemented('create'); 68 | } 69 | 70 | /// Returns a Stream of [VlcMediaEvent]s. 71 | Stream mediaEventsFor(int viewId) { 72 | throw _unimplemented('mediaEventsFor'); 73 | } 74 | 75 | /// Set/Change video streaming url 76 | Future setStreamUrl( 77 | int viewId, { 78 | required String uri, 79 | required DataSourceType type, 80 | String? package, 81 | bool? autoPlay, 82 | HwAcc? hwAcc, 83 | }) { 84 | throw _unimplemented('setStreamUrl'); 85 | } 86 | 87 | /// Sets the looping attribute of the video. 88 | Future setLooping(int viewId, bool looping) { 89 | throw _unimplemented('setLooping'); 90 | } 91 | 92 | /// Starts the video playback. 93 | Future play(int viewId) { 94 | throw _unimplemented('play'); 95 | } 96 | 97 | /// Pauses the video playback. 98 | Future pause(int viewId) { 99 | throw _unimplemented('pause'); 100 | } 101 | 102 | /// Stops the video playback. 103 | Future stop(int viewId) { 104 | throw _unimplemented('stop'); 105 | } 106 | 107 | /// Returns true if media is playing. 108 | Future isPlaying(int viewId) { 109 | throw _unimplemented('isPlaying'); 110 | } 111 | 112 | /// Returns true if media is seekable. 113 | Future isSeekable(int viewId) { 114 | throw _unimplemented('isSeekable'); 115 | } 116 | 117 | /// Same as seekTo 118 | /// Sets the video position to a [Duration] from the start. 119 | Future setTime(int viewId, Duration position) { 120 | throw _unimplemented('setTime'); 121 | } 122 | 123 | /// Sets the video position to a [Duration] from the start. 124 | Future seekTo(int viewId, Duration position) { 125 | throw _unimplemented('seekTo'); 126 | } 127 | 128 | /// Same as getPosition 129 | /// Gets the video position as [Duration] from the start. 130 | Future getTime(int viewId) { 131 | throw _unimplemented('getTime'); 132 | } 133 | 134 | /// Gets the video position as [Duration] from the start. 135 | Future getPosition(int viewId) { 136 | throw _unimplemented('getPosition'); 137 | } 138 | 139 | /// Returns duration/length of loaded video in milliseconds. 140 | Future getDuration(int viewId) { 141 | throw _unimplemented('getDuration'); 142 | } 143 | 144 | /// Sets the volume to a range between 0 and 100. 145 | Future setVolume(int viewId, int volume) { 146 | throw _unimplemented('setVolume'); 147 | } 148 | 149 | /// Returns current vlc volume level within a range between 0 and 100. 150 | Future getVolume(int viewId) { 151 | throw _unimplemented('getVolume'); 152 | } 153 | 154 | /// Sets the playback speed to a [speed] value indicating the playback rate. 155 | Future setPlaybackSpeed(int viewId, double speed) { 156 | throw _unimplemented('setPlaybackSpeed'); 157 | } 158 | 159 | /// Returns the vlc playback speed. 160 | Future getPlaybackSpeed(int viewId) { 161 | throw _unimplemented('getPlaybackSpeed'); 162 | } 163 | 164 | /// Return the number of subtitle tracks (both embedded and inserted) 165 | Future getSpuTracksCount(int viewId) { 166 | throw _unimplemented('getSpuTracksCount'); 167 | } 168 | 169 | /// Return all subtitle tracks as array of 170 | /// The key parameter is the index of subtitle which is used for changing subtitle and the value is the display name of subtitle 171 | Future> getSpuTracks(int viewId) { 172 | throw _unimplemented('getSpuTracks'); 173 | } 174 | 175 | /// Change active subtitle index (set -1 to disable subtitle). 176 | /// [spuTrackNumber] - the subtitle index obtained from getSpuTracks() 177 | Future setSpuTrack(int viewId, int spuTrackNumber) { 178 | throw _unimplemented('setSpuTrack'); 179 | } 180 | 181 | /// Returns the selected spu track index 182 | Future getSpuTrack(int viewId) { 183 | throw _unimplemented('getSpuTrack'); 184 | } 185 | 186 | /// [delay] - the amount of time in milliseconds which vlc subtitle should be delayed. 187 | /// (support both positive & negative delay value) 188 | Future setSpuDelay(int viewId, int delay) { 189 | throw _unimplemented('setSpuDelay'); 190 | } 191 | 192 | /// Returns the amount of subtitle time delay. 193 | Future getSpuDelay(int viewId) { 194 | throw _unimplemented('getSpuDelay'); 195 | } 196 | 197 | /// Add extra subtitle to media. 198 | /// [uri] - URL of subtitle 199 | /// [type] - Set type of subtitle 200 | /// [isSelected] - Set true if you wanna force the added subtitle to start display on media. 201 | Future addSubtitleTrack( 202 | int viewId, { 203 | required String uri, 204 | required DataSourceType type, 205 | bool? isSelected, 206 | }) { 207 | throw _unimplemented('addSubtitleTrack'); 208 | } 209 | 210 | /// Returns the number of audio tracks 211 | Future getAudioTracksCount(int viewId) { 212 | throw _unimplemented('getAudioTracksCount'); 213 | } 214 | 215 | /// Returns all audio tracks as array of 216 | /// The key parameter is the index of audio track which is used for changing audio and the value is the display name of audio 217 | Future> getAudioTracks(int viewId) { 218 | throw _unimplemented('getAudioTracks'); 219 | } 220 | 221 | /// Returns selected audio track index 222 | Future getAudioTrack(int viewId) { 223 | throw _unimplemented('getAudioTrack'); 224 | } 225 | 226 | /// Change active audio track index (set -1 to mute). 227 | /// [audioTrackNumber] - the audio track index obtained from getAudioTracks() 228 | Future setAudioTrack(int viewId, int audioTrackNumber) { 229 | throw _unimplemented('setAudioTrack'); 230 | } 231 | 232 | /// [delay] - the amount of time in milliseconds which vlc audio should be delayed. 233 | /// (support both positive & negative value) 234 | Future setAudioDelay(int viewId, int delay) { 235 | throw _unimplemented('setAudioDelay'); 236 | } 237 | 238 | /// Returns the amount of audio track time delay. 239 | Future getAudioDelay(int viewId) { 240 | throw _unimplemented('getAudioDelay'); 241 | } 242 | 243 | /// Add extra audio to media. 244 | /// [uri] - uri of audio 245 | /// [type] - type of subtitle (network or file) 246 | /// [isSelected] - Set true if you wanna force the added subtitle to start display on media. 247 | Future addAudioTrack( 248 | int viewId, { 249 | required String uri, 250 | required DataSourceType type, 251 | bool? isSelected, 252 | }) { 253 | throw _unimplemented('addAudioTrack'); 254 | } 255 | 256 | /// Returns the number of video tracks 257 | Future getVideoTracksCount(int viewId) { 258 | throw _unimplemented('getVideoTracksCount'); 259 | } 260 | 261 | /// Returns all video tracks as array of 262 | /// The key parameter is the index of video track and the value is the display name of video track 263 | Future> getVideoTracks(int viewId) { 264 | throw _unimplemented('getVideoTracks'); 265 | } 266 | 267 | /// Change active video track index. 268 | /// [videoTrackNumber] - the video track index obtained from getVideoTracks() 269 | Future setVideoTrack(int viewId, int videoTrackNumber) { 270 | throw _unimplemented('setVideoTrack'); 271 | } 272 | 273 | /// Returns selected video track index 274 | Future getVideoTrack(int viewId) { 275 | throw _unimplemented('getVideoTrack'); 276 | } 277 | 278 | /// [scale] - the video scale value 279 | /// Set video scale 280 | Future setVideoScale(int viewId, double scale) { 281 | throw _unimplemented('setVideoScale'); 282 | } 283 | 284 | /// Returns video scale 285 | Future getVideoScale(int viewId) { 286 | throw _unimplemented('getVideoScale'); 287 | } 288 | 289 | /// [aspect] - the video aspect ratio like '16:9' 290 | /// Set video aspect ratio 291 | Future setVideoAspectRatio(int viewId, String aspect) { 292 | throw _unimplemented('setVideoAspectRatio'); 293 | } 294 | 295 | /// Returns video aspect ratio 296 | Future getVideoAspectRatio(int viewId) { 297 | throw _unimplemented('getVideoAspectRatio'); 298 | } 299 | 300 | /// Returns binary data for a snapshot of the media at the current frame. 301 | Future takeSnapshot(int viewId) { 302 | throw _unimplemented('takeSnapshot'); 303 | } 304 | 305 | /// Returns list of all available vlc renderer services 306 | Future> getAvailableRendererServices(int viewId) { 307 | throw _unimplemented('getAvailableRendererServices'); 308 | } 309 | 310 | /// Start vlc renderer discovery to find external display devices (chromecast) 311 | Future startRendererScanning(int viewId, {String? rendererService}) { 312 | throw _unimplemented('startRendererScanning'); 313 | } 314 | 315 | /// Stop vlc renderer and cast discovery 316 | Future stopRendererScanning(int viewId) { 317 | throw _unimplemented('stopRendererScanning'); 318 | } 319 | 320 | /// Returns all detected renderer devices as array of 321 | /// The key parameter is the name of renderer device and the value is the display name of renderer device 322 | Future> getRendererDevices(int viewId) { 323 | throw _unimplemented('getRendererDevices'); 324 | } 325 | 326 | /// [rendererDevice] - name of renderer device 327 | /// Start vlc video casting to the rendered device. 328 | /// Set null if you wanna to stop video casting. 329 | Future castToRenderer(int viewId, String rendererDevice) { 330 | throw _unimplemented('castToRenderer'); 331 | } 332 | 333 | /// Returns a Stream of [VlcRendererEvent]s. 334 | Stream rendererEventsFor(int viewId) { 335 | throw _unimplemented('rendererEventsFor'); 336 | } 337 | 338 | /// Returns true if vlc starts recording. 339 | Future startRecording(int viewId, String saveDirectory) { 340 | throw _unimplemented('startRecording'); 341 | } 342 | 343 | /// Returns true if vlc stops recording. 344 | Future stopRecording(int viewId) { 345 | throw _unimplemented('stopRecording'); 346 | } 347 | 348 | Object _unimplemented(String methodName) { 349 | return UnimplementedError('$methodName has not been implemented.'); 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/utils/helpers/subtitles/vlc_subtitle_color.dart: -------------------------------------------------------------------------------- 1 | class VlcSubtitleColor { 2 | static const _bitsInByte = 8; 3 | static const _redHexOffset = 2 * _bitsInByte; 4 | static const _greenHexOffset = _bitsInByte; 5 | static const black = VlcSubtitleColor(0); 6 | static const gray = VlcSubtitleColor(8421504); 7 | static const silver = VlcSubtitleColor(12632256); 8 | static const white = VlcSubtitleColor(16777215); 9 | static const maroon = VlcSubtitleColor(8388608); 10 | static const red = VlcSubtitleColor(16711680); 11 | static const fuchsia = VlcSubtitleColor(16711935); 12 | static const yellow = VlcSubtitleColor(16776960); 13 | static const olive = VlcSubtitleColor(8421376); 14 | static const green = VlcSubtitleColor(32768); 15 | static const teal = VlcSubtitleColor(32896); 16 | static const lime = VlcSubtitleColor(65280); 17 | static const purple = VlcSubtitleColor(8388736); 18 | static const navy = VlcSubtitleColor(128); 19 | static const blue = VlcSubtitleColor(255); 20 | static const aqua = VlcSubtitleColor(65535); 21 | 22 | final int value; 23 | const VlcSubtitleColor(this.value); 24 | const VlcSubtitleColor.rgb({int red = 0, int green = 0, int blue = 0}) 25 | : value = (red << _redHexOffset) + (green << _greenHexOffset) + blue; 26 | } 27 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/utils/helpers/subtitles/vlc_subtitle_thickness.dart: -------------------------------------------------------------------------------- 1 | class VlcSubtitleThickness { 2 | static const none = VlcSubtitleThickness(0); 3 | static const thin = VlcSubtitleThickness(2); 4 | static const normal = VlcSubtitleThickness(4); 5 | static const thick = VlcSubtitleThickness(6); 6 | 7 | final int value; 8 | const VlcSubtitleThickness(this.value); 9 | } 10 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/utils/options/vlc_advanced_options.dart: -------------------------------------------------------------------------------- 1 | class VlcAdvancedOptions { 2 | final List options; 3 | 4 | VlcAdvancedOptions(this.options); 5 | 6 | /// Caching value for local files, in milliseconds. 7 | static String fileCaching(int millis) { 8 | return '--file-caching=$millis'; 9 | } 10 | 11 | /// Caching value for network resources, in milliseconds. 12 | static String networkCaching(int millis) { 13 | return '--network-caching=$millis'; 14 | } 15 | 16 | /// Caching value for cameras and microphones, in milliseconds. 17 | static String liveCaching(int millis) { 18 | return '--live-caching=$millis'; 19 | } 20 | 21 | /// It is possible to disable the input clock synchronisation for 22 | /// real-time sources. Use this if you experience jerky playback of 23 | /// network streams. {-1 (Default), 0 (Disable), 1 (Enable)} 24 | static String clockSynchronization(int mode) { 25 | return '--clock-synchro=$mode'; 26 | } 27 | 28 | /// This defines the maximum input delay jitter that the synchronization 29 | /// algorithms should try to compensate (in milliseconds). 30 | static String clockJitter(int millis) { 31 | return '--clock-jitter=$millis'; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/utils/options/vlc_audio_options.dart: -------------------------------------------------------------------------------- 1 | class VlcAudioOptions { 2 | final List options; 3 | 4 | VlcAudioOptions(this.options); 5 | 6 | /// Enable/Disable time stretching audio 7 | /// This allows playing audio at lower or higher speed without affecting 8 | /// the audio pitch 9 | static String audioTimeStretch(bool enable) { 10 | return enable ? '--audio-time-stretch' : '--no-audio-time-stretch'; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/utils/options/vlc_http_options.dart: -------------------------------------------------------------------------------- 1 | class VlcHttpOptions { 2 | final List options; 3 | 4 | VlcHttpOptions(this.options); 5 | 6 | /// Automatically try to reconnect to the stream in case of a sudden disconnect. 7 | /// (default disabled) 8 | static String httpReconnect(bool enable) { 9 | return enable ? '--http-reconnect' : '--no-http-reconnect'; 10 | } 11 | 12 | /// Keep reading a resource that keeps being updated. 13 | /// (default disabled) 14 | static String httpContinuous(bool enable) { 15 | return enable ? '--http-continuous' : '--no-http-continuous'; 16 | } 17 | 18 | /// Forward cookies across HTTP redirections. 19 | /// (default enabled) 20 | static String httpForwardCookies(bool enable) { 21 | return enable ? '--http-forward-cookies' : '--no-http-forward-cookies'; 22 | } 23 | 24 | /// Provide the referral URL, i.e. HTTP "Referer" (sic). 25 | static String httpReferrer(String referrer) { 26 | return '--http-referrer=$referrer'; 27 | } 28 | 29 | /// Override the name and version of the application as provided to the 30 | /// HTTP server, i.e. the HTTP "User-Agent". Name and version must be 31 | /// separated by a forward slash, e.g. "FooBar/1.2.3". 32 | static String httpUserAgent(String userAgent) { 33 | // Use colon (:) instead of dashes. 34 | // See https://stackoverflow.com/a/52127734/109747 35 | return ':http-user-agent=$userAgent'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/utils/options/vlc_player_options.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_vlc_player_platform_interface/src/utils/options/vlc_advanced_options.dart'; 2 | import 'package:flutter_vlc_player_platform_interface/src/utils/options/vlc_audio_options.dart'; 3 | import 'package:flutter_vlc_player_platform_interface/src/utils/options/vlc_http_options.dart'; 4 | import 'package:flutter_vlc_player_platform_interface/src/utils/options/vlc_rtp_options.dart'; 5 | import 'package:flutter_vlc_player_platform_interface/src/utils/options/vlc_stream_output_options.dart'; 6 | import 'package:flutter_vlc_player_platform_interface/src/utils/options/vlc_subtitle_options.dart'; 7 | import 'package:flutter_vlc_player_platform_interface/src/utils/options/vlc_video_options.dart'; 8 | 9 | class VlcPlayerOptions { 10 | final VlcAdvancedOptions? advanced; 11 | final VlcAudioOptions? audio; 12 | final VlcHttpOptions? http; 13 | final VlcVideoOptions? video; 14 | final VlcSubtitleOptions? subtitle; 15 | final VlcRtpOptions? rtp; 16 | final VlcStreamOutputOptions? sout; 17 | final List? extras; 18 | 19 | VlcPlayerOptions({ 20 | this.advanced, 21 | this.audio, 22 | this.http, 23 | this.video, 24 | this.subtitle, 25 | this.rtp, 26 | this.sout, 27 | this.extras, 28 | }); 29 | 30 | List get() { 31 | final options = []; 32 | if (advanced != null) options.addAll(advanced?.options ?? []); 33 | if (audio != null) options.addAll(audio?.options ?? []); 34 | if (http != null) options.addAll(http?.options ?? []); 35 | if (video != null) options.addAll(video?.options ?? []); 36 | if (subtitle != null) options.addAll(subtitle?.options ?? []); 37 | if (rtp != null) options.addAll(rtp?.options ?? []); 38 | if (sout != null) options.addAll(sout?.options ?? []); 39 | if (extras != null) options.addAll(extras ?? []); 40 | 41 | return options; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/utils/options/vlc_rtp_options.dart: -------------------------------------------------------------------------------- 1 | class VlcRtpOptions { 2 | final List options; 3 | 4 | VlcRtpOptions(this.options); 5 | 6 | /// Use RTP over RTSP (TCP) 7 | static String rtpOverRtsp(bool enable) { 8 | return enable ? '--rtsp-tcp' : '--no-rtsp-tcp'; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/utils/options/vlc_stream_output_options.dart: -------------------------------------------------------------------------------- 1 | class VlcStreamOutputOptions { 2 | final List options; 3 | 4 | VlcStreamOutputOptions(this.options); 5 | 6 | /// Stream output muxer caching (ms) 7 | /// This allow you to configure the initial caching amount for stream 8 | /// output muxer. This value should be set in milliseconds. 9 | static String soutMuxCaching(int millis) { 10 | return '--sout-mux-caching=$millis'; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/utils/options/vlc_subtitle_options.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_vlc_player_platform_interface/src/enums/subtitles/vlc_subtitle_text_direction.dart'; 2 | import 'package:flutter_vlc_player_platform_interface/src/utils/helpers/subtitles/vlc_subtitle_color.dart'; 3 | import 'package:flutter_vlc_player_platform_interface/src/utils/helpers/subtitles/vlc_subtitle_thickness.dart'; 4 | 5 | class VlcSubtitleOptions { 6 | final List options; 7 | 8 | VlcSubtitleOptions(this.options); 9 | 10 | /// Set subtitle font (must be accessible by vlc) 11 | static String font(String font) { 12 | return '--freetype-font=$font'; 13 | } 14 | 15 | /// Set subtitle mono font (must be accessible by vlc) 16 | static String monofont(String monofont) { 17 | return '--freetype-monofont=$monofont'; 18 | } 19 | 20 | /// Set subtitle font size 21 | static String fontSize(int size) { 22 | return '--freetype-fontsize=$size'; 23 | } 24 | 25 | /// Set subtitle relative font size 26 | static String relativeFontSize(int size) { 27 | return '--freetype-rel-fontsize=$size'; 28 | } 29 | 30 | /// Enable/Disable subtitle bold style 31 | static String boldStyle(bool enable) { 32 | return enable ? '--freetype-bold' : '--no-freetype-bold'; 33 | } 34 | 35 | /// Set subtitle opacity [0 .. 255] 36 | static String opacity(int opacity) { 37 | return '--freetype-opacity=$opacity'; 38 | } 39 | 40 | /// Set subtitle color 41 | static String color(VlcSubtitleColor color) { 42 | return '--freetype-color=${color.value}'; 43 | } 44 | 45 | /// Set subtitle text direction {0 (Left to right), 1 (Right to left), 2 (Auto)} 46 | static String textDirection(VlcSubtitleTextDirection direction) { 47 | return '--freetype-text-direction=${direction.value}'; 48 | } 49 | 50 | /// Set subtitle background opacity [0 .. 255] 51 | static String backgroundOpacity(int opacity) { 52 | return '--freetype-background-opacity=$opacity'; 53 | } 54 | 55 | /// Set subtitle background color 56 | static String backgroundColor(VlcSubtitleColor color) { 57 | return '--freetype-background-color=${color.value}'; 58 | } 59 | 60 | /// Set subtitle outline opacity [0 .. 255] 61 | static String outlineOpacity(int opacity) { 62 | return '--freetype-outline-opacity=$opacity'; 63 | } 64 | 65 | /// Set subtitle outline color 66 | static String outlineColor(VlcSubtitleColor color) { 67 | return '--freetype-outline-color=${color.value}'; 68 | } 69 | 70 | /// Set subtitle outline thickness {0 (None), 2 (Thin), 4 (Normal), 6 (Thick)} 71 | static String outlineThickness(VlcSubtitleThickness thickness) { 72 | return '--freetype-outline-thickness=${thickness.value}'; 73 | } 74 | 75 | /// Set subtitle shadow opacity [0 .. 255] 76 | static String shadowOpacity(int opacity) { 77 | return '--freetype-shadow-opacity=$opacity'; 78 | } 79 | 80 | /// Set subtitle shadow color 81 | static String shadowColor(VlcSubtitleColor color) { 82 | return '--freetype-shadow-color=${color.value}'; 83 | } 84 | 85 | /// Set subtitle shadow angle [-360.000000 .. 360.000000] 86 | static String shadowAngle(double angle) { 87 | return '--freetype-shadow-angle=$angle'; 88 | } 89 | 90 | /// Set subtitle shadow distance in [0.000000 .. 1.000000] 91 | static String shadowDistance(double distance) { 92 | return '--freetype-shadow-distance=$distance'; 93 | } 94 | 95 | /// Enable/Disable subtitle yuvp renderer 96 | static String yuvpRenderer(bool enable) { 97 | return enable ? '--freetype-yuvp' : '--no-freetype-yuvp'; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/lib/src/utils/options/vlc_video_options.dart: -------------------------------------------------------------------------------- 1 | class VlcVideoOptions { 2 | final List options; 3 | 4 | VlcVideoOptions(this.options); 5 | 6 | /// Drop late frames 7 | /// This drops frames that are late (arrive to the video output after 8 | /// their intended display date). 9 | static String dropLateFrames(bool enable) { 10 | return enable ? '--drop-late-frames' : '--no-drop-late-frames'; 11 | } 12 | 13 | /// Skip frames 14 | /// Enables framedropping on MPEG2 stream. Framedropping occurs when your 15 | /// computer is not powerful enough 16 | static String skipFrames(bool enable) { 17 | return enable ? '--skip-frames' : '--no-skip-frames'; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /flutter_vlc_player_platform_interface/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_vlc_player_platform_interface 2 | description: A common platform interface for the flutter vlc player plugin. 3 | homepage: https://github.com/solid-software/flutter_vlc_player 4 | version: 2.0.5 5 | 6 | environment: 7 | sdk: ^3.7.0 8 | flutter: '>=3.3.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | meta: ^1.16.0 14 | plugin_platform_interface: ^2.1.8 15 | 16 | dev_dependencies: 17 | flutter_test: 18 | sdk: flutter 19 | 20 | mockito: ^5.3.2 21 | solid_lints: ^0.3.0 22 | --------------------------------------------------------------------------------