Quellcode durchsuchen

Merge pull request #4 from CaiJingLong/dev

merge dev to master
Caijinglong vor 6 Jahren
Ursprung
Commit
f754ce51cd

+ 6 - 0
CHANGELOG.md

@@ -1,3 +1,9 @@
+## 0.1.5
+
+update iOS framework
+
+add some property
+
 ## 0.1.4
 
 Use [GSYVideoPlayer](https://github.com/CarGuo/GSYVideoPlayer) android ex so

+ 21 - 8
README.md

@@ -8,10 +8,11 @@ ijkplayer,通过纹理的方式接入 bilibili/ijkplayer
 
 有关 android 可能跑不起来的问题会详细解释
 
-模拟器用不了,所以调试请使用真机
+iOS模拟器不显示图像,所以调试请使用真机(iOS10 iOS 12.1.4亲测可用,其他版本有问题可反馈)
+android模拟器mac android sdk自带的emulator(API28 android9)可用,其他类型的没有亲测不保证
 
-- android: 我加入了 x86 的 so 库,但是我这里声音解码异常
-- iOS: 库中包含了真机和模拟器的库文件,但是有声音,无图像,疑似是因为 flutter native 端触发刷新纹理的方法没有回调的问题
+- android: 我这里 sdk 自带的模拟器可用(音视频均正常)
+- iOS: 库中包含了真机和模拟器的库文件,但是模拟器有声音,无图像
 
 在正式使用前,可以先 star 一下仓库, download 代码跑一下 example 尝试 (clone 也可以)
 
@@ -23,7 +24,7 @@ https://github.com/CaiJingLong/flutter_ijkplayer/blob/master/README-EN.md
 
 [![pub package](https://img.shields.io/pub/v/flutter_ijkplayer.svg)](https://pub.dartlang.org/packages/flutter_ijkplayer)
 
-最新版本查看 pub
+最新版本查看 pub
 
 pubspec.yaml
 
@@ -142,9 +143,9 @@ IjkMediaController controller = IjkMediaController();
 
 ### 关于销毁
 
-用户在确定不再使用 controller 时,需要自己调用 dispose 方法以释放资源,如果不调用,则会造成资源无法释放
+用户在确定不再使用 controller 时,必须自己调用 dispose 方法以释放资源,如果不调用,则会造成资源无法释放(后台有音乐等情况),一般情况下,在 ijkplayer 所属的页面销毁时同步销毁
 
-因为一个`controller`可能被多个`IjkPlayer`附着, 导致一个`controller`同时控制多个`IjkPlayer`,所以原则上不能与`IjkPlayer`的`dispose`达成一致,所以这里需要调用者自行 dispose
+因为一个`controller`可能被多个`IjkPlayer`附着, 导致一个`controller`同时控制多个`IjkPlayer`,所以原则上不能与`IjkPlayer`的`dispose`达成一致,所以这里需要调用者自行 dispose,
 
 ```dart
 controller.dispose();
@@ -180,7 +181,7 @@ await controller.setNetworkDataSource("https://www.sample-videos.com/video123/mp
 await controller.play();
 ```
 
-#### 播放的控制
+#### 播放的控制
 
 ```dart
 // 播放或暂停
@@ -197,7 +198,19 @@ await controller.pause();
 await controller.stop();
 
 // 进度跳转
-await controller.seekTo(0); //这里是一个double值, 单位是秒, 如1秒100毫秒=1.1s 1分钟=60.0
+await controller.seekTo(0.0); //这里是一个double值, 单位是秒, 如1秒100毫秒=1.1s 1分钟10秒=70.0
+
+// 进度跳转百分比
+await controller.seekToProgress(0.0); //0.0~1.0
+
+// 暂停其他所有的播放器(适用于ListView滚出屏幕或界面上有多个播放器的情况)
+await controller.pauseOtherController();
+
+// 设置媒体音量,这个可以用于做视频静音而不影响系统音量
+controller.volume = 100; //范围0~100
+
+// 设置系统音量
+await controller.setSystemVolume(100); // 范围0~100
 ```
 
 #### 获取播放信息

+ 10 - 7
TODOLIST.md

@@ -3,6 +3,7 @@
 - [x] 控制器逻辑
   - [x] 设置数据源
     - [x] 网络
+      - [x] 设置请求头
     - [x] 本地
     - [x] 资产
   - [x] 播放
@@ -11,20 +12,22 @@
   - [x] 释放资源
   - [x] 控制音量
   - [x] 控制系统音量
-    - [ ] 修复iOS系统音量与逻辑相反的问题
-    - [ ] 修复iOS系统音量出现系统弹窗的问题
-    - [ ] 修复iOS系统音量出现时明显卡顿的问题
+    - [x] 修复 iOS 系统音量与逻辑相反的问题
+    - [x] 修复 iOS 系统音量出现系统弹窗的问题
+    - [ ] 修复 iOS 系统音量出现时视频明显卡顿的问题
   - [x] 获取视频信息
     - [x] 宽高
     - [x] 当前播放进度
     - [x] 总时长
     - [x] 视频方向
-    - [ ] 视频播放速度
-      - [ ] tcp速度
-      - [ ] udp速度
-    - [ ] 当前视频编解码参数
+    - [x] 视频播放速度
+      - [x] tcp 速度
+    - [ ] 当前视频编解码器(作为未来备选方案,目前android端可获取,iOS端只有解码器id没有名字)
       - [ ] 视频
       - [ ] 音频
+    - [x] 帧数
+      - [x] android
+      - [ ] iOS (目前永远是0,获取的是GL_view的fps)
   - [ ] 控制亮度
 - [x] 默认控制器 UI
   - [x] 进度条

+ 18 - 11
android/src/main/java/top/kikt/ijkplayer/Ijk.kt

@@ -41,25 +41,25 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
         mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "analyzeduration", 1)
         mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "probesize", 1024 * 10)
         mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "flush_packets", 1L)
-//        mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", if (isBufferCache) 1 else 0)
         mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "reconnect", 5)
-//        mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", maxCacheSize)
         mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 5)
         mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", 1)
-        mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "fflags", "fastseek")
-
         mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1) // 开硬解
+
+        //        mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", maxCacheSize)
+        //        mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", if (isBufferCache) 1 else 0)
     }
 
     override fun onMethodCall(call: MethodCall?, result: MethodChannel.Result?) {
         when (call?.method) {
             "setNetworkDataSource" -> {
                 val uri = call.argument<String>("uri")
+                val params = call.argument<Map<String, String>>("headers")
                 if (uri == null) {
                     handleSetUriResult(Exception("uri是必传参数"), result)
                     return
                 }
-                setUri(uri) { throwable ->
+                setUri(uri, params) { throwable ->
                     handleSetUriResult(throwable, result)
                 }
             }
@@ -77,7 +77,7 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
             "setFileDataSource" -> {
                 val path = call.argument<String>("path")
                 if (path != null) {
-                    setUri("file://$path") { throwable ->
+                    setUri("file://$path", hashMapOf()) { throwable ->
                         handleSetUriResult(throwable, result)
                     }
                 }
@@ -110,8 +110,9 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
                 setVolume(volume)
                 result?.success(true)
             }
-            "getVolume"->{
+            "getVolume" -> {
 
+//                result?.success(this.mediaPlayer.setVolume())
             }
             else -> {
                 result?.notImplemented()
@@ -124,14 +125,19 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
         val currentPosition = mediaPlayer.currentPosition
         val width = mediaPlayer.videoWidth
         val height = mediaPlayer.videoHeight
-//        ijkPlayer.mediaInfo.mMeta.mVideoStream.
+        val outputFps = mediaPlayer.videoOutputFramesPerSecond
+//        mediaPlayer.mediaInfo.mAudioDecoder
+//        mediaPlayer.mediaInfo.mVideoDecoder
         return Info(
                 duration = duration.toDouble() / 1000,
                 currentPosition = currentPosition.toDouble() / 1000,
                 width = width,
                 height = height,
                 isPlaying = textureMediaPlayer.isPlaying,
-                degree = degree
+                degree = degree,
+                tcpSpeed = mediaPlayer.tcpSpeed,
+                outputFps = outputFps
+//                decodeFps = mediaPlayer.videoDecodeFramesPerSecond
         )
     }
 
@@ -144,9 +150,10 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
         }
     }
 
-    private fun setUri(uri: String, callback: (Throwable?) -> Unit) {
+    private fun setUri(uri: String, headers: Map<String, String>?, callback: (Throwable?) -> Unit) {
         try {
-            mediaPlayer.dataSource = uri
+//            mediaPlayer.dataSource = uri
+            mediaPlayer.setDataSource(uri, headers)
             mediaPlayer.prepareAsync()
             callback(null)
         } catch (e: Exception) {

+ 7 - 1
android/src/main/java/top/kikt/ijkplayer/entity/Info.kt

@@ -7,7 +7,10 @@ data class Info(
         val width: Int,
         val height: Int,
         val isPlaying: Boolean,
-        val degree: Int = 0
+        val degree: Int = 0,
+        val tcpSpeed: Long = 0,
+        val outputFps: Float = 0f
+//        val decodeFps: Float = 0f
 ) {
 
     fun toMap(): Map<String, Any> {
@@ -18,6 +21,9 @@ data class Info(
         map["height"] = height
         map["isPlaying"] = isPlaying
         map["degree"] = degree
+        map["tcpSpeed"] = tcpSpeed
+        map["outputFps"] = outputFps
+//        map["decodeFps"] = decodeFps
         return map
     }
 

+ 4 - 4
example/ios/Podfile.lock

@@ -2,8 +2,8 @@ PODS:
   - Flutter (1.0.0)
   - flutter_ijkplayer (0.0.1):
     - Flutter
-    - FlutterIJK (~> 0.0.7)
-  - FlutterIJK (0.0.7)
+    - FlutterIJK (~> 0.0.8)
+  - FlutterIJK (0.0.8)
   - photo_manager (0.0.1):
     - Flutter
 
@@ -26,8 +26,8 @@ EXTERNAL SOURCES:
 
 SPEC CHECKSUMS:
   Flutter: 58dd7d1b27887414a370fcccb9e645c08ffd7a6a
-  flutter_ijkplayer: 7973985ab7087e6716f1ac753387e9694bbb6609
-  FlutterIJK: 70be1c85cbf7eeefc849702ac2f794f4e631d526
+  flutter_ijkplayer: 319c057084d453fd81310129f75f5e6770c6d306
+  FlutterIJK: bdcc10a74e25fe5f82ec2331a20ac9cd8c0c7a4b
   photo_manager: d47ddf6cb25cbfa837dc334540eb9a99b208e191
 
 PODFILE CHECKSUM: a14c63eb48a9d676ed6d876506b3258fd9c85235

+ 1 - 0
example/lib/main.dart

@@ -4,6 +4,7 @@ import 'package:ijkplayer_example/page/index.dart';
 
 void main() {
   IjkConfig.isLog = true;
+  // IjkConfig.level = LogLevel.verbose;
   IjkManager.initIJKPlayer();
   runApp(MyApp());
 }

+ 11 - 2
example/lib/page/asset_page.dart

@@ -28,10 +28,19 @@ class _AssetPageState extends State<AssetPage> {
       floatingActionButton: FloatingActionButton(
         child: Icon(Icons.play_arrow),
         onPressed: () async {
-          await controller.setAssetDataSource("assets/sample1.mp4");
-          await controller.play();
+          await controller.setAssetDataSource(
+            "assets/sample1.mp4",
+            autoPlay: true,
+          );
+          await controller.pause();
         },
       ),
     );
   }
+
+  @override
+  void dispose() {
+    controller?.dispose();
+    super.dispose();
+  }
 }

+ 2 - 0
example/lib/page/network.dart

@@ -15,6 +15,8 @@ class _NetworkPageState extends State<NetworkPage> {
     super.initState();
     editingController.text =
         "https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_30mb.mp4";
+    editingController.text =
+        "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4";
   }
 
   @override

+ 4 - 0
example/lib/page/temp.dart

@@ -0,0 +1,4 @@
+import 'package:flutter/material.dart';
+
+void t(){
+}

+ 1 - 1
example/pubspec.lock

@@ -47,7 +47,7 @@ packages:
       path: ".."
       relative: true
     source: path
-    version: "0.1.4"
+    version: "0.1.5"
   flutter_test:
     dependency: "direct dev"
     description: flutter

+ 0 - 2
ios/Classes/CoolFlutterIJK.h

@@ -18,8 +18,6 @@
 
 - (void)dispose;
 
-- (void)setDataSourceWithUri:(NSString *)uri;
-
 - (void)setDegree:(int)degree;
 
 @end

+ 27 - 2
ios/Classes/CoolFlutterIJK.m

@@ -65,7 +65,8 @@
         @try {
             NSDictionary *params = call.arguments;
             NSString *uri = params[@"uri"];
-            [self setDataSourceWithUri:uri];
+            NSDictionary *headers = params[@"headers"];
+            [self setDataSourceWithUri:uri headers:headers];
             result(@(YES));
         }
         @catch (NSException *exception) {
@@ -151,12 +152,34 @@
 
 - (IJKFFOptions *)createOption {
     IJKFFOptions *options = [IJKFFOptions optionsByDefault];
+
+    // see https://www.jianshu.com/p/843c86a9e9ad
+//    [options setFormatOptionValue:@"fflags" forKey:@"fflags"];
+//    [options setFormatOptionIntValue:100 forKey:@"analyzemaxduration"];
+//    [options setFormatOptionIntValue:1 forKey:@"analyzeduration"];
+//    [options setFormatOptionIntValue:10240 forKey:@"probesize"];
+//    [options setFormatOptionIntValue:1 forKey:@"flush_packets"];
+//    [options setFormatOptionIntValue:5 forKey:@"reconnect"];
+//    [options setFormatOptionIntValue:5 forKey:@"framedrop"];
+//    [options setFormatOptionIntValue:1 forKey:@"enable-accurate-seek"];
+//    [options setFormatOptionIntValue:1 forKey:@"mediacodec"]; //硬解
+
     return options;
 }
 
-- (void)setDataSourceWithUri:(NSString *)uri {
+- (void)setDataSourceWithUri:(NSString *)uri headers:(NSDictionary *)headers {
     IJKFFOptions *options = [self createOption];
+    if (headers) {
+        NSMutableString *headerString = [NSMutableString new];
+        for (NSString *key in headers.allKeys) {
+            NSString *value = headers[key];
+            [headerString appendFormat:@"%@:%@", key, value];
+            [headerString appendString:@"\r\n"];
+        }
+        [options setFormatOptionValue:headerString forKey:@"headers"];
+    }
     controller = [[IJKFFMoviePlayerController alloc] initWithContentURLString:uri withOptions:options];
+
     [self prepare];
 }
 
@@ -237,6 +260,8 @@
     info.currentPosition = currentPlaybackTime;
     info.isPlaying = [controller isPlaying];
     info.degree = degree;
+    info.tcpSpeed = [controller tcpSpeed];
+    info.outputFps = [controller fpsAtOutput];
 
     return info;
 }

+ 7 - 0
ios/Classes/CoolVideoInfo.h

@@ -17,6 +17,13 @@
 
 @property(nonatomic, assign) int degree;
 
+/**
+ * Unit is KB.
+ */
+@property(nonatomic, assign) int64_t tcpSpeed;
+
+@property(nonatomic, assign) CGFloat outputFps;
+
 - (NSDictionary *)toMap;
 
 @end

+ 2 - 0
ios/Classes/CoolVideoInfo.m

@@ -27,6 +27,8 @@
     dict[@"currentPosition"] = @(self.currentPosition);
     dict[@"isPlaying"] = @(self.isPlaying);
     dict[@"degree"] = @(self.degree);
+    dict[@"tcpSpeed"] = @(self.tcpSpeed);
+    dict[@"outputFps"] = @(self.outputFps);
     return dict;
 }
 

+ 2 - 2
ios/Classes/IjkplayerPlugin.m

@@ -76,12 +76,12 @@ static IjkplayerPlugin *__sharedInstance;
             result(@(currentVol));
         } else if ([@"volumeUp" isEqualToString:call.method]) {
             int currentVol = [self getSystemVolume];
-            [self setSystemVolume: currentVol - 10];
+            [self setSystemVolume: currentVol + 10];
             currentVol = [self getSystemVolume];
             result(@(currentVol));
         } else if ([@"volumeDown" isEqualToString:call.method]) {
             int currentVol = [self getSystemVolume];
-            [self setSystemVolume: currentVol + 10];
+            [self setSystemVolume: currentVol - 10];
             currentVol = [self getSystemVolume];
             result(@(currentVol));
         } else {

+ 3 - 1
ios/flutter_ijkplayer.podspec

@@ -21,7 +21,9 @@ A new flutter plugin project.
   # s.ios.vendored_frameworks = 'IJKMediaFramework.framework'
   # s.frameworks  = "AudioToolbox", "AVFoundation", "CoreGraphics", "CoreMedia", "CoreVideo", "MobileCoreServices", "OpenGLES", "QuartzCore", "VideoToolbox", "Foundation", "UIKit", "MediaPlayer"
   # s.libraries   = "bz2", "z", "stdc++"
-  s.dependency 'FlutterIJK', '~> 0.0.7'
+  s.dependency 'FlutterIJK', '~> 0.0.8'
+
+  # s.script_phase = {:name => 'extract framework', :script=> 'echo "Hello World"; pwd' ,:execution_position => :before_compile}
 
 end
 

+ 59 - 29
lib/src/controller.dart

@@ -6,9 +6,13 @@ class IjkMediaController {
   IjkMediaController({
     this.autoRotate = true,
   }) {
-    IjkMediaPlayerManager().add(this);
+    index = IjkMediaPlayerManager().add(this);
   }
 
+  int index;
+
+  String get debugLabel => index.toString();
+
   /// texture id from native
   int _textureId;
 
@@ -98,8 +102,8 @@ class IjkMediaController {
       await eventChannel.init();
       volume = 100;
     } catch (e) {
-      LogUtils.verbose(e);
-      LogUtils.verbose("初始化失败");
+      LogUtils.warning(e);
+      LogUtils.warning("初始化失败");
     }
   }
 
@@ -132,10 +136,14 @@ class IjkMediaController {
   /// set net DataSource
   Future<void> setNetworkDataSource(
     String url, {
+    Map<String, String> headers = const {},
     bool autoPlay = false,
   }) async {
     await _initDataSource(() async {
-      await _plugin?.setNetworkDataSource(uri: url);
+      await _plugin?.setNetworkDataSource(
+        uri: url,
+        headers: headers,
+      );
     }, autoPlay);
   }
 
@@ -155,7 +163,7 @@ class IjkMediaController {
     DataSource source, {
     bool autoPlay = false,
   }) async {
-    switch (source.type) {
+    switch (source._type) {
       case DataSourceType.asset:
         await setAssetDataSource(
           source._assetName,
@@ -164,10 +172,17 @@ class IjkMediaController {
         );
         break;
       case DataSourceType.file:
-        await setFileDataSource(source._file, autoPlay: autoPlay);
+        await setFileDataSource(
+          source._file,
+          autoPlay: autoPlay,
+        );
         break;
       case DataSourceType.network:
-        await setNetworkDataSource(source._netWorkUrl, autoPlay: autoPlay);
+        await setNetworkDataSource(
+          source._netWorkUrl,
+          headers: source._headers,
+          autoPlay: autoPlay,
+        );
         break;
       default:
     }
@@ -194,8 +209,9 @@ class IjkMediaController {
       await _plugin?.dispose();
     }
     await _initIjk();
-    _autoPlay(autoPlay);
+    Future playFuture = _autoPlay(autoPlay);
     await setDataSource();
+    return playFuture;
   }
 
   /// Play or pause according to your current status
@@ -205,14 +221,10 @@ class IjkMediaController {
     var videoInfo = await getVideoInfo();
     var playing = videoInfo.isPlaying;
     if (playing) {
-      await _plugin?.pause();
+      await pause();
     } else {
-      if (pauseOther) {
-        await pauseOtherController();
-      }
-      await _plugin?.play();
+      await play(pauseOther: pauseOther);
     }
-    refreshVideoInfo();
   }
 
   /// play media
@@ -222,12 +234,14 @@ class IjkMediaController {
     if (pauseOther) {
       await pauseOtherController();
     }
+    LogUtils.info("$this play");
     await _plugin?.play();
     refreshVideoInfo();
   }
 
   /// pause media
   Future<void> pause() async {
+    LogUtils.info("$this pause");
     await _plugin?.pause();
     refreshVideoInfo();
   }
@@ -240,6 +254,7 @@ class IjkMediaController {
     refreshVideoInfo();
   }
 
+  /// seek to progress
   Future<void> seekToProgress(double progress) async {
     var videoInfo = await getVideoInfo();
     var target = videoInfo.duration * progress;
@@ -258,16 +273,18 @@ class IjkMediaController {
   Future<void> refreshVideoInfo() async {
     var info = await getVideoInfo();
     isPlaying = info.isPlaying;
-    if (info.hasData) _videoInfoController?.add(info);
-    LogUtils.verbose("info = $info");
+    if (info.hasData) {
+      _videoInfoController?.add(info);
+      LogUtils.verbose("onrefreshInfo = $info");
+    }
   }
 
   /// AutoPlay use
-  void _autoPlay(bool autoPlay) {
+  Future<void> _autoPlay(bool autoPlay) async {
     if (autoPlay) {
-      eventChannel?.autoPlay(this);
+      await eventChannel?.autoPlay(this);
     } else {
-      eventChannel?.disableAutoPlay(this);
+      await eventChannel?.disableAutoPlay(this);
     }
   }
 
@@ -298,6 +315,11 @@ class IjkMediaController {
   Future<void> pauseOtherController() async {
     await IjkMediaPlayerManager().pauseOther(this);
   }
+
+  @override
+  String toString() {
+    return "IJKController[$index]";
+  }
 }
 
 /// about channel
@@ -332,13 +354,17 @@ class _IjkPlugin {
     await channel.invokeMethod("stop");
   }
 
-  Future<void> setNetworkDataSource({String uri}) async {
-    LogUtils.verbose("id = $textureId net uri = $uri");
-    await channel.invokeMethod("setNetworkDataSource", {"uri": uri});
+  Future<void> setNetworkDataSource(
+      {String uri, Map<String, String> headers = const {}}) async {
+    LogUtils.debug("id = $textureId net uri = $uri ,headers = $headers");
+    await channel.invokeMethod("setNetworkDataSource", <String, dynamic>{
+      "uri": uri,
+      "headers": headers,
+    });
   }
 
   Future<void> setAssetDataSource(String name, String package) async {
-    LogUtils.verbose("id = $textureId asset name = $name package = $package");
+    LogUtils.debug("id = $textureId asset name = $name package = $package");
     var params = <String, dynamic>{
       "name": name,
     };
@@ -355,7 +381,7 @@ class _IjkPlugin {
     await channel.invokeMethod("setFileDataSource", <String, dynamic>{
       "path": path,
     });
-    LogUtils.verbose("id = $textureId file path = $path");
+    LogUtils.debug("id = $textureId file path = $path");
   }
 
   Future<Map<String, dynamic>> getInfo() async {
@@ -383,7 +409,7 @@ class _IjkPlugin {
 /// Entity classe for data sources.
 class DataSource {
   /// See [DataSourceType]
-  DataSourceType type;
+  DataSourceType _type;
 
   File _file;
 
@@ -393,21 +419,25 @@ class DataSource {
 
   String _netWorkUrl;
 
+  Map<String, String> _headers;
+
   DataSource._();
 
   /// Create file data source
   factory DataSource.file(File file) {
     var ds = DataSource._();
     ds._file = file;
-    ds.type = DataSourceType.file;
+    ds._type = DataSourceType.file;
     return ds;
   }
 
   /// Create network data source
-  factory DataSource.network(String url) {
+  factory DataSource.network(String url,
+      {Map<String, String> headers = const {}}) {
     var ds = DataSource._();
     ds._netWorkUrl = url;
-    ds.type = DataSourceType.network;
+    ds._headers = headers;
+    ds._type = DataSourceType.network;
     return ds;
   }
 
@@ -416,7 +446,7 @@ class DataSource {
     var ds = DataSource._();
     ds._assetName = assetName;
     ds._assetPackage = package;
-    ds.type = DataSourceType.asset;
+    ds._type = DataSourceType.asset;
     return ds;
   }
 }

+ 14 - 3
lib/src/engine/ijk_controller_manager.dart

@@ -2,7 +2,9 @@ import 'package:flutter_ijkplayer/src/ijkplayer.dart';
 import 'package:flutter_ijkplayer/src/helper/logutil.dart';
 
 class IjkMediaPlayerManager {
+  var _currentIndex = 1;
   final ijkPlayerList = <IjkMediaController>[];
+  final ijkPlayerMap = <int, IjkMediaController>{};
 
   static IjkMediaPlayerManager _instance;
 
@@ -13,18 +15,27 @@ class IjkMediaPlayerManager {
 
   IjkMediaPlayerManager._();
 
-  void add(IjkMediaController ijkMediaController) {
+  int add(IjkMediaController ijkMediaController) {
     ijkPlayerList.add(ijkMediaController);
+    var result = _currentIndex;
+    _currentIndex++;
+    ijkPlayerMap[result] = ijkMediaController;
+    return result;
   }
 
   void remove(IjkMediaController ijkMediaController) {
     ijkPlayerList.remove(ijkMediaController);
+    ijkPlayerMap.remove(ijkMediaController.index);
+  }
+
+  IjkMediaController findControllerWithIndex(int ijkPlayerIndex) {
+    return ijkPlayerMap[ijkPlayerIndex];
   }
 
   Future<void> pauseOther(IjkMediaController ijkMediaController) async {
     for (var ctl in this.ijkPlayerList) {
-      if (ctl != ijkMediaController) {
-        LogUtils.verbose("ctl ${ctl.textureId} will pause");
+      if (ctl.index != ijkMediaController.index) {
+        LogUtils.verbose("${ctl.textureId} controller will pause");
         ctl.pause();
       }
     }

+ 4 - 0
lib/src/entity/video_info.dart

@@ -20,6 +20,9 @@ class VideoInfo {
   /// Degree of Video
   int degree;
 
+  /// The media tcp speed, unit is byte
+  int tcpSpeed;
+
   Map<String, dynamic> _map;
 
   /// Percentage playback progress
@@ -56,6 +59,7 @@ class VideoInfo {
     this.currentPosition = map["currentPosition"];
     this.isPlaying = map["isPlaying"];
     this.degree = map["degree"];
+    this.tcpSpeed = map["tcpSpeed"];
   }
 
   @override

+ 1 - 1
lib/src/helper/config.dart

@@ -5,7 +5,7 @@ class IjkConfig {
 
   static LogLevel level = LogLevel.debug;
 
-  static String logTag = "IjkPlayer";
+  static String logTag = "Ijk";
 }
 
 enum LogLevel {

+ 1 - 1
lib/src/helper/logutil.dart

@@ -36,7 +36,7 @@ class LogUtils {
       return;
     }
 
-    String levelString = level.toString()[0];
+    String levelString = level.toString().split(".")[1][0];
 
     print("($levelString)${IjkConfig.logTag}:${msg.toString()}");
   }

+ 7 - 7
lib/src/ijk_event_channel.dart

@@ -72,27 +72,27 @@ class _IJKEventChannel {
     return _prepareCompleter.future;
   }
 
-  autoPlay(IjkMediaController ijkMediaController) async {
+  Future<void> autoPlay(IjkMediaController ijkMediaController) async {
     try {
       await waitPrepare();
-      ijkMediaController.play();
+      await ijkMediaController.play();
     } catch (e) {
-      LogUtils.verbose(e);
+      LogUtils.info(e);
     }
   }
 
-  disableAutoPlay(IjkMediaController ijkMediaController) async {
+  Future<void> disableAutoPlay(IjkMediaController ijkMediaController) async {
     try {
       await waitPrepare();
-      ijkMediaController.pause();
+      await ijkMediaController.pause();
     } catch (e) {
-      LogUtils.verbose(e);
+      LogUtils.info(e);
     }
   }
 
   void onRotateChanged(MethodCall call) {
     var info = getInfo(call);
-    LogUtils.verbose("onRotateChanged , info = $info");
+    LogUtils.debug("onRotateChanged , info = $info");
   }
 }
 

+ 17 - 9
lib/src/widget/controller_widget_builder.dart

@@ -1,4 +1,5 @@
 import 'dart:async';
+import 'dart:io';
 
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
@@ -78,12 +79,13 @@ class _DefaultControllerWidgetState extends State<DefaultControllerWidget>
   void initState() {
     super.initState();
     startTimer();
-    controllerSubscription = controller.textureIdStream.listen(_onTextIdChange);
+    controllerSubscription =
+        controller.textureIdStream.listen(_onTextureIdChange);
   }
 
-  void _onTextIdChange(int textId) {
-    LogUtils.verbose("onTextChange");
-    if (textId != null) {
+  void _onTextureIdChange(int textureId) {
+    LogUtils.debug("onTextureChange $textureId");
+    if (textureId != null) {
       startTimer();
     } else {
       stopTimer();
@@ -109,7 +111,7 @@ class _DefaultControllerWidgetState extends State<DefaultControllerWidget>
 
     progressTimer?.cancel();
     progressTimer = Timer.periodic(Duration(milliseconds: 400), (timer) {
-      LogUtils.verbose("will refresh info");
+      LogUtils.verbose("timer will call refresh info");
       controller.refreshVideoInfo();
     });
   }
@@ -210,7 +212,7 @@ class _DefaultControllerWidgetState extends State<DefaultControllerWidget>
   Function onDoubleTap() {
     return widget.doubleTapPlay
         ? () {
-            LogUtils.verbose("ondouble tap");
+            LogUtils.debug("ondouble tap");
             controller.playOrPause();
           }
         : null;
@@ -273,6 +275,10 @@ class _DefaultControllerWidgetState extends State<DefaultControllerWidget>
       volumeUp();
     }
 
+    if (widget.volumeType == VolumeType.system && !Platform.isAndroid) {
+      return;
+    }
+
     var currentVolume = await getVolume();
 
     var column = Column(
@@ -290,13 +296,15 @@ class _DefaultControllerWidgetState extends State<DefaultControllerWidget>
       ],
     );
 
-    if (widget.volumeType != VolumeType.system) {
-      showTooltip(createTooltipWidgetWrapper(column));
-    }
+    showTooltip(createTooltipWidgetWrapper(column));
   }
 
   void _onVerticalDragEnd(DragEndDetails details) {
     hideTooltip();
+
+    Future.delayed(Duration(seconds: 2), () {
+      hideTooltip();
+    });
   }
 
   Future<int> getVolume() async {

+ 1 - 1
pubspec.yaml

@@ -1,6 +1,6 @@
 name: flutter_ijkplayer
 description: Flutter version of bilibilibili ijkplayer, supports common playback protocols, easy to use.
-version: 0.1.4
+version: 0.1.5
 author: caijinglong<cjl_spy@163.com>
 homepage: https://github.com/CaiJingLong/flutter_ijkplayer