diff --git a/CHANGELOG.md b/CHANGELOG.md
index c1fa361..91b1523 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,8 @@
- Adds setEnvironmentVariable API method
- Depends on mobile-ffmpeg v4.4
- Allows modifying mobile-ffmpeg version for android
-- Fixes issue #115, #120 and #178
+- Includes an updated example application
+- Fixes issue #115, #120, #157, #159, #170, #178 and #202
## 0.2.10
- Fixes issue #94
diff --git a/README.md b/README.md
index 13ec062..d367aca 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# flutter_ffmpeg
-![GitHub release](https://img.shields.io/badge/release-v0.2.10-blue.svg)
+![GitHub release](https://img.shields.io/badge/release-v0.3.0-blue.svg)
![](https://img.shields.io/pub/v/flutter_ffmpeg.svg)
FFmpeg plugin for Flutter. Supports iOS and Android.
@@ -13,12 +13,12 @@ FFmpeg plugin for Flutter. Supports iOS and Android.
- Supports
- Both `Android` and `iOS`
- Both Android (API Level 16+) and iOS (SDK 9.3+)
- - FFmpeg `v4.1`, `v4.2` and `v4.3-dev` releases
+ - FFmpeg `v4.1`, `v4.2` , `v4.3` and `v4.4-dev` 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
- - 24 external libraries
+ - 25 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`
+ `fontconfig`, `freetype`, `fribidi`, `gmp`, `gnutls`, `kvazaar`, `lame`, `libaom`, `libass`, `libiconv`, `libilbc`, `libtheora`, `libvorbis`, `libvpx`, `libwebp`, `libxml2`, `opencore-amr`, `opus`, `shine`, `snappy`, `soxr`, `speex`, `twolame`, `vo-amrwbenc`, `wavpack`
- 4 external libraries with GPL license
@@ -26,23 +26,41 @@ FFmpeg plugin for Flutter. Supports iOS and Android.
- Concurrent execution
- `zlib` and `MediaCodec` Android system libraries
- - `bzip2`, `zlib`, `iconv` iOS system libraries and `AudioToolbox`, `CoreImage`, `VideoToolbox`, `AVFoundation` iOS system frameworks
+ - `bzip2`, `iconv`, `libuuid`, `zlib` system libraries and `AudioToolbox`, `VideoToolbox`, `AVFoundation` 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
+
+### 2. Installation
+
+Add `flutter_ffmpeg` as a dependency in your `pubspec.yaml file`.
+ ```
+dependencies:
+ flutter_ffmpeg: ^0.3.0
+ ```
+
+#### 2.1 Packages
+
+`ffmpeg` includes built-in encoders for some popular formats bu not for all of them. External libraries are necessary
+to encode some specific codecs/formats. For example, to encode an `mp3` file you need `lame` or `shine` library
+enabled. You have to install `flutter_ffmpeg` a package that has them inside. To encode an `h264` video you need to
+install a package with `x264` inside. To encode `vp8` or `vp9` videos you need a package with `libvpx` inside.
+
+`flutter_ffmpeg` provides eight different packages that include different sets of external libraries. Packages are
+named according to the external libraries included in them. Below you can see which libraries are enabled in each one
+of them.
|
-min |
-min-gpl |
-https |
-https-gpl |
-audio |
-video |
-full |
-full-gpl |
+min |
+min-gpl |
+https |
+https-gpl |
+audio |
+video |
+full |
+full-gpl |
@@ -52,10 +70,10 @@ FFmpeg plugin for Flutter. Supports iOS and Android.
vid.stab x264 x265 xvidcore |
gmp gnutls |
gmp gnutls vid.stab x264 x265 xvidcore |
-lame libilbc libvorbis opencore-amr opus shine soxr speex twolame wavpack |
+lame libilbc libvorbis opencore-amr opus shine soxr speex twolame vo-amrwbenc wavpack |
fontconfig freetype fribidi kvazaar libaom libass libiconv libtheora libvpx libwebp snappy |
-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 |
-fontconfig freetype fribidi gmp gnutls kvazaar lame libaom libass libiconv libilbc libtheora libvorbis libvpx libwebp libxml2 opencore-amr opus shine snappy soxr speex twolame vid.stab wavpack x264 x265 xvidcore |
+fontconfig freetype fribidi gmp gnutls kvazaar lame libaom libass libiconv libilbc libtheora libvorbis libvpx libwebp libxml2 opencore-amr opus shine snappy soxr speex twolame vo-amrwbenc wavpack |
+fontconfig freetype fribidi gmp gnutls kvazaar lame libaom libass libiconv libilbc libtheora libvorbis libvpx libwebp libxml2 opencore-amr opus shine snappy soxr speex twolame vid.stab vo-amrwbenc wavpack x264 x265 xvidcore |
android system libraries |
@@ -63,22 +81,13 @@ FFmpeg plugin for Flutter. Supports iOS and Android.
ios system libraries |
-zlib AudioToolbox AVFoundation CoreImage iconv VideoToolbox bzip2 |
+zlib AudioToolbox AVFoundation iconv VideoToolbox bzip2 |
-### 2. Installation
-
-Add `flutter_ffmpeg` as a dependency in your `pubspec.yaml file`.
- ```
-dependencies:
- flutter_ffmpeg: ^0.2.10
- ```
-
-#### 2.1 Packages
-
-Installation of `FlutterFFmpeg` using `pub` enables the default package, which is based on `https` package. It is possible to enable other packages using the following steps.
+Installation of `FlutterFFmpeg` using `pub` enables the default package, which is based on `https` package. It is
+possible to enable other packages using the following steps.
##### 2.1.1 Android
@@ -90,8 +99,49 @@ Installation of `FlutterFFmpeg` using `pub` enables the default package, which i
}
```
+##### 2.1.2 iOS (Flutter >= 1.20.x)
+
+- Edit `ios/Podfile` and add the following block **before** `target 'Runner do` section :
+
+ ```
+ # "fork" of method flutter_install_ios_plugin_pods (in fluttertools podhelpers.rb) to get lts version of ffmpeg
+ def flutter_install_ios_plugin_pods(ios_application_path = nil)
+ # defined_in_file is set by CocoaPods and is a Pathname to the Podfile.
+ ios_application_path ||= File.dirname(defined_in_file.realpath) if self.respond_to?(:defined_in_file)
+ raise 'Could not find iOS application path' unless ios_application_path
+
+ # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
+ # referring to absolute paths on developers' machines.
+
+ symlink_dir = File.expand_path('.symlinks', ios_application_path)
+ system('rm', '-rf', symlink_dir) # Avoid the complication of dependencies like FileUtils.
+
+ symlink_plugins_dir = File.expand_path('plugins', symlink_dir)
+ system('mkdir', '-p', symlink_plugins_dir)
+
+ plugins_file = File.join(ios_application_path, '..', '.flutter-plugins-dependencies')
+ plugin_pods = flutter_parse_plugins_file(plugins_file)
+ plugin_pods.each do |plugin_hash|
+ plugin_name = plugin_hash['name']
+ plugin_path = plugin_hash['path']
+
+ if (plugin_name && plugin_path)
+ symlink = File.join(symlink_plugins_dir, plugin_name)
+ File.symlink(plugin_path, symlink)
+
+ if plugin_name == 'flutter_ffmpeg'
+ pod plugin_name+'/', :path => File.join('.symlinks', 'plugins', plugin_name, 'ios')
+ else
+ pod plugin_name, :path => File.join('.symlinks', 'plugins', plugin_name, 'ios')
+ end
+ end
+ end
+ ```
+- Ensure that `flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))` function is called
+within `target 'Runner' do` block. In that case, it is mandatory that the added function is
+named `flutter_install_ios_plugin_pods` and that you **do not** make an explicit call within that block.
-##### 2.1.2 iOS
+##### 2.1.3 iOS (Flutter < 1.20.x)
- Edit `ios/Podfile` file and modify the default `# Plugin Pods` block as follows.
Do not forget to specify package name in `` section.
@@ -113,7 +163,7 @@ Installation of `FlutterFFmpeg` using `pub` enables the default package, which i
end
```
-##### 2.1.3 Package Names
+##### 2.1.4 Package Names
The following table shows all package names defined for `flutter_ffmpeg`.
@@ -143,55 +193,23 @@ Please execute the following additional steps if you are integrating into an iOS
#### 2.3 LTS Releases
-`flutter_ffmpeg` is published in two different variants: `Main Release` and `LTS Release`. Both releases share the same source code but is built with different settings. Below you can see the changes between the two.
+`flutter_ffmpeg` is published in two different variants: `Main Release` and `LTS Release`. Both releases share the same source code but is built with different settings. Below you can see the differences between the two.
In order to install the `LTS` variant, install the `https-lts` package using instructions in `2.1` or append `-lts` to the package name you are using.
-
-
-
- |
- Main Release |
- LTS Release |
-
-
-
-
- Android API Level |
- 24 |
- 16 |
-
-
- Android Camera Access |
- Yes |
- - |
-
-
- Android Architectures |
- arm-v7a-neon arm64-v8a x86 x86-64 |
- arm-v7a arm-v7a-neon arm64-v8a x86 x86-64 |
-
-
- Xcode Support |
- 10.1 |
- 7.3.1 |
-
-
- iOS SDK |
- 12.1 |
- 9.3 |
-
-
- iOS Architectures |
- arm64 arm64e x86-64 |
- armv7 arm64 i386 x86-64 |
-
-
-
+| | Main Release | LTS Release |
+| :----: | :----: | :----: |
+| Android API Level | 24 | 16 |
+| Android Camera Access | Yes | - |
+| Android Architectures | arm-v7a-neon
arm64-v8a
x86
x86-64 | arm-v7a
arm-v7a-neon
arm64-v8a
x86
x86-64 |
+| Xcode Support | 10.1 | 7.3.1 |
+| iOS SDK | 11.0 | 9.3 |
+| iOS AVFoundation | Yes | - |
+| iOS Architectures | arm64
x86-64
x86-64-mac-catalyst | armv7
arm64
i386
x86-64 |
### 3. Using
-1. Execute FFmpeg commands.
+1. Execute synchronous FFmpeg commands.
- Use execute() method with a single command line
```
@@ -212,8 +230,15 @@ In order to install the `LTS` variant, install the `https-lts` package using ins
var arguments = ["-i", "file1.mp4", "-c:v", "mpeg4", "file2.mp4"];
_flutterFFmpeg.executeWithArguments(arguments).then((rc) => print("FFmpeg process exited with rc $rc"));
```
+2. Execute asynchronous FFmpeg commands.
-2. Execute FFprobe commands.
+ ```
+ _flutterFFmpeg.executeAsync(ffmpegCommand, (int executionId, int returnCode) {
+ print("FFmpeg process for executionId $executionId exited with rc $returnCode");
+ }).then((executionId) => print("Async FFmpeg process started with executionId $executionId."));
+ ```
+
+3. Execute FFprobe commands.
- Use execute() method with a single command line
```
@@ -235,7 +260,7 @@ In order to install the `LTS` variant, install the `https-lts` package using ins
_flutterFFprobe.executeWithArguments(arguments).then((rc) => print("FFprobe process exited with rc $rc"));
```
-3. Check execution output. Zero represents successful execution, non-zero values represent failure.
+4. Check execution output. Zero represents successful execution, 255 means user cancel and non-zero values represent failure.
```
final FlutterFFmpegConfig _flutterFFmpegConfig = new FlutterFFmpegConfig();
@@ -245,12 +270,17 @@ In order to install the `LTS` variant, install the `https-lts` package using ins
_flutterFFmpegConfig.getLastCommandOutput().then((output) => print("Last command output: $output"));
```
-4. Stop an ongoing operation. Note that this function does not wait for termination to complete and returns immediately.
- ```
- _flutterFFmpeg.cancel();
- ```
+5. Stop ongoing FFmpeg operations. Note that these two functions do not wait for termination to complete and return immediately.
+ - Stop all executions
+ ```
+ _flutterFFmpeg.cancel();
+ ```
+ - Stop a specific execution
+ ```
+ _flutterFFmpeg.cancelExecution(executionId);
+ ```
-5. Get media information for a file.
+6. Get media information for a file.
- Print all fields
```
final FlutterFFprobe _flutterFFprobe = new FlutterFFprobe();
@@ -264,37 +294,43 @@ In order to install the `LTS` variant, install the `https-lts` package using ins
_flutterFFprobe.getMediaInformation("").then((info) {
print("Media Information");
- print("Path: ${info['path']}");
- print("Format: ${info['format']}");
- print("Duration: ${info['duration']}");
- print("Start time: ${info['startTime']}");
- print("Bitrate: ${info['bitrate']}");
-
- if (info['streams'] != null) {
- final streamsInfoArray = info['streams'];
-
- if (streamsInfoArray.length > 0) {
- for (var streamsInfo in streamsInfoArray) {
- print("Stream id: ${streamsInfo['index']}");
- print("Stream type: ${streamsInfo['type']}");
- print("Stream codec: ${streamsInfo['codec']}");
- print("Stream full codec: ${streamsInfo['fullCodec']}");
- print("Stream format: ${streamsInfo['format']}");
- print("Stream full format: ${streamsInfo['fullFormat']}");
- print("Stream width: ${streamsInfo['width']}");
- print("Stream height: ${streamsInfo['height']}");
- print("Stream bitrate: ${streamsInfo['bitrate']}");
- print("Stream sample rate: ${streamsInfo['sampleRate']}");
- print("Stream sample format: ${streamsInfo['sampleFormat']}");
- print("Stream channel layout: ${streamsInfo['channelLayout']}");
- print("Stream sar: ${streamsInfo['sampleAspectRatio']}");
- print("Stream dar: ${streamsInfo['displayAspectRatio']}");
- print("Stream average frame rate: ${streamsInfo['averageFrameRate']}");
- print("Stream real frame rate: ${streamsInfo['realFrameRate']}");
- print("Stream time base: ${streamsInfo['timeBase']}");
- print("Stream codec time base: ${streamsInfo['codecTimeBase']}");
-
- final metadataMap = streamsInfo['metadata'];
+ print("Path: ${info.getMediaProperties()['path']}");
+ print("Format: ${info.getMediaProperties()['format']}");
+ print("Duration: ${info.getMediaProperties()['duration']}");
+ print("Start time: ${info.getMediaProperties()['startTime']}");
+ print("Bitrate: ${info.getMediaProperties()['bitrate']}");
+ Map tags = info.getMediaProperties()['tags'];
+ if (tags != null) {
+ tags.forEach((key, value) {
+ print("Tag: " + key + ":" + value + "\n");
+ });
+ }
+
+ if (info.getStreams() != null) {
+ List streams = info.getStreams();
+
+ if (streams.length > 0) {
+ for (var stream in streams) {
+ print("Stream id: ${stream.getAllProperties()['index']}");
+ print("Stream type: ${stream.getAllProperties()['type']}");
+ print("Stream codec: ${stream.getAllProperties()['codec']}");
+ print("Stream full codec: ${stream.getAllProperties()['fullCodec']}");
+ print("Stream format: ${stream.getAllProperties()['format']}");
+ print("Stream full format: ${stream.getAllProperties()['fullFormat']}");
+ print("Stream width: ${stream.getAllProperties()['width']}");
+ print("Stream height: ${stream.getAllProperties()['height']}");
+ print("Stream bitrate: ${stream.getAllProperties()['bitrate']}");
+ print("Stream sample rate: ${stream.getAllProperties()['sampleRate']}");
+ print("Stream sample format: ${stream.getAllProperties()['sampleFormat']}");
+ print("Stream channel layout: ${stream.getAllProperties()['channelLayout']}");
+ print("Stream sar: ${stream.getAllProperties()['sampleAspectRatio']}");
+ print("Stream dar: ${stream.getAllProperties()['displayAspectRatio']}");
+ print("Stream average frame rate: ${stream.getAllProperties()['averageFrameRate']}");
+ print("Stream real frame rate: ${stream.getAllProperties()['realFrameRate']}");
+ print("Stream time base: ${stream.getAllProperties()['timeBase']}");
+ print("Stream codec time base: ${stream.getAllProperties()['codecTimeBase']}");
+
+ final metadataMap = stream.getAllProperties()['metadata'];
if (metadataMap != null) {
print('Stream metadata encoder: ${metadataMap['encoder']}');
print('Stream metadata rotate: ${metadataMap['rotate']}');
@@ -302,7 +338,7 @@ In order to install the `LTS` variant, install the `https-lts` package using ins
print('Stream metadata handler name: ${metadataMap['handler_name']}');
}
- final sideDataMap = streamsInfo['sidedata'];
+ final sideDataMap = stream.getAllProperties()['sidedata'];
if (sideDataMap != null) {
print('Stream side data displaymatrix: ${sideDataMap['displaymatrix']}');
}
@@ -312,78 +348,85 @@ In order to install the `LTS` variant, install the `https-lts` package using ins
```
-6. Enable log callback and redirect all `FFmpeg`/`FFprobe` logs to a console/file/widget.
+7. Enable log callback and redirect all `FFmpeg`/`FFprobe` logs to a console/file/widget.
```
- void logCallback(int level, String message) {
- print(message);
+ void logCallback(Log log) {
+ print("${log.executionId}:${log.message}");
}
...
_flutterFFmpegConfig.enableLogCallback(this.logCallback);
```
-7. Enable statistics callback and follow the progress of an ongoing `FFmpeg` operation.
+8. Enable statistics callback and follow the progress of an ongoing `FFmpeg` operation.
```
- void statisticsCallback(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) {
- print("Statistics: time: $time, size: $size, bitrate: $bitrate, speed: $speed, videoFrameNumber: $videoFrameNumber, videoQuality: $videoQuality, videoFps: $videoFps");
+ void statisticsCallback(Statistics statistics) {
+ print("Statistics: executionId: ${statistics.executionId}, time: ${statistics.time}, size: ${statistics.size}, bitrate: ${statistics.bitrate}, speed: ${statistics.speed}, videoFrameNumber: ${statistics.videoFrameNumber}, videoQuality: ${statistics.videoQuality}, videoFps: ${statistics.videoFps}");
}
...
_flutterFFmpegConfig.enableStatisticsCallback(this.statisticsCallback);
```
-8. Poll statistics without implementing statistics callback.
+9. Poll statistics without implementing statistics callback.
```
_flutterFFmpegConfig.getLastReceivedStatistics().then((stats) => print(stats));
```
-9. Reset statistics before starting a new operation.
+10. List ongoing executions.
```
- _flutterFFmpegConfig.resetStatistics();
+ _flutterFFmpeg.listExecutions().then((ffmpegExecutions) {
+ ffmpegExecutions.forEach((execution) {
+ ffprint(
+ "Execution id:${execution.executionId}, startTime:${execution.command}, command:${execution.startTime}.");
+ });
+ });
```
-10. Set log level.
+11. Set log level.
```
_flutterFFmpegConfig.setLogLevel(LogLevel.AV_LOG_WARNING);
```
-11. Register your own fonts by specifying a custom fonts directory, so they are available to use in `FFmpeg` filters. Please note that this function can not work on relative paths, you need to provide full file system path.
+12. Register your own fonts by specifying a custom fonts directory, so they are available to use in `FFmpeg` filters. Please note that this function can not work on relative paths, you need to provide full file system path.
```
_flutterFFmpegConfig.setFontDirectory("");
```
-12. Use your own `fontconfig` configuration.
+13. Use your own `fontconfig` configuration.
```
_flutterFFmpegConfig.setFontconfigConfigurationPath("");
```
-13. Disable log functionality of the library. Logs will not be printed to console and log callback will be disabled.
+14. Disable log functionality of the library. Logs will not be printed to console and log callback will be disabled.
```
_flutterFFmpegConfig.disableLogs();
```
-14. Disable statistics functionality of the library. Statistics callback will be disabled but the last received statistics data will be still available.
+15. Disable statistics functionality of the library. Statistics callback will be disabled but the last received statistics data will be still available.
```
_flutterFFmpegConfig.disableStatistics();
```
-15. List enabled external libraries.
- ```
- _flutterFFmpegConfig.getExternalLibraries().then((packageList) {
- packageList.forEach((value) => print("External library: $value"));
- });
- ```
16. Create new `FFmpeg` pipe.
```
_flutterFFmpegConfig.registerNewFFmpegPipe().then((path) {
then((stats) => print("New ffmpeg pipe at $path"));
});
```
+
+### 4. Example Application
+You can see how FlutterFFmpeg is used inside an application by running the example application provided under the
+`example` folder. It supports command execution, video encoding, accessing https, encoding audio,
+burning subtitles, video stabilisation, pipe operations and concurrent command execution.
+
+
-### 4. Tips
+### 5. Tips
- `flutter_ffmpeg` uses file system paths, it does not know what an `assets` folder or a `project` folder is. So you can't use resources on those folders directly, you need to provide full paths of those resources.
-- `flutter_ffmpeg` requires ios deployment target to be at least `9.3`.
- If you don't specify a deployment target or set a value smaller than `9.3` then your build will fail with the following error.
+- `flutter_ffmpeg` requires ios deployment target to be at least `11.0` for Main releases and `9.3` for LTS releases.
+ If you don't specify a deployment target or set a value smaller than the required one then your build will fail with
+ the following error.
```
Resolving dependencies of `Podfile`
@@ -395,8 +438,13 @@ In order to install the `LTS` variant, install the `https-lts` package using ins
deployment target.
```
- You can fix this issue by adding `platform :ios, '9.3'` definition to your `ios/Podfile` file.
+ You can fix this issue by adding the definition to your `ios/Podfile` file.
+ - `Main` releases
+ ```
+ platform :ios, '11.0'
+ ```
+ - `LTS` releases
```
platform :ios, '9.3'
```
@@ -447,21 +495,35 @@ You can overcome this situation by registering a font using `setFontDirectory` m
}
```
-### 5. Updates
+### 6. Updates
Refer to [Changelog](CHANGELOG.md) for updates.
-### 6. License
+### 7. License
-This project is licensed under the LGPL v3.0. However, if installation is customized to use a package with `-gpl` postfix (min-gpl, https-gpl, full-gpl) then `FlutterFFmpeg` is subject to the GPL v3.0 license.
+This project is licensed under the LGPL v3.0. However, if installation is customized to use a package with `-gpl`
+postfix (min-gpl, https-gpl, full-gpl) then `FlutterFFmpeg` is subject to the GPL v3.0 license.
-Digital assets used in test applications are published in the public domain.
+In test application; embedded fonts are licensed under the
+[SIL Open Font License](https://opensource.org/licenses/OFL-1.1), other digital assets are published in the public
+domain.
-### 7. Contributing
+### 8. Patents
+
+It is not clearly explained in their documentation but it is believed that `FFmpeg`, `kvazaar`, `x264` and `x265`
+include algorithms which are subject to software patents. If you live in a country where software algorithms are
+patentable then you'll probably need to pay royalty fees to patent holders. We are not lawyers though, so we recommend
+that you seek legal advice first. See [FFmpeg Patent Mini-FAQ](https://ffmpeg.org/legal.html).
+
+### 9. Contributing
Feel free to submit issues or pull requests.
-### 8. See Also
+Please note that `master` branch includes only the latest released source code. Changes planned for the next release
+are implemented under the `development` branch. Therefore, if you want to create a pull request, please open it against
+the `development`.
+
+### 10. See Also
- [FFmpeg](https://www.ffmpeg.org)
- [Mobile FFmpeg Wiki](https://github.com/tanersener/mobile-ffmpeg/wiki)
diff --git a/doc/assets/flutter_test_app.gif b/doc/assets/flutter_test_app.gif
new file mode 100644
index 0000000..23779bb
Binary files /dev/null and b/doc/assets/flutter_test_app.gif differ
diff --git a/example/README.md b/example/README.md
index c980e11..1a72536 100644
--- a/example/README.md
+++ b/example/README.md
@@ -4,7 +4,7 @@ Demonstrates how to use the flutter_ffmpeg plugin.
## Getting Started
-1. Execute FFmpeg commands.
+1. Execute synchronous FFmpeg commands.
- Use execute() method with a single command line
```
@@ -25,8 +25,15 @@ Demonstrates how to use the flutter_ffmpeg plugin.
var arguments = ["-i", "file1.mp4", "-c:v", "mpeg4", "file2.mp4"];
_flutterFFmpeg.executeWithArguments(arguments).then((rc) => print("FFmpeg process exited with rc $rc"));
```
+2. Execute asynchronous FFmpeg commands.
-2. Execute FFprobe commands.
+ ```
+ _flutterFFmpeg.executeAsync(ffmpegCommand, (int executionId, int returnCode) {
+ print("FFmpeg process for executionId $executionId exited with rc $returnCode");
+ }).then((executionId) => print("Async FFmpeg process started with executionId $executionId."));
+ ```
+
+3. Execute FFprobe commands.
- Use execute() method with a single command line
```
@@ -48,7 +55,7 @@ Demonstrates how to use the flutter_ffmpeg plugin.
_flutterFFprobe.executeWithArguments(arguments).then((rc) => print("FFprobe process exited with rc $rc"));
```
-3. Check execution output. Zero represents successful execution, non-zero values represent failure.
+4. Check execution output. Zero represents successful execution, 255 means user cancel and non-zero values represent failure.
```
final FlutterFFmpegConfig _flutterFFmpegConfig = new FlutterFFmpegConfig();
@@ -58,12 +65,17 @@ Demonstrates how to use the flutter_ffmpeg plugin.
_flutterFFmpegConfig.getLastCommandOutput().then((output) => print("Last command output: $output"));
```
-4. Stop an ongoing operation. Note that this function does not wait for termination to complete and returns immediately.
- ```
- _flutterFFmpeg.cancel();
- ```
+5. Stop ongoing FFmpeg operations. Note that these two functions do not wait for termination to complete and return immediately.
+ - Stop all executions
+ ```
+ _flutterFFmpeg.cancel();
+ ```
+ - Stop a specific execution
+ ```
+ _flutterFFmpeg.cancelExecution(executionId);
+ ```
-5. Get media information for a file.
+6. Get media information for a file.
- Print all fields
```
final FlutterFFprobe _flutterFFprobe = new FlutterFFprobe();
@@ -77,37 +89,43 @@ Demonstrates how to use the flutter_ffmpeg plugin.
_flutterFFprobe.getMediaInformation("").then((info) {
print("Media Information");
- print("Path: ${info['path']}");
- print("Format: ${info['format']}");
- print("Duration: ${info['duration']}");
- print("Start time: ${info['startTime']}");
- print("Bitrate: ${info['bitrate']}");
-
- if (info['streams'] != null) {
- final streamsInfoArray = info['streams'];
-
- if (streamsInfoArray.length > 0) {
- for (var streamsInfo in streamsInfoArray) {
- print("Stream id: ${streamsInfo['index']}");
- print("Stream type: ${streamsInfo['type']}");
- print("Stream codec: ${streamsInfo['codec']}");
- print("Stream full codec: ${streamsInfo['fullCodec']}");
- print("Stream format: ${streamsInfo['format']}");
- print("Stream full format: ${streamsInfo['fullFormat']}");
- print("Stream width: ${streamsInfo['width']}");
- print("Stream height: ${streamsInfo['height']}");
- print("Stream bitrate: ${streamsInfo['bitrate']}");
- print("Stream sample rate: ${streamsInfo['sampleRate']}");
- print("Stream sample format: ${streamsInfo['sampleFormat']}");
- print("Stream channel layout: ${streamsInfo['channelLayout']}");
- print("Stream sar: ${streamsInfo['sampleAspectRatio']}");
- print("Stream dar: ${streamsInfo['displayAspectRatio']}");
- print("Stream average frame rate: ${streamsInfo['averageFrameRate']}");
- print("Stream real frame rate: ${streamsInfo['realFrameRate']}");
- print("Stream time base: ${streamsInfo['timeBase']}");
- print("Stream codec time base: ${streamsInfo['codecTimeBase']}");
-
- final metadataMap = streamsInfo['metadata'];
+ print("Path: ${info.getMediaProperties()['path']}");
+ print("Format: ${info.getMediaProperties()['format']}");
+ print("Duration: ${info.getMediaProperties()['duration']}");
+ print("Start time: ${info.getMediaProperties()['startTime']}");
+ print("Bitrate: ${info.getMediaProperties()['bitrate']}");
+ Map tags = info.getMediaProperties()['tags'];
+ if (tags != null) {
+ tags.forEach((key, value) {
+ print("Tag: " + key + ":" + value + "\n");
+ });
+ }
+
+ if (info.getStreams() != null) {
+ List streams = info.getStreams();
+
+ if (streams.length > 0) {
+ for (var stream in streams) {
+ print("Stream id: ${stream.getAllProperties()['index']}");
+ print("Stream type: ${stream.getAllProperties()['type']}");
+ print("Stream codec: ${stream.getAllProperties()['codec']}");
+ print("Stream full codec: ${stream.getAllProperties()['fullCodec']}");
+ print("Stream format: ${stream.getAllProperties()['format']}");
+ print("Stream full format: ${stream.getAllProperties()['fullFormat']}");
+ print("Stream width: ${stream.getAllProperties()['width']}");
+ print("Stream height: ${stream.getAllProperties()['height']}");
+ print("Stream bitrate: ${stream.getAllProperties()['bitrate']}");
+ print("Stream sample rate: ${stream.getAllProperties()['sampleRate']}");
+ print("Stream sample format: ${stream.getAllProperties()['sampleFormat']}");
+ print("Stream channel layout: ${stream.getAllProperties()['channelLayout']}");
+ print("Stream sar: ${stream.getAllProperties()['sampleAspectRatio']}");
+ print("Stream dar: ${stream.getAllProperties()['displayAspectRatio']}");
+ print("Stream average frame rate: ${stream.getAllProperties()['averageFrameRate']}");
+ print("Stream real frame rate: ${stream.getAllProperties()['realFrameRate']}");
+ print("Stream time base: ${stream.getAllProperties()['timeBase']}");
+ print("Stream codec time base: ${stream.getAllProperties()['codecTimeBase']}");
+
+ final metadataMap = stream.getAllProperties()['metadata'];
if (metadataMap != null) {
print('Stream metadata encoder: ${metadataMap['encoder']}');
print('Stream metadata rotate: ${metadataMap['rotate']}');
@@ -115,7 +133,7 @@ Demonstrates how to use the flutter_ffmpeg plugin.
print('Stream metadata handler name: ${metadataMap['handler_name']}');
}
- final sideDataMap = streamsInfo['sidedata'];
+ final sideDataMap = stream.getAllProperties()['sidedata'];
if (sideDataMap != null) {
print('Stream side data displaymatrix: ${sideDataMap['displaymatrix']}');
}
@@ -125,69 +143,67 @@ Demonstrates how to use the flutter_ffmpeg plugin.
```
-6. Enable log callback and redirect all `FFmpeg`/`FFprobe` logs to a console/file/widget.
+7. Enable log callback and redirect all `FFmpeg`/`FFprobe` logs to a console/file/widget.
```
- void logCallback(int level, String message) {
- print(message);
+ void logCallback(Log log) {
+ print("${log.executionId}:${log.message}");
}
...
_flutterFFmpegConfig.enableLogCallback(this.logCallback);
```
-7. Enable statistics callback and follow the progress of an ongoing `FFmpeg` operation.
+8. Enable statistics callback and follow the progress of an ongoing `FFmpeg` operation.
```
- void statisticsCallback(int time, int size, double bitrate, double speed, int videoFrameNumber, double videoQuality, double videoFps) {
- print("Statistics: time: $time, size: $size, bitrate: $bitrate, speed: $speed, videoFrameNumber: $videoFrameNumber, videoQuality: $videoQuality, videoFps: $videoFps");
+ void statisticsCallback(Statistics statistics) {
+ print("Statistics: executionId: ${statistics.executionId}, time: ${statistics.time}, size: ${statistics.size}, bitrate: ${statistics.bitrate}, speed: ${statistics.speed}, videoFrameNumber: ${statistics.videoFrameNumber}, videoQuality: ${statistics.videoQuality}, videoFps: ${statistics.videoFps}");
}
...
_flutterFFmpegConfig.enableStatisticsCallback(this.statisticsCallback);
```
-8. Poll statistics without implementing statistics callback.
+9. Poll statistics without implementing statistics callback.
```
_flutterFFmpegConfig.getLastReceivedStatistics().then((stats) => print(stats));
```
-9. Reset statistics before starting a new operation.
+10. List ongoing executions.
```
- _flutterFFmpegConfig.resetStatistics();
+ _flutterFFmpeg.listExecutions().then((ffmpegExecutions) {
+ ffmpegExecutions.forEach((execution) {
+ ffprint(
+ "Execution id:${execution.executionId}, startTime:${execution.command}, command:${execution.startTime}.");
+ });
+ });
```
-10. Set log level.
+11. Set log level.
```
_flutterFFmpegConfig.setLogLevel(LogLevel.AV_LOG_WARNING);
```
-11. Register your own fonts by specifying a custom fonts directory, so they are available to use in `FFmpeg` filters. Please note that this function can not work on relative paths, you need to provide full file system path.
+12. Register your own fonts by specifying a custom fonts directory, so they are available to use in `FFmpeg` filters. Please note that this function can not work on relative paths, you need to provide full file system path.
```
_flutterFFmpegConfig.setFontDirectory("");
```
-12. Use your own `fontconfig` configuration.
+13. Use your own `fontconfig` configuration.
```
_flutterFFmpegConfig.setFontconfigConfigurationPath("");
```
-13. Disable log functionality of the library. Logs will not be printed to console and log callback will be disabled.
+14. Disable log functionality of the library. Logs will not be printed to console and log callback will be disabled.
```
_flutterFFmpegConfig.disableLogs();
```
-14. Disable statistics functionality of the library. Statistics callback will be disabled but the last received statistics data will be still available.
+15. Disable statistics functionality of the library. Statistics callback will be disabled but the last received statistics data will be still available.
```
_flutterFFmpegConfig.disableStatistics();
```
-15. List enabled external libraries.
- ```
- _flutterFFmpegConfig.getExternalLibraries().then((packageList) {
- packageList.forEach((value) => print("External library: $value"));
- });
- ```
16. Create new `FFmpeg` pipe.
```
_flutterFFmpegConfig.registerNewFFmpegPipe().then((path) {
then((stats) => print("New ffmpeg pipe at $path"));
});
- ```
-
+ ```
\ No newline at end of file
diff --git a/example/android/build.gradle b/example/android/build.gradle
index 03fb4f1..d9d6580 100644
--- a/example/android/build.gradle
+++ b/example/android/build.gradle
@@ -24,7 +24,7 @@ subprojects {
project.evaluationDependsOn(':app')
}
-ext.flutterFFmpegPackage = 'full-gpl'
+ext.flutterFFmpegPackage = 'full'
task clean(type: Delete) {
delete rootProject.buildDir
diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock
index 2b1af55..91b377a 100644
--- a/example/ios/Podfile.lock
+++ b/example/ios/Podfile.lock
@@ -5,9 +5,11 @@ PODS:
- mobile-ffmpeg-audio (= 4.4.LTS)
- fluttertoast (0.0.2):
- Flutter
+ - Toast
- mobile-ffmpeg-audio (4.4.LTS)
- path_provider (0.0.1):
- Flutter
+ - Toast (4.0.0)
- video_player (0.0.1):
- Flutter
@@ -21,6 +23,7 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- mobile-ffmpeg-audio
+ - Toast
EXTERNAL SOURCES:
Flutter:
@@ -37,9 +40,10 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
flutter_ffmpeg: 657ce8a1502c3d25bf34efc58b380b248836f772
- fluttertoast: b644586ef3b16f67fae9a1f8754cef6b2d6b634b
+ fluttertoast: 6122fa75143e992b1d3470f61000f591a798cc58
mobile-ffmpeg-audio: 1e0a053f8a6de57114e50ff48b3a85ff1c60f902
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
+ Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e
PODFILE CHECKSUM: 45c71b51796b78cb6a09bb97eb9786d4c7aa085f
diff --git a/example/lib/concurrent_execution_tab.dart b/example/lib/concurrent_execution_tab.dart
index 7f015f4..81f20d0 100644
--- a/example/lib/concurrent_execution_tab.dart
+++ b/example/lib/concurrent_execution_tab.dart
@@ -112,7 +112,7 @@ class ConcurrentExecutionTab {
}
}
- listFFmpegExecutions();
+ runListFFmpegExecutions();
});
});
});
@@ -126,7 +126,7 @@ class ConcurrentExecutionTab {
return new File("${documentsDirectory.path}/$video");
}
- void listFFmpegExecutio() {
+ void runListFFmpegExecutions() {
listFFmpegExecutions().then((ffmpegExecutions) {
ffprint("Listing ongoing FFmpeg executions.");
int i = 0;
diff --git a/example/pubspec.lock b/example/pubspec.lock
index f5ecf07..b09d61a 100644
--- a/example/pubspec.lock
+++ b/example/pubspec.lock
@@ -49,7 +49,7 @@ packages:
name: cupertino_icons
url: "https://pub.dartlang.org"
source: hosted
- version: "0.1.3"
+ version: "1.0.0"
fake_async:
dependency: transitive
description:
@@ -57,6 +57,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
+ ffi:
+ dependency: transitive
+ description:
+ name: ffi
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.1.3"
file:
dependency: transitive
description:
@@ -92,7 +99,7 @@ packages:
name: fluttertoast
url: "https://pub.dartlang.org"
source: hosted
- version: "7.0.2"
+ version: "7.1.1"
intl:
dependency: transitive
description:
@@ -127,7 +134,7 @@ packages:
name: path_provider
url: "https://pub.dartlang.org"
source: hosted
- version: "1.6.14"
+ version: "1.6.16"
path_provider_linux:
dependency: transitive
description:
@@ -141,7 +148,7 @@ packages:
name: path_provider_macos
url: "https://pub.dartlang.org"
source: hosted
- version: "0.0.4+3"
+ version: "0.0.4+4"
path_provider_platform_interface:
dependency: transitive
description:
@@ -149,6 +156,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
+ path_provider_windows:
+ dependency: transitive
+ description:
+ name: path_provider_windows
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.0.3"
platform:
dependency: transitive
description:
@@ -237,7 +251,7 @@ packages:
name: video_player
url: "https://pub.dartlang.org"
source: hosted
- version: "0.10.12+2"
+ version: "0.10.12+3"
video_player_platform_interface:
dependency: transitive
description:
@@ -252,6 +266,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3+2"
+ win32:
+ dependency: transitive
+ description:
+ name: win32
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.7.2+1"
xdg_directories:
dependency: transitive
description:
diff --git a/example/pubspec.yaml b/example/pubspec.yaml
index 26a3ca4..9e22206 100644
--- a/example/pubspec.yaml
+++ b/example/pubspec.yaml
@@ -4,16 +4,17 @@ version: 0.3.0
publish_to: 'none'
environment:
- sdk: ">=2.0.0-dev.68.0 <3.0.0"
+ sdk: ">=2.1.0 <3.0.0"
+ flutter: ">=1.10.0 <2.0.0"
dependencies:
flutter:
sdk: flutter
- cupertino_icons: ^0.1.3
- path_provider: ^1.6.14
+ cupertino_icons: ^1.0.0
+ path_provider: ^1.6.16
path: ^1.7.0
- fluttertoast: ^7.0.2
- video_player: ^0.10.12+2
+ fluttertoast: ^7.1.1
+ video_player: ^0.10.12+3
flutter_ffmpeg:
path: ..
diff --git a/lib/flutter_ffmpeg.dart b/lib/flutter_ffmpeg.dart
index 90144ca..c1f2955 100644
--- a/lib/flutter_ffmpeg.dart
+++ b/lib/flutter_ffmpeg.dart
@@ -450,7 +450,8 @@ class FlutterFFmpeg {
List arguments, ExecuteCallback executeCallback) async {
try {
return await _methodChannel.invokeMethod(
- 'executeFFmpegAsyncWithArguments', {'arguments': arguments}).then((map) {
+ 'executeFFmpegAsyncWithArguments',
+ {'arguments': arguments}).then((map) {
var executionId = map["executionId"];
FlutterFFmpegConfig.addExecuteCallback(executionId, executeCallback);
return executionId;
diff --git a/lib/stream_information.dart b/lib/stream_information.dart
index e711906..5ed94eb 100644
--- a/lib/stream_information.dart
+++ b/lib/stream_information.dart
@@ -18,7 +18,6 @@
*/
class StreamInformation {
-
Map _allProperties;
/// Creates a new [StreamInformation] instance
@@ -28,5 +27,4 @@ class StreamInformation {
Map getAllProperties() {
return _allProperties;
}
-
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 228fe74..b0e6574 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -5,13 +5,14 @@ homepage: https://github.com/tanersener/flutter-ffmpeg
environment:
sdk: ">=2.1.0 <3.0.0"
+ flutter: ">=1.10.0 <2.0.0"
dependencies:
flutter:
sdk: flutter
dev_dependencies:
- path_provider: ^1.6.14
+ path_provider: ^1.6.16
path: ^1.7.0
flutter: