Sfoglia il codice sorgente

add all channel method result

cjl_macbook 6 anni fa
parent
commit
0796e7a275

+ 0 - 54
android/src/main/java/top/kikt/ijkplayer/AssetDataSource.kt

@@ -1,54 +0,0 @@
-package top.kikt.ijkplayer
-
-import android.content.res.AssetFileDescriptor
-import tv.danmaku.ijk.media.player.misc.IMediaDataSource
-import java.io.IOException
-import java.io.InputStream
-
-
-/// create 2019/3/15 by cai
-///
-/// copy from https://github.com/jadennn/flutter_ijk/blob/2cab57aca9548fde2274ff0651caae6ba36b210b/android/src/main/java/com/jaden/flutterijk/RawDataSourceProvider.java
-class AssetDataSource(private val mDescriptor: AssetFileDescriptor) : IMediaDataSource {
-    private var mMediaBytes: ByteArray? = null
-
-    override fun readAt(position: Long, buffer: ByteArray, offset: Int, size: Int): Int {
-        if (position + 1 >= mMediaBytes!!.size) {
-            return -1
-        }
-        var length: Int
-        if (position + size < mMediaBytes!!.size) {
-            length = size
-        } else {
-            length = (mMediaBytes!!.size - position).toInt()
-            if (length > buffer.size)
-                length = buffer.size
-            length--
-        }
-        // 把文件内容copy到buffer中;
-        System.arraycopy(mMediaBytes!!, position.toInt(), buffer, offset, length)
-        return length
-    }
-
-    @Throws(IOException::class)
-    override fun getSize(): Long {
-        val length = mDescriptor.length
-        if (mMediaBytes == null) {
-            val inputStream = mDescriptor.createInputStream()
-            mMediaBytes = readBytes(inputStream)
-        }
-        return length
-    }
-
-    @Throws(IOException::class)
-    override fun close() {
-        mDescriptor.close()
-        mMediaBytes = null
-    }
-
-    //读取文件内容
-    @Throws(IOException::class)
-    private fun readBytes(inputStream: InputStream): ByteArray {
-        return inputStream.readBytes()
-    }
-}

+ 6 - 5
android/src/main/java/top/kikt/ijkplayer/Ijk.kt

@@ -64,13 +64,15 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
             }
             "play" -> {
                 play()
-                result?.success(1)
+                result?.success(true)
             }
             "pause" -> {
                 pause()
+                result?.success(true)
             }
             "stop" -> {
                 stop()
+                result?.success(true)
             }
             "getInfo" -> {
                 val info = getInfo()
@@ -81,6 +83,7 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
                 if (target != null) {
                     seekTo((target * 1000).toLong())
                 }
+                result?.success(true)
             }
             else -> {
                 result?.notImplemented()
@@ -104,7 +107,7 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
 
     private fun handleSetUriResult(throwable: Throwable?, result: MethodChannel.Result?) {
         if (throwable == null) {
-            result?.success(null)
+            result?.success(true)
         } else {
             throwable.printStackTrace()
             result?.error("1", "设置资源失败", throwable)
@@ -113,11 +116,9 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
 
     private fun setUri(uri: String, callback: (Throwable?) -> Unit) {
         try {
-            ijkPlayer.setOnPreparedListener {
-                callback(null)
-            }
             ijkPlayer.dataSource = uri
             ijkPlayer.prepareAsync()
+            callback(null)
         } catch (e: Exception) {
             e.printStackTrace()
             callback(e)

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

@@ -30,6 +30,7 @@ class IjkplayerPlugin(private val registrar: Registrar) : MethodCallHandler {
             "dispose" -> {
                 val id = call.argument<Int>("id")!!.toLong()
                 manager.dispose(id)
+                result.success(true)
             }
             else -> result.notImplemented()
         }

+ 11 - 0
android/src/main/java/top/kikt/ijkplayer/NotifyChannel.kt

@@ -23,14 +23,17 @@ class NotifyChannel(val registry: PluginRegistry.Registrar, val textureId: Long,
         }
         player.setOnCompletionListener {
             logi("completion $info")
+            channel.invokeMethod("completion", info)
         }
         player.setOnBufferingUpdateListener { mp, percent ->
+            /// 在线视频缓冲
             logi("completion buffer update $info $percent")
         }
         player.setOnSeekCompleteListener {
             logi("onSeekCompletion $info")
         }
         player.setOnErrorListener { mp, what, extra ->
+            channel.invokeMethod("error", what)
             logi("onError $what")
             false
         }
@@ -38,6 +41,14 @@ class NotifyChannel(val registry: PluginRegistry.Registrar, val textureId: Long,
             logi("onInfoListener $what")
             false
         }
+        player.setOnNativeInvokeListener { what, args ->
+            logi("onNativeInvoke $what")
+            false
+        }
+        player.setOnControlMessageListener {
+            logi("onController message $it")
+            ""
+        }
     }
 
     fun dispose() {

+ 2 - 2
example/ios/Podfile.lock

@@ -10,7 +10,7 @@ PODS:
 DEPENDENCIES:
   - Flutter (from `.symlinks/flutter/ios`)
   - flutter_ijkplayer (from `/Users/caijinglong/Documents/GitHub/flutter_ijkplayer/ios/flutter_ijkplayer.podspec`)
-  - photo_manager (from `/Users/caijinglong/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-0.3.2/ios/photo_manager.podspec`)
+  - photo_manager (from `/Users/caijinglong/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-0.3.3/ios/photo_manager.podspec`)
 
 SPEC REPOS:
   https://github.com/cocoapods/specs.git:
@@ -22,7 +22,7 @@ EXTERNAL SOURCES:
   flutter_ijkplayer:
     :path: "/Users/caijinglong/Documents/GitHub/flutter_ijkplayer/ios/flutter_ijkplayer.podspec"
   photo_manager:
-    :path: "/Users/caijinglong/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-0.3.2/ios/photo_manager.podspec"
+    :path: "/Users/caijinglong/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-0.3.3/ios/photo_manager.podspec"
 
 SPEC CHECKSUMS:
   Flutter: 58dd7d1b27887414a370fcccb9e645c08ffd7a6a

+ 48 - 15
example/lib/main.dart

@@ -1,4 +1,5 @@
 import 'dart:async';
+import 'dart:io';
 
 import 'package:flutter/material.dart';
 import 'package:flutter_ijkplayer/flutter_ijkplayer.dart';
@@ -64,6 +65,7 @@ class HomePageState extends State<HomePage> {
               ),
             ),
             _buildPlayAssetButton(),
+            _buildControllerButtons(),
           ],
         ),
       ),
@@ -71,15 +73,15 @@ class HomePageState extends State<HomePage> {
         child: Icon(Icons.play_arrow),
         onPressed: () async {
           await controller.setNetworkDataSource(
-            // 'https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4',
-            // 'rtmp://172.16.100.245/live1',
-            // 'https://www.sample-videos.com/video123/flv/720/big_buck_bunny_720p_10mb.flv',
-            "https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4",
-            // 'http://184.72.239.149/vod/smil:BigBuckBunny.smil/playlist.m3u8',
-            // "file:///sdcard/Download/Sample1.mp4",
-          );
+              // 'https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4',
+              // 'rtmp://172.16.100.245/live1',
+              // 'https://www.sample-videos.com/video123/flv/720/big_buck_bunny_720p_10mb.flv',
+              "https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4",
+              // 'http://184.72.239.149/vod/smil:BigBuckBunny.smil/playlist.m3u8',
+              // "file:///sdcard/Download/Sample1.mp4",
+              autoPlay: true);
           print("set data source success");
-          controller.play();
+          // controller.playOrPause();
         },
       ),
     );
@@ -128,23 +130,27 @@ class HomePageState extends State<HomePage> {
 
     if (imgList != null && imgList.isNotEmpty) {
       var asset = imgList[0];
-      var fileUri = (await asset.file).uri;
-      playUri(fileUri.toString());
+      var file = (await asset.file).absolute;
+      playFile(file);
     }
   }
 
+  void playFile(File file) async {
+    await controller.setFileDataSource(file, autoPlay: true);
+  }
+
   void playUri(String uri) async {
-    await controller.setNetworkDataSource(uri);
-    print("set data source success");
-    controller.play();
+    await controller.setNetworkDataSource(uri, autoPlay: true);
   }
 
   _buildPlayAssetButton() {
     return FlatButton(
       child: Text("play sample asset"),
       onPressed: () async {
-        await controller.setAssetDataSource("assets/sample1.mp4");
-        controller.play();
+        await controller.setAssetDataSource(
+          "assets/sample1.mp4",
+          autoPlay: true,
+        );
 
         Timer.periodic(Duration(seconds: 2), (timer) async {
           var info = await controller.getVideoInfo();
@@ -160,4 +166,31 @@ class HomePageState extends State<HomePage> {
       },
     );
   }
+
+  _buildControllerButtons() {
+    return Row(
+      children: <Widget>[
+        FlatButton(
+          child: Text("播放"),
+          onPressed: () async {
+            var info = await controller?.getVideoInfo();
+            print(info);
+            await controller?.play();
+            info = await controller?.getVideoInfo();
+            print(info);
+          },
+        ),
+        FlatButton(
+          child: Text("暂停"),
+          onPressed: () async {
+            var info = await controller?.getVideoInfo();
+            print(info);
+            await controller?.pause();
+            info = await controller?.getVideoInfo();
+            print(info);
+          },
+        ),
+      ],
+    );
+  }
 }

+ 2 - 2
example/pubspec.lock

@@ -87,14 +87,14 @@ packages:
       name: photo
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "0.3.2"
+    version: "0.3.3"
   photo_manager:
     dependency: transitive
     description:
       name: photo_manager
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "0.3.2"
+    version: "0.3.3"
   quiver:
     dependency: transitive
     description:

+ 1 - 1
example/pubspec.yaml

@@ -12,7 +12,7 @@ dependencies:
   # The following adds the Cupertino Icons font to your application.
   # Use with the CupertinoIcons class for iOS style icons.
   cupertino_icons: ^0.1.2
-  photo: ^0.3.2
+  photo: ^0.3.3
 
 dev_dependencies:
   flutter_test:

+ 8 - 2
ios/Classes/FlutterIJK.m

@@ -53,16 +53,19 @@
 - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
     if ([@"play" isEqualToString:call.method]) {
         [self play];
+        result(@(YES));
     } else if ([@"pause" isEqualToString:call.method]) {
         [self pause];
+        result(@(YES));
     } else if ([@"stop" isEqualToString:call.method]) {
         [self stop];
+        result(@(YES));
     } else if ([@"setNetworkDataSource" isEqualToString:call.method]) {
         @try {
             NSDictionary *params = call.arguments;
             NSString *uri = params[@"uri"];
             [self setDataSourceWithUri:uri];
-            result(nil);
+            result(@(YES));
         }
         @catch (NSException *exception) {
             NSLog(@"Exception occurred: %@, %@", exception, [exception userInfo]);
@@ -75,7 +78,7 @@
             NSString *pkg = params[@"package"];
             IJKFFMoviePlayerController *playerController = [self createControllerWithAssetName:name pkg:pkg];
             [self setDataSourceWithController:playerController];
-            result(nil);
+            result(@(YES));
         }
         @catch (NSException *exception) {
             NSLog(@"Exception occurred: %@, %@", exception, [exception userInfo]);
@@ -85,10 +88,13 @@
         NSDictionary *params = call.arguments;
         NSString *path = params[@"path"];
         IJKFFMoviePlayerController *playerController = [self createControllerWithPath:path];
+        [self setDataSourceWithController:playerController];
+        result(@(YES));
     } else if ([@"seekTo" isEqualToString:call.method]) {
         NSDictionary *params = call.arguments;
         double target = [params[@"target"] doubleValue];
         [self seekTo:target];
+        result(@(YES));
     } else if ([@"getInfo" isEqualToString:call.method]) {
         KKVideoInfo *info = [self getInfo];
         result([info toMap]);

+ 1 - 0
ios/Classes/IjkplayerPlugin.m

@@ -61,6 +61,7 @@ static IjkplayerPlugin *__sharedInstance;
             NSDictionary *params = [call arguments];
             int id = [params[@"id"] intValue];
             [self->manager disposeWithId:id];
+            result(@(YES));
         } else {
             result(FlutterMethodNotImplemented);
         }

+ 16 - 15
ios/Classes/KKIjkNotifyChannel.m

@@ -90,21 +90,22 @@
 }
 
 - (void)moviePlayBackFinish:(NSNotification *)notification {
-    int reason = [[[notification userInfo] valueForKey:IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
-    int type = 2;
-    switch (reason) {
-        case IJKMPMovieFinishReasonPlaybackEnded:
-            type = 0;
-            break;
-        case IJKMPMovieFinishReasonUserExited:
-            type = 1;
-            break;
-        case IJKMPMovieFinishReasonPlaybackError:
-            break;
-        default:
-            break;
-    }
-    [channel invokeMethod:@"finish" arguments:@{@"type": @(type)}];
+//    int reason = [[[notification userInfo] valueForKey:IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
+//    int type = 2;
+//    switch (reason) {
+//        case IJKMPMovieFinishReasonPlaybackEnded:
+//            type = 0;
+//            break;
+//        case IJKMPMovieFinishReasonUserExited:
+//            type = 1;
+//            break;
+//        case IJKMPMovieFinishReasonPlaybackError:
+//            break;
+//        default:
+//            break;
+//    }
+//    [channel invokeMethod:@"finish" arguments:@{@"type": @(type)}];
+    [channel invokeMethod:@"finish" arguments:[self getInfo]];
 }
 
 - (void)loadStateDidChange:(NSNotification *)notification {

+ 62 - 13
lib/src/controller.dart

@@ -15,7 +15,7 @@ class IjkMediaController extends ChangeNotifier {
 
   Future<void> _initIjk() async {
     try {
-      var id = await createIjk();
+      var id = await _createIjk();
       this.textureId = id;
       _plugin = _IjkPlugin(id);
       eventChannel = IJKEventChannel(this);
@@ -36,21 +36,55 @@ class IjkMediaController extends ChangeNotifier {
     super.dispose();
   }
 
-  Future<void> setNetworkDataSource(String url) async {
+  Future<void> setNetworkDataSource(
+    String url, {
+    bool autoPlay = false,
+  }) async {
+    await _initDataSource(() async {
+      await _plugin?.setNetworkDataSource(uri: url);
+    }, autoPlay);
+  }
+
+  Future<void> setAssetDataSource(
+    String name, {
+    String package,
+    bool autoPlay = false,
+  }) async {
+    await _initDataSource(() async {
+      await _plugin?.setAssetDataSource(name, package);
+    }, autoPlay);
+  }
+
+  Future<void> setFileDataSource(
+    File file, {
+    bool autoPlay = false,
+  }) async {
+    await _initDataSource(() async {
+      await _plugin?.setFileDataSource(file.absolute.path);
+    }, autoPlay);
+  }
+
+  Future<void> _initDataSource(
+    Future setDataSource(),
+    bool autoPlay,
+  ) async {
+    autoPlay ??= false;
+
     if (this.textureId != null) {
       await _plugin?.dispose();
     }
     await _initIjk();
-    await _plugin?.setNetworkDataSource(uri: url);
+    _autoPlay(autoPlay);
+    await setDataSource();
     this.notifyListeners();
   }
 
-  Future<void> setAssetDataSource(String name, {String package}) async {
-    if (this.textureId != null) {
-      await _plugin?.dispose();
+  Future<void> playOrPause() async {
+    if (isPlaying == true) {
+      await _plugin?.play();
+    } else {
+      await _plugin?.pause();
     }
-    await _initIjk();
-    await _plugin?.setAssetDataSource(name, package);
     this.notifyListeners();
   }
 
@@ -59,19 +93,34 @@ class IjkMediaController extends ChangeNotifier {
     this.notifyListeners();
   }
 
+  Future<void> pause() async {
+    await _plugin?.pause();
+    this.notifyListeners();
+  }
+
   Future<void> seekTo(double target) async {
     await _plugin?.seekTo(target);
   }
 
   Future<VideoInfo> getVideoInfo() async {
     Map<String, dynamic> result = await _plugin?.getInfo();
-    return VideoInfo.fromMap(result);
+    var info = VideoInfo.fromMap(result);
+    isPlaying = info.isPlaying;
+    return info;
+  }
+
+  void _autoPlay(bool autoPlay) {
+    if (autoPlay) {
+      eventChannel.autoPlay(this);
+    }
   }
 }
 
+/// about channel
+
 const MethodChannel _globalChannel = MethodChannel("top.kikt/ijkplayer");
 
-Future<int> createIjk() async {
+Future<int> _createIjk() async {
   int id = await _globalChannel.invokeMethod("create");
   return id;
 }
@@ -84,7 +133,7 @@ class _IjkPlugin {
   _IjkPlugin(this.textureId);
 
   Future<void> dispose() async {
-    _globalChannel.invokeMethod("dispose", {"id": textureId});
+    await _globalChannel.invokeMethod("dispose", {"id": textureId});
   }
 
   Future<void> play() async {
@@ -92,11 +141,11 @@ class _IjkPlugin {
   }
 
   Future<void> pause() async {
-    channel.invokeMethod("pause");
+    await channel.invokeMethod("pause");
   }
 
   Future<void> stop() async {
-    channel.invokeMethod("stop");
+    await channel.invokeMethod("stop");
   }
 
   Future<void> setNetworkDataSource({String uri}) async {

+ 30 - 10
lib/src/ijk_event_channel.dart

@@ -2,6 +2,7 @@ import 'package:flutter/services.dart';
 import 'package:flutter_ijkplayer/src/video_info.dart';
 
 import './ijkplayer.dart';
+import 'dart:async';
 
 class IJKEventChannel {
   int get textureId => controller?.textureId;
@@ -14,6 +15,8 @@ class IJKEventChannel {
 
   String get channelName => "top.kikt/ijkplayer/event/$textureId";
 
+  Completer _prepareCompleter;
+
   Future<void> init() async {
     channel = MethodChannel(channelName);
     channel.setMethodCallHandler(handler);
@@ -27,9 +30,9 @@ class IJKEventChannel {
   Future<dynamic> handler(MethodCall call) async {
     switch (call.method) {
       case "finish": // 对应状态变化
-        var index = call.arguments["type"];
-        var type = FinishType.values[index];
-        onPlayFinish(type);
+        // var index = call.arguments["type"];
+        // var type = FinishType.values[index];
+        onPlayFinish(getInfo(call));
         break;
       case "playStateChange":
         onPlayStateChange(getInfo(call));
@@ -49,8 +52,8 @@ class IJKEventChannel {
     return VideoInfo.fromMap(map);
   }
 
-  void onPlayFinish(FinishType type) {
-    print("onPlayFinish type = $type");
+  void onPlayFinish(VideoInfo info) {
+    controller.isPlaying = info.isPlaying;
   }
 
   void onPlayStateChange(VideoInfo info) {
@@ -60,11 +63,28 @@ class IJKEventChannel {
 
   void onPrepare(VideoInfo info) {
     print("onPrepare $info");
+    controller.isPlaying = info.isPlaying;
+    _prepareCompleter?.complete();
+    _prepareCompleter = null;
   }
-}
 
-enum FinishType {
-  playEnd,
-  userExit,
-  error,
+  Future<void> waitPrepare() {
+    _prepareCompleter = Completer();
+    return _prepareCompleter.future;
+  }
+
+  void autoPlay(IjkMediaController ijkMediaController) async {
+    try {
+      await waitPrepare();
+      ijkMediaController.play();
+    } catch (e) {
+      print(e);
+    }
+  }
 }
+
+// enum FinishType {
+//   playEnd,
+//   userExit,
+//   error,
+// }