Merge pull request #295 from tanersener/development-flutter

merge flutter v4.5.1 changes to main
This commit is contained in:
Taner Şener 2022-01-02 23:22:14 +00:00 committed by GitHub
commit 44c4fca703
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1698 additions and 560 deletions

View File

@ -1,3 +1,9 @@
## 4.5.1
- Feature release based on native v4.5.1
## 4.5.1-LTS
- Feature release based on native v4.5.1.LTS
## 4.5.0 ## 4.5.0
- Initial release - Initial release

View File

@ -10,15 +10,15 @@
- `Android API Level 16` or later - `Android API Level 16` or later
- `armv7`, `armv7s`, `arm64`, `arm64-simulator`, `i386`, `x86_64`, `x86_64-mac-catalyst` and `arm64-mac-catalyst` - `armv7`, `armv7s`, `arm64`, `arm64-simulator`, `i386`, `x86_64`, `x86_64-mac-catalyst` and `arm64-mac-catalyst`
architectures on iOS architectures on iOS
- `iOS SDK 9.3` or later - `iOS SDK 10` or later
- `arm64` and `x86_64` architectures on macOS - `arm64` and `x86_64` architectures on macOS
- `macOS SDK 10.11+` or later - `macOS SDK 10.12+` or later
- Can process Storage Access Framework (SAF) Uris on Android - Can process Storage Access Framework (SAF) Uris on Android
- 24 external libraries - 25 external libraries
`dav1d`, `fontconfig`, `freetype`, `fribidi`, `gmp`, `gnutls`, `kvazaar`, `lame`, `libass`, `libiconv`, `libilbc` `dav1d`, `fontconfig`, `freetype`, `fribidi`, `gmp`, `gnutls`, `kvazaar`, `lame`, `libass`, `libiconv`, `libilbc`
, `libtheora`, `libvorbis`, `libvpx`, `libwebp`, `libxml2`, `opencore-amr`, `opus`, `shine`, `snappy`, `soxr` , `libtheora`, `libvorbis`, `libvpx`, `libwebp`, `libxml2`, `opencore-amr`, `opus`, `shine`, `snappy`, `soxr`
, `speex`, `twolame`, `vo-amrwbenc` , `speex`, `twolame`, `vo-amrwbenc`, `zimg`
- 4 external libraries with GPL license - 4 external libraries with GPL license
@ -32,7 +32,7 @@ Add `ffmpeg_kit_flutter` as a dependency in your `pubspec.yaml file`.
```yaml ```yaml
dependencies: dependencies:
ffmpeg_kit_flutter: ^4.5.0 ffmpeg_kit_flutter: 4.5.1
``` ```
#### 2.1 Packages #### 2.1 Packages
@ -55,7 +55,7 @@ using the following dependency format.
```yaml ```yaml
dependencies: dependencies:
ffmpeg_kit_flutter_<package name>: ^4.5.0 ffmpeg_kit_flutter_<package name>: 4.5.1
``` ```
Note that hyphens in the package name must be replaced with underscores. Additionally, do not forget to use the package Note that hyphens in the package name must be replaced with underscores. Additionally, do not forget to use the package
@ -67,7 +67,7 @@ In order to install the `LTS` variant, append `-LTS` to the version you have for
```yaml ```yaml
dependencies: dependencies:
ffmpeg_kit_flutter: 4.5.0-LTS ffmpeg_kit_flutter: 4.5.1-LTS
``` ```
#### 2.4 LTS Releases #### 2.4 LTS Releases
@ -99,7 +99,7 @@ The following table shows the Android API level and iOS deployment target requir
<td align="center">24</td> <td align="center">24</td>
<td align="center">12.1</td> <td align="center">12.1</td>
<td align="center">16</td> <td align="center">16</td>
<td align="center">9.3</td> <td align="center">10</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@ -111,7 +111,7 @@ The following table shows the Android API level and iOS deployment target requir
```dart ```dart
import 'package:ffmpeg_kit_flutter/ffmpeg_kit.dart'; import 'package:ffmpeg_kit_flutter/ffmpeg_kit.dart';
FFmpegKit.executeAsync('-i file1.mp4 -c:v mpeg4 file2.mp4', (session) async { FFmpegKit.execute('-i file1.mp4 -c:v mpeg4 file2.mp4').then((session) async {
final returnCode = await session.getReturnCode(); final returnCode = await session.getReturnCode();
if (ReturnCode.isSuccess(returnCode)) { if (ReturnCode.isSuccess(returnCode)) {
@ -133,7 +133,7 @@ The following table shows the Android API level and iOS deployment target requir
2. Each `execute` call creates a new session. Access every detail about your execution from the session created. 2. Each `execute` call creates a new session. Access every detail about your execution from the session created.
```dart ```dart
FFmpegKit.executeAsync('-i file1.mp4 -c:v mpeg4 file2.mp4', (session) async { FFmpegKit.execute('-i file1.mp4 -c:v mpeg4 file2.mp4').then((session) async {
// Unique session id created for this execution // Unique session id created for this execution
final sessionId = session.getSessionId(); final sessionId = session.getSessionId();
@ -190,7 +190,7 @@ The following table shows the Android API level and iOS deployment target requir
4. Execute `FFprobe` commands. 4. Execute `FFprobe` commands.
```dart ```dart
FFprobeKit.executeAsync(ffprobeCommand, (session) { FFprobeKit.execute(ffprobeCommand).then((session) async {
// CALLED WHEN SESSION IS EXECUTED // CALLED WHEN SESSION IS EXECUTED
@ -200,8 +200,18 @@ The following table shows the Android API level and iOS deployment target requir
5. Get media information for a file/url. 5. Get media information for a file/url.
```dart ```dart
FFprobeKit.getMediaInformationAsync('<file path or url>', (session) async { FFprobeKit.getMediaInformation('<file path or url>').then((session) async {
final information = await (session as MediaInformationSession).getMediaInformation(); final information = await session.getMediaInformation();
if (information == null) {
// CHECK THE FOLLOWING ATTRIBUTES ON ERROR
final state = FFmpegKitConfig.sessionStateToString(await session.getState());
final returnCode = await session.getReturnCode();
final failStackTrace = await session.getFailStackTrace();
final duration = await session.getDuration();
final output = await session.getOutput();
}
}); });
``` ```
@ -237,7 +247,7 @@ The following table shows the Android API level and iOS deployment target requir
}); });
``` ```
8. Get previous `FFmpeg` and `FFprobe` sessions from the session history. 8. Get previous `FFmpeg`, `FFprobe` and `MediaInformation` sessions from the session history.
```dart ```dart
FFmpegKit.listSessions().then((sessionList) { FFmpegKit.listSessions().then((sessionList) {
@ -246,7 +256,13 @@ The following table shows the Android API level and iOS deployment target requir
}); });
}); });
FFprobeKit.listSessions().then((sessionList) { FFprobeKit.listFFprobeSessions().then((sessionList) {
sessionList.forEach((session) {
final sessionId = session.getSessionId();
});
});
FFprobeKit.listMediaInformationSessions().then((sessionList) {
sessionList.forEach((session) { sessionList.forEach((session) {
final sessionId = session.getSessionId(); final sessionId = session.getSessionId();
}); });
@ -255,10 +271,18 @@ The following table shows the Android API level and iOS deployment target requir
9. Enable global callbacks. 9. Enable global callbacks.
- Execute Callback, called when an async execution is ended - Session type specific Complete Callbacks, called when an async session has been completed
```dart ```dart
FFmpegKitConfig.enableExecuteCallback((session) { FFmpegKitConfig.enableFFmpegSessionCompleteCallback((session) {
final sessionId = session.getSessionId();
});
FFmpegKitConfig.enableFFprobeSessionCompleteCallback((session) {
final sessionId = session.getSessionId();
});
FFmpegKitConfig.enableMediaInformationSessionCompleteCallback((session) {
final sessionId = session.getSessionId(); final sessionId = session.getSessionId();
}); });
``` ```

View File

@ -1,6 +1,6 @@
*.iml *.iml
.gradle .gradle
/local.properties local.properties
/.idea/workspace.xml /.idea/workspace.xml
/.idea/libraries /.idea/libraries
.DS_Store .DS_Store

View File

@ -17,8 +17,8 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 24 minSdkVersion 24
targetSdkVersion 30 targetSdkVersion 30
versionCode 450 versionCode 451
versionName "4.5.0" versionName "4.5.1"
} }
buildTypes { buildTypes {
@ -43,6 +43,6 @@ repositories {
dependencies { dependencies {
implementation 'androidx.annotation:annotation:1.2.0' implementation 'androidx.annotation:annotation:1.2.0'
implementation 'com.arthenica:ffmpeg-kit-https:4.5' implementation 'com.arthenica:ffmpeg-kit-https:4.5.1-1'
} }

View File

@ -23,6 +23,7 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -57,12 +58,11 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware; import io.flutter.embedding.engine.plugins.activity.ActivityAware;
@ -114,7 +114,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
// EVENTS // EVENTS
public static final String EVENT_LOG_CALLBACK_EVENT = "FFmpegKitLogCallbackEvent"; public static final String EVENT_LOG_CALLBACK_EVENT = "FFmpegKitLogCallbackEvent";
public static final String EVENT_STATISTICS_CALLBACK_EVENT = "FFmpegKitStatisticsCallbackEvent"; public static final String EVENT_STATISTICS_CALLBACK_EVENT = "FFmpegKitStatisticsCallbackEvent";
public static final String EVENT_EXECUTE_CALLBACK_EVENT = "FFmpegKitExecuteCallbackEvent"; public static final String EVENT_COMPLETE_CALLBACK_EVENT = "FFmpegKitCompleteCallbackEvent";
// REQUEST CODES // REQUEST CODES
public static final int READABLE_REQUEST_CODE = 10000; public static final int READABLE_REQUEST_CODE = 10000;
@ -127,11 +127,11 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
public static final String ARGUMENT_FFPROBE_JSON_OUTPUT = "ffprobeJsonOutput"; public static final String ARGUMENT_FFPROBE_JSON_OUTPUT = "ffprobeJsonOutput";
public static final String ARGUMENT_WRITABLE = "writable"; public static final String ARGUMENT_WRITABLE = "writable";
private static final int asyncWriteToPipeConcurrencyLimit = 10; private static final int asyncConcurrencyLimit = 10;
private final AtomicBoolean logsEnabled; private final AtomicBoolean logsEnabled;
private final AtomicBoolean statisticsEnabled; private final AtomicBoolean statisticsEnabled;
private final ExecutorService asyncWriteToPipeExecutorService; private final ExecutorService asyncExecutorService;
private MethodChannel methodChannel; private MethodChannel methodChannel;
private EventChannel eventChannel; private EventChannel eventChannel;
@ -147,10 +147,10 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
public FFmpegKitFlutterPlugin() { public FFmpegKitFlutterPlugin() {
this.logsEnabled = new AtomicBoolean(false); this.logsEnabled = new AtomicBoolean(false);
this.statisticsEnabled = new AtomicBoolean(false); this.statisticsEnabled = new AtomicBoolean(false);
this.asyncWriteToPipeExecutorService = Executors.newFixedThreadPool(asyncWriteToPipeConcurrencyLimit); this.asyncExecutorService = Executors.newFixedThreadPool(asyncConcurrencyLimit);
this.resultHandler = new FFmpegKitFlutterMethodResultHandler(); this.resultHandler = new FFmpegKitFlutterMethodResultHandler();
registerGlobalCallbacks(); Log.d(LIBRARY_NAME, String.format("FFmpegKitFlutterPlugin created %s.", this));
} }
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@ -165,7 +165,9 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
} }
protected void registerGlobalCallbacks() { protected void registerGlobalCallbacks() {
FFmpegKitConfig.enableExecuteCallback(this::emitSession); FFmpegKitConfig.enableFFmpegSessionCompleteCallback(this::emitSession);
FFmpegKitConfig.enableFFprobeSessionCompleteCallback(this::emitSession);
FFmpegKitConfig.enableMediaInformationSessionCompleteCallback(this::emitSession);
FFmpegKitConfig.enableLogCallback(log -> { FFmpegKitConfig.enableLogCallback(log -> {
if (logsEnabled.get()) { if (logsEnabled.get()) {
@ -192,7 +194,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
@Override @Override
public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBinding) { public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBinding) {
Log.d(LIBRARY_NAME, String.format("FFmpegKitFlutterPlugin attached to activity %s.", activityPluginBinding.getActivity())); Log.d(LIBRARY_NAME, String.format("FFmpegKitFlutterPlugin %s attached to activity %s.", this, activityPluginBinding.getActivity()));
init(flutterPluginBinding.getBinaryMessenger(), flutterPluginBinding.getApplicationContext(), activityPluginBinding.getActivity(), null, activityPluginBinding); init(flutterPluginBinding.getBinaryMessenger(), flutterPluginBinding.getApplicationContext(), activityPluginBinding.getActivity(), null, activityPluginBinding);
} }
@ -215,7 +217,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
@Override @Override
public void onListen(final Object o, final EventChannel.EventSink eventSink) { public void onListen(final Object o, final EventChannel.EventSink eventSink) {
this.eventSink = eventSink; this.eventSink = eventSink;
Log.d(LIBRARY_NAME, String.format("FFmpegKitFlutterPlugin started listening to events on %s.", eventSink)); Log.d(LIBRARY_NAME, String.format("FFmpegKitFlutterPlugin %s started listening to events on %s.", this, eventSink));
} }
@Override @Override
@ -249,72 +251,72 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
@Override @Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
final Optional<Integer> sessionIdOptional = Optional.ofNullable(call.argument(ARGUMENT_SESSION_ID)); final Integer sessionId = call.argument(ARGUMENT_SESSION_ID);
final Integer waitTimeout = call.argument(ARGUMENT_WAIT_TIMEOUT); final Integer waitTimeout = call.argument(ARGUMENT_WAIT_TIMEOUT);
final Optional<List<String>> argumentsOptional = Optional.ofNullable(call.argument(ARGUMENT_ARGUMENTS)); final List<String> arguments = call.argument(ARGUMENT_ARGUMENTS);
final Optional<String> ffprobeJsonOutputOptional = Optional.ofNullable(call.argument(ARGUMENT_FFPROBE_JSON_OUTPUT)); final String ffprobeJsonOutput = call.argument(ARGUMENT_FFPROBE_JSON_OUTPUT);
final Optional<Boolean> writableOptional = Optional.ofNullable(call.argument(ARGUMENT_WRITABLE)); final Boolean writable = call.argument(ARGUMENT_WRITABLE);
switch (call.method) { switch (call.method) {
case "abstractSessionGetEndTime": case "abstractSessionGetEndTime":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
abstractSessionGetEndTime(sessionIdOptional.get(), result); abstractSessionGetEndTime(sessionId, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
break; break;
case "abstractSessionGetDuration": case "abstractSessionGetDuration":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
abstractSessionGetDuration(sessionIdOptional.get(), result); abstractSessionGetDuration(sessionId, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
break; break;
case "abstractSessionGetAllLogs": case "abstractSessionGetAllLogs":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
abstractSessionGetAllLogs(sessionIdOptional.get(), waitTimeout, result); abstractSessionGetAllLogs(sessionId, waitTimeout, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
break; break;
case "abstractSessionGetLogs": case "abstractSessionGetLogs":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
abstractSessionGetLogs(sessionIdOptional.get(), result); abstractSessionGetLogs(sessionId, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
break; break;
case "abstractSessionGetAllLogsAsString": case "abstractSessionGetAllLogsAsString":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
abstractSessionGetAllLogsAsString(sessionIdOptional.get(), waitTimeout, result); abstractSessionGetAllLogsAsString(sessionId, waitTimeout, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
break; break;
case "abstractSessionGetState": case "abstractSessionGetState":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
abstractSessionGetState(sessionIdOptional.get(), result); abstractSessionGetState(sessionId, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
break; break;
case "abstractSessionGetReturnCode": case "abstractSessionGetReturnCode":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
abstractSessionGetReturnCode(sessionIdOptional.get(), result); abstractSessionGetReturnCode(sessionId, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
break; break;
case "abstractSessionGetFailStackTrace": case "abstractSessionGetFailStackTrace":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
abstractSessionGetFailStackTrace(sessionIdOptional.get(), result); abstractSessionGetFailStackTrace(sessionId, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
break; break;
case "thereAreAsynchronousMessagesInTransmit": case "thereAreAsynchronousMessagesInTransmit":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
abstractSessionThereAreAsynchronousMessagesInTransmit(sessionIdOptional.get(), result); abstractSessionThereAreAsynchronousMessagesInTransmit(sessionId, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
@ -323,50 +325,57 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
getArch(result); getArch(result);
break; break;
case "ffmpegSession": case "ffmpegSession":
if (argumentsOptional.isPresent()) { if (arguments != null) {
ffmpegSession(argumentsOptional.get(), result); ffmpegSession(arguments, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_ARGUMENTS", "Invalid arguments array."); resultHandler.errorAsync(result, "INVALID_ARGUMENTS", "Invalid arguments array.");
} }
break; break;
case "ffmpegSessionGetAllStatistics": case "ffmpegSessionGetAllStatistics":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
ffmpegSessionGetAllStatistics(sessionIdOptional.get(), waitTimeout, result); ffmpegSessionGetAllStatistics(sessionId, waitTimeout, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
break; break;
case "ffmpegSessionGetStatistics": case "ffmpegSessionGetStatistics":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
ffmpegSessionGetStatistics(sessionIdOptional.get(), result); ffmpegSessionGetStatistics(sessionId, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
break; break;
case "ffprobeSession": case "ffprobeSession":
if (argumentsOptional.isPresent()) { if (arguments != null) {
ffprobeSession(argumentsOptional.get(), result); ffprobeSession(arguments, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_ARGUMENTS", "Invalid arguments array."); resultHandler.errorAsync(result, "INVALID_ARGUMENTS", "Invalid arguments array.");
} }
break; break;
case "mediaInformationSession": case "mediaInformationSession":
if (argumentsOptional.isPresent()) { if (arguments != null) {
mediaInformationSession(argumentsOptional.get(), result); mediaInformationSession(arguments, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_ARGUMENTS", "Invalid arguments array."); resultHandler.errorAsync(result, "INVALID_ARGUMENTS", "Invalid arguments array.");
} }
break; break;
case "getMediaInformation":
if (sessionId != null) {
getMediaInformation(sessionId, result);
} else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
}
break;
case "mediaInformationJsonParserFrom": case "mediaInformationJsonParserFrom":
if (ffprobeJsonOutputOptional.isPresent()) { if (ffprobeJsonOutput != null) {
mediaInformationJsonParserFrom(ffprobeJsonOutputOptional.get(), result); mediaInformationJsonParserFrom(ffprobeJsonOutput, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_FFPROBE_JSON_OUTPUT", "Invalid ffprobe json output."); resultHandler.errorAsync(result, "INVALID_FFPROBE_JSON_OUTPUT", "Invalid ffprobe json output.");
} }
break; break;
case "mediaInformationJsonParserFromWithError": case "mediaInformationJsonParserFromWithError":
if (ffprobeJsonOutputOptional.isPresent()) { if (ffprobeJsonOutput != null) {
mediaInformationJsonParserFromWithError(ffprobeJsonOutputOptional.get(), result); mediaInformationJsonParserFromWithError(ffprobeJsonOutput, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_FFPROBE_JSON_OUTPUT", "Invalid ffprobe json output."); resultHandler.errorAsync(result, "INVALID_FFPROBE_JSON_OUTPUT", "Invalid ffprobe json output.");
} }
@ -390,28 +399,28 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
disableStatistics(result); disableStatistics(result);
break; break;
case "setFontconfigConfigurationPath": case "setFontconfigConfigurationPath":
final Optional<String> pathOptional = Optional.ofNullable(call.argument("path")); final String path = call.argument("path");
if (pathOptional.isPresent()) { if (path != null) {
setFontconfigConfigurationPath(pathOptional.get(), result); setFontconfigConfigurationPath(path, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_PATH", "Invalid path."); resultHandler.errorAsync(result, "INVALID_PATH", "Invalid path.");
} }
break; break;
case "setFontDirectory": { case "setFontDirectory": {
final Optional<String> fontDirectoryOptional = Optional.ofNullable(call.argument("fontDirectory")); final String fontDirectory = call.argument("fontDirectory");
final Map<String, String> fontNameMap = call.argument("fontNameMap"); final Map<String, String> fontNameMap = call.argument("fontNameMap");
if (fontDirectoryOptional.isPresent()) { if (fontDirectory != null) {
setFontDirectory(fontDirectoryOptional.get(), fontNameMap, result); setFontDirectory(fontDirectory, fontNameMap, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_FONT_DIRECTORY", "Invalid font directory."); resultHandler.errorAsync(result, "INVALID_FONT_DIRECTORY", "Invalid font directory.");
} }
break; break;
} }
case "setFontDirectoryList": { case "setFontDirectoryList": {
final Optional<List<String>> fontDirectoryListOptional = Optional.ofNullable(call.argument("fontDirectoryList")); final List<String> fontDirectoryList = call.argument("fontDirectoryList");
final Map<String, String> fontNameMap = call.argument("fontNameMap"); final Map<String, String> fontNameMap = call.argument("fontNameMap");
if (fontDirectoryListOptional.isPresent()) { if (fontDirectoryList != null) {
setFontDirectoryList(fontDirectoryListOptional.get(), fontNameMap, result); setFontDirectoryList(fontDirectoryList, fontNameMap, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_FONT_DIRECTORY_LIST", "Invalid font directory list."); resultHandler.errorAsync(result, "INVALID_FONT_DIRECTORY_LIST", "Invalid font directory list.");
} }
@ -421,9 +430,9 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
registerNewFFmpegPipe(result); registerNewFFmpegPipe(result);
break; break;
case "closeFFmpegPipe": case "closeFFmpegPipe":
final Optional<String> ffmpegPipePathOptional = Optional.ofNullable(call.argument("ffmpegPipePath")); final String ffmpegPipePath = call.argument("ffmpegPipePath");
if (ffmpegPipePathOptional.isPresent()) { if (ffmpegPipePath != null) {
closeFFmpegPipe(ffmpegPipePathOptional.get(), result); closeFFmpegPipe(ffmpegPipePath, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_PIPE_PATH", "Invalid ffmpeg pipe path."); resultHandler.errorAsync(result, "INVALID_PIPE_PATH", "Invalid ffmpeg pipe path.");
} }
@ -438,42 +447,63 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
getBuildDate(result); getBuildDate(result);
break; break;
case "setEnvironmentVariable": case "setEnvironmentVariable":
final Optional<String> variableNameOptional = Optional.ofNullable(call.argument("variableName")); final String variableName = call.argument("variableName");
final Optional<String> variableValueOptional = Optional.ofNullable(call.argument("variableValue")); final String variableValue = call.argument("variableValue");
if (variableNameOptional.isPresent() && variableValueOptional.isPresent()) { if (variableName != null && variableValue != null) {
setEnvironmentVariable(variableNameOptional.get(), variableValueOptional.get(), result); setEnvironmentVariable(variableName, variableValue, result);
} else if (variableValueOptional.isPresent()) { } else if (variableValue != null) {
resultHandler.errorAsync(result, "INVALID_NAME", "Invalid environment variable name."); resultHandler.errorAsync(result, "INVALID_NAME", "Invalid environment variable name.");
} else { } else {
resultHandler.errorAsync(result, "INVALID_VALUE", "Invalid environment variable value."); resultHandler.errorAsync(result, "INVALID_VALUE", "Invalid environment variable value.");
} }
break; break;
case "ignoreSignal": case "ignoreSignal":
final Optional<Integer> signalOptional = Optional.ofNullable(call.argument("signal")); final Integer signal = call.argument("signal");
if (signalOptional.isPresent()) { if (signal != null) {
ignoreSignal(signalOptional.get(), result); ignoreSignal(signal, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SIGNAL", "Invalid signal value."); resultHandler.errorAsync(result, "INVALID_SIGNAL", "Invalid signal value.");
} }
break; break;
case "ffmpegSessionExecute":
if (sessionId != null) {
ffmpegSessionExecute(sessionId, result);
} else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
}
break;
case "ffprobeSessionExecute":
if (sessionId != null) {
ffprobeSessionExecute(sessionId, result);
} else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
}
break;
case "mediaInformationSessionExecute":
if (sessionId != null) {
mediaInformationSessionExecute(sessionId, waitTimeout, result);
} else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
}
break;
case "asyncFFmpegSessionExecute": case "asyncFFmpegSessionExecute":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
asyncFFmpegSessionExecute(sessionIdOptional.get(), result); asyncFFmpegSessionExecute(sessionId, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
break; break;
case "asyncFFprobeSessionExecute": case "asyncFFprobeSessionExecute":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
asyncFFprobeSessionExecute(sessionIdOptional.get(), result); asyncFFprobeSessionExecute(sessionId, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
break; break;
case "asyncMediaInformationSessionExecute": case "asyncMediaInformationSessionExecute":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
asyncMediaInformationSessionExecute(sessionIdOptional.get(), waitTimeout, result); asyncMediaInformationSessionExecute(sessionId, waitTimeout, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
@ -482,9 +512,9 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
getLogLevel(result); getLogLevel(result);
break; break;
case "setLogLevel": case "setLogLevel":
final Optional<Integer> levelOptional = Optional.ofNullable(call.argument("level")); final Integer level = call.argument("level");
if (levelOptional.isPresent()) { if (level != null) {
setLogLevel(levelOptional.get(), result); setLogLevel(level, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_LEVEL", "Invalid level value."); resultHandler.errorAsync(result, "INVALID_LEVEL", "Invalid level value.");
} }
@ -493,16 +523,16 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
getSessionHistorySize(result); getSessionHistorySize(result);
break; break;
case "setSessionHistorySize": case "setSessionHistorySize":
final Optional<Integer> sessionHistorySizeOptional = Optional.ofNullable(call.argument("sessionHistorySize")); final Integer sessionHistorySize = call.argument("sessionHistorySize");
if (sessionHistorySizeOptional.isPresent()) { if (sessionHistorySize != null) {
setSessionHistorySize(sessionHistorySizeOptional.get(), result); setSessionHistorySize(sessionHistorySize, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SIZE", "Invalid session history size value."); resultHandler.errorAsync(result, "INVALID_SIZE", "Invalid session history size value.");
} }
break; break;
case "getSession": case "getSession":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
getSession(sessionIdOptional.get(), result); getSession(sessionId, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
@ -520,9 +550,9 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
clearSessions(result); clearSessions(result);
break; break;
case "getSessionsByState": case "getSessionsByState":
final Optional<Integer> stateOptional = Optional.ofNullable(call.argument("state")); final Integer state = call.argument("state");
if (stateOptional.isPresent()) { if (state != null) {
getSessionsByState(stateOptional.get(), result); getSessionsByState(state, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION_STATE", "Invalid session state value."); resultHandler.errorAsync(result, "INVALID_SESSION_STATE", "Invalid session state value.");
} }
@ -531,16 +561,16 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
getLogRedirectionStrategy(result); getLogRedirectionStrategy(result);
break; break;
case "setLogRedirectionStrategy": case "setLogRedirectionStrategy":
final Optional<Integer> strategyOptional = Optional.ofNullable(call.argument("strategy")); final Integer strategy = call.argument("strategy");
if (strategyOptional.isPresent()) { if (strategy != null) {
setLogRedirectionStrategy(strategyOptional.get(), result); setLogRedirectionStrategy(strategy, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_LOG_REDIRECTION_STRATEGY", "Invalid log redirection strategy value."); resultHandler.errorAsync(result, "INVALID_LOG_REDIRECTION_STRATEGY", "Invalid log redirection strategy value.");
} }
break; break;
case "messagesInTransmit": case "messagesInTransmit":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
messagesInTransmit(sessionIdOptional.get(), result); messagesInTransmit(sessionId, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
@ -549,11 +579,11 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
getPlatform(result); getPlatform(result);
break; break;
case "writeToPipe": case "writeToPipe":
final Optional<String> inputOptional = Optional.ofNullable(call.argument("input")); final String input = call.argument("input");
final Optional<String> pipeOptional = Optional.ofNullable(call.argument("pipe")); final String pipe = call.argument("pipe");
if (inputOptional.isPresent() && pipeOptional.isPresent()) { if (input != null && pipe != null) {
writeToPipe(inputOptional.get(), pipeOptional.get(), result); writeToPipe(input, pipe, result);
} else if (pipeOptional.isPresent()) { } else if (pipe != null) {
resultHandler.errorAsync(result, "INVALID_INPUT", "Invalid input value."); resultHandler.errorAsync(result, "INVALID_INPUT", "Invalid input value.");
} else { } else {
resultHandler.errorAsync(result, "INVALID_PIPE", "Invalid pipe value."); resultHandler.errorAsync(result, "INVALID_PIPE", "Invalid pipe value.");
@ -562,20 +592,26 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
case "selectDocument": case "selectDocument":
final String title = call.argument("title"); final String title = call.argument("title");
final String type = call.argument("type"); final String type = call.argument("type");
final Optional<List<String>> extraTypesOptional = Optional.ofNullable(call.argument("extraTypes")); final List<String> extraTypes = call.argument("extraTypes");
final String[] extraTypesArray = extraTypesOptional.map(strings -> strings.toArray(new String[0])).orElse(null); final String[] extraTypesArray;
if (writableOptional.isPresent()) { if (extraTypes != null) {
selectDocument(writableOptional.get(), title, type, extraTypesArray, result); extraTypesArray = extraTypes.toArray(new String[0]);
} else {
extraTypesArray = null;
}
if (writable != null) {
selectDocument(writable, title, type, extraTypesArray, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_WRITABLE", "Invalid writable value."); resultHandler.errorAsync(result, "INVALID_WRITABLE", "Invalid writable value.");
} }
break; break;
case "getSafParameter": case "getSafParameter":
final Optional<String> uriOptional = Optional.ofNullable(call.argument("uri")); final String uri = call.argument("uri");
if (writableOptional.isPresent() && uriOptional.isPresent()) { final String openMode = call.argument("openMode");
getSafParameter(writableOptional.get(), uriOptional.get(), result); if (uri != null && openMode != null) {
} else if (uriOptional.isPresent()) { getSafParameter(uri, openMode, result);
resultHandler.errorAsync(result, "INVALID_WRITABLE", "Invalid writable value."); } else if (uri != null) {
resultHandler.errorAsync(result, "INVALID_OPEN_MODE", "Invalid openMode value.");
} else { } else {
resultHandler.errorAsync(result, "INVALID_URI", "Invalid uri value."); resultHandler.errorAsync(result, "INVALID_URI", "Invalid uri value.");
} }
@ -584,8 +620,8 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
cancel(result); cancel(result);
break; break;
case "cancelSession": case "cancelSession":
if (sessionIdOptional.isPresent()) { if (sessionId != null) {
cancelSession(sessionIdOptional.get(), result); cancelSession(sessionId, result);
} else { } else {
resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id."); resultHandler.errorAsync(result, "INVALID_SESSION", "Invalid session id.");
} }
@ -596,6 +632,9 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
case "getFFprobeSessions": case "getFFprobeSessions":
getFFprobeSessions(result); getFFprobeSessions(result);
break; break;
case "getMediaInformationSessions":
getMediaInformationSessions(result);
break;
case "getPackageName": case "getPackageName":
getPackageName(result); getPackageName(result);
break; break;
@ -610,6 +649,8 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
protected void init(final BinaryMessenger messenger, final Context context, final Activity activity, final io.flutter.plugin.common.PluginRegistry.Registrar registrar, final ActivityPluginBinding activityBinding) { protected void init(final BinaryMessenger messenger, final Context context, final Activity activity, final io.flutter.plugin.common.PluginRegistry.Registrar registrar, final ActivityPluginBinding activityBinding) {
registerGlobalCallbacks();
if (methodChannel == null) { if (methodChannel == null) {
methodChannel = new MethodChannel(messenger, METHOD_CHANNEL); methodChannel = new MethodChannel(messenger, METHOD_CHANNEL);
methodChannel.setMethodCallHandler(this); methodChannel.setMethodCallHandler(this);
@ -635,7 +676,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
activityBinding.addActivityResultListener(this); activityBinding.addActivityResultListener(this);
} }
Log.d(LIBRARY_NAME, String.format("FFmpegKitFlutterPlugin initialized with context %s and activity %s.", context, activity)); Log.d(LIBRARY_NAME, String.format("FFmpegKitFlutterPlugin %s initialised with context %s and activity %s.", this, context, activity));
} }
protected void uninit() { protected void uninit() {
@ -648,7 +689,6 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
this.context = null; this.context = null;
this.activity = null; this.activity = null;
this.flutterPluginBinding = null;
this.activityPluginBinding = null; this.activityPluginBinding = null;
Log.d(LIBRARY_NAME, "FFmpegKitFlutterPlugin uninitialized."); Log.d(LIBRARY_NAME, "FFmpegKitFlutterPlugin uninitialized.");
@ -711,7 +751,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
timeout = AbstractSession.DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT; timeout = AbstractSession.DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT;
} }
final List<com.arthenica.ffmpegkit.Log> allLogs = session.getAllLogs(timeout); final List<com.arthenica.ffmpegkit.Log> allLogs = session.getAllLogs(timeout);
resultHandler.successAsync(result, allLogs.stream().map(FFmpegKitFlutterPlugin::toMap).collect(Collectors.toList())); resultHandler.successAsync(result, toLogMapList(allLogs));
} }
} }
@ -721,7 +761,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found."); resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found.");
} else { } else {
final List<com.arthenica.ffmpegkit.Log> allLogs = session.getLogs(); final List<com.arthenica.ffmpegkit.Log> allLogs = session.getLogs();
resultHandler.successAsync(result, allLogs.stream().map(FFmpegKitFlutterPlugin::toMap).collect(Collectors.toList())); resultHandler.successAsync(result, toLogMapList(allLogs));
} }
} }
@ -800,7 +840,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
if (session == null) { if (session == null) {
resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found."); resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found.");
} else { } else {
if (session instanceof FFmpegSession) { if (session.isFFmpeg()) {
final int timeout; final int timeout;
if (isValidPositiveNumber(waitTimeout)) { if (isValidPositiveNumber(waitTimeout)) {
timeout = waitTimeout; timeout = waitTimeout;
@ -808,7 +848,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
timeout = AbstractSession.DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT; timeout = AbstractSession.DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT;
} }
final List<Statistics> allStatistics = ((FFmpegSession) session).getAllStatistics(timeout); final List<Statistics> allStatistics = ((FFmpegSession) session).getAllStatistics(timeout);
resultHandler.successAsync(result, allStatistics.stream().map(FFmpegKitFlutterPlugin::toMap).collect(Collectors.toList())); resultHandler.successAsync(result, toStatisticsMapList(allStatistics));
} else { } else {
resultHandler.errorAsync(result, "NOT_FFMPEG_SESSION", "A session is found but it does not have the correct type."); resultHandler.errorAsync(result, "NOT_FFMPEG_SESSION", "A session is found but it does not have the correct type.");
} }
@ -820,9 +860,9 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
if (session == null) { if (session == null) {
resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found."); resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found.");
} else { } else {
if (session instanceof FFmpegSession) { if (session.isFFmpeg()) {
final List<Statistics> statistics = ((FFmpegSession) session).getStatistics(); final List<Statistics> statistics = ((FFmpegSession) session).getStatistics();
resultHandler.successAsync(result, statistics.stream().map(FFmpegKitFlutterPlugin::toMap).collect(Collectors.toList())); resultHandler.successAsync(result, toStatisticsMapList(statistics));
} else { } else {
resultHandler.errorAsync(result, "NOT_FFMPEG_SESSION", "A session is found but it does not have the correct type."); resultHandler.errorAsync(result, "NOT_FFMPEG_SESSION", "A session is found but it does not have the correct type.");
} }
@ -843,6 +883,21 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
resultHandler.successAsync(result, toMap(session)); resultHandler.successAsync(result, toMap(session));
} }
protected void getMediaInformation(@NonNull final Integer sessionId, @NonNull final Result result) {
final Session session = FFmpegKitConfig.getSession(sessionId.longValue());
if (session == null) {
resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found.");
} else {
if (session.isMediaInformation()) {
final MediaInformationSession mediaInformationSession = (MediaInformationSession) session;
final MediaInformation mediaInformation = mediaInformationSession.getMediaInformation();
resultHandler.successAsync(result, toMap(mediaInformation));
} else {
resultHandler.errorAsync(result, "NOT_MEDIA_INFORMATION_SESSION", "A session is found but it does not have the correct type.");
}
}
}
// MediaInformationJsonParser // MediaInformationJsonParser
protected void mediaInformationJsonParserFrom(@NonNull final String ffprobeJsonOutput, @NonNull final Result result) { protected void mediaInformationJsonParserFrom(@NonNull final String ffprobeJsonOutput, @NonNull final Result result) {
@ -988,12 +1043,60 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
} }
} }
protected void ffmpegSessionExecute(@NonNull final Integer sessionId, @NonNull final Result result) {
final Session session = FFmpegKitConfig.getSession(sessionId.longValue());
if (session == null) {
resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found.");
} else {
if (session.isFFmpeg()) {
final FFmpegSessionExecuteTask ffmpegSessionExecuteTask = new FFmpegSessionExecuteTask((FFmpegSession) session, resultHandler, result);
asyncExecutorService.submit(ffmpegSessionExecuteTask);
} else {
resultHandler.errorAsync(result, "NOT_FFMPEG_SESSION", "A session is found but it does not have the correct type.");
}
}
}
protected void ffprobeSessionExecute(@NonNull final Integer sessionId, @NonNull final Result result) {
final Session session = FFmpegKitConfig.getSession(sessionId.longValue());
if (session == null) {
resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found.");
} else {
if (session.isFFprobe()) {
final FFprobeSessionExecuteTask ffprobeSessionExecuteTask = new FFprobeSessionExecuteTask((FFprobeSession) session, resultHandler, result);
asyncExecutorService.submit(ffprobeSessionExecuteTask);
} else {
resultHandler.errorAsync(result, "NOT_FFPROBE_SESSION", "A session is found but it does not have the correct type.");
}
}
}
protected void mediaInformationSessionExecute(@NonNull final Integer sessionId, @Nullable final Integer waitTimeout, @NonNull final Result result) {
final Session session = FFmpegKitConfig.getSession(sessionId.longValue());
if (session == null) {
resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found.");
} else {
if (session.isMediaInformation()) {
final int timeout;
if (isValidPositiveNumber(waitTimeout)) {
timeout = waitTimeout;
} else {
timeout = AbstractSession.DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT;
}
final MediaInformationSessionExecuteTask mediaInformationSessionExecuteTask = new MediaInformationSessionExecuteTask((MediaInformationSession) session, timeout, resultHandler, result);
asyncExecutorService.submit(mediaInformationSessionExecuteTask);
} else {
resultHandler.errorAsync(result, "NOT_MEDIA_INFORMATION_SESSION", "A session is found but it does not have the correct type.");
}
}
}
protected void asyncFFmpegSessionExecute(@NonNull final Integer sessionId, @NonNull final Result result) { protected void asyncFFmpegSessionExecute(@NonNull final Integer sessionId, @NonNull final Result result) {
final Session session = FFmpegKitConfig.getSession(sessionId.longValue()); final Session session = FFmpegKitConfig.getSession(sessionId.longValue());
if (session == null) { if (session == null) {
resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found."); resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found.");
} else { } else {
if (session instanceof FFmpegSession) { if (session.isFFmpeg()) {
FFmpegKitConfig.asyncFFmpegExecute((FFmpegSession) session); FFmpegKitConfig.asyncFFmpegExecute((FFmpegSession) session);
resultHandler.successAsync(result, null); resultHandler.successAsync(result, null);
} else { } else {
@ -1007,7 +1110,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
if (session == null) { if (session == null) {
resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found."); resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found.");
} else { } else {
if (session instanceof FFprobeSession) { if (session.isFFprobe()) {
FFmpegKitConfig.asyncFFprobeExecute((FFprobeSession) session); FFmpegKitConfig.asyncFFprobeExecute((FFprobeSession) session);
resultHandler.successAsync(result, null); resultHandler.successAsync(result, null);
} else { } else {
@ -1021,7 +1124,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
if (session == null) { if (session == null) {
resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found."); resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found.");
} else { } else {
if (session instanceof MediaInformationSession) { if (session.isMediaInformation()) {
final int timeout; final int timeout;
if (isValidPositiveNumber(waitTimeout)) { if (isValidPositiveNumber(waitTimeout)) {
timeout = waitTimeout; timeout = waitTimeout;
@ -1074,7 +1177,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
} }
protected void getSessions(@NonNull final Result result) { protected void getSessions(@NonNull final Result result) {
resultHandler.successAsync(result, toSessionArray(FFmpegKitConfig.getSessions())); resultHandler.successAsync(result, toSessionMapList(FFmpegKitConfig.getSessions()));
} }
protected void clearSessions(@NonNull final Result result) { protected void clearSessions(@NonNull final Result result) {
@ -1083,7 +1186,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
} }
protected void getSessionsByState(@NonNull final Integer sessionState, @NonNull final Result result) { protected void getSessionsByState(@NonNull final Integer sessionState, @NonNull final Result result) {
resultHandler.successAsync(result, toSessionArray(FFmpegKitConfig.getSessionsByState(toSessionState(sessionState)))); resultHandler.successAsync(result, toSessionMapList(FFmpegKitConfig.getSessionsByState(toSessionState(sessionState))));
} }
protected void getLogRedirectionStrategy(@NonNull final Result result) { protected void getLogRedirectionStrategy(@NonNull final Result result) {
@ -1104,11 +1207,17 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
} }
protected void writeToPipe(@NonNull final String inputPath, @NonNull final String namedPipePath, @NonNull final Result result) { protected void writeToPipe(@NonNull final String inputPath, @NonNull final String namedPipePath, @NonNull final Result result) {
final AsyncWriteToPipeTask asyncTask = new AsyncWriteToPipeTask(inputPath, namedPipePath, resultHandler, result); final WriteToPipeTask asyncTask = new WriteToPipeTask(inputPath, namedPipePath, resultHandler, result);
asyncWriteToPipeExecutorService.submit(asyncTask); asyncExecutorService.submit(asyncTask);
} }
protected void selectDocument(@NonNull final Boolean writable, @Nullable final String title, @Nullable final String type, @Nullable final String[] extraTypes, @NonNull final Result result) { protected void selectDocument(@NonNull final Boolean writable, @Nullable final String title, @Nullable final String type, @Nullable final String[] extraTypes, @NonNull final Result result) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
android.util.Log.i(LIBRARY_NAME, String.format(Locale.getDefault(), "selectDocument is not supported on API Level %d", Build.VERSION.SDK_INT));
resultHandler.errorAsync(result, "SELECT_FAILED", String.format(Locale.getDefault(), "selectDocument is not supported on API Level %d", Build.VERSION.SDK_INT));
return;
}
final Intent intent; final Intent intent;
if (writable) { if (writable) {
intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
@ -1152,26 +1261,27 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
} }
} }
protected void getSafParameter(@NonNull final Boolean writable, @NonNull final String uriString, @NonNull final Result result) { protected void getSafParameter(@NonNull final String uriString, @NonNull final String openMode, @NonNull final Result result) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
android.util.Log.i(LIBRARY_NAME, String.format(Locale.getDefault(), "getSafParameter is not supported on API Level %d", Build.VERSION.SDK_INT));
resultHandler.errorAsync(result, "GET_SAF_PARAMETER_FAILED", String.format(Locale.getDefault(), "getSafParameter is not supported on API Level %d", Build.VERSION.SDK_INT));
return;
}
if (context != null) { if (context != null) {
final Uri uri = Uri.parse(uriString); final Uri uri = Uri.parse(uriString);
if (uri == null) { if (uri == null) {
Log.w(LIBRARY_NAME, String.format("Cannot getSafParameter using parameters writable: %s, uriString: %s. Uri string cannot be parsed.", writable, uriString)); Log.w(LIBRARY_NAME, String.format("Cannot getSafParameter using parameters uriString: %s, openMode: %s. Uri string cannot be parsed.", uriString, openMode));
resultHandler.errorAsync(result, "GET_SAF_PARAMETER_FAILED", "Uri string cannot be parsed."); resultHandler.errorAsync(result, "GET_SAF_PARAMETER_FAILED", "Uri string cannot be parsed.");
} else { } else {
final String safParameter; final String safParameter = FFmpegKitConfig.getSafParameter(context, uri, openMode);
if (writable) {
safParameter = FFmpegKitConfig.getSafParameterForWrite(context, uri);
} else {
safParameter = FFmpegKitConfig.getSafParameterForRead(context, uri);
}
Log.d(LIBRARY_NAME, String.format("getSafParameter using parameters writable: %s, uriString: %s completed with saf parameter: %s.", writable, uriString, safParameter)); Log.d(LIBRARY_NAME, String.format("getSafParameter using parameters uriString: %s, openMode: %s completed with saf parameter: %s.", uriString, openMode, safParameter));
resultHandler.successAsync(result, safParameter); resultHandler.successAsync(result, safParameter);
} }
} else { } else {
Log.w(LIBRARY_NAME, String.format("Cannot getSafParameter using parameters writable: %s, uriString: %s. Context is null.", writable, uriString)); Log.w(LIBRARY_NAME, String.format("Cannot getSafParameter using parameters uriString: %s, openMode: %s. Context is null.", uriString, openMode));
resultHandler.errorAsync(result, "INVALID_CONTEXT", "Context is null."); resultHandler.errorAsync(result, "INVALID_CONTEXT", "Context is null.");
} }
} }
@ -1189,13 +1299,17 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
} }
protected void getFFmpegSessions(@NonNull final Result result) { protected void getFFmpegSessions(@NonNull final Result result) {
resultHandler.successAsync(result, toSessionArray(FFmpegKit.listSessions())); resultHandler.successAsync(result, toSessionMapList(FFmpegKit.listSessions()));
} }
// FFprobeKit // FFprobeKit
protected void getFFprobeSessions(@NonNull final Result result) { protected void getFFprobeSessions(@NonNull final Result result) {
resultHandler.successAsync(result, toSessionArray(FFprobeKit.listSessions())); resultHandler.successAsync(result, toSessionMapList(FFprobeKit.listFFprobeSessions()));
}
protected void getMediaInformationSessions(@NonNull final Result result) {
resultHandler.successAsync(result, toSessionMapList(FFprobeKit.listMediaInformationSessions()));
} }
// Packages // Packages
@ -1240,19 +1354,17 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
sessionMap.put(KEY_SESSION_START_TIME, toLong(session.getStartTime())); sessionMap.put(KEY_SESSION_START_TIME, toLong(session.getStartTime()));
sessionMap.put(KEY_SESSION_COMMAND, session.getCommand()); sessionMap.put(KEY_SESSION_COMMAND, session.getCommand());
if (session.isFFprobe()) { if (session.isFFmpeg()) {
if (session instanceof MediaInformationSession) { sessionMap.put(KEY_SESSION_TYPE, SESSION_TYPE_FFMPEG);
} else if (session.isFFprobe()) {
sessionMap.put(KEY_SESSION_TYPE, SESSION_TYPE_FFPROBE);
} else if (session.isMediaInformation()) {
final MediaInformationSession mediaInformationSession = (MediaInformationSession) session; final MediaInformationSession mediaInformationSession = (MediaInformationSession) session;
final MediaInformation mediaInformation = mediaInformationSession.getMediaInformation(); final MediaInformation mediaInformation = mediaInformationSession.getMediaInformation();
if (mediaInformation != null) { if (mediaInformation != null) {
sessionMap.put(KEY_SESSION_MEDIA_INFORMATION, toMap(mediaInformation)); sessionMap.put(KEY_SESSION_MEDIA_INFORMATION, toMap(mediaInformation));
} }
sessionMap.put(KEY_SESSION_TYPE, SESSION_TYPE_MEDIA_INFORMATION); sessionMap.put(KEY_SESSION_TYPE, SESSION_TYPE_MEDIA_INFORMATION);
} else {
sessionMap.put(KEY_SESSION_TYPE, SESSION_TYPE_FFPROBE);
}
} else {
sessionMap.put(KEY_SESSION_TYPE, SESSION_TYPE_FFMPEG);
} }
return sessionMap; return sessionMap;
@ -1339,29 +1451,21 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
return statisticsMap; return statisticsMap;
} }
protected static List<Map<String, Object>> toSessionArray(final List<? extends Session> sessions) {
final List<Map<String, Object>> sessionArray = new ArrayList<>();
for (int i = 0; i < sessions.size(); i++) {
sessionArray.add(toMap(sessions.get(i)));
}
return sessionArray;
}
protected static Map<String, Object> toMap(final MediaInformation mediaInformation) { protected static Map<String, Object> toMap(final MediaInformation mediaInformation) {
if (mediaInformation != null) {
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
if (mediaInformation != null) {
if (mediaInformation.getAllProperties() != null) { if (mediaInformation.getAllProperties() != null) {
JSONObject allProperties = mediaInformation.getAllProperties(); JSONObject allProperties = mediaInformation.getAllProperties();
if (allProperties != null) { if (allProperties != null) {
map = toMap(allProperties); map = toMap(allProperties);
} }
} }
}
return map; return map;
} else {
return null;
}
} }
protected static Map<String, Object> toMap(final JSONObject jsonObject) { protected static Map<String, Object> toMap(final JSONObject jsonObject) {
@ -1404,6 +1508,36 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
return list; return list;
} }
protected static List<Map<String, Object>> toSessionMapList(final List<? extends Session> sessionList) {
final List<Map<String, Object>> list = new ArrayList<>();
for (int i = 0; i < sessionList.size(); i++) {
list.add(toMap(sessionList.get(i)));
}
return list;
}
protected static List<Map<String, Object>> toLogMapList(final List<com.arthenica.ffmpegkit.Log> logList) {
final List<Map<String, Object>> list = new ArrayList<>();
for (int i = 0; i < logList.size(); i++) {
list.add(toMap(logList.get(i)));
}
return list;
}
protected static List<Map<String, Object>> toStatisticsMapList(final List<com.arthenica.ffmpegkit.Statistics> statisticsList) {
final List<Map<String, Object>> list = new ArrayList<>();
for (int i = 0; i < statisticsList.size(); i++) {
list.add(toMap(statisticsList.get(i)));
}
return list;
}
protected static boolean isValidPositiveNumber(final Integer value) { protected static boolean isValidPositiveNumber(final Integer value) {
return (value != null) && (value >= 0); return (value != null) && (value >= 0);
} }
@ -1422,7 +1556,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
protected void emitSession(final Session session) { protected void emitSession(final Session session) {
final HashMap<String, Object> sessionMap = new HashMap<>(); final HashMap<String, Object> sessionMap = new HashMap<>();
sessionMap.put(EVENT_EXECUTE_CALLBACK_EVENT, toMap(session)); sessionMap.put(EVENT_COMPLETE_CALLBACK_EVENT, toMap(session));
resultHandler.successAsync(eventSink, sessionMap); resultHandler.successAsync(eventSink, sessionMap);
} }

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2021 Taner Sener
*
* This file is part of FFmpegKit.
*
* FFmpegKit 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.
*
* FFmpegKit 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 FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.ffmpegkit.flutter;
import androidx.annotation.NonNull;
import com.arthenica.ffmpegkit.FFmpegKitConfig;
import com.arthenica.ffmpegkit.FFmpegSession;
import io.flutter.plugin.common.MethodChannel;
public class FFmpegSessionExecuteTask implements Runnable {
private final FFmpegSession ffmpegSession;
private final FFmpegKitFlutterMethodResultHandler resultHandler;
private final MethodChannel.Result result;
public FFmpegSessionExecuteTask(@NonNull final FFmpegSession ffmpegSession, @NonNull final FFmpegKitFlutterMethodResultHandler resultHandler, @NonNull final MethodChannel.Result result) {
this.ffmpegSession = ffmpegSession;
this.resultHandler = resultHandler;
this.result = result;
}
@Override
public void run() {
FFmpegKitConfig.ffmpegExecute(ffmpegSession);
resultHandler.successAsync(result, null);
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2021 Taner Sener
*
* This file is part of FFmpegKit.
*
* FFmpegKit 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.
*
* FFmpegKit 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 FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.ffmpegkit.flutter;
import androidx.annotation.NonNull;
import com.arthenica.ffmpegkit.FFmpegKitConfig;
import com.arthenica.ffmpegkit.FFprobeSession;
import io.flutter.plugin.common.MethodChannel;
public class FFprobeSessionExecuteTask implements Runnable {
private final FFprobeSession ffprobeSession;
private final FFmpegKitFlutterMethodResultHandler resultHandler;
private final MethodChannel.Result result;
public FFprobeSessionExecuteTask(@NonNull final FFprobeSession ffprobeSession, @NonNull final FFmpegKitFlutterMethodResultHandler resultHandler, @NonNull final MethodChannel.Result result) {
this.ffprobeSession = ffprobeSession;
this.resultHandler = resultHandler;
this.result = result;
}
@Override
public void run() {
FFmpegKitConfig.ffprobeExecute(ffprobeSession);
resultHandler.successAsync(result, null);
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2021 Taner Sener
*
* This file is part of FFmpegKit.
*
* FFmpegKit 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.
*
* FFmpegKit 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 FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.ffmpegkit.flutter;
import androidx.annotation.NonNull;
import com.arthenica.ffmpegkit.FFmpegKitConfig;
import com.arthenica.ffmpegkit.MediaInformationSession;
import io.flutter.plugin.common.MethodChannel;
public class MediaInformationSessionExecuteTask implements Runnable {
private final MediaInformationSession mediaInformationSession;
private final int timeout;
private final FFmpegKitFlutterMethodResultHandler resultHandler;
private final MethodChannel.Result result;
public MediaInformationSessionExecuteTask(@NonNull final MediaInformationSession mediaInformationSession, final int timeout, @NonNull final FFmpegKitFlutterMethodResultHandler resultHandler, @NonNull final MethodChannel.Result result) {
this.mediaInformationSession = mediaInformationSession;
this.timeout = timeout;
this.resultHandler = resultHandler;
this.result = result;
}
@Override
public void run() {
FFmpegKitConfig.getMediaInformationExecute(mediaInformationSession, timeout);
resultHandler.successAsync(result, null);
}
}

View File

@ -29,13 +29,13 @@ import java.io.IOException;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class AsyncWriteToPipeTask implements Runnable { public class WriteToPipeTask implements Runnable {
private final String inputPath; private final String inputPath;
private final String namedPipePath; private final String namedPipePath;
private final FFmpegKitFlutterMethodResultHandler resultHandler; private final FFmpegKitFlutterMethodResultHandler resultHandler;
private final MethodChannel.Result result; private final MethodChannel.Result result;
public AsyncWriteToPipeTask(@NonNull final String inputPath, @NonNull final String namedPipePath, @NonNull final FFmpegKitFlutterMethodResultHandler resultHandler, @NonNull final MethodChannel.Result result) { public WriteToPipeTask(@NonNull final String inputPath, @NonNull final String namedPipePath, @NonNull final FFmpegKitFlutterMethodResultHandler resultHandler, @NonNull final MethodChannel.Result result) {
this.inputPath = inputPath; this.inputPath = inputPath;
this.namedPipePath = namedPipePath; this.namedPipePath = namedPipePath;
this.resultHandler = resultHandler; this.resultHandler = resultHandler;

View File

@ -57,7 +57,7 @@ static int const SESSION_TYPE_MEDIA_INFORMATION = 3;
// EVENTS // EVENTS
static NSString *const EVENT_LOG_CALLBACK_EVENT = @"FFmpegKitLogCallbackEvent"; static NSString *const EVENT_LOG_CALLBACK_EVENT = @"FFmpegKitLogCallbackEvent";
static NSString *const EVENT_STATISTICS_CALLBACK_EVENT = @"FFmpegKitStatisticsCallbackEvent"; static NSString *const EVENT_STATISTICS_CALLBACK_EVENT = @"FFmpegKitStatisticsCallbackEvent";
static NSString *const EVENT_EXECUTE_CALLBACK_EVENT = @"FFmpegKitExecuteCallbackEvent"; static NSString *const EVENT_COMPLETE_CALLBACK_EVENT = @"FFmpegKitCompleteCallbackEvent";
// ARGUMENT NAMES // ARGUMENT NAMES
static NSString *const ARGUMENT_SESSION_ID = @"sessionId"; static NSString *const ARGUMENT_SESSION_ID = @"sessionId";
@ -71,7 +71,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
FlutterEventSink _eventSink; FlutterEventSink _eventSink;
BOOL logsEnabled; BOOL logsEnabled;
BOOL statisticsEnabled; BOOL statisticsEnabled;
dispatch_queue_t asyncWriteToPipeDispatchQueue; dispatch_queue_t asyncDispatchQueue;
} }
- (instancetype)init { - (instancetype)init {
@ -79,9 +79,9 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
if (self) { if (self) {
logsEnabled = false; logsEnabled = false;
statisticsEnabled = false; statisticsEnabled = false;
asyncWriteToPipeDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); asyncDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
[self registerGlobalCallbacks]; NSLog(@"FFmpegKitFlutterPlugin %p created.\n", self);
} }
return self; return self;
@ -89,6 +89,8 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
- (FlutterError *)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink { - (FlutterError *)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink {
_eventSink = eventSink; _eventSink = eventSink;
NSLog(@"FFmpegKitFlutterPlugin %p started listening to events on %p.\n", self, eventSink);
[self registerGlobalCallbacks];
return nil; return nil;
} }
@ -108,9 +110,19 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
} }
- (void)registerGlobalCallbacks { - (void)registerGlobalCallbacks {
[FFmpegKitConfig enableExecuteCallback:^(id<Session> session){ [FFmpegKitConfig enableFFmpegSessionCompleteCallback:^(FFmpegSession* session){
NSDictionary *dictionary = [FFmpegKitFlutterPlugin toSessionDictionary:session]; NSDictionary *dictionary = [FFmpegKitFlutterPlugin toSessionDictionary:session];
self->_eventSink([FFmpegKitFlutterPlugin toStringDictionary:EVENT_EXECUTE_CALLBACK_EVENT withDictionary:dictionary]); self->_eventSink([FFmpegKitFlutterPlugin toStringDictionary:EVENT_COMPLETE_CALLBACK_EVENT withDictionary:dictionary]);
}];
[FFmpegKitConfig enableFFprobeSessionCompleteCallback:^(FFprobeSession* session){
NSDictionary *dictionary = [FFmpegKitFlutterPlugin toSessionDictionary:session];
self->_eventSink([FFmpegKitFlutterPlugin toStringDictionary:EVENT_COMPLETE_CALLBACK_EVENT withDictionary:dictionary]);
}];
[FFmpegKitConfig enableMediaInformationSessionCompleteCallback:^(MediaInformationSession* session){
NSDictionary *dictionary = [FFmpegKitFlutterPlugin toSessionDictionary:session];
self->_eventSink([FFmpegKitFlutterPlugin toStringDictionary:EVENT_COMPLETE_CALLBACK_EVENT withDictionary:dictionary]);
}]; }];
[FFmpegKitConfig enableLogCallback: ^(Log* log){ [FFmpegKitConfig enableLogCallback: ^(Log* log){
@ -220,6 +232,12 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
} else { } else {
result([FlutterError errorWithCode:@"INVALID_ARGUMENTS" message:@"Invalid arguments array." details:nil]); result([FlutterError errorWithCode:@"INVALID_ARGUMENTS" message:@"Invalid arguments array." details:nil]);
} }
} else if ([@"getMediaInformation" isEqualToString:call.method]) {
if (sessionId != nil) {
[self getMediaInformation:sessionId result:result];
} else {
result([FlutterError errorWithCode:@"INVALID_SESSION" message:@"Invalid session id." details:nil]);
}
} else if ([@"mediaInformationJsonParserFrom" isEqualToString:call.method]) { } else if ([@"mediaInformationJsonParserFrom" isEqualToString:call.method]) {
if (ffprobeJsonOutput != nil) { if (ffprobeJsonOutput != nil) {
[self mediaInformationJsonParserFrom:ffprobeJsonOutput result:result]; [self mediaInformationJsonParserFrom:ffprobeJsonOutput result:result];
@ -299,6 +317,24 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
} else { } else {
result([FlutterError errorWithCode:@"INVALID_SIGNAL" message:@"Invalid signal value." details:nil]); result([FlutterError errorWithCode:@"INVALID_SIGNAL" message:@"Invalid signal value." details:nil]);
} }
} else if ([@"ffmpegSessionExecute" isEqualToString:call.method]) {
if (sessionId != nil) {
[self ffmpegSessionExecute:sessionId result:result];
} else {
result([FlutterError errorWithCode:@"INVALID_SESSION" message:@"Invalid session id." details:nil]);
}
} else if ([@"ffprobeSessionExecute" isEqualToString:call.method]) {
if (sessionId != nil) {
[self ffprobeSessionExecute:sessionId result:result];
} else {
result([FlutterError errorWithCode:@"INVALID_SESSION" message:@"Invalid session id." details:nil]);
}
} else if ([@"mediaInformationSessionExecute" isEqualToString:call.method]) {
if (sessionId != nil) {
[self mediaInformationSessionExecute:sessionId timeout:waitTimeout result:result];
} else {
result([FlutterError errorWithCode:@"INVALID_SESSION" message:@"Invalid session id." details:nil]);
}
} else if ([@"asyncFFmpegSessionExecute" isEqualToString:call.method]) { } else if ([@"asyncFFmpegSessionExecute" isEqualToString:call.method]) {
if (sessionId != nil) { if (sessionId != nil) {
[self asyncFFmpegSessionExecute:sessionId result:result]; [self asyncFFmpegSessionExecute:sessionId result:result];
@ -399,6 +435,8 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
[self getFFmpegSessions:result]; [self getFFmpegSessions:result];
} else if ([@"getFFprobeSessions" isEqualToString:call.method]) { } else if ([@"getFFprobeSessions" isEqualToString:call.method]) {
[self getFFprobeSessions:result]; [self getFFprobeSessions:result];
} else if ([@"getMediaInformationSessions" isEqualToString:call.method]) {
[self getMediaInformationSessions:result];
} else if ([@"getPackageName" isEqualToString:call.method]) { } else if ([@"getPackageName" isEqualToString:call.method]) {
[self getPackageName:result]; [self getPackageName:result];
} else if ([@"getExternalLibraries" isEqualToString:call.method]) { } else if ([@"getExternalLibraries" isEqualToString:call.method]) {
@ -525,7 +563,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
// FFmpegSession // FFmpegSession
- (void)ffmpegSession:(NSArray*)arguments result:(FlutterResult)result { - (void)ffmpegSession:(NSArray*)arguments result:(FlutterResult)result {
FFmpegSession* session = [[FFmpegSession alloc] init:arguments withExecuteCallback:nil withLogCallback:nil withStatisticsCallback:nil withLogRedirectionStrategy:LogRedirectionStrategyNeverPrintLogs]; FFmpegSession* session = [[FFmpegSession alloc] init:arguments withCompleteCallback:nil withLogCallback:nil withStatisticsCallback:nil withLogRedirectionStrategy:LogRedirectionStrategyNeverPrintLogs];
result([FFmpegKitFlutterPlugin toSessionDictionary:session]); result([FFmpegKitFlutterPlugin toSessionDictionary:session]);
} }
@ -534,7 +572,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
if (session == nil) { if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else { } else {
if ([session isMemberOfClass:[FFmpegSession class]]) { if ([session isFFmpeg]) {
int timeout; int timeout;
if ([FFmpegKitFlutterPlugin isValidPositiveNumber:waitTimeout]) { if ([FFmpegKitFlutterPlugin isValidPositiveNumber:waitTimeout]) {
timeout = [waitTimeout intValue]; timeout = [waitTimeout intValue];
@ -554,7 +592,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
if (session == nil) { if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else { } else {
if ([session isMemberOfClass:[FFmpegSession class]]) { if ([session isFFmpeg]) {
NSArray* statistics = [(FFmpegSession*)session getStatistics]; NSArray* statistics = [(FFmpegSession*)session getStatistics];
result([FFmpegKitFlutterPlugin toStatisticsArray:statistics]); result([FFmpegKitFlutterPlugin toStatisticsArray:statistics]);
} else { } else {
@ -566,17 +604,31 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
// FFprobeSession // FFprobeSession
- (void)ffprobeSession:(NSArray*)arguments result:(FlutterResult)result { - (void)ffprobeSession:(NSArray*)arguments result:(FlutterResult)result {
FFprobeSession* session = [[FFprobeSession alloc] init:arguments withExecuteCallback:nil withLogCallback:nil withLogRedirectionStrategy:LogRedirectionStrategyNeverPrintLogs]; FFprobeSession* session = [[FFprobeSession alloc] init:arguments withCompleteCallback:nil withLogCallback:nil withLogRedirectionStrategy:LogRedirectionStrategyNeverPrintLogs];
result([FFmpegKitFlutterPlugin toSessionDictionary:session]); result([FFmpegKitFlutterPlugin toSessionDictionary:session]);
} }
// MediaInformationSession // MediaInformationSession
- (void)mediaInformationSession:(NSArray*)arguments result:(FlutterResult)result { - (void)mediaInformationSession:(NSArray*)arguments result:(FlutterResult)result {
MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments withExecuteCallback:nil withLogCallback:nil]; MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments withCompleteCallback:nil withLogCallback:nil];
result([FFmpegKitFlutterPlugin toSessionDictionary:session]); result([FFmpegKitFlutterPlugin toSessionDictionary:session]);
} }
- (void)getMediaInformation:(NSNumber*)sessionId result:(FlutterResult)result {
AbstractSession* session = (AbstractSession*)[FFmpegKitConfig getSession:[sessionId longValue]];
if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else {
if ([session isMediaInformation]) {
MediaInformationSession *mediaInformationSession = (MediaInformationSession*)session;
result([FFmpegKitFlutterPlugin toMediaInformationDictionary:[mediaInformationSession getMediaInformation]]);
} else {
result([FlutterError errorWithCode:@"NOT_MEDIA_INFORMATION_SESSION" message:@"A session is found but it does not have the correct type." details:nil]);
}
}
}
// MediaInformationJsonParser // MediaInformationJsonParser
- (void)mediaInformationJsonParserFrom:(NSString*)ffprobeJsonOutput result:(FlutterResult)result { - (void)mediaInformationJsonParserFrom:(NSString*)ffprobeJsonOutput result:(FlutterResult)result {
@ -708,12 +760,66 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
} }
} }
- (void)ffmpegSessionExecute:(NSNumber*)sessionId result:(FlutterResult)result {
AbstractSession* session = (AbstractSession*)[FFmpegKitConfig getSession:[sessionId longValue]];
if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else {
if ([session isFFmpeg]) {
dispatch_async(asyncDispatchQueue, ^{
[FFmpegKitConfig ffmpegExecute:(FFmpegSession*)session];
result(nil);
});
} else {
result([FlutterError errorWithCode:@"NOT_FFMPEG_SESSION" message:@"A session is found but it does not have the correct type." details:nil]);
}
}
}
- (void)ffprobeSessionExecute:(NSNumber*)sessionId result:(FlutterResult)result {
AbstractSession* session = (AbstractSession*)[FFmpegKitConfig getSession:[sessionId longValue]];
if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else {
if ([session isFFprobe]) {
dispatch_async(asyncDispatchQueue, ^{
[FFmpegKitConfig ffprobeExecute:(FFprobeSession*)session];
result(nil);
});
} else {
result([FlutterError errorWithCode:@"NOT_FFPROBE_SESSION" message:@"A session is found but it does not have the correct type." details:nil]);
}
}
}
- (void)mediaInformationSessionExecute:(NSNumber*)sessionId timeout:(NSNumber*)waitTimeout result:(FlutterResult)result {
AbstractSession* session = (AbstractSession*)[FFmpegKitConfig getSession:[sessionId longValue]];
if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else {
if ([session isMediaInformation]) {
int timeout;
if ([FFmpegKitFlutterPlugin isValidPositiveNumber:waitTimeout]) {
timeout = [waitTimeout intValue];
} else {
timeout = AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
}
dispatch_async(asyncDispatchQueue, ^{
[FFmpegKitConfig getMediaInformationExecute:(MediaInformationSession*)session withTimeout:timeout];
result(nil);
});
} else {
result([FlutterError errorWithCode:@"NOT_MEDIA_INFORMATION_SESSION" message:@"A session is found but it does not have the correct type." details:nil]);
}
}
}
- (void)asyncFFmpegSessionExecute:(NSNumber*)sessionId result:(FlutterResult)result { - (void)asyncFFmpegSessionExecute:(NSNumber*)sessionId result:(FlutterResult)result {
AbstractSession* session = (AbstractSession*)[FFmpegKitConfig getSession:[sessionId longValue]]; AbstractSession* session = (AbstractSession*)[FFmpegKitConfig getSession:[sessionId longValue]];
if (session == nil) { if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else { } else {
if ([session isMemberOfClass:[FFmpegSession class]]) { if ([session isFFmpeg]) {
[FFmpegKitConfig asyncFFmpegExecute:(FFmpegSession*)session]; [FFmpegKitConfig asyncFFmpegExecute:(FFmpegSession*)session];
result(nil); result(nil);
} else { } else {
@ -727,7 +833,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
if (session == nil) { if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else { } else {
if ([session isMemberOfClass:[FFprobeSession class]]) { if ([session isFFprobe]) {
[FFmpegKitConfig asyncFFprobeExecute:(FFprobeSession*)session]; [FFmpegKitConfig asyncFFprobeExecute:(FFprobeSession*)session];
result(nil); result(nil);
} else { } else {
@ -741,7 +847,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
if (session == nil) { if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else { } else {
if ([session isMemberOfClass:[MediaInformationSession class]]) { if ([session isMediaInformation]) {
int timeout; int timeout;
if ([FFmpegKitFlutterPlugin isValidPositiveNumber:waitTimeout]) { if ([FFmpegKitFlutterPlugin isValidPositiveNumber:waitTimeout]) {
timeout = [waitTimeout intValue]; timeout = [waitTimeout intValue];
@ -852,7 +958,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
} }
- (void)writeToPipe:(NSString*)inputPath pipe:(NSString*)namedPipePath result:(FlutterResult)result { - (void)writeToPipe:(NSString*)inputPath pipe:(NSString*)namedPipePath result:(FlutterResult)result {
dispatch_async(asyncWriteToPipeDispatchQueue, ^{ dispatch_async(asyncDispatchQueue, ^{
NSLog(@"Starting copy %@ to pipe %@ operation.\n", inputPath, namedPipePath); NSLog(@"Starting copy %@ to pipe %@ operation.\n", inputPath, namedPipePath);
@ -933,7 +1039,11 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
// FFprobeKit // FFprobeKit
- (void)getFFprobeSessions:(FlutterResult)result { - (void)getFFprobeSessions:(FlutterResult)result {
result([FFmpegKitFlutterPlugin toSessionArray:[FFprobeKit listSessions]]); result([FFmpegKitFlutterPlugin toSessionArray:[FFprobeKit listFFprobeSessions]]);
}
- (void)getMediaInformationSessions:(FlutterResult)result {
result([FFmpegKitFlutterPlugin toSessionArray:[FFprobeKit listMediaInformationSessions]]);
} }
// Packages // Packages
@ -971,16 +1081,14 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
dictionary[KEY_SESSION_START_TIME] = [NSNumber numberWithLong:[[session getStartTime] timeIntervalSince1970]*1000]; dictionary[KEY_SESSION_START_TIME] = [NSNumber numberWithLong:[[session getStartTime] timeIntervalSince1970]*1000];
dictionary[KEY_SESSION_COMMAND] = [session getCommand]; dictionary[KEY_SESSION_COMMAND] = [session getCommand];
if ([session isFFprobe]) { if ([session isFFmpeg]) {
if ([(AbstractSession*)session isMemberOfClass:[MediaInformationSession class]]) { dictionary[KEY_SESSION_TYPE] = [NSNumber numberWithInt:SESSION_TYPE_FFMPEG];
} else if ([session isFFprobe]) {
dictionary[KEY_SESSION_TYPE] = [NSNumber numberWithInt:SESSION_TYPE_FFPROBE];
} else if ([session isMediaInformation]) {
MediaInformationSession *mediaInformationSession = (MediaInformationSession*)session; MediaInformationSession *mediaInformationSession = (MediaInformationSession*)session;
dictionary[KEY_SESSION_MEDIA_INFORMATION] = [FFmpegKitFlutterPlugin toMediaInformationDictionary:[mediaInformationSession getMediaInformation]]; dictionary[KEY_SESSION_MEDIA_INFORMATION] = [FFmpegKitFlutterPlugin toMediaInformationDictionary:[mediaInformationSession getMediaInformation]];
dictionary[KEY_SESSION_TYPE] = [NSNumber numberWithInt:SESSION_TYPE_MEDIA_INFORMATION]; dictionary[KEY_SESSION_TYPE] = [NSNumber numberWithInt:SESSION_TYPE_MEDIA_INFORMATION];
} else {
dictionary[KEY_SESSION_TYPE] = [NSNumber numberWithInt:SESSION_TYPE_FFPROBE];
}
} else {
dictionary[KEY_SESSION_TYPE] = [NSNumber numberWithInt:SESSION_TYPE_FFMPEG];
} }
return dictionary; return dictionary;

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'ffmpeg_kit_flutter' s.name = 'ffmpeg_kit_flutter'
s.version = '4.5.0' s.version = '4.5.1'
s.summary = 'FFmpeg Kit for Flutter' s.summary = 'FFmpeg Kit for Flutter'
s.description = 'A Flutter plugin for running FFmpeg and FFprobe commands.' s.description = 'A Flutter plugin for running FFmpeg and FFprobe commands.'
s.homepage = 'https://github.com/tanersener/ffmpeg-kit' s.homepage = 'https://github.com/tanersener/ffmpeg-kit'
@ -23,113 +23,113 @@ Pod::Spec.new do |s|
s.subspec 'min' do |ss| s.subspec 'min' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-min', "4.5" ss.dependency 'ffmpeg-kit-ios-min', "4.5.1"
ss.ios.deployment_target = '12.1' ss.ios.deployment_target = '12.1'
end end
s.subspec 'min-lts' do |ss| s.subspec 'min-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-min', "4.5.LTS" ss.dependency 'ffmpeg-kit-ios-min', "4.5.1.LTS"
ss.ios.deployment_target = '9.3' ss.ios.deployment_target = '10'
end end
s.subspec 'min-gpl' do |ss| s.subspec 'min-gpl' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-min-gpl', "4.5" ss.dependency 'ffmpeg-kit-ios-min-gpl', "4.5.1"
ss.ios.deployment_target = '12.1' ss.ios.deployment_target = '12.1'
end end
s.subspec 'min-gpl-lts' do |ss| s.subspec 'min-gpl-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-min-gpl', "4.5.LTS" ss.dependency 'ffmpeg-kit-ios-min-gpl', "4.5.1.LTS"
ss.ios.deployment_target = '9.3' ss.ios.deployment_target = '10'
end end
s.subspec 'https' do |ss| s.subspec 'https' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-https', "4.5" ss.dependency 'ffmpeg-kit-ios-https', "4.5.1"
ss.ios.deployment_target = '12.1' ss.ios.deployment_target = '12.1'
end end
s.subspec 'https-lts' do |ss| s.subspec 'https-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-https', "4.5.LTS" ss.dependency 'ffmpeg-kit-ios-https', "4.5.1.LTS"
ss.ios.deployment_target = '9.3' ss.ios.deployment_target = '10'
end end
s.subspec 'https-gpl' do |ss| s.subspec 'https-gpl' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-https-gpl', "4.5" ss.dependency 'ffmpeg-kit-ios-https-gpl', "4.5.1"
ss.ios.deployment_target = '12.1' ss.ios.deployment_target = '12.1'
end end
s.subspec 'https-gpl-lts' do |ss| s.subspec 'https-gpl-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-https-gpl', "4.5.LTS" ss.dependency 'ffmpeg-kit-ios-https-gpl', "4.5.1.LTS"
ss.ios.deployment_target = '9.3' ss.ios.deployment_target = '10'
end end
s.subspec 'audio' do |ss| s.subspec 'audio' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-audio', "4.5" ss.dependency 'ffmpeg-kit-ios-audio', "4.5.1"
ss.ios.deployment_target = '12.1' ss.ios.deployment_target = '12.1'
end end
s.subspec 'audio-lts' do |ss| s.subspec 'audio-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-audio', "4.5.LTS" ss.dependency 'ffmpeg-kit-ios-audio', "4.5.1.LTS"
ss.ios.deployment_target = '9.3' ss.ios.deployment_target = '10'
end end
s.subspec 'video' do |ss| s.subspec 'video' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-video', "4.5" ss.dependency 'ffmpeg-kit-ios-video', "4.5.1"
ss.ios.deployment_target = '12.1' ss.ios.deployment_target = '12.1'
end end
s.subspec 'video-lts' do |ss| s.subspec 'video-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-video', "4.5.LTS" ss.dependency 'ffmpeg-kit-ios-video', "4.5.1.LTS"
ss.ios.deployment_target = '9.3' ss.ios.deployment_target = '10'
end end
s.subspec 'full' do |ss| s.subspec 'full' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-full', "4.5" ss.dependency 'ffmpeg-kit-ios-full', "4.5.1"
ss.ios.deployment_target = '12.1' ss.ios.deployment_target = '12.1'
end end
s.subspec 'full-lts' do |ss| s.subspec 'full-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-full', "4.5.LTS" ss.dependency 'ffmpeg-kit-ios-full', "4.5.1.LTS"
ss.ios.deployment_target = '9.3' ss.ios.deployment_target = '10'
end end
s.subspec 'full-gpl' do |ss| s.subspec 'full-gpl' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-full-gpl', "4.5" ss.dependency 'ffmpeg-kit-ios-full-gpl', "4.5.1"
ss.ios.deployment_target = '12.1' ss.ios.deployment_target = '12.1'
end end
s.subspec 'full-gpl-lts' do |ss| s.subspec 'full-gpl-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-ios-full-gpl', "4.5.LTS" ss.dependency 'ffmpeg-kit-ios-full-gpl', "4.5.1.LTS"
ss.ios.deployment_target = '9.3' ss.ios.deployment_target = '10'
end end
end end

View File

@ -20,7 +20,6 @@
import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platform_interface.dart'; import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platform_interface.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'execute_callback.dart';
import 'ffmpeg_kit_config.dart'; import 'ffmpeg_kit_config.dart';
import 'ffmpeg_session.dart'; import 'ffmpeg_session.dart';
import 'ffprobe_session.dart'; import 'ffprobe_session.dart';
@ -35,7 +34,7 @@ import 'session_state.dart';
import 'src/ffmpeg_kit_factory.dart'; import 'src/ffmpeg_kit_factory.dart';
/// Abstract session implementation which includes common features shared by /// Abstract session implementation which includes common features shared by
/// "FFmpeg" and "FFprobe" sessions. /// "FFmpeg", "FFprobe" and "MediaInformation" sessions.
class AbstractSession extends Session { class AbstractSession extends Session {
static FFmpegKitPlatform _platform = FFmpegKitPlatform.instance; static FFmpegKitPlatform _platform = FFmpegKitPlatform.instance;
@ -221,11 +220,7 @@ class AbstractSession extends Session {
return session; return session;
} }
/// Returns the session specific execute callback function. /// Returns the session specific log callback.
ExecuteCallback? getExecuteCallback() =>
FFmpegKitFactory.getExecuteCallback(this.getSessionId());
/// Returns the session specific log callback function.
LogCallback? getLogCallback() => LogCallback? getLogCallback() =>
FFmpegKitFactory.getLogCallback(this.getSessionId()); FFmpegKitFactory.getLogCallback(this.getSessionId());
@ -429,6 +424,9 @@ class AbstractSession extends Session {
/// Returns whether it is an "FFprobe" session or not. /// Returns whether it is an "FFprobe" session or not.
bool isFFprobe() => false; bool isFFprobe() => false;
/// Returns whether it is an "MediaInformation" session or not.
bool isMediaInformation() => false;
/// Cancels running the session. /// Cancels running the session.
void cancel() {} void cancel() {}
} }

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2021 Taner Sener
*
* This file is part of FFmpegKit.
*
* FFmpegKit 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.
*
* FFmpegKit 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 FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
*/
/// Chapter class.
class Chapter {
static const keyId = "id";
static const keyTimeBase = "time_base";
static const keyStart = "start";
static const keyStartTime = "start_time";
static const keyEnd = "end";
static const keyEndTime = "end_time";
static const keyTags = "tags";
Map<dynamic, dynamic>? _allProperties;
/// Creates a new [Chapter] instance
Chapter(this._allProperties);
/// Returns id.
int? getId() => this.getNumberProperty(Chapter.keyId)?.toInt();
/// Returns time base.
String? getTimeBase() => this.getStringProperty(Chapter.keyTimeBase);
/// Returns start.
int? getStart() => this.getNumberProperty(Chapter.keyStart)?.toInt();
/// Returns start time.
String? getStartTime() => this.getStringProperty(Chapter.keyStartTime);
/// Returns end.
int? getEnd() => this.getNumberProperty(Chapter.keyEnd)?.toInt();
/// Returns end time.
String? getEndTime() => this.getStringProperty(Chapter.keyEndTime);
/// Returns all tags.
Map<dynamic, dynamic>? getTags() => this.getProperties(Chapter.keyTags);
/// Returns the chapter property associated with the key.
String? getStringProperty(String key) => this._allProperties?[key];
/// Returns the chapter property associated with the key.
num? getNumberProperty(String key) => this._allProperties?[key];
/// Returns the chapter properties associated with the key.
dynamic getProperties(String key) => this._allProperties?[key];
/// Returns all properties found.
Map<dynamic, dynamic>? getAllProperties() => this._allProperties;
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2021 Taner Sener * Copyright (c) 2019-2022 Taner Sener
* *
* This file is part of FFmpegKit. * This file is part of FFmpegKit.
* *
@ -20,9 +20,9 @@
import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platform_interface.dart'; import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platform_interface.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'execute_callback.dart';
import 'ffmpeg_kit_config.dart'; import 'ffmpeg_kit_config.dart';
import 'ffmpeg_session.dart'; import 'ffmpeg_session.dart';
import 'ffmpeg_session_complete_callback.dart';
import 'log_callback.dart'; import 'log_callback.dart';
import 'src/ffmpeg_kit_factory.dart'; import 'src/ffmpeg_kit_factory.dart';
import 'statistics_callback.dart'; import 'statistics_callback.dart';
@ -31,32 +31,49 @@ import 'statistics_callback.dart';
class FFmpegKit { class FFmpegKit {
static FFmpegKitPlatform _platform = FFmpegKitPlatform.instance; static FFmpegKitPlatform _platform = FFmpegKitPlatform.instance;
/// Synchronously executes FFmpeg command provided. Space character is used
/// to split command into arguments. You can use single or double quote
/// characters to specify arguments inside your command.
static Future<FFmpegSession> execute(String command) async =>
FFmpegKit.executeWithArguments(FFmpegKitConfig.parseArguments(command));
/// Synchronously executes FFmpeg with arguments provided.
static Future<FFmpegSession> executeWithArguments(
List<String> commandArguments) async {
final session =
await FFmpegSession.create(commandArguments, null, null, null, null);
await FFmpegKitConfig.ffmpegExecute(session);
return session;
}
/// Starts an asynchronous FFmpeg execution for the given command. Space character is used to split the command /// Starts an asynchronous FFmpeg execution for the given command. Space character is used to split the command
/// into arguments. You can use single or double quote characters to specify arguments inside your command. /// into arguments. You can use single or double quote characters to specify arguments inside your command.
/// ///
/// Note that this method returns immediately and does not wait the execution to complete. You must use an /// Note that this method returns immediately and does not wait the execution to complete. You must use an
/// [ExecuteCallback] if you want to be notified about the result. /// [FFmpegSessionCompleteCallback] if you want to be notified about the result.
static Future<FFmpegSession> executeAsync(String command, static Future<FFmpegSession> executeAsync(String command,
[ExecuteCallback? executeCallback = null, [FFmpegSessionCompleteCallback? completeCallback = null,
LogCallback? logCallback = null, LogCallback? logCallback = null,
StatisticsCallback? statisticsCallback = null]) async => StatisticsCallback? statisticsCallback = null]) async =>
FFmpegKit.executeWithArgumentsAsync( FFmpegKit.executeWithArgumentsAsync(
FFmpegKitConfig.parseArguments(command), FFmpegKitConfig.parseArguments(command),
executeCallback, completeCallback,
logCallback, logCallback,
statisticsCallback); statisticsCallback);
/// Starts an asynchronous FFmpeg execution with arguments provided. /// Starts an asynchronous FFmpeg execution with arguments provided.
/// ///
/// Note that this method returns immediately and does not wait the execution to complete. You must use an /// Note that this method returns immediately and does not wait the execution to complete. You must use an
/// [ExecuteCallback] if you want to be notified about the result. /// [FFmpegSessionCompleteCallback] if you want to be notified about the result.
static Future<FFmpegSession> executeWithArgumentsAsync( static Future<FFmpegSession> executeWithArgumentsAsync(
List<String> commandArguments, List<String> commandArguments,
[ExecuteCallback? executeCallback = null, [FFmpegSessionCompleteCallback? completeCallback = null,
LogCallback? logCallback = null, LogCallback? logCallback = null,
StatisticsCallback? statisticsCallback = null]) async { StatisticsCallback? statisticsCallback = null]) async {
final session = await FFmpegSession.create(commandArguments, final session = await FFmpegSession.create(commandArguments,
executeCallback, logCallback, statisticsCallback, null); completeCallback, logCallback, statisticsCallback, null);
await FFmpegKitConfig.asyncFFmpegExecute(session); await FFmpegKitConfig.asyncFFmpegExecute(session);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2021 Taner Sener * Copyright (c) 2019-2022 Taner Sener
* *
* This file is part of FFmpegKit. * This file is part of FFmpegKit.
* *
@ -20,13 +20,15 @@
import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platform_interface.dart'; import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platform_interface.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'execute_callback.dart';
import 'ffmpeg_session.dart'; import 'ffmpeg_session.dart';
import 'ffmpeg_session_complete_callback.dart';
import 'ffprobe_session.dart'; import 'ffprobe_session.dart';
import 'ffprobe_session_complete_callback.dart';
import 'level.dart'; import 'level.dart';
import 'log_callback.dart'; import 'log_callback.dart';
import 'log_redirection_strategy.dart'; import 'log_redirection_strategy.dart';
import 'media_information_session.dart'; import 'media_information_session.dart';
import 'media_information_session_complete_callback.dart';
import 'session.dart'; import 'session.dart';
import 'session_state.dart'; import 'session_state.dart';
import 'signal.dart'; import 'signal.dart';
@ -215,10 +217,48 @@ class FFmpegKitConfig {
} }
} }
/// Synchronously executes the FFmpeg session provided.
static Future<void> ffmpegExecute(FFmpegSession ffmpegSession) async {
try {
await init();
return _platform
.ffmpegKitConfigFFmpegExecute(ffmpegSession.getSessionId());
} on PlatformException catch (e, stack) {
print("Plugin ffmpegExecute error: ${e.message}");
return Future.error("ffmpegExecute failed.", stack);
}
}
/// Synchronously executes the FFprobe session provided.
static Future<void> ffprobeExecute(FFprobeSession ffprobeSession) async {
try {
await init();
return _platform
.ffmpegKitConfigFFprobeExecute(ffprobeSession.getSessionId());
} on PlatformException catch (e, stack) {
print("Plugin ffprobeExecute error: ${e.message}");
return Future.error("ffprobeExecute failed.", stack);
}
}
/// Synchronously executes the media information session provided.
static Future<void> getMediaInformationExecute(
MediaInformationSession mediaInformationSession,
[int? waitTimeout = null]) async {
try {
await init();
return _platform.ffmpegKitConfigGetMediaInformationExecute(
mediaInformationSession.getSessionId(), waitTimeout);
} on PlatformException catch (e, stack) {
print("Plugin getMediaInformationExecute error: ${e.message}");
return Future.error("getMediaInformationExecute failed.", stack);
}
}
/// Starts an asynchronous FFmpeg execution for the given session. /// Starts an asynchronous FFmpeg execution for the given session.
/// ///
/// Note that this method returns immediately and does not wait the execution to complete. You must use an /// Note that this method returns immediately and does not wait the execution to complete. You must use an
/// [ExecuteCallback] if you want to be notified about the result. /// [FFmpegSessionCompleteCallback] if you want to be notified about the result.
static Future<void> asyncFFmpegExecute(FFmpegSession ffmpegSession) async { static Future<void> asyncFFmpegExecute(FFmpegSession ffmpegSession) async {
try { try {
await init(); await init();
@ -233,7 +273,7 @@ class FFmpegKitConfig {
/// Starts an asynchronous FFprobe execution for the given session. /// Starts an asynchronous FFprobe execution for the given session.
/// ///
/// Note that this method returns immediately and does not wait the execution to complete. You must use an /// Note that this method returns immediately and does not wait the execution to complete. You must use an
/// [ExecuteCallback] if you want to be notified about the result. /// [FFprobeSessionCompleteCallback] if you want to be notified about the result.
static Future<void> asyncFFprobeExecute(FFprobeSession ffprobeSession) async { static Future<void> asyncFFprobeExecute(FFprobeSession ffprobeSession) async {
try { try {
await init(); await init();
@ -248,7 +288,7 @@ class FFmpegKitConfig {
/// Starts an asynchronous FFprobe execution for the given media information session. /// Starts an asynchronous FFprobe execution for the given media information session.
/// ///
/// Note that this method returns immediately and does not wait the execution to complete. You must use an /// Note that this method returns immediately and does not wait the execution to complete. You must use an
/// [ExecuteCallback] if you want to be notified about the result. /// [MediaInformationSessionCompleteCallback] if you want to be notified about the result.
static Future<void> asyncGetMediaInformationExecute( static Future<void> asyncGetMediaInformationExecute(
MediaInformationSession mediaInformationSession, MediaInformationSession mediaInformationSession,
[int? waitTimeout = null]) async { [int? waitTimeout = null]) async {
@ -262,22 +302,55 @@ class FFmpegKitConfig {
} }
} }
/// Sets a global callback function to redirect FFmpeg/FFprobe logs. /// Sets a global callback to redirect FFmpeg/FFprobe logs.
static void enableLogCallback([LogCallback? logCallback = null]) { static void enableLogCallback([LogCallback? logCallback = null]) {
FFmpegKitFactory.setGlobalLogCallback(logCallback); FFmpegKitFactory.setGlobalLogCallback(logCallback);
} }
/// Sets a global callback function to redirect FFmpeg statistics. /// Sets a global callback to redirect FFmpeg statistics.
static void enableStatisticsCallback( static void enableStatisticsCallback(
[StatisticsCallback? statisticsCallback = null]) { [StatisticsCallback? statisticsCallback = null]) {
FFmpegKitFactory.setGlobalStatisticsCallback(statisticsCallback); FFmpegKitFactory.setGlobalStatisticsCallback(statisticsCallback);
} }
/// Sets a global callback function to receive execution results. /// Sets a global FFmpegSessionCompleteCallback to receive execution results
static void enableExecuteCallback([ExecuteCallback? executeCallback = null]) { /// for FFmpeg sessions.
FFmpegKitFactory.setGlobalExecuteCallback(executeCallback); static void enableFFmpegSessionCompleteCallback(
[FFmpegSessionCompleteCallback? ffmpegSessionCompleteCallback = null]) {
FFmpegKitFactory.setGlobalFFmpegSessionCompleteCallback(
ffmpegSessionCompleteCallback);
} }
/// Returns the global FFmpegSessionCompleteCallback set.
static FFmpegSessionCompleteCallback? getFFmpegSessionCompleteCallback() =>
FFmpegKitFactory.getGlobalFFmpegSessionCompleteCallback();
/// Sets a global FFprobeSessionCompleteCallback to receive execution results
/// for FFprobe sessions.
static void enableFFprobeSessionCompleteCallback(
[FFprobeSessionCompleteCallback? ffprobeSessionCompleteCallback = null]) {
FFmpegKitFactory.setGlobalFFprobeSessionCompleteCallback(
ffprobeSessionCompleteCallback);
}
/// Returns the global FFprobeSessionCompleteCallback set.
static FFprobeSessionCompleteCallback? getFFprobeSessionCompleteCallback() =>
FFmpegKitFactory.getGlobalFFprobeSessionCompleteCallback();
/// Sets a global MediaInformationSessionCompleteCallback to receive
/// execution results for MediaInformation sessions.
static void enableMediaInformationSessionCompleteCallback(
[MediaInformationSessionCompleteCallback?
mediaInformationSessionCompleteCallback = null]) {
FFmpegKitFactory.setGlobalMediaInformationSessionCompleteCallback(
mediaInformationSessionCompleteCallback);
}
/// Returns the global MediaInformationSessionCompleteCallback set.
static MediaInformationSessionCompleteCallback?
getMediaInformationSessionCompleteCallback() =>
FFmpegKitFactory.getGlobalMediaInformationSessionCompleteCallback();
/// Returns the current log level. /// Returns the current log level.
static int getLogLevel() => _activeLogLevel; static int getLogLevel() => _activeLogLevel;
@ -293,6 +366,55 @@ class FFmpegKitConfig {
} }
} }
/// Converts the given Structured Access Framework Uri ("content:…") into
/// an input url that can be used in FFmpeg and FFprobe commands.
///
/// Note that this method is Android only. It will fail if called on other
/// platforms. It also requires API Level &ge; 19. On older API levels it
/// returns an empty url.
static Future<String?> getSafParameterForRead(String uriString) async {
try {
await init();
return _platform.ffmpegKitConfigGetSafParameter(uriString, "r");
} on PlatformException catch (e, stack) {
print("Plugin getSafParameterForRead error: ${e.message}");
return Future.error("getSafParameterForRead failed.", stack);
}
}
/// Converts the given Structured Access Framework Uri ("content:…") into
/// an output url that can be used in FFmpeg and FFprobe commands.
///
/// Note that this method is Android only. It will fail if called on other
/// platforms. It also requires API Level &ge; 19. On older API levels it
/// returns an empty url.
static Future<String?> getSafParameterForWrite(String uriString) async {
try {
await init();
return _platform.ffmpegKitConfigGetSafParameter(uriString, "w");
} on PlatformException catch (e, stack) {
print("Plugin getSafParameterForWrite error: ${e.message}");
return Future.error("getSafParameterForWrite failed.", stack);
}
}
/// Converts the given Structured Access Framework Uri into an saf protocol
/// url opened with the given open mode.
///
/// Note that this method is Android only. It will fail if called on other
/// platforms. It also requires API Level &ge; 19. On older API levels it
/// returns an empty url.
static Future<String?> getSafParameter(
String uriString, String openMode) async {
try {
await init();
return _platform.ffmpegKitConfigGetSafParameter(uriString, openMode);
} on PlatformException catch (e, stack) {
print("Plugin getSafParameter error: ${e.message}");
return Future.error("getSafParameter failed.", stack);
}
}
/// Returns the session history size. /// Returns the session history size.
static Future<int?> getSessionHistorySize() async { static Future<int?> getSessionHistorySize() async {
try { try {
@ -386,6 +508,72 @@ class FFmpegKitConfig {
} }
} }
/// Returns all FFmpeg sessions in the session history.
static Future<List<FFmpegSession>> getFFmpegSessions() async {
try {
await FFmpegKitConfig.init();
return _platform.ffmpegKitListSessions().then((sessions) {
if (sessions == null) {
return List.empty();
} else {
return sessions
.map((dynamic sessionObject) => FFmpegKitFactory.mapToSession(
sessionObject as Map<dynamic, dynamic>))
.map((session) => session as FFmpegSession)
.toList();
}
});
} on PlatformException catch (e, stack) {
print("Plugin getFFmpegSessions error: ${e.message}");
return Future.error("getFFmpegSessions failed.", stack);
}
}
/// Returns all FFprobe sessions in the session history.
static Future<List<FFprobeSession>> getFFprobeSessions() async {
try {
await FFmpegKitConfig.init();
return _platform.ffprobeKitListFFprobeSessions().then((sessions) {
if (sessions == null) {
return List.empty();
} else {
return sessions
.map((dynamic sessionObject) => FFmpegKitFactory.mapToSession(
sessionObject as Map<dynamic, dynamic>))
.map((session) => session as FFprobeSession)
.toList();
}
});
} on PlatformException catch (e, stack) {
print("Plugin getFFprobeSessions error: ${e.message}");
return Future.error("getFFprobeSessions failed.", stack);
}
}
/// Returns all MediaInformation sessions in the session history.
static Future<List<MediaInformationSession>>
getMediaInformationSessions() async {
try {
await FFmpegKitConfig.init();
return _platform
.ffprobeKitListMediaInformationSessions()
.then((sessions) {
if (sessions == null) {
return List.empty();
} else {
return sessions
.map((dynamic sessionObject) => FFmpegKitFactory.mapToSession(
sessionObject as Map<dynamic, dynamic>))
.map((session) => session as MediaInformationSession)
.toList();
}
});
} on PlatformException catch (e, stack) {
print("Plugin getMediaInformationSessions error: ${e.message}");
return Future.error("getMediaInformationSessions failed.", stack);
}
}
/// Returns sessions that have [sessionState]. /// Returns sessions that have [sessionState].
static Future<List<Session>> getSessionsByState( static Future<List<Session>> getSessionsByState(
SessionState sessionState) async { SessionState sessionState) async {
@ -624,36 +812,4 @@ class FFmpegKitConfig {
return Future.error("selectDocumentForWrite failed.", stack); return Future.error("selectDocumentForWrite failed.", stack);
} }
} }
/// Converts the given Structured Access Framework Uri ("content:…") into
/// an input url that can be used in FFmpeg and FFprobe commands.
///
/// Note that this method is Android only. It will fail if called on other
/// platforms. It also requires API Level &ge; 19. On older API levels it
/// returns an empty url.
static Future<String?> getSafParameterForRead(String uriString) async {
try {
await init();
return _platform.ffmpegKitConfigGetSafParameterForRead(uriString);
} on PlatformException catch (e, stack) {
print("Plugin getSafParameterForRead error: ${e.message}");
return Future.error("getSafParameterForRead failed.", stack);
}
}
/// Converts the given Structured Access Framework Uri ("content:…") into
/// an output url that can be used in FFmpeg and FFprobe commands.
///
/// Note that this method is Android only. It will fail if called on other
/// platforms. It also requires API Level &ge; 19. On older API levels it
/// returns an empty url.
static Future<String?> getSafParameterForWrite(String uriString) async {
try {
await init();
return _platform.ffmpegKitConfigGetSafParameterForWrite(uriString);
} on PlatformException catch (e, stack) {
print("Plugin getSafParameterForWrite error: ${e.message}");
return Future.error("getSafParameterForWrite failed.", stack);
}
}
} }

View File

@ -21,8 +21,8 @@ import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platfor
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'abstract_session.dart'; import 'abstract_session.dart';
import 'execute_callback.dart';
import 'ffmpeg_kit_config.dart'; import 'ffmpeg_kit_config.dart';
import 'ffmpeg_session_complete_callback.dart';
import 'log_callback.dart'; import 'log_callback.dart';
import 'log_redirection_strategy.dart'; import 'log_redirection_strategy.dart';
import 'src/ffmpeg_kit_factory.dart'; import 'src/ffmpeg_kit_factory.dart';
@ -33,7 +33,7 @@ import 'statistics_callback.dart';
class FFmpegSession extends AbstractSession { class FFmpegSession extends AbstractSession {
/// Creates a new FFmpeg session with [argumentsArray]. /// Creates a new FFmpeg session with [argumentsArray].
static Future<FFmpegSession> create(List<String> argumentsArray, static Future<FFmpegSession> create(List<String> argumentsArray,
[ExecuteCallback? executeCallback = null, [FFmpegSessionCompleteCallback? completeCallback = null,
LogCallback? logCallback = null, LogCallback? logCallback = null,
StatisticsCallback? statisticsCallback = null, StatisticsCallback? statisticsCallback = null,
LogRedirectionStrategy? logRedirectionStrategy = null]) async { LogRedirectionStrategy? logRedirectionStrategy = null]) async {
@ -41,7 +41,8 @@ class FFmpegSession extends AbstractSession {
argumentsArray, logRedirectionStrategy); argumentsArray, logRedirectionStrategy);
final sessionId = session.getSessionId(); final sessionId = session.getSessionId();
FFmpegKitFactory.setExecuteCallback(sessionId, executeCallback); FFmpegKitFactory.setFFmpegSessionCompleteCallback(
sessionId, completeCallback);
FFmpegKitFactory.setLogCallback(sessionId, logCallback); FFmpegKitFactory.setLogCallback(sessionId, logCallback);
FFmpegKitFactory.setStatisticsCallback(sessionId, statisticsCallback); FFmpegKitFactory.setStatisticsCallback(sessionId, statisticsCallback);
@ -53,10 +54,14 @@ class FFmpegSession extends AbstractSession {
static FFmpegSession fromMap(Map<dynamic, dynamic> sessionMap) => static FFmpegSession fromMap(Map<dynamic, dynamic> sessionMap) =>
AbstractSession.createFFmpegSessionFromMap(sessionMap); AbstractSession.createFFmpegSessionFromMap(sessionMap);
/// Returns the session specific statistics callback function. /// Returns the session specific statistics callback.
StatisticsCallback? getStatisticsCallback() => StatisticsCallback? getStatisticsCallback() =>
FFmpegKitFactory.getStatisticsCallback(this.getSessionId()); FFmpegKitFactory.getStatisticsCallback(this.getSessionId());
/// Returns the session specific complete callback.
FFmpegSessionCompleteCallback? getCompleteCallback() =>
FFmpegKitFactory.getFFmpegSessionCompleteCallback(this.getSessionId());
/// Returns all statistics entries generated for this session. If there are /// Returns all statistics entries generated for this session. If there are
/// asynchronous statistics that are not delivered yet, this method waits for /// asynchronous statistics that are not delivered yet, this method waits for
/// them until [waitTimeout]. /// them until [waitTimeout].
@ -120,4 +125,6 @@ class FFmpegSession extends AbstractSession {
bool isFFmpeg() => true; bool isFFmpeg() => true;
bool isFFprobe() => false; bool isFFprobe() => false;
bool isMediaInformation() => false;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2021 Taner Sener * Copyright (c) 2021 Taner Sener
* *
* This file is part of FFmpegKit. * This file is part of FFmpegKit.
* *
@ -17,13 +17,13 @@
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>. * along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
*/ */
import 'session.dart'; import 'ffmpeg_session.dart';
/// Callback function invoked when a session ends running. /// Callback function that is invoked when an asynchronous FFmpeg session has
/// Session has either SessionState.completed or SessionState.failed state when /// ended. Session has either SessionState.completed or SessionState.failed
/// the callback is invoked. /// state when the callback is invoked.
/// If it has SessionState.completed state, "ReturnCode" should be checked to /// If it has SessionState.completed state, "ReturnCode" should be checked to
/// see the execution result. /// see the execution result.
/// If "getState" returns SessionState.failed then "getFailStackTrace" should /// If "getState" returns SessionState.failed then "getFailStackTrace" should
/// be used to get the failure reason. /// be used to get the failure reason.
typedef ExecuteCallback = void Function(Session session); typedef FFmpegSessionCompleteCallback = void Function(FFmpegSession session);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2021 Taner Sener * Copyright (c) 2019-2022 Taner Sener
* *
* This file is part of FFmpegKit. * This file is part of FFmpegKit.
* *
@ -20,52 +20,119 @@
import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platform_interface.dart'; import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platform_interface.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'execute_callback.dart';
import 'ffmpeg_kit_config.dart'; import 'ffmpeg_kit_config.dart';
import 'ffprobe_session.dart'; import 'ffprobe_session.dart';
import 'ffprobe_session_complete_callback.dart';
import 'log_callback.dart'; import 'log_callback.dart';
import 'media_information_session.dart'; import 'media_information_session.dart';
import 'media_information_session_complete_callback.dart';
import 'src/ffmpeg_kit_factory.dart'; import 'src/ffmpeg_kit_factory.dart';
/// Main class to run "FFprobe" commands. /// Main class to run "FFprobe" commands.
class FFprobeKit { class FFprobeKit {
static FFmpegKitPlatform _platform = FFmpegKitPlatform.instance; static FFmpegKitPlatform _platform = FFmpegKitPlatform.instance;
/// Synchronously executes FFprobe command provided. Space character is used
/// to split command into arguments. You can use single or double quote
/// characters to specify arguments inside your command.
static Future<FFprobeSession> execute(String command) async =>
FFprobeKit.executeWithArguments(FFmpegKitConfig.parseArguments(command));
/// Synchronously executes FFprobe with arguments provided.
static Future<FFprobeSession> executeWithArguments(
List<String> commandArguments) async {
final session =
await FFprobeSession.create(commandArguments, null, null, null);
await FFmpegKitConfig.ffprobeExecute(session);
return session;
}
/// Starts an asynchronous FFprobe execution for the given command. Space character is used to split the command /// Starts an asynchronous FFprobe execution for the given command. Space character is used to split the command
/// into arguments. You can use single or double quote characters to specify arguments inside your command. /// into arguments. You can use single or double quote characters to specify arguments inside your command.
/// ///
/// Note that this method returns immediately and does not wait the execution to complete. You must use an /// Note that this method returns immediately and does not wait the execution to complete. You must use an
/// [ExecuteCallback] if you want to be notified about the result. /// [FFprobeSessionCompleteCallback] if you want to be notified about the result.
static Future<FFprobeSession> executeAsync(String command, static Future<FFprobeSession> executeAsync(String command,
[ExecuteCallback? executeCallback = null, [FFprobeSessionCompleteCallback? completeCallback = null,
LogCallback? logCallback = null]) async => LogCallback? logCallback = null]) async =>
FFprobeKit.executeWithArgumentsAsync( FFprobeKit.executeWithArgumentsAsync(
FFmpegKitConfig.parseArguments(command), FFmpegKitConfig.parseArguments(command),
executeCallback, completeCallback,
logCallback); logCallback);
/// Starts an asynchronous FFprobe execution with arguments provided. /// Starts an asynchronous FFprobe execution with arguments provided.
/// ///
/// Note that this method returns immediately and does not wait the execution to complete. You must use an /// Note that this method returns immediately and does not wait the execution to complete. You must use an
/// [ExecuteCallback] if you want to be notified about the result. /// [FFprobeSessionCompleteCallback] if you want to be notified about the result.
static Future<FFprobeSession> executeWithArgumentsAsync( static Future<FFprobeSession> executeWithArgumentsAsync(
List<String> commandArguments, List<String> commandArguments,
[ExecuteCallback? executeCallback = null, [FFprobeSessionCompleteCallback? completeCallback = null,
LogCallback? logCallback = null]) async { LogCallback? logCallback = null]) async {
final session = await FFprobeSession.create( final session = await FFprobeSession.create(
commandArguments, executeCallback, logCallback, null); commandArguments, completeCallback, logCallback, null);
await FFmpegKitConfig.asyncFFprobeExecute(session); await FFmpegKitConfig.asyncFFprobeExecute(session);
return session; return session;
} }
/// Extracts media information for the file specified with path.
static Future<MediaInformationSession> getMediaInformation(String path,
[int? waitTimeout = null]) async {
final commandArguments = [
"-v",
"error",
"-hide_banner",
"-print_format",
"json",
"-show_format",
"-show_streams",
"-show_chapters",
"-i",
path
];
return FFprobeKit.getMediaInformationFromCommandArguments(
commandArguments, waitTimeout);
}
/// Extracts media information using the command provided. The command
/// passed to this method must generate the output in JSON format in order to
/// successfully extract media information from it.
static Future<MediaInformationSession> getMediaInformationFromCommand(
String command,
[int? waitTimeout = null]) async =>
FFprobeKit.getMediaInformationFromCommandArguments(
FFmpegKitConfig.parseArguments(command), waitTimeout);
/// Extracts media information using the command arguments provided. The
/// command passed to this method must generate the output in JSON format in
/// order to successfully extract media information from it.
static Future<MediaInformationSession>
getMediaInformationFromCommandArguments(List<String> commandArguments,
[int? waitTimeout = null]) async {
final session =
await MediaInformationSession.create(commandArguments, null, null);
await FFmpegKitConfig.getMediaInformationExecute(session, waitTimeout);
final mediaInformation = await _platform
.mediaInformationSessionGetMediaInformation(session.getSessionId())
.then(FFmpegKitFactory.mapToNullableMediaInformation);
if (mediaInformation != null) {
session.setMediaInformation(mediaInformation);
}
return session;
}
/// Starts an asynchronous FFprobe execution to extract the media information for the specified file. /// Starts an asynchronous FFprobe execution to extract the media information for the specified file.
/// ///
/// Note that this method returns immediately and does not wait the execution to complete. You must use an /// Note that this method returns immediately and does not wait the execution to complete. You must use an
/// [ExecuteCallback] if you want to be notified about the result. /// [MediaInformationSessionCompleteCallback] if you want to be notified about the result.
static Future<MediaInformationSession> getMediaInformationAsync(String path, static Future<MediaInformationSession> getMediaInformationAsync(String path,
[ExecuteCallback? executeCallback = null, [MediaInformationSessionCompleteCallback? completeCallback = null,
LogCallback? logCallback = null, LogCallback? logCallback = null,
int? waitTimeout = null]) async { int? waitTimeout = null]) async {
final commandArguments = [ final commandArguments = [
@ -76,54 +143,64 @@ class FFprobeKit {
"json", "json",
"-show_format", "-show_format",
"-show_streams", "-show_streams",
"-show_chapters",
"-i", "-i",
path path
]; ];
return FFprobeKit.getMediaInformationFromCommandArgumentsAsync( return FFprobeKit.getMediaInformationFromCommandArgumentsAsync(
commandArguments, executeCallback, logCallback, waitTimeout); commandArguments, completeCallback, logCallback, waitTimeout);
} }
/// Starts an asynchronous FFprobe execution to extract media information using a command. The command passed to /// Starts an asynchronous FFprobe execution to extract media information using a command. The command passed to
/// this method must generate the output in JSON format in order to successfully extract media information from it. /// this method must generate the output in JSON format in order to successfully extract media information from it.
/// ///
/// Note that this method returns immediately and does not wait the execution to complete. You must use an /// Note that this method returns immediately and does not wait the execution to complete. You must use an
/// [ExecuteCallback] if you want to be notified about the result. /// [MediaInformationSessionCompleteCallback] if you want to be notified about the result.
static Future<MediaInformationSession> getMediaInformationFromCommandAsync( static Future<MediaInformationSession> getMediaInformationFromCommandAsync(
String command, String command,
[ExecuteCallback? executeCallback = null, [MediaInformationSessionCompleteCallback? completeCallback = null,
LogCallback? logCallback = null, LogCallback? logCallback = null,
int? waitTimeout = null]) async => int? waitTimeout = null]) async =>
FFprobeKit.getMediaInformationFromCommandArgumentsAsync( FFprobeKit.getMediaInformationFromCommandArgumentsAsync(
FFmpegKitConfig.parseArguments(command), FFmpegKitConfig.parseArguments(command),
executeCallback, completeCallback,
logCallback, logCallback,
waitTimeout); waitTimeout);
/// Starts an asynchronous FFprobe execution to extract media information using command arguments. The command /// Starts an asynchronous FFprobe execution to extract media information
/// passed to this method must generate the output in JSON format in order to successfully extract media information /// using command arguments. The command passed to this method must generate
/// from it. /// the output in JSON format in order to successfully extract media
/// information from it.
/// ///
/// Note that this method returns immediately and does not wait the execution to complete. You must use an /// Note that this method returns immediately and does not wait the execution
/// [ExecuteCallback] if you want to be notified about the result. /// to complete. You must use an [MediaInformationSessionCompleteCallback] if you want to be
/// notified about the result.
static Future<MediaInformationSession> static Future<MediaInformationSession>
getMediaInformationFromCommandArgumentsAsync( getMediaInformationFromCommandArgumentsAsync(
List<String> commandArguments, List<String> commandArguments,
[ExecuteCallback? executeCallback = null, [MediaInformationSessionCompleteCallback? completeCallback = null,
LogCallback? logCallback = null, LogCallback? logCallback = null,
int? waitTimeout = null]) async { int? waitTimeout = null]) async {
final session = await MediaInformationSession.create( final session = await MediaInformationSession.create(
commandArguments, executeCallback, logCallback); commandArguments, completeCallback, logCallback);
await FFmpegKitConfig.asyncGetMediaInformationExecute(session, waitTimeout); await FFmpegKitConfig.asyncGetMediaInformationExecute(session, waitTimeout);
final mediaInformation = await _platform
.mediaInformationSessionGetMediaInformation(session.getSessionId())
.then(FFmpegKitFactory.mapToNullableMediaInformation);
if (mediaInformation != null) {
session.setMediaInformation(mediaInformation);
}
return session; return session;
} }
/// Lists all FFprobe sessions in the session history. /// Lists all FFprobe sessions in the session history.
static Future<List<FFprobeSession>> listSessions() async { static Future<List<FFprobeSession>> listFFprobeSessions() async {
try { try {
await FFmpegKitConfig.init(); await FFmpegKitConfig.init();
return _platform.ffprobeKitListSessions().then((sessions) { return _platform.ffprobeKitListFFprobeSessions().then((sessions) {
if (sessions == null) { if (sessions == null) {
return List.empty(); return List.empty();
} else { } else {
@ -135,8 +212,32 @@ class FFprobeKit {
} }
}); });
} on PlatformException catch (e, stack) { } on PlatformException catch (e, stack) {
print("Plugin listSessions error: ${e.message}"); print("Plugin listFFprobeSessions error: ${e.message}");
return Future.error("listSessions failed.", stack); return Future.error("listFFprobeSessions failed.", stack);
}
}
/// Lists all MediaInformation sessions in the session history.
static Future<List<MediaInformationSession>>
listMediaInformationSessions() async {
try {
await FFmpegKitConfig.init();
return _platform
.ffprobeKitListMediaInformationSessions()
.then((sessions) {
if (sessions == null) {
return List.empty();
} else {
return sessions
.map((dynamic sessionObject) => FFmpegKitFactory.mapToSession(
sessionObject as Map<dynamic, dynamic>))
.map((session) => session as MediaInformationSession)
.toList();
}
});
} on PlatformException catch (e, stack) {
print("Plugin listMediaInformationSessions error: ${e.message}");
return Future.error("listMediaInformationSessions failed.", stack);
} }
} }
} }

View File

@ -18,7 +18,7 @@
*/ */
import 'abstract_session.dart'; import 'abstract_session.dart';
import 'execute_callback.dart'; import 'ffprobe_session_complete_callback.dart';
import 'log_callback.dart'; import 'log_callback.dart';
import 'log_redirection_strategy.dart'; import 'log_redirection_strategy.dart';
import 'src/ffmpeg_kit_factory.dart'; import 'src/ffmpeg_kit_factory.dart';
@ -27,14 +27,15 @@ import 'src/ffmpeg_kit_factory.dart';
class FFprobeSession extends AbstractSession { class FFprobeSession extends AbstractSession {
/// Creates a new FFprobe session with [argumentsArray]. /// Creates a new FFprobe session with [argumentsArray].
static Future<FFprobeSession> create(List<String> argumentsArray, static Future<FFprobeSession> create(List<String> argumentsArray,
[ExecuteCallback? executeCallback = null, [FFprobeSessionCompleteCallback? completeCallback = null,
LogCallback? logCallback = null, LogCallback? logCallback = null,
LogRedirectionStrategy? logRedirectionStrategy = null]) async { LogRedirectionStrategy? logRedirectionStrategy = null]) async {
final session = await AbstractSession.createFFprobeSession( final session = await AbstractSession.createFFprobeSession(
argumentsArray, logRedirectionStrategy); argumentsArray, logRedirectionStrategy);
final sessionId = session.getSessionId(); final sessionId = session.getSessionId();
FFmpegKitFactory.setExecuteCallback(sessionId, executeCallback); FFmpegKitFactory.setFFprobeSessionCompleteCallback(
sessionId, completeCallback);
FFmpegKitFactory.setLogCallback(sessionId, logCallback); FFmpegKitFactory.setLogCallback(sessionId, logCallback);
return session; return session;
@ -45,7 +46,13 @@ class FFprobeSession extends AbstractSession {
static FFprobeSession fromMap(Map<dynamic, dynamic> sessionMap) => static FFprobeSession fromMap(Map<dynamic, dynamic> sessionMap) =>
AbstractSession.createFFprobeSessionFromMap(sessionMap); AbstractSession.createFFprobeSessionFromMap(sessionMap);
/// Returns the session specific complete callback.
FFprobeSessionCompleteCallback? getCompleteCallback() =>
FFmpegKitFactory.getFFprobeSessionCompleteCallback(this.getSessionId());
bool isFFmpeg() => false; bool isFFmpeg() => false;
bool isFFprobe() => true; bool isFFprobe() => true;
bool isMediaInformation() => false;
} }

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2021 Taner Sener
*
* This file is part of FFmpegKit.
*
* FFmpegKit 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.
*
* FFmpegKit 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 FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
*/
import 'ffprobe_session.dart';
/// Callback function that is invoked when an asynchronous FFprobe session has
/// ended. Session has either SessionState.completed or SessionState.failed
/// state when the callback is invoked.
/// If it has SessionState.completed state, "ReturnCode" should be checked to
/// see the execution result.
/// If "getState" returns SessionState.failed then "getFailStackTrace" should
/// be used to get the failure reason.
typedef FFprobeSessionCompleteCallback = void Function(FFprobeSession session);

View File

@ -17,6 +17,7 @@
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>. * along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
*/ */
import 'chapter.dart';
import 'stream_information.dart'; import 'stream_information.dart';
/// Media information class. /// Media information class.
@ -87,6 +88,20 @@ class MediaInformation {
return list; return list;
} }
/// Returns all chapters found as a list.
List<Chapter> getChapters() {
final List<Chapter> list = List<Chapter>.empty(growable: true);
dynamic createChapter(Map<dynamic, dynamic> chapterProperties) =>
list.add(new Chapter(chapterProperties));
this._allProperties?["chapters"]?.forEach((Object? chapter) {
createChapter(chapter as Map<dynamic, dynamic>);
});
return list;
}
/// Returns all media properties. /// Returns all media properties.
Map<dynamic, dynamic>? getMediaProperties() => Map<dynamic, dynamic>? getMediaProperties() =>
this._allProperties?[keyMediaProperties]; this._allProperties?[keyMediaProperties];

View File

@ -18,26 +18,26 @@
*/ */
import 'abstract_session.dart'; import 'abstract_session.dart';
import 'execute_callback.dart';
import 'ffprobe_session.dart';
import 'log_callback.dart'; import 'log_callback.dart';
import 'media_information.dart'; import 'media_information.dart';
import 'media_information_session_complete_callback.dart';
import 'src/ffmpeg_kit_factory.dart'; import 'src/ffmpeg_kit_factory.dart';
/// A custom FFprobe session, which produces a "MediaInformation" object /// A custom FFprobe session, which produces a "MediaInformation" object
/// using the FFprobe output. /// using the FFprobe output.
class MediaInformationSession extends FFprobeSession { class MediaInformationSession extends AbstractSession {
MediaInformation? _mediaInformation; MediaInformation? _mediaInformation;
/// Creates a new MediaInformation session with [argumentsArray]. /// Creates a new MediaInformation session with [argumentsArray].
static Future<MediaInformationSession> create(List<String> argumentsArray, static Future<MediaInformationSession> create(List<String> argumentsArray,
[ExecuteCallback? executeCallback = null, [MediaInformationSessionCompleteCallback? completeCallback = null,
LogCallback? logCallback = null]) async { LogCallback? logCallback = null]) async {
final session = final session =
await AbstractSession.createMediaInformationSession(argumentsArray); await AbstractSession.createMediaInformationSession(argumentsArray);
final sessionId = session.getSessionId(); final sessionId = session.getSessionId();
FFmpegKitFactory.setExecuteCallback(sessionId, executeCallback); FFmpegKitFactory.setMediaInformationSessionCompleteCallback(
sessionId, completeCallback);
FFmpegKitFactory.setLogCallback(sessionId, logCallback); FFmpegKitFactory.setLogCallback(sessionId, logCallback);
return session; return session;
@ -55,4 +55,15 @@ class MediaInformationSession extends FFprobeSession {
void setMediaInformation(MediaInformation? mediaInformation) { void setMediaInformation(MediaInformation? mediaInformation) {
this._mediaInformation = mediaInformation; this._mediaInformation = mediaInformation;
} }
/// Returns the session specific complete callback.
MediaInformationSessionCompleteCallback? getCompleteCallback() =>
FFmpegKitFactory.getMediaInformationSessionCompleteCallback(
this.getSessionId());
bool isFFmpeg() => false;
bool isFFprobe() => false;
bool isMediaInformation() => true;
} }

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2021 Taner Sener
*
* This file is part of FFmpegKit.
*
* FFmpegKit 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.
*
* FFmpegKit 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 FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
*/
import 'media_information_session.dart';
/// Callback function that is invoked when an asynchronous MediaInformation
/// session has ended. Session has either SessionState.completed or
/// SessionState.failed state when the callback is invoked.
/// If it has SessionState.completed state, "ReturnCode" should be checked to
/// see the execution result.
/// If "getState" returns SessionState.failed then "getFailStackTrace" should
/// be used to get the failure reason.
typedef MediaInformationSessionCompleteCallback = void Function(
MediaInformationSession session);

View File

@ -17,7 +17,6 @@
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>. * along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
*/ */
import 'execute_callback.dart';
import 'log.dart'; import 'log.dart';
import 'log_callback.dart'; import 'log_callback.dart';
import 'log_redirection_strategy.dart'; import 'log_redirection_strategy.dart';
@ -26,10 +25,7 @@ import 'session_state.dart';
/// Common interface for all "FFmpegKit" sessions. /// Common interface for all "FFmpegKit" sessions.
abstract class Session { abstract class Session {
/// Returns the session specific execute callback function. /// Returns the session specific log callback.
ExecuteCallback? getExecuteCallback();
/// Returns the session specific log callback function.
LogCallback? getLogCallback(); LogCallback? getLogCallback();
/// Returns the session identifier. /// Returns the session identifier.
@ -106,6 +102,9 @@ abstract class Session {
/// Returns whether it is an "FFprobe" session or not. /// Returns whether it is an "FFprobe" session or not.
bool isFFprobe(); bool isFFprobe();
/// Returns whether it is an "MediaInformation" session or not.
bool isMediaInformation();
/// Cancels running the session. /// Cancels running the session.
void cancel(); void cancel();
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2021 Taner Sener * Copyright (c) 2019-2022 Taner Sener
* *
* This file is part of FFmpegKit. * This file is part of FFmpegKit.
* *
@ -17,18 +17,26 @@
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>. * along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
*/ */
import '../execute_callback.dart';
import '../ffmpeg_session.dart'; import '../ffmpeg_session.dart';
import '../ffmpeg_session_complete_callback.dart';
import '../ffprobe_session.dart'; import '../ffprobe_session.dart';
import '../ffprobe_session_complete_callback.dart';
import '../log.dart'; import '../log.dart';
import '../log_callback.dart'; import '../log_callback.dart';
import '../log_redirection_strategy.dart'; import '../log_redirection_strategy.dart';
import '../media_information.dart';
import '../media_information_session.dart'; import '../media_information_session.dart';
import '../media_information_session_complete_callback.dart';
import '../session.dart'; import '../session.dart';
import '../statistics.dart'; import '../statistics.dart';
import '../statistics_callback.dart'; import '../statistics_callback.dart';
final executeCallbackMap = new Map<int, ExecuteCallback>(); final ffmpegSessionCompleteCallbackMap =
new Map<int, FFmpegSessionCompleteCallback>();
final ffprobeSessionCompleteCallbackMap =
new Map<int, FFprobeSessionCompleteCallback>();
final mediaInformationSessionCompleteCallbackMap =
new Map<int, MediaInformationSessionCompleteCallback>();
final logCallbackMap = new Map<int, LogCallback>(); final logCallbackMap = new Map<int, LogCallback>();
final statisticsCallbackMap = new Map<int, StatisticsCallback>(); final statisticsCallbackMap = new Map<int, StatisticsCallback>();
final logRedirectionStrategyMap = new Map<int, LogRedirectionStrategy>(); final logRedirectionStrategyMap = new Map<int, LogRedirectionStrategy>();
@ -36,7 +44,10 @@ final logRedirectionStrategyMap = new Map<int, LogRedirectionStrategy>();
class FFmpegKitFactory { class FFmpegKitFactory {
static LogCallback? _logCallback; static LogCallback? _logCallback;
static StatisticsCallback? _statisticsCallback; static StatisticsCallback? _statisticsCallback;
static ExecuteCallback? _executeCallback; static FFmpegSessionCompleteCallback? _ffmpegSessionCompleteCallback;
static FFprobeSessionCompleteCallback? _ffprobeSessionCompleteCallback;
static MediaInformationSessionCompleteCallback?
_mediaInformationSessionCompleteCallback;
static Statistics mapToStatistics(Map<dynamic, dynamic> statisticsMap) => static Statistics mapToStatistics(Map<dynamic, dynamic> statisticsMap) =>
new Statistics( new Statistics(
@ -80,7 +91,16 @@ class FFmpegKitFactory {
} }
} }
static String getVersion() => "4.5.0"; static MediaInformation? mapToNullableMediaInformation(
Map<dynamic, dynamic>? mediaInformationMap) {
if (mediaInformationMap != null) {
return new MediaInformation(mediaInformationMap);
} else {
return null;
}
}
static String getVersion() => "4.5.1";
static LogRedirectionStrategy? getLogRedirectionStrategy(int? sessionId) => static LogRedirectionStrategy? getLogRedirectionStrategy(int? sessionId) =>
logRedirectionStrategyMap[sessionId]; logRedirectionStrategyMap[sessionId];
@ -125,20 +145,64 @@ class FFmpegKitFactory {
_statisticsCallback = statisticsCallback; _statisticsCallback = statisticsCallback;
} }
static ExecuteCallback? getExecuteCallback(int? sessionId) => static FFmpegSessionCompleteCallback? getFFmpegSessionCompleteCallback(
executeCallbackMap[sessionId]; int? sessionId) =>
ffmpegSessionCompleteCallbackMap[sessionId];
static void setExecuteCallback( static void setFFmpegSessionCompleteCallback(
int? sessionId, ExecuteCallback? executeCallback) { int? sessionId, FFmpegSessionCompleteCallback? completeCallback) {
if (sessionId != null && executeCallback != null) { if (sessionId != null && completeCallback != null) {
executeCallbackMap[sessionId] = executeCallback; ffmpegSessionCompleteCallbackMap[sessionId] = completeCallback;
} }
} }
static ExecuteCallback? getGlobalExecuteCallback() => _executeCallback; static FFmpegSessionCompleteCallback?
getGlobalFFmpegSessionCompleteCallback() =>
_ffmpegSessionCompleteCallback;
static void setGlobalExecuteCallback(ExecuteCallback? executeCallback) { static void setGlobalFFmpegSessionCompleteCallback(
_executeCallback = executeCallback; FFmpegSessionCompleteCallback? completeCallback) {
_ffmpegSessionCompleteCallback = completeCallback;
}
static FFprobeSessionCompleteCallback? getFFprobeSessionCompleteCallback(
int? sessionId) =>
ffprobeSessionCompleteCallbackMap[sessionId];
static void setFFprobeSessionCompleteCallback(
int? sessionId, FFprobeSessionCompleteCallback? completeCallback) {
if (sessionId != null && completeCallback != null) {
ffprobeSessionCompleteCallbackMap[sessionId] = completeCallback;
}
}
static FFprobeSessionCompleteCallback?
getGlobalFFprobeSessionCompleteCallback() =>
_ffprobeSessionCompleteCallback;
static void setGlobalFFprobeSessionCompleteCallback(
FFprobeSessionCompleteCallback? completeCallback) {
_ffprobeSessionCompleteCallback = completeCallback;
}
static MediaInformationSessionCompleteCallback?
getMediaInformationSessionCompleteCallback(int? sessionId) =>
mediaInformationSessionCompleteCallbackMap[sessionId];
static void setMediaInformationSessionCompleteCallback(int? sessionId,
MediaInformationSessionCompleteCallback? completeCallback) {
if (sessionId != null && completeCallback != null) {
mediaInformationSessionCompleteCallbackMap[sessionId] = completeCallback;
}
}
static MediaInformationSessionCompleteCallback?
getGlobalMediaInformationSessionCompleteCallback() =>
_mediaInformationSessionCompleteCallback;
static void setGlobalMediaInformationSessionCompleteCallback(
MediaInformationSessionCompleteCallback? completeCallback) {
_mediaInformationSessionCompleteCallback = completeCallback;
} }
static DateTime? validDate(int? time) { static DateTime? validDate(int? time) {

View File

@ -23,12 +23,16 @@ import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platfor
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import '../arch_detect.dart'; import '../arch_detect.dart';
import '../execute_callback.dart';
import '../ffmpeg_kit_config.dart'; import '../ffmpeg_kit_config.dart';
import '../ffmpeg_session.dart'; import '../ffmpeg_session.dart';
import '../ffmpeg_session_complete_callback.dart';
import '../ffprobe_session.dart';
import '../ffprobe_session_complete_callback.dart';
import '../level.dart'; import '../level.dart';
import '../log_callback.dart'; import '../log_callback.dart';
import '../log_redirection_strategy.dart'; import '../log_redirection_strategy.dart';
import '../media_information_session.dart';
import '../media_information_session_complete_callback.dart';
import '../packages.dart'; import '../packages.dart';
import '../session.dart'; import '../session.dart';
import '../statistics.dart'; import '../statistics.dart';
@ -59,8 +63,8 @@ class FFmpegKitInitializer {
eventMap['FFmpegKitLogCallbackEvent']; eventMap['FFmpegKitLogCallbackEvent'];
final Map<dynamic, dynamic>? statisticsEvent = final Map<dynamic, dynamic>? statisticsEvent =
eventMap['FFmpegKitStatisticsCallbackEvent']; eventMap['FFmpegKitStatisticsCallbackEvent'];
final Map<dynamic, dynamic>? executeEvent = final Map<dynamic, dynamic>? completeEvent =
eventMap['FFmpegKitExecuteCallbackEvent']; eventMap['FFmpegKitCompleteCallbackEvent'];
if (logEvent != null) { if (logEvent != null) {
_processLogCallbackEvent(logEvent); _processLogCallbackEvent(logEvent);
@ -70,8 +74,8 @@ class FFmpegKitInitializer {
_processStatisticsCallbackEvent(statisticsEvent); _processStatisticsCallbackEvent(statisticsEvent);
} }
if (executeEvent != null) { if (completeEvent != null) {
_processExecuteCallbackEvent(executeEvent); _processCompleteCallbackEvent(completeEvent);
} }
} }
} }
@ -98,10 +102,10 @@ class FFmpegKitInitializer {
return; return;
} }
FFmpegKitConfig.getSession(sessionId).then((Session? session) {
activeLogRedirectionStrategy = activeLogRedirectionStrategy =
session?.getLogRedirectionStrategy() ?? activeLogRedirectionStrategy; FFmpegKitFactory.getLogRedirectionStrategy(sessionId) ??
final LogCallback? logCallback = session?.getLogCallback(); activeLogRedirectionStrategy;
final LogCallback? logCallback = FFmpegKitFactory.getLogCallback(sessionId);
if (logCallback != null) { if (logCallback != null) {
sessionCallbackDefined = true; sessionCallbackDefined = true;
@ -110,7 +114,7 @@ class FFmpegKitInitializer {
// NOTIFY SESSION CALLBACK DEFINED // NOTIFY SESSION CALLBACK DEFINED
logCallback(log); logCallback(log);
} on Exception catch (e, stack) { } on Exception catch (e, stack) {
print("Exception thrown inside session LogCallback block. $e"); print("Exception thrown inside session log callback. $e");
print(stack); print(stack);
} }
} }
@ -123,7 +127,7 @@ class FFmpegKitInitializer {
// NOTIFY GLOBAL CALLBACK DEFINED // NOTIFY GLOBAL CALLBACK DEFINED
globalLogCallbackFunction(log); globalLogCallbackFunction(log);
} on Exception catch (e, stack) { } on Exception catch (e, stack) {
print("Exception thrown inside global LogCallback block. $e"); print("Exception thrown inside global log callback. $e");
print(stack); print(stack);
} }
} }
@ -172,30 +176,23 @@ class FFmpegKitInitializer {
stdout.write(text); stdout.write(text);
} }
} }
});
} }
void _processStatisticsCallbackEvent(Map<dynamic, dynamic> event) { void _processStatisticsCallbackEvent(Map<dynamic, dynamic> event) {
final Statistics statistics = FFmpegKitFactory.mapToStatistics(event); final Statistics statistics = FFmpegKitFactory.mapToStatistics(event);
final int sessionId = event["sessionId"]; final int sessionId = event["sessionId"];
FFmpegKitConfig.getSession(sessionId).then((Session? session) {
if (session != null && session.isFFmpeg()) {
final FFmpegSession ffmpegSession = session as FFmpegSession;
final StatisticsCallback? statisticsCallback = final StatisticsCallback? statisticsCallback =
ffmpegSession.getStatisticsCallback(); FFmpegKitFactory.getStatisticsCallback(sessionId);
if (statisticsCallback != null) { if (statisticsCallback != null) {
try { try {
// NOTIFY SESSION CALLBACK DEFINED // NOTIFY SESSION CALLBACK DEFINED
statisticsCallback(statistics); statisticsCallback(statistics);
} on Exception catch (e, stack) { } on Exception catch (e, stack) {
print( print("Exception thrown inside session statistics callback. $e");
"Exception thrown inside session StatisticsCallback block. $e");
print(stack); print(stack);
} }
} }
}
final globalStatisticsCallbackFunction = final globalStatisticsCallbackFunction =
FFmpegKitFactory.getGlobalStatisticsCallback(); FFmpegKitFactory.getGlobalStatisticsCallback();
@ -204,40 +201,98 @@ class FFmpegKitInitializer {
// NOTIFY GLOBAL CALLBACK DEFINED // NOTIFY GLOBAL CALLBACK DEFINED
globalStatisticsCallbackFunction(statistics); globalStatisticsCallbackFunction(statistics);
} on Exception catch (e, stack) { } on Exception catch (e, stack) {
print("Exception thrown inside global StatisticsCallback block. $e"); print("Exception thrown inside global statistics callback. $e");
print(stack); print(stack);
} }
} }
});
} }
void _processExecuteCallbackEvent(Map<dynamic, dynamic> event) { void _processCompleteCallbackEvent(Map<dynamic, dynamic> event) {
final int sessionId = event["sessionId"]; final int sessionId = event["sessionId"];
FFmpegKitConfig.getSession(sessionId).then((Session? session) { FFmpegKitConfig.getSession(sessionId).then((Session? session) {
final ExecuteCallback? executeCallback = session?.getExecuteCallback(); if (session != null) {
if (session.isFFmpeg()) {
final ffmpegSession = session as FFmpegSession;
final FFmpegSessionCompleteCallback? completeCallback =
ffmpegSession.getCompleteCallback();
if (executeCallback != null && session != null) { if (completeCallback != null) {
try { try {
// NOTIFY SESSION CALLBACK DEFINED // NOTIFY SESSION CALLBACK DEFINED
executeCallback(session); completeCallback(ffmpegSession);
} on Exception catch (e, stack) { } on Exception catch (e, stack) {
print("Exception thrown inside session ExecuteCallback block. $e"); print("Exception thrown inside session complete callback. $e");
print(stack); print(stack);
} }
} }
final globalExecuteCallbackFunction = final globalFFmpegSessionCompleteCallback =
FFmpegKitFactory.getGlobalExecuteCallback(); FFmpegKitFactory.getGlobalFFmpegSessionCompleteCallback();
if (globalExecuteCallbackFunction != null && session != null) { if (globalFFmpegSessionCompleteCallback != null) {
try { try {
// NOTIFY GLOBAL CALLBACK DEFINED // NOTIFY GLOBAL CALLBACK DEFINED
globalExecuteCallbackFunction(session); globalFFmpegSessionCompleteCallback(ffmpegSession);
} on Exception catch (e, stack) { } on Exception catch (e, stack) {
print("Exception thrown inside global ExecuteCallback block. $e"); print("Exception thrown inside global complete callback. $e");
print(stack); print(stack);
} }
} }
} else if (session.isFFprobe()) {
final ffprobeSession = session as FFprobeSession;
final FFprobeSessionCompleteCallback? completeCallback =
ffprobeSession.getCompleteCallback();
if (completeCallback != null) {
try {
// NOTIFY SESSION CALLBACK DEFINED
completeCallback(ffprobeSession);
} on Exception catch (e, stack) {
print("Exception thrown inside session complete callback. $e");
print(stack);
}
}
final globalFFprobeSessionCompleteCallback =
FFmpegKitFactory.getGlobalFFprobeSessionCompleteCallback();
if (globalFFprobeSessionCompleteCallback != null) {
try {
// NOTIFY GLOBAL CALLBACK DEFINED
globalFFprobeSessionCompleteCallback(ffprobeSession);
} on Exception catch (e, stack) {
print("Exception thrown inside global complete callback. $e");
print(stack);
}
}
} else if (session.isMediaInformation()) {
final mediaInformationSession = session as MediaInformationSession;
final MediaInformationSessionCompleteCallback? completeCallback =
mediaInformationSession.getCompleteCallback();
if (completeCallback != null) {
try {
// NOTIFY SESSION CALLBACK DEFINED
completeCallback(mediaInformationSession);
} on Exception catch (e, stack) {
print("Exception thrown inside session complete callback. $e");
print(stack);
}
}
final globalMediaInformationSessionCompleteCallback = FFmpegKitFactory
.getGlobalMediaInformationSessionCompleteCallback();
if (globalMediaInformationSessionCompleteCallback != null) {
try {
// NOTIFY GLOBAL CALLBACK DEFINED
globalMediaInformationSessionCompleteCallback(
mediaInformationSession);
} on Exception catch (e, stack) {
print("Exception thrown inside global complete callback. $e");
print(stack);
}
}
}
}
}); });
} }

View File

@ -19,5 +19,5 @@
import 'statistics.dart'; import 'statistics.dart';
/// Callback function that receives statistics generated for "FFmpeg" sessions.dc /// Callback function that receives statistics generated for "FFmpeg" sessions.
typedef StatisticsCallback = void Function(Statistics statistics); typedef StatisticsCallback = void Function(Statistics statistics);

View File

@ -119,6 +119,6 @@ class StreamInformation {
/// Returns the stream properties associated with the key. /// Returns the stream properties associated with the key.
dynamic getProperties(String key) => this._allProperties?[key]; dynamic getProperties(String key) => this._allProperties?[key];
/// Returns all properties found.d /// Returns all properties found.
Map<dynamic, dynamic>? getAllProperties() => this._allProperties; Map<dynamic, dynamic>? getAllProperties() => this._allProperties;
} }

View File

@ -57,7 +57,7 @@ static int const SESSION_TYPE_MEDIA_INFORMATION = 3;
// EVENTS // EVENTS
static NSString *const EVENT_LOG_CALLBACK_EVENT = @"FFmpegKitLogCallbackEvent"; static NSString *const EVENT_LOG_CALLBACK_EVENT = @"FFmpegKitLogCallbackEvent";
static NSString *const EVENT_STATISTICS_CALLBACK_EVENT = @"FFmpegKitStatisticsCallbackEvent"; static NSString *const EVENT_STATISTICS_CALLBACK_EVENT = @"FFmpegKitStatisticsCallbackEvent";
static NSString *const EVENT_EXECUTE_CALLBACK_EVENT = @"FFmpegKitExecuteCallbackEvent"; static NSString *const EVENT_COMPLETE_CALLBACK_EVENT = @"FFmpegKitCompleteCallbackEvent";
// ARGUMENT NAMES // ARGUMENT NAMES
static NSString *const ARGUMENT_SESSION_ID = @"sessionId"; static NSString *const ARGUMENT_SESSION_ID = @"sessionId";
@ -71,7 +71,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
FlutterEventSink _eventSink; FlutterEventSink _eventSink;
BOOL logsEnabled; BOOL logsEnabled;
BOOL statisticsEnabled; BOOL statisticsEnabled;
dispatch_queue_t asyncWriteToPipeDispatchQueue; dispatch_queue_t asyncDispatchQueue;
} }
- (instancetype)init { - (instancetype)init {
@ -79,9 +79,9 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
if (self) { if (self) {
logsEnabled = false; logsEnabled = false;
statisticsEnabled = false; statisticsEnabled = false;
asyncWriteToPipeDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); asyncDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
[self registerGlobalCallbacks]; NSLog(@"FFmpegKitFlutterPlugin %p created.\n", self);
} }
return self; return self;
@ -89,6 +89,8 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
- (FlutterError *)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink { - (FlutterError *)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink {
_eventSink = eventSink; _eventSink = eventSink;
NSLog(@"FFmpegKitFlutterPlugin %p started listening to events on %p.\n", self, eventSink);
[self registerGlobalCallbacks];
return nil; return nil;
} }
@ -108,9 +110,19 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
} }
- (void)registerGlobalCallbacks { - (void)registerGlobalCallbacks {
[FFmpegKitConfig enableExecuteCallback:^(id<Session> session){ [FFmpegKitConfig enableFFmpegSessionCompleteCallback:^(FFmpegSession* session){
NSDictionary *dictionary = [FFmpegKitFlutterPlugin toSessionDictionary:session]; NSDictionary *dictionary = [FFmpegKitFlutterPlugin toSessionDictionary:session];
self->_eventSink([FFmpegKitFlutterPlugin toStringDictionary:EVENT_EXECUTE_CALLBACK_EVENT withDictionary:dictionary]); self->_eventSink([FFmpegKitFlutterPlugin toStringDictionary:EVENT_COMPLETE_CALLBACK_EVENT withDictionary:dictionary]);
}];
[FFmpegKitConfig enableFFprobeSessionCompleteCallback:^(FFprobeSession* session){
NSDictionary *dictionary = [FFmpegKitFlutterPlugin toSessionDictionary:session];
self->_eventSink([FFmpegKitFlutterPlugin toStringDictionary:EVENT_COMPLETE_CALLBACK_EVENT withDictionary:dictionary]);
}];
[FFmpegKitConfig enableMediaInformationSessionCompleteCallback:^(MediaInformationSession* session){
NSDictionary *dictionary = [FFmpegKitFlutterPlugin toSessionDictionary:session];
self->_eventSink([FFmpegKitFlutterPlugin toStringDictionary:EVENT_COMPLETE_CALLBACK_EVENT withDictionary:dictionary]);
}]; }];
[FFmpegKitConfig enableLogCallback: ^(Log* log){ [FFmpegKitConfig enableLogCallback: ^(Log* log){
@ -220,6 +232,12 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
} else { } else {
result([FlutterError errorWithCode:@"INVALID_ARGUMENTS" message:@"Invalid arguments array." details:nil]); result([FlutterError errorWithCode:@"INVALID_ARGUMENTS" message:@"Invalid arguments array." details:nil]);
} }
} else if ([@"getMediaInformation" isEqualToString:call.method]) {
if (sessionId != nil) {
[self getMediaInformation:sessionId result:result];
} else {
result([FlutterError errorWithCode:@"INVALID_SESSION" message:@"Invalid session id." details:nil]);
}
} else if ([@"mediaInformationJsonParserFrom" isEqualToString:call.method]) { } else if ([@"mediaInformationJsonParserFrom" isEqualToString:call.method]) {
if (ffprobeJsonOutput != nil) { if (ffprobeJsonOutput != nil) {
[self mediaInformationJsonParserFrom:ffprobeJsonOutput result:result]; [self mediaInformationJsonParserFrom:ffprobeJsonOutput result:result];
@ -299,6 +317,24 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
} else { } else {
result([FlutterError errorWithCode:@"INVALID_SIGNAL" message:@"Invalid signal value." details:nil]); result([FlutterError errorWithCode:@"INVALID_SIGNAL" message:@"Invalid signal value." details:nil]);
} }
} else if ([@"ffmpegSessionExecute" isEqualToString:call.method]) {
if (sessionId != nil) {
[self ffmpegSessionExecute:sessionId result:result];
} else {
result([FlutterError errorWithCode:@"INVALID_SESSION" message:@"Invalid session id." details:nil]);
}
} else if ([@"ffprobeSessionExecute" isEqualToString:call.method]) {
if (sessionId != nil) {
[self ffprobeSessionExecute:sessionId result:result];
} else {
result([FlutterError errorWithCode:@"INVALID_SESSION" message:@"Invalid session id." details:nil]);
}
} else if ([@"mediaInformationSessionExecute" isEqualToString:call.method]) {
if (sessionId != nil) {
[self mediaInformationSessionExecute:sessionId timeout:waitTimeout result:result];
} else {
result([FlutterError errorWithCode:@"INVALID_SESSION" message:@"Invalid session id." details:nil]);
}
} else if ([@"asyncFFmpegSessionExecute" isEqualToString:call.method]) { } else if ([@"asyncFFmpegSessionExecute" isEqualToString:call.method]) {
if (sessionId != nil) { if (sessionId != nil) {
[self asyncFFmpegSessionExecute:sessionId result:result]; [self asyncFFmpegSessionExecute:sessionId result:result];
@ -399,6 +435,8 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
[self getFFmpegSessions:result]; [self getFFmpegSessions:result];
} else if ([@"getFFprobeSessions" isEqualToString:call.method]) { } else if ([@"getFFprobeSessions" isEqualToString:call.method]) {
[self getFFprobeSessions:result]; [self getFFprobeSessions:result];
} else if ([@"getMediaInformationSessions" isEqualToString:call.method]) {
[self getMediaInformationSessions:result];
} else if ([@"getPackageName" isEqualToString:call.method]) { } else if ([@"getPackageName" isEqualToString:call.method]) {
[self getPackageName:result]; [self getPackageName:result];
} else if ([@"getExternalLibraries" isEqualToString:call.method]) { } else if ([@"getExternalLibraries" isEqualToString:call.method]) {
@ -525,7 +563,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
// FFmpegSession // FFmpegSession
- (void)ffmpegSession:(NSArray*)arguments result:(FlutterResult)result { - (void)ffmpegSession:(NSArray*)arguments result:(FlutterResult)result {
FFmpegSession* session = [[FFmpegSession alloc] init:arguments withExecuteCallback:nil withLogCallback:nil withStatisticsCallback:nil withLogRedirectionStrategy:LogRedirectionStrategyNeverPrintLogs]; FFmpegSession* session = [[FFmpegSession alloc] init:arguments withCompleteCallback:nil withLogCallback:nil withStatisticsCallback:nil withLogRedirectionStrategy:LogRedirectionStrategyNeverPrintLogs];
result([FFmpegKitFlutterPlugin toSessionDictionary:session]); result([FFmpegKitFlutterPlugin toSessionDictionary:session]);
} }
@ -534,7 +572,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
if (session == nil) { if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else { } else {
if ([session isMemberOfClass:[FFmpegSession class]]) { if ([session isFFmpeg]) {
int timeout; int timeout;
if ([FFmpegKitFlutterPlugin isValidPositiveNumber:waitTimeout]) { if ([FFmpegKitFlutterPlugin isValidPositiveNumber:waitTimeout]) {
timeout = [waitTimeout intValue]; timeout = [waitTimeout intValue];
@ -554,7 +592,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
if (session == nil) { if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else { } else {
if ([session isMemberOfClass:[FFmpegSession class]]) { if ([session isFFmpeg]) {
NSArray* statistics = [(FFmpegSession*)session getStatistics]; NSArray* statistics = [(FFmpegSession*)session getStatistics];
result([FFmpegKitFlutterPlugin toStatisticsArray:statistics]); result([FFmpegKitFlutterPlugin toStatisticsArray:statistics]);
} else { } else {
@ -566,17 +604,31 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
// FFprobeSession // FFprobeSession
- (void)ffprobeSession:(NSArray*)arguments result:(FlutterResult)result { - (void)ffprobeSession:(NSArray*)arguments result:(FlutterResult)result {
FFprobeSession* session = [[FFprobeSession alloc] init:arguments withExecuteCallback:nil withLogCallback:nil withLogRedirectionStrategy:LogRedirectionStrategyNeverPrintLogs]; FFprobeSession* session = [[FFprobeSession alloc] init:arguments withCompleteCallback:nil withLogCallback:nil withLogRedirectionStrategy:LogRedirectionStrategyNeverPrintLogs];
result([FFmpegKitFlutterPlugin toSessionDictionary:session]); result([FFmpegKitFlutterPlugin toSessionDictionary:session]);
} }
// MediaInformationSession // MediaInformationSession
- (void)mediaInformationSession:(NSArray*)arguments result:(FlutterResult)result { - (void)mediaInformationSession:(NSArray*)arguments result:(FlutterResult)result {
MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments withExecuteCallback:nil withLogCallback:nil]; MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments withCompleteCallback:nil withLogCallback:nil];
result([FFmpegKitFlutterPlugin toSessionDictionary:session]); result([FFmpegKitFlutterPlugin toSessionDictionary:session]);
} }
- (void)getMediaInformation:(NSNumber*)sessionId result:(FlutterResult)result {
AbstractSession* session = (AbstractSession*)[FFmpegKitConfig getSession:[sessionId longValue]];
if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else {
if ([session isMediaInformation]) {
MediaInformationSession *mediaInformationSession = (MediaInformationSession*)session;
result([FFmpegKitFlutterPlugin toMediaInformationDictionary:[mediaInformationSession getMediaInformation]]);
} else {
result([FlutterError errorWithCode:@"NOT_MEDIA_INFORMATION_SESSION" message:@"A session is found but it does not have the correct type." details:nil]);
}
}
}
// MediaInformationJsonParser // MediaInformationJsonParser
- (void)mediaInformationJsonParserFrom:(NSString*)ffprobeJsonOutput result:(FlutterResult)result { - (void)mediaInformationJsonParserFrom:(NSString*)ffprobeJsonOutput result:(FlutterResult)result {
@ -708,12 +760,66 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
} }
} }
- (void)ffmpegSessionExecute:(NSNumber*)sessionId result:(FlutterResult)result {
AbstractSession* session = (AbstractSession*)[FFmpegKitConfig getSession:[sessionId longValue]];
if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else {
if ([session isFFmpeg]) {
dispatch_async(asyncDispatchQueue, ^{
[FFmpegKitConfig ffmpegExecute:(FFmpegSession*)session];
result(nil);
});
} else {
result([FlutterError errorWithCode:@"NOT_FFMPEG_SESSION" message:@"A session is found but it does not have the correct type." details:nil]);
}
}
}
- (void)ffprobeSessionExecute:(NSNumber*)sessionId result:(FlutterResult)result {
AbstractSession* session = (AbstractSession*)[FFmpegKitConfig getSession:[sessionId longValue]];
if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else {
if ([session isFFprobe]) {
dispatch_async(asyncDispatchQueue, ^{
[FFmpegKitConfig ffprobeExecute:(FFprobeSession*)session];
result(nil);
});
} else {
result([FlutterError errorWithCode:@"NOT_FFPROBE_SESSION" message:@"A session is found but it does not have the correct type." details:nil]);
}
}
}
- (void)mediaInformationSessionExecute:(NSNumber*)sessionId timeout:(NSNumber*)waitTimeout result:(FlutterResult)result {
AbstractSession* session = (AbstractSession*)[FFmpegKitConfig getSession:[sessionId longValue]];
if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else {
if ([session isMediaInformation]) {
int timeout;
if ([FFmpegKitFlutterPlugin isValidPositiveNumber:waitTimeout]) {
timeout = [waitTimeout intValue];
} else {
timeout = AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
}
dispatch_async(asyncDispatchQueue, ^{
[FFmpegKitConfig getMediaInformationExecute:(MediaInformationSession*)session withTimeout:timeout];
result(nil);
});
} else {
result([FlutterError errorWithCode:@"NOT_MEDIA_INFORMATION_SESSION" message:@"A session is found but it does not have the correct type." details:nil]);
}
}
}
- (void)asyncFFmpegSessionExecute:(NSNumber*)sessionId result:(FlutterResult)result { - (void)asyncFFmpegSessionExecute:(NSNumber*)sessionId result:(FlutterResult)result {
AbstractSession* session = (AbstractSession*)[FFmpegKitConfig getSession:[sessionId longValue]]; AbstractSession* session = (AbstractSession*)[FFmpegKitConfig getSession:[sessionId longValue]];
if (session == nil) { if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else { } else {
if ([session isMemberOfClass:[FFmpegSession class]]) { if ([session isFFmpeg]) {
[FFmpegKitConfig asyncFFmpegExecute:(FFmpegSession*)session]; [FFmpegKitConfig asyncFFmpegExecute:(FFmpegSession*)session];
result(nil); result(nil);
} else { } else {
@ -727,7 +833,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
if (session == nil) { if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else { } else {
if ([session isMemberOfClass:[FFprobeSession class]]) { if ([session isFFprobe]) {
[FFmpegKitConfig asyncFFprobeExecute:(FFprobeSession*)session]; [FFmpegKitConfig asyncFFprobeExecute:(FFprobeSession*)session];
result(nil); result(nil);
} else { } else {
@ -741,7 +847,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
if (session == nil) { if (session == nil) {
result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]);
} else { } else {
if ([session isMemberOfClass:[MediaInformationSession class]]) { if ([session isMediaInformation]) {
int timeout; int timeout;
if ([FFmpegKitFlutterPlugin isValidPositiveNumber:waitTimeout]) { if ([FFmpegKitFlutterPlugin isValidPositiveNumber:waitTimeout]) {
timeout = [waitTimeout intValue]; timeout = [waitTimeout intValue];
@ -852,7 +958,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
} }
- (void)writeToPipe:(NSString*)inputPath pipe:(NSString*)namedPipePath result:(FlutterResult)result { - (void)writeToPipe:(NSString*)inputPath pipe:(NSString*)namedPipePath result:(FlutterResult)result {
dispatch_async(asyncWriteToPipeDispatchQueue, ^{ dispatch_async(asyncDispatchQueue, ^{
NSLog(@"Starting copy %@ to pipe %@ operation.\n", inputPath, namedPipePath); NSLog(@"Starting copy %@ to pipe %@ operation.\n", inputPath, namedPipePath);
@ -933,7 +1039,11 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
// FFprobeKit // FFprobeKit
- (void)getFFprobeSessions:(FlutterResult)result { - (void)getFFprobeSessions:(FlutterResult)result {
result([FFmpegKitFlutterPlugin toSessionArray:[FFprobeKit listSessions]]); result([FFmpegKitFlutterPlugin toSessionArray:[FFprobeKit listFFprobeSessions]]);
}
- (void)getMediaInformationSessions:(FlutterResult)result {
result([FFmpegKitFlutterPlugin toSessionArray:[FFprobeKit listMediaInformationSessions]]);
} }
// Packages // Packages
@ -971,16 +1081,14 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
dictionary[KEY_SESSION_START_TIME] = [NSNumber numberWithLong:[[session getStartTime] timeIntervalSince1970]*1000]; dictionary[KEY_SESSION_START_TIME] = [NSNumber numberWithLong:[[session getStartTime] timeIntervalSince1970]*1000];
dictionary[KEY_SESSION_COMMAND] = [session getCommand]; dictionary[KEY_SESSION_COMMAND] = [session getCommand];
if ([session isFFprobe]) { if ([session isFFmpeg]) {
if ([(AbstractSession*)session isMemberOfClass:[MediaInformationSession class]]) { dictionary[KEY_SESSION_TYPE] = [NSNumber numberWithInt:SESSION_TYPE_FFMPEG];
} else if ([session isFFprobe]) {
dictionary[KEY_SESSION_TYPE] = [NSNumber numberWithInt:SESSION_TYPE_FFPROBE];
} else if ([session isMediaInformation]) {
MediaInformationSession *mediaInformationSession = (MediaInformationSession*)session; MediaInformationSession *mediaInformationSession = (MediaInformationSession*)session;
dictionary[KEY_SESSION_MEDIA_INFORMATION] = [FFmpegKitFlutterPlugin toMediaInformationDictionary:[mediaInformationSession getMediaInformation]]; dictionary[KEY_SESSION_MEDIA_INFORMATION] = [FFmpegKitFlutterPlugin toMediaInformationDictionary:[mediaInformationSession getMediaInformation]];
dictionary[KEY_SESSION_TYPE] = [NSNumber numberWithInt:SESSION_TYPE_MEDIA_INFORMATION]; dictionary[KEY_SESSION_TYPE] = [NSNumber numberWithInt:SESSION_TYPE_MEDIA_INFORMATION];
} else {
dictionary[KEY_SESSION_TYPE] = [NSNumber numberWithInt:SESSION_TYPE_FFPROBE];
}
} else {
dictionary[KEY_SESSION_TYPE] = [NSNumber numberWithInt:SESSION_TYPE_FFMPEG];
} }
return dictionary; return dictionary;

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'ffmpeg_kit_flutter' s.name = 'ffmpeg_kit_flutter'
s.version = '4.5.0' s.version = '4.5.1'
s.summary = 'FFmpeg Kit for Flutter' s.summary = 'FFmpeg Kit for Flutter'
s.description = 'A Flutter plugin for running FFmpeg and FFprobe commands.' s.description = 'A Flutter plugin for running FFmpeg and FFprobe commands.'
s.homepage = 'https://github.com/tanersener/ffmpeg-kit' s.homepage = 'https://github.com/tanersener/ffmpeg-kit'
@ -23,113 +23,113 @@ Pod::Spec.new do |s|
s.subspec 'min' do |ss| s.subspec 'min' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-min', "4.5" ss.dependency 'ffmpeg-kit-macos-min', "4.5.1"
ss.osx.deployment_target = '10.15' ss.osx.deployment_target = '10.15'
end end
s.subspec 'min-lts' do |ss| s.subspec 'min-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-min', "4.5.LTS" ss.dependency 'ffmpeg-kit-macos-min', "4.5.1.LTS"
ss.osx.deployment_target = '10.11' ss.osx.deployment_target = '10.12'
end end
s.subspec 'min-gpl' do |ss| s.subspec 'min-gpl' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-min-gpl', "4.5" ss.dependency 'ffmpeg-kit-macos-min-gpl', "4.5.1"
ss.osx.deployment_target = '10.15' ss.osx.deployment_target = '10.15'
end end
s.subspec 'min-gpl-lts' do |ss| s.subspec 'min-gpl-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-min-gpl', "4.5.LTS" ss.dependency 'ffmpeg-kit-macos-min-gpl', "4.5.1.LTS"
ss.osx.deployment_target = '10.11' ss.osx.deployment_target = '10.12'
end end
s.subspec 'https' do |ss| s.subspec 'https' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-https', "4.5" ss.dependency 'ffmpeg-kit-macos-https', "4.5.1"
ss.osx.deployment_target = '10.15' ss.osx.deployment_target = '10.15'
end end
s.subspec 'https-lts' do |ss| s.subspec 'https-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-https', "4.5.LTS" ss.dependency 'ffmpeg-kit-macos-https', "4.5.1.LTS"
ss.osx.deployment_target = '10.11' ss.osx.deployment_target = '10.12'
end end
s.subspec 'https-gpl' do |ss| s.subspec 'https-gpl' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-https-gpl', "4.5" ss.dependency 'ffmpeg-kit-macos-https-gpl', "4.5.1"
ss.osx.deployment_target = '10.15' ss.osx.deployment_target = '10.15'
end end
s.subspec 'https-gpl-lts' do |ss| s.subspec 'https-gpl-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-https-gpl', "4.5.LTS" ss.dependency 'ffmpeg-kit-macos-https-gpl', "4.5.1.LTS"
ss.osx.deployment_target = '10.11' ss.osx.deployment_target = '10.12'
end end
s.subspec 'audio' do |ss| s.subspec 'audio' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-audio', "4.5" ss.dependency 'ffmpeg-kit-macos-audio', "4.5.1"
ss.osx.deployment_target = '10.15' ss.osx.deployment_target = '10.15'
end end
s.subspec 'audio-lts' do |ss| s.subspec 'audio-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-audio', "4.5.LTS" ss.dependency 'ffmpeg-kit-macos-audio', "4.5.1.LTS"
ss.osx.deployment_target = '10.11' ss.osx.deployment_target = '10.12'
end end
s.subspec 'video' do |ss| s.subspec 'video' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-video', "4.5" ss.dependency 'ffmpeg-kit-macos-video', "4.5.1"
ss.osx.deployment_target = '10.15' ss.osx.deployment_target = '10.15'
end end
s.subspec 'video-lts' do |ss| s.subspec 'video-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-video', "4.5.LTS" ss.dependency 'ffmpeg-kit-macos-video', "4.5.1.LTS"
ss.osx.deployment_target = '10.11' ss.osx.deployment_target = '10.12'
end end
s.subspec 'full' do |ss| s.subspec 'full' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-full', "4.5" ss.dependency 'ffmpeg-kit-macos-full', "4.5.1"
ss.osx.deployment_target = '10.15' ss.osx.deployment_target = '10.15'
end end
s.subspec 'full-lts' do |ss| s.subspec 'full-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-full', "4.5.LTS" ss.dependency 'ffmpeg-kit-macos-full', "4.5.1.LTS"
ss.osx.deployment_target = '10.11' ss.osx.deployment_target = '10.12'
end end
s.subspec 'full-gpl' do |ss| s.subspec 'full-gpl' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-full-gpl', "4.5" ss.dependency 'ffmpeg-kit-macos-full-gpl', "4.5.1"
ss.osx.deployment_target = '10.15' ss.osx.deployment_target = '10.15'
end end
s.subspec 'full-gpl-lts' do |ss| s.subspec 'full-gpl-lts' do |ss|
ss.source_files = 'Classes/**/*' ss.source_files = 'Classes/**/*'
ss.public_header_files = 'Classes/**/*.h' ss.public_header_files = 'Classes/**/*.h'
ss.dependency 'ffmpeg-kit-macos-full-gpl', "4.5.LTS" ss.dependency 'ffmpeg-kit-macos-full-gpl', "4.5.1.LTS"
ss.osx.deployment_target = '10.11' ss.osx.deployment_target = '10.12'
end end
end end

View File

@ -3,7 +3,7 @@ description: FFmpeg Kit for Flutter. Supports Android, iOS and macOS platforms.
repository: https://github.com/tanersener/ffmpeg-kit repository: https://github.com/tanersener/ffmpeg-kit
issue_tracker: https://github.com/tanersener/ffmpeg-kit/issues issue_tracker: https://github.com/tanersener/ffmpeg-kit/issues
homepage: https://github.com/tanersener/ffmpeg-kit homepage: https://github.com/tanersener/ffmpeg-kit
version: 4.5.0 version: 4.5.1
environment: environment:
sdk: ">=2.12.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"
@ -21,7 +21,7 @@ flutter:
pluginClass: FFmpegKitFlutterPlugin pluginClass: FFmpegKitFlutterPlugin
dependencies: dependencies:
ffmpeg_kit_flutter_platform_interface: ^0.1.0 ffmpeg_kit_flutter_platform_interface: ^0.2.1
flutter: flutter:
sdk: flutter sdk: flutter

View File

@ -1,2 +1,11 @@
## 0.2.1
- Fixes the signature of getMediaInformation method
## 0.2.0
- Implements execute methods
- Merges existing getSafParameter methods into a single method with a new openMode parameter
- Adds list media information sessions methods to FFprobeKit
- Adds getMediaInformation method
## 0.1.0 ## 0.1.0
- Initial release - Initial release

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021 Taner Sener * Copyright (c) 2021-2022 Taner Sener
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -218,6 +218,22 @@ abstract class FFmpegKitPlatform extends PlatformInterface {
' has not been implemented!'); ' has not been implemented!');
} }
Future<void> ffmpegKitConfigFFmpegExecute(int? sessionId) async {
throw UnimplementedError(
'ffmpegKitConfigFFmpegExecute() has not been implemented!');
}
Future<void> ffmpegKitConfigFFprobeExecute(int? sessionId) async {
throw UnimplementedError(
'ffmpegKitConfigFFprobeExecute() has not been implemented!');
}
Future<void> ffmpegKitConfigGetMediaInformationExecute(
int? sessionId, int? waitTimeout) async {
throw UnimplementedError('ffmpegKitConfigGetMediaInformationExecute()'
' has not been implemented!');
}
Future<void> ffmpegKitConfigSetLogLevel(int logLevel) async { Future<void> ffmpegKitConfigSetLogLevel(int logLevel) async {
throw UnimplementedError( throw UnimplementedError(
'ffmpegKitConfigSetLogLevel() has not been implemented!'); 'ffmpegKitConfigSetLogLevel() has not been implemented!');
@ -314,16 +330,10 @@ abstract class FFmpegKitPlatform extends PlatformInterface {
'ffmpegKitConfigSelectDocumentForWrite() has not been implemented!'); 'ffmpegKitConfigSelectDocumentForWrite() has not been implemented!');
} }
Future<String?> ffmpegKitConfigGetSafParameterForRead( Future<String?> ffmpegKitConfigGetSafParameter(
String uriString) async { String uriString, String openMode) async {
throw UnimplementedError( throw UnimplementedError(
'ffmpegKitConfigGetSafParameterForRead() has not been implemented!'); 'ffmpegKitConfigGetSafParameter() has not been implemented!');
}
Future<String?> ffmpegKitConfigGetSafParameterForWrite(
String uriString) async {
throw UnimplementedError(
'ffmpegKitConfigGetSafParameterForWrite() has not been implemented!');
} }
// FFmpegKitFlutterInitializer // FFmpegKitFlutterInitializer
@ -348,9 +358,14 @@ abstract class FFmpegKitPlatform extends PlatformInterface {
// FFprobeKit // FFprobeKit
Future<List<dynamic>?> ffprobeKitListSessions() async { Future<List<dynamic>?> ffprobeKitListFFprobeSessions() async {
throw UnimplementedError( throw UnimplementedError(
'ffprobeKitListSessions() has not been implemented!'); 'ffprobeKitListFFprobeSessions() has not been implemented!');
}
Future<List<dynamic>?> ffprobeKitListMediaInformationSessions() async {
throw UnimplementedError(
'ffprobeKitListMediaInformationSessions() has not been implemented!');
} }
// MediaInformationJsonParser // MediaInformationJsonParser
@ -367,6 +382,12 @@ abstract class FFmpegKitPlatform extends PlatformInterface {
'mediaInformationJsonParserFromWithError() has not been implemented!'); 'mediaInformationJsonParserFromWithError() has not been implemented!');
} }
Future<Map<dynamic, dynamic>?> mediaInformationSessionGetMediaInformation(
int? sessionId) async {
throw UnimplementedError('mediaInformationSessionGetMediaInformation() '
'has not been implemented!');
}
Future<String?> getPackageName() async { Future<String?> getPackageName() async {
throw UnimplementedError('getPackageName() has not been implemented!'); throw UnimplementedError('getPackageName() has not been implemented!');
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021 Taner Sener * Copyright (c) 2021-2022 Taner Sener
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -99,13 +99,14 @@ class MethodChannelFFmpegKit extends FFmpegKitPlatform {
int? sessionId) async => int? sessionId) async =>
_channel.invokeMethod<bool>( _channel.invokeMethod<bool>(
'abstractSessionThereAreAsynchronousMessagesInTransmit', 'abstractSessionThereAreAsynchronousMessagesInTransmit',
{'sessionId': sessionId}).then((value) => value ?? false); {'sessionId': sessionId}).then((bool? value) => value ?? false);
// ArchDetect // ArchDetect
@override @override
Future<String> archDetectGetArch() async => Future<String> archDetectGetArch() async => _channel
_channel.invokeMethod<String>('getArch').then((value) => value ?? ""); .invokeMethod<String>('getArch')
.then((String? value) => value ?? "");
// FFmpegKit // FFmpegKit
@ -179,6 +180,20 @@ class MethodChannelFFmpegKit extends FFmpegKitPlatform {
Future<void> ffmpegKitConfigIgnoreSignal(int signal) async => Future<void> ffmpegKitConfigIgnoreSignal(int signal) async =>
_channel.invokeMethod<void>('ignoreSignal', {'signal': signal}); _channel.invokeMethod<void>('ignoreSignal', {'signal': signal});
@override
Future<void> ffmpegKitConfigFFmpegExecute(int? sessionId) async => _channel
.invokeMethod<void>('ffmpegSessionExecute', {'sessionId': sessionId});
@override
Future<void> ffmpegKitConfigFFprobeExecute(int? sessionId) async => _channel
.invokeMethod<void>('ffprobeSessionExecute', {'sessionId': sessionId});
@override
Future<void> ffmpegKitConfigGetMediaInformationExecute(
int? sessionId, int? waitTimeout) async =>
_channel.invokeMethod<void>('mediaInformationSessionExecute',
{'sessionId': sessionId, 'waitTimeout': waitTimeout});
@override @override
Future<void> ffmpegKitConfigAsyncFFmpegExecute(int? sessionId) async => Future<void> ffmpegKitConfigAsyncFFmpegExecute(int? sessionId) async =>
_channel.invokeMethod<void>( _channel.invokeMethod<void>(
@ -286,16 +301,10 @@ class MethodChannelFFmpegKit extends FFmpegKitPlatform {
}); });
@override @override
Future<String?> ffmpegKitConfigGetSafParameterForRead( Future<String?> ffmpegKitConfigGetSafParameter(
String uriString) async => String uriString, String openMode) async =>
_channel.invokeMethod<String>( _channel.invokeMethod<String>(
'getSafParameter', {'writable': false, 'uri': uriString}); 'getSafParameter', {'uri': uriString, 'openMode': openMode});
@override
Future<String?> ffmpegKitConfigGetSafParameterForWrite(
String uriString) async =>
_channel.invokeMethod<String>(
'getSafParameter', {'writable': true, 'uri': uriString});
// FFmpegKitFlutterInitializer // FFmpegKitFlutterInitializer
@ -318,9 +327,13 @@ class MethodChannelFFmpegKit extends FFmpegKitPlatform {
// FFprobeKit // FFprobeKit
@override @override
Future<List<dynamic>?> ffprobeKitListSessions() async => Future<List<dynamic>?> ffprobeKitListFFprobeSessions() async =>
_channel.invokeMethod<List<dynamic>>('getFFprobeSessions'); _channel.invokeMethod<List<dynamic>>('getFFprobeSessions');
@override
Future<List<dynamic>?> ffprobeKitListMediaInformationSessions() async =>
_channel.invokeMethod<List<dynamic>>('getMediaInformationSessions');
// MediaInformationJsonParser // MediaInformationJsonParser
@override @override
@ -337,6 +350,14 @@ class MethodChannelFFmpegKit extends FFmpegKitPlatform {
'mediaInformationJsonParserFromWithError', 'mediaInformationJsonParserFromWithError',
{'ffprobeJsonOutput': ffprobeJsonOutput}); {'ffprobeJsonOutput': ffprobeJsonOutput});
// MediaInformationSession
@override
Future<Map<dynamic, dynamic>?> mediaInformationSessionGetMediaInformation(
int? sessionId) async =>
_channel.invokeMethod<Map<dynamic, dynamic>>(
'getMediaInformation', {'sessionId': sessionId});
@override @override
Future<String?> getPackageName() async => Future<String?> getPackageName() async =>
_channel.invokeMethod<String>('getPackageName'); _channel.invokeMethod<String>('getPackageName');

View File

@ -5,7 +5,7 @@ issue_tracker: https://github.com/tanersener/ffmpeg-kit/issues
homepage: https://github.com/tanersener/ffmpeg-kit homepage: https://github.com/tanersener/ffmpeg-kit
# NOTE: We strongly prefer non-breaking changes, even at the expense of a # NOTE: We strongly prefer non-breaking changes, even at the expense of a
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
version: 0.1.0 version: 0.2.1
environment: environment:
sdk: ">=2.12.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"

View File

@ -2,8 +2,8 @@
CURRENT_DIR=$(pwd) CURRENT_DIR=$(pwd)
BASEDIR="${CURRENT_DIR}/../../.." BASEDIR="${CURRENT_DIR}/../../.."
TMPDIR="${BASEDIR}/.tmp" PACKAGES_DIR_MAIN="${BASEDIR}/prebuilt/bundle-flutter-main"
PACKAGES_DIR="${TMPDIR}/flutter_packages" PACKAGES_DIR_LTS="${BASEDIR}/prebuilt/bundle-flutter-lts"
SOURCE_DIR="${BASEDIR}/flutter/flutter" SOURCE_DIR="${BASEDIR}/flutter/flutter"
PACKAGES=(min min-gpl https https-gpl audio video full full-gpl) PACKAGES=(min min-gpl https https-gpl audio video full full-gpl)
@ -18,7 +18,7 @@ prepare_inline_sed() {
create_main_releases() { create_main_releases() {
for CURRENT_PACKAGE in "${PACKAGES[@]}"; do for CURRENT_PACKAGE in "${PACKAGES[@]}"; do
local FLUTTER_PACKAGE_NAME="$(echo "${CURRENT_PACKAGE}" | sed "s/\-/\_/g")" local FLUTTER_PACKAGE_NAME="$(echo "${CURRENT_PACKAGE}" | sed "s/\-/\_/g")"
local PACKAGE_PATH="${PACKAGES_DIR}/${CURRENT_PACKAGE}" local PACKAGE_PATH="${PACKAGES_DIR_MAIN}/${CURRENT_PACKAGE}"
cp -R ${SOURCE_DIR} ${PACKAGE_PATH} cp -R ${SOURCE_DIR} ${PACKAGE_PATH}
# 1. pubspec # 1. pubspec
@ -47,13 +47,16 @@ create_main_releases() {
done; done;
# CREATE DEFAULT PACKAGE
cp -R "${SOURCE_DIR}" "${PACKAGES_DIR_MAIN}/default"
echo "main releases created!" echo "main releases created!"
} }
create_lts_releases() { create_lts_releases() {
for CURRENT_PACKAGE in "${PACKAGES[@]}"; do for CURRENT_PACKAGE in "${PACKAGES[@]}"; do
local FLUTTER_PACKAGE_NAME="$(echo "${CURRENT_PACKAGE}" | sed "s/\-/\_/g")" local FLUTTER_PACKAGE_NAME="$(echo "${CURRENT_PACKAGE}" | sed "s/\-/\_/g")"
local PACKAGE_PATH="${PACKAGES_DIR}/${CURRENT_PACKAGE}-lts" local PACKAGE_PATH="${PACKAGES_DIR_LTS}/${CURRENT_PACKAGE}"
cp -R ${SOURCE_DIR} ${PACKAGE_PATH} cp -R ${SOURCE_DIR} ${PACKAGE_PATH}
# 1. pubspec # 1. pubspec
@ -82,6 +85,17 @@ create_lts_releases() {
done; done;
# CREATE DEFAULT PACKAGE
cp -R "${PACKAGES_DIR_LTS}/https" "${PACKAGES_DIR_LTS}/default"
$SED_INLINE "s|name: ffmpeg_kit_flutter_https|name: ffmpeg_kit_flutter|g" ${PACKAGES_DIR_LTS}/default/pubspec.yaml
rm -f ${PACKAGES_DIR_LTS}/default/pubspec.yaml.tmp
$SED_INLINE "s|ffmpeg_kit_flutter_https|ffmpeg_kit_flutter|g" ${PACKAGES_DIR_LTS}/default/ios/ffmpeg_kit_flutter_https.podspec
rm -f ${PACKAGES_DIR_LTS}/default/ios/ffmpeg_kit_flutter_https.podspec.tmp
mv ${PACKAGES_DIR_LTS}/default/ios/ffmpeg_kit_flutter_https.podspec ${PACKAGES_DIR_LTS}/default/ios/ffmpeg_kit_flutter.podspec
$SED_INLINE "s|ffmpeg_kit_flutter_https|ffmpeg_kit_flutter|g" ${PACKAGES_DIR_LTS}/default/macos/ffmpeg_kit_flutter_https.podspec
rm -f ${PACKAGES_DIR_LTS}/default/macos/ffmpeg_kit_flutter_https.podspec.tmp
mv ${PACKAGES_DIR_LTS}/default/macos/ffmpeg_kit_flutter_https.podspec ${PACKAGES_DIR_LTS}/default/macos/ffmpeg_kit_flutter.podspec
echo "lts releases created!" echo "lts releases created!"
} }
@ -94,13 +108,13 @@ fi
VERSION="$1" VERSION="$1"
NATIVE_VERSION="$2" NATIVE_VERSION="$2"
rm -rf "${PACKAGES_DIR}" rm -rf "${PACKAGES_DIR_MAIN}"
mkdir -p "${PACKAGES_DIR}" mkdir -p "${PACKAGES_DIR_MAIN}"
rm -rf "${PACKAGES_DIR_LTS}"
mkdir -p "${PACKAGES_DIR_LTS}"
prepare_inline_sed prepare_inline_sed
create_main_releases; create_main_releases;
create_lts_releases; create_lts_releases;
cp -R "${BASEDIR}/flutter/flutter_platform_interface" "$PACKAGES_DIR"