Ver código fonte

release v0.2.2

Taner Sener 6 anos atrás
pai
commit
07cc05a611
100 arquivos alterados com 2058 adições e 621 exclusões
  1. 3 0
      CHANGELOG.md
  2. 10 10
      README.md
  3. 1 1
      example/pubspec.lock
  4. 52 22
      lib/flutter_ffmpeg.dart
  5. 2 1
      packages/flutter_ffmpeg_audio/.gitignore
  6. 4 2
      packages/flutter_ffmpeg_audio/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java
  7. 4 2
      packages/flutter_ffmpeg_audio/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java
  8. 4 2
      packages/flutter_ffmpeg_audio/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java
  9. 20 17
      packages/flutter_ffmpeg_audio/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java
  10. 77 0
      packages/flutter_ffmpeg_audio/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java
  11. 52 22
      packages/flutter_ffmpeg_audio/lib/flutter_ffmpeg.dart
  12. 3 3
      packages/flutter_ffmpeg_audio/pubspec.yaml
  13. 2 1
      packages/flutter_ffmpeg_audio_lts/.gitignore
  14. 4 2
      packages/flutter_ffmpeg_audio_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java
  15. 4 2
      packages/flutter_ffmpeg_audio_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java
  16. 4 2
      packages/flutter_ffmpeg_audio_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java
  17. 20 17
      packages/flutter_ffmpeg_audio_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java
  18. 77 0
      packages/flutter_ffmpeg_audio_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java
  19. 52 22
      packages/flutter_ffmpeg_audio_lts/lib/flutter_ffmpeg.dart
  20. 3 3
      packages/flutter_ffmpeg_audio_lts/pubspec.yaml
  21. 2 1
      packages/flutter_ffmpeg_full-gpl/.gitignore
  22. 4 2
      packages/flutter_ffmpeg_full-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java
  23. 4 2
      packages/flutter_ffmpeg_full-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java
  24. 4 2
      packages/flutter_ffmpeg_full-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java
  25. 20 17
      packages/flutter_ffmpeg_full-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java
  26. 77 0
      packages/flutter_ffmpeg_full-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java
  27. 52 22
      packages/flutter_ffmpeg_full-gpl/lib/flutter_ffmpeg.dart
  28. 3 3
      packages/flutter_ffmpeg_full-gpl/pubspec.yaml
  29. 2 1
      packages/flutter_ffmpeg_full-gpl_lts/.gitignore
  30. 4 2
      packages/flutter_ffmpeg_full-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java
  31. 4 2
      packages/flutter_ffmpeg_full-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java
  32. 4 2
      packages/flutter_ffmpeg_full-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java
  33. 20 17
      packages/flutter_ffmpeg_full-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java
  34. 77 0
      packages/flutter_ffmpeg_full-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java
  35. 52 22
      packages/flutter_ffmpeg_full-gpl_lts/lib/flutter_ffmpeg.dart
  36. 3 3
      packages/flutter_ffmpeg_full-gpl_lts/pubspec.yaml
  37. 2 1
      packages/flutter_ffmpeg_full/.gitignore
  38. 4 2
      packages/flutter_ffmpeg_full/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java
  39. 4 2
      packages/flutter_ffmpeg_full/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java
  40. 4 2
      packages/flutter_ffmpeg_full/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java
  41. 20 17
      packages/flutter_ffmpeg_full/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java
  42. 77 0
      packages/flutter_ffmpeg_full/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java
  43. 52 22
      packages/flutter_ffmpeg_full/lib/flutter_ffmpeg.dart
  44. 3 3
      packages/flutter_ffmpeg_full/pubspec.yaml
  45. 2 1
      packages/flutter_ffmpeg_full_lts/.gitignore
  46. 4 2
      packages/flutter_ffmpeg_full_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java
  47. 4 2
      packages/flutter_ffmpeg_full_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java
  48. 4 2
      packages/flutter_ffmpeg_full_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java
  49. 20 17
      packages/flutter_ffmpeg_full_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java
  50. 77 0
      packages/flutter_ffmpeg_full_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java
  51. 52 22
      packages/flutter_ffmpeg_full_lts/lib/flutter_ffmpeg.dart
  52. 3 3
      packages/flutter_ffmpeg_full_lts/pubspec.yaml
  53. 2 1
      packages/flutter_ffmpeg_https-gpl/.gitignore
  54. 4 2
      packages/flutter_ffmpeg_https-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java
  55. 4 2
      packages/flutter_ffmpeg_https-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java
  56. 4 2
      packages/flutter_ffmpeg_https-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java
  57. 20 17
      packages/flutter_ffmpeg_https-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java
  58. 77 0
      packages/flutter_ffmpeg_https-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java
  59. 52 22
      packages/flutter_ffmpeg_https-gpl/lib/flutter_ffmpeg.dart
  60. 3 3
      packages/flutter_ffmpeg_https-gpl/pubspec.yaml
  61. 2 1
      packages/flutter_ffmpeg_https-gpl_lts/.gitignore
  62. 4 2
      packages/flutter_ffmpeg_https-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java
  63. 4 2
      packages/flutter_ffmpeg_https-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java
  64. 4 2
      packages/flutter_ffmpeg_https-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java
  65. 20 17
      packages/flutter_ffmpeg_https-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java
  66. 77 0
      packages/flutter_ffmpeg_https-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java
  67. 52 22
      packages/flutter_ffmpeg_https-gpl_lts/lib/flutter_ffmpeg.dart
  68. 3 3
      packages/flutter_ffmpeg_https-gpl_lts/pubspec.yaml
  69. 2 1
      packages/flutter_ffmpeg_https/.gitignore
  70. 4 2
      packages/flutter_ffmpeg_https/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java
  71. 4 2
      packages/flutter_ffmpeg_https/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java
  72. 4 2
      packages/flutter_ffmpeg_https/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java
  73. 20 17
      packages/flutter_ffmpeg_https/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java
  74. 77 0
      packages/flutter_ffmpeg_https/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java
  75. 52 22
      packages/flutter_ffmpeg_https/lib/flutter_ffmpeg.dart
  76. 3 3
      packages/flutter_ffmpeg_https/pubspec.yaml
  77. 2 1
      packages/flutter_ffmpeg_https_lts/.gitignore
  78. 4 2
      packages/flutter_ffmpeg_https_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java
  79. 4 2
      packages/flutter_ffmpeg_https_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java
  80. 4 2
      packages/flutter_ffmpeg_https_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java
  81. 20 17
      packages/flutter_ffmpeg_https_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java
  82. 77 0
      packages/flutter_ffmpeg_https_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java
  83. 52 22
      packages/flutter_ffmpeg_https_lts/lib/flutter_ffmpeg.dart
  84. 3 3
      packages/flutter_ffmpeg_https_lts/pubspec.yaml
  85. 2 1
      packages/flutter_ffmpeg_min-gpl/.gitignore
  86. 4 2
      packages/flutter_ffmpeg_min-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java
  87. 4 2
      packages/flutter_ffmpeg_min-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java
  88. 4 2
      packages/flutter_ffmpeg_min-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java
  89. 20 17
      packages/flutter_ffmpeg_min-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java
  90. 77 0
      packages/flutter_ffmpeg_min-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java
  91. 52 22
      packages/flutter_ffmpeg_min-gpl/lib/flutter_ffmpeg.dart
  92. 3 3
      packages/flutter_ffmpeg_min-gpl/pubspec.yaml
  93. 2 1
      packages/flutter_ffmpeg_min-gpl_lts/.gitignore
  94. 4 2
      packages/flutter_ffmpeg_min-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java
  95. 4 2
      packages/flutter_ffmpeg_min-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java
  96. 4 2
      packages/flutter_ffmpeg_min-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java
  97. 20 17
      packages/flutter_ffmpeg_min-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java
  98. 77 0
      packages/flutter_ffmpeg_min-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java
  99. 52 22
      packages/flutter_ffmpeg_min-gpl_lts/lib/flutter_ffmpeg.dart
  100. 3 3
      packages/flutter_ffmpeg_min-gpl_lts/pubspec.yaml

+ 3 - 0
CHANGELOG.md

@@ -1,3 +1,6 @@
+## 0.2.2
+- Fixed flutter v1.6 compatibility errors
+
 ## 0.2.1
 - Fixed documentation errors
 - Updated package description

+ 10 - 10
README.md

@@ -1,6 +1,6 @@
 # flutter_ffmpeg 
 
-![GitHub release](https://img.shields.io/badge/release-v0.2.1-blue.svg) 
+![GitHub release](https://img.shields.io/badge/release-v0.2.2-blue.svg) 
 ![](https://img.shields.io/pub/v/flutter_ffmpeg.svg)
 
 FFmpeg plugin for Flutter. Supports iOS and Android.
@@ -10,10 +10,10 @@ FFmpeg plugin for Flutter. Supports iOS and Android.
 ### 1. Features
 - Based on MobileFFmpeg
 - Supports
-    - Both Android and IOS
+    - Both Android (API 21+) and iOS (SDK 9.3+)
     - FFmpeg `v4.2-dev-x` (master) releases
     - `arm-v7a`, `arm-v7a-neon`, `arm64-v8a`, `x86` and `x86_64` architectures on Android
-    - `armv7`, `armv7s`, `arm64`, `arm64e`, `i386` and `x86_64` architectures on IOS
+    - `armv7`, `armv7s`, `arm64`, `arm64e`, `i386` and `x86_64` architectures on iOS
     - 24 external libraries
 
         `fontconfig`, `freetype`, `fribidi`, `gmp`, `gnutls`, `kvazaar`, `lame`, `libaom`, `libass`, `libiconv`, `libilbc`, `libtheora`, `libvorbis`, `libvpx`, `libwebp`, `libxml2`, `opencore-amr`, `opus`, `shine`, `snappy`, `soxr`, `speex`, `twolame`, `wavpack`
@@ -23,7 +23,7 @@ FFmpeg plugin for Flutter. Supports iOS and Android.
         `vid.stab`, `x264`, `x265`, `xvidcore`
 
     - `zlib` and `MediaCodec` Android system libraries
-    - `bzip2`, `zlib` IOS system libraries and `AudioToolbox`, `CoreImage`, `VideoToolbox`, `AVFoundation` IOS system frameworks
+    - `bzip2`, `zlib` iOS system libraries and `AudioToolbox`, `CoreImage`, `VideoToolbox`, `AVFoundation` iOS system frameworks
 
 - Licensed under LGPL 3.0, can be customized to support GPL v3.0
 - Includes eight different packages with different external libraries enabled in FFmpeg
@@ -117,18 +117,18 @@ In order to install the `LTS` variant, install the `flutter_ffmpeg_https_lts` pa
         <td align="center">arm-v7a-neon<br>arm64-v8a<br>x86<br>x86-64</td>
         <td align="center">arm-v7a<br>arm-v7a-neon<br>arm64-v8a<br>x86<br>x86-64</td>
     </tr>
-    <tr>
-        <td align="center">IOS SDK</td>
-        <td align="center">12.1</td>
-        <td align="center">9.3</td>
-    </tr>
     <tr>
         <td align="center">Xcode Support</td>
         <td align="center">10.1</td>
         <td align="center">7.3.1</td>
     </tr>
     <tr>
-        <td align="center">IOS Architectures</td>
+        <td align="center">iOS SDK</td>
+        <td align="center">12.1</td>
+        <td align="center">9.3</td>
+    </tr>
+    <tr>
+        <td align="center">iOS Architectures</td>
         <td align="center">arm64<br>arm64e<br>x86-64</td>
         <td align="center">armv7<br>arm64<br>i386<br>x86-64</td>
     </tr>

+ 1 - 1
example/pubspec.lock

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

+ 52 - 22
lib/flutter_ffmpeg.dart

@@ -22,11 +22,20 @@ import 'dart:async';
 import 'package:flutter/services.dart';
 
 class FlutterFFmpeg {
-  static const MethodChannel _methodChannel = const MethodChannel('flutter_ffmpeg');
-  static const EventChannel _eventChannel = const EventChannel('flutter_ffmpeg_event');
+  static const MethodChannel _methodChannel =
+      const MethodChannel('flutter_ffmpeg');
+  static const EventChannel _eventChannel =
+      const EventChannel('flutter_ffmpeg_event');
 
   Function(int level, String message) logCallback;
-  Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) statisticsCallback;
+  Function(
+      int time,
+      int size,
+      double bitrate,
+      double speed,
+      int videoFrameNumber,
+      double videoQuality,
+      double videoFps) statisticsCallback;
 
   FlutterFFmpeg() {
     logCallback = null;
@@ -46,8 +55,10 @@ class FlutterFFmpeg {
   void _onEvent(Object event) {
     if (event is Map<dynamic, dynamic>) {
       final Map<String, dynamic> eventMap = event.cast();
-      final Map<dynamic, dynamic> logEvent = eventMap['FlutterFFmpegLogCallback'];
-      final Map<dynamic, dynamic> statisticsEvent = eventMap['FlutterFFmpegStatisticsCallback'];
+      final Map<dynamic, dynamic> logEvent =
+          eventMap['FlutterFFmpegLogCallback'];
+      final Map<dynamic, dynamic> statisticsEvent =
+          eventMap['FlutterFFmpegStatisticsCallback'];
 
       if (logEvent != null) {
         int level = logEvent['level'];
@@ -74,10 +85,12 @@ class FlutterFFmpeg {
           double bitrate = _doublePrecision(statisticsEvent['bitrate'], 2);
           double speed = _doublePrecision(statisticsEvent['speed'], 2);
           int videoFrameNumber = statisticsEvent['videoFrameNumber'];
-          double videoQuality = _doublePrecision(statisticsEvent['videoQuality'], 2);
+          double videoQuality =
+              _doublePrecision(statisticsEvent['videoQuality'], 2);
           double videoFps = _doublePrecision(statisticsEvent['videoFps'], 2);
 
-          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber, videoQuality, videoFps);
+          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber,
+              videoQuality, videoFps);
         }
       }
     }
@@ -98,7 +111,8 @@ class FlutterFFmpeg {
   /// Returns FFmpeg version bundled within the library.
   Future<String> getFFmpegVersion() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getFFmpegVersion');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getFFmpegVersion');
       return result['version'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -109,7 +123,8 @@ class FlutterFFmpeg {
   /// Returns platform name where library is loaded.
   Future<String> getPlatform() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPlatform');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPlatform');
       return result['platform'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -120,7 +135,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg with [commandArguments] provided.
   Future<int> executeWithArguments(List<String> arguments) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('executeWithArguments', {'arguments': arguments});
+      final Map<dynamic, dynamic> result = await _methodChannel
+          .invokeMethod('executeWithArguments', {'arguments': arguments});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -131,7 +147,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg [command] provided. Command is split into arguments using provided [delimiter].
   Future<int> execute(String command, [String delimiter = ' ']) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('execute', {'command': command, 'delimiter': delimiter});
+      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod(
+          'execute', {'command': command, 'delimiter': delimiter});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -175,7 +192,8 @@ class FlutterFFmpeg {
   /// Returns log level.
   Future<int> getLogLevel() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLogLevel');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLogLevel');
       return result['level'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -241,7 +259,10 @@ class FlutterFFmpeg {
   }
 
   /// Sets a callback to redirect FFmpeg statistics. [newCallback] is a new statistics callback function, use null to disable a previously defined callback
-  void enableStatisticsCallback(Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) newCallback) {
+  void enableStatisticsCallback(
+      Function(int time, int size, double bitrate, double speed,
+              int videoFrameNumber, double videoQuality, double videoFps)
+          newCallback) {
     try {
       this.statisticsCallback = newCallback;
     } on PlatformException catch (e) {
@@ -253,7 +274,8 @@ class FlutterFFmpeg {
   /// videoQuality fields
   Future<Map<dynamic, dynamic>> getLastReceivedStatistics() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReceivedStatistics');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReceivedStatistics');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -273,14 +295,16 @@ class FlutterFFmpeg {
   /// Sets and overrides fontconfig configuration directory.
   Future<void> setFontconfigConfigurationPath(String path) async {
     try {
-      await _methodChannel.invokeMethod('setFontconfigConfigurationPath', {'path': path});
+      await _methodChannel
+          .invokeMethod('setFontconfigConfigurationPath', {'path': path});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
     }
   }
 
   /// Registers fonts inside the given [fontDirectory], so they are available to use in FFmpeg filters.
-  Future<void> setFontDirectory(String fontDirectory, Map<String, String> fontNameMap) async {
+  Future<void> setFontDirectory(
+      String fontDirectory, Map<String, String> fontNameMap) async {
     var parameters;
     if (fontNameMap == null) {
       parameters = {'fontDirectory': fontDirectory};
@@ -298,7 +322,8 @@ class FlutterFFmpeg {
   /// Returns FlutterFFmpeg package name.
   Future<String> getPackageName() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPackageName');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPackageName');
       return result['packageName'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -309,7 +334,8 @@ class FlutterFFmpeg {
   /// Returns supported external libraries.
   Future<List<dynamic>> getExternalLibraries() async {
     try {
-      final List<dynamic> result = await _methodChannel.invokeMethod('getExternalLibraries');
+      final List<dynamic> result =
+          await _methodChannel.invokeMethod('getExternalLibraries');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -320,7 +346,8 @@ class FlutterFFmpeg {
   /// Returns return code of last executed command.
   Future<int> getLastReturnCode() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReturnCode');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReturnCode');
       return result['lastRc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -332,7 +359,8 @@ class FlutterFFmpeg {
   /// [disableRedirection()] method also disables this functionality.
   Future<String> getLastCommandOutput() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastCommandOutput');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastCommandOutput');
       return result['lastCommandOutput'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -341,9 +369,11 @@ class FlutterFFmpeg {
   }
 
   /// Returns media information for given [path] using optional [timeout]
-  Future<Map<dynamic, dynamic>> getMediaInformation(String path, [int timeout = 10000]) async {
+  Future<Map<dynamic, dynamic>> getMediaInformation(String path,
+      [int timeout = 10000]) async {
     try {
-      return await _methodChannel.invokeMethod('getMediaInformation', {'path': path, 'timeout': timeout});
+      return await _methodChannel.invokeMethod(
+          'getMediaInformation', {'path': path, 'timeout': timeout});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
       return null;

+ 2 - 1
packages/flutter_ffmpeg_audio/.gitignore

@@ -3,5 +3,6 @@
 .dart_tool/
 .pub/
 build/
-pubspec.lock
+/pubspec.lock
 /.packages
+/.gradle/

+ 4 - 2
packages/flutter_ffmpeg_audio/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java

@@ -39,10 +39,12 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     private final MethodChannel.Result result;
     private final List<String> arguments;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncArgumentsTask(final List<String> arguments, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncArgumentsTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final List<String> arguments, final MethodChannel.Result result) {
         this.arguments = arguments;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -60,7 +62,7 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_audio/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java

@@ -36,8 +36,9 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     private String delimiter;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncCommandTask(final String delimiter, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncCommandTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final String delimiter, final MethodChannel.Result result) {
         if (delimiter == null) {
             this.delimiter = " ";
         } else {
@@ -45,6 +46,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
         }
 
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -66,7 +68,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_audio/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java

@@ -37,10 +37,12 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     private Integer timeout;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegGetMediaInformationAsyncTask(final Integer timeout, final MethodChannel.Result result) {
+    FlutterFFmpegGetMediaInformationAsyncTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final Integer timeout, final MethodChannel.Result result) {
         this.timeout = timeout;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -64,7 +66,7 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     @Override
     protected void onPostExecute(final MediaInformation mediaInformation) {
-        result.success(FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
     }
 
 }

+ 20 - 17
packages/flutter_ffmpeg_audio/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java

@@ -80,6 +80,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
     private EventChannel.EventSink eventSink;
     private final Registrar registrar;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
     /**
      * Registers plugin to registry.
@@ -87,17 +88,19 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
      * @param registrar receiver of plugin registration
      */
     public static void registerWith(final Registrar registrar) {
-        FlutterFFmpegPlugin handler = new FlutterFFmpegPlugin(registrar);
+        FlutterFFmpegPlugin flutterFFmpegPlugin = new FlutterFFmpegPlugin(registrar);
 
         final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_ffmpeg");
-        channel.setMethodCallHandler(handler);
+        channel.setMethodCallHandler(flutterFFmpegPlugin);
 
         final EventChannel eventChannel = new EventChannel(registrar.messenger(), "flutter_ffmpeg_event");
-        eventChannel.setStreamHandler(handler);
+        eventChannel.setStreamHandler(flutterFFmpegPlugin);
     }
 
     private FlutterFFmpegPlugin(Registrar registrar) {
         this.registrar = registrar;
+
+        this.flutterFFmpegResultHandler = new FlutterFFmpegResultHandler();
     }
 
     private Context getActiveContext() {
@@ -115,18 +118,18 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         if (call.method.equals("getPlatform")) {
 
             final String abi = AbiDetect.getAbi();
-            result.success(toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
 
         } else if (call.method.equals("getFFmpegVersion")) {
 
             final String version = FFmpeg.getFFmpegVersion();
-            result.success(toStringMap(KEY_VERSION, version));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_VERSION, version));
 
         } else if (call.method.equals("executeWithArguments")) {
 
             List<String> arguments = call.argument("arguments");
 
-            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(arguments, result);
+            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(flutterFFmpegResultHandler, arguments, result);
             asyncTask.execute("dummy-trigger");
 
         } else if (call.method.equals("execute")) {
@@ -134,7 +137,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
             String command = call.argument("command");
             String delimiter = call.argument("delimiter");
 
-            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(delimiter, result);
+            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(flutterFFmpegResultHandler, delimiter, result);
             asyncTask.execute(command);
 
         } else if (call.method.equals("cancel")) {
@@ -152,7 +155,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getLogLevel")) {
 
             final Level level = Config.getLogLevel();
-            result.success(toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
 
         } else if (call.method.equals("setLogLevel")) {
 
@@ -192,7 +195,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         } else if (call.method.equals("getLastReceivedStatistics")) {
 
-            result.success(toMap(Config.getLastReceivedStatistics()));
+            flutterFFmpegResultHandler.success(result, toMap(Config.getLastReceivedStatistics()));
 
         } else if (call.method.equals("resetStatistics")) {
 
@@ -217,22 +220,22 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getPackageName")) {
 
             final String packageName = Config.getPackageName();
-            result.success(toStringMap(KEY_PACKAGE_NAME, packageName));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PACKAGE_NAME, packageName));
 
         } else if (call.method.equals("getExternalLibraries")) {
 
             final List<String> externalLibraries = Config.getExternalLibraries();
-            result.success(externalLibraries);
+            flutterFFmpegResultHandler.success(result, externalLibraries);
 
         } else if (call.method.equals("getLastReturnCode")) {
 
             int lastReturnCode = FFmpeg.getLastReturnCode();
-            result.success(toIntMap(KEY_LAST_RC, lastReturnCode));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LAST_RC, lastReturnCode));
 
         } else if (call.method.equals("getLastCommandOutput")) {
 
             final String lastCommandOutput = FFmpeg.getLastCommandOutput();
-            result.success(toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
 
         } else if (call.method.equals("getMediaInformation")) {
             final String path = call.argument("path");
@@ -241,11 +244,11 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
                 timeout = 10000;
             }
 
-            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(timeout, result);
+            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(flutterFFmpegResultHandler, timeout, result);
             asyncTask.execute(path);
 
         } else {
-            result.notImplemented();
+            flutterFFmpegResultHandler.notImplemented(result);
         }
     }
 
@@ -268,13 +271,13 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         logWrapperMap.put(EVENT_LOG, logMap);
 
-        eventSink.success(logWrapperMap);
+        flutterFFmpegResultHandler.success(eventSink, logWrapperMap);
     }
 
     protected void emitStatistics(final Statistics statistics) {
         final HashMap<String, Object> statisticsMap = new HashMap<>();
         statisticsMap.put(EVENT_STAT, toMap(statistics));
-        eventSink.success(statisticsMap);
+        flutterFFmpegResultHandler.success(eventSink, statisticsMap);
     }
 
     public static int levelToInt(final Level level) {

+ 77 - 0
packages/flutter_ffmpeg_audio/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Taner Sener
+ *
+ * This file is part of FlutterFFmpeg.
+ *
+ * FlutterFFmpeg is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FlutterFFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FlutterFFmpeg.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.arthenica.flutter.ffmpeg;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.MethodChannel;
+
+/**
+ * <h3>Flutter FFmpeg Result Handler</h3>
+ *
+ * @author Taner Sener
+ * @since 0.2.2
+ */
+class FlutterFFmpegResultHandler {
+    private final Handler handler;
+
+    FlutterFFmpegResultHandler() {
+        handler = new Handler(Looper.getMainLooper());
+    }
+
+    void notImplemented(final MethodChannel.Result result) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.notImplemented();
+                }
+            }
+        });
+    }
+
+    void success(final MethodChannel.Result result, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.success(object);
+                }
+            }
+        });
+    }
+
+    void success(final EventChannel.EventSink eventSink, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (eventSink != null) {
+                    eventSink.success(object);
+                }
+            }
+        });
+    }
+
+}

+ 52 - 22
packages/flutter_ffmpeg_audio/lib/flutter_ffmpeg.dart

@@ -22,11 +22,20 @@ import 'dart:async';
 import 'package:flutter/services.dart';
 
 class FlutterFFmpeg {
-  static const MethodChannel _methodChannel = const MethodChannel('flutter_ffmpeg');
-  static const EventChannel _eventChannel = const EventChannel('flutter_ffmpeg_event');
+  static const MethodChannel _methodChannel =
+      const MethodChannel('flutter_ffmpeg');
+  static const EventChannel _eventChannel =
+      const EventChannel('flutter_ffmpeg_event');
 
   Function(int level, String message) logCallback;
-  Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) statisticsCallback;
+  Function(
+      int time,
+      int size,
+      double bitrate,
+      double speed,
+      int videoFrameNumber,
+      double videoQuality,
+      double videoFps) statisticsCallback;
 
   FlutterFFmpeg() {
     logCallback = null;
@@ -46,8 +55,10 @@ class FlutterFFmpeg {
   void _onEvent(Object event) {
     if (event is Map<dynamic, dynamic>) {
       final Map<String, dynamic> eventMap = event.cast();
-      final Map<dynamic, dynamic> logEvent = eventMap['FlutterFFmpegLogCallback'];
-      final Map<dynamic, dynamic> statisticsEvent = eventMap['FlutterFFmpegStatisticsCallback'];
+      final Map<dynamic, dynamic> logEvent =
+          eventMap['FlutterFFmpegLogCallback'];
+      final Map<dynamic, dynamic> statisticsEvent =
+          eventMap['FlutterFFmpegStatisticsCallback'];
 
       if (logEvent != null) {
         int level = logEvent['level'];
@@ -74,10 +85,12 @@ class FlutterFFmpeg {
           double bitrate = _doublePrecision(statisticsEvent['bitrate'], 2);
           double speed = _doublePrecision(statisticsEvent['speed'], 2);
           int videoFrameNumber = statisticsEvent['videoFrameNumber'];
-          double videoQuality = _doublePrecision(statisticsEvent['videoQuality'], 2);
+          double videoQuality =
+              _doublePrecision(statisticsEvent['videoQuality'], 2);
           double videoFps = _doublePrecision(statisticsEvent['videoFps'], 2);
 
-          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber, videoQuality, videoFps);
+          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber,
+              videoQuality, videoFps);
         }
       }
     }
@@ -98,7 +111,8 @@ class FlutterFFmpeg {
   /// Returns FFmpeg version bundled within the library.
   Future<String> getFFmpegVersion() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getFFmpegVersion');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getFFmpegVersion');
       return result['version'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -109,7 +123,8 @@ class FlutterFFmpeg {
   /// Returns platform name where library is loaded.
   Future<String> getPlatform() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPlatform');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPlatform');
       return result['platform'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -120,7 +135,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg with [commandArguments] provided.
   Future<int> executeWithArguments(List<String> arguments) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('executeWithArguments', {'arguments': arguments});
+      final Map<dynamic, dynamic> result = await _methodChannel
+          .invokeMethod('executeWithArguments', {'arguments': arguments});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -131,7 +147,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg [command] provided. Command is split into arguments using provided [delimiter].
   Future<int> execute(String command, [String delimiter = ' ']) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('execute', {'command': command, 'delimiter': delimiter});
+      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod(
+          'execute', {'command': command, 'delimiter': delimiter});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -175,7 +192,8 @@ class FlutterFFmpeg {
   /// Returns log level.
   Future<int> getLogLevel() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLogLevel');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLogLevel');
       return result['level'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -241,7 +259,10 @@ class FlutterFFmpeg {
   }
 
   /// Sets a callback to redirect FFmpeg statistics. [newCallback] is a new statistics callback function, use null to disable a previously defined callback
-  void enableStatisticsCallback(Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) newCallback) {
+  void enableStatisticsCallback(
+      Function(int time, int size, double bitrate, double speed,
+              int videoFrameNumber, double videoQuality, double videoFps)
+          newCallback) {
     try {
       this.statisticsCallback = newCallback;
     } on PlatformException catch (e) {
@@ -253,7 +274,8 @@ class FlutterFFmpeg {
   /// videoQuality fields
   Future<Map<dynamic, dynamic>> getLastReceivedStatistics() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReceivedStatistics');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReceivedStatistics');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -273,14 +295,16 @@ class FlutterFFmpeg {
   /// Sets and overrides fontconfig configuration directory.
   Future<void> setFontconfigConfigurationPath(String path) async {
     try {
-      await _methodChannel.invokeMethod('setFontconfigConfigurationPath', {'path': path});
+      await _methodChannel
+          .invokeMethod('setFontconfigConfigurationPath', {'path': path});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
     }
   }
 
   /// Registers fonts inside the given [fontDirectory], so they are available to use in FFmpeg filters.
-  Future<void> setFontDirectory(String fontDirectory, Map<String, String> fontNameMap) async {
+  Future<void> setFontDirectory(
+      String fontDirectory, Map<String, String> fontNameMap) async {
     var parameters;
     if (fontNameMap == null) {
       parameters = {'fontDirectory': fontDirectory};
@@ -298,7 +322,8 @@ class FlutterFFmpeg {
   /// Returns FlutterFFmpeg package name.
   Future<String> getPackageName() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPackageName');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPackageName');
       return result['packageName'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -309,7 +334,8 @@ class FlutterFFmpeg {
   /// Returns supported external libraries.
   Future<List<dynamic>> getExternalLibraries() async {
     try {
-      final List<dynamic> result = await _methodChannel.invokeMethod('getExternalLibraries');
+      final List<dynamic> result =
+          await _methodChannel.invokeMethod('getExternalLibraries');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -320,7 +346,8 @@ class FlutterFFmpeg {
   /// Returns return code of last executed command.
   Future<int> getLastReturnCode() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReturnCode');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReturnCode');
       return result['lastRc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -332,7 +359,8 @@ class FlutterFFmpeg {
   /// [disableRedirection()] method also disables this functionality.
   Future<String> getLastCommandOutput() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastCommandOutput');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastCommandOutput');
       return result['lastCommandOutput'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -341,9 +369,11 @@ class FlutterFFmpeg {
   }
 
   /// Returns media information for given [path] using optional [timeout]
-  Future<Map<dynamic, dynamic>> getMediaInformation(String path, [int timeout = 10000]) async {
+  Future<Map<dynamic, dynamic>> getMediaInformation(String path,
+      [int timeout = 10000]) async {
     try {
-      return await _methodChannel.invokeMethod('getMediaInformation', {'path': path, 'timeout': timeout});
+      return await _methodChannel.invokeMethod(
+          'getMediaInformation', {'path': path, 'timeout': timeout});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
       return null;

+ 3 - 3
packages/flutter_ffmpeg_audio/pubspec.yaml

@@ -1,6 +1,6 @@
 name: flutter_ffmpeg
-description: Flutter plugin to run FFmpeg in the mobile platform. Supports iOS and Android.
-version: 0.2.1
+description: Flutter plugin to run FFmpeg on mobile platforms. Supports iOS and Android.
+version: 0.2.2
 author: Taner Sener <tanersener@gmail.com>
 homepage: https://github.com/tanersener/flutter-ffmpeg
 
@@ -12,7 +12,7 @@ dependencies:
     sdk: flutter
 
 dev_dependencies:
-  path_provider: ^0.5.0+1
+  path_provider: ^1.1.0
   path: ^1.6.2
 
 flutter:

+ 2 - 1
packages/flutter_ffmpeg_audio_lts/.gitignore

@@ -3,5 +3,6 @@
 .dart_tool/
 .pub/
 build/
-pubspec.lock
+/pubspec.lock
 /.packages
+/.gradle/

+ 4 - 2
packages/flutter_ffmpeg_audio_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java

@@ -39,10 +39,12 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     private final MethodChannel.Result result;
     private final List<String> arguments;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncArgumentsTask(final List<String> arguments, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncArgumentsTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final List<String> arguments, final MethodChannel.Result result) {
         this.arguments = arguments;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -60,7 +62,7 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_audio_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java

@@ -36,8 +36,9 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     private String delimiter;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncCommandTask(final String delimiter, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncCommandTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final String delimiter, final MethodChannel.Result result) {
         if (delimiter == null) {
             this.delimiter = " ";
         } else {
@@ -45,6 +46,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
         }
 
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -66,7 +68,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_audio_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java

@@ -37,10 +37,12 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     private Integer timeout;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegGetMediaInformationAsyncTask(final Integer timeout, final MethodChannel.Result result) {
+    FlutterFFmpegGetMediaInformationAsyncTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final Integer timeout, final MethodChannel.Result result) {
         this.timeout = timeout;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -64,7 +66,7 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     @Override
     protected void onPostExecute(final MediaInformation mediaInformation) {
-        result.success(FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
     }
 
 }

+ 20 - 17
packages/flutter_ffmpeg_audio_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java

@@ -80,6 +80,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
     private EventChannel.EventSink eventSink;
     private final Registrar registrar;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
     /**
      * Registers plugin to registry.
@@ -87,17 +88,19 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
      * @param registrar receiver of plugin registration
      */
     public static void registerWith(final Registrar registrar) {
-        FlutterFFmpegPlugin handler = new FlutterFFmpegPlugin(registrar);
+        FlutterFFmpegPlugin flutterFFmpegPlugin = new FlutterFFmpegPlugin(registrar);
 
         final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_ffmpeg");
-        channel.setMethodCallHandler(handler);
+        channel.setMethodCallHandler(flutterFFmpegPlugin);
 
         final EventChannel eventChannel = new EventChannel(registrar.messenger(), "flutter_ffmpeg_event");
-        eventChannel.setStreamHandler(handler);
+        eventChannel.setStreamHandler(flutterFFmpegPlugin);
     }
 
     private FlutterFFmpegPlugin(Registrar registrar) {
         this.registrar = registrar;
+
+        this.flutterFFmpegResultHandler = new FlutterFFmpegResultHandler();
     }
 
     private Context getActiveContext() {
@@ -115,18 +118,18 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         if (call.method.equals("getPlatform")) {
 
             final String abi = AbiDetect.getAbi();
-            result.success(toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
 
         } else if (call.method.equals("getFFmpegVersion")) {
 
             final String version = FFmpeg.getFFmpegVersion();
-            result.success(toStringMap(KEY_VERSION, version));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_VERSION, version));
 
         } else if (call.method.equals("executeWithArguments")) {
 
             List<String> arguments = call.argument("arguments");
 
-            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(arguments, result);
+            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(flutterFFmpegResultHandler, arguments, result);
             asyncTask.execute("dummy-trigger");
 
         } else if (call.method.equals("execute")) {
@@ -134,7 +137,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
             String command = call.argument("command");
             String delimiter = call.argument("delimiter");
 
-            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(delimiter, result);
+            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(flutterFFmpegResultHandler, delimiter, result);
             asyncTask.execute(command);
 
         } else if (call.method.equals("cancel")) {
@@ -152,7 +155,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getLogLevel")) {
 
             final Level level = Config.getLogLevel();
-            result.success(toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
 
         } else if (call.method.equals("setLogLevel")) {
 
@@ -192,7 +195,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         } else if (call.method.equals("getLastReceivedStatistics")) {
 
-            result.success(toMap(Config.getLastReceivedStatistics()));
+            flutterFFmpegResultHandler.success(result, toMap(Config.getLastReceivedStatistics()));
 
         } else if (call.method.equals("resetStatistics")) {
 
@@ -217,22 +220,22 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getPackageName")) {
 
             final String packageName = Config.getPackageName();
-            result.success(toStringMap(KEY_PACKAGE_NAME, packageName));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PACKAGE_NAME, packageName));
 
         } else if (call.method.equals("getExternalLibraries")) {
 
             final List<String> externalLibraries = Config.getExternalLibraries();
-            result.success(externalLibraries);
+            flutterFFmpegResultHandler.success(result, externalLibraries);
 
         } else if (call.method.equals("getLastReturnCode")) {
 
             int lastReturnCode = FFmpeg.getLastReturnCode();
-            result.success(toIntMap(KEY_LAST_RC, lastReturnCode));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LAST_RC, lastReturnCode));
 
         } else if (call.method.equals("getLastCommandOutput")) {
 
             final String lastCommandOutput = FFmpeg.getLastCommandOutput();
-            result.success(toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
 
         } else if (call.method.equals("getMediaInformation")) {
             final String path = call.argument("path");
@@ -241,11 +244,11 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
                 timeout = 10000;
             }
 
-            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(timeout, result);
+            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(flutterFFmpegResultHandler, timeout, result);
             asyncTask.execute(path);
 
         } else {
-            result.notImplemented();
+            flutterFFmpegResultHandler.notImplemented(result);
         }
     }
 
@@ -268,13 +271,13 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         logWrapperMap.put(EVENT_LOG, logMap);
 
-        eventSink.success(logWrapperMap);
+        flutterFFmpegResultHandler.success(eventSink, logWrapperMap);
     }
 
     protected void emitStatistics(final Statistics statistics) {
         final HashMap<String, Object> statisticsMap = new HashMap<>();
         statisticsMap.put(EVENT_STAT, toMap(statistics));
-        eventSink.success(statisticsMap);
+        flutterFFmpegResultHandler.success(eventSink, statisticsMap);
     }
 
     public static int levelToInt(final Level level) {

+ 77 - 0
packages/flutter_ffmpeg_audio_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Taner Sener
+ *
+ * This file is part of FlutterFFmpeg.
+ *
+ * FlutterFFmpeg is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FlutterFFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FlutterFFmpeg.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.arthenica.flutter.ffmpeg;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.MethodChannel;
+
+/**
+ * <h3>Flutter FFmpeg Result Handler</h3>
+ *
+ * @author Taner Sener
+ * @since 0.2.2
+ */
+class FlutterFFmpegResultHandler {
+    private final Handler handler;
+
+    FlutterFFmpegResultHandler() {
+        handler = new Handler(Looper.getMainLooper());
+    }
+
+    void notImplemented(final MethodChannel.Result result) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.notImplemented();
+                }
+            }
+        });
+    }
+
+    void success(final MethodChannel.Result result, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.success(object);
+                }
+            }
+        });
+    }
+
+    void success(final EventChannel.EventSink eventSink, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (eventSink != null) {
+                    eventSink.success(object);
+                }
+            }
+        });
+    }
+
+}

+ 52 - 22
packages/flutter_ffmpeg_audio_lts/lib/flutter_ffmpeg.dart

@@ -22,11 +22,20 @@ import 'dart:async';
 import 'package:flutter/services.dart';
 
 class FlutterFFmpeg {
-  static const MethodChannel _methodChannel = const MethodChannel('flutter_ffmpeg');
-  static const EventChannel _eventChannel = const EventChannel('flutter_ffmpeg_event');
+  static const MethodChannel _methodChannel =
+      const MethodChannel('flutter_ffmpeg');
+  static const EventChannel _eventChannel =
+      const EventChannel('flutter_ffmpeg_event');
 
   Function(int level, String message) logCallback;
-  Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) statisticsCallback;
+  Function(
+      int time,
+      int size,
+      double bitrate,
+      double speed,
+      int videoFrameNumber,
+      double videoQuality,
+      double videoFps) statisticsCallback;
 
   FlutterFFmpeg() {
     logCallback = null;
@@ -46,8 +55,10 @@ class FlutterFFmpeg {
   void _onEvent(Object event) {
     if (event is Map<dynamic, dynamic>) {
       final Map<String, dynamic> eventMap = event.cast();
-      final Map<dynamic, dynamic> logEvent = eventMap['FlutterFFmpegLogCallback'];
-      final Map<dynamic, dynamic> statisticsEvent = eventMap['FlutterFFmpegStatisticsCallback'];
+      final Map<dynamic, dynamic> logEvent =
+          eventMap['FlutterFFmpegLogCallback'];
+      final Map<dynamic, dynamic> statisticsEvent =
+          eventMap['FlutterFFmpegStatisticsCallback'];
 
       if (logEvent != null) {
         int level = logEvent['level'];
@@ -74,10 +85,12 @@ class FlutterFFmpeg {
           double bitrate = _doublePrecision(statisticsEvent['bitrate'], 2);
           double speed = _doublePrecision(statisticsEvent['speed'], 2);
           int videoFrameNumber = statisticsEvent['videoFrameNumber'];
-          double videoQuality = _doublePrecision(statisticsEvent['videoQuality'], 2);
+          double videoQuality =
+              _doublePrecision(statisticsEvent['videoQuality'], 2);
           double videoFps = _doublePrecision(statisticsEvent['videoFps'], 2);
 
-          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber, videoQuality, videoFps);
+          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber,
+              videoQuality, videoFps);
         }
       }
     }
@@ -98,7 +111,8 @@ class FlutterFFmpeg {
   /// Returns FFmpeg version bundled within the library.
   Future<String> getFFmpegVersion() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getFFmpegVersion');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getFFmpegVersion');
       return result['version'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -109,7 +123,8 @@ class FlutterFFmpeg {
   /// Returns platform name where library is loaded.
   Future<String> getPlatform() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPlatform');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPlatform');
       return result['platform'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -120,7 +135,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg with [commandArguments] provided.
   Future<int> executeWithArguments(List<String> arguments) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('executeWithArguments', {'arguments': arguments});
+      final Map<dynamic, dynamic> result = await _methodChannel
+          .invokeMethod('executeWithArguments', {'arguments': arguments});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -131,7 +147,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg [command] provided. Command is split into arguments using provided [delimiter].
   Future<int> execute(String command, [String delimiter = ' ']) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('execute', {'command': command, 'delimiter': delimiter});
+      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod(
+          'execute', {'command': command, 'delimiter': delimiter});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -175,7 +192,8 @@ class FlutterFFmpeg {
   /// Returns log level.
   Future<int> getLogLevel() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLogLevel');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLogLevel');
       return result['level'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -241,7 +259,10 @@ class FlutterFFmpeg {
   }
 
   /// Sets a callback to redirect FFmpeg statistics. [newCallback] is a new statistics callback function, use null to disable a previously defined callback
-  void enableStatisticsCallback(Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) newCallback) {
+  void enableStatisticsCallback(
+      Function(int time, int size, double bitrate, double speed,
+              int videoFrameNumber, double videoQuality, double videoFps)
+          newCallback) {
     try {
       this.statisticsCallback = newCallback;
     } on PlatformException catch (e) {
@@ -253,7 +274,8 @@ class FlutterFFmpeg {
   /// videoQuality fields
   Future<Map<dynamic, dynamic>> getLastReceivedStatistics() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReceivedStatistics');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReceivedStatistics');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -273,14 +295,16 @@ class FlutterFFmpeg {
   /// Sets and overrides fontconfig configuration directory.
   Future<void> setFontconfigConfigurationPath(String path) async {
     try {
-      await _methodChannel.invokeMethod('setFontconfigConfigurationPath', {'path': path});
+      await _methodChannel
+          .invokeMethod('setFontconfigConfigurationPath', {'path': path});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
     }
   }
 
   /// Registers fonts inside the given [fontDirectory], so they are available to use in FFmpeg filters.
-  Future<void> setFontDirectory(String fontDirectory, Map<String, String> fontNameMap) async {
+  Future<void> setFontDirectory(
+      String fontDirectory, Map<String, String> fontNameMap) async {
     var parameters;
     if (fontNameMap == null) {
       parameters = {'fontDirectory': fontDirectory};
@@ -298,7 +322,8 @@ class FlutterFFmpeg {
   /// Returns FlutterFFmpeg package name.
   Future<String> getPackageName() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPackageName');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPackageName');
       return result['packageName'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -309,7 +334,8 @@ class FlutterFFmpeg {
   /// Returns supported external libraries.
   Future<List<dynamic>> getExternalLibraries() async {
     try {
-      final List<dynamic> result = await _methodChannel.invokeMethod('getExternalLibraries');
+      final List<dynamic> result =
+          await _methodChannel.invokeMethod('getExternalLibraries');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -320,7 +346,8 @@ class FlutterFFmpeg {
   /// Returns return code of last executed command.
   Future<int> getLastReturnCode() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReturnCode');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReturnCode');
       return result['lastRc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -332,7 +359,8 @@ class FlutterFFmpeg {
   /// [disableRedirection()] method also disables this functionality.
   Future<String> getLastCommandOutput() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastCommandOutput');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastCommandOutput');
       return result['lastCommandOutput'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -341,9 +369,11 @@ class FlutterFFmpeg {
   }
 
   /// Returns media information for given [path] using optional [timeout]
-  Future<Map<dynamic, dynamic>> getMediaInformation(String path, [int timeout = 10000]) async {
+  Future<Map<dynamic, dynamic>> getMediaInformation(String path,
+      [int timeout = 10000]) async {
     try {
-      return await _methodChannel.invokeMethod('getMediaInformation', {'path': path, 'timeout': timeout});
+      return await _methodChannel.invokeMethod(
+          'getMediaInformation', {'path': path, 'timeout': timeout});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
       return null;

+ 3 - 3
packages/flutter_ffmpeg_audio_lts/pubspec.yaml

@@ -1,6 +1,6 @@
 name: flutter_ffmpeg
-description: Flutter plugin to run FFmpeg in the mobile platform. Supports iOS and Android.
-version: 0.2.1
+description: Flutter plugin to run FFmpeg on mobile platforms. Supports iOS and Android.
+version: 0.2.2
 author: Taner Sener <tanersener@gmail.com>
 homepage: https://github.com/tanersener/flutter-ffmpeg
 
@@ -12,7 +12,7 @@ dependencies:
     sdk: flutter
 
 dev_dependencies:
-  path_provider: ^0.5.0+1
+  path_provider: ^1.1.0
   path: ^1.6.2
 
 flutter:

+ 2 - 1
packages/flutter_ffmpeg_full-gpl/.gitignore

@@ -3,5 +3,6 @@
 .dart_tool/
 .pub/
 build/
-pubspec.lock
+/pubspec.lock
 /.packages
+/.gradle/

+ 4 - 2
packages/flutter_ffmpeg_full-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java

@@ -39,10 +39,12 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     private final MethodChannel.Result result;
     private final List<String> arguments;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncArgumentsTask(final List<String> arguments, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncArgumentsTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final List<String> arguments, final MethodChannel.Result result) {
         this.arguments = arguments;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -60,7 +62,7 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_full-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java

@@ -36,8 +36,9 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     private String delimiter;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncCommandTask(final String delimiter, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncCommandTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final String delimiter, final MethodChannel.Result result) {
         if (delimiter == null) {
             this.delimiter = " ";
         } else {
@@ -45,6 +46,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
         }
 
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -66,7 +68,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_full-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java

@@ -37,10 +37,12 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     private Integer timeout;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegGetMediaInformationAsyncTask(final Integer timeout, final MethodChannel.Result result) {
+    FlutterFFmpegGetMediaInformationAsyncTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final Integer timeout, final MethodChannel.Result result) {
         this.timeout = timeout;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -64,7 +66,7 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     @Override
     protected void onPostExecute(final MediaInformation mediaInformation) {
-        result.success(FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
     }
 
 }

+ 20 - 17
packages/flutter_ffmpeg_full-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java

@@ -80,6 +80,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
     private EventChannel.EventSink eventSink;
     private final Registrar registrar;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
     /**
      * Registers plugin to registry.
@@ -87,17 +88,19 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
      * @param registrar receiver of plugin registration
      */
     public static void registerWith(final Registrar registrar) {
-        FlutterFFmpegPlugin handler = new FlutterFFmpegPlugin(registrar);
+        FlutterFFmpegPlugin flutterFFmpegPlugin = new FlutterFFmpegPlugin(registrar);
 
         final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_ffmpeg");
-        channel.setMethodCallHandler(handler);
+        channel.setMethodCallHandler(flutterFFmpegPlugin);
 
         final EventChannel eventChannel = new EventChannel(registrar.messenger(), "flutter_ffmpeg_event");
-        eventChannel.setStreamHandler(handler);
+        eventChannel.setStreamHandler(flutterFFmpegPlugin);
     }
 
     private FlutterFFmpegPlugin(Registrar registrar) {
         this.registrar = registrar;
+
+        this.flutterFFmpegResultHandler = new FlutterFFmpegResultHandler();
     }
 
     private Context getActiveContext() {
@@ -115,18 +118,18 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         if (call.method.equals("getPlatform")) {
 
             final String abi = AbiDetect.getAbi();
-            result.success(toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
 
         } else if (call.method.equals("getFFmpegVersion")) {
 
             final String version = FFmpeg.getFFmpegVersion();
-            result.success(toStringMap(KEY_VERSION, version));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_VERSION, version));
 
         } else if (call.method.equals("executeWithArguments")) {
 
             List<String> arguments = call.argument("arguments");
 
-            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(arguments, result);
+            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(flutterFFmpegResultHandler, arguments, result);
             asyncTask.execute("dummy-trigger");
 
         } else if (call.method.equals("execute")) {
@@ -134,7 +137,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
             String command = call.argument("command");
             String delimiter = call.argument("delimiter");
 
-            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(delimiter, result);
+            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(flutterFFmpegResultHandler, delimiter, result);
             asyncTask.execute(command);
 
         } else if (call.method.equals("cancel")) {
@@ -152,7 +155,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getLogLevel")) {
 
             final Level level = Config.getLogLevel();
-            result.success(toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
 
         } else if (call.method.equals("setLogLevel")) {
 
@@ -192,7 +195,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         } else if (call.method.equals("getLastReceivedStatistics")) {
 
-            result.success(toMap(Config.getLastReceivedStatistics()));
+            flutterFFmpegResultHandler.success(result, toMap(Config.getLastReceivedStatistics()));
 
         } else if (call.method.equals("resetStatistics")) {
 
@@ -217,22 +220,22 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getPackageName")) {
 
             final String packageName = Config.getPackageName();
-            result.success(toStringMap(KEY_PACKAGE_NAME, packageName));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PACKAGE_NAME, packageName));
 
         } else if (call.method.equals("getExternalLibraries")) {
 
             final List<String> externalLibraries = Config.getExternalLibraries();
-            result.success(externalLibraries);
+            flutterFFmpegResultHandler.success(result, externalLibraries);
 
         } else if (call.method.equals("getLastReturnCode")) {
 
             int lastReturnCode = FFmpeg.getLastReturnCode();
-            result.success(toIntMap(KEY_LAST_RC, lastReturnCode));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LAST_RC, lastReturnCode));
 
         } else if (call.method.equals("getLastCommandOutput")) {
 
             final String lastCommandOutput = FFmpeg.getLastCommandOutput();
-            result.success(toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
 
         } else if (call.method.equals("getMediaInformation")) {
             final String path = call.argument("path");
@@ -241,11 +244,11 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
                 timeout = 10000;
             }
 
-            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(timeout, result);
+            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(flutterFFmpegResultHandler, timeout, result);
             asyncTask.execute(path);
 
         } else {
-            result.notImplemented();
+            flutterFFmpegResultHandler.notImplemented(result);
         }
     }
 
@@ -268,13 +271,13 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         logWrapperMap.put(EVENT_LOG, logMap);
 
-        eventSink.success(logWrapperMap);
+        flutterFFmpegResultHandler.success(eventSink, logWrapperMap);
     }
 
     protected void emitStatistics(final Statistics statistics) {
         final HashMap<String, Object> statisticsMap = new HashMap<>();
         statisticsMap.put(EVENT_STAT, toMap(statistics));
-        eventSink.success(statisticsMap);
+        flutterFFmpegResultHandler.success(eventSink, statisticsMap);
     }
 
     public static int levelToInt(final Level level) {

+ 77 - 0
packages/flutter_ffmpeg_full-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Taner Sener
+ *
+ * This file is part of FlutterFFmpeg.
+ *
+ * FlutterFFmpeg is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FlutterFFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FlutterFFmpeg.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.arthenica.flutter.ffmpeg;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.MethodChannel;
+
+/**
+ * <h3>Flutter FFmpeg Result Handler</h3>
+ *
+ * @author Taner Sener
+ * @since 0.2.2
+ */
+class FlutterFFmpegResultHandler {
+    private final Handler handler;
+
+    FlutterFFmpegResultHandler() {
+        handler = new Handler(Looper.getMainLooper());
+    }
+
+    void notImplemented(final MethodChannel.Result result) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.notImplemented();
+                }
+            }
+        });
+    }
+
+    void success(final MethodChannel.Result result, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.success(object);
+                }
+            }
+        });
+    }
+
+    void success(final EventChannel.EventSink eventSink, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (eventSink != null) {
+                    eventSink.success(object);
+                }
+            }
+        });
+    }
+
+}

+ 52 - 22
packages/flutter_ffmpeg_full-gpl/lib/flutter_ffmpeg.dart

@@ -22,11 +22,20 @@ import 'dart:async';
 import 'package:flutter/services.dart';
 
 class FlutterFFmpeg {
-  static const MethodChannel _methodChannel = const MethodChannel('flutter_ffmpeg');
-  static const EventChannel _eventChannel = const EventChannel('flutter_ffmpeg_event');
+  static const MethodChannel _methodChannel =
+      const MethodChannel('flutter_ffmpeg');
+  static const EventChannel _eventChannel =
+      const EventChannel('flutter_ffmpeg_event');
 
   Function(int level, String message) logCallback;
-  Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) statisticsCallback;
+  Function(
+      int time,
+      int size,
+      double bitrate,
+      double speed,
+      int videoFrameNumber,
+      double videoQuality,
+      double videoFps) statisticsCallback;
 
   FlutterFFmpeg() {
     logCallback = null;
@@ -46,8 +55,10 @@ class FlutterFFmpeg {
   void _onEvent(Object event) {
     if (event is Map<dynamic, dynamic>) {
       final Map<String, dynamic> eventMap = event.cast();
-      final Map<dynamic, dynamic> logEvent = eventMap['FlutterFFmpegLogCallback'];
-      final Map<dynamic, dynamic> statisticsEvent = eventMap['FlutterFFmpegStatisticsCallback'];
+      final Map<dynamic, dynamic> logEvent =
+          eventMap['FlutterFFmpegLogCallback'];
+      final Map<dynamic, dynamic> statisticsEvent =
+          eventMap['FlutterFFmpegStatisticsCallback'];
 
       if (logEvent != null) {
         int level = logEvent['level'];
@@ -74,10 +85,12 @@ class FlutterFFmpeg {
           double bitrate = _doublePrecision(statisticsEvent['bitrate'], 2);
           double speed = _doublePrecision(statisticsEvent['speed'], 2);
           int videoFrameNumber = statisticsEvent['videoFrameNumber'];
-          double videoQuality = _doublePrecision(statisticsEvent['videoQuality'], 2);
+          double videoQuality =
+              _doublePrecision(statisticsEvent['videoQuality'], 2);
           double videoFps = _doublePrecision(statisticsEvent['videoFps'], 2);
 
-          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber, videoQuality, videoFps);
+          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber,
+              videoQuality, videoFps);
         }
       }
     }
@@ -98,7 +111,8 @@ class FlutterFFmpeg {
   /// Returns FFmpeg version bundled within the library.
   Future<String> getFFmpegVersion() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getFFmpegVersion');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getFFmpegVersion');
       return result['version'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -109,7 +123,8 @@ class FlutterFFmpeg {
   /// Returns platform name where library is loaded.
   Future<String> getPlatform() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPlatform');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPlatform');
       return result['platform'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -120,7 +135,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg with [commandArguments] provided.
   Future<int> executeWithArguments(List<String> arguments) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('executeWithArguments', {'arguments': arguments});
+      final Map<dynamic, dynamic> result = await _methodChannel
+          .invokeMethod('executeWithArguments', {'arguments': arguments});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -131,7 +147,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg [command] provided. Command is split into arguments using provided [delimiter].
   Future<int> execute(String command, [String delimiter = ' ']) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('execute', {'command': command, 'delimiter': delimiter});
+      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod(
+          'execute', {'command': command, 'delimiter': delimiter});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -175,7 +192,8 @@ class FlutterFFmpeg {
   /// Returns log level.
   Future<int> getLogLevel() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLogLevel');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLogLevel');
       return result['level'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -241,7 +259,10 @@ class FlutterFFmpeg {
   }
 
   /// Sets a callback to redirect FFmpeg statistics. [newCallback] is a new statistics callback function, use null to disable a previously defined callback
-  void enableStatisticsCallback(Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) newCallback) {
+  void enableStatisticsCallback(
+      Function(int time, int size, double bitrate, double speed,
+              int videoFrameNumber, double videoQuality, double videoFps)
+          newCallback) {
     try {
       this.statisticsCallback = newCallback;
     } on PlatformException catch (e) {
@@ -253,7 +274,8 @@ class FlutterFFmpeg {
   /// videoQuality fields
   Future<Map<dynamic, dynamic>> getLastReceivedStatistics() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReceivedStatistics');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReceivedStatistics');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -273,14 +295,16 @@ class FlutterFFmpeg {
   /// Sets and overrides fontconfig configuration directory.
   Future<void> setFontconfigConfigurationPath(String path) async {
     try {
-      await _methodChannel.invokeMethod('setFontconfigConfigurationPath', {'path': path});
+      await _methodChannel
+          .invokeMethod('setFontconfigConfigurationPath', {'path': path});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
     }
   }
 
   /// Registers fonts inside the given [fontDirectory], so they are available to use in FFmpeg filters.
-  Future<void> setFontDirectory(String fontDirectory, Map<String, String> fontNameMap) async {
+  Future<void> setFontDirectory(
+      String fontDirectory, Map<String, String> fontNameMap) async {
     var parameters;
     if (fontNameMap == null) {
       parameters = {'fontDirectory': fontDirectory};
@@ -298,7 +322,8 @@ class FlutterFFmpeg {
   /// Returns FlutterFFmpeg package name.
   Future<String> getPackageName() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPackageName');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPackageName');
       return result['packageName'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -309,7 +334,8 @@ class FlutterFFmpeg {
   /// Returns supported external libraries.
   Future<List<dynamic>> getExternalLibraries() async {
     try {
-      final List<dynamic> result = await _methodChannel.invokeMethod('getExternalLibraries');
+      final List<dynamic> result =
+          await _methodChannel.invokeMethod('getExternalLibraries');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -320,7 +346,8 @@ class FlutterFFmpeg {
   /// Returns return code of last executed command.
   Future<int> getLastReturnCode() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReturnCode');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReturnCode');
       return result['lastRc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -332,7 +359,8 @@ class FlutterFFmpeg {
   /// [disableRedirection()] method also disables this functionality.
   Future<String> getLastCommandOutput() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastCommandOutput');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastCommandOutput');
       return result['lastCommandOutput'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -341,9 +369,11 @@ class FlutterFFmpeg {
   }
 
   /// Returns media information for given [path] using optional [timeout]
-  Future<Map<dynamic, dynamic>> getMediaInformation(String path, [int timeout = 10000]) async {
+  Future<Map<dynamic, dynamic>> getMediaInformation(String path,
+      [int timeout = 10000]) async {
     try {
-      return await _methodChannel.invokeMethod('getMediaInformation', {'path': path, 'timeout': timeout});
+      return await _methodChannel.invokeMethod(
+          'getMediaInformation', {'path': path, 'timeout': timeout});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
       return null;

+ 3 - 3
packages/flutter_ffmpeg_full-gpl/pubspec.yaml

@@ -1,6 +1,6 @@
 name: flutter_ffmpeg
-description: Flutter plugin to run FFmpeg in the mobile platform. Supports iOS and Android.
-version: 0.2.1
+description: Flutter plugin to run FFmpeg on mobile platforms. Supports iOS and Android.
+version: 0.2.2
 author: Taner Sener <tanersener@gmail.com>
 homepage: https://github.com/tanersener/flutter-ffmpeg
 
@@ -12,7 +12,7 @@ dependencies:
     sdk: flutter
 
 dev_dependencies:
-  path_provider: ^0.5.0+1
+  path_provider: ^1.1.0
   path: ^1.6.2
 
 flutter:

+ 2 - 1
packages/flutter_ffmpeg_full-gpl_lts/.gitignore

@@ -3,5 +3,6 @@
 .dart_tool/
 .pub/
 build/
-pubspec.lock
+/pubspec.lock
 /.packages
+/.gradle/

+ 4 - 2
packages/flutter_ffmpeg_full-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java

@@ -39,10 +39,12 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     private final MethodChannel.Result result;
     private final List<String> arguments;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncArgumentsTask(final List<String> arguments, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncArgumentsTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final List<String> arguments, final MethodChannel.Result result) {
         this.arguments = arguments;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -60,7 +62,7 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_full-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java

@@ -36,8 +36,9 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     private String delimiter;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncCommandTask(final String delimiter, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncCommandTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final String delimiter, final MethodChannel.Result result) {
         if (delimiter == null) {
             this.delimiter = " ";
         } else {
@@ -45,6 +46,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
         }
 
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -66,7 +68,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_full-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java

@@ -37,10 +37,12 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     private Integer timeout;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegGetMediaInformationAsyncTask(final Integer timeout, final MethodChannel.Result result) {
+    FlutterFFmpegGetMediaInformationAsyncTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final Integer timeout, final MethodChannel.Result result) {
         this.timeout = timeout;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -64,7 +66,7 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     @Override
     protected void onPostExecute(final MediaInformation mediaInformation) {
-        result.success(FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
     }
 
 }

+ 20 - 17
packages/flutter_ffmpeg_full-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java

@@ -80,6 +80,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
     private EventChannel.EventSink eventSink;
     private final Registrar registrar;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
     /**
      * Registers plugin to registry.
@@ -87,17 +88,19 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
      * @param registrar receiver of plugin registration
      */
     public static void registerWith(final Registrar registrar) {
-        FlutterFFmpegPlugin handler = new FlutterFFmpegPlugin(registrar);
+        FlutterFFmpegPlugin flutterFFmpegPlugin = new FlutterFFmpegPlugin(registrar);
 
         final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_ffmpeg");
-        channel.setMethodCallHandler(handler);
+        channel.setMethodCallHandler(flutterFFmpegPlugin);
 
         final EventChannel eventChannel = new EventChannel(registrar.messenger(), "flutter_ffmpeg_event");
-        eventChannel.setStreamHandler(handler);
+        eventChannel.setStreamHandler(flutterFFmpegPlugin);
     }
 
     private FlutterFFmpegPlugin(Registrar registrar) {
         this.registrar = registrar;
+
+        this.flutterFFmpegResultHandler = new FlutterFFmpegResultHandler();
     }
 
     private Context getActiveContext() {
@@ -115,18 +118,18 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         if (call.method.equals("getPlatform")) {
 
             final String abi = AbiDetect.getAbi();
-            result.success(toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
 
         } else if (call.method.equals("getFFmpegVersion")) {
 
             final String version = FFmpeg.getFFmpegVersion();
-            result.success(toStringMap(KEY_VERSION, version));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_VERSION, version));
 
         } else if (call.method.equals("executeWithArguments")) {
 
             List<String> arguments = call.argument("arguments");
 
-            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(arguments, result);
+            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(flutterFFmpegResultHandler, arguments, result);
             asyncTask.execute("dummy-trigger");
 
         } else if (call.method.equals("execute")) {
@@ -134,7 +137,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
             String command = call.argument("command");
             String delimiter = call.argument("delimiter");
 
-            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(delimiter, result);
+            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(flutterFFmpegResultHandler, delimiter, result);
             asyncTask.execute(command);
 
         } else if (call.method.equals("cancel")) {
@@ -152,7 +155,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getLogLevel")) {
 
             final Level level = Config.getLogLevel();
-            result.success(toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
 
         } else if (call.method.equals("setLogLevel")) {
 
@@ -192,7 +195,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         } else if (call.method.equals("getLastReceivedStatistics")) {
 
-            result.success(toMap(Config.getLastReceivedStatistics()));
+            flutterFFmpegResultHandler.success(result, toMap(Config.getLastReceivedStatistics()));
 
         } else if (call.method.equals("resetStatistics")) {
 
@@ -217,22 +220,22 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getPackageName")) {
 
             final String packageName = Config.getPackageName();
-            result.success(toStringMap(KEY_PACKAGE_NAME, packageName));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PACKAGE_NAME, packageName));
 
         } else if (call.method.equals("getExternalLibraries")) {
 
             final List<String> externalLibraries = Config.getExternalLibraries();
-            result.success(externalLibraries);
+            flutterFFmpegResultHandler.success(result, externalLibraries);
 
         } else if (call.method.equals("getLastReturnCode")) {
 
             int lastReturnCode = FFmpeg.getLastReturnCode();
-            result.success(toIntMap(KEY_LAST_RC, lastReturnCode));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LAST_RC, lastReturnCode));
 
         } else if (call.method.equals("getLastCommandOutput")) {
 
             final String lastCommandOutput = FFmpeg.getLastCommandOutput();
-            result.success(toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
 
         } else if (call.method.equals("getMediaInformation")) {
             final String path = call.argument("path");
@@ -241,11 +244,11 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
                 timeout = 10000;
             }
 
-            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(timeout, result);
+            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(flutterFFmpegResultHandler, timeout, result);
             asyncTask.execute(path);
 
         } else {
-            result.notImplemented();
+            flutterFFmpegResultHandler.notImplemented(result);
         }
     }
 
@@ -268,13 +271,13 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         logWrapperMap.put(EVENT_LOG, logMap);
 
-        eventSink.success(logWrapperMap);
+        flutterFFmpegResultHandler.success(eventSink, logWrapperMap);
     }
 
     protected void emitStatistics(final Statistics statistics) {
         final HashMap<String, Object> statisticsMap = new HashMap<>();
         statisticsMap.put(EVENT_STAT, toMap(statistics));
-        eventSink.success(statisticsMap);
+        flutterFFmpegResultHandler.success(eventSink, statisticsMap);
     }
 
     public static int levelToInt(final Level level) {

+ 77 - 0
packages/flutter_ffmpeg_full-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Taner Sener
+ *
+ * This file is part of FlutterFFmpeg.
+ *
+ * FlutterFFmpeg is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FlutterFFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FlutterFFmpeg.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.arthenica.flutter.ffmpeg;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.MethodChannel;
+
+/**
+ * <h3>Flutter FFmpeg Result Handler</h3>
+ *
+ * @author Taner Sener
+ * @since 0.2.2
+ */
+class FlutterFFmpegResultHandler {
+    private final Handler handler;
+
+    FlutterFFmpegResultHandler() {
+        handler = new Handler(Looper.getMainLooper());
+    }
+
+    void notImplemented(final MethodChannel.Result result) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.notImplemented();
+                }
+            }
+        });
+    }
+
+    void success(final MethodChannel.Result result, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.success(object);
+                }
+            }
+        });
+    }
+
+    void success(final EventChannel.EventSink eventSink, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (eventSink != null) {
+                    eventSink.success(object);
+                }
+            }
+        });
+    }
+
+}

+ 52 - 22
packages/flutter_ffmpeg_full-gpl_lts/lib/flutter_ffmpeg.dart

@@ -22,11 +22,20 @@ import 'dart:async';
 import 'package:flutter/services.dart';
 
 class FlutterFFmpeg {
-  static const MethodChannel _methodChannel = const MethodChannel('flutter_ffmpeg');
-  static const EventChannel _eventChannel = const EventChannel('flutter_ffmpeg_event');
+  static const MethodChannel _methodChannel =
+      const MethodChannel('flutter_ffmpeg');
+  static const EventChannel _eventChannel =
+      const EventChannel('flutter_ffmpeg_event');
 
   Function(int level, String message) logCallback;
-  Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) statisticsCallback;
+  Function(
+      int time,
+      int size,
+      double bitrate,
+      double speed,
+      int videoFrameNumber,
+      double videoQuality,
+      double videoFps) statisticsCallback;
 
   FlutterFFmpeg() {
     logCallback = null;
@@ -46,8 +55,10 @@ class FlutterFFmpeg {
   void _onEvent(Object event) {
     if (event is Map<dynamic, dynamic>) {
       final Map<String, dynamic> eventMap = event.cast();
-      final Map<dynamic, dynamic> logEvent = eventMap['FlutterFFmpegLogCallback'];
-      final Map<dynamic, dynamic> statisticsEvent = eventMap['FlutterFFmpegStatisticsCallback'];
+      final Map<dynamic, dynamic> logEvent =
+          eventMap['FlutterFFmpegLogCallback'];
+      final Map<dynamic, dynamic> statisticsEvent =
+          eventMap['FlutterFFmpegStatisticsCallback'];
 
       if (logEvent != null) {
         int level = logEvent['level'];
@@ -74,10 +85,12 @@ class FlutterFFmpeg {
           double bitrate = _doublePrecision(statisticsEvent['bitrate'], 2);
           double speed = _doublePrecision(statisticsEvent['speed'], 2);
           int videoFrameNumber = statisticsEvent['videoFrameNumber'];
-          double videoQuality = _doublePrecision(statisticsEvent['videoQuality'], 2);
+          double videoQuality =
+              _doublePrecision(statisticsEvent['videoQuality'], 2);
           double videoFps = _doublePrecision(statisticsEvent['videoFps'], 2);
 
-          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber, videoQuality, videoFps);
+          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber,
+              videoQuality, videoFps);
         }
       }
     }
@@ -98,7 +111,8 @@ class FlutterFFmpeg {
   /// Returns FFmpeg version bundled within the library.
   Future<String> getFFmpegVersion() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getFFmpegVersion');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getFFmpegVersion');
       return result['version'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -109,7 +123,8 @@ class FlutterFFmpeg {
   /// Returns platform name where library is loaded.
   Future<String> getPlatform() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPlatform');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPlatform');
       return result['platform'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -120,7 +135,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg with [commandArguments] provided.
   Future<int> executeWithArguments(List<String> arguments) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('executeWithArguments', {'arguments': arguments});
+      final Map<dynamic, dynamic> result = await _methodChannel
+          .invokeMethod('executeWithArguments', {'arguments': arguments});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -131,7 +147,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg [command] provided. Command is split into arguments using provided [delimiter].
   Future<int> execute(String command, [String delimiter = ' ']) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('execute', {'command': command, 'delimiter': delimiter});
+      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod(
+          'execute', {'command': command, 'delimiter': delimiter});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -175,7 +192,8 @@ class FlutterFFmpeg {
   /// Returns log level.
   Future<int> getLogLevel() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLogLevel');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLogLevel');
       return result['level'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -241,7 +259,10 @@ class FlutterFFmpeg {
   }
 
   /// Sets a callback to redirect FFmpeg statistics. [newCallback] is a new statistics callback function, use null to disable a previously defined callback
-  void enableStatisticsCallback(Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) newCallback) {
+  void enableStatisticsCallback(
+      Function(int time, int size, double bitrate, double speed,
+              int videoFrameNumber, double videoQuality, double videoFps)
+          newCallback) {
     try {
       this.statisticsCallback = newCallback;
     } on PlatformException catch (e) {
@@ -253,7 +274,8 @@ class FlutterFFmpeg {
   /// videoQuality fields
   Future<Map<dynamic, dynamic>> getLastReceivedStatistics() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReceivedStatistics');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReceivedStatistics');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -273,14 +295,16 @@ class FlutterFFmpeg {
   /// Sets and overrides fontconfig configuration directory.
   Future<void> setFontconfigConfigurationPath(String path) async {
     try {
-      await _methodChannel.invokeMethod('setFontconfigConfigurationPath', {'path': path});
+      await _methodChannel
+          .invokeMethod('setFontconfigConfigurationPath', {'path': path});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
     }
   }
 
   /// Registers fonts inside the given [fontDirectory], so they are available to use in FFmpeg filters.
-  Future<void> setFontDirectory(String fontDirectory, Map<String, String> fontNameMap) async {
+  Future<void> setFontDirectory(
+      String fontDirectory, Map<String, String> fontNameMap) async {
     var parameters;
     if (fontNameMap == null) {
       parameters = {'fontDirectory': fontDirectory};
@@ -298,7 +322,8 @@ class FlutterFFmpeg {
   /// Returns FlutterFFmpeg package name.
   Future<String> getPackageName() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPackageName');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPackageName');
       return result['packageName'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -309,7 +334,8 @@ class FlutterFFmpeg {
   /// Returns supported external libraries.
   Future<List<dynamic>> getExternalLibraries() async {
     try {
-      final List<dynamic> result = await _methodChannel.invokeMethod('getExternalLibraries');
+      final List<dynamic> result =
+          await _methodChannel.invokeMethod('getExternalLibraries');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -320,7 +346,8 @@ class FlutterFFmpeg {
   /// Returns return code of last executed command.
   Future<int> getLastReturnCode() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReturnCode');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReturnCode');
       return result['lastRc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -332,7 +359,8 @@ class FlutterFFmpeg {
   /// [disableRedirection()] method also disables this functionality.
   Future<String> getLastCommandOutput() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastCommandOutput');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastCommandOutput');
       return result['lastCommandOutput'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -341,9 +369,11 @@ class FlutterFFmpeg {
   }
 
   /// Returns media information for given [path] using optional [timeout]
-  Future<Map<dynamic, dynamic>> getMediaInformation(String path, [int timeout = 10000]) async {
+  Future<Map<dynamic, dynamic>> getMediaInformation(String path,
+      [int timeout = 10000]) async {
     try {
-      return await _methodChannel.invokeMethod('getMediaInformation', {'path': path, 'timeout': timeout});
+      return await _methodChannel.invokeMethod(
+          'getMediaInformation', {'path': path, 'timeout': timeout});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
       return null;

+ 3 - 3
packages/flutter_ffmpeg_full-gpl_lts/pubspec.yaml

@@ -1,6 +1,6 @@
 name: flutter_ffmpeg
-description: Flutter plugin to run FFmpeg in the mobile platform. Supports iOS and Android.
-version: 0.2.1
+description: Flutter plugin to run FFmpeg on mobile platforms. Supports iOS and Android.
+version: 0.2.2
 author: Taner Sener <tanersener@gmail.com>
 homepage: https://github.com/tanersener/flutter-ffmpeg
 
@@ -12,7 +12,7 @@ dependencies:
     sdk: flutter
 
 dev_dependencies:
-  path_provider: ^0.5.0+1
+  path_provider: ^1.1.0
   path: ^1.6.2
 
 flutter:

+ 2 - 1
packages/flutter_ffmpeg_full/.gitignore

@@ -3,5 +3,6 @@
 .dart_tool/
 .pub/
 build/
-pubspec.lock
+/pubspec.lock
 /.packages
+/.gradle/

+ 4 - 2
packages/flutter_ffmpeg_full/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java

@@ -39,10 +39,12 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     private final MethodChannel.Result result;
     private final List<String> arguments;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncArgumentsTask(final List<String> arguments, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncArgumentsTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final List<String> arguments, final MethodChannel.Result result) {
         this.arguments = arguments;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -60,7 +62,7 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_full/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java

@@ -36,8 +36,9 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     private String delimiter;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncCommandTask(final String delimiter, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncCommandTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final String delimiter, final MethodChannel.Result result) {
         if (delimiter == null) {
             this.delimiter = " ";
         } else {
@@ -45,6 +46,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
         }
 
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -66,7 +68,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_full/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java

@@ -37,10 +37,12 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     private Integer timeout;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegGetMediaInformationAsyncTask(final Integer timeout, final MethodChannel.Result result) {
+    FlutterFFmpegGetMediaInformationAsyncTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final Integer timeout, final MethodChannel.Result result) {
         this.timeout = timeout;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -64,7 +66,7 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     @Override
     protected void onPostExecute(final MediaInformation mediaInformation) {
-        result.success(FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
     }
 
 }

+ 20 - 17
packages/flutter_ffmpeg_full/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java

@@ -80,6 +80,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
     private EventChannel.EventSink eventSink;
     private final Registrar registrar;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
     /**
      * Registers plugin to registry.
@@ -87,17 +88,19 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
      * @param registrar receiver of plugin registration
      */
     public static void registerWith(final Registrar registrar) {
-        FlutterFFmpegPlugin handler = new FlutterFFmpegPlugin(registrar);
+        FlutterFFmpegPlugin flutterFFmpegPlugin = new FlutterFFmpegPlugin(registrar);
 
         final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_ffmpeg");
-        channel.setMethodCallHandler(handler);
+        channel.setMethodCallHandler(flutterFFmpegPlugin);
 
         final EventChannel eventChannel = new EventChannel(registrar.messenger(), "flutter_ffmpeg_event");
-        eventChannel.setStreamHandler(handler);
+        eventChannel.setStreamHandler(flutterFFmpegPlugin);
     }
 
     private FlutterFFmpegPlugin(Registrar registrar) {
         this.registrar = registrar;
+
+        this.flutterFFmpegResultHandler = new FlutterFFmpegResultHandler();
     }
 
     private Context getActiveContext() {
@@ -115,18 +118,18 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         if (call.method.equals("getPlatform")) {
 
             final String abi = AbiDetect.getAbi();
-            result.success(toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
 
         } else if (call.method.equals("getFFmpegVersion")) {
 
             final String version = FFmpeg.getFFmpegVersion();
-            result.success(toStringMap(KEY_VERSION, version));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_VERSION, version));
 
         } else if (call.method.equals("executeWithArguments")) {
 
             List<String> arguments = call.argument("arguments");
 
-            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(arguments, result);
+            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(flutterFFmpegResultHandler, arguments, result);
             asyncTask.execute("dummy-trigger");
 
         } else if (call.method.equals("execute")) {
@@ -134,7 +137,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
             String command = call.argument("command");
             String delimiter = call.argument("delimiter");
 
-            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(delimiter, result);
+            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(flutterFFmpegResultHandler, delimiter, result);
             asyncTask.execute(command);
 
         } else if (call.method.equals("cancel")) {
@@ -152,7 +155,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getLogLevel")) {
 
             final Level level = Config.getLogLevel();
-            result.success(toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
 
         } else if (call.method.equals("setLogLevel")) {
 
@@ -192,7 +195,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         } else if (call.method.equals("getLastReceivedStatistics")) {
 
-            result.success(toMap(Config.getLastReceivedStatistics()));
+            flutterFFmpegResultHandler.success(result, toMap(Config.getLastReceivedStatistics()));
 
         } else if (call.method.equals("resetStatistics")) {
 
@@ -217,22 +220,22 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getPackageName")) {
 
             final String packageName = Config.getPackageName();
-            result.success(toStringMap(KEY_PACKAGE_NAME, packageName));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PACKAGE_NAME, packageName));
 
         } else if (call.method.equals("getExternalLibraries")) {
 
             final List<String> externalLibraries = Config.getExternalLibraries();
-            result.success(externalLibraries);
+            flutterFFmpegResultHandler.success(result, externalLibraries);
 
         } else if (call.method.equals("getLastReturnCode")) {
 
             int lastReturnCode = FFmpeg.getLastReturnCode();
-            result.success(toIntMap(KEY_LAST_RC, lastReturnCode));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LAST_RC, lastReturnCode));
 
         } else if (call.method.equals("getLastCommandOutput")) {
 
             final String lastCommandOutput = FFmpeg.getLastCommandOutput();
-            result.success(toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
 
         } else if (call.method.equals("getMediaInformation")) {
             final String path = call.argument("path");
@@ -241,11 +244,11 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
                 timeout = 10000;
             }
 
-            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(timeout, result);
+            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(flutterFFmpegResultHandler, timeout, result);
             asyncTask.execute(path);
 
         } else {
-            result.notImplemented();
+            flutterFFmpegResultHandler.notImplemented(result);
         }
     }
 
@@ -268,13 +271,13 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         logWrapperMap.put(EVENT_LOG, logMap);
 
-        eventSink.success(logWrapperMap);
+        flutterFFmpegResultHandler.success(eventSink, logWrapperMap);
     }
 
     protected void emitStatistics(final Statistics statistics) {
         final HashMap<String, Object> statisticsMap = new HashMap<>();
         statisticsMap.put(EVENT_STAT, toMap(statistics));
-        eventSink.success(statisticsMap);
+        flutterFFmpegResultHandler.success(eventSink, statisticsMap);
     }
 
     public static int levelToInt(final Level level) {

+ 77 - 0
packages/flutter_ffmpeg_full/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Taner Sener
+ *
+ * This file is part of FlutterFFmpeg.
+ *
+ * FlutterFFmpeg is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FlutterFFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FlutterFFmpeg.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.arthenica.flutter.ffmpeg;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.MethodChannel;
+
+/**
+ * <h3>Flutter FFmpeg Result Handler</h3>
+ *
+ * @author Taner Sener
+ * @since 0.2.2
+ */
+class FlutterFFmpegResultHandler {
+    private final Handler handler;
+
+    FlutterFFmpegResultHandler() {
+        handler = new Handler(Looper.getMainLooper());
+    }
+
+    void notImplemented(final MethodChannel.Result result) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.notImplemented();
+                }
+            }
+        });
+    }
+
+    void success(final MethodChannel.Result result, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.success(object);
+                }
+            }
+        });
+    }
+
+    void success(final EventChannel.EventSink eventSink, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (eventSink != null) {
+                    eventSink.success(object);
+                }
+            }
+        });
+    }
+
+}

+ 52 - 22
packages/flutter_ffmpeg_full/lib/flutter_ffmpeg.dart

@@ -22,11 +22,20 @@ import 'dart:async';
 import 'package:flutter/services.dart';
 
 class FlutterFFmpeg {
-  static const MethodChannel _methodChannel = const MethodChannel('flutter_ffmpeg');
-  static const EventChannel _eventChannel = const EventChannel('flutter_ffmpeg_event');
+  static const MethodChannel _methodChannel =
+      const MethodChannel('flutter_ffmpeg');
+  static const EventChannel _eventChannel =
+      const EventChannel('flutter_ffmpeg_event');
 
   Function(int level, String message) logCallback;
-  Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) statisticsCallback;
+  Function(
+      int time,
+      int size,
+      double bitrate,
+      double speed,
+      int videoFrameNumber,
+      double videoQuality,
+      double videoFps) statisticsCallback;
 
   FlutterFFmpeg() {
     logCallback = null;
@@ -46,8 +55,10 @@ class FlutterFFmpeg {
   void _onEvent(Object event) {
     if (event is Map<dynamic, dynamic>) {
       final Map<String, dynamic> eventMap = event.cast();
-      final Map<dynamic, dynamic> logEvent = eventMap['FlutterFFmpegLogCallback'];
-      final Map<dynamic, dynamic> statisticsEvent = eventMap['FlutterFFmpegStatisticsCallback'];
+      final Map<dynamic, dynamic> logEvent =
+          eventMap['FlutterFFmpegLogCallback'];
+      final Map<dynamic, dynamic> statisticsEvent =
+          eventMap['FlutterFFmpegStatisticsCallback'];
 
       if (logEvent != null) {
         int level = logEvent['level'];
@@ -74,10 +85,12 @@ class FlutterFFmpeg {
           double bitrate = _doublePrecision(statisticsEvent['bitrate'], 2);
           double speed = _doublePrecision(statisticsEvent['speed'], 2);
           int videoFrameNumber = statisticsEvent['videoFrameNumber'];
-          double videoQuality = _doublePrecision(statisticsEvent['videoQuality'], 2);
+          double videoQuality =
+              _doublePrecision(statisticsEvent['videoQuality'], 2);
           double videoFps = _doublePrecision(statisticsEvent['videoFps'], 2);
 
-          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber, videoQuality, videoFps);
+          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber,
+              videoQuality, videoFps);
         }
       }
     }
@@ -98,7 +111,8 @@ class FlutterFFmpeg {
   /// Returns FFmpeg version bundled within the library.
   Future<String> getFFmpegVersion() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getFFmpegVersion');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getFFmpegVersion');
       return result['version'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -109,7 +123,8 @@ class FlutterFFmpeg {
   /// Returns platform name where library is loaded.
   Future<String> getPlatform() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPlatform');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPlatform');
       return result['platform'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -120,7 +135,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg with [commandArguments] provided.
   Future<int> executeWithArguments(List<String> arguments) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('executeWithArguments', {'arguments': arguments});
+      final Map<dynamic, dynamic> result = await _methodChannel
+          .invokeMethod('executeWithArguments', {'arguments': arguments});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -131,7 +147,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg [command] provided. Command is split into arguments using provided [delimiter].
   Future<int> execute(String command, [String delimiter = ' ']) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('execute', {'command': command, 'delimiter': delimiter});
+      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod(
+          'execute', {'command': command, 'delimiter': delimiter});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -175,7 +192,8 @@ class FlutterFFmpeg {
   /// Returns log level.
   Future<int> getLogLevel() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLogLevel');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLogLevel');
       return result['level'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -241,7 +259,10 @@ class FlutterFFmpeg {
   }
 
   /// Sets a callback to redirect FFmpeg statistics. [newCallback] is a new statistics callback function, use null to disable a previously defined callback
-  void enableStatisticsCallback(Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) newCallback) {
+  void enableStatisticsCallback(
+      Function(int time, int size, double bitrate, double speed,
+              int videoFrameNumber, double videoQuality, double videoFps)
+          newCallback) {
     try {
       this.statisticsCallback = newCallback;
     } on PlatformException catch (e) {
@@ -253,7 +274,8 @@ class FlutterFFmpeg {
   /// videoQuality fields
   Future<Map<dynamic, dynamic>> getLastReceivedStatistics() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReceivedStatistics');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReceivedStatistics');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -273,14 +295,16 @@ class FlutterFFmpeg {
   /// Sets and overrides fontconfig configuration directory.
   Future<void> setFontconfigConfigurationPath(String path) async {
     try {
-      await _methodChannel.invokeMethod('setFontconfigConfigurationPath', {'path': path});
+      await _methodChannel
+          .invokeMethod('setFontconfigConfigurationPath', {'path': path});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
     }
   }
 
   /// Registers fonts inside the given [fontDirectory], so they are available to use in FFmpeg filters.
-  Future<void> setFontDirectory(String fontDirectory, Map<String, String> fontNameMap) async {
+  Future<void> setFontDirectory(
+      String fontDirectory, Map<String, String> fontNameMap) async {
     var parameters;
     if (fontNameMap == null) {
       parameters = {'fontDirectory': fontDirectory};
@@ -298,7 +322,8 @@ class FlutterFFmpeg {
   /// Returns FlutterFFmpeg package name.
   Future<String> getPackageName() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPackageName');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPackageName');
       return result['packageName'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -309,7 +334,8 @@ class FlutterFFmpeg {
   /// Returns supported external libraries.
   Future<List<dynamic>> getExternalLibraries() async {
     try {
-      final List<dynamic> result = await _methodChannel.invokeMethod('getExternalLibraries');
+      final List<dynamic> result =
+          await _methodChannel.invokeMethod('getExternalLibraries');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -320,7 +346,8 @@ class FlutterFFmpeg {
   /// Returns return code of last executed command.
   Future<int> getLastReturnCode() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReturnCode');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReturnCode');
       return result['lastRc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -332,7 +359,8 @@ class FlutterFFmpeg {
   /// [disableRedirection()] method also disables this functionality.
   Future<String> getLastCommandOutput() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastCommandOutput');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastCommandOutput');
       return result['lastCommandOutput'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -341,9 +369,11 @@ class FlutterFFmpeg {
   }
 
   /// Returns media information for given [path] using optional [timeout]
-  Future<Map<dynamic, dynamic>> getMediaInformation(String path, [int timeout = 10000]) async {
+  Future<Map<dynamic, dynamic>> getMediaInformation(String path,
+      [int timeout = 10000]) async {
     try {
-      return await _methodChannel.invokeMethod('getMediaInformation', {'path': path, 'timeout': timeout});
+      return await _methodChannel.invokeMethod(
+          'getMediaInformation', {'path': path, 'timeout': timeout});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
       return null;

+ 3 - 3
packages/flutter_ffmpeg_full/pubspec.yaml

@@ -1,6 +1,6 @@
 name: flutter_ffmpeg
-description: Flutter plugin to run FFmpeg in the mobile platform. Supports iOS and Android.
-version: 0.2.1
+description: Flutter plugin to run FFmpeg on mobile platforms. Supports iOS and Android.
+version: 0.2.2
 author: Taner Sener <tanersener@gmail.com>
 homepage: https://github.com/tanersener/flutter-ffmpeg
 
@@ -12,7 +12,7 @@ dependencies:
     sdk: flutter
 
 dev_dependencies:
-  path_provider: ^0.5.0+1
+  path_provider: ^1.1.0
   path: ^1.6.2
 
 flutter:

+ 2 - 1
packages/flutter_ffmpeg_full_lts/.gitignore

@@ -3,5 +3,6 @@
 .dart_tool/
 .pub/
 build/
-pubspec.lock
+/pubspec.lock
 /.packages
+/.gradle/

+ 4 - 2
packages/flutter_ffmpeg_full_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java

@@ -39,10 +39,12 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     private final MethodChannel.Result result;
     private final List<String> arguments;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncArgumentsTask(final List<String> arguments, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncArgumentsTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final List<String> arguments, final MethodChannel.Result result) {
         this.arguments = arguments;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -60,7 +62,7 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_full_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java

@@ -36,8 +36,9 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     private String delimiter;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncCommandTask(final String delimiter, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncCommandTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final String delimiter, final MethodChannel.Result result) {
         if (delimiter == null) {
             this.delimiter = " ";
         } else {
@@ -45,6 +46,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
         }
 
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -66,7 +68,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_full_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java

@@ -37,10 +37,12 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     private Integer timeout;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegGetMediaInformationAsyncTask(final Integer timeout, final MethodChannel.Result result) {
+    FlutterFFmpegGetMediaInformationAsyncTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final Integer timeout, final MethodChannel.Result result) {
         this.timeout = timeout;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -64,7 +66,7 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     @Override
     protected void onPostExecute(final MediaInformation mediaInformation) {
-        result.success(FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
     }
 
 }

+ 20 - 17
packages/flutter_ffmpeg_full_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java

@@ -80,6 +80,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
     private EventChannel.EventSink eventSink;
     private final Registrar registrar;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
     /**
      * Registers plugin to registry.
@@ -87,17 +88,19 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
      * @param registrar receiver of plugin registration
      */
     public static void registerWith(final Registrar registrar) {
-        FlutterFFmpegPlugin handler = new FlutterFFmpegPlugin(registrar);
+        FlutterFFmpegPlugin flutterFFmpegPlugin = new FlutterFFmpegPlugin(registrar);
 
         final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_ffmpeg");
-        channel.setMethodCallHandler(handler);
+        channel.setMethodCallHandler(flutterFFmpegPlugin);
 
         final EventChannel eventChannel = new EventChannel(registrar.messenger(), "flutter_ffmpeg_event");
-        eventChannel.setStreamHandler(handler);
+        eventChannel.setStreamHandler(flutterFFmpegPlugin);
     }
 
     private FlutterFFmpegPlugin(Registrar registrar) {
         this.registrar = registrar;
+
+        this.flutterFFmpegResultHandler = new FlutterFFmpegResultHandler();
     }
 
     private Context getActiveContext() {
@@ -115,18 +118,18 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         if (call.method.equals("getPlatform")) {
 
             final String abi = AbiDetect.getAbi();
-            result.success(toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
 
         } else if (call.method.equals("getFFmpegVersion")) {
 
             final String version = FFmpeg.getFFmpegVersion();
-            result.success(toStringMap(KEY_VERSION, version));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_VERSION, version));
 
         } else if (call.method.equals("executeWithArguments")) {
 
             List<String> arguments = call.argument("arguments");
 
-            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(arguments, result);
+            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(flutterFFmpegResultHandler, arguments, result);
             asyncTask.execute("dummy-trigger");
 
         } else if (call.method.equals("execute")) {
@@ -134,7 +137,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
             String command = call.argument("command");
             String delimiter = call.argument("delimiter");
 
-            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(delimiter, result);
+            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(flutterFFmpegResultHandler, delimiter, result);
             asyncTask.execute(command);
 
         } else if (call.method.equals("cancel")) {
@@ -152,7 +155,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getLogLevel")) {
 
             final Level level = Config.getLogLevel();
-            result.success(toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
 
         } else if (call.method.equals("setLogLevel")) {
 
@@ -192,7 +195,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         } else if (call.method.equals("getLastReceivedStatistics")) {
 
-            result.success(toMap(Config.getLastReceivedStatistics()));
+            flutterFFmpegResultHandler.success(result, toMap(Config.getLastReceivedStatistics()));
 
         } else if (call.method.equals("resetStatistics")) {
 
@@ -217,22 +220,22 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getPackageName")) {
 
             final String packageName = Config.getPackageName();
-            result.success(toStringMap(KEY_PACKAGE_NAME, packageName));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PACKAGE_NAME, packageName));
 
         } else if (call.method.equals("getExternalLibraries")) {
 
             final List<String> externalLibraries = Config.getExternalLibraries();
-            result.success(externalLibraries);
+            flutterFFmpegResultHandler.success(result, externalLibraries);
 
         } else if (call.method.equals("getLastReturnCode")) {
 
             int lastReturnCode = FFmpeg.getLastReturnCode();
-            result.success(toIntMap(KEY_LAST_RC, lastReturnCode));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LAST_RC, lastReturnCode));
 
         } else if (call.method.equals("getLastCommandOutput")) {
 
             final String lastCommandOutput = FFmpeg.getLastCommandOutput();
-            result.success(toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
 
         } else if (call.method.equals("getMediaInformation")) {
             final String path = call.argument("path");
@@ -241,11 +244,11 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
                 timeout = 10000;
             }
 
-            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(timeout, result);
+            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(flutterFFmpegResultHandler, timeout, result);
             asyncTask.execute(path);
 
         } else {
-            result.notImplemented();
+            flutterFFmpegResultHandler.notImplemented(result);
         }
     }
 
@@ -268,13 +271,13 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         logWrapperMap.put(EVENT_LOG, logMap);
 
-        eventSink.success(logWrapperMap);
+        flutterFFmpegResultHandler.success(eventSink, logWrapperMap);
     }
 
     protected void emitStatistics(final Statistics statistics) {
         final HashMap<String, Object> statisticsMap = new HashMap<>();
         statisticsMap.put(EVENT_STAT, toMap(statistics));
-        eventSink.success(statisticsMap);
+        flutterFFmpegResultHandler.success(eventSink, statisticsMap);
     }
 
     public static int levelToInt(final Level level) {

+ 77 - 0
packages/flutter_ffmpeg_full_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Taner Sener
+ *
+ * This file is part of FlutterFFmpeg.
+ *
+ * FlutterFFmpeg is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FlutterFFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FlutterFFmpeg.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.arthenica.flutter.ffmpeg;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.MethodChannel;
+
+/**
+ * <h3>Flutter FFmpeg Result Handler</h3>
+ *
+ * @author Taner Sener
+ * @since 0.2.2
+ */
+class FlutterFFmpegResultHandler {
+    private final Handler handler;
+
+    FlutterFFmpegResultHandler() {
+        handler = new Handler(Looper.getMainLooper());
+    }
+
+    void notImplemented(final MethodChannel.Result result) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.notImplemented();
+                }
+            }
+        });
+    }
+
+    void success(final MethodChannel.Result result, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.success(object);
+                }
+            }
+        });
+    }
+
+    void success(final EventChannel.EventSink eventSink, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (eventSink != null) {
+                    eventSink.success(object);
+                }
+            }
+        });
+    }
+
+}

+ 52 - 22
packages/flutter_ffmpeg_full_lts/lib/flutter_ffmpeg.dart

@@ -22,11 +22,20 @@ import 'dart:async';
 import 'package:flutter/services.dart';
 
 class FlutterFFmpeg {
-  static const MethodChannel _methodChannel = const MethodChannel('flutter_ffmpeg');
-  static const EventChannel _eventChannel = const EventChannel('flutter_ffmpeg_event');
+  static const MethodChannel _methodChannel =
+      const MethodChannel('flutter_ffmpeg');
+  static const EventChannel _eventChannel =
+      const EventChannel('flutter_ffmpeg_event');
 
   Function(int level, String message) logCallback;
-  Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) statisticsCallback;
+  Function(
+      int time,
+      int size,
+      double bitrate,
+      double speed,
+      int videoFrameNumber,
+      double videoQuality,
+      double videoFps) statisticsCallback;
 
   FlutterFFmpeg() {
     logCallback = null;
@@ -46,8 +55,10 @@ class FlutterFFmpeg {
   void _onEvent(Object event) {
     if (event is Map<dynamic, dynamic>) {
       final Map<String, dynamic> eventMap = event.cast();
-      final Map<dynamic, dynamic> logEvent = eventMap['FlutterFFmpegLogCallback'];
-      final Map<dynamic, dynamic> statisticsEvent = eventMap['FlutterFFmpegStatisticsCallback'];
+      final Map<dynamic, dynamic> logEvent =
+          eventMap['FlutterFFmpegLogCallback'];
+      final Map<dynamic, dynamic> statisticsEvent =
+          eventMap['FlutterFFmpegStatisticsCallback'];
 
       if (logEvent != null) {
         int level = logEvent['level'];
@@ -74,10 +85,12 @@ class FlutterFFmpeg {
           double bitrate = _doublePrecision(statisticsEvent['bitrate'], 2);
           double speed = _doublePrecision(statisticsEvent['speed'], 2);
           int videoFrameNumber = statisticsEvent['videoFrameNumber'];
-          double videoQuality = _doublePrecision(statisticsEvent['videoQuality'], 2);
+          double videoQuality =
+              _doublePrecision(statisticsEvent['videoQuality'], 2);
           double videoFps = _doublePrecision(statisticsEvent['videoFps'], 2);
 
-          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber, videoQuality, videoFps);
+          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber,
+              videoQuality, videoFps);
         }
       }
     }
@@ -98,7 +111,8 @@ class FlutterFFmpeg {
   /// Returns FFmpeg version bundled within the library.
   Future<String> getFFmpegVersion() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getFFmpegVersion');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getFFmpegVersion');
       return result['version'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -109,7 +123,8 @@ class FlutterFFmpeg {
   /// Returns platform name where library is loaded.
   Future<String> getPlatform() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPlatform');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPlatform');
       return result['platform'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -120,7 +135,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg with [commandArguments] provided.
   Future<int> executeWithArguments(List<String> arguments) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('executeWithArguments', {'arguments': arguments});
+      final Map<dynamic, dynamic> result = await _methodChannel
+          .invokeMethod('executeWithArguments', {'arguments': arguments});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -131,7 +147,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg [command] provided. Command is split into arguments using provided [delimiter].
   Future<int> execute(String command, [String delimiter = ' ']) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('execute', {'command': command, 'delimiter': delimiter});
+      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod(
+          'execute', {'command': command, 'delimiter': delimiter});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -175,7 +192,8 @@ class FlutterFFmpeg {
   /// Returns log level.
   Future<int> getLogLevel() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLogLevel');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLogLevel');
       return result['level'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -241,7 +259,10 @@ class FlutterFFmpeg {
   }
 
   /// Sets a callback to redirect FFmpeg statistics. [newCallback] is a new statistics callback function, use null to disable a previously defined callback
-  void enableStatisticsCallback(Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) newCallback) {
+  void enableStatisticsCallback(
+      Function(int time, int size, double bitrate, double speed,
+              int videoFrameNumber, double videoQuality, double videoFps)
+          newCallback) {
     try {
       this.statisticsCallback = newCallback;
     } on PlatformException catch (e) {
@@ -253,7 +274,8 @@ class FlutterFFmpeg {
   /// videoQuality fields
   Future<Map<dynamic, dynamic>> getLastReceivedStatistics() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReceivedStatistics');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReceivedStatistics');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -273,14 +295,16 @@ class FlutterFFmpeg {
   /// Sets and overrides fontconfig configuration directory.
   Future<void> setFontconfigConfigurationPath(String path) async {
     try {
-      await _methodChannel.invokeMethod('setFontconfigConfigurationPath', {'path': path});
+      await _methodChannel
+          .invokeMethod('setFontconfigConfigurationPath', {'path': path});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
     }
   }
 
   /// Registers fonts inside the given [fontDirectory], so they are available to use in FFmpeg filters.
-  Future<void> setFontDirectory(String fontDirectory, Map<String, String> fontNameMap) async {
+  Future<void> setFontDirectory(
+      String fontDirectory, Map<String, String> fontNameMap) async {
     var parameters;
     if (fontNameMap == null) {
       parameters = {'fontDirectory': fontDirectory};
@@ -298,7 +322,8 @@ class FlutterFFmpeg {
   /// Returns FlutterFFmpeg package name.
   Future<String> getPackageName() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPackageName');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPackageName');
       return result['packageName'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -309,7 +334,8 @@ class FlutterFFmpeg {
   /// Returns supported external libraries.
   Future<List<dynamic>> getExternalLibraries() async {
     try {
-      final List<dynamic> result = await _methodChannel.invokeMethod('getExternalLibraries');
+      final List<dynamic> result =
+          await _methodChannel.invokeMethod('getExternalLibraries');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -320,7 +346,8 @@ class FlutterFFmpeg {
   /// Returns return code of last executed command.
   Future<int> getLastReturnCode() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReturnCode');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReturnCode');
       return result['lastRc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -332,7 +359,8 @@ class FlutterFFmpeg {
   /// [disableRedirection()] method also disables this functionality.
   Future<String> getLastCommandOutput() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastCommandOutput');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastCommandOutput');
       return result['lastCommandOutput'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -341,9 +369,11 @@ class FlutterFFmpeg {
   }
 
   /// Returns media information for given [path] using optional [timeout]
-  Future<Map<dynamic, dynamic>> getMediaInformation(String path, [int timeout = 10000]) async {
+  Future<Map<dynamic, dynamic>> getMediaInformation(String path,
+      [int timeout = 10000]) async {
     try {
-      return await _methodChannel.invokeMethod('getMediaInformation', {'path': path, 'timeout': timeout});
+      return await _methodChannel.invokeMethod(
+          'getMediaInformation', {'path': path, 'timeout': timeout});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
       return null;

+ 3 - 3
packages/flutter_ffmpeg_full_lts/pubspec.yaml

@@ -1,6 +1,6 @@
 name: flutter_ffmpeg
-description: Flutter plugin to run FFmpeg in the mobile platform. Supports iOS and Android.
-version: 0.2.1
+description: Flutter plugin to run FFmpeg on mobile platforms. Supports iOS and Android.
+version: 0.2.2
 author: Taner Sener <tanersener@gmail.com>
 homepage: https://github.com/tanersener/flutter-ffmpeg
 
@@ -12,7 +12,7 @@ dependencies:
     sdk: flutter
 
 dev_dependencies:
-  path_provider: ^0.5.0+1
+  path_provider: ^1.1.0
   path: ^1.6.2
 
 flutter:

+ 2 - 1
packages/flutter_ffmpeg_https-gpl/.gitignore

@@ -3,5 +3,6 @@
 .dart_tool/
 .pub/
 build/
-pubspec.lock
+/pubspec.lock
 /.packages
+/.gradle/

+ 4 - 2
packages/flutter_ffmpeg_https-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java

@@ -39,10 +39,12 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     private final MethodChannel.Result result;
     private final List<String> arguments;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncArgumentsTask(final List<String> arguments, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncArgumentsTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final List<String> arguments, final MethodChannel.Result result) {
         this.arguments = arguments;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -60,7 +62,7 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_https-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java

@@ -36,8 +36,9 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     private String delimiter;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncCommandTask(final String delimiter, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncCommandTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final String delimiter, final MethodChannel.Result result) {
         if (delimiter == null) {
             this.delimiter = " ";
         } else {
@@ -45,6 +46,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
         }
 
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -66,7 +68,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_https-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java

@@ -37,10 +37,12 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     private Integer timeout;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegGetMediaInformationAsyncTask(final Integer timeout, final MethodChannel.Result result) {
+    FlutterFFmpegGetMediaInformationAsyncTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final Integer timeout, final MethodChannel.Result result) {
         this.timeout = timeout;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -64,7 +66,7 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     @Override
     protected void onPostExecute(final MediaInformation mediaInformation) {
-        result.success(FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
     }
 
 }

+ 20 - 17
packages/flutter_ffmpeg_https-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java

@@ -80,6 +80,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
     private EventChannel.EventSink eventSink;
     private final Registrar registrar;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
     /**
      * Registers plugin to registry.
@@ -87,17 +88,19 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
      * @param registrar receiver of plugin registration
      */
     public static void registerWith(final Registrar registrar) {
-        FlutterFFmpegPlugin handler = new FlutterFFmpegPlugin(registrar);
+        FlutterFFmpegPlugin flutterFFmpegPlugin = new FlutterFFmpegPlugin(registrar);
 
         final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_ffmpeg");
-        channel.setMethodCallHandler(handler);
+        channel.setMethodCallHandler(flutterFFmpegPlugin);
 
         final EventChannel eventChannel = new EventChannel(registrar.messenger(), "flutter_ffmpeg_event");
-        eventChannel.setStreamHandler(handler);
+        eventChannel.setStreamHandler(flutterFFmpegPlugin);
     }
 
     private FlutterFFmpegPlugin(Registrar registrar) {
         this.registrar = registrar;
+
+        this.flutterFFmpegResultHandler = new FlutterFFmpegResultHandler();
     }
 
     private Context getActiveContext() {
@@ -115,18 +118,18 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         if (call.method.equals("getPlatform")) {
 
             final String abi = AbiDetect.getAbi();
-            result.success(toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
 
         } else if (call.method.equals("getFFmpegVersion")) {
 
             final String version = FFmpeg.getFFmpegVersion();
-            result.success(toStringMap(KEY_VERSION, version));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_VERSION, version));
 
         } else if (call.method.equals("executeWithArguments")) {
 
             List<String> arguments = call.argument("arguments");
 
-            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(arguments, result);
+            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(flutterFFmpegResultHandler, arguments, result);
             asyncTask.execute("dummy-trigger");
 
         } else if (call.method.equals("execute")) {
@@ -134,7 +137,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
             String command = call.argument("command");
             String delimiter = call.argument("delimiter");
 
-            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(delimiter, result);
+            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(flutterFFmpegResultHandler, delimiter, result);
             asyncTask.execute(command);
 
         } else if (call.method.equals("cancel")) {
@@ -152,7 +155,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getLogLevel")) {
 
             final Level level = Config.getLogLevel();
-            result.success(toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
 
         } else if (call.method.equals("setLogLevel")) {
 
@@ -192,7 +195,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         } else if (call.method.equals("getLastReceivedStatistics")) {
 
-            result.success(toMap(Config.getLastReceivedStatistics()));
+            flutterFFmpegResultHandler.success(result, toMap(Config.getLastReceivedStatistics()));
 
         } else if (call.method.equals("resetStatistics")) {
 
@@ -217,22 +220,22 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getPackageName")) {
 
             final String packageName = Config.getPackageName();
-            result.success(toStringMap(KEY_PACKAGE_NAME, packageName));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PACKAGE_NAME, packageName));
 
         } else if (call.method.equals("getExternalLibraries")) {
 
             final List<String> externalLibraries = Config.getExternalLibraries();
-            result.success(externalLibraries);
+            flutterFFmpegResultHandler.success(result, externalLibraries);
 
         } else if (call.method.equals("getLastReturnCode")) {
 
             int lastReturnCode = FFmpeg.getLastReturnCode();
-            result.success(toIntMap(KEY_LAST_RC, lastReturnCode));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LAST_RC, lastReturnCode));
 
         } else if (call.method.equals("getLastCommandOutput")) {
 
             final String lastCommandOutput = FFmpeg.getLastCommandOutput();
-            result.success(toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
 
         } else if (call.method.equals("getMediaInformation")) {
             final String path = call.argument("path");
@@ -241,11 +244,11 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
                 timeout = 10000;
             }
 
-            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(timeout, result);
+            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(flutterFFmpegResultHandler, timeout, result);
             asyncTask.execute(path);
 
         } else {
-            result.notImplemented();
+            flutterFFmpegResultHandler.notImplemented(result);
         }
     }
 
@@ -268,13 +271,13 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         logWrapperMap.put(EVENT_LOG, logMap);
 
-        eventSink.success(logWrapperMap);
+        flutterFFmpegResultHandler.success(eventSink, logWrapperMap);
     }
 
     protected void emitStatistics(final Statistics statistics) {
         final HashMap<String, Object> statisticsMap = new HashMap<>();
         statisticsMap.put(EVENT_STAT, toMap(statistics));
-        eventSink.success(statisticsMap);
+        flutterFFmpegResultHandler.success(eventSink, statisticsMap);
     }
 
     public static int levelToInt(final Level level) {

+ 77 - 0
packages/flutter_ffmpeg_https-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Taner Sener
+ *
+ * This file is part of FlutterFFmpeg.
+ *
+ * FlutterFFmpeg is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FlutterFFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FlutterFFmpeg.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.arthenica.flutter.ffmpeg;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.MethodChannel;
+
+/**
+ * <h3>Flutter FFmpeg Result Handler</h3>
+ *
+ * @author Taner Sener
+ * @since 0.2.2
+ */
+class FlutterFFmpegResultHandler {
+    private final Handler handler;
+
+    FlutterFFmpegResultHandler() {
+        handler = new Handler(Looper.getMainLooper());
+    }
+
+    void notImplemented(final MethodChannel.Result result) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.notImplemented();
+                }
+            }
+        });
+    }
+
+    void success(final MethodChannel.Result result, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.success(object);
+                }
+            }
+        });
+    }
+
+    void success(final EventChannel.EventSink eventSink, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (eventSink != null) {
+                    eventSink.success(object);
+                }
+            }
+        });
+    }
+
+}

+ 52 - 22
packages/flutter_ffmpeg_https-gpl/lib/flutter_ffmpeg.dart

@@ -22,11 +22,20 @@ import 'dart:async';
 import 'package:flutter/services.dart';
 
 class FlutterFFmpeg {
-  static const MethodChannel _methodChannel = const MethodChannel('flutter_ffmpeg');
-  static const EventChannel _eventChannel = const EventChannel('flutter_ffmpeg_event');
+  static const MethodChannel _methodChannel =
+      const MethodChannel('flutter_ffmpeg');
+  static const EventChannel _eventChannel =
+      const EventChannel('flutter_ffmpeg_event');
 
   Function(int level, String message) logCallback;
-  Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) statisticsCallback;
+  Function(
+      int time,
+      int size,
+      double bitrate,
+      double speed,
+      int videoFrameNumber,
+      double videoQuality,
+      double videoFps) statisticsCallback;
 
   FlutterFFmpeg() {
     logCallback = null;
@@ -46,8 +55,10 @@ class FlutterFFmpeg {
   void _onEvent(Object event) {
     if (event is Map<dynamic, dynamic>) {
       final Map<String, dynamic> eventMap = event.cast();
-      final Map<dynamic, dynamic> logEvent = eventMap['FlutterFFmpegLogCallback'];
-      final Map<dynamic, dynamic> statisticsEvent = eventMap['FlutterFFmpegStatisticsCallback'];
+      final Map<dynamic, dynamic> logEvent =
+          eventMap['FlutterFFmpegLogCallback'];
+      final Map<dynamic, dynamic> statisticsEvent =
+          eventMap['FlutterFFmpegStatisticsCallback'];
 
       if (logEvent != null) {
         int level = logEvent['level'];
@@ -74,10 +85,12 @@ class FlutterFFmpeg {
           double bitrate = _doublePrecision(statisticsEvent['bitrate'], 2);
           double speed = _doublePrecision(statisticsEvent['speed'], 2);
           int videoFrameNumber = statisticsEvent['videoFrameNumber'];
-          double videoQuality = _doublePrecision(statisticsEvent['videoQuality'], 2);
+          double videoQuality =
+              _doublePrecision(statisticsEvent['videoQuality'], 2);
           double videoFps = _doublePrecision(statisticsEvent['videoFps'], 2);
 
-          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber, videoQuality, videoFps);
+          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber,
+              videoQuality, videoFps);
         }
       }
     }
@@ -98,7 +111,8 @@ class FlutterFFmpeg {
   /// Returns FFmpeg version bundled within the library.
   Future<String> getFFmpegVersion() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getFFmpegVersion');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getFFmpegVersion');
       return result['version'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -109,7 +123,8 @@ class FlutterFFmpeg {
   /// Returns platform name where library is loaded.
   Future<String> getPlatform() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPlatform');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPlatform');
       return result['platform'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -120,7 +135,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg with [commandArguments] provided.
   Future<int> executeWithArguments(List<String> arguments) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('executeWithArguments', {'arguments': arguments});
+      final Map<dynamic, dynamic> result = await _methodChannel
+          .invokeMethod('executeWithArguments', {'arguments': arguments});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -131,7 +147,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg [command] provided. Command is split into arguments using provided [delimiter].
   Future<int> execute(String command, [String delimiter = ' ']) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('execute', {'command': command, 'delimiter': delimiter});
+      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod(
+          'execute', {'command': command, 'delimiter': delimiter});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -175,7 +192,8 @@ class FlutterFFmpeg {
   /// Returns log level.
   Future<int> getLogLevel() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLogLevel');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLogLevel');
       return result['level'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -241,7 +259,10 @@ class FlutterFFmpeg {
   }
 
   /// Sets a callback to redirect FFmpeg statistics. [newCallback] is a new statistics callback function, use null to disable a previously defined callback
-  void enableStatisticsCallback(Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) newCallback) {
+  void enableStatisticsCallback(
+      Function(int time, int size, double bitrate, double speed,
+              int videoFrameNumber, double videoQuality, double videoFps)
+          newCallback) {
     try {
       this.statisticsCallback = newCallback;
     } on PlatformException catch (e) {
@@ -253,7 +274,8 @@ class FlutterFFmpeg {
   /// videoQuality fields
   Future<Map<dynamic, dynamic>> getLastReceivedStatistics() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReceivedStatistics');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReceivedStatistics');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -273,14 +295,16 @@ class FlutterFFmpeg {
   /// Sets and overrides fontconfig configuration directory.
   Future<void> setFontconfigConfigurationPath(String path) async {
     try {
-      await _methodChannel.invokeMethod('setFontconfigConfigurationPath', {'path': path});
+      await _methodChannel
+          .invokeMethod('setFontconfigConfigurationPath', {'path': path});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
     }
   }
 
   /// Registers fonts inside the given [fontDirectory], so they are available to use in FFmpeg filters.
-  Future<void> setFontDirectory(String fontDirectory, Map<String, String> fontNameMap) async {
+  Future<void> setFontDirectory(
+      String fontDirectory, Map<String, String> fontNameMap) async {
     var parameters;
     if (fontNameMap == null) {
       parameters = {'fontDirectory': fontDirectory};
@@ -298,7 +322,8 @@ class FlutterFFmpeg {
   /// Returns FlutterFFmpeg package name.
   Future<String> getPackageName() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPackageName');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPackageName');
       return result['packageName'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -309,7 +334,8 @@ class FlutterFFmpeg {
   /// Returns supported external libraries.
   Future<List<dynamic>> getExternalLibraries() async {
     try {
-      final List<dynamic> result = await _methodChannel.invokeMethod('getExternalLibraries');
+      final List<dynamic> result =
+          await _methodChannel.invokeMethod('getExternalLibraries');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -320,7 +346,8 @@ class FlutterFFmpeg {
   /// Returns return code of last executed command.
   Future<int> getLastReturnCode() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReturnCode');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReturnCode');
       return result['lastRc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -332,7 +359,8 @@ class FlutterFFmpeg {
   /// [disableRedirection()] method also disables this functionality.
   Future<String> getLastCommandOutput() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastCommandOutput');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastCommandOutput');
       return result['lastCommandOutput'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -341,9 +369,11 @@ class FlutterFFmpeg {
   }
 
   /// Returns media information for given [path] using optional [timeout]
-  Future<Map<dynamic, dynamic>> getMediaInformation(String path, [int timeout = 10000]) async {
+  Future<Map<dynamic, dynamic>> getMediaInformation(String path,
+      [int timeout = 10000]) async {
     try {
-      return await _methodChannel.invokeMethod('getMediaInformation', {'path': path, 'timeout': timeout});
+      return await _methodChannel.invokeMethod(
+          'getMediaInformation', {'path': path, 'timeout': timeout});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
       return null;

+ 3 - 3
packages/flutter_ffmpeg_https-gpl/pubspec.yaml

@@ -1,6 +1,6 @@
 name: flutter_ffmpeg
-description: Flutter plugin to run FFmpeg in the mobile platform. Supports iOS and Android.
-version: 0.2.1
+description: Flutter plugin to run FFmpeg on mobile platforms. Supports iOS and Android.
+version: 0.2.2
 author: Taner Sener <tanersener@gmail.com>
 homepage: https://github.com/tanersener/flutter-ffmpeg
 
@@ -12,7 +12,7 @@ dependencies:
     sdk: flutter
 
 dev_dependencies:
-  path_provider: ^0.5.0+1
+  path_provider: ^1.1.0
   path: ^1.6.2
 
 flutter:

+ 2 - 1
packages/flutter_ffmpeg_https-gpl_lts/.gitignore

@@ -3,5 +3,6 @@
 .dart_tool/
 .pub/
 build/
-pubspec.lock
+/pubspec.lock
 /.packages
+/.gradle/

+ 4 - 2
packages/flutter_ffmpeg_https-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java

@@ -39,10 +39,12 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     private final MethodChannel.Result result;
     private final List<String> arguments;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncArgumentsTask(final List<String> arguments, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncArgumentsTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final List<String> arguments, final MethodChannel.Result result) {
         this.arguments = arguments;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -60,7 +62,7 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_https-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java

@@ -36,8 +36,9 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     private String delimiter;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncCommandTask(final String delimiter, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncCommandTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final String delimiter, final MethodChannel.Result result) {
         if (delimiter == null) {
             this.delimiter = " ";
         } else {
@@ -45,6 +46,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
         }
 
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -66,7 +68,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_https-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java

@@ -37,10 +37,12 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     private Integer timeout;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegGetMediaInformationAsyncTask(final Integer timeout, final MethodChannel.Result result) {
+    FlutterFFmpegGetMediaInformationAsyncTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final Integer timeout, final MethodChannel.Result result) {
         this.timeout = timeout;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -64,7 +66,7 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     @Override
     protected void onPostExecute(final MediaInformation mediaInformation) {
-        result.success(FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
     }
 
 }

+ 20 - 17
packages/flutter_ffmpeg_https-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java

@@ -80,6 +80,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
     private EventChannel.EventSink eventSink;
     private final Registrar registrar;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
     /**
      * Registers plugin to registry.
@@ -87,17 +88,19 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
      * @param registrar receiver of plugin registration
      */
     public static void registerWith(final Registrar registrar) {
-        FlutterFFmpegPlugin handler = new FlutterFFmpegPlugin(registrar);
+        FlutterFFmpegPlugin flutterFFmpegPlugin = new FlutterFFmpegPlugin(registrar);
 
         final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_ffmpeg");
-        channel.setMethodCallHandler(handler);
+        channel.setMethodCallHandler(flutterFFmpegPlugin);
 
         final EventChannel eventChannel = new EventChannel(registrar.messenger(), "flutter_ffmpeg_event");
-        eventChannel.setStreamHandler(handler);
+        eventChannel.setStreamHandler(flutterFFmpegPlugin);
     }
 
     private FlutterFFmpegPlugin(Registrar registrar) {
         this.registrar = registrar;
+
+        this.flutterFFmpegResultHandler = new FlutterFFmpegResultHandler();
     }
 
     private Context getActiveContext() {
@@ -115,18 +118,18 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         if (call.method.equals("getPlatform")) {
 
             final String abi = AbiDetect.getAbi();
-            result.success(toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
 
         } else if (call.method.equals("getFFmpegVersion")) {
 
             final String version = FFmpeg.getFFmpegVersion();
-            result.success(toStringMap(KEY_VERSION, version));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_VERSION, version));
 
         } else if (call.method.equals("executeWithArguments")) {
 
             List<String> arguments = call.argument("arguments");
 
-            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(arguments, result);
+            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(flutterFFmpegResultHandler, arguments, result);
             asyncTask.execute("dummy-trigger");
 
         } else if (call.method.equals("execute")) {
@@ -134,7 +137,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
             String command = call.argument("command");
             String delimiter = call.argument("delimiter");
 
-            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(delimiter, result);
+            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(flutterFFmpegResultHandler, delimiter, result);
             asyncTask.execute(command);
 
         } else if (call.method.equals("cancel")) {
@@ -152,7 +155,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getLogLevel")) {
 
             final Level level = Config.getLogLevel();
-            result.success(toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
 
         } else if (call.method.equals("setLogLevel")) {
 
@@ -192,7 +195,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         } else if (call.method.equals("getLastReceivedStatistics")) {
 
-            result.success(toMap(Config.getLastReceivedStatistics()));
+            flutterFFmpegResultHandler.success(result, toMap(Config.getLastReceivedStatistics()));
 
         } else if (call.method.equals("resetStatistics")) {
 
@@ -217,22 +220,22 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getPackageName")) {
 
             final String packageName = Config.getPackageName();
-            result.success(toStringMap(KEY_PACKAGE_NAME, packageName));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PACKAGE_NAME, packageName));
 
         } else if (call.method.equals("getExternalLibraries")) {
 
             final List<String> externalLibraries = Config.getExternalLibraries();
-            result.success(externalLibraries);
+            flutterFFmpegResultHandler.success(result, externalLibraries);
 
         } else if (call.method.equals("getLastReturnCode")) {
 
             int lastReturnCode = FFmpeg.getLastReturnCode();
-            result.success(toIntMap(KEY_LAST_RC, lastReturnCode));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LAST_RC, lastReturnCode));
 
         } else if (call.method.equals("getLastCommandOutput")) {
 
             final String lastCommandOutput = FFmpeg.getLastCommandOutput();
-            result.success(toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
 
         } else if (call.method.equals("getMediaInformation")) {
             final String path = call.argument("path");
@@ -241,11 +244,11 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
                 timeout = 10000;
             }
 
-            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(timeout, result);
+            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(flutterFFmpegResultHandler, timeout, result);
             asyncTask.execute(path);
 
         } else {
-            result.notImplemented();
+            flutterFFmpegResultHandler.notImplemented(result);
         }
     }
 
@@ -268,13 +271,13 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         logWrapperMap.put(EVENT_LOG, logMap);
 
-        eventSink.success(logWrapperMap);
+        flutterFFmpegResultHandler.success(eventSink, logWrapperMap);
     }
 
     protected void emitStatistics(final Statistics statistics) {
         final HashMap<String, Object> statisticsMap = new HashMap<>();
         statisticsMap.put(EVENT_STAT, toMap(statistics));
-        eventSink.success(statisticsMap);
+        flutterFFmpegResultHandler.success(eventSink, statisticsMap);
     }
 
     public static int levelToInt(final Level level) {

+ 77 - 0
packages/flutter_ffmpeg_https-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Taner Sener
+ *
+ * This file is part of FlutterFFmpeg.
+ *
+ * FlutterFFmpeg is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FlutterFFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FlutterFFmpeg.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.arthenica.flutter.ffmpeg;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.MethodChannel;
+
+/**
+ * <h3>Flutter FFmpeg Result Handler</h3>
+ *
+ * @author Taner Sener
+ * @since 0.2.2
+ */
+class FlutterFFmpegResultHandler {
+    private final Handler handler;
+
+    FlutterFFmpegResultHandler() {
+        handler = new Handler(Looper.getMainLooper());
+    }
+
+    void notImplemented(final MethodChannel.Result result) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.notImplemented();
+                }
+            }
+        });
+    }
+
+    void success(final MethodChannel.Result result, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.success(object);
+                }
+            }
+        });
+    }
+
+    void success(final EventChannel.EventSink eventSink, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (eventSink != null) {
+                    eventSink.success(object);
+                }
+            }
+        });
+    }
+
+}

+ 52 - 22
packages/flutter_ffmpeg_https-gpl_lts/lib/flutter_ffmpeg.dart

@@ -22,11 +22,20 @@ import 'dart:async';
 import 'package:flutter/services.dart';
 
 class FlutterFFmpeg {
-  static const MethodChannel _methodChannel = const MethodChannel('flutter_ffmpeg');
-  static const EventChannel _eventChannel = const EventChannel('flutter_ffmpeg_event');
+  static const MethodChannel _methodChannel =
+      const MethodChannel('flutter_ffmpeg');
+  static const EventChannel _eventChannel =
+      const EventChannel('flutter_ffmpeg_event');
 
   Function(int level, String message) logCallback;
-  Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) statisticsCallback;
+  Function(
+      int time,
+      int size,
+      double bitrate,
+      double speed,
+      int videoFrameNumber,
+      double videoQuality,
+      double videoFps) statisticsCallback;
 
   FlutterFFmpeg() {
     logCallback = null;
@@ -46,8 +55,10 @@ class FlutterFFmpeg {
   void _onEvent(Object event) {
     if (event is Map<dynamic, dynamic>) {
       final Map<String, dynamic> eventMap = event.cast();
-      final Map<dynamic, dynamic> logEvent = eventMap['FlutterFFmpegLogCallback'];
-      final Map<dynamic, dynamic> statisticsEvent = eventMap['FlutterFFmpegStatisticsCallback'];
+      final Map<dynamic, dynamic> logEvent =
+          eventMap['FlutterFFmpegLogCallback'];
+      final Map<dynamic, dynamic> statisticsEvent =
+          eventMap['FlutterFFmpegStatisticsCallback'];
 
       if (logEvent != null) {
         int level = logEvent['level'];
@@ -74,10 +85,12 @@ class FlutterFFmpeg {
           double bitrate = _doublePrecision(statisticsEvent['bitrate'], 2);
           double speed = _doublePrecision(statisticsEvent['speed'], 2);
           int videoFrameNumber = statisticsEvent['videoFrameNumber'];
-          double videoQuality = _doublePrecision(statisticsEvent['videoQuality'], 2);
+          double videoQuality =
+              _doublePrecision(statisticsEvent['videoQuality'], 2);
           double videoFps = _doublePrecision(statisticsEvent['videoFps'], 2);
 
-          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber, videoQuality, videoFps);
+          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber,
+              videoQuality, videoFps);
         }
       }
     }
@@ -98,7 +111,8 @@ class FlutterFFmpeg {
   /// Returns FFmpeg version bundled within the library.
   Future<String> getFFmpegVersion() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getFFmpegVersion');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getFFmpegVersion');
       return result['version'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -109,7 +123,8 @@ class FlutterFFmpeg {
   /// Returns platform name where library is loaded.
   Future<String> getPlatform() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPlatform');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPlatform');
       return result['platform'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -120,7 +135,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg with [commandArguments] provided.
   Future<int> executeWithArguments(List<String> arguments) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('executeWithArguments', {'arguments': arguments});
+      final Map<dynamic, dynamic> result = await _methodChannel
+          .invokeMethod('executeWithArguments', {'arguments': arguments});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -131,7 +147,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg [command] provided. Command is split into arguments using provided [delimiter].
   Future<int> execute(String command, [String delimiter = ' ']) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('execute', {'command': command, 'delimiter': delimiter});
+      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod(
+          'execute', {'command': command, 'delimiter': delimiter});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -175,7 +192,8 @@ class FlutterFFmpeg {
   /// Returns log level.
   Future<int> getLogLevel() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLogLevel');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLogLevel');
       return result['level'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -241,7 +259,10 @@ class FlutterFFmpeg {
   }
 
   /// Sets a callback to redirect FFmpeg statistics. [newCallback] is a new statistics callback function, use null to disable a previously defined callback
-  void enableStatisticsCallback(Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) newCallback) {
+  void enableStatisticsCallback(
+      Function(int time, int size, double bitrate, double speed,
+              int videoFrameNumber, double videoQuality, double videoFps)
+          newCallback) {
     try {
       this.statisticsCallback = newCallback;
     } on PlatformException catch (e) {
@@ -253,7 +274,8 @@ class FlutterFFmpeg {
   /// videoQuality fields
   Future<Map<dynamic, dynamic>> getLastReceivedStatistics() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReceivedStatistics');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReceivedStatistics');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -273,14 +295,16 @@ class FlutterFFmpeg {
   /// Sets and overrides fontconfig configuration directory.
   Future<void> setFontconfigConfigurationPath(String path) async {
     try {
-      await _methodChannel.invokeMethod('setFontconfigConfigurationPath', {'path': path});
+      await _methodChannel
+          .invokeMethod('setFontconfigConfigurationPath', {'path': path});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
     }
   }
 
   /// Registers fonts inside the given [fontDirectory], so they are available to use in FFmpeg filters.
-  Future<void> setFontDirectory(String fontDirectory, Map<String, String> fontNameMap) async {
+  Future<void> setFontDirectory(
+      String fontDirectory, Map<String, String> fontNameMap) async {
     var parameters;
     if (fontNameMap == null) {
       parameters = {'fontDirectory': fontDirectory};
@@ -298,7 +322,8 @@ class FlutterFFmpeg {
   /// Returns FlutterFFmpeg package name.
   Future<String> getPackageName() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPackageName');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPackageName');
       return result['packageName'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -309,7 +334,8 @@ class FlutterFFmpeg {
   /// Returns supported external libraries.
   Future<List<dynamic>> getExternalLibraries() async {
     try {
-      final List<dynamic> result = await _methodChannel.invokeMethod('getExternalLibraries');
+      final List<dynamic> result =
+          await _methodChannel.invokeMethod('getExternalLibraries');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -320,7 +346,8 @@ class FlutterFFmpeg {
   /// Returns return code of last executed command.
   Future<int> getLastReturnCode() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReturnCode');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReturnCode');
       return result['lastRc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -332,7 +359,8 @@ class FlutterFFmpeg {
   /// [disableRedirection()] method also disables this functionality.
   Future<String> getLastCommandOutput() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastCommandOutput');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastCommandOutput');
       return result['lastCommandOutput'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -341,9 +369,11 @@ class FlutterFFmpeg {
   }
 
   /// Returns media information for given [path] using optional [timeout]
-  Future<Map<dynamic, dynamic>> getMediaInformation(String path, [int timeout = 10000]) async {
+  Future<Map<dynamic, dynamic>> getMediaInformation(String path,
+      [int timeout = 10000]) async {
     try {
-      return await _methodChannel.invokeMethod('getMediaInformation', {'path': path, 'timeout': timeout});
+      return await _methodChannel.invokeMethod(
+          'getMediaInformation', {'path': path, 'timeout': timeout});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
       return null;

+ 3 - 3
packages/flutter_ffmpeg_https-gpl_lts/pubspec.yaml

@@ -1,6 +1,6 @@
 name: flutter_ffmpeg
-description: Flutter plugin to run FFmpeg in the mobile platform. Supports iOS and Android.
-version: 0.2.1
+description: Flutter plugin to run FFmpeg on mobile platforms. Supports iOS and Android.
+version: 0.2.2
 author: Taner Sener <tanersener@gmail.com>
 homepage: https://github.com/tanersener/flutter-ffmpeg
 
@@ -12,7 +12,7 @@ dependencies:
     sdk: flutter
 
 dev_dependencies:
-  path_provider: ^0.5.0+1
+  path_provider: ^1.1.0
   path: ^1.6.2
 
 flutter:

+ 2 - 1
packages/flutter_ffmpeg_https/.gitignore

@@ -3,5 +3,6 @@
 .dart_tool/
 .pub/
 build/
-pubspec.lock
+/pubspec.lock
 /.packages
+/.gradle/

+ 4 - 2
packages/flutter_ffmpeg_https/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java

@@ -39,10 +39,12 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     private final MethodChannel.Result result;
     private final List<String> arguments;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncArgumentsTask(final List<String> arguments, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncArgumentsTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final List<String> arguments, final MethodChannel.Result result) {
         this.arguments = arguments;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -60,7 +62,7 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_https/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java

@@ -36,8 +36,9 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     private String delimiter;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncCommandTask(final String delimiter, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncCommandTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final String delimiter, final MethodChannel.Result result) {
         if (delimiter == null) {
             this.delimiter = " ";
         } else {
@@ -45,6 +46,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
         }
 
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -66,7 +68,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_https/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java

@@ -37,10 +37,12 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     private Integer timeout;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegGetMediaInformationAsyncTask(final Integer timeout, final MethodChannel.Result result) {
+    FlutterFFmpegGetMediaInformationAsyncTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final Integer timeout, final MethodChannel.Result result) {
         this.timeout = timeout;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -64,7 +66,7 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     @Override
     protected void onPostExecute(final MediaInformation mediaInformation) {
-        result.success(FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
     }
 
 }

+ 20 - 17
packages/flutter_ffmpeg_https/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java

@@ -80,6 +80,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
     private EventChannel.EventSink eventSink;
     private final Registrar registrar;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
     /**
      * Registers plugin to registry.
@@ -87,17 +88,19 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
      * @param registrar receiver of plugin registration
      */
     public static void registerWith(final Registrar registrar) {
-        FlutterFFmpegPlugin handler = new FlutterFFmpegPlugin(registrar);
+        FlutterFFmpegPlugin flutterFFmpegPlugin = new FlutterFFmpegPlugin(registrar);
 
         final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_ffmpeg");
-        channel.setMethodCallHandler(handler);
+        channel.setMethodCallHandler(flutterFFmpegPlugin);
 
         final EventChannel eventChannel = new EventChannel(registrar.messenger(), "flutter_ffmpeg_event");
-        eventChannel.setStreamHandler(handler);
+        eventChannel.setStreamHandler(flutterFFmpegPlugin);
     }
 
     private FlutterFFmpegPlugin(Registrar registrar) {
         this.registrar = registrar;
+
+        this.flutterFFmpegResultHandler = new FlutterFFmpegResultHandler();
     }
 
     private Context getActiveContext() {
@@ -115,18 +118,18 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         if (call.method.equals("getPlatform")) {
 
             final String abi = AbiDetect.getAbi();
-            result.success(toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
 
         } else if (call.method.equals("getFFmpegVersion")) {
 
             final String version = FFmpeg.getFFmpegVersion();
-            result.success(toStringMap(KEY_VERSION, version));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_VERSION, version));
 
         } else if (call.method.equals("executeWithArguments")) {
 
             List<String> arguments = call.argument("arguments");
 
-            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(arguments, result);
+            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(flutterFFmpegResultHandler, arguments, result);
             asyncTask.execute("dummy-trigger");
 
         } else if (call.method.equals("execute")) {
@@ -134,7 +137,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
             String command = call.argument("command");
             String delimiter = call.argument("delimiter");
 
-            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(delimiter, result);
+            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(flutterFFmpegResultHandler, delimiter, result);
             asyncTask.execute(command);
 
         } else if (call.method.equals("cancel")) {
@@ -152,7 +155,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getLogLevel")) {
 
             final Level level = Config.getLogLevel();
-            result.success(toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
 
         } else if (call.method.equals("setLogLevel")) {
 
@@ -192,7 +195,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         } else if (call.method.equals("getLastReceivedStatistics")) {
 
-            result.success(toMap(Config.getLastReceivedStatistics()));
+            flutterFFmpegResultHandler.success(result, toMap(Config.getLastReceivedStatistics()));
 
         } else if (call.method.equals("resetStatistics")) {
 
@@ -217,22 +220,22 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getPackageName")) {
 
             final String packageName = Config.getPackageName();
-            result.success(toStringMap(KEY_PACKAGE_NAME, packageName));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PACKAGE_NAME, packageName));
 
         } else if (call.method.equals("getExternalLibraries")) {
 
             final List<String> externalLibraries = Config.getExternalLibraries();
-            result.success(externalLibraries);
+            flutterFFmpegResultHandler.success(result, externalLibraries);
 
         } else if (call.method.equals("getLastReturnCode")) {
 
             int lastReturnCode = FFmpeg.getLastReturnCode();
-            result.success(toIntMap(KEY_LAST_RC, lastReturnCode));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LAST_RC, lastReturnCode));
 
         } else if (call.method.equals("getLastCommandOutput")) {
 
             final String lastCommandOutput = FFmpeg.getLastCommandOutput();
-            result.success(toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
 
         } else if (call.method.equals("getMediaInformation")) {
             final String path = call.argument("path");
@@ -241,11 +244,11 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
                 timeout = 10000;
             }
 
-            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(timeout, result);
+            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(flutterFFmpegResultHandler, timeout, result);
             asyncTask.execute(path);
 
         } else {
-            result.notImplemented();
+            flutterFFmpegResultHandler.notImplemented(result);
         }
     }
 
@@ -268,13 +271,13 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         logWrapperMap.put(EVENT_LOG, logMap);
 
-        eventSink.success(logWrapperMap);
+        flutterFFmpegResultHandler.success(eventSink, logWrapperMap);
     }
 
     protected void emitStatistics(final Statistics statistics) {
         final HashMap<String, Object> statisticsMap = new HashMap<>();
         statisticsMap.put(EVENT_STAT, toMap(statistics));
-        eventSink.success(statisticsMap);
+        flutterFFmpegResultHandler.success(eventSink, statisticsMap);
     }
 
     public static int levelToInt(final Level level) {

+ 77 - 0
packages/flutter_ffmpeg_https/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Taner Sener
+ *
+ * This file is part of FlutterFFmpeg.
+ *
+ * FlutterFFmpeg is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FlutterFFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FlutterFFmpeg.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.arthenica.flutter.ffmpeg;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.MethodChannel;
+
+/**
+ * <h3>Flutter FFmpeg Result Handler</h3>
+ *
+ * @author Taner Sener
+ * @since 0.2.2
+ */
+class FlutterFFmpegResultHandler {
+    private final Handler handler;
+
+    FlutterFFmpegResultHandler() {
+        handler = new Handler(Looper.getMainLooper());
+    }
+
+    void notImplemented(final MethodChannel.Result result) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.notImplemented();
+                }
+            }
+        });
+    }
+
+    void success(final MethodChannel.Result result, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.success(object);
+                }
+            }
+        });
+    }
+
+    void success(final EventChannel.EventSink eventSink, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (eventSink != null) {
+                    eventSink.success(object);
+                }
+            }
+        });
+    }
+
+}

+ 52 - 22
packages/flutter_ffmpeg_https/lib/flutter_ffmpeg.dart

@@ -22,11 +22,20 @@ import 'dart:async';
 import 'package:flutter/services.dart';
 
 class FlutterFFmpeg {
-  static const MethodChannel _methodChannel = const MethodChannel('flutter_ffmpeg');
-  static const EventChannel _eventChannel = const EventChannel('flutter_ffmpeg_event');
+  static const MethodChannel _methodChannel =
+      const MethodChannel('flutter_ffmpeg');
+  static const EventChannel _eventChannel =
+      const EventChannel('flutter_ffmpeg_event');
 
   Function(int level, String message) logCallback;
-  Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) statisticsCallback;
+  Function(
+      int time,
+      int size,
+      double bitrate,
+      double speed,
+      int videoFrameNumber,
+      double videoQuality,
+      double videoFps) statisticsCallback;
 
   FlutterFFmpeg() {
     logCallback = null;
@@ -46,8 +55,10 @@ class FlutterFFmpeg {
   void _onEvent(Object event) {
     if (event is Map<dynamic, dynamic>) {
       final Map<String, dynamic> eventMap = event.cast();
-      final Map<dynamic, dynamic> logEvent = eventMap['FlutterFFmpegLogCallback'];
-      final Map<dynamic, dynamic> statisticsEvent = eventMap['FlutterFFmpegStatisticsCallback'];
+      final Map<dynamic, dynamic> logEvent =
+          eventMap['FlutterFFmpegLogCallback'];
+      final Map<dynamic, dynamic> statisticsEvent =
+          eventMap['FlutterFFmpegStatisticsCallback'];
 
       if (logEvent != null) {
         int level = logEvent['level'];
@@ -74,10 +85,12 @@ class FlutterFFmpeg {
           double bitrate = _doublePrecision(statisticsEvent['bitrate'], 2);
           double speed = _doublePrecision(statisticsEvent['speed'], 2);
           int videoFrameNumber = statisticsEvent['videoFrameNumber'];
-          double videoQuality = _doublePrecision(statisticsEvent['videoQuality'], 2);
+          double videoQuality =
+              _doublePrecision(statisticsEvent['videoQuality'], 2);
           double videoFps = _doublePrecision(statisticsEvent['videoFps'], 2);
 
-          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber, videoQuality, videoFps);
+          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber,
+              videoQuality, videoFps);
         }
       }
     }
@@ -98,7 +111,8 @@ class FlutterFFmpeg {
   /// Returns FFmpeg version bundled within the library.
   Future<String> getFFmpegVersion() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getFFmpegVersion');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getFFmpegVersion');
       return result['version'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -109,7 +123,8 @@ class FlutterFFmpeg {
   /// Returns platform name where library is loaded.
   Future<String> getPlatform() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPlatform');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPlatform');
       return result['platform'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -120,7 +135,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg with [commandArguments] provided.
   Future<int> executeWithArguments(List<String> arguments) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('executeWithArguments', {'arguments': arguments});
+      final Map<dynamic, dynamic> result = await _methodChannel
+          .invokeMethod('executeWithArguments', {'arguments': arguments});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -131,7 +147,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg [command] provided. Command is split into arguments using provided [delimiter].
   Future<int> execute(String command, [String delimiter = ' ']) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('execute', {'command': command, 'delimiter': delimiter});
+      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod(
+          'execute', {'command': command, 'delimiter': delimiter});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -175,7 +192,8 @@ class FlutterFFmpeg {
   /// Returns log level.
   Future<int> getLogLevel() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLogLevel');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLogLevel');
       return result['level'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -241,7 +259,10 @@ class FlutterFFmpeg {
   }
 
   /// Sets a callback to redirect FFmpeg statistics. [newCallback] is a new statistics callback function, use null to disable a previously defined callback
-  void enableStatisticsCallback(Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) newCallback) {
+  void enableStatisticsCallback(
+      Function(int time, int size, double bitrate, double speed,
+              int videoFrameNumber, double videoQuality, double videoFps)
+          newCallback) {
     try {
       this.statisticsCallback = newCallback;
     } on PlatformException catch (e) {
@@ -253,7 +274,8 @@ class FlutterFFmpeg {
   /// videoQuality fields
   Future<Map<dynamic, dynamic>> getLastReceivedStatistics() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReceivedStatistics');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReceivedStatistics');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -273,14 +295,16 @@ class FlutterFFmpeg {
   /// Sets and overrides fontconfig configuration directory.
   Future<void> setFontconfigConfigurationPath(String path) async {
     try {
-      await _methodChannel.invokeMethod('setFontconfigConfigurationPath', {'path': path});
+      await _methodChannel
+          .invokeMethod('setFontconfigConfigurationPath', {'path': path});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
     }
   }
 
   /// Registers fonts inside the given [fontDirectory], so they are available to use in FFmpeg filters.
-  Future<void> setFontDirectory(String fontDirectory, Map<String, String> fontNameMap) async {
+  Future<void> setFontDirectory(
+      String fontDirectory, Map<String, String> fontNameMap) async {
     var parameters;
     if (fontNameMap == null) {
       parameters = {'fontDirectory': fontDirectory};
@@ -298,7 +322,8 @@ class FlutterFFmpeg {
   /// Returns FlutterFFmpeg package name.
   Future<String> getPackageName() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPackageName');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPackageName');
       return result['packageName'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -309,7 +334,8 @@ class FlutterFFmpeg {
   /// Returns supported external libraries.
   Future<List<dynamic>> getExternalLibraries() async {
     try {
-      final List<dynamic> result = await _methodChannel.invokeMethod('getExternalLibraries');
+      final List<dynamic> result =
+          await _methodChannel.invokeMethod('getExternalLibraries');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -320,7 +346,8 @@ class FlutterFFmpeg {
   /// Returns return code of last executed command.
   Future<int> getLastReturnCode() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReturnCode');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReturnCode');
       return result['lastRc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -332,7 +359,8 @@ class FlutterFFmpeg {
   /// [disableRedirection()] method also disables this functionality.
   Future<String> getLastCommandOutput() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastCommandOutput');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastCommandOutput');
       return result['lastCommandOutput'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -341,9 +369,11 @@ class FlutterFFmpeg {
   }
 
   /// Returns media information for given [path] using optional [timeout]
-  Future<Map<dynamic, dynamic>> getMediaInformation(String path, [int timeout = 10000]) async {
+  Future<Map<dynamic, dynamic>> getMediaInformation(String path,
+      [int timeout = 10000]) async {
     try {
-      return await _methodChannel.invokeMethod('getMediaInformation', {'path': path, 'timeout': timeout});
+      return await _methodChannel.invokeMethod(
+          'getMediaInformation', {'path': path, 'timeout': timeout});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
       return null;

+ 3 - 3
packages/flutter_ffmpeg_https/pubspec.yaml

@@ -1,6 +1,6 @@
 name: flutter_ffmpeg
-description: Flutter plugin to run FFmpeg in the mobile platform. Supports iOS and Android.
-version: 0.2.1
+description: Flutter plugin to run FFmpeg on mobile platforms. Supports iOS and Android.
+version: 0.2.2
 author: Taner Sener <tanersener@gmail.com>
 homepage: https://github.com/tanersener/flutter-ffmpeg
 
@@ -12,7 +12,7 @@ dependencies:
     sdk: flutter
 
 dev_dependencies:
-  path_provider: ^0.5.0+1
+  path_provider: ^1.1.0
   path: ^1.6.2
 
 flutter:

+ 2 - 1
packages/flutter_ffmpeg_https_lts/.gitignore

@@ -3,5 +3,6 @@
 .dart_tool/
 .pub/
 build/
-pubspec.lock
+/pubspec.lock
 /.packages
+/.gradle/

+ 4 - 2
packages/flutter_ffmpeg_https_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java

@@ -39,10 +39,12 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     private final MethodChannel.Result result;
     private final List<String> arguments;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncArgumentsTask(final List<String> arguments, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncArgumentsTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final List<String> arguments, final MethodChannel.Result result) {
         this.arguments = arguments;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -60,7 +62,7 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_https_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java

@@ -36,8 +36,9 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     private String delimiter;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncCommandTask(final String delimiter, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncCommandTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final String delimiter, final MethodChannel.Result result) {
         if (delimiter == null) {
             this.delimiter = " ";
         } else {
@@ -45,6 +46,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
         }
 
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -66,7 +68,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_https_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java

@@ -37,10 +37,12 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     private Integer timeout;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegGetMediaInformationAsyncTask(final Integer timeout, final MethodChannel.Result result) {
+    FlutterFFmpegGetMediaInformationAsyncTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final Integer timeout, final MethodChannel.Result result) {
         this.timeout = timeout;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -64,7 +66,7 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     @Override
     protected void onPostExecute(final MediaInformation mediaInformation) {
-        result.success(FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
     }
 
 }

+ 20 - 17
packages/flutter_ffmpeg_https_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java

@@ -80,6 +80,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
     private EventChannel.EventSink eventSink;
     private final Registrar registrar;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
     /**
      * Registers plugin to registry.
@@ -87,17 +88,19 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
      * @param registrar receiver of plugin registration
      */
     public static void registerWith(final Registrar registrar) {
-        FlutterFFmpegPlugin handler = new FlutterFFmpegPlugin(registrar);
+        FlutterFFmpegPlugin flutterFFmpegPlugin = new FlutterFFmpegPlugin(registrar);
 
         final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_ffmpeg");
-        channel.setMethodCallHandler(handler);
+        channel.setMethodCallHandler(flutterFFmpegPlugin);
 
         final EventChannel eventChannel = new EventChannel(registrar.messenger(), "flutter_ffmpeg_event");
-        eventChannel.setStreamHandler(handler);
+        eventChannel.setStreamHandler(flutterFFmpegPlugin);
     }
 
     private FlutterFFmpegPlugin(Registrar registrar) {
         this.registrar = registrar;
+
+        this.flutterFFmpegResultHandler = new FlutterFFmpegResultHandler();
     }
 
     private Context getActiveContext() {
@@ -115,18 +118,18 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         if (call.method.equals("getPlatform")) {
 
             final String abi = AbiDetect.getAbi();
-            result.success(toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
 
         } else if (call.method.equals("getFFmpegVersion")) {
 
             final String version = FFmpeg.getFFmpegVersion();
-            result.success(toStringMap(KEY_VERSION, version));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_VERSION, version));
 
         } else if (call.method.equals("executeWithArguments")) {
 
             List<String> arguments = call.argument("arguments");
 
-            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(arguments, result);
+            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(flutterFFmpegResultHandler, arguments, result);
             asyncTask.execute("dummy-trigger");
 
         } else if (call.method.equals("execute")) {
@@ -134,7 +137,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
             String command = call.argument("command");
             String delimiter = call.argument("delimiter");
 
-            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(delimiter, result);
+            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(flutterFFmpegResultHandler, delimiter, result);
             asyncTask.execute(command);
 
         } else if (call.method.equals("cancel")) {
@@ -152,7 +155,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getLogLevel")) {
 
             final Level level = Config.getLogLevel();
-            result.success(toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
 
         } else if (call.method.equals("setLogLevel")) {
 
@@ -192,7 +195,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         } else if (call.method.equals("getLastReceivedStatistics")) {
 
-            result.success(toMap(Config.getLastReceivedStatistics()));
+            flutterFFmpegResultHandler.success(result, toMap(Config.getLastReceivedStatistics()));
 
         } else if (call.method.equals("resetStatistics")) {
 
@@ -217,22 +220,22 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getPackageName")) {
 
             final String packageName = Config.getPackageName();
-            result.success(toStringMap(KEY_PACKAGE_NAME, packageName));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PACKAGE_NAME, packageName));
 
         } else if (call.method.equals("getExternalLibraries")) {
 
             final List<String> externalLibraries = Config.getExternalLibraries();
-            result.success(externalLibraries);
+            flutterFFmpegResultHandler.success(result, externalLibraries);
 
         } else if (call.method.equals("getLastReturnCode")) {
 
             int lastReturnCode = FFmpeg.getLastReturnCode();
-            result.success(toIntMap(KEY_LAST_RC, lastReturnCode));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LAST_RC, lastReturnCode));
 
         } else if (call.method.equals("getLastCommandOutput")) {
 
             final String lastCommandOutput = FFmpeg.getLastCommandOutput();
-            result.success(toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
 
         } else if (call.method.equals("getMediaInformation")) {
             final String path = call.argument("path");
@@ -241,11 +244,11 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
                 timeout = 10000;
             }
 
-            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(timeout, result);
+            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(flutterFFmpegResultHandler, timeout, result);
             asyncTask.execute(path);
 
         } else {
-            result.notImplemented();
+            flutterFFmpegResultHandler.notImplemented(result);
         }
     }
 
@@ -268,13 +271,13 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         logWrapperMap.put(EVENT_LOG, logMap);
 
-        eventSink.success(logWrapperMap);
+        flutterFFmpegResultHandler.success(eventSink, logWrapperMap);
     }
 
     protected void emitStatistics(final Statistics statistics) {
         final HashMap<String, Object> statisticsMap = new HashMap<>();
         statisticsMap.put(EVENT_STAT, toMap(statistics));
-        eventSink.success(statisticsMap);
+        flutterFFmpegResultHandler.success(eventSink, statisticsMap);
     }
 
     public static int levelToInt(final Level level) {

+ 77 - 0
packages/flutter_ffmpeg_https_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Taner Sener
+ *
+ * This file is part of FlutterFFmpeg.
+ *
+ * FlutterFFmpeg is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FlutterFFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FlutterFFmpeg.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.arthenica.flutter.ffmpeg;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.MethodChannel;
+
+/**
+ * <h3>Flutter FFmpeg Result Handler</h3>
+ *
+ * @author Taner Sener
+ * @since 0.2.2
+ */
+class FlutterFFmpegResultHandler {
+    private final Handler handler;
+
+    FlutterFFmpegResultHandler() {
+        handler = new Handler(Looper.getMainLooper());
+    }
+
+    void notImplemented(final MethodChannel.Result result) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.notImplemented();
+                }
+            }
+        });
+    }
+
+    void success(final MethodChannel.Result result, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.success(object);
+                }
+            }
+        });
+    }
+
+    void success(final EventChannel.EventSink eventSink, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (eventSink != null) {
+                    eventSink.success(object);
+                }
+            }
+        });
+    }
+
+}

+ 52 - 22
packages/flutter_ffmpeg_https_lts/lib/flutter_ffmpeg.dart

@@ -22,11 +22,20 @@ import 'dart:async';
 import 'package:flutter/services.dart';
 
 class FlutterFFmpeg {
-  static const MethodChannel _methodChannel = const MethodChannel('flutter_ffmpeg');
-  static const EventChannel _eventChannel = const EventChannel('flutter_ffmpeg_event');
+  static const MethodChannel _methodChannel =
+      const MethodChannel('flutter_ffmpeg');
+  static const EventChannel _eventChannel =
+      const EventChannel('flutter_ffmpeg_event');
 
   Function(int level, String message) logCallback;
-  Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) statisticsCallback;
+  Function(
+      int time,
+      int size,
+      double bitrate,
+      double speed,
+      int videoFrameNumber,
+      double videoQuality,
+      double videoFps) statisticsCallback;
 
   FlutterFFmpeg() {
     logCallback = null;
@@ -46,8 +55,10 @@ class FlutterFFmpeg {
   void _onEvent(Object event) {
     if (event is Map<dynamic, dynamic>) {
       final Map<String, dynamic> eventMap = event.cast();
-      final Map<dynamic, dynamic> logEvent = eventMap['FlutterFFmpegLogCallback'];
-      final Map<dynamic, dynamic> statisticsEvent = eventMap['FlutterFFmpegStatisticsCallback'];
+      final Map<dynamic, dynamic> logEvent =
+          eventMap['FlutterFFmpegLogCallback'];
+      final Map<dynamic, dynamic> statisticsEvent =
+          eventMap['FlutterFFmpegStatisticsCallback'];
 
       if (logEvent != null) {
         int level = logEvent['level'];
@@ -74,10 +85,12 @@ class FlutterFFmpeg {
           double bitrate = _doublePrecision(statisticsEvent['bitrate'], 2);
           double speed = _doublePrecision(statisticsEvent['speed'], 2);
           int videoFrameNumber = statisticsEvent['videoFrameNumber'];
-          double videoQuality = _doublePrecision(statisticsEvent['videoQuality'], 2);
+          double videoQuality =
+              _doublePrecision(statisticsEvent['videoQuality'], 2);
           double videoFps = _doublePrecision(statisticsEvent['videoFps'], 2);
 
-          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber, videoQuality, videoFps);
+          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber,
+              videoQuality, videoFps);
         }
       }
     }
@@ -98,7 +111,8 @@ class FlutterFFmpeg {
   /// Returns FFmpeg version bundled within the library.
   Future<String> getFFmpegVersion() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getFFmpegVersion');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getFFmpegVersion');
       return result['version'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -109,7 +123,8 @@ class FlutterFFmpeg {
   /// Returns platform name where library is loaded.
   Future<String> getPlatform() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPlatform');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPlatform');
       return result['platform'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -120,7 +135,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg with [commandArguments] provided.
   Future<int> executeWithArguments(List<String> arguments) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('executeWithArguments', {'arguments': arguments});
+      final Map<dynamic, dynamic> result = await _methodChannel
+          .invokeMethod('executeWithArguments', {'arguments': arguments});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -131,7 +147,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg [command] provided. Command is split into arguments using provided [delimiter].
   Future<int> execute(String command, [String delimiter = ' ']) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('execute', {'command': command, 'delimiter': delimiter});
+      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod(
+          'execute', {'command': command, 'delimiter': delimiter});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -175,7 +192,8 @@ class FlutterFFmpeg {
   /// Returns log level.
   Future<int> getLogLevel() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLogLevel');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLogLevel');
       return result['level'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -241,7 +259,10 @@ class FlutterFFmpeg {
   }
 
   /// Sets a callback to redirect FFmpeg statistics. [newCallback] is a new statistics callback function, use null to disable a previously defined callback
-  void enableStatisticsCallback(Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) newCallback) {
+  void enableStatisticsCallback(
+      Function(int time, int size, double bitrate, double speed,
+              int videoFrameNumber, double videoQuality, double videoFps)
+          newCallback) {
     try {
       this.statisticsCallback = newCallback;
     } on PlatformException catch (e) {
@@ -253,7 +274,8 @@ class FlutterFFmpeg {
   /// videoQuality fields
   Future<Map<dynamic, dynamic>> getLastReceivedStatistics() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReceivedStatistics');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReceivedStatistics');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -273,14 +295,16 @@ class FlutterFFmpeg {
   /// Sets and overrides fontconfig configuration directory.
   Future<void> setFontconfigConfigurationPath(String path) async {
     try {
-      await _methodChannel.invokeMethod('setFontconfigConfigurationPath', {'path': path});
+      await _methodChannel
+          .invokeMethod('setFontconfigConfigurationPath', {'path': path});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
     }
   }
 
   /// Registers fonts inside the given [fontDirectory], so they are available to use in FFmpeg filters.
-  Future<void> setFontDirectory(String fontDirectory, Map<String, String> fontNameMap) async {
+  Future<void> setFontDirectory(
+      String fontDirectory, Map<String, String> fontNameMap) async {
     var parameters;
     if (fontNameMap == null) {
       parameters = {'fontDirectory': fontDirectory};
@@ -298,7 +322,8 @@ class FlutterFFmpeg {
   /// Returns FlutterFFmpeg package name.
   Future<String> getPackageName() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPackageName');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPackageName');
       return result['packageName'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -309,7 +334,8 @@ class FlutterFFmpeg {
   /// Returns supported external libraries.
   Future<List<dynamic>> getExternalLibraries() async {
     try {
-      final List<dynamic> result = await _methodChannel.invokeMethod('getExternalLibraries');
+      final List<dynamic> result =
+          await _methodChannel.invokeMethod('getExternalLibraries');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -320,7 +346,8 @@ class FlutterFFmpeg {
   /// Returns return code of last executed command.
   Future<int> getLastReturnCode() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReturnCode');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReturnCode');
       return result['lastRc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -332,7 +359,8 @@ class FlutterFFmpeg {
   /// [disableRedirection()] method also disables this functionality.
   Future<String> getLastCommandOutput() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastCommandOutput');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastCommandOutput');
       return result['lastCommandOutput'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -341,9 +369,11 @@ class FlutterFFmpeg {
   }
 
   /// Returns media information for given [path] using optional [timeout]
-  Future<Map<dynamic, dynamic>> getMediaInformation(String path, [int timeout = 10000]) async {
+  Future<Map<dynamic, dynamic>> getMediaInformation(String path,
+      [int timeout = 10000]) async {
     try {
-      return await _methodChannel.invokeMethod('getMediaInformation', {'path': path, 'timeout': timeout});
+      return await _methodChannel.invokeMethod(
+          'getMediaInformation', {'path': path, 'timeout': timeout});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
       return null;

+ 3 - 3
packages/flutter_ffmpeg_https_lts/pubspec.yaml

@@ -1,6 +1,6 @@
 name: flutter_ffmpeg
-description: Flutter plugin to run FFmpeg in the mobile platform. Supports iOS and Android.
-version: 0.2.1
+description: Flutter plugin to run FFmpeg on mobile platforms. Supports iOS and Android.
+version: 0.2.2
 author: Taner Sener <tanersener@gmail.com>
 homepage: https://github.com/tanersener/flutter-ffmpeg
 
@@ -12,7 +12,7 @@ dependencies:
     sdk: flutter
 
 dev_dependencies:
-  path_provider: ^0.5.0+1
+  path_provider: ^1.1.0
   path: ^1.6.2
 
 flutter:

+ 2 - 1
packages/flutter_ffmpeg_min-gpl/.gitignore

@@ -3,5 +3,6 @@
 .dart_tool/
 .pub/
 build/
-pubspec.lock
+/pubspec.lock
 /.packages
+/.gradle/

+ 4 - 2
packages/flutter_ffmpeg_min-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java

@@ -39,10 +39,12 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     private final MethodChannel.Result result;
     private final List<String> arguments;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncArgumentsTask(final List<String> arguments, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncArgumentsTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final List<String> arguments, final MethodChannel.Result result) {
         this.arguments = arguments;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -60,7 +62,7 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_min-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java

@@ -36,8 +36,9 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     private String delimiter;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncCommandTask(final String delimiter, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncCommandTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final String delimiter, final MethodChannel.Result result) {
         if (delimiter == null) {
             this.delimiter = " ";
         } else {
@@ -45,6 +46,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
         }
 
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -66,7 +68,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_min-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java

@@ -37,10 +37,12 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     private Integer timeout;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegGetMediaInformationAsyncTask(final Integer timeout, final MethodChannel.Result result) {
+    FlutterFFmpegGetMediaInformationAsyncTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final Integer timeout, final MethodChannel.Result result) {
         this.timeout = timeout;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -64,7 +66,7 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     @Override
     protected void onPostExecute(final MediaInformation mediaInformation) {
-        result.success(FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
     }
 
 }

+ 20 - 17
packages/flutter_ffmpeg_min-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java

@@ -80,6 +80,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
     private EventChannel.EventSink eventSink;
     private final Registrar registrar;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
     /**
      * Registers plugin to registry.
@@ -87,17 +88,19 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
      * @param registrar receiver of plugin registration
      */
     public static void registerWith(final Registrar registrar) {
-        FlutterFFmpegPlugin handler = new FlutterFFmpegPlugin(registrar);
+        FlutterFFmpegPlugin flutterFFmpegPlugin = new FlutterFFmpegPlugin(registrar);
 
         final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_ffmpeg");
-        channel.setMethodCallHandler(handler);
+        channel.setMethodCallHandler(flutterFFmpegPlugin);
 
         final EventChannel eventChannel = new EventChannel(registrar.messenger(), "flutter_ffmpeg_event");
-        eventChannel.setStreamHandler(handler);
+        eventChannel.setStreamHandler(flutterFFmpegPlugin);
     }
 
     private FlutterFFmpegPlugin(Registrar registrar) {
         this.registrar = registrar;
+
+        this.flutterFFmpegResultHandler = new FlutterFFmpegResultHandler();
     }
 
     private Context getActiveContext() {
@@ -115,18 +118,18 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         if (call.method.equals("getPlatform")) {
 
             final String abi = AbiDetect.getAbi();
-            result.success(toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
 
         } else if (call.method.equals("getFFmpegVersion")) {
 
             final String version = FFmpeg.getFFmpegVersion();
-            result.success(toStringMap(KEY_VERSION, version));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_VERSION, version));
 
         } else if (call.method.equals("executeWithArguments")) {
 
             List<String> arguments = call.argument("arguments");
 
-            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(arguments, result);
+            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(flutterFFmpegResultHandler, arguments, result);
             asyncTask.execute("dummy-trigger");
 
         } else if (call.method.equals("execute")) {
@@ -134,7 +137,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
             String command = call.argument("command");
             String delimiter = call.argument("delimiter");
 
-            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(delimiter, result);
+            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(flutterFFmpegResultHandler, delimiter, result);
             asyncTask.execute(command);
 
         } else if (call.method.equals("cancel")) {
@@ -152,7 +155,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getLogLevel")) {
 
             final Level level = Config.getLogLevel();
-            result.success(toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
 
         } else if (call.method.equals("setLogLevel")) {
 
@@ -192,7 +195,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         } else if (call.method.equals("getLastReceivedStatistics")) {
 
-            result.success(toMap(Config.getLastReceivedStatistics()));
+            flutterFFmpegResultHandler.success(result, toMap(Config.getLastReceivedStatistics()));
 
         } else if (call.method.equals("resetStatistics")) {
 
@@ -217,22 +220,22 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getPackageName")) {
 
             final String packageName = Config.getPackageName();
-            result.success(toStringMap(KEY_PACKAGE_NAME, packageName));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PACKAGE_NAME, packageName));
 
         } else if (call.method.equals("getExternalLibraries")) {
 
             final List<String> externalLibraries = Config.getExternalLibraries();
-            result.success(externalLibraries);
+            flutterFFmpegResultHandler.success(result, externalLibraries);
 
         } else if (call.method.equals("getLastReturnCode")) {
 
             int lastReturnCode = FFmpeg.getLastReturnCode();
-            result.success(toIntMap(KEY_LAST_RC, lastReturnCode));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LAST_RC, lastReturnCode));
 
         } else if (call.method.equals("getLastCommandOutput")) {
 
             final String lastCommandOutput = FFmpeg.getLastCommandOutput();
-            result.success(toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
 
         } else if (call.method.equals("getMediaInformation")) {
             final String path = call.argument("path");
@@ -241,11 +244,11 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
                 timeout = 10000;
             }
 
-            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(timeout, result);
+            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(flutterFFmpegResultHandler, timeout, result);
             asyncTask.execute(path);
 
         } else {
-            result.notImplemented();
+            flutterFFmpegResultHandler.notImplemented(result);
         }
     }
 
@@ -268,13 +271,13 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         logWrapperMap.put(EVENT_LOG, logMap);
 
-        eventSink.success(logWrapperMap);
+        flutterFFmpegResultHandler.success(eventSink, logWrapperMap);
     }
 
     protected void emitStatistics(final Statistics statistics) {
         final HashMap<String, Object> statisticsMap = new HashMap<>();
         statisticsMap.put(EVENT_STAT, toMap(statistics));
-        eventSink.success(statisticsMap);
+        flutterFFmpegResultHandler.success(eventSink, statisticsMap);
     }
 
     public static int levelToInt(final Level level) {

+ 77 - 0
packages/flutter_ffmpeg_min-gpl/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Taner Sener
+ *
+ * This file is part of FlutterFFmpeg.
+ *
+ * FlutterFFmpeg is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FlutterFFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FlutterFFmpeg.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.arthenica.flutter.ffmpeg;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.MethodChannel;
+
+/**
+ * <h3>Flutter FFmpeg Result Handler</h3>
+ *
+ * @author Taner Sener
+ * @since 0.2.2
+ */
+class FlutterFFmpegResultHandler {
+    private final Handler handler;
+
+    FlutterFFmpegResultHandler() {
+        handler = new Handler(Looper.getMainLooper());
+    }
+
+    void notImplemented(final MethodChannel.Result result) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.notImplemented();
+                }
+            }
+        });
+    }
+
+    void success(final MethodChannel.Result result, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.success(object);
+                }
+            }
+        });
+    }
+
+    void success(final EventChannel.EventSink eventSink, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (eventSink != null) {
+                    eventSink.success(object);
+                }
+            }
+        });
+    }
+
+}

+ 52 - 22
packages/flutter_ffmpeg_min-gpl/lib/flutter_ffmpeg.dart

@@ -22,11 +22,20 @@ import 'dart:async';
 import 'package:flutter/services.dart';
 
 class FlutterFFmpeg {
-  static const MethodChannel _methodChannel = const MethodChannel('flutter_ffmpeg');
-  static const EventChannel _eventChannel = const EventChannel('flutter_ffmpeg_event');
+  static const MethodChannel _methodChannel =
+      const MethodChannel('flutter_ffmpeg');
+  static const EventChannel _eventChannel =
+      const EventChannel('flutter_ffmpeg_event');
 
   Function(int level, String message) logCallback;
-  Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) statisticsCallback;
+  Function(
+      int time,
+      int size,
+      double bitrate,
+      double speed,
+      int videoFrameNumber,
+      double videoQuality,
+      double videoFps) statisticsCallback;
 
   FlutterFFmpeg() {
     logCallback = null;
@@ -46,8 +55,10 @@ class FlutterFFmpeg {
   void _onEvent(Object event) {
     if (event is Map<dynamic, dynamic>) {
       final Map<String, dynamic> eventMap = event.cast();
-      final Map<dynamic, dynamic> logEvent = eventMap['FlutterFFmpegLogCallback'];
-      final Map<dynamic, dynamic> statisticsEvent = eventMap['FlutterFFmpegStatisticsCallback'];
+      final Map<dynamic, dynamic> logEvent =
+          eventMap['FlutterFFmpegLogCallback'];
+      final Map<dynamic, dynamic> statisticsEvent =
+          eventMap['FlutterFFmpegStatisticsCallback'];
 
       if (logEvent != null) {
         int level = logEvent['level'];
@@ -74,10 +85,12 @@ class FlutterFFmpeg {
           double bitrate = _doublePrecision(statisticsEvent['bitrate'], 2);
           double speed = _doublePrecision(statisticsEvent['speed'], 2);
           int videoFrameNumber = statisticsEvent['videoFrameNumber'];
-          double videoQuality = _doublePrecision(statisticsEvent['videoQuality'], 2);
+          double videoQuality =
+              _doublePrecision(statisticsEvent['videoQuality'], 2);
           double videoFps = _doublePrecision(statisticsEvent['videoFps'], 2);
 
-          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber, videoQuality, videoFps);
+          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber,
+              videoQuality, videoFps);
         }
       }
     }
@@ -98,7 +111,8 @@ class FlutterFFmpeg {
   /// Returns FFmpeg version bundled within the library.
   Future<String> getFFmpegVersion() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getFFmpegVersion');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getFFmpegVersion');
       return result['version'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -109,7 +123,8 @@ class FlutterFFmpeg {
   /// Returns platform name where library is loaded.
   Future<String> getPlatform() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPlatform');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPlatform');
       return result['platform'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -120,7 +135,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg with [commandArguments] provided.
   Future<int> executeWithArguments(List<String> arguments) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('executeWithArguments', {'arguments': arguments});
+      final Map<dynamic, dynamic> result = await _methodChannel
+          .invokeMethod('executeWithArguments', {'arguments': arguments});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -131,7 +147,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg [command] provided. Command is split into arguments using provided [delimiter].
   Future<int> execute(String command, [String delimiter = ' ']) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('execute', {'command': command, 'delimiter': delimiter});
+      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod(
+          'execute', {'command': command, 'delimiter': delimiter});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -175,7 +192,8 @@ class FlutterFFmpeg {
   /// Returns log level.
   Future<int> getLogLevel() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLogLevel');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLogLevel');
       return result['level'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -241,7 +259,10 @@ class FlutterFFmpeg {
   }
 
   /// Sets a callback to redirect FFmpeg statistics. [newCallback] is a new statistics callback function, use null to disable a previously defined callback
-  void enableStatisticsCallback(Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) newCallback) {
+  void enableStatisticsCallback(
+      Function(int time, int size, double bitrate, double speed,
+              int videoFrameNumber, double videoQuality, double videoFps)
+          newCallback) {
     try {
       this.statisticsCallback = newCallback;
     } on PlatformException catch (e) {
@@ -253,7 +274,8 @@ class FlutterFFmpeg {
   /// videoQuality fields
   Future<Map<dynamic, dynamic>> getLastReceivedStatistics() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReceivedStatistics');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReceivedStatistics');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -273,14 +295,16 @@ class FlutterFFmpeg {
   /// Sets and overrides fontconfig configuration directory.
   Future<void> setFontconfigConfigurationPath(String path) async {
     try {
-      await _methodChannel.invokeMethod('setFontconfigConfigurationPath', {'path': path});
+      await _methodChannel
+          .invokeMethod('setFontconfigConfigurationPath', {'path': path});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
     }
   }
 
   /// Registers fonts inside the given [fontDirectory], so they are available to use in FFmpeg filters.
-  Future<void> setFontDirectory(String fontDirectory, Map<String, String> fontNameMap) async {
+  Future<void> setFontDirectory(
+      String fontDirectory, Map<String, String> fontNameMap) async {
     var parameters;
     if (fontNameMap == null) {
       parameters = {'fontDirectory': fontDirectory};
@@ -298,7 +322,8 @@ class FlutterFFmpeg {
   /// Returns FlutterFFmpeg package name.
   Future<String> getPackageName() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPackageName');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPackageName');
       return result['packageName'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -309,7 +334,8 @@ class FlutterFFmpeg {
   /// Returns supported external libraries.
   Future<List<dynamic>> getExternalLibraries() async {
     try {
-      final List<dynamic> result = await _methodChannel.invokeMethod('getExternalLibraries');
+      final List<dynamic> result =
+          await _methodChannel.invokeMethod('getExternalLibraries');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -320,7 +346,8 @@ class FlutterFFmpeg {
   /// Returns return code of last executed command.
   Future<int> getLastReturnCode() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReturnCode');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReturnCode');
       return result['lastRc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -332,7 +359,8 @@ class FlutterFFmpeg {
   /// [disableRedirection()] method also disables this functionality.
   Future<String> getLastCommandOutput() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastCommandOutput');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastCommandOutput');
       return result['lastCommandOutput'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -341,9 +369,11 @@ class FlutterFFmpeg {
   }
 
   /// Returns media information for given [path] using optional [timeout]
-  Future<Map<dynamic, dynamic>> getMediaInformation(String path, [int timeout = 10000]) async {
+  Future<Map<dynamic, dynamic>> getMediaInformation(String path,
+      [int timeout = 10000]) async {
     try {
-      return await _methodChannel.invokeMethod('getMediaInformation', {'path': path, 'timeout': timeout});
+      return await _methodChannel.invokeMethod(
+          'getMediaInformation', {'path': path, 'timeout': timeout});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
       return null;

+ 3 - 3
packages/flutter_ffmpeg_min-gpl/pubspec.yaml

@@ -1,6 +1,6 @@
 name: flutter_ffmpeg
-description: Flutter plugin to run FFmpeg in the mobile platform. Supports iOS and Android.
-version: 0.2.1
+description: Flutter plugin to run FFmpeg on mobile platforms. Supports iOS and Android.
+version: 0.2.2
 author: Taner Sener <tanersener@gmail.com>
 homepage: https://github.com/tanersener/flutter-ffmpeg
 
@@ -12,7 +12,7 @@ dependencies:
     sdk: flutter
 
 dev_dependencies:
-  path_provider: ^0.5.0+1
+  path_provider: ^1.1.0
   path: ^1.6.2
 
 flutter:

+ 2 - 1
packages/flutter_ffmpeg_min-gpl_lts/.gitignore

@@ -3,5 +3,6 @@
 .dart_tool/
 .pub/
 build/
-pubspec.lock
+/pubspec.lock
 /.packages
+/.gradle/

+ 4 - 2
packages/flutter_ffmpeg_min-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncArgumentsTask.java

@@ -39,10 +39,12 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     private final MethodChannel.Result result;
     private final List<String> arguments;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncArgumentsTask(final List<String> arguments, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncArgumentsTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final List<String> arguments, final MethodChannel.Result result) {
         this.arguments = arguments;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -60,7 +62,7 @@ public class FlutterFFmpegExecuteAsyncArgumentsTask extends AsyncTask<String, In
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_min-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegExecuteAsyncCommandTask.java

@@ -36,8 +36,9 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     private String delimiter;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegExecuteAsyncCommandTask(final String delimiter, final MethodChannel.Result result) {
+    FlutterFFmpegExecuteAsyncCommandTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final String delimiter, final MethodChannel.Result result) {
         if (delimiter == null) {
             this.delimiter = " ";
         } else {
@@ -45,6 +46,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
         }
 
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -66,7 +68,7 @@ public class FlutterFFmpegExecuteAsyncCommandTask extends AsyncTask<String, Inte
 
     @Override
     protected void onPostExecute(final Integer rc) {
-        result.success(FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toIntMap(FlutterFFmpegPlugin.KEY_RC, rc));
     }
 
 }

+ 4 - 2
packages/flutter_ffmpeg_min-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegGetMediaInformationAsyncTask.java

@@ -37,10 +37,12 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     private Integer timeout;
     private final MethodChannel.Result result;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
-    FlutterFFmpegGetMediaInformationAsyncTask(final Integer timeout, final MethodChannel.Result result) {
+    FlutterFFmpegGetMediaInformationAsyncTask(final FlutterFFmpegResultHandler flutterFFmpegResultHandler, final Integer timeout, final MethodChannel.Result result) {
         this.timeout = timeout;
         this.result = result;
+        this.flutterFFmpegResultHandler = flutterFFmpegResultHandler;
     }
 
     @Override
@@ -64,7 +66,7 @@ public class FlutterFFmpegGetMediaInformationAsyncTask extends AsyncTask<String,
 
     @Override
     protected void onPostExecute(final MediaInformation mediaInformation) {
-        result.success(FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
+        flutterFFmpegResultHandler.success(result, FlutterFFmpegPlugin.toMediaInformationMap(mediaInformation));
     }
 
 }

+ 20 - 17
packages/flutter_ffmpeg_min-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegPlugin.java

@@ -80,6 +80,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
     private EventChannel.EventSink eventSink;
     private final Registrar registrar;
+    private final FlutterFFmpegResultHandler flutterFFmpegResultHandler;
 
     /**
      * Registers plugin to registry.
@@ -87,17 +88,19 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
      * @param registrar receiver of plugin registration
      */
     public static void registerWith(final Registrar registrar) {
-        FlutterFFmpegPlugin handler = new FlutterFFmpegPlugin(registrar);
+        FlutterFFmpegPlugin flutterFFmpegPlugin = new FlutterFFmpegPlugin(registrar);
 
         final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_ffmpeg");
-        channel.setMethodCallHandler(handler);
+        channel.setMethodCallHandler(flutterFFmpegPlugin);
 
         final EventChannel eventChannel = new EventChannel(registrar.messenger(), "flutter_ffmpeg_event");
-        eventChannel.setStreamHandler(handler);
+        eventChannel.setStreamHandler(flutterFFmpegPlugin);
     }
 
     private FlutterFFmpegPlugin(Registrar registrar) {
         this.registrar = registrar;
+
+        this.flutterFFmpegResultHandler = new FlutterFFmpegResultHandler();
     }
 
     private Context getActiveContext() {
@@ -115,18 +118,18 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         if (call.method.equals("getPlatform")) {
 
             final String abi = AbiDetect.getAbi();
-            result.success(toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PLATFORM, PLATFORM_NAME + "-" + abi));
 
         } else if (call.method.equals("getFFmpegVersion")) {
 
             final String version = FFmpeg.getFFmpegVersion();
-            result.success(toStringMap(KEY_VERSION, version));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_VERSION, version));
 
         } else if (call.method.equals("executeWithArguments")) {
 
             List<String> arguments = call.argument("arguments");
 
-            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(arguments, result);
+            final FlutterFFmpegExecuteAsyncArgumentsTask asyncTask = new FlutterFFmpegExecuteAsyncArgumentsTask(flutterFFmpegResultHandler, arguments, result);
             asyncTask.execute("dummy-trigger");
 
         } else if (call.method.equals("execute")) {
@@ -134,7 +137,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
             String command = call.argument("command");
             String delimiter = call.argument("delimiter");
 
-            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(delimiter, result);
+            final FlutterFFmpegExecuteAsyncCommandTask asyncTask = new FlutterFFmpegExecuteAsyncCommandTask(flutterFFmpegResultHandler, delimiter, result);
             asyncTask.execute(command);
 
         } else if (call.method.equals("cancel")) {
@@ -152,7 +155,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getLogLevel")) {
 
             final Level level = Config.getLogLevel();
-            result.success(toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LOG_LEVEL, levelToInt(level)));
 
         } else if (call.method.equals("setLogLevel")) {
 
@@ -192,7 +195,7 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         } else if (call.method.equals("getLastReceivedStatistics")) {
 
-            result.success(toMap(Config.getLastReceivedStatistics()));
+            flutterFFmpegResultHandler.success(result, toMap(Config.getLastReceivedStatistics()));
 
         } else if (call.method.equals("resetStatistics")) {
 
@@ -217,22 +220,22 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
         } else if (call.method.equals("getPackageName")) {
 
             final String packageName = Config.getPackageName();
-            result.success(toStringMap(KEY_PACKAGE_NAME, packageName));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_PACKAGE_NAME, packageName));
 
         } else if (call.method.equals("getExternalLibraries")) {
 
             final List<String> externalLibraries = Config.getExternalLibraries();
-            result.success(externalLibraries);
+            flutterFFmpegResultHandler.success(result, externalLibraries);
 
         } else if (call.method.equals("getLastReturnCode")) {
 
             int lastReturnCode = FFmpeg.getLastReturnCode();
-            result.success(toIntMap(KEY_LAST_RC, lastReturnCode));
+            flutterFFmpegResultHandler.success(result, toIntMap(KEY_LAST_RC, lastReturnCode));
 
         } else if (call.method.equals("getLastCommandOutput")) {
 
             final String lastCommandOutput = FFmpeg.getLastCommandOutput();
-            result.success(toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
+            flutterFFmpegResultHandler.success(result, toStringMap(KEY_LAST_COMMAND_OUTPUT, lastCommandOutput));
 
         } else if (call.method.equals("getMediaInformation")) {
             final String path = call.argument("path");
@@ -241,11 +244,11 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
                 timeout = 10000;
             }
 
-            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(timeout, result);
+            final FlutterFFmpegGetMediaInformationAsyncTask asyncTask = new FlutterFFmpegGetMediaInformationAsyncTask(flutterFFmpegResultHandler, timeout, result);
             asyncTask.execute(path);
 
         } else {
-            result.notImplemented();
+            flutterFFmpegResultHandler.notImplemented(result);
         }
     }
 
@@ -268,13 +271,13 @@ public class FlutterFFmpegPlugin implements MethodCallHandler, EventChannel.Stre
 
         logWrapperMap.put(EVENT_LOG, logMap);
 
-        eventSink.success(logWrapperMap);
+        flutterFFmpegResultHandler.success(eventSink, logWrapperMap);
     }
 
     protected void emitStatistics(final Statistics statistics) {
         final HashMap<String, Object> statisticsMap = new HashMap<>();
         statisticsMap.put(EVENT_STAT, toMap(statistics));
-        eventSink.success(statisticsMap);
+        flutterFFmpegResultHandler.success(eventSink, statisticsMap);
     }
 
     public static int levelToInt(final Level level) {

+ 77 - 0
packages/flutter_ffmpeg_min-gpl_lts/android/src/main/java/com/arthenica/flutter/ffmpeg/FlutterFFmpegResultHandler.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Taner Sener
+ *
+ * This file is part of FlutterFFmpeg.
+ *
+ * FlutterFFmpeg is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FlutterFFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FlutterFFmpeg.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.arthenica.flutter.ffmpeg;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.MethodChannel;
+
+/**
+ * <h3>Flutter FFmpeg Result Handler</h3>
+ *
+ * @author Taner Sener
+ * @since 0.2.2
+ */
+class FlutterFFmpegResultHandler {
+    private final Handler handler;
+
+    FlutterFFmpegResultHandler() {
+        handler = new Handler(Looper.getMainLooper());
+    }
+
+    void notImplemented(final MethodChannel.Result result) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.notImplemented();
+                }
+            }
+        });
+    }
+
+    void success(final MethodChannel.Result result, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (result != null) {
+                    result.success(object);
+                }
+            }
+        });
+    }
+
+    void success(final EventChannel.EventSink eventSink, final Object object) {
+        handler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                if (eventSink != null) {
+                    eventSink.success(object);
+                }
+            }
+        });
+    }
+
+}

+ 52 - 22
packages/flutter_ffmpeg_min-gpl_lts/lib/flutter_ffmpeg.dart

@@ -22,11 +22,20 @@ import 'dart:async';
 import 'package:flutter/services.dart';
 
 class FlutterFFmpeg {
-  static const MethodChannel _methodChannel = const MethodChannel('flutter_ffmpeg');
-  static const EventChannel _eventChannel = const EventChannel('flutter_ffmpeg_event');
+  static const MethodChannel _methodChannel =
+      const MethodChannel('flutter_ffmpeg');
+  static const EventChannel _eventChannel =
+      const EventChannel('flutter_ffmpeg_event');
 
   Function(int level, String message) logCallback;
-  Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) statisticsCallback;
+  Function(
+      int time,
+      int size,
+      double bitrate,
+      double speed,
+      int videoFrameNumber,
+      double videoQuality,
+      double videoFps) statisticsCallback;
 
   FlutterFFmpeg() {
     logCallback = null;
@@ -46,8 +55,10 @@ class FlutterFFmpeg {
   void _onEvent(Object event) {
     if (event is Map<dynamic, dynamic>) {
       final Map<String, dynamic> eventMap = event.cast();
-      final Map<dynamic, dynamic> logEvent = eventMap['FlutterFFmpegLogCallback'];
-      final Map<dynamic, dynamic> statisticsEvent = eventMap['FlutterFFmpegStatisticsCallback'];
+      final Map<dynamic, dynamic> logEvent =
+          eventMap['FlutterFFmpegLogCallback'];
+      final Map<dynamic, dynamic> statisticsEvent =
+          eventMap['FlutterFFmpegStatisticsCallback'];
 
       if (logEvent != null) {
         int level = logEvent['level'];
@@ -74,10 +85,12 @@ class FlutterFFmpeg {
           double bitrate = _doublePrecision(statisticsEvent['bitrate'], 2);
           double speed = _doublePrecision(statisticsEvent['speed'], 2);
           int videoFrameNumber = statisticsEvent['videoFrameNumber'];
-          double videoQuality = _doublePrecision(statisticsEvent['videoQuality'], 2);
+          double videoQuality =
+              _doublePrecision(statisticsEvent['videoQuality'], 2);
           double videoFps = _doublePrecision(statisticsEvent['videoFps'], 2);
 
-          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber, videoQuality, videoFps);
+          this.statisticsCallback(time, size, bitrate, speed, videoFrameNumber,
+              videoQuality, videoFps);
         }
       }
     }
@@ -98,7 +111,8 @@ class FlutterFFmpeg {
   /// Returns FFmpeg version bundled within the library.
   Future<String> getFFmpegVersion() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getFFmpegVersion');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getFFmpegVersion');
       return result['version'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -109,7 +123,8 @@ class FlutterFFmpeg {
   /// Returns platform name where library is loaded.
   Future<String> getPlatform() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPlatform');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPlatform');
       return result['platform'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -120,7 +135,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg with [commandArguments] provided.
   Future<int> executeWithArguments(List<String> arguments) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('executeWithArguments', {'arguments': arguments});
+      final Map<dynamic, dynamic> result = await _methodChannel
+          .invokeMethod('executeWithArguments', {'arguments': arguments});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -131,7 +147,8 @@ class FlutterFFmpeg {
   /// Executes FFmpeg [command] provided. Command is split into arguments using provided [delimiter].
   Future<int> execute(String command, [String delimiter = ' ']) async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('execute', {'command': command, 'delimiter': delimiter});
+      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod(
+          'execute', {'command': command, 'delimiter': delimiter});
       return result['rc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -175,7 +192,8 @@ class FlutterFFmpeg {
   /// Returns log level.
   Future<int> getLogLevel() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLogLevel');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLogLevel');
       return result['level'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -241,7 +259,10 @@ class FlutterFFmpeg {
   }
 
   /// Sets a callback to redirect FFmpeg statistics. [newCallback] is a new statistics callback function, use null to disable a previously defined callback
-  void enableStatisticsCallback(Function(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) newCallback) {
+  void enableStatisticsCallback(
+      Function(int time, int size, double bitrate, double speed,
+              int videoFrameNumber, double videoQuality, double videoFps)
+          newCallback) {
     try {
       this.statisticsCallback = newCallback;
     } on PlatformException catch (e) {
@@ -253,7 +274,8 @@ class FlutterFFmpeg {
   /// videoQuality fields
   Future<Map<dynamic, dynamic>> getLastReceivedStatistics() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReceivedStatistics');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReceivedStatistics');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -273,14 +295,16 @@ class FlutterFFmpeg {
   /// Sets and overrides fontconfig configuration directory.
   Future<void> setFontconfigConfigurationPath(String path) async {
     try {
-      await _methodChannel.invokeMethod('setFontconfigConfigurationPath', {'path': path});
+      await _methodChannel
+          .invokeMethod('setFontconfigConfigurationPath', {'path': path});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
     }
   }
 
   /// Registers fonts inside the given [fontDirectory], so they are available to use in FFmpeg filters.
-  Future<void> setFontDirectory(String fontDirectory, Map<String, String> fontNameMap) async {
+  Future<void> setFontDirectory(
+      String fontDirectory, Map<String, String> fontNameMap) async {
     var parameters;
     if (fontNameMap == null) {
       parameters = {'fontDirectory': fontDirectory};
@@ -298,7 +322,8 @@ class FlutterFFmpeg {
   /// Returns FlutterFFmpeg package name.
   Future<String> getPackageName() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getPackageName');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getPackageName');
       return result['packageName'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -309,7 +334,8 @@ class FlutterFFmpeg {
   /// Returns supported external libraries.
   Future<List<dynamic>> getExternalLibraries() async {
     try {
-      final List<dynamic> result = await _methodChannel.invokeMethod('getExternalLibraries');
+      final List<dynamic> result =
+          await _methodChannel.invokeMethod('getExternalLibraries');
       return result;
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -320,7 +346,8 @@ class FlutterFFmpeg {
   /// Returns return code of last executed command.
   Future<int> getLastReturnCode() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastReturnCode');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastReturnCode');
       return result['lastRc'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -332,7 +359,8 @@ class FlutterFFmpeg {
   /// [disableRedirection()] method also disables this functionality.
   Future<String> getLastCommandOutput() async {
     try {
-      final Map<dynamic, dynamic> result = await _methodChannel.invokeMethod('getLastCommandOutput');
+      final Map<dynamic, dynamic> result =
+          await _methodChannel.invokeMethod('getLastCommandOutput');
       return result['lastCommandOutput'];
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
@@ -341,9 +369,11 @@ class FlutterFFmpeg {
   }
 
   /// Returns media information for given [path] using optional [timeout]
-  Future<Map<dynamic, dynamic>> getMediaInformation(String path, [int timeout = 10000]) async {
+  Future<Map<dynamic, dynamic>> getMediaInformation(String path,
+      [int timeout = 10000]) async {
     try {
-      return await _methodChannel.invokeMethod('getMediaInformation', {'path': path, 'timeout': timeout});
+      return await _methodChannel.invokeMethod(
+          'getMediaInformation', {'path': path, 'timeout': timeout});
     } on PlatformException catch (e) {
       print("Plugin error: ${e.message}");
       return null;

+ 3 - 3
packages/flutter_ffmpeg_min-gpl_lts/pubspec.yaml

@@ -1,6 +1,6 @@
 name: flutter_ffmpeg
-description: Flutter plugin to run FFmpeg in the mobile platform. Supports iOS and Android.
-version: 0.2.1
+description: Flutter plugin to run FFmpeg on mobile platforms. Supports iOS and Android.
+version: 0.2.2
 author: Taner Sener <tanersener@gmail.com>
 homepage: https://github.com/tanersener/flutter-ffmpeg
 
@@ -12,7 +12,7 @@ dependencies:
     sdk: flutter
 
 dev_dependencies:
-  path_provider: ^0.5.0+1
+  path_provider: ^1.1.0
   path: ^1.6.2
 
 flutter:

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff