├── .all-contributorsrc ├── .gitattributes ├── .github └── ISSUE_TEMPLATE │ ├── -------.md │ ├── ----.md │ ├── --bug.md │ ├── bug_report.md │ ├── feature_request.md │ └── need-help.md ├── .gitignore ├── .metadata ├── .vscode ├── launch.json └── settings.json ├── BUG.md ├── CHANGELOG.md ├── CONTRIBUTING.md ├── FAQ.md ├── LICENSE ├── README-EN.md ├── README.md ├── TODOLIST.md ├── android ├── .classpath ├── .gitignore ├── .project ├── .settings │ └── org.eclipse.buildship.core.prefs ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── proguard-rules.pro ├── settings.gradle ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ ├── top │ │ │ └── kikt │ │ │ │ └── ijkplayer │ │ │ │ ├── FileMediaDataSource.java │ │ │ │ ├── Ijk.kt │ │ │ │ ├── IjkManager.kt │ │ │ │ ├── Log.kt │ │ │ │ ├── NotifyChannel.kt │ │ │ │ └── entity │ │ │ │ ├── IjkOption.kt │ │ │ │ └── Info.kt │ │ └── tv │ │ │ └── danmaku │ │ │ └── ijk │ │ │ └── media │ │ │ └── player │ │ │ ├── AbstractMediaPlayer.java │ │ │ ├── AndroidMediaPlayer.java │ │ │ ├── IMediaPlayer.java │ │ │ ├── ISurfaceTextureHolder.java │ │ │ ├── ISurfaceTextureHost.java │ │ │ ├── IjkLibLoader.java │ │ │ ├── IjkMediaCodecInfo.java │ │ │ ├── IjkMediaMeta.java │ │ │ ├── IjkMediaPlayer.java │ │ │ ├── IjkTimedText.java │ │ │ ├── MediaInfo.java │ │ │ ├── MediaPlayerProxy.java │ │ │ ├── TextureMediaPlayer.java │ │ │ ├── annotations │ │ │ ├── AccessedByNative.java │ │ │ └── CalledByNative.java │ │ │ ├── exceptions │ │ │ └── IjkMediaException.java │ │ │ ├── ffmpeg │ │ │ └── FFmpegApi.java │ │ │ ├── misc │ │ │ ├── AndroidMediaFormat.java │ │ │ ├── AndroidTrackInfo.java │ │ │ ├── IAndroidIO.java │ │ │ ├── IMediaDataSource.java │ │ │ ├── IMediaFormat.java │ │ │ ├── ITrackInfo.java │ │ │ ├── IjkMediaFormat.java │ │ │ └── IjkTrackInfo.java │ │ │ └── pragma │ │ │ ├── DebugLog.java │ │ │ └── Pragma.java │ │ ├── kotlin │ │ └── top │ │ │ └── kikt │ │ │ └── ijkplayer │ │ │ └── IjkplayerPlugin.kt │ │ └── libs │ │ ├── arm64-v8a │ │ ├── libijkffmpeg.so │ │ ├── libijkplayer.so │ │ └── libijksdl.so │ │ ├── armeabi-v7a │ │ ├── libijkffmpeg.so │ │ ├── libijkplayer.so │ │ └── libijksdl.so │ │ ├── x86 │ │ ├── libijkffmpeg.so │ │ ├── libijkplayer.so │ │ └── libijksdl.so │ │ └── x86_64 │ │ ├── libijkffmpeg.so │ │ ├── libijkplayer.so │ │ └── libijksdl.so └── switch_env.sh ├── compile-cn.md ├── compile.md ├── example ├── .flutter-plugins-dependencies ├── .gitignore ├── .metadata ├── README.md ├── android │ ├── .project │ ├── .settings │ │ └── org.eclipse.buildship.core.prefs │ ├── app │ │ ├── .classpath │ │ ├── .project │ │ ├── .settings │ │ │ └── org.eclipse.buildship.core.prefs │ │ ├── arm64.gradle │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── ijkplayer_example │ │ │ │ │ └── MainActivity.java │ │ │ └── res │ │ │ │ ├── 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 │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── example-key.jks │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── assets │ └── sample1.mp4 ├── ios │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ ├── Flutter.podspec │ │ ├── Release.xcconfig │ │ └── flutter_export_environment.sh │ ├── Podfile │ ├── Podfile.lock │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── 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 │ │ └── main.m ├── lib │ ├── const │ │ ├── resource.dart │ │ └── video_datasource.dart │ ├── i18n │ │ ├── cn.dart │ │ ├── en.dart │ │ └── i18n.dart │ ├── main.dart │ ├── page │ │ ├── asset_page.dart │ │ ├── auto_full_screen.dart │ │ ├── controller_stream_use.dart │ │ ├── custom_ijk_opt_page.dart │ │ ├── developing │ │ │ ├── crash_on_set_src_page.dart │ │ │ ├── develop_index.dart │ │ │ ├── develop_prepare_page.dart │ │ │ ├── live_interruption_page.dart │ │ │ ├── new_full_screen_page.dart │ │ │ ├── src_error_page.dart │ │ │ └── test_hide_system_bar.dart │ │ ├── dialog_video_page.dart │ │ ├── error_url.dart │ │ ├── full_screen.dart │ │ ├── gallery_page.dart │ │ ├── ijk_status_page.dart │ │ ├── in_overlay_page.dart │ │ ├── index.dart │ │ ├── network.dart │ │ ├── paging_page.dart │ │ ├── screen_shot_page.dart │ │ ├── simple_use.dart │ │ ├── speed_page.dart │ │ └── video_list.dart │ └── utils │ │ └── options_utils.dart ├── pubspec.yaml └── test │ └── widget_test.dart ├── ijkplayer.iml ├── ios ├── .gitignore ├── Assets │ └── .gitkeep ├── Classes │ ├── CoolFlutterIJK.h │ ├── CoolFlutterIJK.m │ ├── CoolFlutterIjkManager.h │ ├── CoolFlutterIjkManager.m │ ├── CoolFlutterResult.h │ ├── CoolFlutterResult.m │ ├── CoolIjkNotifyChannel.h │ ├── CoolIjkNotifyChannel.m │ ├── CoolIjkOption.h │ ├── CoolIjkOption.m │ ├── CoolVideoInfo.h │ ├── CoolVideoInfo.m │ ├── FlutterViewController+CoolStatusBarHidden.h │ ├── FlutterViewController+CoolStatusBarHidden.m │ ├── IjkplayerPlugin.h │ └── IjkplayerPlugin.m ├── flutter_ijkplayer.dev.podspec ├── flutter_ijkplayer.podspec ├── flutter_ijkplayer.prod.podspec └── switch_local.sh ├── lib ├── flutter_ijkplayer.dart └── src │ ├── controller │ ├── controller.dart │ ├── datasoure.dart │ ├── enums.dart │ ├── ijk_event_channel.dart │ ├── ijkplayer_controller_mixin.dart │ └── plugin.dart │ ├── engine │ ├── ijk_controller_manager.dart │ └── manager.dart │ ├── entity │ ├── options.dart │ └── video_info.dart │ ├── error.dart │ ├── helper │ ├── config.dart │ ├── full_screen_helper.dart │ ├── logutil.dart │ ├── time_helper.dart │ └── ui_helper.dart │ ├── ijkplayer.dart │ ├── route │ └── fullscreen_route.dart │ └── widget │ ├── controller_widget_builder.dart │ ├── full_screen.part.dart │ ├── ijk_status_widget.dart │ ├── ijkplayer_builder.dart │ └── progress_bar.dart ├── package.json ├── pubspec.yaml ├── svg └── logo.html └── yarn.lock /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "flutter_ijkplayer", 3 | "projectOwner": "caijinglong", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "CONTRIBUTING.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": true, 11 | "commitConvention": "gitmoji", 12 | "contributors": [ 13 | { 14 | "login": "CaiJingLong", 15 | "name": "Caijinglong", 16 | "avatar_url": "https://avatars0.githubusercontent.com/u/14145407?v=4", 17 | "profile": "https://www.kikt.top", 18 | "contributions": [ 19 | "code", 20 | "design" 21 | ] 22 | }, 23 | { 24 | "login": "gwuhaolin", 25 | "name": "浩麟", 26 | "avatar_url": "https://avatars2.githubusercontent.com/u/5773264?v=4", 27 | "profile": "https://github.com/gwuhaolin", 28 | "contributions": [ 29 | "code" 30 | ] 31 | } 32 | ], 33 | "contributorsPerLine": 7 34 | } 35 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ios/IJKMediaFramework.framework/IJKMediaFramework filter=lfs diff=lfs merge=lfs -text 2 | *.java linguist-language=dart 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/-------.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 如何使用这个库 3 | about: 关于这个库使用上的问题 4 | title: '[Need help]' 5 | labels: help wanted, wait confirm 6 | assignees: '' 7 | --- 8 | 9 | ** 简单描述 ** 10 | 简单描述你遇到的问题 11 | 12 | ** 辅助信息 ** 13 | 14 | 添加一些截图/设计图以便于可以让别人理解你遇到的问题 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/----.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 功能请求 3 | about: 关于功能的请求或建议 4 | title: '[Feature request]' 5 | labels: wait confirm 6 | assignees: '' 7 | --- 8 | 9 | **功能描述** 10 | 11 | **添加辅助信息帮助明确** 12 | 13 | 添加原型/截图/UI 设计图等方式帮助开发者明确需求,以评估是否应该是插件做的事情 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 报告bug 3 | about: 报告一个bug以帮助开发者定位,或解决问题 4 | title: '[Bug]' 5 | labels: wait confirm 6 | assignees: '' 7 | --- 8 | 9 | **描述一下你遇到的 bug** 10 | 描述一下你的 bug 11 | 12 | **重现 bug** 13 | 14 | 通过什么样的步骤可以重现: 15 | 16 | 1. Go to '...' 17 | 2. Click on '....' 18 | 3. Scroll down to '....' 19 | 4. See error 20 | 21 | **日志** 22 | 23 | ``` 24 | 25 | ``` 26 | 27 | **flutter 版本** 28 | 使用 `$ flutter doctor -v` 并粘贴详细的信息到这里,如果是特定机型的 bug,请包含设备信息 29 | 30 | ```bash 31 | 32 | ``` 33 | 34 | **插件版本** 35 | 36 | **截图** 37 | 如果有,请截图 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[Bug report]" 5 | labels: wait confirm 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Flutter version** 24 | Use `$ flutter doctor -v` and paste info to this. 25 | 26 | **Plugin version** 27 | Example: 0.x.x 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[Feature Request]" 5 | labels: wait confirm 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Simple description ** 11 | 12 | **Describe the solution you'd like** 13 | Explain your detailed requirements in order to assess whether you will join the development plan. 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/need-help.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Need help 3 | about: Describe your needs, see if anyone can help you. 4 | title: "[Need help]" 5 | labels: help wanted, wait confirm 6 | assignees: '' 7 | 8 | --- 9 | 10 | Describe your needs 11 | 12 | If possible, add prototypes / designs and other supporting documents to help others understand your needs. 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | .idea 9 | doc/ 10 | pubspec.lock 11 | fvm 12 | 13 | node_modules -------------------------------------------------------------------------------- /.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: 7fc14a55af64462763d28abfb4e610086c6e0f39 8 | channel: dev 9 | 10 | project_type: plugin 11 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Flutter", 9 | "request": "launch", 10 | "type": "dart", 11 | "program": "example/lib/main.dart" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "dart.flutterSdkPath": "/Users/caijinglong/Library/Flutter/flutter_dev" 3 | } -------------------------------------------------------------------------------- /BUG.md: -------------------------------------------------------------------------------- 1 | ## all 2 | 3 | - [x] 全屏模式可自定义 4 | 5 | ## iOS 6 | 7 | - [x] 全屏模式在 iphone xs max 上未全屏 8 | 9 | ## android 10 | 11 | - [x] 一些 m3u8 无声音 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.3.6 2 | 3 | New feature 4 | 5 | - Support playing video directly through photo_manager URL. 6 | 7 | Fix: 8 | 9 | - iOS 10 | 11 | - Support hardware decoding in iOS. 12 | - Fix hardware decoding memory leaks error. 13 | - Support screenshot in hardware-decoding. 14 | 15 | - android 16 | - [#204](https://github.com/CaiJingLong/flutter_ijkplayer/pull/204) 17 | 18 | ## 0.3.5+1 19 | 20 | To adapt to the new version of the flutter sdk check kt plugin. 21 | 22 | ## 0.3.5 23 | 24 | Feature: 25 | 26 | - Auto hide the status bar when full screen and show in exit. 27 | - Add callback when the full screen state changes for `DefaultIJKControllerWidget`. 28 | 29 | ## 0.3.4 30 | 31 | Fix: 32 | 33 | - The fps of the autoplayed datasource is always 3. 34 | 35 | ## 0.3.3 36 | 37 | Migrate ios pod library from github to azure. 38 | 39 | There is no code modification compared to 0.3.2. 40 | 41 | ## 0.3.2 42 | 43 | Fix: 44 | 45 | - Touch gesture problem 46 | - Missing plugin error message 47 | 48 | ## 0.3.1 49 | 50 | Update: 51 | 52 | - Use a new full screen type: Now, use `RotateBox` to rotate IjkPlayer. 53 | 54 | ## 0.3.0 55 | 56 | Fix: [#91](https://github.com/CaiJingLong/flutter_ijkplayer/issues/91) 57 | 58 | - Fix: for android annotation @Nonnull 59 | 60 | ## 0.2.9 61 | 62 | Fix: [#87](https://github.com/CaiJingLong/flutter_ijkplayer/issues/87) 63 | 64 | ## 0.2.8+1 65 | 66 | Update pubspec and some Readme. 67 | 68 | ## 0.2.8 69 | 70 | New feature: 71 | 72 | - Now, user can setSpeed. 73 | 74 | Fix: 75 | 76 | - About setDataSource and autoPlay. 77 | 78 | ## 0.2.7 79 | 80 | Fix bug: 81 | 82 | - some m3u8 no sound. 83 | - some asset cannot play. 84 | 85 | ## 0.2.6 86 | 87 | Fix bug: 88 | 89 | - Possible null pointer exceptions 90 | 91 | ## 0.2.5 92 | 93 | Fix bug: 94 | 95 | Problems in `TabView`. 96 | 97 | ## 0.2.4 98 | 99 | fix bug: 100 | 101 | - set datasource and play error. 102 | - iOS xs max fullscreen problem. 103 | 104 | new: 105 | 106 | - Customizing the interface affects the full screen. 107 | 108 | ## 0.2.3 109 | 110 | Fixed the problem that a project without kotlin could not be compiled. 111 | 112 | ## 0.2.2 113 | 114 | Add `setIjkPlayerOptions` and `addIjkPlayerOptions`. 115 | 116 | iOS podspec add `s.static_framework = true` 117 | 118 | ## 0.2.1 119 | 120 | Recompile android so library. 121 | 122 | ## 0.2.0 123 | 124 | Add `StatusWidgetBuilder` params. 125 | 126 | Update volume and brightness icon 127 | 128 | ## 0.1.9 129 | 130 | add screen shot method. 131 | 132 | ## 0.1.8 133 | 134 | Screen rotation and full screen control code. 135 | 136 | ## 0.1.7 137 | 138 | Fixed some video decoding problems. 139 | 140 | ## 0.1.6 141 | 142 | - add problem left vertical gesture to control brightness. 143 | 144 | - fix some problem. 145 | 146 | ## 0.1.5 147 | 148 | update iOS framework 149 | 150 | add some property 151 | 152 | ## 0.1.4 153 | 154 | Use [GSYVideoPlayer](https://github.com/CarGuo/GSYVideoPlayer) android ex so 155 | 156 | ## 0.1.3 157 | 158 | Use [GSYVideoPlayer](https://github.com/CarGuo/GSYVideoPlayer) android \*.so 159 | 160 | ## 0.1.2 161 | 162 | fix ios fps problem. 163 | 164 | ## 0.1.1 165 | 166 | fix some bug 167 | 168 | ## 0.1.0 169 | 170 | first version 171 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributors ✨ 2 | 3 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
Caijinglong
Caijinglong

💻 🎨
浩麟
浩麟

💻
14 | 15 | 16 | 17 | 18 | 19 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 20 | -------------------------------------------------------------------------------- /FAQ.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 3 | ## iOS 4 | 5 | ### About get cocoapod error 6 | 7 | Q: Use the 0.2.3 version of FlutterIJK error in iOS. 8 | A: Use next method: 9 | 10 | ```bash 11 | pod cache clean FlutterIJK 12 | ``` 13 | 14 | Remove your FlutterIJK version. 15 | And rerun `pod install` 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Caijinglong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /TODOLIST.md: -------------------------------------------------------------------------------- 1 | # TodoList 2 | 3 | - [x] 控制器逻辑 4 | - [x] 设置数据源 5 | - [x] 网络 6 | - [x] 设置请求头 7 | - [x] 本地 8 | - [x] 资产 9 | - [x] 播放 10 | - [x] 暂停 11 | - [x] 停止 12 | - [x] 释放资源 13 | - [x] 控制音量 14 | - [x] 监听播放完成 15 | - [x] 控制系统音量 16 | - [x] 修复 iOS 系统音量与逻辑相反的问题 17 | - [x] 修复 iOS 系统音量出现系统弹窗的问题 18 | - [x] 修复 iOS 系统音量出现时视频明显卡顿的问题 19 | - [x] 获取视频信息 20 | - [x] 宽高 21 | - [x] 当前播放进度 22 | - [x] 总时长 23 | - [x] 视频方向 24 | - [x] 视频播放速度 25 | - [x] tcp 速度 26 | - [ ] 当前视频编解码器(作为未来备选方案,目前 android 端可获取,iOS 端只有解码器 id 没有名字) 27 | - [ ] 视频 28 | - [ ] 音频 29 | - [x] 帧数 30 | - [x] android 31 | - [ ] iOS (目前永远是 0,获取的是 GL_view 的 fps) 32 | - [x] 控制亮度 33 | - [x] 逻辑方法 34 | - [x] 界面实现 35 | - [x] 屏幕方向锁定 : 这个指当前页面支持什么方向的应用 36 | - [ ] iPad 无效,暂不知原因 37 | - [x] 屏幕旋转: 这个指强制当前屏幕旋转至哪个方向 38 | - [ ] iPad 无效,暂不知原因 39 | - [x] 截图 40 | - [ ] 悬浮窗中播放 41 | - [ ] 悬浮窗的 UI 控制器 42 | - [ ] 自定义 UI 43 | - [x] 视频播放出错时的回调通知 44 | - [x] 默认控制器 UI 45 | - [x] 进度条 46 | - [x] 播放/暂停按钮 47 | - [x] 全屏横向滑动进度 48 | - [x] 拖动进度条快速调节进度 49 | - [x] 逻辑部分实现 50 | - [x] UI 提示 51 | - [x] 纵向滑动音量 52 | - [x] 单击显示/隐藏界面 53 | - [x] 双击播放/暂停 54 | - [x] 使用选项切换音量的控制是系统音量还是资源音量 55 | - [x] 允许根据情况禁用各种控制手势 56 | - [x] 当一个视频是直播视频时,进度条应该隐藏,且无拖动进度相关手势 57 | - [x] 全屏切换 58 | - [x] UI(控制器 UI 内) 59 | - [x] android 60 | - [x] iOS 61 | - [x] 利用 ShowDialog 开发一个全屏的播放界面,不仅仅在 Example 中 62 | - [x] 根据屏幕宽高确定是横屏全屏还是竖屏全屏(比如:常规电影是横屏,常规自拍类视频为竖屏) 63 | - [ ] 全屏的界面也接受自定义 UI 的参数 64 | - [ ] 网络视频发生缓冲的情况,应在 UI 上有所反馈 65 | - [x] 根据视频角度自动旋转 66 | - [x] 保证视频图像宽高比不失真 67 | - [x] 允许自定义控制器 UI 68 | - [ ] 未开始播放时的界面 69 | - [ ] 默认 70 | - [ ] 允许自定义 71 | - [ ] 完善示例代码 72 | - [x] 播放网络 73 | - [x] 播放相册 74 | - [x] 播放 asset 75 | - [ ] 设置选项的使用 76 | - [x] 切换全屏播放的示例代码 77 | - [x] 在列表中(ListView) 78 | - [x] 视频竖向分页滑动 79 | - [x] 在悬浮窗中播放 80 | - [x] 悬浮窗的 UI 控制器 81 | - [x] iOS 部分视频无法显示图像的问题: 可能很长时间内都无法解决 82 | - [x] 支持在 dart 端初始化 ijkPlayer 播放器的 option 83 | - [x] android 84 | - [x] iOS 85 | -------------------------------------------------------------------------------- /android/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | ijkplayer 4 | Project ijkplayer created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir= 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'top.kikt.ijkplayer' 2 | version '1.0-SNAPSHOT' 3 | 4 | buildscript { 5 | ext.kotlin_version = '1.3.21' 6 | repositories { 7 | google() 8 | jcenter() 9 | } 10 | 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:3.3.2' 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | } 15 | } 16 | 17 | rootProject.allprojects { 18 | repositories { 19 | google() 20 | jcenter() 21 | } 22 | } 23 | 24 | apply plugin: 'com.android.library' 25 | apply plugin: 'kotlin-android' 26 | 27 | android { 28 | compileSdkVersion 29 29 | 30 | defaultConfig { 31 | minSdkVersion 16 32 | consumerProguardFiles 'proguard-rules.pro' 33 | } 34 | lintOptions { 35 | disable 'InvalidPackage' 36 | } 37 | 38 | sourceSets.main { 39 | jniLibs.srcDirs 'src/main/libs' 40 | java.srcDirs = ['src/main/java', 'src/main/kotlin'] 41 | } 42 | 43 | buildTypes { 44 | profile { 45 | initWith debug 46 | } 47 | } 48 | } 49 | 50 | 51 | dependencies { 52 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 53 | } 54 | repositories { 55 | mavenCentral() 56 | } -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /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-4.10.2-all.zip 6 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keep class tv.danmaku.ijk.media.player.** { 2 | *; 3 | } -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'ijkplayer' 2 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/src/main/java/top/kikt/ijkplayer/FileMediaDataSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Bilibili 3 | * Copyright (C) 2015 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package top.kikt.ijkplayer; 19 | 20 | import java.io.File; 21 | import java.io.IOException; 22 | import java.io.RandomAccessFile; 23 | 24 | import tv.danmaku.ijk.media.player.misc.IMediaDataSource; 25 | 26 | public class FileMediaDataSource implements IMediaDataSource { 27 | private RandomAccessFile mFile; 28 | private long mFileSize; 29 | private File originFile; 30 | 31 | public FileMediaDataSource(File file) throws IOException { 32 | this.originFile =file; 33 | mFile = new RandomAccessFile(file, "r"); 34 | mFileSize = mFile.length(); 35 | } 36 | 37 | @Override 38 | public int readAt(long position, byte[] buffer, int offset, int size) throws IOException { 39 | if (mFile.getFilePointer() != position) 40 | mFile.seek(position); 41 | 42 | if (size == 0) 43 | return 0; 44 | 45 | return mFile.read(buffer, 0, size); 46 | } 47 | 48 | @Override 49 | public long getSize() throws IOException { 50 | return mFileSize; 51 | } 52 | 53 | @Override 54 | public void close() throws IOException { 55 | if (originFile.exists()) { 56 | mFileSize = 0; 57 | mFile.close(); 58 | } 59 | mFile = null; 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /android/src/main/java/top/kikt/ijkplayer/IjkManager.kt: -------------------------------------------------------------------------------- 1 | package top.kikt.ijkplayer 2 | 3 | /// create 2019/3/7 by cai 4 | 5 | 6 | import io.flutter.plugin.common.PluginRegistry 7 | import java.util.* 8 | 9 | class IjkManager(private val registrar: PluginRegistry.Registrar) { 10 | private val ijkList = ArrayList() 11 | 12 | fun create(options: Map): Ijk { 13 | val ijk = Ijk(registrar,options) 14 | ijkList.add(ijk) 15 | return ijk 16 | } 17 | 18 | private fun findIJK(id: Long): Ijk? { 19 | return ijkList.find { it.id == id } 20 | } 21 | 22 | fun dispose(id: Long) { 23 | val ijk = findIJK(id) ?: return 24 | ijkList.remove(ijk) 25 | ijk.dispose() 26 | } 27 | 28 | fun disposeAll() { 29 | for (ijk in ijkList.toList()) { 30 | ijkList.remove(ijk) 31 | ijk.dispose() 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /android/src/main/java/top/kikt/ijkplayer/Log.kt: -------------------------------------------------------------------------------- 1 | package top.kikt.ijkplayer 2 | 3 | import android.util.Log 4 | 5 | var showLog = true 6 | 7 | fun Any.logi(any: Any?) { 8 | if (showLog) { 9 | Log.i(this::class.java.simpleName, any.toString()) 10 | } 11 | } -------------------------------------------------------------------------------- /android/src/main/java/top/kikt/ijkplayer/NotifyChannel.kt: -------------------------------------------------------------------------------- 1 | package top.kikt.ijkplayer 2 | 3 | import io.flutter.plugin.common.MethodChannel 4 | import io.flutter.plugin.common.PluginRegistry 5 | import tv.danmaku.ijk.media.player.IMediaPlayer 6 | 7 | class NotifyChannel(val registry: PluginRegistry.Registrar, val textureId: Long, val ijk: Ijk) { 8 | 9 | private val player 10 | get() = ijk.mediaPlayer 11 | 12 | private val channel = MethodChannel( 13 | registry.messenger(), 14 | "top.kikt/ijkplayer/event/$textureId" 15 | ) 16 | // private val channel = Temp() 17 | 18 | private val info 19 | get() = ijk.getInfo().toMap() 20 | 21 | init { 22 | player.setOnPreparedListener { 23 | logi("prepare $info") 24 | player.trackInfo.forEach { 25 | 26 | } 27 | channel.invokeMethod("prepare", info) 28 | } 29 | player.setOnCompletionListener { 30 | logi("completion $info") 31 | channel.invokeMethod("finish", info) 32 | } 33 | player.setOnBufferingUpdateListener { mp, percent -> 34 | /// 在线视频缓冲 35 | logi("completion buffer update $info $percent") 36 | } 37 | player.setOnSeekCompleteListener { 38 | logi("onSeekCompletion $info") 39 | } 40 | player.setOnErrorListener { mp, what, extra -> 41 | channel.invokeMethod("error", what) 42 | logi("onError $what , extra = $extra") 43 | false 44 | } 45 | player.setOnInfoListener { mp, what, extra -> 46 | logi("onInfoListener $what, extra = $extra, isPlaying = ${player.isPlaying} ") 47 | when (what) { 48 | IMediaPlayer.MEDIA_INFO_AUDIO_DECODED_START, IMediaPlayer.MEDIA_INFO_VIDEO_DECODED_START -> { 49 | // channel.invokeMethod("playStateChange", info) 50 | } 51 | IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED -> { 52 | ijk.degree = extra 53 | channel.invokeMethod("rotateChanged", info) 54 | } 55 | } 56 | false 57 | } 58 | player.setOnNativeInvokeListener { what, args -> 59 | logi("onNativeInvoke $what") 60 | false 61 | } 62 | player.setOnControlMessageListener { 63 | logi("onController message $it, isPlaying = ${player.isPlaying}") 64 | "" 65 | } 66 | } 67 | 68 | fun dispose() { 69 | player.resetListeners() 70 | } 71 | 72 | } -------------------------------------------------------------------------------- /android/src/main/java/top/kikt/ijkplayer/entity/IjkOption.kt: -------------------------------------------------------------------------------- 1 | package top.kikt.ijkplayer.entity 2 | 3 | /// create 2019/4/12 by cai 4 | 5 | class IjkOption(option: Map<*, *>) { 6 | 7 | lateinit var type: Type 8 | lateinit var key: String 9 | lateinit var value: Any 10 | 11 | var isInit = true 12 | 13 | init { 14 | val type = option["category"] 15 | if (type is Int) { 16 | this.type = convertIntToType(type) 17 | } 18 | 19 | val key = option["key"] 20 | if (key is String) { 21 | this.key = key 22 | isInit = isInit and true 23 | } 24 | 25 | option["value"]?.let { 26 | this.value = it 27 | isInit = isInit and true 28 | } 29 | 30 | isInit = (type is Int) and (key is String) and (option.containsKey("value")) 31 | } 32 | 33 | private fun convertIntToType(typeInt: Int): Type { 34 | return when (typeInt) { 35 | 0 -> Type.Format 36 | 1 -> Type.Codec 37 | 2 -> Type.Sws 38 | 3 -> Type.Player 39 | else -> Type.Other 40 | } 41 | } 42 | 43 | enum class Type { 44 | Format, 45 | Codec, 46 | Sws, 47 | Player, 48 | Other, 49 | } 50 | } -------------------------------------------------------------------------------- /android/src/main/java/top/kikt/ijkplayer/entity/Info.kt: -------------------------------------------------------------------------------- 1 | package top.kikt.ijkplayer.entity 2 | 3 | /// create 2019/3/15 by cai 4 | data class Info( 5 | val duration: Double, 6 | val currentPosition: Double, 7 | val width: Int, 8 | val height: Int, 9 | val isPlaying: Boolean, 10 | val degree: Int = 0, 11 | val tcpSpeed: Long = 0, 12 | val outputFps: Float = 0f 13 | // val decodeFps: Float = 0f 14 | ) { 15 | 16 | fun toMap(): Map { 17 | val map = HashMap() 18 | map["duration"] = duration 19 | map["currentPosition"] = currentPosition 20 | map["width"] = width 21 | map["height"] = height 22 | map["isPlaying"] = isPlaying 23 | map["degree"] = degree 24 | map["tcpSpeed"] = tcpSpeed 25 | map["outputFps"] = outputFps 26 | // map["decodeFps"] = decodeFps 27 | return map 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Bilibili 3 | * Copyright (C) 2015 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player; 19 | 20 | import android.graphics.SurfaceTexture; 21 | 22 | public interface ISurfaceTextureHolder { 23 | void setSurfaceTexture(SurfaceTexture surfaceTexture); 24 | 25 | SurfaceTexture getSurfaceTexture(); 26 | 27 | void setSurfaceTextureHost(ISurfaceTextureHost surfaceTextureHost); 28 | } 29 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHost.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Bilibili 3 | * Copyright (C) 2015 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player; 19 | 20 | import android.graphics.SurfaceTexture; 21 | 22 | public interface ISurfaceTextureHost { 23 | void releaseSurfaceTexture(SurfaceTexture surfaceTexture); 24 | } 25 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/IjkLibLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013-2014 Bilibili 3 | * Copyright (C) 2013-2014 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player; 19 | 20 | public interface IjkLibLoader { 21 | void loadLibrary(String libName) throws UnsatisfiedLinkError, 22 | SecurityException; 23 | } 24 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/IjkTimedText.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Zheng Yuan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package tv.danmaku.ijk.media.player; 18 | 19 | import android.graphics.Rect; 20 | import java.lang.String; 21 | 22 | public final class IjkTimedText { 23 | 24 | private Rect mTextBounds = null; 25 | private String mTextChars = null; 26 | 27 | public IjkTimedText(Rect bounds, String text) { 28 | mTextBounds = bounds; 29 | mTextChars = text; 30 | } 31 | 32 | public Rect getBounds() { 33 | return mTextBounds; 34 | } 35 | 36 | public String getText() { 37 | return mTextChars; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/MediaInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013-2014 Bilibili 3 | * Copyright (C) 2013-2014 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player; 19 | 20 | public class MediaInfo { 21 | public String mMediaPlayerName; 22 | 23 | public String mVideoDecoder; 24 | public String mVideoDecoderImpl; 25 | 26 | public String mAudioDecoder; 27 | public String mAudioDecoderImpl; 28 | 29 | public IjkMediaMeta mMeta; 30 | } 31 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/TextureMediaPlayer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Bilibili 3 | * Copyright (C) 2015 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player; 19 | 20 | import android.annotation.TargetApi; 21 | import android.graphics.SurfaceTexture; 22 | import android.os.Build; 23 | import android.view.Surface; 24 | import android.view.SurfaceHolder; 25 | 26 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 27 | public class TextureMediaPlayer extends MediaPlayerProxy implements IMediaPlayer, ISurfaceTextureHolder { 28 | private SurfaceTexture mSurfaceTexture; 29 | private ISurfaceTextureHost mSurfaceTextureHost; 30 | 31 | public TextureMediaPlayer(IMediaPlayer backEndMediaPlayer) { 32 | super(backEndMediaPlayer); 33 | } 34 | 35 | public void releaseSurfaceTexture() { 36 | if (mSurfaceTexture != null) { 37 | if (mSurfaceTextureHost != null) { 38 | mSurfaceTextureHost.releaseSurfaceTexture(mSurfaceTexture); 39 | } else { 40 | mSurfaceTexture.release(); 41 | } 42 | mSurfaceTexture = null; 43 | } 44 | } 45 | 46 | //-------------------- 47 | // IMediaPlayer 48 | //-------------------- 49 | @Override 50 | public void reset() { 51 | super.reset(); 52 | releaseSurfaceTexture(); 53 | } 54 | 55 | @Override 56 | public void release() { 57 | super.release(); 58 | releaseSurfaceTexture(); 59 | } 60 | 61 | @Override 62 | public void setDisplay(SurfaceHolder sh) { 63 | if (mSurfaceTexture == null) 64 | super.setDisplay(sh); 65 | } 66 | 67 | @Override 68 | public void setSurface(Surface surface) { 69 | if (mSurfaceTexture == null) 70 | super.setSurface(surface); 71 | } 72 | 73 | //-------------------- 74 | // ISurfaceTextureHolder 75 | //-------------------- 76 | 77 | @Override 78 | public void setSurfaceTexture(SurfaceTexture surfaceTexture) { 79 | if (mSurfaceTexture == surfaceTexture) 80 | return; 81 | 82 | releaseSurfaceTexture(); 83 | mSurfaceTexture = surfaceTexture; 84 | if (surfaceTexture == null) { 85 | super.setSurface(null); 86 | } else { 87 | super.setSurface(new Surface(surfaceTexture)); 88 | } 89 | } 90 | 91 | @Override 92 | public SurfaceTexture getSurfaceTexture() { 93 | return mSurfaceTexture; 94 | } 95 | 96 | @Override 97 | public void setSurfaceTextureHost(ISurfaceTextureHost surfaceTextureHost) { 98 | mSurfaceTextureHost = surfaceTextureHost; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/annotations/AccessedByNative.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013-2014 Bilibili 3 | * Copyright (C) 2013-2014 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player.annotations; 19 | 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | /** 26 | * is used by the JNI generator to create the necessary JNI 27 | * bindings and expose this method to native code. 28 | */ 29 | @Target(ElementType.FIELD) 30 | @Retention(RetentionPolicy.CLASS) 31 | public @interface AccessedByNative { 32 | } -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/annotations/CalledByNative.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013-2014 Bilibili 3 | * Copyright (C) 2013-2014 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player.annotations; 19 | 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | /** 26 | * is used by the JNI generator to create the necessary JNI 27 | * bindings and expose this method to native code. 28 | */ 29 | @Target(ElementType.METHOD) 30 | @Retention(RetentionPolicy.CLASS) 31 | public @interface CalledByNative { 32 | /* 33 | * If present, tells which inner class the method belongs to. 34 | */ 35 | String value() default ""; 36 | } -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/exceptions/IjkMediaException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013-2014 Bilibili 3 | * Copyright (C) 2013-2014 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player.exceptions; 19 | 20 | public class IjkMediaException extends Exception { 21 | private static final long serialVersionUID = 7234796519009099506L; 22 | } 23 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/ffmpeg/FFmpegApi.java: -------------------------------------------------------------------------------- 1 | package tv.danmaku.ijk.media.player.ffmpeg; 2 | 3 | public class FFmpegApi { 4 | public static native String av_base64_encode(byte in[]); 5 | } 6 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidMediaFormat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Bilibili 3 | * Copyright (C) 2015 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player.misc; 19 | 20 | import android.annotation.TargetApi; 21 | import android.media.MediaFormat; 22 | import android.os.Build; 23 | 24 | public class AndroidMediaFormat implements IMediaFormat { 25 | private final MediaFormat mMediaFormat; 26 | 27 | public AndroidMediaFormat(MediaFormat mediaFormat) { 28 | mMediaFormat = mediaFormat; 29 | } 30 | 31 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 32 | @Override 33 | public int getInteger(String name) { 34 | if (mMediaFormat == null) 35 | return 0; 36 | 37 | return mMediaFormat.getInteger(name); 38 | } 39 | 40 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 41 | @Override 42 | public String getString(String name) { 43 | if (mMediaFormat == null) 44 | return null; 45 | 46 | return mMediaFormat.getString(name); 47 | } 48 | 49 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 50 | @Override 51 | public String toString() { 52 | StringBuilder out = new StringBuilder(128); 53 | out.append(getClass().getName()); 54 | out.append('{'); 55 | if (mMediaFormat != null) { 56 | out.append(mMediaFormat.toString()); 57 | } else { 58 | out.append("null"); 59 | } 60 | out.append('}'); 61 | return out.toString(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidTrackInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Bilibili 3 | * Copyright (C) 2015 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player.misc; 19 | 20 | import android.annotation.TargetApi; 21 | import android.media.MediaFormat; 22 | import android.media.MediaPlayer; 23 | import android.os.Build; 24 | 25 | public class AndroidTrackInfo implements ITrackInfo { 26 | private final MediaPlayer.TrackInfo mTrackInfo; 27 | 28 | public static AndroidTrackInfo[] fromMediaPlayer(MediaPlayer mp) { 29 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) 30 | return fromTrackInfo(mp.getTrackInfo()); 31 | 32 | return null; 33 | } 34 | 35 | private static AndroidTrackInfo[] fromTrackInfo(MediaPlayer.TrackInfo[] trackInfos) { 36 | if (trackInfos == null) 37 | return null; 38 | 39 | AndroidTrackInfo androidTrackInfo[] = new AndroidTrackInfo[trackInfos.length]; 40 | for (int i = 0; i < trackInfos.length; ++i) { 41 | androidTrackInfo[i] = new AndroidTrackInfo(trackInfos[i]); 42 | } 43 | 44 | return androidTrackInfo; 45 | } 46 | 47 | private AndroidTrackInfo(MediaPlayer.TrackInfo trackInfo) { 48 | mTrackInfo = trackInfo; 49 | } 50 | 51 | @TargetApi(Build.VERSION_CODES.KITKAT) 52 | @Override 53 | public IMediaFormat getFormat() { 54 | if (mTrackInfo == null) 55 | return null; 56 | 57 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) 58 | return null; 59 | 60 | MediaFormat mediaFormat = mTrackInfo.getFormat(); 61 | if (mediaFormat == null) 62 | return null; 63 | 64 | return new AndroidMediaFormat(mediaFormat); 65 | } 66 | 67 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 68 | @Override 69 | public String getLanguage() { 70 | if (mTrackInfo == null) 71 | return "und"; 72 | 73 | return mTrackInfo.getLanguage(); 74 | } 75 | 76 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 77 | @Override 78 | public int getTrackType() { 79 | if (mTrackInfo == null) 80 | return MEDIA_TRACK_TYPE_UNKNOWN; 81 | 82 | return mTrackInfo.getTrackType(); 83 | } 84 | 85 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 86 | @Override 87 | public String toString() { 88 | StringBuilder out = new StringBuilder(128); 89 | out.append(getClass().getSimpleName()); 90 | out.append('{'); 91 | if (mTrackInfo != null) { 92 | out.append(mTrackInfo.toString()); 93 | } else { 94 | out.append("null"); 95 | } 96 | out.append('}'); 97 | return out.toString(); 98 | } 99 | 100 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 101 | @Override 102 | public String getInfoInline() { 103 | if (mTrackInfo != null) { 104 | return mTrackInfo.toString(); 105 | } else { 106 | return "null"; 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/misc/IAndroidIO.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Bilibili 3 | * Copyright (C) 2016 Raymond Zheng 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player.misc; 19 | 20 | import java.io.IOException; 21 | 22 | @SuppressWarnings("RedundantThrows") 23 | public interface IAndroidIO { 24 | int open(String url) throws IOException; 25 | int read(byte[] buffer, int size) throws IOException; 26 | long seek(long offset, int whence) throws IOException; 27 | int close() throws IOException; 28 | } 29 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaDataSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Bilibili 3 | * Copyright (C) 2015 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player.misc; 19 | 20 | import java.io.IOException; 21 | 22 | @SuppressWarnings("RedundantThrows") 23 | public interface IMediaDataSource { 24 | int readAt(long position, byte[] buffer, int offset, int size) throws IOException; 25 | 26 | long getSize() throws IOException; 27 | 28 | void close() throws IOException; 29 | } 30 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaFormat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Bilibili 3 | * Copyright (C) 2015 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player.misc; 19 | 20 | public interface IMediaFormat { 21 | // Common keys 22 | String KEY_MIME = "mime"; 23 | 24 | // Video Keys 25 | String KEY_WIDTH = "width"; 26 | String KEY_HEIGHT = "height"; 27 | 28 | String getString(String name); 29 | 30 | int getInteger(String name); 31 | } 32 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/misc/ITrackInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Bilibili 3 | * Copyright (C) 2015 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player.misc; 19 | 20 | public interface ITrackInfo { 21 | int MEDIA_TRACK_TYPE_AUDIO = 2; 22 | int MEDIA_TRACK_TYPE_METADATA = 5; 23 | int MEDIA_TRACK_TYPE_SUBTITLE = 4; 24 | int MEDIA_TRACK_TYPE_TIMEDTEXT = 3; 25 | int MEDIA_TRACK_TYPE_UNKNOWN = 0; 26 | int MEDIA_TRACK_TYPE_VIDEO = 1; 27 | 28 | IMediaFormat getFormat(); 29 | 30 | String getLanguage(); 31 | 32 | int getTrackType(); 33 | 34 | String getInfoInline(); 35 | } 36 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/misc/IjkTrackInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Bilibili 3 | * Copyright (C) 2015 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player.misc; 19 | 20 | import android.text.TextUtils; 21 | 22 | import tv.danmaku.ijk.media.player.IjkMediaMeta; 23 | 24 | public class IjkTrackInfo implements ITrackInfo { 25 | private int mTrackType = MEDIA_TRACK_TYPE_UNKNOWN; 26 | private IjkMediaMeta.IjkStreamMeta mStreamMeta; 27 | 28 | public IjkTrackInfo(IjkMediaMeta.IjkStreamMeta streamMeta) { 29 | mStreamMeta = streamMeta; 30 | } 31 | 32 | public void setMediaMeta(IjkMediaMeta.IjkStreamMeta streamMeta) { 33 | mStreamMeta = streamMeta; 34 | } 35 | 36 | @Override 37 | public IMediaFormat getFormat() { 38 | return new IjkMediaFormat(mStreamMeta); 39 | } 40 | 41 | @Override 42 | public String getLanguage() { 43 | if (mStreamMeta == null || TextUtils.isEmpty(mStreamMeta.mLanguage)) 44 | return "und"; 45 | 46 | return mStreamMeta.mLanguage; 47 | } 48 | 49 | @Override 50 | public int getTrackType() { 51 | return mTrackType; 52 | } 53 | 54 | public void setTrackType(int trackType) { 55 | mTrackType = trackType; 56 | } 57 | 58 | @Override 59 | public String toString() { 60 | return getClass().getSimpleName() + '{' + getInfoInline() + "}"; 61 | } 62 | 63 | @Override 64 | public String getInfoInline() { 65 | StringBuilder out = new StringBuilder(128); 66 | switch (mTrackType) { 67 | case MEDIA_TRACK_TYPE_VIDEO: 68 | out.append("VIDEO"); 69 | out.append(", "); 70 | out.append(mStreamMeta.getCodecShortNameInline()); 71 | out.append(", "); 72 | out.append(mStreamMeta.getBitrateInline()); 73 | out.append(", "); 74 | out.append(mStreamMeta.getResolutionInline()); 75 | break; 76 | case MEDIA_TRACK_TYPE_AUDIO: 77 | out.append("AUDIO"); 78 | out.append(", "); 79 | out.append(mStreamMeta.getCodecShortNameInline()); 80 | out.append(", "); 81 | out.append(mStreamMeta.getBitrateInline()); 82 | out.append(", "); 83 | out.append(mStreamMeta.getSampleRateInline()); 84 | break; 85 | case MEDIA_TRACK_TYPE_TIMEDTEXT: 86 | out.append("TIMEDTEXT"); 87 | out.append(", "); 88 | out.append(mStreamMeta.mLanguage); 89 | break; 90 | case MEDIA_TRACK_TYPE_SUBTITLE: 91 | out.append("SUBTITLE"); 92 | break; 93 | default: 94 | out.append("UNKNOWN"); 95 | break; 96 | } 97 | return out.toString(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/pragma/DebugLog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Bilibili 3 | * Copyright (C) 2013 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package tv.danmaku.ijk.media.player.pragma; 19 | 20 | import java.util.Locale; 21 | 22 | 23 | import android.util.Log; 24 | 25 | @SuppressWarnings({"SameParameterValue", "WeakerAccess"}) 26 | public class DebugLog { 27 | public static final boolean ENABLE_ERROR = Pragma.ENABLE_VERBOSE; 28 | public static final boolean ENABLE_INFO = Pragma.ENABLE_VERBOSE; 29 | public static final boolean ENABLE_WARN = Pragma.ENABLE_VERBOSE; 30 | public static final boolean ENABLE_DEBUG = Pragma.ENABLE_VERBOSE; 31 | public static final boolean ENABLE_VERBOSE = Pragma.ENABLE_VERBOSE; 32 | 33 | public static void e(String tag, String msg) { 34 | if (ENABLE_ERROR) { 35 | Log.e(tag, msg); 36 | } 37 | } 38 | 39 | public static void e(String tag, String msg, Throwable tr) { 40 | if (ENABLE_ERROR) { 41 | Log.e(tag, msg, tr); 42 | } 43 | } 44 | 45 | public static void efmt(String tag, String fmt, Object... args) { 46 | if (ENABLE_ERROR) { 47 | String msg = String.format(Locale.US, fmt, args); 48 | Log.e(tag, msg); 49 | } 50 | } 51 | 52 | public static void i(String tag, String msg) { 53 | if (ENABLE_INFO) { 54 | Log.i(tag, msg); 55 | } 56 | } 57 | 58 | public static void i(String tag, String msg, Throwable tr) { 59 | if (ENABLE_INFO) { 60 | Log.i(tag, msg, tr); 61 | } 62 | } 63 | 64 | public static void ifmt(String tag, String fmt, Object... args) { 65 | if (ENABLE_INFO) { 66 | String msg = String.format(Locale.US, fmt, args); 67 | Log.i(tag, msg); 68 | } 69 | } 70 | 71 | public static void w(String tag, String msg) { 72 | if (ENABLE_WARN) { 73 | Log.w(tag, msg); 74 | } 75 | } 76 | 77 | public static void w(String tag, String msg, Throwable tr) { 78 | if (ENABLE_WARN) { 79 | Log.w(tag, msg, tr); 80 | } 81 | } 82 | 83 | public static void wfmt(String tag, String fmt, Object... args) { 84 | if (ENABLE_WARN) { 85 | String msg = String.format(Locale.US, fmt, args); 86 | Log.w(tag, msg); 87 | } 88 | } 89 | 90 | public static void d(String tag, String msg) { 91 | if (ENABLE_DEBUG) { 92 | Log.d(tag, msg); 93 | } 94 | } 95 | 96 | public static void d(String tag, String msg, Throwable tr) { 97 | if (ENABLE_DEBUG) { 98 | Log.d(tag, msg, tr); 99 | } 100 | } 101 | 102 | public static void dfmt(String tag, String fmt, Object... args) { 103 | if (ENABLE_DEBUG) { 104 | String msg = String.format(Locale.US, fmt, args); 105 | Log.d(tag, msg); 106 | } 107 | } 108 | 109 | public static void v(String tag, String msg) { 110 | if (ENABLE_VERBOSE) { 111 | Log.v(tag, msg); 112 | } 113 | } 114 | 115 | public static void v(String tag, String msg, Throwable tr) { 116 | if (ENABLE_VERBOSE) { 117 | Log.v(tag, msg, tr); 118 | } 119 | } 120 | 121 | public static void vfmt(String tag, String fmt, Object... args) { 122 | if (ENABLE_VERBOSE) { 123 | String msg = String.format(Locale.US, fmt, args); 124 | Log.v(tag, msg); 125 | } 126 | } 127 | 128 | public static void printStackTrace(Throwable e) { 129 | if (ENABLE_WARN) { 130 | e.printStackTrace(); 131 | } 132 | } 133 | 134 | public static void printCause(Throwable e) { 135 | if (ENABLE_WARN) { 136 | Throwable cause = e.getCause(); 137 | if (cause != null) 138 | e = cause; 139 | 140 | printStackTrace(e); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /android/src/main/java/tv/danmaku/ijk/media/player/pragma/Pragma.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Bilibili 3 | * Copyright (C) 2013 Zhang Rui 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package tv.danmaku.ijk.media.player.pragma; 18 | 19 | /*- 20 | * configurated by app project 21 | */ 22 | public class Pragma { 23 | public static final boolean ENABLE_VERBOSE = true; 24 | } 25 | -------------------------------------------------------------------------------- /android/src/main/libs/arm64-v8a/libijkffmpeg.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/android/src/main/libs/arm64-v8a/libijkffmpeg.so -------------------------------------------------------------------------------- /android/src/main/libs/arm64-v8a/libijkplayer.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/android/src/main/libs/arm64-v8a/libijkplayer.so -------------------------------------------------------------------------------- /android/src/main/libs/arm64-v8a/libijksdl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/android/src/main/libs/arm64-v8a/libijksdl.so -------------------------------------------------------------------------------- /android/src/main/libs/armeabi-v7a/libijkffmpeg.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/android/src/main/libs/armeabi-v7a/libijkffmpeg.so -------------------------------------------------------------------------------- /android/src/main/libs/armeabi-v7a/libijkplayer.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/android/src/main/libs/armeabi-v7a/libijkplayer.so -------------------------------------------------------------------------------- /android/src/main/libs/armeabi-v7a/libijksdl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/android/src/main/libs/armeabi-v7a/libijksdl.so -------------------------------------------------------------------------------- /android/src/main/libs/x86/libijkffmpeg.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/android/src/main/libs/x86/libijkffmpeg.so -------------------------------------------------------------------------------- /android/src/main/libs/x86/libijkplayer.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/android/src/main/libs/x86/libijkplayer.so -------------------------------------------------------------------------------- /android/src/main/libs/x86/libijksdl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/android/src/main/libs/x86/libijksdl.so -------------------------------------------------------------------------------- /android/src/main/libs/x86_64/libijkffmpeg.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/android/src/main/libs/x86_64/libijkffmpeg.so -------------------------------------------------------------------------------- /android/src/main/libs/x86_64/libijkplayer.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/android/src/main/libs/x86_64/libijkplayer.so -------------------------------------------------------------------------------- /android/src/main/libs/x86_64/libijksdl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/android/src/main/libs/x86_64/libijksdl.so -------------------------------------------------------------------------------- /android/switch_env.sh: -------------------------------------------------------------------------------- 1 | cd src/main 2 | case "$1" in 3 | "dev") 4 | mv libs libs-prod 5 | ln -s /Volumes/Samsung-T5/code/media_projects/ijkplayer/flutter_ijk/android/out/libs libs 6 | ;; 7 | "prod") 8 | rm libs 9 | mv libs-prod libs 10 | ;; 11 | *) 12 | echo "$0 dev|prod" 13 | exit 1 14 | ;; 15 | esac 16 | -------------------------------------------------------------------------------- /example/.flutter-plugins-dependencies: -------------------------------------------------------------------------------- 1 | {"_info":"// This is a generated file; do not edit or check into version control.","dependencyGraph":[{"name":"flutter_ijkplayer","dependencies":[]},{"name":"photo_manager","dependencies":[]}]} -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # Visual Studio Code related 19 | .vscode/ 20 | 21 | # Flutter/Dart/Pub related 22 | **/doc/api/ 23 | .dart_tool/ 24 | .flutter-plugins 25 | .packages 26 | .pub-cache/ 27 | .pub/ 28 | /build/ 29 | 30 | # Android related 31 | **/android/**/gradle-wrapper.jar 32 | **/android/.gradle 33 | **/android/captures/ 34 | **/android/gradlew 35 | **/android/gradlew.bat 36 | **/android/local.properties 37 | **/android/**/GeneratedPluginRegistrant.java 38 | 39 | # iOS/XCode related 40 | **/ios/**/*.mode1v3 41 | **/ios/**/*.mode2v3 42 | **/ios/**/*.moved-aside 43 | **/ios/**/*.pbxuser 44 | **/ios/**/*.perspectivev3 45 | **/ios/**/*sync/ 46 | **/ios/**/.sconsign.dblite 47 | **/ios/**/.tags* 48 | **/ios/**/.vagrant/ 49 | **/ios/**/DerivedData/ 50 | **/ios/**/Icon? 51 | **/ios/**/Pods/ 52 | **/ios/**/.symlinks/ 53 | **/ios/**/profile 54 | **/ios/**/xcuserdata 55 | **/ios/.generated/ 56 | **/ios/Flutter/App.framework 57 | **/ios/Flutter/Flutter.framework 58 | **/ios/Flutter/Generated.xcconfig 59 | **/ios/Flutter/app.flx 60 | **/ios/Flutter/app.zip 61 | **/ios/Flutter/flutter_assets/ 62 | **/ios/ServiceDefinitions.json 63 | **/ios/Runner/GeneratedPluginRegistrant.* 64 | 65 | # Exceptions to above rules. 66 | !**/ios/**/default.mode1v3 67 | !**/ios/**/default.mode2v3 68 | !**/ios/**/default.pbxuser 69 | !**/ios/**/default.perspectivev3 70 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 71 | -------------------------------------------------------------------------------- /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: 7fc14a55af64462763d28abfb4e610086c6e0f39 8 | channel: dev 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # ijkplayer_example 2 | 3 | Demonstrates how to use the ijkplayer 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 | -------------------------------------------------------------------------------- /example/android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android 4 | Project android created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | -------------------------------------------------------------------------------- /example/android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir= 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /example/android/app/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /example/android/app/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | app 4 | Project app created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /example/android/app/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir=.. 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /example/android/app/arm64.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: Arm64Plugin 2 | 3 | class Arm64Plugin implements Plugin { 4 | private Properties localProperties 5 | 6 | private Properties readPropertiesIfExist(File propertiesFile) { 7 | Properties result = new Properties() 8 | if (propertiesFile.exists()) { 9 | propertiesFile.withReader('UTF-8') { reader -> result.load(reader) } 10 | } 11 | return result 12 | } 13 | 14 | private String resolveProperty(Project project, String name, String defaultValue) { 15 | if (localProperties == null) { 16 | localProperties = readPropertiesIfExist(new File(project.projectDir.parentFile, "local.properties")) 17 | } 18 | String result 19 | if (project.hasProperty(name)) { 20 | result = project.property(name) 21 | } 22 | if (result == null) { 23 | result = localProperties.getProperty(name) 24 | } 25 | if (result == null) { 26 | result = defaultValue 27 | } 28 | return result 29 | } 30 | 31 | @Override 32 | void apply(Project project) { 33 | project.android.buildTypes { 34 | profile { 35 | initWith debug 36 | if (it.hasProperty('matchingFallbacks')) { 37 | matchingFallbacks = ['debug', 'release'] 38 | } 39 | } 40 | dynamicProfile { 41 | initWith debug 42 | if (it.hasProperty('matchingFallbacks')) { 43 | matchingFallbacks = ['debug', 'release'] 44 | } 45 | } 46 | dynamicRelease { 47 | initWith debug 48 | if (it.hasProperty('matchingFallbacks')) { 49 | matchingFallbacks = ['debug', 'release'] 50 | } 51 | } 52 | } 53 | 54 | String flutterRoot = resolveProperty(project, "flutter.sdk", System.env.FLUTTER_ROOT) 55 | // 原始jar包文件 56 | def zipFile = file("$flutterRoot/bin/cache/artifacts/engine/android-arm64-dynamic-release/flutter.jar") 57 | 58 | // 解压缩目标目录 59 | def outputDir = file("$flutterRoot/bin/cache/artifacts/engine/android-arm64-dynamic-release/dist") 60 | 61 | // FileTree jarTree = zipTree(zipFile) 62 | // 63 | // from jarTree 64 | // into outputDir 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | android { 27 | signingConfigs { 28 | config1 { 29 | keyAlias 'run' 30 | keyPassword '123456' 31 | storeFile file("${project.rootDir}/example-key.jks") 32 | storePassword '123456' 33 | } 34 | } 35 | compileSdkVersion 29 36 | lintOptions { 37 | disable 'InvalidPackage' 38 | } 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.example.ijkplayer_example" 42 | minSdkVersion 16 43 | targetSdkVersion 28 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 47 | 48 | } 49 | buildTypes { 50 | release { 51 | // TODO: Add your own signing config for the release build. 52 | // Signing with the debug keys for now, so `flutter run --release` works. 53 | signingConfig signingConfigs.config1 54 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'app/proguard-rules.pro' 55 | } 56 | debug { 57 | signingConfig signingConfigs.config1 58 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'app/proguard-rules.pro' 59 | } 60 | } 61 | } 62 | 63 | flutter { 64 | source '../..' 65 | } 66 | 67 | dependencies { 68 | // testImplementation 'junit:junit:4.12' 69 | // androidTestImplementation 'com.android.support.test:runner:1.0.2' 70 | // androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 71 | } 72 | -------------------------------------------------------------------------------- /example/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/android/app/proguard-rules.pro -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 13 | 20 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/example/ijkplayer_example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.ijkplayer_example; 2 | 3 | import android.os.Bundle; 4 | import io.flutter.app.FlutterActivity; 5 | import io.flutter.plugins.GeneratedPluginRegistrant; 6 | 7 | public class MainActivity extends FlutterActivity { 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | GeneratedPluginRegistrant.registerWith(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.21' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.3.2' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | 23 | subprojects { 24 | project.buildDir = "${rootProject.buildDir}/${project.name}" 25 | project.evaluationDependsOn(':app') 26 | } 27 | 28 | task clean(type: Delete) { 29 | delete rootProject.buildDir 30 | } 31 | -------------------------------------------------------------------------------- /example/android/example-key.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/android/example-key.jks -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | #target-platform=android-arm 3 | android.enableJetifier=true 4 | android.useAndroidX=true 5 | android.enableR8=true 6 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /example/assets/sample1.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/assets/sample1.mp4 -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Flutter.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE: This podspec is NOT to be published. It is only used as a local source! 3 | # 4 | 5 | Pod::Spec.new do |s| 6 | s.name = 'Flutter' 7 | s.version = '1.0.0' 8 | s.summary = 'High-performance, high-fidelity mobile apps.' 9 | s.description = <<-DESC 10 | Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS. 11 | DESC 12 | s.homepage = 'https://flutter.io' 13 | s.license = { :type => 'MIT' } 14 | s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } 15 | s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } 16 | s.ios.deployment_target = '8.0' 17 | s.vendored_frameworks = 'Flutter.framework' 18 | end 19 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/flutter_export_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This is a generated file; do not edit or check into version control. 3 | export "FLUTTER_ROOT=/Users/caijinglong/Library/Flutter/flutter_dev" 4 | export "FLUTTER_APPLICATION_PATH=/Volumes/Samsung-T5/code/flutter/plugins/flutter_ijkplayer/example" 5 | export "FLUTTER_TARGET=/Volumes/Samsung-T5/code/flutter/plugins/flutter_ijkplayer/example/lib/main.dart" 6 | export "FLUTTER_BUILD_DIR=build" 7 | export "SYMROOT=${SOURCE_ROOT}/../build/ios" 8 | export "FLUTTER_FRAMEWORK_DIR=/Users/caijinglong/Library/Flutter/flutter_dev/bin/cache/artifacts/engine/ios" 9 | export "FLUTTER_BUILD_NAME=1.0.0" 10 | export "FLUTTER_BUILD_NUMBER=1" 11 | export "TRACK_WIDGET_CREATION=true" 12 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '9.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 parse_KV_file(file, separator='=') 14 | file_abs_path = File.expand_path(file) 15 | if !File.exists? file_abs_path 16 | return []; 17 | end 18 | generated_key_values = {} 19 | skip_line_start_symbols = ["#", "/"] 20 | File.foreach(file_abs_path) do |line| 21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 22 | plugin = line.split(pattern=separator) 23 | if plugin.length == 2 24 | podname = plugin[0].strip() 25 | path = plugin[1].strip() 26 | podpath = File.expand_path("#{path}", file_abs_path) 27 | generated_key_values[podname] = podpath 28 | else 29 | puts "Invalid plugin specification: #{line}" 30 | end 31 | end 32 | generated_key_values 33 | end 34 | 35 | target 'Runner' do 36 | # Flutter Pod 37 | 38 | copied_flutter_dir = File.join(__dir__, 'Flutter') 39 | copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') 40 | copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') 41 | unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) 42 | # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. 43 | # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. 44 | # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. 45 | 46 | generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') 47 | unless File.exist?(generated_xcode_build_settings_path) 48 | raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" 49 | end 50 | generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) 51 | cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; 52 | 53 | unless File.exist?(copied_framework_path) 54 | FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) 55 | end 56 | unless File.exist?(copied_podspec_path) 57 | FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) 58 | end 59 | end 60 | 61 | # Keep pod path relative so it can be checked into Podfile.lock. 62 | pod 'Flutter', :path => 'Flutter' 63 | 64 | # Plugin Pods 65 | 66 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 67 | # referring to absolute paths on developers' machines. 68 | system('rm -rf .symlinks') 69 | system('mkdir -p .symlinks/plugins') 70 | plugin_pods = parse_KV_file('../.flutter-plugins') 71 | plugin_pods.each do |name, path| 72 | specPath = "#{path}/ios/#{name}.podspec" 73 | pod name,:path=>specPath 74 | end 75 | end 76 | 77 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. 78 | install! 'cocoapods', :disable_input_output_paths => true 79 | 80 | post_install do |installer| 81 | installer.pods_project.targets.each do |target| 82 | target.build_configurations.each do |config| 83 | config.build_settings['ENABLE_BITCODE'] = 'NO' 84 | end 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - flutter_ijkplayer (0.0.1): 4 | - Flutter 5 | - FlutterIJK (~> 0.2.3) 6 | - FlutterIJK (0.2.3) 7 | - photo_manager (0.0.1): 8 | - Flutter 9 | 10 | DEPENDENCIES: 11 | - Flutter (from `Flutter`) 12 | - flutter_ijkplayer (from `/Volumes/Samsung-T5/code/flutter/plugins/flutter_ijkplayer/ios/flutter_ijkplayer.podspec`) 13 | - photo_manager (from `/Users/caijinglong/.pub-cache/git/flutter_photo_manager-15e4b37a4b3efc07b7500f94d316dfe02f1a324a/ios/photo_manager.podspec`) 14 | 15 | SPEC REPOS: 16 | trunk: 17 | - FlutterIJK 18 | 19 | EXTERNAL SOURCES: 20 | Flutter: 21 | :path: Flutter 22 | flutter_ijkplayer: 23 | :path: "/Volumes/Samsung-T5/code/flutter/plugins/flutter_ijkplayer/ios/flutter_ijkplayer.podspec" 24 | photo_manager: 25 | :path: "/Users/caijinglong/.pub-cache/git/flutter_photo_manager-15e4b37a4b3efc07b7500f94d316dfe02f1a324a/ios/photo_manager.podspec" 26 | 27 | SPEC CHECKSUMS: 28 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec 29 | flutter_ijkplayer: a8f1ef22fa3e22e1ea80b70e6cb70b049cf88063 30 | FlutterIJK: f3715f94cea893b0e643b2b27b781033a1bb5007 31 | photo_manager: f7c619c2cc8c2adb8d85c63363babac477de9c67 32 | 33 | PODFILE CHECKSUM: 806836eca77383388df20b27737ff664222206cd 34 | 35 | COCOAPODS: 1.9.1 36 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /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 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Original 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | top.kikt.ijkplayer.example 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_IjkPlayer_example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0.0 23 | LSRequiresIPhoneOS 24 | 25 | NSPhotoLibraryUsageDescription 26 | App need your agree, can visit your album 27 | UIBackgroundModes 28 | 29 | fetch 30 | remote-notification 31 | 32 | UILaunchStoryboardName 33 | LaunchScreen 34 | UIMainStoryboardFile 35 | Main 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | UIViewControllerBasedStatusBarAppearance 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /example/ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/lib/const/resource.dart: -------------------------------------------------------------------------------- 1 | /// generate by resouce_generator library, shouldn't edit. 2 | class R { 3 | /// ![preview](file:///Users/cai/Documents/GitHub/flutter_ijkplayer/./example/assets/sample1.mp4) 4 | static const String ASSETS_SAMPLE1_MP4 = "assets/sample1.mp4"; 5 | } 6 | -------------------------------------------------------------------------------- /example/lib/const/video_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 2 | 3 | class VideoDataSource { 4 | static final springBootMenuM3u8 = DataSource.network( 5 | "https://media001.geekbang.org/f433fd1ce5e84d27b1101f0dad72a126/de563bb4aba94b5f95f448b33be4dd9f-9aede6861be944d696fe365f3a33b7b4-sd.m3u8"); 6 | 7 | static final ai = DataSource.network( 8 | "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4"); 9 | 10 | static final reportErrorM3u8FromAliyun = DataSource.network( 11 | "https://outin-4839d24d670f11e988c600163e1a3b4a.oss-cn-shanghai.aliyuncs.com/2b9f4f2d1c4d4985a11352cb1970fead/86c3f36ed4e1cd5539ed347282725b3e-fd-encrypt-stream.m3u8?Expires=1563162783&OSSAccessKeyId=LTAIrkwb21KyGjJl&Signature=y4m98BAzJUQVzFwHszQS%2BFGtq5A%3D"); 12 | } 13 | -------------------------------------------------------------------------------- /example/lib/i18n/cn.dart: -------------------------------------------------------------------------------- 1 | part of 'i18n.dart'; 2 | 3 | class _I18nZh extends I18n { 4 | _I18nZh() : super._(); 5 | 6 | @override 7 | String get indexTitle => "首页"; 8 | 9 | @override 10 | String get assetButton => "播放asset视频"; 11 | 12 | @override 13 | String get fullScreenAutoButton => "全屏切换示例(自动)"; 14 | 15 | @override 16 | String get fullScreenManualButton => "全屏切换示例(手动)"; 17 | 18 | @override 19 | String get listViewButton => "在ListView中"; 20 | 21 | @override 22 | String get networkButton => "播放网络视频"; 23 | 24 | @override 25 | String get pageViewButton => "在PageView中播放视频"; 26 | 27 | @override 28 | String get photoButton => "在相册中播放"; 29 | 30 | @override 31 | String get withDialogButton => "在dialog中播放"; 32 | 33 | @override 34 | String get showDialog => "显示 dialog"; 35 | 36 | @override 37 | String get autoFullScreenTitle => "切换横竖屏可以看到界面变化"; 38 | 39 | @override 40 | String get changeFullScreenWithButton => "点击按钮切换横竖屏"; 41 | 42 | @override 43 | String get fullScreen => "全屏"; 44 | 45 | @override 46 | String get play => "播放"; 47 | 48 | @override 49 | String get noPickTip => "没有选择"; 50 | 51 | @override 52 | String get pick => "选择"; 53 | 54 | @override 55 | String get useStreamUsage => "Controller stream的使用"; 56 | 57 | @override 58 | String get playFinishToast => "播放完毕"; 59 | 60 | @override 61 | String get screenshotTitle => "截取视频画面"; 62 | 63 | @override 64 | String get overlayPageTitle => "悬浮窗中显示(开发中)"; 65 | 66 | @override 67 | String get ijkStatusTitle => "IjkStatus的使用"; 68 | 69 | @override 70 | String get customOption => "自定义Option的使用"; 71 | 72 | @override 73 | String get errorUrl => "错误的url"; 74 | 75 | @override 76 | String get customFullScreenWidget => "自定义全屏界面"; 77 | 78 | @override 79 | String get setSpeed => "播放速度"; 80 | 81 | @override 82 | String get autoFullScreenOnPlay => "在开始播放时自动播放"; 83 | } 84 | -------------------------------------------------------------------------------- /example/lib/i18n/en.dart: -------------------------------------------------------------------------------- 1 | part of 'i18n.dart'; 2 | 3 | class _I18nEn extends I18n { 4 | _I18nEn() : super._(); 5 | 6 | @override 7 | String get indexTitle => "index"; 8 | 9 | @override 10 | String get assetButton => "Play asset video"; 11 | 12 | @override 13 | String get fullScreenAutoButton => "Full Screen (Auto)"; 14 | 15 | @override 16 | String get fullScreenManualButton => "Full Screen (Manual)"; 17 | 18 | @override 19 | String get listViewButton => "Use in ListView"; 20 | 21 | @override 22 | String get networkButton => "Play network video"; 23 | 24 | @override 25 | String get pageViewButton => "Use in PageView"; 26 | 27 | @override 28 | String get photoButton => "Play video in photo"; 29 | 30 | @override 31 | String get withDialogButton => "Play with dialog"; 32 | 33 | @override 34 | String get showDialog => "Show dialog"; 35 | 36 | @override 37 | String get autoFullScreenTitle => "Rotate device to see change"; 38 | 39 | @override 40 | String get changeFullScreenWithButton => "Click button to show change"; 41 | 42 | @override 43 | String get fullScreen => "full screen"; 44 | 45 | @override 46 | String get play => "play"; 47 | 48 | @override 49 | String get noPickTip => "at least pick one video"; 50 | 51 | @override 52 | String get pick => "pick"; 53 | 54 | @override 55 | String get useStreamUsage => "Controller stream usage"; 56 | 57 | @override 58 | String get playFinishToast => "Play video finish"; 59 | 60 | @override 61 | String get screenshotTitle => "screenshot video frame"; 62 | 63 | @override 64 | String get overlayPageTitle => "In overlay(Developing)"; 65 | 66 | @override 67 | String get ijkStatusTitle => "Usage of IjkStatus"; 68 | 69 | @override 70 | String get customOption => "Usage of custom IjkPlayer options"; 71 | 72 | @override 73 | String get errorUrl => "Error Url"; 74 | 75 | @override 76 | String get customFullScreenWidget => "Custom Full Screen Interface"; 77 | 78 | @override 79 | String get setSpeed => "Set media speed"; 80 | 81 | @override 82 | String get autoFullScreenOnPlay => "Auto full screen on start."; 83 | } 84 | -------------------------------------------------------------------------------- /example/lib/i18n/i18n.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | part 'cn.dart'; 3 | part 'en.dart'; 4 | 5 | abstract class I18n { 6 | 7 | I18n._(); 8 | 9 | factory I18n(Locale locale) { 10 | if (locale?.languageCode == "zh") { 11 | return _I18nZh(); 12 | } else { 13 | return _I18nEn(); 14 | } 15 | } 16 | 17 | String get indexTitle; 18 | String get networkButton; 19 | String get photoButton; 20 | String get assetButton; 21 | String get listViewButton; 22 | String get fullScreenAutoButton; 23 | String get fullScreenManualButton; 24 | String get withDialogButton; 25 | String get pageViewButton; 26 | 27 | String get showDialog; 28 | 29 | String get autoFullScreenTitle; 30 | 31 | String get changeFullScreenWithButton; 32 | 33 | String get play; 34 | 35 | String get fullScreen; 36 | 37 | String get pick; 38 | 39 | String get noPickTip; 40 | 41 | String get useStreamUsage; 42 | 43 | String get playFinishToast; 44 | 45 | String get screenshotTitle; 46 | 47 | String get overlayPageTitle; 48 | 49 | String get ijkStatusTitle; 50 | 51 | String get customOption; 52 | 53 | String get errorUrl; 54 | 55 | String get customFullScreenWidget; 56 | 57 | String get setSpeed; 58 | 59 | String get autoFullScreenOnPlay; 60 | } 61 | 62 | I18n get currentI18n => I18n(window.locale); 63 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | import 'package:ijkplayer_example/page/index.dart'; 4 | import 'package:oktoast/oktoast.dart'; 5 | 6 | Future main() async { 7 | WidgetsFlutterBinding.ensureInitialized(); 8 | await IjkManager.initIJKPlayer(); 9 | runApp(MyApp()); 10 | } 11 | 12 | class MyApp extends StatefulWidget { 13 | @override 14 | _MyAppState createState() => _MyAppState(); 15 | } 16 | 17 | class _MyAppState extends State { 18 | bool isInitPlugin = false; 19 | 20 | @override 21 | void initState() { 22 | super.initState(); 23 | Future.delayed(Duration.zero, () { 24 | isInitPlugin = true; 25 | setState(() {}); 26 | }); 27 | } 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | if (!isInitPlugin) { 32 | return Container(); 33 | } 34 | return OKToast( 35 | child: MaterialApp( 36 | home: IndexPage(), 37 | ), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /example/lib/page/asset_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | import 'package:ijkplayer_example/i18n/i18n.dart'; 4 | import 'package:ijkplayer_example/utils/options_utils.dart'; 5 | 6 | class AssetPage extends StatefulWidget { 7 | @override 8 | _AssetPageState createState() => _AssetPageState(); 9 | } 10 | 11 | class _AssetPageState extends State { 12 | IjkMediaController controller = IjkMediaController(); 13 | 14 | @override 15 | void initState() { 16 | super.initState(); 17 | OptionUtils.addDefaultOptions(controller); 18 | } 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return Scaffold( 23 | appBar: AppBar( 24 | title: Text(currentI18n.assetButton), 25 | ), 26 | body: ListView( 27 | children: [ 28 | AspectRatio( 29 | aspectRatio: 1, 30 | child: IjkPlayer( 31 | mediaController: controller, 32 | ), 33 | ) 34 | ], 35 | ), 36 | floatingActionButton: FloatingActionButton( 37 | child: Icon(Icons.play_arrow), 38 | onPressed: () async { 39 | await controller.setAssetDataSource( 40 | "assets/sample1.mp4", 41 | autoPlay: true, 42 | ); 43 | await controller.pause(); 44 | }, 45 | ), 46 | ); 47 | } 48 | 49 | @override 50 | void dispose() { 51 | controller?.dispose(); 52 | super.dispose(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /example/lib/page/auto_full_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | import 'package:ijkplayer_example/const/video_datasource.dart'; 4 | import 'package:ijkplayer_example/i18n/i18n.dart'; 5 | import 'package:ijkplayer_example/utils/options_utils.dart'; 6 | 7 | class AutoFullScreenPage extends StatefulWidget { 8 | @override 9 | _AutoFullScreenPageState createState() => _AutoFullScreenPageState(); 10 | } 11 | 12 | class _AutoFullScreenPageState extends State { 13 | IjkMediaController controller = IjkMediaController(); 14 | final key = GlobalKey(); 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | OptionUtils.addDefaultOptions(controller); 20 | setDataSource(); 21 | } 22 | 23 | void setDataSource() async { 24 | await controller.setDataSource( 25 | VideoDataSource.springBootMenuM3u8, 26 | autoPlay: true, 27 | ); 28 | key.currentState.fullScreen(); 29 | } 30 | 31 | @override 32 | void dispose() { 33 | controller.dispose(); 34 | super.dispose(); 35 | } 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | return Scaffold( 40 | appBar: AppBar( 41 | title: Text(currentI18n.autoFullScreenOnPlay), 42 | ), 43 | body: Container( 44 | child: AspectRatio( 45 | aspectRatio: 1280 / 720, 46 | child: IjkPlayer( 47 | mediaController: controller, 48 | controllerWidgetBuilder: (ctl) => DefaultIJKControllerWidget( 49 | controller: ctl, 50 | key: key, 51 | ), 52 | ), 53 | ), 54 | ), 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /example/lib/page/custom_ijk_opt_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | import 'package:ijkplayer_example/i18n/i18n.dart'; 4 | 5 | class CustomIjkOptionPage extends StatefulWidget { 6 | @override 7 | _CustomIjkOptionPageState createState() => _CustomIjkOptionPageState(); 8 | } 9 | 10 | class _CustomIjkOptionPageState extends State { 11 | IjkMediaController controller = IjkMediaController(); 12 | 13 | @override 14 | void initState() { 15 | super.initState(); 16 | initIjkController(); 17 | } 18 | 19 | @override 20 | void dispose() { 21 | controller?.dispose(); 22 | super.dispose(); 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Scaffold( 28 | appBar: AppBar( 29 | title: Text(currentI18n.customOption), 30 | ), 31 | body: ListView( 32 | children: [ 33 | AspectRatio( 34 | aspectRatio: 1280 / 720, 35 | child: IjkPlayer( 36 | mediaController: controller, 37 | ), 38 | ), 39 | ], 40 | ), 41 | ); 42 | } 43 | 44 | void initIjkController() async { 45 | var option1 = IjkOption(IjkOptionCategory.format, "fflags", "fastseek"); 46 | 47 | controller.setIjkPlayerOptions( 48 | [TargetPlatform.iOS, TargetPlatform.android], 49 | [option1].toSet(), 50 | ); 51 | 52 | await controller.setDataSource( 53 | DataSource.network( 54 | "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4"), 55 | autoPlay: true, 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /example/lib/page/developing/crash_on_set_src_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | 4 | class CrashOnSetSrcPage extends StatefulWidget { 5 | @override 6 | _CrashOnSetSrcPageState createState() => _CrashOnSetSrcPageState(); 7 | } 8 | 9 | class _CrashOnSetSrcPageState extends State { 10 | IjkMediaController controller; 11 | 12 | List networkList = [ 13 | "http://playertest.longtailvideo.com/adaptive/bipbop/gear4/prog_index.m3u8", 14 | "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4", 15 | "https://media001.geekbang.org/f433fd1ce5e84d27b1101f0dad72a126/de563bb4aba94b5f95f448b33be4dd9f-9aede6861be944d696fe365f3a33b7b4-sd.m3u8", 16 | ]; 17 | 18 | int currentIndex = 0; 19 | 20 | @override 21 | void initState() { 22 | super.initState(); 23 | controller = IjkMediaController(); 24 | } 25 | 26 | @override 27 | void dispose() { 28 | controller.dispose(); 29 | super.dispose(); 30 | } 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | return Scaffold( 35 | appBar: AppBar( 36 | title: Text("切换数据崩溃"), 37 | ), 38 | body: ListView( 39 | children: [ 40 | AspectRatio( 41 | aspectRatio: 1, 42 | child: IjkPlayer( 43 | mediaController: controller, 44 | ), 45 | ), 46 | ], 47 | ), 48 | floatingActionButton: FloatingActionButton( 49 | onPressed: () { 50 | final url = networkList[currentIndex]; 51 | controller.setDataSource(DataSource.network(url), autoPlay: true); 52 | currentIndex++; 53 | currentIndex %= networkList.length; 54 | }, 55 | ), 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /example/lib/page/developing/develop_index.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ijkplayer_example/page/developing/test_hide_system_bar.dart'; 3 | 4 | import 'crash_on_set_src_page.dart'; 5 | import 'develop_prepare_page.dart'; 6 | import 'live_interruption_page.dart'; 7 | import 'new_full_screen_page.dart'; 8 | import 'src_error_page.dart'; 9 | 10 | class DevelopingIndexPage extends StatefulWidget { 11 | @override 12 | DevelopingIndexPageState createState() => DevelopingIndexPageState(); 13 | } 14 | 15 | class DevelopingIndexPageState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | return Scaffold( 19 | appBar: AppBar( 20 | title: Text("For Developer , user don't use."), 21 | ), 22 | body: ListView( 23 | children: [ 24 | buildButton("developing preare page", ForPreparePage()), 25 | buildButton("切换视频源crash", CrashOnSetSrcPage()), 26 | buildButton("直播中断", LiveInterruptionPage()), 27 | buildButton("视频源错误", SreErrorPage()), 28 | buildButton("新的全屏", NewFullScreenPage()), 29 | buildButton("隐藏或显示状态栏", TestHideSystemBar()), 30 | ], 31 | ), 32 | ); 33 | } 34 | 35 | Widget buildButton(String text, Widget targetPage) { 36 | return FlatButton( 37 | onPressed: () { 38 | Navigator.push(context, MaterialPageRoute(builder: (_) => targetPage)); 39 | }, 40 | child: Text(text), 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /example/lib/page/developing/develop_prepare_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | 4 | class ForPreparePage extends StatefulWidget { 5 | @override 6 | _ForPreparePageState createState() => _ForPreparePageState(); 7 | } 8 | 9 | class _ForPreparePageState extends State { 10 | IjkMediaController controller = IjkMediaController(); 11 | 12 | @override 13 | void initState() { 14 | super.initState(); 15 | initPlayer(); 16 | } 17 | 18 | @override 19 | void dispose() { 20 | controller.dispose(); 21 | super.dispose(); 22 | } 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return Scaffold( 27 | appBar: AppBar( 28 | title: Text("prepare属性"), 29 | ), 30 | body: Column( 31 | children: [ 32 | Container( 33 | child: IjkPlayer(mediaController: controller), 34 | height: 300, 35 | ), 36 | ], 37 | ), 38 | ); 39 | } 40 | 41 | Future initPlayer() async { 42 | await controller.setDataSource( 43 | DataSource.asset("assets/sample1.mp4"), 44 | autoPlay: true, 45 | ); 46 | controller.pause(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/lib/page/developing/live_interruption_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | import 'package:ijkplayer_example/i18n/i18n.dart'; 4 | 5 | /// 直播异常中断 6 | class LiveInterruptionPage extends StatefulWidget { 7 | @override 8 | _LiveInterruptionPageState createState() => _LiveInterruptionPageState(); 9 | } 10 | 11 | class _LiveInterruptionPageState extends State { 12 | TextEditingController editingController = TextEditingController(); 13 | IjkMediaController mediaController = IjkMediaController(); 14 | 15 | @override 16 | void initState() { 17 | super.initState(); 18 | 19 | editingController.text = 20 | "http://js.flv.huya.com/huyalive/94525224-2460685313-10568562945082523648-2789274524-10057-A-0-1.flv?wsSecret=9b67d35535b6956aec37815c21e43cc8&wsTime=5cbbea84&ratio=2000"; 21 | } 22 | 23 | @override 24 | void dispose() { 25 | editingController.dispose(); 26 | mediaController.dispose(); 27 | super.dispose(); 28 | } 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return Scaffold( 33 | appBar: AppBar( 34 | title: Text(currentI18n.networkButton), 35 | ), 36 | body: ListView( 37 | children: [ 38 | Row( 39 | children: [ 40 | Expanded( 41 | child: TextField( 42 | controller: editingController, 43 | ), 44 | ), 45 | FlatButton( 46 | child: Text(currentI18n.play), 47 | onPressed: _playInput, 48 | ), 49 | ], 50 | ), 51 | Container( 52 | height: 400, 53 | child: IjkPlayer( 54 | mediaController: mediaController, 55 | ), 56 | ), 57 | ], 58 | ), 59 | ); 60 | } 61 | 62 | void _playInput() async { 63 | var text = editingController.text; 64 | await mediaController.setNetworkDataSource(text, autoPlay: true); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /example/lib/page/developing/new_full_screen_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | import 'package:ijkplayer_example/const/video_datasource.dart'; 4 | 5 | class NewFullScreenPage extends StatefulWidget { 6 | @override 7 | _NewFullScreenPageState createState() => _NewFullScreenPageState(); 8 | } 9 | 10 | class _NewFullScreenPageState extends State { 11 | IjkMediaController controller; 12 | 13 | @override 14 | void initState() { 15 | super.initState(); 16 | controller = IjkMediaController(); 17 | controller.setDataSource(VideoDataSource.springBootMenuM3u8); 18 | } 19 | 20 | @override 21 | void dispose() { 22 | controller?.dispose(); 23 | super.dispose(); 24 | } 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return Scaffold( 29 | appBar: AppBar( 30 | title: Text("New full screen"), 31 | ), 32 | body: Column( 33 | children: [ 34 | AspectRatio( 35 | aspectRatio: 1920 / 1080, 36 | child: IjkPlayer( 37 | mediaController: controller, 38 | ), 39 | ), 40 | ], 41 | ), 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /example/lib/page/developing/src_error_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | 4 | class VideoWidget extends StatefulWidget { 5 | final String url; 6 | VideoWidget(this.url); 7 | @override 8 | _VideoWidgetState createState() => _VideoWidgetState(); 9 | } 10 | 11 | class _VideoWidgetState extends State with WidgetsBindingObserver { 12 | IjkMediaController controller; 13 | @override 14 | void initState() { 15 | super.initState(); 16 | controller = IjkMediaController(); 17 | controller.setNetworkDataSource(widget.url, autoPlay: true); 18 | Stream ijkStatusStream = controller.ijkStatusStream; 19 | ijkStatusStream.listen((status) { 20 | if (status == IjkStatus.complete) { 21 | controller?.play(); 22 | } 23 | }); 24 | // SystemChannels.lifecycle.setMessageHandler((msg) {}); 25 | } 26 | 27 | @override 28 | void didChangeAppLifecycleState(AppLifecycleState state) { 29 | if (state == AppLifecycleState.resumed) { 30 | controller?.play(); 31 | } else if (state == AppLifecycleState.paused) { 32 | controller?.pause(); 33 | } 34 | } 35 | 36 | @override 37 | void deactivate() { 38 | super.deactivate(); 39 | controller?.pause(); 40 | } 41 | 42 | @override 43 | void reassemble() { 44 | super.reassemble(); 45 | controller?.play(); 46 | } 47 | 48 | @override 49 | void dispose() { 50 | super.dispose(); 51 | controller?.dispose(); 52 | } 53 | 54 | @override 55 | Widget build(BuildContext context) { 56 | return IjkPlayer( 57 | mediaController: controller, 58 | controllerWidgetBuilder: (mController) => new Container(), 59 | ); 60 | } 61 | } 62 | 63 | class SreErrorPage extends StatefulWidget { 64 | @override 65 | _SreErrorPageState createState() => _SreErrorPageState(); 66 | } 67 | 68 | class _SreErrorPageState extends State { 69 | @override 70 | Widget build(BuildContext context) { 71 | return Scaffold( 72 | appBar: AppBar(), 73 | body: Container( 74 | child: PageView.builder( 75 | itemBuilder: (BuildContext context, int index) { 76 | // return VideoWidget("http://114.55.36.48/1204/27/index$index.m3u8"); 77 | return VideoWidget( 78 | "http://itv.100.ahct.lv1.vcache.cn/100/ott_baseline_kalaok/hd/151/CP0541903573/playlist.m3u8"); 79 | }, 80 | ), 81 | ), 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /example/lib/page/developing/test_hide_system_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | 4 | class TestHideSystemBar extends StatefulWidget { 5 | @override 6 | _TestHideSystemBarState createState() => _TestHideSystemBarState(); 7 | } 8 | 9 | class _TestHideSystemBarState extends State { 10 | @override 11 | Widget build(BuildContext context) { 12 | return Scaffold( 13 | appBar: AppBar( 14 | title: Text("Test system bar"), 15 | ), 16 | body: Column( 17 | children: [ 18 | FlatButton( 19 | child: Text("show"), 20 | onPressed: () => show(true), 21 | ), 22 | FlatButton( 23 | child: Text("hide"), 24 | onPressed: () => show(false), 25 | ), 26 | ], 27 | ), 28 | ); 29 | } 30 | 31 | show(bool show) { 32 | IjkManager.showStatusBar(show); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /example/lib/page/dialog_video_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | import 'package:ijkplayer_example/i18n/i18n.dart'; 4 | import 'package:ijkplayer_example/utils/options_utils.dart'; 5 | 6 | class DialogVideoPage extends StatefulWidget { 7 | @override 8 | _DialogVideoPageState createState() => _DialogVideoPageState(); 9 | } 10 | 11 | class _DialogVideoPageState extends State { 12 | IjkMediaController controller = IjkMediaController(); 13 | 14 | @override 15 | void initState() { 16 | super.initState(); 17 | OptionUtils.addDefaultOptions(controller); 18 | } 19 | 20 | @override 21 | void dispose() { 22 | controller?.dispose(); 23 | super.dispose(); 24 | } 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return Scaffold( 29 | appBar: AppBar( 30 | title: Text(currentI18n.withDialogButton), 31 | ), 32 | body: Center( 33 | child: Column( 34 | children: [ 35 | FlatButton( 36 | child: Text(currentI18n.showDialog), 37 | onPressed: showIJKDialog, 38 | ), 39 | ], 40 | ), 41 | ), 42 | ); 43 | } 44 | 45 | void showIJKDialog() async { 46 | await controller.setDataSource( 47 | DataSource.network( 48 | "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4"), 49 | ); 50 | await controller.play(); 51 | 52 | await showDialog( 53 | context: context, 54 | builder: (_) => _buildIJKPlayer(), 55 | ); 56 | 57 | controller.pause(); 58 | } 59 | 60 | _buildIJKPlayer() { 61 | return IjkPlayer( 62 | mediaController: controller, 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /example/lib/page/error_url.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | import 'package:ijkplayer_example/const/video_datasource.dart'; 4 | import 'package:ijkplayer_example/i18n/i18n.dart'; 5 | import 'package:ijkplayer_example/utils/options_utils.dart'; 6 | 7 | class ErrorUrlPage extends StatefulWidget { 8 | @override 9 | _ErrorUrlPageState createState() => _ErrorUrlPageState(); 10 | } 11 | 12 | class _ErrorUrlPageState extends State { 13 | TextEditingController editingController = TextEditingController(); 14 | IjkMediaController mediaController = IjkMediaController(); 15 | 16 | // StreamSubscription statusSub; 17 | // StreamSubscription ijkErrorSub; 18 | @override 19 | void initState() { 20 | super.initState(); 21 | 22 | // editingController.text = 23 | // "https://js.wshls.acgvideo.com/live-js/922199/live_8747041_1741679.m3u8?wsSecret=1337e20698b1673ac73ea8f35e2d60e8&wsTime=1556966389&trid=5afe0383d7d149dabe0c0327c2e53a75&order=1&sig=no"; 24 | 25 | // statusSub = mediaController.ijkStatusStream.listen((status) { 26 | // print("status = $status"); 27 | // }); 28 | 29 | // ijkErrorSub = mediaController.ijkErrorStream.listen((error) { 30 | // print("error = $error"); 31 | // }); 32 | OptionUtils.addDefaultOptions(mediaController); 33 | mediaController.setDataSource( 34 | VideoDataSource.reportErrorM3u8FromAliyun, 35 | autoPlay: true, 36 | ); 37 | } 38 | 39 | @override 40 | void dispose() { 41 | // statusSub?.cancel(); 42 | // ijkErrorSub?.cancel(); 43 | editingController.dispose(); 44 | mediaController.dispose(); 45 | super.dispose(); 46 | } 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | return Scaffold( 51 | appBar: AppBar( 52 | title: Text(currentI18n.networkButton), 53 | ), 54 | body: ListView( 55 | children: [ 56 | Row( 57 | children: [ 58 | Expanded( 59 | child: TextField( 60 | controller: editingController, 61 | ), 62 | ), 63 | FlatButton( 64 | child: Text(currentI18n.play), 65 | onPressed: _playInput, 66 | ), 67 | ], 68 | ), 69 | Container( 70 | height: 400, 71 | child: IjkPlayer( 72 | mediaController: mediaController, 73 | ), 74 | ), 75 | ], 76 | ), 77 | ); 78 | } 79 | 80 | void _playInput() async { 81 | var text = editingController.text; 82 | await mediaController.setNetworkDataSource(text, autoPlay: true); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /example/lib/page/gallery_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | import 'package:ijkplayer_example/i18n/i18n.dart'; 4 | import 'package:photo/photo.dart'; 5 | import 'package:photo_manager/photo_manager.dart'; 6 | 7 | class PlayGalleryPage extends StatefulWidget { 8 | @override 9 | _PlayGalleryPageState createState() => _PlayGalleryPageState(); 10 | } 11 | 12 | class _PlayGalleryPageState extends State { 13 | IjkMediaController mediaController = IjkMediaController(); 14 | 15 | String mediaUrl; 16 | 17 | @override 18 | void initState() { 19 | super.initState(); 20 | mediaController.addIjkPlayerOptions([ 21 | TargetPlatform.iOS, 22 | TargetPlatform.android, 23 | ], [ 24 | IjkOption(IjkOptionCategory.player, 'mediacodec', 1), 25 | IjkOption(IjkOptionCategory.player, 'mediacodec-hevc', 1), 26 | IjkOption(IjkOptionCategory.player, 'videotoolbox', 1), 27 | IjkOption(IjkOptionCategory.player, 'video-max-frame-width-default', 1), 28 | IjkOption(IjkOptionCategory.player, 'videotoolbox-max-frame-width', 1920), 29 | // IjkOption(IjkOptionCategory.player, 'videotoolbox-max-frame-width', 960), 30 | ]); 31 | } 32 | 33 | @override 34 | void dispose() { 35 | mediaController.dispose(); 36 | super.dispose(); 37 | } 38 | 39 | @override 40 | Widget build(BuildContext context) { 41 | return Scaffold( 42 | appBar: AppBar( 43 | title: Text(currentI18n.photoButton), 44 | ), 45 | body: ListView( 46 | children: [ 47 | FlatButton( 48 | child: Text("Pick"), 49 | onPressed: _pickVideo, 50 | ), 51 | ListTile( 52 | title: Text("mediaUrl = $mediaUrl"), 53 | ), 54 | Container( 55 | height: 400, 56 | child: IjkPlayer( 57 | mediaController: mediaController, 58 | ), 59 | ), 60 | ], 61 | ), 62 | ); 63 | } 64 | 65 | void _pickVideo() async { 66 | var assetList = await PhotoPicker.pickAsset( 67 | context: context, 68 | pickType: PickType.onlyVideo, 69 | maxSelected: 1, 70 | ); 71 | if (assetList?.isNotEmpty == true) { 72 | var asset = assetList[0]; 73 | _playVideo(asset); 74 | } 75 | } 76 | 77 | void _playVideo(AssetEntity asset) async { 78 | mediaUrl = await asset.getMediaUrl(); 79 | setState(() {}); 80 | final file = await asset.file; 81 | if (file != null && file.existsSync()) { 82 | await mediaController.setFileDataSource(file); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /example/lib/page/ijk_status_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | import 'package:ijkplayer_example/i18n/i18n.dart'; 4 | import 'package:ijkplayer_example/utils/options_utils.dart'; 5 | 6 | class IjkStatusPage extends StatefulWidget { 7 | @override 8 | _IjkStatusPageState createState() => _IjkStatusPageState(); 9 | } 10 | 11 | class _IjkStatusPageState extends State { 12 | TextEditingController editingController = TextEditingController(); 13 | IjkMediaController mediaController = IjkMediaController(); 14 | 15 | @override 16 | void initState() { 17 | super.initState(); 18 | editingController.text = 19 | "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4"; 20 | OptionUtils.addDefaultOptions(mediaController); 21 | } 22 | 23 | @override 24 | void dispose() { 25 | editingController.dispose(); 26 | mediaController.dispose(); 27 | super.dispose(); 28 | } 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return Scaffold( 33 | appBar: AppBar( 34 | title: Text(currentI18n.ijkStatusTitle), 35 | ), 36 | body: ListView( 37 | children: [ 38 | Row( 39 | children: [ 40 | Expanded( 41 | child: TextField( 42 | controller: editingController, 43 | ), 44 | ), 45 | FlatButton( 46 | child: Text(currentI18n.play), 47 | onPressed: _playInput, 48 | ), 49 | ], 50 | ), 51 | AspectRatio( 52 | aspectRatio: 12 / 7, 53 | child: buildIjkPlayer(), 54 | ), 55 | ], 56 | ), 57 | ); 58 | } 59 | 60 | void _playInput() async { 61 | var text = editingController.text; 62 | await mediaController.setNetworkDataSource(text, autoPlay: true); 63 | } 64 | 65 | Widget buildIjkPlayer() { 66 | return IjkPlayer( 67 | mediaController: mediaController, 68 | statusWidgetBuilder: _buildStatusWidget, 69 | ); 70 | } 71 | 72 | Widget _buildStatusWidget( 73 | BuildContext context, 74 | IjkMediaController controller, 75 | IjkStatus status, 76 | ) { 77 | if (status == IjkStatus.noDatasource) { 78 | return Center( 79 | child: Text( 80 | "no data", 81 | style: TextStyle(color: Colors.white), 82 | ), 83 | ); 84 | } 85 | 86 | // you can custom your self status widget 87 | return IjkStatusWidget.buildStatusWidget(context, controller, status); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /example/lib/page/index.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | import 'package:ijkplayer_example/page/paging_page.dart'; 4 | import 'package:ijkplayer_example/page/screen_shot_page.dart'; 5 | import 'package:ijkplayer_example/page/video_list.dart'; 6 | 7 | import '../i18n/i18n.dart'; 8 | import 'asset_page.dart'; 9 | import 'auto_full_screen.dart'; 10 | import 'controller_stream_use.dart'; 11 | import 'custom_ijk_opt_page.dart'; 12 | import 'developing/develop_index.dart'; 13 | import 'dialog_video_page.dart'; 14 | import 'error_url.dart'; 15 | import 'full_screen.dart'; 16 | import 'gallery_page.dart'; 17 | import 'ijk_status_page.dart'; 18 | import 'in_overlay_page.dart'; 19 | import 'network.dart'; 20 | import 'speed_page.dart'; 21 | 22 | class IndexPage extends StatefulWidget { 23 | @override 24 | _IndexPageState createState() => _IndexPageState(); 25 | } 26 | 27 | class _IndexPageState extends State { 28 | @override 29 | Widget build(BuildContext context) { 30 | return Scaffold( 31 | appBar: AppBar( 32 | title: Text(currentI18n.indexTitle), 33 | ), 34 | body: ListView( 35 | children: [ 36 | buildButton("For developer, user don't use.", DevelopingIndexPage()), 37 | buildButton(currentI18n.networkButton, NetworkPage()), 38 | buildButton(currentI18n.photoButton, PlayGalleryPage()), 39 | buildButton(currentI18n.assetButton, AssetPage()), 40 | buildButton(currentI18n.listViewButton, VideoList()), 41 | buildButton(currentI18n.fullScreenAutoButton, FullScreen()), 42 | buildButton(currentI18n.fullScreenManualButton, FullScreen2()), 43 | buildButton(currentI18n.autoFullScreenOnPlay, AutoFullScreenPage()), 44 | buildButton(currentI18n.withDialogButton, DialogVideoPage()), 45 | buildButton(currentI18n.pageViewButton, PagingPickPage()), 46 | buildButton(currentI18n.useStreamUsage, ControllerStreamUsagePage()), 47 | buildButton(currentI18n.screenshotTitle, ScreenShotPage()), 48 | buildButton(currentI18n.overlayPageTitle, InOverlayPage()), 49 | buildButton(currentI18n.ijkStatusTitle, IjkStatusPage()), 50 | buildButton(currentI18n.customOption, CustomIjkOptionPage()), 51 | buildButton(currentI18n.errorUrl, ErrorUrlPage()), 52 | buildButton(currentI18n.setSpeed, SpeedPage()), 53 | buildButton( 54 | currentI18n.customFullScreenWidget, CustomFullControllerPage()), 55 | FlatButton( 56 | onPressed: () { 57 | IjkManager.initIJKPlayer(); 58 | }, 59 | child: Text("release all ijkplayer resource"), 60 | ), 61 | ], 62 | ), 63 | ); 64 | } 65 | 66 | Widget buildButton(String text, Widget targetPage) { 67 | return FlatButton( 68 | onPressed: () { 69 | Navigator.push(context, MaterialPageRoute(builder: (_) => targetPage)); 70 | }, 71 | child: Text(text), 72 | ); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /example/lib/page/network.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | import 'package:ijkplayer_example/i18n/i18n.dart'; 4 | import 'package:ijkplayer_example/utils/options_utils.dart'; 5 | 6 | class NetworkPage extends StatefulWidget { 7 | @override 8 | _NetworkPageState createState() => _NetworkPageState(); 9 | } 10 | 11 | class _NetworkPageState extends State { 12 | TextEditingController editingController = TextEditingController(); 13 | IjkMediaController mediaController = IjkMediaController(); 14 | 15 | @override 16 | void initState() { 17 | super.initState(); 18 | 19 | editingController.text = 20 | "https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_30mb.mp4"; 21 | 22 | editingController.text = 23 | "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4"; 24 | 25 | // editingController.text = 26 | // "https://media001.geekbang.org/f433fd1ce5e84d27b1101f0dad72a126/de563bb4aba94b5f95f448b33be4dd9f-9aede6861be944d696fe365f3a33b7b4-sd.m3u8"; 27 | 28 | // editingController.text = 29 | // "https://cctvalih5ca.v.myalicdn.com/live/cctv1_2/index.m3u8"; 30 | 31 | // editingController.text = "http://222.207.48.30/hls/startv.m3u8"; 32 | 33 | // editingController.text = "rtmp://172.16.100.245:1935/live1"; 34 | 35 | // editingController.text = "http://172.16.100.245:5000/meng.mp4"; 36 | // editingController.text = "http://172.16.100.245:5000/sample1.mp4"; 37 | // editingController.text = 38 | // "http://172.16.100.245:5000/05-2%20ffmpeg%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8Log%E7%B3%BB%E7%BB%9F.mp4"; 39 | // editingController.text = 40 | // "http://172.16.100.245:5000/09-01%20%E7%AC%AC%E4%B8%80%E4%B8%AAJNI%E7%A8%8B%E5%BA%8F.mp4"; 41 | // editingController.text = "http://172.16.100.245:5000/trailer.mp4"; 42 | 43 | OptionUtils.addDefaultOptions(mediaController); 44 | } 45 | 46 | @override 47 | void dispose() { 48 | editingController.dispose(); 49 | mediaController.dispose(); 50 | super.dispose(); 51 | } 52 | 53 | @override 54 | Widget build(BuildContext context) { 55 | return Scaffold( 56 | appBar: AppBar( 57 | title: Text(currentI18n.networkButton), 58 | ), 59 | body: ListView( 60 | children: [ 61 | Row( 62 | children: [ 63 | Expanded( 64 | child: TextField( 65 | controller: editingController, 66 | ), 67 | ), 68 | FlatButton( 69 | child: Text(currentI18n.play), 70 | onPressed: _playInput, 71 | ), 72 | ], 73 | ), 74 | Container( 75 | height: 400, 76 | child: IjkPlayer( 77 | mediaController: mediaController, 78 | ), 79 | ), 80 | ], 81 | ), 82 | ); 83 | } 84 | 85 | void _playInput() async { 86 | var text = editingController.text; 87 | await mediaController.setNetworkDataSource( 88 | text, 89 | autoPlay: true, 90 | headers: {}, 91 | ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /example/lib/page/screen_shot_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | import 'dart:async'; 3 | import 'package:flutter/material.dart'; 4 | 5 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 6 | import 'package:ijkplayer_example/i18n/i18n.dart'; 7 | import 'dart:ui' as ui; 8 | 9 | import 'package:ijkplayer_example/utils/options_utils.dart'; 10 | 11 | class ScreenShotPage extends StatefulWidget { 12 | @override 13 | _ScreenShotPageState createState() => _ScreenShotPageState(); 14 | } 15 | 16 | class _ScreenShotPageState extends State { 17 | IjkMediaController mediaController = IjkMediaController(); 18 | 19 | ImageProvider provider; 20 | 21 | @override 22 | void initState() { 23 | super.initState(); 24 | OptionUtils.addDefaultOptions(mediaController); 25 | mediaController.setDataSource( 26 | DataSource.network( 27 | "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4"), 28 | // "rtmp://58.200.131.2:1935/livetv/hunantv"), 29 | autoPlay: true); 30 | } 31 | 32 | @override 33 | void dispose() { 34 | mediaController.dispose(); 35 | super.dispose(); 36 | } 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | return Scaffold( 41 | appBar: AppBar( 42 | title: Text(currentI18n.screenshotTitle), 43 | ), 44 | body: ListView( 45 | children: [ 46 | AspectRatio( 47 | aspectRatio: 1280 / 720, 48 | child: IjkPlayer( 49 | mediaController: mediaController, 50 | ), 51 | ), 52 | FlatButton( 53 | child: Text(currentI18n.screenshotTitle), 54 | onPressed: () async { 55 | var uint8List = await mediaController.screenShot(); 56 | if (uint8List == null) { 57 | return; 58 | } 59 | provider = MemoryImage(uint8List); 60 | setState(() {}); 61 | }, 62 | ), 63 | provider == null 64 | ? Container() 65 | : Image( 66 | image: provider, 67 | ), 68 | ], 69 | ), 70 | ); 71 | } 72 | } 73 | 74 | Future getImageForUint8List(Uint8List imageSrc) { 75 | Completer completer = Completer(); 76 | ui.decodeImageFromList(imageSrc, (img) { 77 | completer.complete(Size(img.width.toDouble(), img.height.toDouble())); 78 | img.dispose(); 79 | }); 80 | return completer.future; 81 | } 82 | -------------------------------------------------------------------------------- /example/lib/page/speed_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | import 'package:ijkplayer_example/i18n/i18n.dart'; 4 | import 'package:ijkplayer_example/utils/options_utils.dart'; 5 | 6 | class SpeedPage extends StatefulWidget { 7 | @override 8 | _SpeedPageState createState() => _SpeedPageState(); 9 | } 10 | 11 | class _SpeedPageState extends State { 12 | IjkMediaController controller = IjkMediaController(); 13 | 14 | double speed = 1; 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | var url = "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4"; 20 | var dataSource = DataSource.network(url); 21 | 22 | OptionUtils.addDefaultOptions(controller); 23 | controller?.setDataSource(dataSource, autoPlay: true); 24 | } 25 | 26 | @override 27 | void dispose() { 28 | controller.dispose(); 29 | controller = null; 30 | super.dispose(); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return Scaffold( 36 | appBar: AppBar( 37 | title: Text(currentI18n.setSpeed), 38 | ), 39 | body: Container( 40 | child: ListView( 41 | children: [ 42 | Container( 43 | height: 280, 44 | child: IjkPlayer( 45 | mediaController: controller, 46 | ), 47 | ), 48 | Slider( 49 | value: speed, 50 | max: 2, 51 | min: 0.5, 52 | divisions: 6, 53 | onChanged: _onChangeSpeed, 54 | ), 55 | Center(child: Text("speed is $speed")), 56 | ], 57 | ), 58 | ), 59 | ); 60 | } 61 | 62 | void _onChangeSpeed(double value) { 63 | this.speed = value; 64 | setState(() {}); 65 | controller?.setSpeed(speed); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /example/lib/page/video_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | import 'package:ijkplayer_example/i18n/i18n.dart'; 4 | import 'package:ijkplayer_example/utils/options_utils.dart'; 5 | 6 | class VideoList extends StatefulWidget { 7 | @override 8 | _VideoListState createState() => _VideoListState(); 9 | } 10 | 11 | class _VideoListState extends State { 12 | var list = [ 13 | DataSource.network( 14 | "https://www.sample-videos.com/video123/mp4/360/big_buck_bunny_360p_30mb.mp4"), 15 | DataSource.network( 16 | "https://www.sample-videos.com/video123/mp4/360/big_buck_bunny_360p_30mb.mp4"), 17 | DataSource.asset("assets/sample1.mp4") 18 | ]; 19 | 20 | var map = {}; 21 | 22 | @override 23 | void initState() { 24 | super.initState(); 25 | for (var data in list) { 26 | var controller = IjkMediaController(); 27 | OptionUtils.addDefaultOptions(controller); 28 | map[data] = controller; 29 | // controller.setDataSource(data); 30 | } 31 | } 32 | 33 | @override 34 | void dispose() { 35 | map.values.forEach((c) { 36 | c.dispose(); 37 | }); 38 | super.dispose(); 39 | } 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | return Scaffold( 44 | appBar: AppBar( 45 | title: Text(currentI18n.listViewButton), 46 | ), 47 | body: ListView.separated( 48 | itemBuilder: _buildItem, 49 | separatorBuilder: (BuildContext context, int index) { 50 | return Container( 51 | height: 10.0, 52 | color: Colors.blue, 53 | ); 54 | }, 55 | itemCount: list.length, 56 | ), 57 | ); 58 | } 59 | 60 | Widget _buildItem(BuildContext context, int index) { 61 | return AspectRatio( 62 | child: VideoItem(list[index]), 63 | aspectRatio: 1280 / 500, 64 | ); 65 | } 66 | } 67 | 68 | class VideoItem extends StatefulWidget { 69 | final DataSource dataSource; 70 | 71 | VideoItem(this.dataSource); 72 | 73 | @override 74 | _VideoItemState createState() => _VideoItemState(); 75 | } 76 | 77 | class _VideoItemState extends State { 78 | IjkMediaController controller; 79 | 80 | var isInit = false; 81 | var isLoading = false; 82 | 83 | @override 84 | void initState() { 85 | super.initState(); 86 | controller = IjkMediaController(); 87 | } 88 | 89 | @override 90 | void dispose() { 91 | controller?.dispose(); 92 | super.dispose(); 93 | } 94 | 95 | @override 96 | Widget build(BuildContext context) { 97 | if (!isInit) { 98 | Widget stateButton = IconButton( 99 | icon: Icon(Icons.play_arrow), 100 | onPressed: _play, 101 | color: Colors.white, 102 | ); 103 | 104 | if (isLoading) { 105 | stateButton = CircularProgressIndicator(); 106 | } 107 | 108 | var center = Center( 109 | child: Container( 110 | width: 60.0, 111 | height: 60.0, 112 | child: stateButton, 113 | ), 114 | ); 115 | 116 | return Stack( 117 | children: [ 118 | Container( 119 | color: Colors.black, 120 | ), 121 | center, 122 | ], 123 | ); 124 | } 125 | 126 | var ijkPlayer = IjkPlayer( 127 | mediaController: controller, 128 | controllerWidgetBuilder: _buildControllerWidget, 129 | ); 130 | return ijkPlayer; 131 | } 132 | 133 | void _play() async { 134 | setState(() { 135 | isLoading = true; 136 | }); 137 | await controller.setDataSource(widget.dataSource, autoPlay: true); 138 | await controller.pauseOtherController(); 139 | setState(() { 140 | isLoading = false; 141 | isInit = true; 142 | }); 143 | } 144 | 145 | Widget _buildControllerWidget(IjkMediaController controller) { 146 | return DefaultIJKControllerWidget( 147 | controller: controller, 148 | verticalGesture: false, 149 | ); 150 | } 151 | } 152 | 153 | class PauseOtherNotification extends Notification {} 154 | -------------------------------------------------------------------------------- /example/lib/utils/options_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | 4 | class OptionUtils { 5 | static void addDefaultOptions(IjkMediaController controller) { 6 | controller.addIjkPlayerOptions( 7 | [TargetPlatform.iOS, TargetPlatform.android], 8 | createIJKOptions(), 9 | ); 10 | } 11 | 12 | static Set createIJKOptions() { 13 | return [ 14 | IjkOption(IjkOptionCategory.player, "mediacodec", 1), 15 | IjkOption(IjkOptionCategory.player, "mediacodec-hevc", 1), 16 | IjkOption(IjkOptionCategory.player, "videotoolbox", 1), 17 | IjkOption(IjkOptionCategory.player, "opensles", 0), 18 | IjkOption(IjkOptionCategory.player, "overlay-format", 0x32335652), 19 | IjkOption(IjkOptionCategory.player, "framedrop", 1), 20 | IjkOption(IjkOptionCategory.player, "start-on-prepared", 0), 21 | IjkOption(IjkOptionCategory.format, "http-detect-range-support", 0), 22 | IjkOption(IjkOptionCategory.codec, "skip_loop_filter", 48), 23 | ].toSet(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: ijkplayer_example 2 | description: Demonstrates how to use the ijkplayer plugin. 3 | publish_to: "none" 4 | 5 | environment: 6 | sdk: ">=2.1.0 <3.0.0" 7 | 8 | dependencies: 9 | flutter: 10 | sdk: flutter 11 | # The following adds the Cupertino Icons font to your application. 12 | # Use with the CupertinoIcons class for iOS style icons. 13 | cupertino_icons: ^0.1.2 14 | photo: ^0.4.8 15 | 16 | oktoast: ^2.1.7 17 | 18 | flutter_localizations: 19 | sdk: flutter 20 | intl: ">=0.15.8 <1.0.0" 21 | 22 | flutter_ijkplayer: 23 | path: ../ 24 | 25 | dependency_overrides: 26 | photo_manager: 27 | git: 28 | url: https://github.com/caijinglong/flutter_photo_manager.git 29 | ref: master 30 | 31 | dev_dependencies: 32 | flutter_test: 33 | sdk: flutter 34 | 35 | intl_translation: ^0.17.3 36 | 37 | # For information on the generic Dart part of this file, see the 38 | # following page: https://www.dartlang.org/tools/pub/pubspec 39 | 40 | # The following section is specific to Flutter. 41 | flutter: 42 | # The following line ensures that the Material Icons font is 43 | # included with your application, so that you can use the icons in 44 | # the material Icons class. 45 | uses-material-design: true 46 | # To add assets to your application, add an assets section, like this: 47 | # assets: 48 | # - images/a_dot_burr.jpeg 49 | # - images/a_dot_ham.jpeg 50 | assets: 51 | - assets/ 52 | # An image asset can refer to one or more resolution-specific "variants", see 53 | # https://flutter.io/assets-and-images/#resolution-aware. 54 | # For details regarding adding assets from package dependencies, see 55 | # https://flutter.io/assets-and-images/#from-packages 56 | # To add custom fonts to your application, add a fonts section here, 57 | # in this "flutter" section. Each entry in this list should have a 58 | # "family" key with the font family name, and a "fonts" key with a 59 | # list giving the asset and other descriptors for the font. For 60 | # example: 61 | # fonts: 62 | # - family: Schyler 63 | # fonts: 64 | # - asset: fonts/Schyler-Regular.ttf 65 | # - asset: fonts/Schyler-Italic.ttf 66 | # style: italic 67 | # - family: Trajan Pro 68 | # fonts: 69 | # - asset: fonts/TrajanPro.ttf 70 | # - asset: fonts/TrajanPro_Bold.ttf 71 | # weight: 700 72 | # 73 | # For details regarding fonts from package dependencies, 74 | # see https://flutter.io/custom-fonts/#from-packages 75 | -------------------------------------------------------------------------------- /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 | 11 | import 'package:ijkplayer_example/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Verify Platform version', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that platform version is retrieved. 19 | expect( 20 | find.byWidgetPredicate( 21 | (Widget widget) => 22 | widget is Text && widget.data.startsWith('Running on:'), 23 | ), 24 | findsOneWidget, 25 | ); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /ijkplayer.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaiJingLong/flutter_ijkplayer/468040c4222c26f65eb63ab22676362f9d350b9b/ios/Assets/.gitkeep -------------------------------------------------------------------------------- /ios/Classes/CoolFlutterIJK.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Caijinglong on 2019-03-08. 3 | // 4 | 5 | #import 6 | #import 7 | #import "CoolIjkNotifyChannel.h" 8 | #import "CoolIjkOption.h" 9 | 10 | @interface CoolFlutterIJK : NSObject 11 | 12 | @property(nonatomic, strong) NSObject *registrar; 13 | 14 | @property(nonatomic, strong) NSArray *options; 15 | 16 | @property(nonatomic, assign) BOOL isDisposed; 17 | 18 | - (instancetype)initWithRegistrar:(NSObject *)registrar; 19 | 20 | + (instancetype)ijkWithRegistrar:(NSObject *)registrar; 21 | 22 | - (int64_t)id; 23 | 24 | - (void)dispose; 25 | 26 | - (void)setDegree:(int)degree; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /ios/Classes/CoolFlutterIjkManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Caijinglong on 2019-03-08. 3 | // 4 | 5 | #import 6 | #import 7 | 8 | @class CoolFlutterIJK; 9 | 10 | @interface CoolFlutterIjkManager : NSObject 11 | 12 | @property(nonatomic, strong) NSObject *registrar; 13 | 14 | - (instancetype)initWithRegistrar:(NSObject *)registrar; 15 | 16 | + (instancetype)managerWithRegistrar:(NSObject *)registrar; 17 | 18 | - (int64_t)createWithCall:(FlutterMethodCall*) call; 19 | 20 | - (CoolFlutterIJK *)findIJKWithId:(int64_t)id1; 21 | 22 | - (int) ijkCount; 23 | 24 | - (void)disposeWithId:(int64_t)id; 25 | 26 | - (void)disposeAll; 27 | @end 28 | -------------------------------------------------------------------------------- /ios/Classes/CoolFlutterIjkManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Caijinglong on 2019-03-08. 3 | // 4 | 5 | #import "CoolFlutterIjkManager.h" 6 | #import "CoolFlutterIJK.h" 7 | #import 8 | #import "CoolIjkOption.h" 9 | 10 | @implementation CoolFlutterIjkManager { 11 | NSMutableDictionary *dict; 12 | } 13 | 14 | 15 | - (instancetype)initWithRegistrar:(NSObject *)registrar { 16 | self = [super init]; 17 | if (self) { 18 | self.registrar = registrar; 19 | dict = [NSMutableDictionary new]; 20 | } 21 | 22 | return self; 23 | } 24 | 25 | + (instancetype)managerWithRegistrar:(NSObject *)registrar { 26 | return [[self alloc] initWithRegistrar:registrar]; 27 | } 28 | 29 | - (int64_t)createWithCall:(FlutterMethodCall*) call { 30 | NSArray* options = [self getOptionsFromCall:call]; 31 | CoolFlutterIJK *ijk = [CoolFlutterIJK ijkWithRegistrar:self.registrar]; 32 | ijk.options = options; 33 | NSNumber *number = @([ijk id]); 34 | dict[number] = ijk; 35 | return [ijk id]; 36 | } 37 | 38 | -(NSArray*)getOptionsFromCall:(FlutterMethodCall *)call{ 39 | NSMutableArray *array = [NSMutableArray new]; 40 | 41 | NSDictionary *args = call.arguments; 42 | NSArray *dartOptions = args[@"options"]; 43 | 44 | for (NSDictionary *dict in dartOptions){ 45 | int type = [dict[@"category"] intValue]; 46 | NSString *key = dict[@"key"]; 47 | id value = dict[@"value"]; 48 | CoolIjkOption *option = [CoolIjkOption new]; 49 | option.key = key; 50 | option.value = value; 51 | option.type = type; 52 | 53 | [array addObject:option]; 54 | } 55 | 56 | return array; 57 | } 58 | 59 | - (CoolFlutterIJK *)findIJKWithId:(int64_t)id { 60 | return dict[@(id)]; 61 | } 62 | 63 | - (int)ijkCount{ 64 | if(!dict){ 65 | return 0; 66 | } 67 | return [dict count]; 68 | } 69 | 70 | - (void)disposeWithId:(int64_t)id { 71 | CoolFlutterIJK *ijk = dict[@(id)]; 72 | if (ijk) { 73 | [ijk dispose]; 74 | [dict removeObjectForKey:@(id)]; 75 | } 76 | } 77 | 78 | - (void)disposeAll { 79 | NSArray *keys = dict.allKeys; 80 | for (NSNumber *key in keys) { 81 | CoolFlutterIJK *ijk = dict[key]; 82 | [dict removeObjectForKey:key]; 83 | [ijk dispose]; 84 | } 85 | } 86 | @end 87 | -------------------------------------------------------------------------------- /ios/Classes/CoolFlutterResult.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Caijinglong on 2019-06-12. 3 | // 4 | 5 | 6 | #import 7 | 8 | @interface CoolFlutterResult : NSObject 9 | 10 | @property(nonatomic, strong) FlutterResult result; 11 | 12 | @property(nonatomic, assign) BOOL isReply; 13 | 14 | - (instancetype)initWithResult:(FlutterResult)result; 15 | 16 | + (instancetype)resultWithResult:(FlutterResult)result; 17 | 18 | - (void)replyResult:(id _Nullable)result; 19 | 20 | @end -------------------------------------------------------------------------------- /ios/Classes/CoolFlutterResult.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Caijinglong on 2019-06-12. 3 | // 4 | 5 | #import "CoolFlutterResult.h" 6 | 7 | @implementation CoolFlutterResult { 8 | 9 | } 10 | - (instancetype)initWithResult:(FlutterResult)result { 11 | self = [super init]; 12 | if (self) { 13 | self.result = result; 14 | self.isReply = NO; 15 | } 16 | 17 | return self; 18 | } 19 | 20 | + (instancetype)resultWithResult:(FlutterResult)result { 21 | return [[self alloc] initWithResult:result]; 22 | } 23 | 24 | - (void)replyResult:(id _Nullable)result { 25 | if (self.isReply) { 26 | return; 27 | } 28 | self.isReply = YES; 29 | self.result(result); 30 | } 31 | 32 | 33 | @end -------------------------------------------------------------------------------- /ios/Classes/CoolIjkNotifyChannel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Caijinglong on 2019-03-15. 3 | // 4 | 5 | #import 6 | #import 7 | #import 8 | 9 | @class CoolVideoInfo; 10 | 11 | @protocol KKIjkNotifyDelegate 12 | - (CoolVideoInfo *)getInfo; 13 | 14 | - (void)setDegree:(int)newDegree; 15 | 16 | - (void)onLoadStateChange; 17 | @end 18 | 19 | @interface CoolIjkNotifyChannel : NSObject 20 | 21 | @property(nonatomic, strong) IJKFFMoviePlayerController *controller; 22 | 23 | @property(nonatomic, assign) int64_t textureId; 24 | 25 | @property(nonatomic, strong) NSObject *registrar; 26 | 27 | @property(nonatomic, weak) NSObject *infoDelegate; 28 | 29 | - (instancetype)initWithController:(IJKFFMoviePlayerController *)controller textureId:(int64_t)textureId 30 | registrar:(NSObject *)registrar; 31 | 32 | + (instancetype)channelWithController:(IJKFFMoviePlayerController *)controller textureId:(int64_t)textureId 33 | registrar:(NSObject *)registrar; 34 | 35 | 36 | - (void)dispose; 37 | 38 | @end -------------------------------------------------------------------------------- /ios/Classes/CoolIjkOption.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoolIjkOption.h 3 | // flutter_ijkplayer 4 | // 5 | // Created by Caijinglong on 2019/4/12. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface CoolIjkOption : NSObject 13 | 14 | @property(nonatomic,assign) int type; 15 | @property(nonatomic,copy) NSString *key; 16 | @property(nonatomic,copy) id value; 17 | 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /ios/Classes/CoolIjkOption.m: -------------------------------------------------------------------------------- 1 | // 2 | // CoolIjkOption.m 3 | // flutter_ijkplayer 4 | // 5 | // Created by Caijinglong on 2019/4/12. 6 | // 7 | 8 | #import "CoolIjkOption.h" 9 | 10 | @implementation CoolIjkOption 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /ios/Classes/CoolVideoInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Caijinglong on 2019-03-15. 3 | // 4 | 5 | #import 6 | 7 | 8 | @interface CoolVideoInfo : NSObject 9 | 10 | @property(nonatomic, assign) NSTimeInterval duration; 11 | 12 | @property(nonatomic, assign) NSTimeInterval currentPosition; 13 | 14 | @property(nonatomic, assign) CGSize size; 15 | 16 | @property(nonatomic, assign) BOOL isPlaying; 17 | 18 | @property(nonatomic, assign) int degree; 19 | 20 | /** 21 | * Unit is Byte. 22 | */ 23 | @property(nonatomic, assign) int64_t tcpSpeed; 24 | 25 | @property(nonatomic, assign) CGFloat outputFps; 26 | 27 | - (NSDictionary *)toMap; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /ios/Classes/CoolVideoInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Caijinglong on 2019-03-15. 3 | // 4 | 5 | #import "CoolVideoInfo.h" 6 | 7 | 8 | @implementation CoolVideoInfo { 9 | 10 | } 11 | 12 | - (instancetype)init { 13 | self = [super init]; 14 | if (self) { 15 | self.degree = 0; 16 | } 17 | 18 | return self; 19 | } 20 | 21 | 22 | - (NSDictionary *)toMap { 23 | NSMutableDictionary *dict = [NSMutableDictionary new]; 24 | dict[@"width"] = @((int) self.size.width); 25 | dict[@"height"] = @((int) self.size.height); 26 | dict[@"duration"] = @(self.duration); 27 | dict[@"currentPosition"] = @(self.currentPosition); 28 | dict[@"isPlaying"] = @(self.isPlaying); 29 | dict[@"degree"] = @(self.degree); 30 | dict[@"tcpSpeed"] = @(self.tcpSpeed); 31 | dict[@"outputFps"] = @(self.outputFps); 32 | return dict; 33 | } 34 | 35 | @end -------------------------------------------------------------------------------- /ios/Classes/FlutterViewController+CoolStatusBarHidden.h: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterViewController+CoolViewController.h 3 | // flutter_ijkplayer 4 | // 5 | // Created by Caijinglong on 2019/11/8. 6 | // 7 | #import 8 | 9 | NS_ASSUME_NONNULL_BEGIN 10 | 11 | @interface FlutterViewController (CoolViewController) 12 | 13 | -(void)showStatusBar; 14 | 15 | -(void)hideStatusBar; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /ios/Classes/FlutterViewController+CoolStatusBarHidden.m: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterViewController+CoolViewController.m 3 | // flutter_ijkplayer 4 | // 5 | // Created by Caijinglong on 2019/11/8. 6 | // 7 | 8 | #import "FlutterViewController+CoolStatusBarHidden.h" 9 | #import 10 | 11 | @implementation FlutterViewController (CoolViewController) 12 | 13 | -(void)showStatusBar{ 14 | objc_setAssociatedObject(self, @selector(showStatusBar), @"show", OBJC_ASSOCIATION_RETAIN_NONATOMIC); 15 | [UIView animateWithDuration:1 animations:^{ 16 | [self setNeedsStatusBarAppearanceUpdate]; 17 | }]; 18 | } 19 | 20 | -(void)hideStatusBar{ 21 | objc_setAssociatedObject(self, @selector(showStatusBar), @"hide", OBJC_ASSOCIATION_RETAIN_NONATOMIC); 22 | [UIView animateWithDuration:1 animations:^{ 23 | [self setNeedsStatusBarAppearanceUpdate]; 24 | }]; 25 | } 26 | 27 | -(BOOL)isStatusBarShow{ 28 | NSString *value = objc_getAssociatedObject(self, @selector(showStatusBar)); 29 | return ![value isEqualToString:@"hide"]; 30 | } 31 | 32 | - (UIStatusBarAnimation)preferredStatusBarUpdateAnimation{ 33 | return UIStatusBarAnimationFade; 34 | } 35 | 36 | -(BOOL)prefersStatusBarHidden{ 37 | return ![self isStatusBarShow]; 38 | } 39 | 40 | -(void)viewDidDisappear:(BOOL)animated{ 41 | objc_removeAssociatedObjects(self); 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /ios/Classes/IjkplayerPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface IjkplayerPlugin : NSObject 4 | 5 | @property(nonatomic, strong) NSObject *registrar; 6 | 7 | - (instancetype)initWithRegistrar:(NSObject *)registrar; 8 | 9 | + (instancetype)pluginWithRegistrar:(NSObject *)registrar; 10 | 11 | + (instancetype)sharedInstance; 12 | 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /ios/flutter_ijkplayer.dev.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'flutter_ijkplayer' 6 | s.version = '0.0.1' 7 | s.summary = 'IjkPlayer plugin for flutter' 8 | s.description = <<-DESC 9 | A new flutter plugin project. 10 | DESC 11 | s.homepage = 'http://example.com' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Caijinglong' => 'cjl_spy@163.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' , 'IJKMediaFramework.framework' 16 | s.public_header_files = 'Classes/**/*.h' 17 | s.dependency 'Flutter' 18 | s.static_framework = true 19 | s.ios.deployment_target = '8.0' 20 | 21 | s.ios.vendored_frameworks = 'IJKMediaFramework.framework' 22 | s.frameworks = "AudioToolbox", "AVFoundation", "CoreGraphics", "CoreMedia", "CoreVideo", "MobileCoreServices", "OpenGLES", "QuartzCore", "VideoToolbox", "Foundation", "UIKit", "MediaPlayer" 23 | s.libraries = "bz2", "z", "stdc++" 24 | # s.dependency 'FlutterIJK', '~> 0.1.0' 25 | 26 | # s.script_phase = {:name => 'extract framework', :script=> 'echo "Hello World"; pwd' ,:execution_position => :before_compile} 27 | 28 | end 29 | 30 | -------------------------------------------------------------------------------- /ios/flutter_ijkplayer.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'flutter_ijkplayer' 6 | s.version = '0.0.1' 7 | s.summary = 'IjkPlayer plugin for flutter' 8 | s.description = <<-DESC 9 | A new flutter plugin project. 10 | DESC 11 | s.homepage = 'http://example.com' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Caijinglong' => 'cjl_spy@163.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' , 'IJKMediaFramework.framework' 16 | s.public_header_files = 'Classes/**/*.h' 17 | s.dependency 'Flutter' 18 | s.static_framework = true 19 | s.ios.deployment_target = '8.0' 20 | 21 | # s.ios.vendored_frameworks = 'IJKMediaFramework.framework' 22 | # s.frameworks = "AudioToolbox", "AVFoundation", "CoreGraphics", "CoreMedia", "CoreVideo", "MobileCoreServices", "OpenGLES", "QuartzCore", "VideoToolbox", "Foundation", "UIKit", "MediaPlayer" 23 | # s.libraries = "bz2", "z", "stdc++" 24 | s.dependency 'FlutterIJK', '~> 0.2.3' 25 | 26 | # s.script_phase = {:name => 'extract framework', :script=> 'echo "Hello World"; pwd' ,:execution_position => :before_compile} 27 | 28 | end 29 | 30 | -------------------------------------------------------------------------------- /ios/flutter_ijkplayer.prod.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'flutter_ijkplayer' 6 | s.version = '0.0.1' 7 | s.summary = 'IjkPlayer plugin for flutter' 8 | s.description = <<-DESC 9 | A new flutter plugin project. 10 | DESC 11 | s.homepage = 'http://example.com' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Caijinglong' => 'cjl_spy@163.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' , 'IJKMediaFramework.framework' 16 | s.public_header_files = 'Classes/**/*.h' 17 | s.dependency 'Flutter' 18 | s.static_framework = true 19 | s.ios.deployment_target = '8.0' 20 | 21 | # s.ios.vendored_frameworks = 'IJKMediaFramework.framework' 22 | # s.frameworks = "AudioToolbox", "AVFoundation", "CoreGraphics", "CoreMedia", "CoreVideo", "MobileCoreServices", "OpenGLES", "QuartzCore", "VideoToolbox", "Foundation", "UIKit", "MediaPlayer" 23 | # s.libraries = "bz2", "z", "stdc++" 24 | s.dependency 'FlutterIJK', '~> 0.2.3' 25 | 26 | # s.script_phase = {:name => 'extract framework', :script=> 'echo "Hello World"; pwd' ,:execution_position => :before_compile} 27 | 28 | end 29 | 30 | -------------------------------------------------------------------------------- /ios/switch_local.sh: -------------------------------------------------------------------------------- 1 | if [ "$1" == "dev" ]; then 2 | rm IJKMediaFramework.framework 3 | ln -s /Volumes/Samsung-T5/code/media_projects/ijkplayer/flutter_ijk/ios/output/IJKMediaFramework.framework IJKMediaFramework.framework 4 | rm flutter_ijkplayer.podspec 5 | ln flutter_ijkplayer.dev.podspec flutter_ijkplayer.podspec 6 | echo 'switch to local' 7 | elif [ "$1" == "prod" ]; then 8 | rm IJKMediaFramework.framework 9 | rm flutter_ijkplayer.podspec 10 | ln flutter_ijkplayer.prod.podspec flutter_ijkplayer.podspec 11 | echo 'switch to pod version' 12 | else 13 | echo "Switch dev or product" 14 | echo "Usage:" 15 | echo " $0 dev|prod" 16 | fi 17 | -------------------------------------------------------------------------------- /lib/flutter_ijkplayer.dart: -------------------------------------------------------------------------------- 1 | export 'src/error.dart'; 2 | export 'src/ijkplayer.dart'; 3 | export 'src/entity/video_info.dart'; 4 | export 'src/entity/options.dart'; 5 | export 'src/widget/controller_widget_builder.dart' 6 | show DefaultIJKControllerWidget,DefaultIJKControllerWidgetState, VolumeType, FullScreenType; 7 | export 'src/helper/config.dart'; 8 | export 'src/widget/ijk_status_widget.dart' 9 | show IjkStatusWidget, StatusWidgetBuilder; 10 | -------------------------------------------------------------------------------- /lib/src/controller/datasoure.dart: -------------------------------------------------------------------------------- 1 | part of '../ijkplayer.dart'; 2 | 3 | /// Entity classe for data sources. 4 | class DataSource { 5 | /// See [DataSourceType] 6 | DataSourceType _type; 7 | 8 | File _file; 9 | 10 | String _assetName; 11 | 12 | String _assetPackage; 13 | 14 | String _netWorkUrl; 15 | 16 | Map _headers; 17 | 18 | String _mediaUrl; 19 | 20 | DataSource._(); 21 | 22 | /// Create file data source 23 | factory DataSource.file(File file) { 24 | final ds = DataSource._(); 25 | ds._file = file; 26 | ds._type = DataSourceType.file; 27 | return ds; 28 | } 29 | 30 | /// Create network data source 31 | factory DataSource.network(String url, 32 | {Map headers = const {}}) { 33 | final ds = DataSource._(); 34 | ds._netWorkUrl = url; 35 | ds._headers = headers; 36 | ds._type = DataSourceType.network; 37 | return ds; 38 | } 39 | 40 | /// Create asset data source 41 | factory DataSource.asset(String assetName, {String package}) { 42 | final ds = DataSource._(); 43 | ds._assetName = assetName; 44 | ds._assetPackage = package; 45 | ds._type = DataSourceType.asset; 46 | return ds; 47 | } 48 | 49 | /// Create for [photo_manager](https://pub.dev/packages/photo_manager) library. [AssetEntity.mediaUrl] 50 | factory DataSource.photoManagerUrl(String mediaUrl) { 51 | final ds = DataSource._(); 52 | ds._mediaUrl = mediaUrl; 53 | ds._type = DataSourceType.photoManager; 54 | return ds; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/src/controller/enums.dart: -------------------------------------------------------------------------------- 1 | part of '../ijkplayer.dart'; 2 | 3 | enum DataSourceType { 4 | network, 5 | file, 6 | asset, 7 | photoManager, 8 | } 9 | 10 | /// Current IjkMedia status 11 | enum IjkStatus { 12 | noDatasource, 13 | preparing, 14 | setDatasourceFail, 15 | prepared, 16 | pause, 17 | error, 18 | playing, 19 | complete, 20 | disposed, 21 | } 22 | -------------------------------------------------------------------------------- /lib/src/controller/ijk_event_channel.dart: -------------------------------------------------------------------------------- 1 | part of '../ijkplayer.dart'; 2 | 3 | class _IJKEventChannel { 4 | int get textureId => controller?.textureId; 5 | 6 | IjkMediaController controller; 7 | 8 | _IJKEventChannel(this.controller); 9 | 10 | MethodChannel channel; 11 | 12 | String get channelName => "top.kikt/ijkplayer/event/$textureId"; 13 | 14 | Completer _prepareCompleter; 15 | 16 | bool _isDisposed = false; 17 | 18 | bool get isDisposed => _isDisposed; 19 | 20 | Future init() async { 21 | channel = MethodChannel(channelName); 22 | channel.setMethodCallHandler(handler); 23 | } 24 | 25 | void dispose() { 26 | _isDisposed = true; 27 | channel.setMethodCallHandler(null); 28 | controller = null; 29 | } 30 | 31 | Future handler(MethodCall call) async { 32 | switch (call.method) { 33 | case "finish": // 播放完毕 34 | // var index = call.arguments["type"]; 35 | // var type = FinishType.values[index]; 36 | _onPlayFinish(getInfo(call)); 37 | break; 38 | case "playStateChange": 39 | onPlayStateChange(getInfo(call)); 40 | break; 41 | case "prepare": 42 | onPrepare(getInfo(call)); 43 | break; 44 | case "rotateChanged": 45 | onRotateChanged(call); 46 | break; 47 | case "error": 48 | var info = await controller.getVideoInfo(); 49 | _onPlayFinish(info); 50 | int errorValue = call.arguments; 51 | _onPlayError(errorValue); 52 | break; 53 | default: 54 | return MissingPluginException( 55 | "$channelName ${call.method} not implement", 56 | ); 57 | } 58 | return true; 59 | } 60 | 61 | VideoInfo getInfo(MethodCall call) { 62 | var map = call.arguments.cast(); 63 | return VideoInfo.fromMap(map); 64 | } 65 | 66 | void _onPlayFinish(VideoInfo info) { 67 | controller?._onPlayFinish(); 68 | } 69 | 70 | void onPlayStateChange(VideoInfo info) { 71 | controller.isPlaying = info.isPlaying; 72 | } 73 | 74 | void onPrepare(VideoInfo info) { 75 | controller.isPlaying = info.isPlaying; 76 | _prepareCompleter?.complete(); 77 | _prepareCompleter = null; 78 | } 79 | 80 | Future waitPrepare() { 81 | _prepareCompleter = Completer(); 82 | return _prepareCompleter.future; 83 | } 84 | 85 | Future autoPlay(IjkMediaController ijkMediaController) async { 86 | try { 87 | await waitPrepare(); 88 | await ijkMediaController.play(); 89 | } catch (e) { 90 | LogUtils.info(e); 91 | } 92 | } 93 | 94 | Future disableAutoPlay(IjkMediaController ijkMediaController) async { 95 | try { 96 | await waitPrepare(); 97 | await ijkMediaController.pause(); 98 | } catch (e) { 99 | LogUtils.info(e); 100 | } 101 | } 102 | 103 | void onRotateChanged(MethodCall call) { 104 | var info = getInfo(call); 105 | LogUtils.debug("onRotateChanged , info = $info"); 106 | } 107 | 108 | void _onPlayError(int errorValue) { 109 | LogUtils.warning("play error , errorValue : $errorValue"); 110 | controller._onError(errorValue); 111 | } 112 | } 113 | 114 | // enum FinishType { 115 | // playEnd, 116 | // userExit, 117 | // error, 118 | // } 119 | -------------------------------------------------------------------------------- /lib/src/controller/plugin.dart: -------------------------------------------------------------------------------- 1 | part of '../ijkplayer.dart'; 2 | 3 | /// about channel 4 | MethodChannel _globalChannel = MethodChannel("top.kikt/ijkplayer"); 5 | 6 | Future _createIjk({ 7 | List options, 8 | }) async { 9 | List> _optionList = []; 10 | 11 | for (var option in options) { 12 | _optionList.add(option.toMap()); 13 | } 14 | 15 | int id = await _globalChannel.invokeMethod( 16 | "create", 17 | { 18 | "options": _optionList, 19 | }, 20 | ); 21 | return id; 22 | } 23 | 24 | class _IjkPlugin { 25 | MethodChannel get channel => MethodChannel("top.kikt/ijkplayer/$textureId"); 26 | 27 | /// texture id 28 | int textureId; 29 | 30 | bool _isDisposed = false; 31 | 32 | bool get isDisposed => _isDisposed; 33 | 34 | _IjkPlugin(this.textureId); 35 | 36 | Future dispose() async { 37 | if (isDisposed) { 38 | return; 39 | } 40 | _isDisposed = true; 41 | await _globalChannel.invokeMethod("dispose", {"id": textureId}); 42 | } 43 | 44 | Future play() async { 45 | if (isDisposed) { 46 | return; 47 | } 48 | await channel.invokeMethod("play"); 49 | } 50 | 51 | Future pause() async { 52 | if (isDisposed) { 53 | return; 54 | } 55 | await channel.invokeMethod("pause"); 56 | } 57 | 58 | Future stop() async { 59 | if (isDisposed) { 60 | return; 61 | } 62 | await channel.invokeMethod("stop"); 63 | } 64 | 65 | Future setNetworkDataSource( 66 | {String uri, Map headers = const {}}) async { 67 | if (isDisposed) { 68 | return; 69 | } 70 | LogUtils.debug("id = $textureId net uri = $uri ,headers = $headers"); 71 | await channel.invokeMethod("setNetworkDataSource", { 72 | "uri": uri, 73 | "headers": headers, 74 | }); 75 | } 76 | 77 | Future setAssetDataSource(String name, String package) async { 78 | if (isDisposed) { 79 | return; 80 | } 81 | LogUtils.debug("id = $textureId asset name = $name package = $package"); 82 | var params = { 83 | "name": name, 84 | }; 85 | if (package != null) { 86 | params["package"] = package; 87 | } 88 | await channel.invokeMethod("setAssetDataSource", params); 89 | } 90 | 91 | Future setFileDataSource(String path) async { 92 | if (isDisposed) { 93 | return; 94 | } 95 | if (!File(path).existsSync()) { 96 | return; 97 | } 98 | await channel.invokeMethod("setFileDataSource", { 99 | "path": path, 100 | }); 101 | LogUtils.debug("id = $textureId file path = $path"); 102 | } 103 | 104 | Future setPhotoManagerUrl(String mediaUrl) async { 105 | if (isDisposed) { 106 | return; 107 | } 108 | if (mediaUrl == null) { 109 | return; 110 | } 111 | await channel.invokeMethod("setPhotoManagerUrl", { 112 | "mediaUrl": mediaUrl, 113 | }); 114 | } 115 | 116 | Future> getInfo() async { 117 | if (isDisposed) { 118 | return null; 119 | } 120 | try { 121 | var map = await channel.invokeMethod("getInfo"); 122 | if (map == null) { 123 | return null; 124 | } else { 125 | return map.cast(); 126 | } 127 | } on Exception { 128 | return null; 129 | } 130 | } 131 | 132 | Future seekTo(double target) async { 133 | if (isDisposed) { 134 | return null; 135 | } 136 | await channel.invokeMethod("seekTo", { 137 | "target": target, 138 | }); 139 | } 140 | 141 | /// 142 | Future setVolume(int volume) async { 143 | if (isDisposed) { 144 | return null; 145 | } 146 | await channel.invokeMethod("setVolume", { 147 | "volume": volume, 148 | }); 149 | } 150 | 151 | Future screenShot() async { 152 | if (isDisposed) { 153 | return null; 154 | } 155 | var result = await channel.invokeMethod("screenShot"); 156 | if (result == null) { 157 | return null; 158 | } 159 | return result; 160 | } 161 | 162 | Future setSpeed(double speed) async { 163 | if (isDisposed) { 164 | return null; 165 | } 166 | await channel.invokeMethod("setSpeed", speed); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /lib/src/engine/ijk_controller_manager.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_ijkplayer/src/ijkplayer.dart'; 2 | import 'package:flutter_ijkplayer/src/helper/logutil.dart'; 3 | 4 | class IjkMediaPlayerManager { 5 | var _currentIndex = 1; 6 | final ijkPlayerList = []; 7 | final ijkPlayerMap = {}; 8 | 9 | static IjkMediaPlayerManager _instance; 10 | 11 | factory IjkMediaPlayerManager() { 12 | _instance ??= IjkMediaPlayerManager._(); 13 | return _instance; 14 | } 15 | 16 | IjkMediaPlayerManager._(); 17 | 18 | int add(IjkMediaController ijkMediaController) { 19 | ijkPlayerList.add(ijkMediaController); 20 | var result = _currentIndex; 21 | _currentIndex++; 22 | ijkPlayerMap[result] = ijkMediaController; 23 | return result; 24 | } 25 | 26 | void remove(IjkMediaController ijkMediaController) { 27 | ijkPlayerList.remove(ijkMediaController); 28 | ijkPlayerMap.remove(ijkMediaController.index); 29 | } 30 | 31 | IjkMediaController findControllerWithIndex(int ijkPlayerIndex) { 32 | return ijkPlayerMap[ijkPlayerIndex]; 33 | } 34 | 35 | Future pauseOther(IjkMediaController ijkMediaController) async { 36 | for (var ctl in this.ijkPlayerList) { 37 | if (ctl.index != ijkMediaController.index) { 38 | LogUtils.verbose("${ctl.textureId} controller will pause"); 39 | ctl.pause(); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/src/entity/options.dart: -------------------------------------------------------------------------------- 1 | /// see [bilibili/ijkplayer](https://github.com/bilibili/ijkplayer) 2 | enum IjkOptionCategory { 3 | format, 4 | codec, 5 | sws, 6 | player, 7 | } 8 | 9 | /// see [bilibili/ijkplayer](https://github.com/bilibili/ijkplayer) 10 | class IjkOption { 11 | /// see [bilibili/ijkplayer](https://github.com/bilibili/ijkplayer) 12 | final IjkOptionCategory category; 13 | 14 | /// see [bilibili/ijkplayer](https://github.com/bilibili/ijkplayer) 15 | final String key; 16 | 17 | /// see [bilibili/ijkplayer](https://github.com/bilibili/ijkplayer) 18 | final dynamic value; 19 | 20 | IjkOption(this.category, this.key, this.value); 21 | 22 | /// to map 23 | Map toMap() { 24 | return { 25 | "category": category.index, 26 | "key": key, 27 | "value": value, 28 | }; 29 | } 30 | 31 | @override 32 | int get hashCode => category.hashCode + key.hashCode; 33 | 34 | @override 35 | bool operator ==(other) { 36 | if (identical(other, this)) { 37 | return true; 38 | } 39 | if (other == null) { 40 | return false; 41 | } 42 | if (other is! IjkOption) { 43 | return false; 44 | } 45 | return this.category == other.category && this.key == other.key; 46 | } 47 | 48 | @override 49 | String toString() { 50 | return 'IjkOption{category: $category, key: $key, value: $value}'; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/src/entity/video_info.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | /// about video info 4 | class VideoInfo { 5 | /// Width of Video 6 | int width; 7 | 8 | /// Height of Video 9 | int height; 10 | 11 | /// Total length of video 12 | double duration; 13 | 14 | /// Current playback progress 15 | double currentPosition; 16 | 17 | /// In play 18 | bool isPlaying; 19 | 20 | /// Degree of Video 21 | int degree; 22 | 23 | /// The media tcp speed, unit is byte 24 | int tcpSpeed; 25 | 26 | Map _map; 27 | 28 | /// Percentage playback progress 29 | double get progress => (currentPosition ?? 0) / (duration ?? 1); 30 | 31 | ///Is there any information? 32 | bool get hasData => _map != null; 33 | 34 | /// Aspect ratio 35 | double get ratio { 36 | double r; 37 | if (width != null && height != null) { 38 | if (width == 0 || height == 0) { 39 | r = 1280 / 720; 40 | } else { 41 | r = width / height; 42 | } 43 | } else { 44 | r = 1280 / 720; 45 | } 46 | 47 | return r; 48 | } 49 | 50 | /// Constructing from the native method 51 | VideoInfo.fromMap(Map map) { 52 | if (map == null) { 53 | return; 54 | } 55 | this._map = map; 56 | this.width = map["width"]; 57 | this.height = map["height"]; 58 | this.duration = map["duration"]; 59 | this.currentPosition = map["currentPosition"]; 60 | this.isPlaying = map["isPlaying"]; 61 | this.degree = map["degree"]; 62 | this.tcpSpeed = map["tcpSpeed"]; 63 | } 64 | 65 | @override 66 | String toString() { 67 | if (_map == null) { 68 | return "null"; 69 | } 70 | return json.encode(_map); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/src/error.dart: -------------------------------------------------------------------------------- 1 | /// errors enum 2 | enum Error { 3 | /// file is not exists 4 | fileNotExists, 5 | } 6 | -------------------------------------------------------------------------------- /lib/src/helper/config.dart: -------------------------------------------------------------------------------- 1 | /// IJKPlayer Config 2 | class IjkConfig { 3 | /// when [isLog] is true, will print log in console 4 | static bool isLog = false; 5 | 6 | static LogLevel level = LogLevel.debug; 7 | 8 | static String logTag = "Ijk"; 9 | } 10 | 11 | enum LogLevel { 12 | verbose, 13 | debug, 14 | info, 15 | warning, 16 | error, 17 | } 18 | -------------------------------------------------------------------------------- /lib/src/helper/full_screen_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | 4 | class FullScreenHelper { 5 | static int getQuarterTurns(VideoInfo info, BuildContext context) { 6 | Axis axis; 7 | 8 | if (info.width == 0 || info.height == 0) { 9 | axis = Axis.horizontal; 10 | } else if (info.width > info.height) { 11 | if (info.degree == 90 || info.degree == 270) { 12 | axis = Axis.vertical; 13 | } else { 14 | axis = Axis.horizontal; 15 | } 16 | } else { 17 | if (info.degree == 90 || info.degree == 270) { 18 | axis = Axis.horizontal; 19 | } else { 20 | axis = Axis.vertical; 21 | } 22 | } 23 | 24 | var mediaQueryData = MediaQuery.of(context); 25 | 26 | int quarterTurns; 27 | 28 | if (axis == Axis.horizontal) { 29 | if (mediaQueryData.orientation == Orientation.landscape) { 30 | quarterTurns = 0; 31 | } else { 32 | quarterTurns = 1; 33 | } 34 | } else { 35 | quarterTurns = 0; 36 | } 37 | 38 | return quarterTurns; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/helper/logutil.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_ijkplayer/src/helper/config.dart'; 2 | 3 | /// IJKPlayer Log Util 4 | class LogUtils { 5 | LogUtils._(); 6 | 7 | static void verbose(Object msg) { 8 | log("${msg?.toString()}", LogLevel.verbose); 9 | } 10 | 11 | static void debug(Object msg) { 12 | log("${msg?.toString()}", LogLevel.debug); 13 | } 14 | 15 | static void info(Object msg) { 16 | log("${msg?.toString()}", LogLevel.info); 17 | } 18 | 19 | static void warning(Object msg) { 20 | log("${msg?.toString()}", LogLevel.warning); 21 | } 22 | 23 | static void error(Object msg) { 24 | log("${msg?.toString()}", LogLevel.error); 25 | } 26 | 27 | static void log(Object msg, LogLevel level) { 28 | if (level == null) { 29 | return; 30 | } 31 | if (!IjkConfig.isLog) { 32 | return; 33 | } 34 | 35 | if (level.index < IjkConfig.level.index) { 36 | return; 37 | } 38 | 39 | String levelString = level.toString().split(".")[1][0]; 40 | 41 | print("($levelString)${IjkConfig.logTag}:${msg.toString()}"); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/src/helper/time_helper.dart: -------------------------------------------------------------------------------- 1 | class TimeHelper { 2 | static String getTimeText(double seconds) { 3 | var duration = Duration(milliseconds: (seconds * 1000).toInt()); 4 | 5 | String twoDigits(int n) { 6 | if (n >= 10) return "$n"; 7 | return "0$n"; 8 | } 9 | 10 | String twoDigitMinutes = 11 | twoDigits(duration.inMinutes.remainder(Duration.minutesPerHour)); 12 | String twoDigitSeconds = 13 | twoDigits(duration.inSeconds.remainder(Duration.secondsPerMinute)); 14 | 15 | var str = "$twoDigitMinutes:$twoDigitSeconds"; 16 | 17 | if (duration.inHours == 0) { 18 | return str; 19 | } 20 | var hour = duration.inHours.toString().padLeft(2, "0"); 21 | return "$hour:$str"; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/src/helper/ui_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class UIHelper { 4 | static Rect findGlobalRect(GlobalKey key) { 5 | RenderBox renderObject = key.currentContext?.findRenderObject(); 6 | if (renderObject == null) { 7 | return null; 8 | } 9 | 10 | var globalOffset = renderObject?.localToGlobal(Offset.zero); 11 | 12 | if (globalOffset == null) { 13 | return null; 14 | } 15 | 16 | var bounds = renderObject.paintBounds; 17 | bounds = bounds.translate(globalOffset.dx, globalOffset.dy); 18 | return bounds; 19 | } 20 | 21 | static Offset globalOffsetToLocal(GlobalKey key, Offset offsetGlobal) { 22 | RenderBox renderObject = key.currentContext?.findRenderObject(); 23 | if (renderObject == null) { 24 | return null; 25 | } 26 | return renderObject.globalToLocal(offsetGlobal); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /lib/src/route/fullscreen_route.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | typedef Widget AnimationPageBuilder(BuildContext context, 4 | Animation animation, Animation secondaryAnimation); 5 | 6 | class DialogRoute extends PageRoute { 7 | final Color barrierColor; 8 | final String barrierLabel; 9 | final bool maintainState; 10 | final Duration transitionDuration; 11 | final AnimationPageBuilder builder; 12 | 13 | DialogRoute({ 14 | this.barrierColor = const Color(0x44FFFFFF), 15 | this.barrierLabel = "full", 16 | this.maintainState = true, 17 | this.transitionDuration = const Duration(milliseconds: 300), 18 | @required this.builder, 19 | }) : assert(barrierColor != Colors.transparent, 20 | "The barrierColor must not be transparent."); 21 | 22 | @override 23 | Widget buildPage(BuildContext context, Animation animation, 24 | Animation secondaryAnimation) { 25 | return builder(context, animation, secondaryAnimation); 26 | } 27 | } 28 | 29 | class FullScreenRoute extends DialogRoute { 30 | FullScreenRoute({WidgetBuilder builder}) 31 | : super(builder: (ctx, a, s) => fullScreenBuilder(ctx, builder, a, s)); 32 | 33 | static Widget fullScreenBuilder( 34 | BuildContext context, 35 | WidgetBuilder builder, 36 | Animation animation, 37 | Animation secondaryAnimation, 38 | ) { 39 | return AnimatedBuilder( 40 | animation: animation, 41 | builder: (BuildContext context, Widget child) { 42 | return Opacity( 43 | opacity: animation.value, 44 | child: builder(context), 45 | ); 46 | }, 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/src/widget/ijk_status_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 4 | 5 | /// Construct a Widget based on the current status. 6 | typedef Widget StatusWidgetBuilder( 7 | BuildContext context, 8 | IjkMediaController controller, 9 | IjkStatus status, 10 | ); 11 | 12 | /// Default IjkStatusWidget 13 | class IjkStatusWidget extends StatelessWidget { 14 | final IjkMediaController controller; 15 | final StatusWidgetBuilder statusWidgetBuilder; 16 | 17 | const IjkStatusWidget({ 18 | this.controller, 19 | this.statusWidgetBuilder = IjkStatusWidget.buildStatusWidget, 20 | }); 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | var statusBuilder = 25 | this.statusWidgetBuilder ?? IjkStatusWidget.buildStatusWidget; 26 | return StreamBuilder( 27 | initialData: controller.ijkStatus, 28 | stream: controller.ijkStatusStream, 29 | builder: (BuildContext context, snapshot) { 30 | return statusBuilder.call(context, controller, snapshot.data); 31 | }, 32 | ); 33 | } 34 | 35 | static Widget buildStatusWidget( 36 | BuildContext context, 37 | IjkMediaController controller, 38 | IjkStatus status, 39 | ) { 40 | if (status == IjkStatus.noDatasource) { 41 | return _buildNothing(context); 42 | } 43 | 44 | if (status == IjkStatus.preparing) { 45 | return _buildProgressWidget(context); 46 | } 47 | if (status == IjkStatus.prepared) { 48 | return _buildPreparedWidget(context, controller); 49 | } 50 | if (status == IjkStatus.error) { 51 | return _buildFailWidget(context); 52 | } 53 | if (status == IjkStatus.pause) { 54 | return _buildCenterIconButton(Icons.play_arrow, controller.play); 55 | } 56 | if (status == IjkStatus.complete) { 57 | return _buildCenterIconButton(Icons.replay, () async { 58 | await controller?.seekTo(0); 59 | await controller?.play(); 60 | }); 61 | } 62 | return Container(); 63 | } 64 | 65 | static Widget _buildPreparedWidget( 66 | BuildContext context, 67 | IjkMediaController controller, 68 | ) { 69 | return _buildCenterIconButton(Icons.play_arrow, controller.play); 70 | } 71 | } 72 | 73 | Widget _buildNothing(BuildContext context) { 74 | return Center( 75 | child: Text( 76 | "", 77 | style: TextStyle(color: Colors.white), 78 | ), 79 | ); 80 | } 81 | 82 | Widget _buildCenterIconButton(IconData iconData, Function onTap) { 83 | return Center( 84 | child: Container( 85 | width: 50, 86 | height: 50, 87 | decoration: BoxDecoration( 88 | color: Colors.white.withOpacity(0.75), 89 | borderRadius: BorderRadius.circular(30), 90 | ), 91 | child: IconButton( 92 | iconSize: 30, 93 | color: Colors.black, 94 | icon: Icon(iconData), 95 | onPressed: onTap, 96 | ), 97 | ), 98 | ); 99 | } 100 | 101 | Widget _buildProgressWidget(BuildContext context) { 102 | return Center( 103 | child: Container( 104 | width: 60, 105 | height: 60, 106 | child: RefreshProgressIndicator( 107 | backgroundColor: Colors.transparent, 108 | valueColor: AlwaysStoppedAnimation(Colors.white), 109 | ), 110 | ), 111 | ); 112 | } 113 | 114 | Widget _buildFailWidget(BuildContext context) { 115 | return Center( 116 | child: Icon( 117 | Icons.error, 118 | color: Colors.white, 119 | size: 44, 120 | ), 121 | ); 122 | } 123 | -------------------------------------------------------------------------------- /lib/src/widget/ijkplayer_builder.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ijkplayer/flutter_ijkplayer.dart'; 3 | 4 | /// Player builder, Inheritance of this class allows you to implement your own player 5 | typedef Widget IJKTextureBuilder( 6 | BuildContext context, 7 | IjkMediaController controller, 8 | VideoInfo info, 9 | ); 10 | 11 | /// default IJKPlayer method 12 | Widget buildDefaultIjkPlayer( 13 | BuildContext context, 14 | IjkMediaController controller, 15 | VideoInfo info, 16 | ) { 17 | return DefaultIJKPlayerWrapper( 18 | controller: controller, 19 | info: info, 20 | ); 21 | } 22 | 23 | /// Default IJKPlayer Wrapper 24 | /// 25 | /// This widget solves the aspect ratio problem in video direction. 26 | class DefaultIJKPlayerWrapper extends StatelessWidget { 27 | final IjkMediaController controller; 28 | final VideoInfo info; 29 | 30 | const DefaultIJKPlayerWrapper({ 31 | Key key, 32 | this.controller, 33 | this.info, 34 | }) : super(key: key); 35 | 36 | @override 37 | Widget build(BuildContext context) { 38 | double ratio = info?.ratio ?? 1280 / 720; 39 | 40 | var id = controller.textureId; 41 | 42 | if (id == null) { 43 | return AspectRatio( 44 | aspectRatio: ratio, 45 | child: Container( 46 | color: Colors.black, 47 | ), 48 | ); 49 | } 50 | 51 | Widget w = Container( 52 | color: Colors.black, 53 | child: Texture( 54 | textureId: id, 55 | ), 56 | ); 57 | 58 | if (!controller.autoRotate) { 59 | return w; 60 | } 61 | 62 | int degree = info?.degree ?? 0; 63 | 64 | if (ratio == 0) { 65 | ratio = 1280 / 720; 66 | } 67 | 68 | w = AspectRatio( 69 | aspectRatio: ratio, 70 | child: w, 71 | ); 72 | 73 | if (degree != 0) { 74 | w = RotatedBox( 75 | quarterTurns: degree ~/ 90, 76 | child: w, 77 | ); 78 | } 79 | 80 | return Container( 81 | child: w, 82 | alignment: Alignment.center, 83 | color: Colors.black, 84 | ); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "all-contributors-cli": "^6.11.0" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_ijkplayer 2 | description: Base by bilibili ijkplayer, it's video/audio player, support https、rtmp、m3u8 and more protocol. 3 | version: 0.3.6 4 | # author: caijinglong 5 | homepage: https://github.com/CaiJingLong/flutter_ijkplayer 6 | 7 | environment: 8 | sdk: ">=2.1.0 <3.0.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | 14 | dev_dependencies: 15 | flutter_test: 16 | sdk: flutter 17 | 18 | flutter: 19 | plugin: 20 | androidPackage: top.kikt.ijkplayer 21 | pluginClass: IjkplayerPlugin 22 | --------------------------------------------------------------------------------