Browse Source

android部分提供了角度参数

iOS待修改
Caijinglong 6 years ago
parent
commit
4fb4607f77

+ 43 - 21
android/src/main/java/top/kikt/ijkplayer/Ijk.kt

@@ -18,19 +18,39 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
     val id: Long
         get() = textureEntry.id()
 
-    val ijkPlayer: IjkMediaPlayer = IjkMediaPlayer()
-    private val mediaPlayer: TextureMediaPlayer
+    val mediaPlayer: IjkMediaPlayer = IjkMediaPlayer()
+    private val textureMediaPlayer: TextureMediaPlayer
 
     private val methodChannel: MethodChannel = MethodChannel(registry.messenger(), "top.kikt/ijkplayer/$id")
 
     private val notifyChannel: NotifyChannel = NotifyChannel(registry, id, this)
 
+    var degree = 0
+
     init {
-        mediaPlayer = TextureMediaPlayer(ijkPlayer)
-        mediaPlayer.surfaceTexture = textureEntry.surfaceTexture()
+        textureMediaPlayer = TextureMediaPlayer(mediaPlayer)
+        configOptions()
+        textureMediaPlayer.surfaceTexture = textureEntry.surfaceTexture()
         methodChannel.setMethodCallHandler(this)
     }
 
+    private fun configOptions() {
+        // see https://www.jianshu.com/p/843c86a9e9ad
+        mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "fflags", "fastseek")
+        mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "analyzemaxduration", 100L)
+        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) // 开硬解
+    }
+
     override fun onMethodCall(call: MethodCall?, result: MethodChannel.Result?) {
         when (call?.method) {
             "setNetworkDataSource" -> {
@@ -97,16 +117,18 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
     }
 
     fun getInfo(): Info {
-        val duration = ijkPlayer.duration
-        val currentPosition = ijkPlayer.currentPosition
-        val width = ijkPlayer.videoWidth
-        val height = ijkPlayer.videoHeight
+        val duration = mediaPlayer.duration
+        val currentPosition = mediaPlayer.currentPosition
+        val width = mediaPlayer.videoWidth
+        val height = mediaPlayer.videoHeight
+//        ijkPlayer.mediaInfo.mMeta.mVideoStream.
         return Info(
                 duration = duration.toDouble() / 1000,
                 currentPosition = currentPosition.toDouble() / 1000,
                 width = width,
                 height = height,
-                isPlaying = mediaPlayer.isPlaying
+                isPlaying = textureMediaPlayer.isPlaying,
+                degree = degree
         )
     }
 
@@ -121,8 +143,8 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
 
     private fun setUri(uri: String, callback: (Throwable?) -> Unit) {
         try {
-            ijkPlayer.dataSource = uri
-            ijkPlayer.prepareAsync()
+            mediaPlayer.dataSource = uri
+            mediaPlayer.prepareAsync()
             callback(null)
         } catch (e: Exception) {
             e.printStackTrace()
@@ -132,7 +154,7 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
 
     private fun setAssetUri(name: String, `package`: String?, callback: (Throwable?) -> Unit) {
         try {
-            ijkPlayer.setOnPreparedListener {
+            mediaPlayer.setOnPreparedListener {
                 callback(null)
             }
             val asset =
@@ -148,9 +170,9 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
             val fileName = Base64.encodeToString(asset.toByteArray(), Base64.DEFAULT)
             val file = File(cacheDir, fileName)
             fd.createInputStream().copyTo(file.outputStream())
-            ijkPlayer.dataSource = file.path
+            mediaPlayer.dataSource = file.path
 //            ijkPlayer.setDataSource(fd.fileDescriptor) // can't use,
-            ijkPlayer.prepareAsync()
+            mediaPlayer.prepareAsync()
         } catch (e: Exception) {
             e.printStackTrace()
             callback(e)
@@ -160,29 +182,29 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
     fun dispose() {
         notifyChannel.dispose()
         methodChannel.setMethodCallHandler(null)
-        mediaPlayer.stop()
-        mediaPlayer.release()
+        textureMediaPlayer.stop()
+        textureMediaPlayer.release()
         textureEntry.release()
     }
 
     private fun play() {
         try {
-            ijkPlayer.start()
+            mediaPlayer.start()
         } catch (e: Exception) {
             e.printStackTrace()
         }
     }
 
     private fun pause() {
-        mediaPlayer.pause()
+        textureMediaPlayer.pause()
     }
 
     private fun stop() {
-        mediaPlayer.stop()
+        textureMediaPlayer.stop()
     }
 
     private fun seekTo(msec: Long) {
-        mediaPlayer.seekTo(msec)
+        textureMediaPlayer.seekTo(msec)
     }
 
     private fun setVolume(volume: Int?) {
@@ -190,7 +212,7 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
             return
         }
         val v = volume.toFloat() / 100
-        ijkPlayer.setVolume(v, v)
+        mediaPlayer.setVolume(v, v)
     }
 
 }

+ 21 - 0
android/src/main/java/top/kikt/ijkplayer/IjkplayerPlugin.kt

@@ -1,11 +1,14 @@
 package top.kikt.ijkplayer
 
+import android.content.Context
+import android.media.AudioManager
 import io.flutter.plugin.common.MethodCall
 import io.flutter.plugin.common.MethodChannel
 import io.flutter.plugin.common.MethodChannel.MethodCallHandler
 import io.flutter.plugin.common.MethodChannel.Result
 import io.flutter.plugin.common.PluginRegistry.Registrar
 
+
 /**
  * IjkplayerPlugin
  */
@@ -32,10 +35,28 @@ class IjkplayerPlugin(private val registrar: Registrar) : MethodCallHandler {
                 manager.dispose(id)
                 result.success(true)
             }
+            "setSystemVolume" -> {
+                val volume = call.argument<Int>("volume")
+                if (volume != null) {
+                    setVolume(volume)
+                }
+                result.success(true)
+            }
             else -> result.notImplemented()
         }
     }
 
+    private fun setVolume(volume: Int) {
+        val am = registrar.activity().getSystemService(Context.AUDIO_SERVICE) as AudioManager?
+        am?.apply {
+            val max = getStreamMaxVolume(AudioManager.STREAM_MUSIC)
+            val min = getStreamMinVolume(AudioManager.STREAM_MUSIC)
+            val diff: Float = (max - min).toFloat()
+            val target: Int = ((min + diff) * volume).toInt()
+            setStreamVolume(AudioManager.STREAM_MUSIC, target, 0)
+        }
+    }
+
     fun MethodCall.getLongArg(key: String): Long {
         return this.argument<Int>(key)!!.toLong()
     }

+ 5 - 1
android/src/main/java/top/kikt/ijkplayer/NotifyChannel.kt

@@ -7,7 +7,7 @@ import tv.danmaku.ijk.media.player.IMediaPlayer
 class NotifyChannel(val registry: PluginRegistry.Registrar, val textureId: Long, val ijk: Ijk) {
 
     private val player
-        get() = ijk.ijkPlayer
+        get() = ijk.mediaPlayer
 
     private val channel = MethodChannel(
             registry.messenger(),
@@ -44,6 +44,9 @@ class NotifyChannel(val registry: PluginRegistry.Registrar, val textureId: Long,
                 IMediaPlayer.MEDIA_INFO_AUDIO_DECODED_START, IMediaPlayer.MEDIA_INFO_VIDEO_DECODED_START -> {
                     channel.invokeMethod("playStateChange", info)
                 }
+                IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED -> {
+                    ijk.degree = extra
+                }
             }
             false
         }
@@ -55,6 +58,7 @@ class NotifyChannel(val registry: PluginRegistry.Registrar, val textureId: Long,
             logi("onController message $it, isPlaying = ${player.isPlaying}")
             ""
         }
+
     }
 
     fun dispose() {

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

@@ -6,7 +6,8 @@ data class Info(
         val currentPosition: Double,
         val width: Int,
         val height: Int,
-        val isPlaying: Boolean
+        val isPlaying: Boolean,
+        val degree: Int = 0
 ) {
 
     fun toMap(): Map<String, Any> {
@@ -16,6 +17,7 @@ data class Info(
         map["width"] = width
         map["height"] = height
         map["isPlaying"] = isPlaying
+        map["degree"] = degree
         return map
     }
 

+ 16 - 13
example/lib/main.dart

@@ -194,20 +194,23 @@ class HomePageState extends State<HomePage> {
     );
   }
 
-  int volume = 100;
-
   _buildVolumeBar() {
-    return Slider(
-      value: volume / 100,
-      label: (volume * 100).toInt().toString(),
-      onChanged: (double value) {
-        var targetVolume = (value * 100).toInt();
-        print("target volume = $targetVolume");
-        controller.setVolume(targetVolume);
-        setState(() {
-          this.volume = targetVolume;
+    return StreamBuilder<int>(
+        stream: controller?.volumeStream,
+        initialData: controller?.volume,
+        builder: (context, snapshot) {
+          if (!snapshot.hasData) {
+            return Container();
+          }
+          var volume = snapshot.data;
+          print("volume = $volume  ${volume / 100}");
+          return Slider(
+            value: volume / 100,
+            onChanged: (double value) {
+              var targetVolume = (value * 100).toInt();
+              controller.volume = targetVolume;
+            },
+          );
         });
-      },
-    );
   }
 }

+ 2 - 0
ios/Classes/CoolFlutterIJK.h

@@ -20,4 +20,6 @@
 
 - (void)setDataSourceWithUri:(NSString *)uri;
 
+- (void)setDegree:(int)degree;
+
 @end

+ 35 - 1
ios/Classes/CoolFlutterIJK.m

@@ -21,6 +21,7 @@
     CVPixelBufferRef latestPixelBuffer;
     FlutterMethodChannel *channel;
     CoolIjkNotifyChannel *notifyChannel;
+    int degree;
 }
 
 - (instancetype)initWithRegistrar:(NSObject <FlutterPluginRegistrar> *)registrar {
@@ -109,7 +110,7 @@
 }
 
 - (NSDictionary *)params:(FlutterMethodCall *)call {
-
+    return call.arguments;
 }
 
 + (instancetype)ijkWithRegistrar:(NSObject <FlutterPluginRegistrar> *)registrar {
@@ -150,6 +151,11 @@
     [self prepare];
 }
 
+- (void)setDegree:(int)d {
+    degree = d;
+}
+
+
 - (void)prepare {
     [controller prepareToPlay];
     if (displayLink) {
@@ -221,8 +227,36 @@
     info.duration = duration;
     info.currentPosition = currentPlaybackTime;
     info.isPlaying = [controller isPlaying];
+    info.degree = degree;
 
     return info;
 }
 
+- (NSUInteger)degreeFromVideoFileWithURL:(NSURL *)url {
+    NSUInteger mDegree = 0;
+
+    AVAsset *asset = [AVAsset assetWithURL:url];
+    NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
+    if ([tracks count] > 0) {
+        AVAssetTrack *videoTrack = tracks[0];
+        CGAffineTransform t = videoTrack.preferredTransform;
+
+        if (t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0) {
+            // Portrait
+            mDegree = 90;
+        } else if (t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0) {
+            // PortraitUpsideDown
+            mDegree = 270;
+        } else if (t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0) {
+            // LandscapeRight
+            mDegree = 0;
+        } else if (t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0) {
+            // LandscapeLeft
+            mDegree = 180;
+        }
+    }
+
+    return mDegree;
+}
+
 @end

+ 2 - 0
ios/Classes/CoolVideoInfo.h

@@ -15,6 +15,8 @@
 
 @property(nonatomic, assign) BOOL isPlaying;
 
+@property(nonatomic, assign) int degree;
+
 - (NSDictionary *)toMap;
 
 @end

+ 11 - 0
ios/Classes/CoolVideoInfo.m

@@ -9,6 +9,16 @@
 
 }
 
+- (instancetype)init {
+    self = [super init];
+    if (self) {
+        self.degree = 0;
+    }
+
+    return self;
+}
+
+
 - (NSDictionary *)toMap {
     NSMutableDictionary *dict = [NSMutableDictionary new];
     dict[@"width"] = @((int) self.size.width);
@@ -16,6 +26,7 @@
     dict[@"duration"] = @(self.duration);
     dict[@"currentPosition"] = @(self.currentPosition);
     dict[@"isPlaying"] = @(self.isPlaying);
+    dict[@"degree"] = @(self.degree);
     return dict;
 }
 

+ 12 - 1
ios/Classes/IjkplayerPlugin.m

@@ -62,12 +62,22 @@ static IjkplayerPlugin *__sharedInstance;
             int id = [params[@"id"] intValue];
             [self->manager disposeWithId:id];
             result(@(YES));
+        } else if ([@"setSystemVolume" isEqualToString:call.method]) {
+            NSDictionary *params = [call arguments];
+            int volume = [params[@"setSystemVolume"] intValue];
+            [self setVolume:volume];
+            result(@YES);
         } else {
             result(FlutterMethodNotImplemented);
         }
     });
 }
 
+- (void)setVolume:(int)volume {
+    MPMusicPlayerController *mpc = [MPMusicPlayerController applicationMusicPlayer];
+    mpc.volume = volume / 100;
+}
+
 @end
 
 @implementation FlutterMethodCall (Ijk)
@@ -83,5 +93,6 @@ static IjkplayerPlugin *__sharedInstance;
 - (NSString *)getStringParam:(NSString *)key {
     return [self arguments][key];
 }
-
 @end
+
+

+ 18 - 1
lib/src/controller.dart

@@ -39,6 +39,20 @@ class IjkMediaController {
 
   Stream<VideoInfo> get videoInfoStream => _videoInfoController.stream;
 
+  StreamController<int> _volumeController = StreamController.broadcast();
+
+  Stream<int> get volumeStream => _volumeController.stream;
+
+  int _volume = 100;
+
+  set volume(int value) {
+    this._volume = value;
+    _volumeController.add(volume);
+    _setVolume(value);
+  }
+
+  int get volume => _volume;
+
   Future<void> _initIjk() async {
     try {
       var id = await _createIjk();
@@ -46,6 +60,7 @@ class IjkMediaController {
       _plugin = _IjkPlugin(id);
       eventChannel = IJKEventChannel(this);
       await eventChannel.init();
+      volume = 100;
     } catch (e) {
       print(e);
       print("初始化失败");
@@ -57,9 +72,11 @@ class IjkMediaController {
     _playingController.close();
     _videoInfoController.close();
     _textureIdController.close();
+    _volumeController.close();
   }
 
   Future<void> reset() async {
+    volume = 100;
     this.textureId = null;
     _plugin?.dispose();
     _plugin = null;
@@ -153,7 +170,7 @@ class IjkMediaController {
     }
   }
 
-  Future<void> setVolume(int volume) async {
+  Future<void> _setVolume(int volume) async {
     await _plugin.setVolume(volume);
   }
 

+ 1 - 0
lib/src/ijkplayer.dart

@@ -10,6 +10,7 @@ import './error.dart';
 import './controller_builder.dart';
 
 part './controller.dart';
+part './manager.dart';
 
 typedef Widget ControllerWidgetBuilder(IjkMediaController controller);
 

+ 11 - 0
lib/src/manager.dart

@@ -0,0 +1,11 @@
+part of './ijkplayer.dart';
+
+/// create 2019/3/18 by cai
+
+class IjkManager {
+  static Future<void> setSystemVolume(int volume) async {
+    await _globalChannel.invokeMethod("setSystemVolume", {
+      "volume": volume,
+    });
+  }
+}

+ 5 - 0
lib/src/widget/progress_bar.dart

@@ -49,6 +49,11 @@ class ProgressBar extends StatelessWidget {
   }
 
   Widget buildColorWidget(Color color, double flex) {
+    if (flex == double.nan ||
+        flex == double.infinity ||
+        flex == double.negativeInfinity) {
+      flex = 0;
+    }
     return Expanded(
       flex: (flex * 1000).toInt(),
       child: Container(