فهرست منبع

修改了datasource的设置方案,将datasource按file asset url的形式区分开

Caijinglong 6 سال پیش
والد
کامیت
4ba2e12176

+ 54 - 0
android/src/main/java/com/example/ijkplayer/AssetDataSource.kt

@@ -0,0 +1,54 @@
+package com.example.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()
+    }
+}

+ 42 - 20
android/src/main/java/com/example/ijkplayer/Ijk.kt

@@ -3,11 +3,13 @@ package com.example.ijkplayer
 /// create 2019/3/7 by cai
 
 
+import android.util.Base64
 import io.flutter.plugin.common.MethodCall
 import io.flutter.plugin.common.MethodChannel
 import io.flutter.plugin.common.PluginRegistry
 import tv.danmaku.ijk.media.player.IjkMediaPlayer
 import tv.danmaku.ijk.media.player.TextureMediaPlayer
+import java.io.File
 
 class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.MethodCallHandler {
 
@@ -28,26 +30,32 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
 
     override fun onMethodCall(call: MethodCall?, result: MethodChannel.Result?) {
         when (call?.method) {
-            "setDataSource" -> {
-                val uri = call.argument<String>("uri")!!
+            "setNetworkDataSource" -> {
+                val uri = call.argument<String>("uri")
+                if (uri == null) {
+                    handleSetUriResult(Exception("uri是必传参数"), result)
+                    return
+                }
                 setUri(uri) { throwable ->
-                    if (throwable == null) {
-                        result?.success(throwable)
-                    } else {
-                        throwable.printStackTrace()
-                        result?.error("2", "加载失败", throwable)
-                    }
+                    handleSetUriResult(throwable, result)
                 }
             }
             "setAssetDataSource" -> {
-
-                val uri = call.argument<String>("uri")!!
-                setUri(uri) { throwable ->
-                    if (throwable == null) {
-                        result?.success(throwable)
-                    } else {
-                        throwable.printStackTrace()
-                        result?.error("2", "加载失败", throwable)
+                val name = call.argument<String>("name")
+                val `package` = call.argument<String>("package")
+                if (name != null) {
+                    setAssetUri(name, `package`) { throwable ->
+                        handleSetUriResult(throwable, result)
+                    }
+                } else {
+                    handleSetUriResult(Exception("没有找到资源"), result)
+                }
+            }
+            "setFileDataSource" -> {
+                val path = call.argument<String>("path")
+                if (path != null) {
+                    setUri("file://$path") { throwable ->
+                        handleSetUriResult(throwable, result)
                     }
                 }
             }
@@ -67,6 +75,15 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
         }
     }
 
+    private fun handleSetUriResult(throwable: Throwable?, result: MethodChannel.Result?) {
+        if (throwable == null) {
+            result?.success(null)
+        } else {
+            throwable.printStackTrace()
+            result?.error("1", "设置资源失败", throwable)
+        }
+    }
+
     private fun setUri(uri: String, callback: (Throwable?) -> Unit) {
         try {
             ijkPlayer.setOnPreparedListener {
@@ -91,10 +108,15 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
                     } else {
                         registry.lookupKeyForAsset(name, `package`)
                     }
-
-            // 设置资产系的datasource
-
-
+            val assetManager = registry.context().assets
+            val fd = assetManager.openFd(asset)
+            val cacheDir = registry.context().cacheDir.absoluteFile.path
+
+            val fileName = Base64.encodeToString(asset.toByteArray(), Base64.DEFAULT)
+            val file = File(cacheDir, fileName)
+            fd.createInputStream().copyTo(file.outputStream())
+            ijkPlayer.dataSource = file.path
+//            ijkPlayer.setDataSource(fd.fileDescriptor) // can't use,
             ijkPlayer.prepareAsync()
         } catch (e: Exception) {
             e.printStackTrace()

BIN
android/src/main/libs/armeabi-v7a/libijkffmpeg.so


BIN
android/src/main/libs/armeabi-v7a/libijkplayer.so


BIN
android/src/main/libs/armeabi-v7a/libijksdl.so


BIN
example/assets/sample1.mp4


+ 15 - 3
example/lib/main.dart

@@ -61,16 +61,18 @@ class HomePageState extends State<HomePage> {
                 controller: controller,
               ),
             ),
+            _buildPlayAssetButton(),
           ],
         ),
       ),
       floatingActionButton: FloatingActionButton(
         child: Icon(Icons.play_arrow),
         onPressed: () async {
-          await controller.setDataSource(
-            'https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4',
+          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",
           );
@@ -130,8 +132,18 @@ class HomePageState extends State<HomePage> {
   }
 
   void playUri(String uri) async {
-    await controller.setDataSource(uri);
+    await controller.setNetworkDataSource(uri);
     print("set data source success");
     controller.play();
   }
+
+  _buildPlayAssetButton() {
+    return FlatButton(
+      child: Text("play sample asset"),
+      onPressed: () async {
+        await controller.setAssetDataSource("assets/sample1.mp4");
+        controller.play();
+      },
+    );
+  }
 }

+ 2 - 0
example/pubspec.yaml

@@ -34,6 +34,8 @@ flutter:
   # assets:
   #  - images/a_dot_burr.jpeg
   #  - images/a_dot_ham.jpeg
+  assets:
+    - assets/
   # An image asset can refer to one or more resolution-specific "variants", see
   # https://flutter.io/assets-and-images/#resolution-aware.
   # For details regarding adding assets from package dependencies, see

+ 1 - 1
ios/Classes/FlutterIJK.h

@@ -23,5 +23,5 @@
 
 - (void)stop;
 
-- (void)setDateSourceWithUri:(NSString *)uri;
+- (void)setDataSourceWithUri:(NSString *)uri;
 @end

+ 66 - 3
ios/Classes/FlutterIJK.m

@@ -44,17 +44,36 @@
         [self pause];
     } else if ([@"stop" isEqualToString:call.method]) {
         [self stop];
-    } else if ([@"setDataSource" isEqualToString:call.method]) {
+    } else if ([@"setNetworkDataSource" isEqualToString:call.method]) {
         @try {
             NSDictionary *params = call.arguments;
             NSString *uri = params[@"uri"];
-            [self setDateSourceWithUri:uri];
+            [self setDataSourceWithUri:uri];
             result(nil);
         }
         @catch (NSException *exception) {
             NSLog(@"Exception occurred: %@, %@", exception, [exception userInfo]);
             result([FlutterError errorWithCode:@"1" message:@"设置失败" details:nil]);
         }
+    } else if ([@"setAssetDataSource" isEqualToString:call.method]) {
+        @try {
+            NSDictionary *params = [call arguments];
+            NSString *name = params[@"name"];
+            NSString *pkg = params[@"package"];
+            IJKFFMoviePlayerController *playerController = [self createControllerWithAssetName:name pkg:pkg];
+            [self setDataSourceWithController:playerController];
+            result(nil);
+        }
+        @catch (NSException *exception) {
+            NSLog(@"Exception occurred: %@, %@", exception, [exception userInfo]);
+            result([FlutterError errorWithCode:@"1" message:@"设置失败" details:nil]);
+        }
+    } else if ([@"setFileDataSource" isEqualToString:call.method]) {
+        NSDictionary *params = call.arguments;
+        NSString *path = params[@"path"];
+        IJKFFMoviePlayerController *playerController = [self createControllerWithPath:path];
+    } else {
+        result(FlutterMethodNotImplemented);
     }
 }
 
@@ -87,15 +106,59 @@
     [controller stop];
 }
 
-- (void)setDateSourceWithUri:(NSString *)uri {
+- (void)setDataSourceWithController:(IJKFFMoviePlayerController *)ctl {
+    if (ctl) {
+        controller = ctl;
+        [self prepare];
+    }
+}
+
+- (IJKFFOptions *)createOption {
     IJKFFOptions *options = [IJKFFOptions optionsByDefault];
+    return options;
+}
+
+- (void)setDataSourceWithUri:(NSString *)uri {
+    IJKFFOptions *options = [self createOption];
     controller = [[IJKFFMoviePlayerController alloc] initWithContentURLString:uri withOptions:options];
+    [self prepare];
+}
+
+- (void)prepare {
     [controller prepareToPlay];
+
+    if (displayLink) {
+        displayLink.paused = YES;
+        [displayLink invalidate];
+        displayLink = nil;
+    }
     displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)];
     [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
     displayLink.paused = YES;
 }
 
+- (IJKFFMoviePlayerController *)createControllerWithAssetName:(NSString *)assetName pkg:(NSString *)pkg {
+    NSString *asset;
+    if (!pkg) {
+        asset = [self.registrar lookupKeyForAsset:assetName];
+    } else {
+        asset = [self.registrar lookupKeyForAsset:assetName fromPackage:pkg];
+    }
+    NSString *path = [[NSBundle mainBundle] pathForResource:asset ofType:nil];
+    NSURL *url = [NSURL fileURLWithPath:path];
+
+    IJKFFOptions *options = [self createOption];
+
+    return [[IJKFFMoviePlayerController alloc] initWithContentURL:url withOptions:options];
+}
+
+
+- (IJKFFMoviePlayerController *)createControllerWithPath:(NSString *)path {
+    NSURL *url = [NSURL fileURLWithPath:path];
+    IJKFFOptions *options = [self createOption];
+    return [[IJKFFMoviePlayerController alloc] initWithContentURL:url withOptions:options];
+}
+
 - (void)onDisplayLink:(CADisplayLink *)link {
     [textures textureFrameAvailable:textureId];
 }

+ 1 - 0
lib/flutter_ijkplayer.dart

@@ -1 +1,2 @@
 export 'src/ijkplayer.dart';
+export 'src/error.dart';

+ 17 - 7
lib/src/controller.dart

@@ -27,7 +27,7 @@ class IjkMediaController extends ChangeNotifier {
     super.dispose();
   }
 
-  Future<void> setDataSource(String url) async {
+  Future<void> setNetworkDataSource(String url) async {
     if (this.textureId != null) {
       await _plugin?.dispose();
     }
@@ -83,19 +83,29 @@ class _IjkPlugin {
 
   Future<void> setNetworkDataSource({String uri}) async {
     // todo
-    print("id = $textureId uri = $uri");
-    channel.invokeMethod("setDataSource", {"uri": uri});
+    print("id = $textureId net uri = $uri");
+    channel.invokeMethod("setNetworkDataSource", {"uri": uri});
   }
 
   Future<void> setAssetDataSource(String name, String package) async {
     print("id = $textureId asset name = $name package = $package");
-    channel.invokeMethod("setAssetDataSource", <String, dynamic>{
+    var params = <String, dynamic>{
       "name": name,
-      "package": package,
-    });
+    };
+    if (package != null) {
+      params["package"] = package;
+    }
+    channel.invokeMethod("setAssetDataSource", params);
   }
 
   Future<void> setFileDataSource(String path) async {
-    // todo 
+    if (!File(path).existsSync()) {
+      return Error.fileNotExists;
+    }
+    channel.invokeMethod("setFileDataSource", <String, dynamic>{
+      "path": path,
+    });
+    // todo
+    print("id = $textureId file path = $path");
   }
 }

+ 3 - 0
lib/src/error.dart

@@ -0,0 +1,3 @@
+enum Error {
+  fileNotExists,
+}

+ 2 - 0
lib/src/ijkplayer.dart

@@ -1,7 +1,9 @@
 import 'dart:async';
+import 'dart:io';
 
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
+import './error.dart';
 
 part './controller.dart';