Browse Source

support custom ijkplayer option

Caijinglong 6 years ago
parent
commit
91068768e5

+ 36 - 1
android/src/main/java/top/kikt/ijkplayer/Ijk.kt

@@ -8,13 +8,14 @@ import android.util.Base64
 import io.flutter.plugin.common.MethodCall
 import io.flutter.plugin.common.MethodChannel
 import io.flutter.plugin.common.PluginRegistry
+import top.kikt.ijkplayer.entity.IjkOption
 import top.kikt.ijkplayer.entity.Info
 import tv.danmaku.ijk.media.player.IjkMediaPlayer
 import tv.danmaku.ijk.media.player.TextureMediaPlayer
 import java.io.ByteArrayOutputStream
 import java.io.File
 
-class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.MethodCallHandler {
+class Ijk(private val registry: PluginRegistry.Registrar, val options: Map<String, Any>) : MethodChannel.MethodCallHandler {
 
     private val textureEntry = registry.textures().createSurfaceTexture()
     val id: Long
@@ -50,6 +51,40 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
 
         //        mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", maxCacheSize)
         //        mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", if (isBufferCache) 1 else 0)
+
+        fun setOptionToMediaPlayer(option: IjkOption) {
+            if (option.isInit.not()) {
+                return
+            }
+            val category = when (option.type) {
+                IjkOption.Type.Format -> IjkMediaPlayer.OPT_CATEGORY_FORMAT
+                IjkOption.Type.Player -> IjkMediaPlayer.OPT_CATEGORY_PLAYER
+                IjkOption.Type.Sws -> IjkMediaPlayer.OPT_CATEGORY_SWS
+                IjkOption.Type.Codec -> IjkMediaPlayer.OPT_CATEGORY_CODEC
+                else -> -1
+            }
+
+            if (category == -1) {
+                return
+            }
+
+            val value = option.value
+            when (value) {
+                is Int -> mediaPlayer.setOption(category, option.key, value.toLong())
+                is String -> mediaPlayer.setOption(category, option.key, value)
+                is Long -> mediaPlayer.setOption(category, option.key, value)
+            }
+        }
+
+        val options = options["options"]
+        if (options is List<*>) {
+            for (option in options) {
+                if (option is Map<*, *>) {
+                    val ijkOptions = IjkOption(option)
+                    setOptionToMediaPlayer(ijkOptions)
+                }
+            }
+        }
     }
 
     override fun onMethodCall(call: MethodCall?, result: MethodChannel.Result?) {

+ 2 - 2
android/src/main/java/top/kikt/ijkplayer/IjkManager.kt

@@ -9,8 +9,8 @@ import java.util.*
 class IjkManager(private val registrar: PluginRegistry.Registrar) {
     private val ijkList = ArrayList<Ijk>()
 
-    fun create(): Ijk {
-        val ijk = Ijk(registrar)
+    fun create(options: Map<String, Any>): Ijk {
+        val ijk = Ijk(registrar,options)
         ijkList.add(ijk)
         return ijk
     }

+ 2 - 1
android/src/main/java/top/kikt/ijkplayer/IjkplayerPlugin.kt

@@ -28,7 +28,8 @@ class IjkplayerPlugin(private val registrar: Registrar) : MethodCallHandler {
             }
             "create" -> {
                 try {
-                    val ijk = manager.create()
+                    val options: Map<String, Any> = call.arguments()
+                    val ijk = manager.create(options)
                     result.success(ijk.id)
                 } catch (e: Exception) {
                     e.printStackTrace()

+ 50 - 0
android/src/main/java/top/kikt/ijkplayer/entity/IjkOption.kt

@@ -0,0 +1,50 @@
+package top.kikt.ijkplayer.entity
+
+/// create 2019/4/12 by cai
+
+class IjkOption(option: Map<*, *>) {
+
+    lateinit var type: Type
+    lateinit var key: String
+    lateinit var value: Any
+
+    var isInit = true
+
+    init {
+        val type = option["category"]
+        if (type is Int) {
+            this.type = convertIntToType(type)
+        }
+
+        val key = option["key"]
+        if (key is String) {
+            this.key = key
+            isInit = isInit and true
+        }
+
+        option["value"]?.let {
+            this.value = it
+            isInit = isInit and true
+        }
+
+        isInit = (type is Int) and (key is String) and (option.containsKey("value"))
+    }
+
+    private fun convertIntToType(typeInt: Int): Type {
+        return when (typeInt) {
+            0 -> Type.Format
+            1 -> Type.Codec
+            2 -> Type.Sws
+            3 -> Type.Player
+            else -> Type.Other
+        }
+    }
+
+    enum class Type {
+        Format,
+        Codec,
+        Sws,
+        Player,
+        Other,
+    }
+}

+ 3 - 0
example/lib/i18n/cn.dart

@@ -65,4 +65,7 @@ class _I18nZh extends I18n {
 
   @override
   String get ijkStatusTitle => "IjkStatus的使用";
+
+  @override
+  String get customOption => "自定义Option的使用";
 }

+ 4 - 0
example/lib/i18n/en.dart

@@ -35,6 +35,7 @@ class _I18nEn extends I18n {
 
   @override
   String get autoFullScreenTitle => "Rotate device to see change";
+
   @override
   String get changeFullScreenWithButton => "Click button to show change";
 
@@ -64,4 +65,7 @@ class _I18nEn extends I18n {
 
   @override
   String get ijkStatusTitle => "Usage of IjkStatus";
+
+  @override
+  String get customOption => "Usage of custom IjkPlayer options";
 }

+ 2 - 0
example/lib/i18n/i18n.dart

@@ -46,6 +46,8 @@ abstract class I18n {
   String get overlayPageTitle;
 
   String get ijkStatusTitle;
+
+  String get customOption;
 }
 
 I18n get currentI18n => I18n(window.locale);

+ 63 - 0
example/lib/page/custom_ijk_opt_page.dart

@@ -0,0 +1,63 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_ijkplayer/flutter_ijkplayer.dart';
+import 'package:ijkplayer_example/i18n/i18n.dart';
+
+class CustomIjkOptionPage extends StatefulWidget {
+  @override
+  _CustomIjkOptionPageState createState() => _CustomIjkOptionPageState();
+}
+
+class _CustomIjkOptionPageState extends State<CustomIjkOptionPage> {
+  IjkMediaController controller = IjkMediaController();
+
+  @override
+  void initState() {
+    super.initState();
+    initIjkController();
+  }
+
+  @override
+  void dispose() {
+    controller?.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        title: Text(currentI18n.customOption),
+      ),
+      body: ListView(
+        children: <Widget>[
+          AspectRatio(
+            aspectRatio: 1280 / 720,
+            child: IjkPlayer(
+              mediaController: controller,
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+
+  void initIjkController() async {
+    var option1 = IjkOption(IjkOptionCategory.format, "fflags", "fastseek");
+
+    controller.setIjkPlayerOptions(
+      TargetPlatform.iOS,
+      [option1],
+    );
+
+    controller.setIjkPlayerOptions(
+      TargetPlatform.android,
+      [option1],
+    );
+
+    await controller.setDataSource(
+      DataSource.network(
+          "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4"),
+      autoPlay: true,
+    );
+  }
+}

+ 12 - 9
example/lib/page/index.dart

@@ -1,16 +1,18 @@
 import 'package:flutter/material.dart';
-import 'package:ijkplayer_example/i18n/i18n.dart';
-import 'package:ijkplayer_example/page/asset_page.dart';
-import 'package:ijkplayer_example/page/controller_stream_use.dart';
-import 'package:ijkplayer_example/page/dialog_video_page.dart';
-import 'package:ijkplayer_example/page/full_screen.dart';
-import 'package:ijkplayer_example/page/gallery_page.dart';
-import 'package:ijkplayer_example/page/ijk_status_page.dart';
-import 'package:ijkplayer_example/page/in_overlay_page.dart';
-import 'package:ijkplayer_example/page/network.dart';
 import 'package:ijkplayer_example/page/paging_page.dart';
 import 'package:ijkplayer_example/page/screen_shot_page.dart';
 import 'package:ijkplayer_example/page/video_list.dart';
+import '../i18n/i18n.dart';
+
+import 'asset_page.dart';
+import 'controller_stream_use.dart';
+import 'custom_ijk_opt_page.dart';
+import 'dialog_video_page.dart';
+import 'full_screen.dart';
+import 'gallery_page.dart';
+import 'ijk_status_page.dart';
+import 'in_overlay_page.dart';
+import 'network.dart';
 
 class IndexPage extends StatefulWidget {
   @override
@@ -38,6 +40,7 @@ class _IndexPageState extends State<IndexPage> {
           buildButton(currentI18n.screenshotTitle, ScreenShotPage()),
           buildButton(currentI18n.overlayPageTitle, InOverlayPage()),
           buildButton(currentI18n.ijkStatusTitle, IjkStatusPage()),
+          buildButton(currentI18n.customOption, CustomIjkOptionPage()),
         ],
       ),
     );

+ 4 - 1
ios/Classes/CoolFlutterIJK.h

@@ -5,11 +5,14 @@
 #import <Foundation/Foundation.h>
 #import <Flutter/Flutter.h>
 #import "CoolIjkNotifyChannel.h"
+#import "CoolIjkOption.h"
 
 @interface CoolFlutterIJK : NSObject
 
 @property(nonatomic, strong) NSObject <FlutterPluginRegistrar> *registrar;
 
+@property(nonatomic, strong) NSArray<CoolIjkOption*> *options;
+
 - (instancetype)initWithRegistrar:(NSObject <FlutterPluginRegistrar> *)registrar;
 
 + (instancetype)ijkWithRegistrar:(NSObject <FlutterPluginRegistrar> *)registrar;
@@ -20,4 +23,4 @@
 
 - (void)setDegree:(int)degree;
 
-@end
+@end

+ 45 - 0
ios/Classes/CoolFlutterIJK.m

@@ -173,6 +173,51 @@
 //    [options setPlayerOptionIntValue:0      forKey:@"video-max-frame-width-default"];
 //    [options setPlayerOptionIntValue:1      forKey:@"videotoolbox"];
 
+    for (CoolIjkOption *opt in self.options) {
+        if (opt) {
+            NSString* key = opt.key;
+            BOOL isString = [opt.value isKindOfClass:[NSString class]];
+            BOOL isInt;
+            if([opt.value isKindOfClass:[NSNumber class]]){
+                isInt = strcmp([opt.value objCType], @encode(int)) == 0;
+            }else{
+                isInt = NO;
+            }
+            switch (opt.type) {
+                case 0:
+                    if(isString){
+                        [options setFormatOptionValue:opt.value forKey:key];
+                    }else if(isInt){
+                        [options setFormatOptionIntValue:[opt.value intValue] forKey:key];
+                    }
+                    break;
+                case 1:
+                    if(isString){
+                        [options setCodecOptionValue:opt.value forKey:key];
+                    }else if(isInt){
+                        [options setCodecOptionIntValue:[opt.value intValue] forKey:key];
+                    }
+                    break;
+                case 2:
+                    if(isString){
+                        [options setSwsOptionValue:opt.value forKey:key];
+                    }else if(isInt){
+                        [options setSwsOptionIntValue:[opt.value intValue] forKey:key];
+                    }
+                    break;
+                case 3:
+                    if(isString){
+                        [options setPlayerOptionValue:opt.value forKey:key];
+                    }else if(isInt){
+                        [options setPlayerOptionIntValue:[opt.value intValue] forKey:key];
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+    
     return options;
 }
 

+ 1 - 1
ios/Classes/CoolFlutterIjkManager.h

@@ -15,7 +15,7 @@
 
 + (instancetype)managerWithRegistrar:(NSObject <FlutterPluginRegistrar> *)registrar;
 
-- (int64_t)create;
+- (int64_t)createWithCall:(FlutterMethodCall*) call;
 
 - (CoolFlutterIJK *)findIJKWithId:(int64_t)id1;
 

+ 25 - 1
ios/Classes/CoolFlutterIjkManager.m

@@ -5,6 +5,7 @@
 #import "CoolFlutterIjkManager.h"
 #import "CoolFlutterIJK.h"
 #import <IJKMediaFramework/IJKMediaFramework.h>
+#import "CoolIjkOption.h"
 
 @implementation CoolFlutterIjkManager {
     NSMutableDictionary<NSNumber *, CoolFlutterIJK *> *dict;
@@ -25,13 +26,36 @@
     return [[self alloc] initWithRegistrar:registrar];
 }
 
-- (int64_t)create {
+- (int64_t)createWithCall:(FlutterMethodCall*) call {
+    NSArray<CoolIjkOption*>* options = [self getOptionsFromCall:call];
     CoolFlutterIJK *ijk = [CoolFlutterIJK ijkWithRegistrar:self.registrar];
+    ijk.options = options;
     NSNumber *number = @([ijk id]);
     dict[number] = ijk;
     return [ijk id];
 }
 
+-(NSArray<CoolIjkOption*>*)getOptionsFromCall:(FlutterMethodCall *)call{
+    NSMutableArray<CoolIjkOption*> *array = [NSMutableArray new];
+    
+    NSDictionary *args = call.arguments;
+    NSArray *dartOptions = args[@"options"];
+    
+    for (NSDictionary *dict in dartOptions){
+        int type = [dict[@"category"] intValue];
+        NSString *key = dict[@"key"];
+        id value = dict[@"value"];
+        CoolIjkOption *option = [CoolIjkOption new];
+        option.key = key;
+        option.value = value;
+        option.type = type;
+        
+        [array addObject:option];
+    }
+    
+    return array;
+}
+
 - (CoolFlutterIJK *)findIJKWithId:(int64_t)id {
     return dict[@(id)];
 }

+ 20 - 0
ios/Classes/CoolIjkOption.h

@@ -0,0 +1,20 @@
+//
+//  CoolIjkOption.h
+//  flutter_ijkplayer
+//
+//  Created by Caijinglong on 2019/4/12.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CoolIjkOption : NSObject
+
+@property(nonatomic,assign) int type;
+@property(nonatomic,copy) NSString *key;
+@property(nonatomic,copy) id value;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 12 - 0
ios/Classes/CoolIjkOption.m

@@ -0,0 +1,12 @@
+//
+//  CoolIjkOption.m
+//  flutter_ijkplayer
+//
+//  Created by Caijinglong on 2019/4/12.
+//
+
+#import "CoolIjkOption.h"
+
+@implementation CoolIjkOption
+
+@end

+ 2 - 2
ios/Classes/CoolVideoInfo.h

@@ -18,7 +18,7 @@
 @property(nonatomic, assign) int degree;
 
 /**
- * Unit is KB.
+ * Unit is Byte.
  */
 @property(nonatomic, assign) int64_t tcpSpeed;
 
@@ -26,4 +26,4 @@
 
 - (NSDictionary *)toMap;
 
-@end
+@end

+ 1 - 1
ios/Classes/IjkplayerPlugin.m

@@ -57,7 +57,7 @@ static IjkplayerPlugin *__sharedInstance;
     dispatch_async(mainQueue, ^{
         if ([@"create" isEqualToString:call.method]) {
             @try {
-                int64_t id = [self->manager create];
+                int64_t id = [self->manager createWithCall:call];
                 result(@(id));
             }
             @catch (NSException *exception) {

+ 1 - 0
lib/flutter_ijkplayer.dart

@@ -1,6 +1,7 @@
 export 'src/error.dart';
 export 'src/ijkplayer.dart';
 export 'src/entity/video_info.dart';
+export 'src/entity/options.dart';
 export 'src/widget/controller_widget_builder.dart'
     show DefaultIJKControllerWidget, VolumeType;
 export 'src/helper/config.dart';

+ 16 - 1
lib/src/controller/controller.dart

@@ -10,6 +10,8 @@ class IjkMediaController
 
   String get debugLabel => index.toString();
 
+  Map<TargetPlatform, List<IjkOption>> _options = {};
+
   /// MediaController
   IjkMediaController({
     this.autoRotate = true,
@@ -20,7 +22,16 @@ class IjkMediaController
   /// create ijk texture id from native
   Future<void> _initIjk() async {
     try {
-      var id = await _createIjk();
+      List<IjkOption> options = [];
+      if (Platform.isAndroid) {
+        var opt = _options[TargetPlatform.android] ?? [];
+        options.addAll(opt);
+      } else {
+        var opt = _options[TargetPlatform.iOS] ?? [];
+        options.addAll(opt);
+      }
+
+      var id = await _createIjk(options: options);
       this.textureId = id;
       _plugin = _IjkPlugin(id);
       eventChannel = _IJKEventChannel(this);
@@ -267,4 +278,8 @@ class IjkMediaController
   Future<Uint8List> screenShot() {
     return _plugin.screenShot();
   }
+
+  void setIjkPlayerOptions(TargetPlatform platform, List<IjkOption> options) {
+    _options[platform] = options;
+  }
 }

+ 15 - 2
lib/src/controller/plugin.dart

@@ -3,8 +3,21 @@ part of '../ijkplayer.dart';
 /// about channel
 MethodChannel _globalChannel = MethodChannel("top.kikt/ijkplayer");
 
-Future<int> _createIjk() async {
-  int id = await _globalChannel.invokeMethod("create");
+Future<int> _createIjk({
+  List<IjkOption> options,
+}) async {
+  List<Map<String, dynamic>> _optionList = [];
+
+  for (var option in options) {
+    _optionList.add(option.toMap());
+  }
+
+  int id = await _globalChannel.invokeMethod(
+    "create",
+    <String, dynamic>{
+      "options": _optionList,
+    },
+  );
   return id;
 }
 

+ 22 - 0
lib/src/entity/options.dart

@@ -0,0 +1,22 @@
+enum IjkOptionCategory {
+  format,
+  codec,
+  sws,
+  player,
+}
+
+class IjkOption {
+  final IjkOptionCategory category;
+  final String key;
+  final dynamic value;
+
+  IjkOption(this.category, this.key, this.value);
+
+  Map<String, dynamic> toMap() {
+    return {
+      "category": category.index,
+      "key": key,
+      "value": value,
+    };
+  }
+}

+ 1 - 0
lib/src/ijkplayer.dart

@@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 
 import 'entity/video_info.dart';
+import 'entity/options.dart';
 import 'engine/ijk_controller_manager.dart';
 import 'error.dart';
 import 'helper/logutil.dart';