diff --git a/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/FFmpegKitFlutterPlugin.java b/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/FFmpegKitFlutterPlugin.java
index 3ab411a..876fa2b 100644
--- a/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/FFmpegKitFlutterPlugin.java
+++ b/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/FFmpegKitFlutterPlugin.java
@@ -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_WRITABLE = "writable";
- private static final int asyncWriteToPipeConcurrencyLimit = 10;
+ private static final int asyncConcurrencyLimit = 10;
private final AtomicBoolean logsEnabled;
private final AtomicBoolean statisticsEnabled;
- private final ExecutorService asyncWriteToPipeExecutorService;
+ private final ExecutorService asyncExecutorService;
private MethodChannel methodChannel;
private EventChannel eventChannel;
@@ -147,7 +147,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
public FFmpegKitFlutterPlugin() {
this.logsEnabled = new AtomicBoolean(false);
this.statisticsEnabled = new AtomicBoolean(false);
- this.asyncWriteToPipeExecutorService = Executors.newFixedThreadPool(asyncWriteToPipeConcurrencyLimit);
+ this.asyncExecutorService = Executors.newFixedThreadPool(asyncConcurrencyLimit);
this.resultHandler = new FFmpegKitFlutterMethodResultHandler();
Log.d(LIBRARY_NAME, String.format("FFmpegKitFlutterPlugin created %s.", this));
@@ -457,6 +457,27 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
resultHandler.errorAsync(result, "INVALID_SIGNAL", "Invalid signal value.");
}
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":
if (sessionId != null) {
asyncFFmpegSessionExecute(sessionId, result);
@@ -994,6 +1015,54 @@ 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 instanceof FFmpegSession) {
+ 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 instanceof FFprobeSession) {
+ 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 instanceof MediaInformationSession) {
+ 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) {
final Session session = FFmpegKitConfig.getSession(sessionId.longValue());
if (session == null) {
@@ -1110,8 +1179,8 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met
}
protected void writeToPipe(@NonNull final String inputPath, @NonNull final String namedPipePath, @NonNull final Result result) {
- final AsyncWriteToPipeTask asyncTask = new AsyncWriteToPipeTask(inputPath, namedPipePath, resultHandler, result);
- asyncWriteToPipeExecutorService.submit(asyncTask);
+ final WriteToPipeTask asyncTask = new WriteToPipeTask(inputPath, namedPipePath, resultHandler, result);
+ 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) {
diff --git a/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/FFmpegSessionExecuteTask.java b/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/FFmpegSessionExecuteTask.java
new file mode 100644
index 0000000..a099cf4
--- /dev/null
+++ b/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/FFmpegSessionExecuteTask.java
@@ -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 .
+ */
+
+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);
+ }
+}
diff --git a/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/FFprobeSessionExecuteTask.java b/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/FFprobeSessionExecuteTask.java
new file mode 100644
index 0000000..dc748eb
--- /dev/null
+++ b/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/FFprobeSessionExecuteTask.java
@@ -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 .
+ */
+
+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);
+ }
+}
diff --git a/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/MediaInformationSessionExecuteTask.java b/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/MediaInformationSessionExecuteTask.java
new file mode 100644
index 0000000..f942cd2
--- /dev/null
+++ b/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/MediaInformationSessionExecuteTask.java
@@ -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 .
+ */
+
+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);
+ }
+}
diff --git a/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/AsyncWriteToPipeTask.java b/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/WriteToPipeTask.java
similarity index 89%
rename from flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/AsyncWriteToPipeTask.java
rename to flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/WriteToPipeTask.java
index d052738..e157437 100644
--- a/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/AsyncWriteToPipeTask.java
+++ b/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/WriteToPipeTask.java
@@ -29,13 +29,13 @@ import java.io.IOException;
import io.flutter.plugin.common.MethodChannel;
-public class AsyncWriteToPipeTask implements Runnable {
+public class WriteToPipeTask implements Runnable {
private final String inputPath;
private final String namedPipePath;
private final FFmpegKitFlutterMethodResultHandler resultHandler;
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.namedPipePath = namedPipePath;
this.resultHandler = resultHandler;
diff --git a/flutter/flutter/ios/Classes/FFmpegKitFlutterPlugin.m b/flutter/flutter/ios/Classes/FFmpegKitFlutterPlugin.m
index 37b86c6..05aeb12 100644
--- a/flutter/flutter/ios/Classes/FFmpegKitFlutterPlugin.m
+++ b/flutter/flutter/ios/Classes/FFmpegKitFlutterPlugin.m
@@ -71,7 +71,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
FlutterEventSink _eventSink;
BOOL logsEnabled;
BOOL statisticsEnabled;
- dispatch_queue_t asyncWriteToPipeDispatchQueue;
+ dispatch_queue_t asyncDispatchQueue;
}
- (instancetype)init {
@@ -79,7 +79,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
if (self) {
logsEnabled = false;
statisticsEnabled = false;
- asyncWriteToPipeDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ asyncDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"FFmpegKitFlutterPlugin %p created.\n", self);
}
@@ -301,6 +301,24 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
} else {
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]) {
if (sessionId != nil) {
[self asyncFFmpegSessionExecute:sessionId result:result];
@@ -710,6 +728,60 @@ 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 isMemberOfClass:[FFmpegSession class]]) {
+ 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 isMemberOfClass:[FFprobeSession class]]) {
+ 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 isMemberOfClass:[MediaInformationSession class]]) {
+ 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 {
AbstractSession* session = (AbstractSession*)[FFmpegKitConfig getSession:[sessionId longValue]];
if (session == nil) {
@@ -854,7 +926,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
}
- (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);
diff --git a/flutter/flutter/lib/ffmpeg_kit.dart b/flutter/flutter/lib/ffmpeg_kit.dart
index c19efe2..20230d1 100644
--- a/flutter/flutter/lib/ffmpeg_kit.dart
+++ b/flutter/flutter/lib/ffmpeg_kit.dart
@@ -31,6 +31,33 @@ import 'statistics_callback.dart';
class FFmpegKit {
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 execute(String command,
+ [ExecuteCallback? executeCallback = null,
+ LogCallback? logCallback = null,
+ StatisticsCallback? statisticsCallback = null]) async =>
+ FFmpegKit.executeWithArguments(
+ FFmpegKitConfig.parseArguments(command),
+ executeCallback,
+ logCallback,
+ statisticsCallback);
+
+ /// Synchronously executes FFmpeg with arguments provided.
+ static Future executeWithArguments(
+ List commandArguments,
+ [ExecuteCallback? executeCallback = null,
+ LogCallback? logCallback = null,
+ StatisticsCallback? statisticsCallback = null]) async {
+ final session = await FFmpegSession.create(commandArguments,
+ executeCallback, logCallback, statisticsCallback, null);
+
+ await FFmpegKitConfig.ffmpegExecute(session);
+
+ return session;
+ }
+
/// 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.
///
diff --git a/flutter/flutter/lib/ffmpeg_kit_config.dart b/flutter/flutter/lib/ffmpeg_kit_config.dart
index b2c037e..04bae7c 100644
--- a/flutter/flutter/lib/ffmpeg_kit_config.dart
+++ b/flutter/flutter/lib/ffmpeg_kit_config.dart
@@ -215,6 +215,44 @@ class FFmpegKitConfig {
}
}
+ /// Synchronously executes the FFmpeg session provided.
+ static Future 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 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 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.
///
/// Note that this method returns immediately and does not wait the execution to complete. You must use an
diff --git a/flutter/flutter/lib/ffprobe_kit.dart b/flutter/flutter/lib/ffprobe_kit.dart
index 47d7e2b..5140895 100644
--- a/flutter/flutter/lib/ffprobe_kit.dart
+++ b/flutter/flutter/lib/ffprobe_kit.dart
@@ -31,6 +31,30 @@ import 'src/ffmpeg_kit_factory.dart';
class FFprobeKit {
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 execute(String command,
+ [ExecuteCallback? executeCallback = null,
+ LogCallback? logCallback = null]) async =>
+ FFprobeKit.executeWithArguments(
+ FFmpegKitConfig.parseArguments(command),
+ executeCallback,
+ logCallback);
+
+ /// Synchronously executes FFprobe with arguments provided.
+ static Future executeWithArguments(
+ List commandArguments,
+ [ExecuteCallback? executeCallback = null,
+ LogCallback? logCallback = null]) async {
+ final session = await FFprobeSession.create(
+ commandArguments, executeCallback, logCallback, null);
+
+ await FFmpegKitConfig.ffprobeExecute(session);
+
+ return session;
+ }
+
/// 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.
///
@@ -60,6 +84,58 @@ class FFprobeKit {
return session;
}
+ /// Extracts media information for the file specified with path.
+ static Future getMediaInformation(String path,
+ [ExecuteCallback? executeCallback = null,
+ LogCallback? logCallback = null,
+ 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, executeCallback, logCallback, 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 getMediaInformationFromCommand(
+ String command,
+ [ExecuteCallback? executeCallback = null,
+ LogCallback? logCallback = null,
+ int? waitTimeout = null]) async =>
+ FFprobeKit.getMediaInformationFromCommandArguments(
+ FFmpegKitConfig.parseArguments(command),
+ executeCallback,
+ logCallback,
+ 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
+ getMediaInformationFromCommandArguments(
+ List commandArguments,
+ [ExecuteCallback? executeCallback = null,
+ LogCallback? logCallback = null,
+ int? waitTimeout = null]) async {
+ final session = await MediaInformationSession.create(
+ commandArguments, executeCallback, logCallback);
+
+ await FFmpegKitConfig.getMediaInformationExecute(session, waitTimeout);
+
+ return session;
+ }
+
/// 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
@@ -100,12 +176,14 @@ class FFprobeKit {
logCallback,
waitTimeout);
- /// Starts an asynchronous FFprobe execution to extract media information using command arguments. The command
- /// passed to this method must generate the output in JSON format in order to successfully extract media information
- /// from it.
+ /// Starts an asynchronous FFprobe execution to extract media information
+ /// using command arguments. The command passed to 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
- /// [ExecuteCallback] if you want to be notified about the result.
+ /// 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.
static Future
getMediaInformationFromCommandArgumentsAsync(
List commandArguments,
diff --git a/flutter/flutter/macos/Classes/FFmpegKitFlutterPlugin.m b/flutter/flutter/macos/Classes/FFmpegKitFlutterPlugin.m
index 33f5269..d12bdf4 100644
--- a/flutter/flutter/macos/Classes/FFmpegKitFlutterPlugin.m
+++ b/flutter/flutter/macos/Classes/FFmpegKitFlutterPlugin.m
@@ -71,7 +71,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
FlutterEventSink _eventSink;
BOOL logsEnabled;
BOOL statisticsEnabled;
- dispatch_queue_t asyncWriteToPipeDispatchQueue;
+ dispatch_queue_t asyncDispatchQueue;
}
- (instancetype)init {
@@ -79,7 +79,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
if (self) {
logsEnabled = false;
statisticsEnabled = false;
- asyncWriteToPipeDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ asyncDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"FFmpegKitFlutterPlugin %p created.\n", self);
}
@@ -301,6 +301,24 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
} else {
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]) {
if (sessionId != nil) {
[self asyncFFmpegSessionExecute:sessionId result:result];
@@ -710,6 +728,60 @@ 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 isMemberOfClass:[FFmpegSession class]]) {
+ 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 isMemberOfClass:[FFprobeSession class]]) {
+ 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 isMemberOfClass:[MediaInformationSession class]]) {
+ 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 {
AbstractSession* session = (AbstractSession*)[FFmpegKitConfig getSession:[sessionId longValue]];
if (session == nil) {
@@ -854,7 +926,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
}
- (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);
diff --git a/flutter/flutter_platform_interface/lib/ffmpeg_kit_flutter_platform_interface.dart b/flutter/flutter_platform_interface/lib/ffmpeg_kit_flutter_platform_interface.dart
index 82f50ea..daf485b 100644
--- a/flutter/flutter_platform_interface/lib/ffmpeg_kit_flutter_platform_interface.dart
+++ b/flutter/flutter_platform_interface/lib/ffmpeg_kit_flutter_platform_interface.dart
@@ -218,6 +218,22 @@ abstract class FFmpegKitPlatform extends PlatformInterface {
' has not been implemented!');
}
+ Future ffmpegKitConfigFFmpegExecute(int? sessionId) async {
+ throw UnimplementedError(
+ 'ffmpegKitConfigFFmpegExecute() has not been implemented!');
+ }
+
+ Future ffmpegKitConfigFFprobeExecute(int? sessionId) async {
+ throw UnimplementedError(
+ 'ffmpegKitConfigFFprobeExecute() has not been implemented!');
+ }
+
+ Future ffmpegKitConfigGetMediaInformationExecute(
+ int? sessionId, int? waitTimeout) async {
+ throw UnimplementedError('ffmpegKitConfigGetMediaInformationExecute()'
+ ' has not been implemented!');
+ }
+
Future ffmpegKitConfigSetLogLevel(int logLevel) async {
throw UnimplementedError(
'ffmpegKitConfigSetLogLevel() has not been implemented!');
diff --git a/flutter/flutter_platform_interface/lib/method_channel_ffmpeg_kit_flutter.dart b/flutter/flutter_platform_interface/lib/method_channel_ffmpeg_kit_flutter.dart
index 1076405..7ec5914 100644
--- a/flutter/flutter_platform_interface/lib/method_channel_ffmpeg_kit_flutter.dart
+++ b/flutter/flutter_platform_interface/lib/method_channel_ffmpeg_kit_flutter.dart
@@ -179,6 +179,22 @@ class MethodChannelFFmpegKit extends FFmpegKitPlatform {
Future ffmpegKitConfigIgnoreSignal(int signal) async =>
_channel.invokeMethod('ignoreSignal', {'signal': signal});
+ @override
+ Future ffmpegKitConfigFFmpegExecute(int? sessionId) async =>
+ _channel.invokeMethod(
+ 'ffmpegSessionExecute', {'sessionId': sessionId});
+
+ @override
+ Future ffmpegKitConfigFFprobeExecute(int? sessionId) async =>
+ _channel.invokeMethod(
+ 'ffprobeSessionExecute', {'sessionId': sessionId});
+
+ @override
+ Future ffmpegKitConfigGetMediaInformationExecute(
+ int? sessionId, int? waitTimeout) async =>
+ _channel.invokeMethod('mediaInformationSessionExecute',
+ {'sessionId': sessionId, 'waitTimeout': waitTimeout});
+
@override
Future ffmpegKitConfigAsyncFFmpegExecute(int? sessionId) async =>
_channel.invokeMethod(