From 8034629c430410b3b0841fd327567d9d50a2d22b Mon Sep 17 00:00:00 2001 From: Taner Sener Date: Sat, 25 Dec 2021 13:47:37 +0000 Subject: [PATCH] replace execute callback with session specific complete callbacks, fixes #197 --- .../flutter/FFmpegKitFlutterPlugin.java | 35 +++-- .../ios/Classes/FFmpegKitFlutterPlugin.m | 48 ++++--- flutter/flutter/lib/abstract_session.dart | 12 +- flutter/flutter/lib/ffmpeg_kit.dart | 27 ++-- flutter/flutter/lib/ffmpeg_kit_config.dart | 119 +++++++++++++++-- flutter/flutter/lib/ffmpeg_session.dart | 15 ++- ... => ffmpeg_session_complete_callback.dart} | 12 +- flutter/flutter/lib/ffprobe_kit.dart | 92 ++++++++----- flutter/flutter/lib/ffprobe_session.dart | 13 +- .../ffprobe_session_complete_callback.dart | 29 +++++ .../lib/media_information_session.dart | 21 ++- ...information_session_complete_callback.dart | 30 +++++ flutter/flutter/lib/session.dart | 9 +- .../flutter/lib/src/ffmpeg_kit_factory.dart | 78 +++++++++-- .../src/ffmpeg_kit_flutter_initializer.dart | 121 +++++++++++++----- flutter/flutter/lib/statistics_callback.dart | 2 +- .../macos/Classes/FFmpegKitFlutterPlugin.m | 2 +- ...ffmpeg_kit_flutter_platform_interface.dart | 9 +- .../method_channel_ffmpeg_kit_flutter.dart | 6 +- 19 files changed, 516 insertions(+), 164 deletions(-) rename flutter/flutter/lib/{execute_callback.dart => ffmpeg_session_complete_callback.dart} (73%) create mode 100644 flutter/flutter/lib/ffprobe_session_complete_callback.dart create mode 100644 flutter/flutter/lib/media_information_session_complete_callback.dart 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 876fa2b..1c81907 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 @@ -114,7 +114,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met // EVENTS public static final String EVENT_LOG_CALLBACK_EVENT = "FFmpegKitLogCallbackEvent"; 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 public static final int READABLE_REQUEST_CODE = 10000; @@ -165,7 +165,9 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met } protected void registerGlobalCallbacks() { - FFmpegKitConfig.enableExecuteCallback(this::emitSession); + FFmpegKitConfig.enableFFmpegSessionCompleteCallback(this::emitSession); + FFmpegKitConfig.enableFFprobeSessionCompleteCallback(this::emitSession); + FFmpegKitConfig.enableMediaInformationSessionCompleteCallback(this::emitSession); FFmpegKitConfig.enableLogCallback(log -> { if (logsEnabled.get()) { @@ -622,6 +624,9 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met case "getFFprobeSessions": getFFprobeSessions(result); break; + case "getMediaInformationSessions": + getMediaInformationSessions(result); + break; case "getPackageName": getPackageName(result); break; @@ -827,7 +832,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met if (session == null) { resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found."); } else { - if (session instanceof FFmpegSession) { + if (session.isFFmpeg()) { final int timeout; if (isValidPositiveNumber(waitTimeout)) { timeout = waitTimeout; @@ -847,7 +852,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met if (session == null) { resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found."); } else { - if (session instanceof FFmpegSession) { + if (session.isFFmpeg()) { final List statistics = ((FFmpegSession) session).getStatistics(); resultHandler.successAsync(result, toStatisticsMapList(statistics)); } else { @@ -1020,7 +1025,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met if (session == null) { resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found."); } else { - if (session instanceof FFmpegSession) { + if (session.isFFmpeg()) { final FFmpegSessionExecuteTask ffmpegSessionExecuteTask = new FFmpegSessionExecuteTask((FFmpegSession) session, resultHandler, result); asyncExecutorService.submit(ffmpegSessionExecuteTask); } else { @@ -1034,7 +1039,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met if (session == null) { resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found."); } else { - if (session instanceof FFprobeSession) { + if (session.isFFprobe()) { final FFprobeSessionExecuteTask ffprobeSessionExecuteTask = new FFprobeSessionExecuteTask((FFprobeSession) session, resultHandler, result); asyncExecutorService.submit(ffprobeSessionExecuteTask); } else { @@ -1048,7 +1053,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met if (session == null) { resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found."); } else { - if (session instanceof MediaInformationSession) { + if (session.isMediaInformation()) { final int timeout; if (isValidPositiveNumber(waitTimeout)) { timeout = waitTimeout; @@ -1068,7 +1073,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met if (session == null) { resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found."); } else { - if (session instanceof FFmpegSession) { + if (session.isFFmpeg()) { FFmpegKitConfig.asyncFFmpegExecute((FFmpegSession) session); resultHandler.successAsync(result, null); } else { @@ -1082,7 +1087,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met if (session == null) { resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found."); } else { - if (session instanceof FFprobeSession) { + if (session.isFFprobe()) { FFmpegKitConfig.asyncFFprobeExecute((FFprobeSession) session); resultHandler.successAsync(result, null); } else { @@ -1096,7 +1101,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met if (session == null) { resultHandler.errorAsync(result, "SESSION_NOT_FOUND", "Session not found."); } else { - if (session instanceof MediaInformationSession) { + if (session.isMediaInformation()) { final int timeout; if (isValidPositiveNumber(waitTimeout)) { timeout = waitTimeout; @@ -1282,7 +1287,11 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met // FFprobeKit protected void getFFprobeSessions(@NonNull final Result result) { - resultHandler.successAsync(result, toSessionMapList(FFprobeKit.listSessions())); + resultHandler.successAsync(result, toSessionMapList(FFprobeKit.listFFprobeSessions())); + } + + protected void getMediaInformationSessions(@NonNull final Result result) { + resultHandler.successAsync(result, toSessionMapList(FFprobeKit.listMediaInformationSessions())); } // Packages @@ -1328,7 +1337,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met sessionMap.put(KEY_SESSION_COMMAND, session.getCommand()); if (session.isFFprobe()) { - if (session instanceof MediaInformationSession) { + if (session.isMediaInformation()) { final MediaInformationSession mediaInformationSession = (MediaInformationSession) session; final MediaInformation mediaInformation = mediaInformationSession.getMediaInformation(); if (mediaInformation != null) { @@ -1529,7 +1538,7 @@ public class FFmpegKitFlutterPlugin implements FlutterPlugin, ActivityAware, Met protected void emitSession(final Session session) { final HashMap sessionMap = new HashMap<>(); - sessionMap.put(EVENT_EXECUTE_CALLBACK_EVENT, toMap(session)); + sessionMap.put(EVENT_COMPLETE_CALLBACK_EVENT, toMap(session)); resultHandler.successAsync(eventSink, sessionMap); } diff --git a/flutter/flutter/ios/Classes/FFmpegKitFlutterPlugin.m b/flutter/flutter/ios/Classes/FFmpegKitFlutterPlugin.m index 05aeb12..965c799 100644 --- a/flutter/flutter/ios/Classes/FFmpegKitFlutterPlugin.m +++ b/flutter/flutter/ios/Classes/FFmpegKitFlutterPlugin.m @@ -57,7 +57,7 @@ static int const SESSION_TYPE_MEDIA_INFORMATION = 3; // EVENTS static NSString *const EVENT_LOG_CALLBACK_EVENT = @"FFmpegKitLogCallbackEvent"; 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 static NSString *const ARGUMENT_SESSION_ID = @"sessionId"; @@ -110,9 +110,19 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit; } - (void)registerGlobalCallbacks { - [FFmpegKitConfig enableExecuteCallback:^(id session){ + [FFmpegKitConfig enableFFmpegSessionCompleteCallback:^(FFmpegSession* 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){ @@ -419,6 +429,8 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit; [self getFFmpegSessions:result]; } else if ([@"getFFprobeSessions" isEqualToString:call.method]) { [self getFFprobeSessions:result]; + } else if ([@"getMediaInformationSessions" isEqualToString:call.method]) { + [self getMediaInformationSessions:result]; } else if ([@"getPackageName" isEqualToString:call.method]) { [self getPackageName:result]; } else if ([@"getExternalLibraries" isEqualToString:call.method]) { @@ -545,7 +557,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit; // FFmpegSession - (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]); } @@ -554,7 +566,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit; if (session == nil) { result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); } else { - if ([session isMemberOfClass:[FFmpegSession class]]) { + if ([session isFFmpeg]) { int timeout; if ([FFmpegKitFlutterPlugin isValidPositiveNumber:waitTimeout]) { timeout = [waitTimeout intValue]; @@ -574,7 +586,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit; if (session == nil) { result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); } else { - if ([session isMemberOfClass:[FFmpegSession class]]) { + if ([session isFFmpeg]) { NSArray* statistics = [(FFmpegSession*)session getStatistics]; result([FFmpegKitFlutterPlugin toStatisticsArray:statistics]); } else { @@ -586,14 +598,14 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit; // FFprobeSession - (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]); } // MediaInformationSession - (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]); } @@ -733,7 +745,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit; if (session == nil) { result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); } else { - if ([session isMemberOfClass:[FFmpegSession class]]) { + if ([session isFFmpeg]) { dispatch_async(asyncDispatchQueue, ^{ [FFmpegKitConfig ffmpegExecute:(FFmpegSession*)session]; result(nil); @@ -749,7 +761,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit; if (session == nil) { result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); } else { - if ([session isMemberOfClass:[FFprobeSession class]]) { + if ([session isFFprobe]) { dispatch_async(asyncDispatchQueue, ^{ [FFmpegKitConfig ffprobeExecute:(FFprobeSession*)session]; result(nil); @@ -765,7 +777,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit; if (session == nil) { result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); } else { - if ([session isMemberOfClass:[MediaInformationSession class]]) { + if ([session isMediaInformation]) { int timeout; if ([FFmpegKitFlutterPlugin isValidPositiveNumber:waitTimeout]) { timeout = [waitTimeout intValue]; @@ -787,7 +799,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit; if (session == nil) { result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); } else { - if ([session isMemberOfClass:[FFmpegSession class]]) { + if ([session isFFmpeg]) { [FFmpegKitConfig asyncFFmpegExecute:(FFmpegSession*)session]; result(nil); } else { @@ -801,7 +813,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit; if (session == nil) { result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); } else { - if ([session isMemberOfClass:[FFprobeSession class]]) { + if ([session isFFprobe]) { [FFmpegKitConfig asyncFFprobeExecute:(FFprobeSession*)session]; result(nil); } else { @@ -815,7 +827,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit; if (session == nil) { result([FlutterError errorWithCode:@"SESSION_NOT_FOUND" message:@"Session not found." details:nil]); } else { - if ([session isMemberOfClass:[MediaInformationSession class]]) { + if ([session isMediaInformation]) { int timeout; if ([FFmpegKitFlutterPlugin isValidPositiveNumber:waitTimeout]) { timeout = [waitTimeout intValue]; @@ -1007,7 +1019,11 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit; // FFprobeKit - (void)getFFprobeSessions:(FlutterResult)result { - result([FFmpegKitFlutterPlugin toSessionArray:[FFprobeKit listSessions]]); + result([FFmpegKitFlutterPlugin toSessionArray:[FFprobeKit listFFprobeSessions]]); +} + +- (void)getMediaInformationSessions:(FlutterResult)result { + result([FFmpegKitFlutterPlugin toSessionArray:[FFprobeKit listMediaInformationSessions]]); } // Packages @@ -1046,7 +1062,7 @@ extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit; dictionary[KEY_SESSION_COMMAND] = [session getCommand]; if ([session isFFprobe]) { - if ([(AbstractSession*)session isMemberOfClass:[MediaInformationSession class]]) { + if ([session isMediaInformation]) { MediaInformationSession *mediaInformationSession = (MediaInformationSession*)session; dictionary[KEY_SESSION_MEDIA_INFORMATION] = [FFmpegKitFlutterPlugin toMediaInformationDictionary:[mediaInformationSession getMediaInformation]]; dictionary[KEY_SESSION_TYPE] = [NSNumber numberWithInt:SESSION_TYPE_MEDIA_INFORMATION]; diff --git a/flutter/flutter/lib/abstract_session.dart b/flutter/flutter/lib/abstract_session.dart index 6529192..4667569 100644 --- a/flutter/flutter/lib/abstract_session.dart +++ b/flutter/flutter/lib/abstract_session.dart @@ -20,7 +20,6 @@ import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platform_interface.dart'; import 'package:flutter/services.dart'; -import 'execute_callback.dart'; import 'ffmpeg_kit_config.dart'; import 'ffmpeg_session.dart'; import 'ffprobe_session.dart'; @@ -35,7 +34,7 @@ import 'session_state.dart'; import 'src/ffmpeg_kit_factory.dart'; /// Abstract session implementation which includes common features shared by -/// "FFmpeg" and "FFprobe" sessions. +/// "FFmpeg", "FFprobe" and "MediaInformation" sessions. class AbstractSession extends Session { static FFmpegKitPlatform _platform = FFmpegKitPlatform.instance; @@ -221,11 +220,7 @@ class AbstractSession extends Session { return session; } - /// Returns the session specific execute callback function. - ExecuteCallback? getExecuteCallback() => - FFmpegKitFactory.getExecuteCallback(this.getSessionId()); - - /// Returns the session specific log callback function. + /// Returns the session specific log callback. LogCallback? getLogCallback() => FFmpegKitFactory.getLogCallback(this.getSessionId()); @@ -429,6 +424,9 @@ class AbstractSession extends Session { /// Returns whether it is an "FFprobe" session or not. bool isFFprobe() => false; + /// Returns whether it is an "MediaInformation" session or not. + bool isMediaInformation() => false; + /// Cancels running the session. void cancel() {} } diff --git a/flutter/flutter/lib/ffmpeg_kit.dart b/flutter/flutter/lib/ffmpeg_kit.dart index 20230d1..18dce96 100644 --- a/flutter/flutter/lib/ffmpeg_kit.dart +++ b/flutter/flutter/lib/ffmpeg_kit.dart @@ -20,9 +20,9 @@ import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platform_interface.dart'; import 'package:flutter/services.dart'; -import 'execute_callback.dart'; import 'ffmpeg_kit_config.dart'; import 'ffmpeg_session.dart'; +import 'ffmpeg_session_complete_callback.dart'; import 'log_callback.dart'; import 'src/ffmpeg_kit_factory.dart'; import 'statistics_callback.dart'; @@ -35,23 +35,20 @@ class FFmpegKit { /// 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, + [FFmpegSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null, StatisticsCallback? statisticsCallback = null]) async => - FFmpegKit.executeWithArguments( - FFmpegKitConfig.parseArguments(command), - executeCallback, - logCallback, - statisticsCallback); + FFmpegKit.executeWithArguments(FFmpegKitConfig.parseArguments(command), + completeCallback, logCallback, statisticsCallback); /// Synchronously executes FFmpeg with arguments provided. static Future executeWithArguments( List commandArguments, - [ExecuteCallback? executeCallback = null, + [FFmpegSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null, StatisticsCallback? statisticsCallback = null]) async { final session = await FFmpegSession.create(commandArguments, - executeCallback, logCallback, statisticsCallback, null); + completeCallback, logCallback, statisticsCallback, null); await FFmpegKitConfig.ffmpegExecute(session); @@ -62,28 +59,28 @@ class FFmpegKit { /// 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 - /// [ExecuteCallback] if you want to be notified about the result. + /// [FFmpegSessionCompleteCallback] if you want to be notified about the result. static Future executeAsync(String command, - [ExecuteCallback? executeCallback = null, + [FFmpegSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null, StatisticsCallback? statisticsCallback = null]) async => FFmpegKit.executeWithArgumentsAsync( FFmpegKitConfig.parseArguments(command), - executeCallback, + completeCallback, logCallback, statisticsCallback); /// 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 - /// [ExecuteCallback] if you want to be notified about the result. + /// [FFmpegSessionCompleteCallback] if you want to be notified about the result. static Future executeWithArgumentsAsync( List commandArguments, - [ExecuteCallback? executeCallback = null, + [FFmpegSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null, StatisticsCallback? statisticsCallback = null]) async { final session = await FFmpegSession.create(commandArguments, - executeCallback, logCallback, statisticsCallback, null); + completeCallback, logCallback, statisticsCallback, null); await FFmpegKitConfig.asyncFFmpegExecute(session); diff --git a/flutter/flutter/lib/ffmpeg_kit_config.dart b/flutter/flutter/lib/ffmpeg_kit_config.dart index 04bae7c..795ac34 100644 --- a/flutter/flutter/lib/ffmpeg_kit_config.dart +++ b/flutter/flutter/lib/ffmpeg_kit_config.dart @@ -20,13 +20,15 @@ import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platform_interface.dart'; import 'package:flutter/services.dart'; -import 'execute_callback.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 'log_callback.dart'; import 'log_redirection_strategy.dart'; import 'media_information_session.dart'; +import 'media_information_session_complete_callback.dart'; import 'session.dart'; import 'session_state.dart'; import 'signal.dart'; @@ -256,7 +258,7 @@ class FFmpegKitConfig { /// 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 - /// [ExecuteCallback] if you want to be notified about the result. + /// [FFmpegSessionCompleteCallback] if you want to be notified about the result. static Future asyncFFmpegExecute(FFmpegSession ffmpegSession) async { try { await init(); @@ -271,7 +273,7 @@ class FFmpegKitConfig { /// 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 - /// [ExecuteCallback] if you want to be notified about the result. + /// [FFprobeSessionCompleteCallback] if you want to be notified about the result. static Future asyncFFprobeExecute(FFprobeSession ffprobeSession) async { try { await init(); @@ -286,7 +288,7 @@ class FFmpegKitConfig { /// 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 - /// [ExecuteCallback] if you want to be notified about the result. + /// [MediaInformationSessionCompleteCallback] if you want to be notified about the result. static Future asyncGetMediaInformationExecute( MediaInformationSession mediaInformationSession, [int? waitTimeout = null]) async { @@ -300,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]) { FFmpegKitFactory.setGlobalLogCallback(logCallback); } - /// Sets a global callback function to redirect FFmpeg statistics. + /// Sets a global callback to redirect FFmpeg statistics. static void enableStatisticsCallback( [StatisticsCallback? statisticsCallback = null]) { FFmpegKitFactory.setGlobalStatisticsCallback(statisticsCallback); } - /// Sets a global callback function to receive execution results. - static void enableExecuteCallback([ExecuteCallback? executeCallback = null]) { - FFmpegKitFactory.setGlobalExecuteCallback(executeCallback); + /// Sets a global FFmpegSessionCompleteCallback to receive execution results + /// for FFmpeg sessions. + 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. static int getLogLevel() => _activeLogLevel; @@ -424,6 +459,72 @@ class FFmpegKitConfig { } } + /// Returns all FFmpeg sessions in the session history. + static Future> 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)) + .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> 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)) + .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> + 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)) + .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]. static Future> getSessionsByState( SessionState sessionState) async { diff --git a/flutter/flutter/lib/ffmpeg_session.dart b/flutter/flutter/lib/ffmpeg_session.dart index 736b21d..2cbc777 100644 --- a/flutter/flutter/lib/ffmpeg_session.dart +++ b/flutter/flutter/lib/ffmpeg_session.dart @@ -21,8 +21,8 @@ import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platfor import 'package:flutter/services.dart'; import 'abstract_session.dart'; -import 'execute_callback.dart'; import 'ffmpeg_kit_config.dart'; +import 'ffmpeg_session_complete_callback.dart'; import 'log_callback.dart'; import 'log_redirection_strategy.dart'; import 'src/ffmpeg_kit_factory.dart'; @@ -33,7 +33,7 @@ import 'statistics_callback.dart'; class FFmpegSession extends AbstractSession { /// Creates a new FFmpeg session with [argumentsArray]. static Future create(List argumentsArray, - [ExecuteCallback? executeCallback = null, + [FFmpegSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null, StatisticsCallback? statisticsCallback = null, LogRedirectionStrategy? logRedirectionStrategy = null]) async { @@ -41,7 +41,8 @@ class FFmpegSession extends AbstractSession { argumentsArray, logRedirectionStrategy); final sessionId = session.getSessionId(); - FFmpegKitFactory.setExecuteCallback(sessionId, executeCallback); + FFmpegKitFactory.setFFmpegSessionCompleteCallback( + sessionId, completeCallback); FFmpegKitFactory.setLogCallback(sessionId, logCallback); FFmpegKitFactory.setStatisticsCallback(sessionId, statisticsCallback); @@ -53,10 +54,14 @@ class FFmpegSession extends AbstractSession { static FFmpegSession fromMap(Map sessionMap) => AbstractSession.createFFmpegSessionFromMap(sessionMap); - /// Returns the session specific statistics callback function. + /// Returns the session specific statistics callback. StatisticsCallback? getStatisticsCallback() => 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 /// asynchronous statistics that are not delivered yet, this method waits for /// them until [waitTimeout]. @@ -120,4 +125,6 @@ class FFmpegSession extends AbstractSession { bool isFFmpeg() => true; bool isFFprobe() => false; + + bool isMediaInformation() => false; } diff --git a/flutter/flutter/lib/execute_callback.dart b/flutter/flutter/lib/ffmpeg_session_complete_callback.dart similarity index 73% rename from flutter/flutter/lib/execute_callback.dart rename to flutter/flutter/lib/ffmpeg_session_complete_callback.dart index 063bff7..4e8a40c 100644 --- a/flutter/flutter/lib/execute_callback.dart +++ b/flutter/flutter/lib/ffmpeg_session_complete_callback.dart @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 Taner Sener + * Copyright (c) 2021 Taner Sener * * This file is part of FFmpegKit. * @@ -17,13 +17,13 @@ * along with FFmpegKit. If not, see . */ -import 'session.dart'; +import 'ffmpeg_session.dart'; -/// Callback function invoked when a session ends running. -/// Session has either SessionState.completed or SessionState.failed state when -/// the callback is invoked. +/// Callback function that is invoked when an asynchronous FFmpeg 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 ExecuteCallback = void Function(Session session); +typedef FFmpegSessionCompleteCallback = void Function(FFmpegSession session); diff --git a/flutter/flutter/lib/ffprobe_kit.dart b/flutter/flutter/lib/ffprobe_kit.dart index 5140895..7822755 100644 --- a/flutter/flutter/lib/ffprobe_kit.dart +++ b/flutter/flutter/lib/ffprobe_kit.dart @@ -20,11 +20,12 @@ import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platform_interface.dart'; import 'package:flutter/services.dart'; -import 'execute_callback.dart'; import 'ffmpeg_kit_config.dart'; import 'ffprobe_session.dart'; +import 'ffprobe_session_complete_callback.dart'; import 'log_callback.dart'; import 'media_information_session.dart'; +import 'media_information_session_complete_callback.dart'; import 'src/ffmpeg_kit_factory.dart'; /// Main class to run "FFprobe" commands. @@ -35,20 +36,18 @@ class FFprobeKit { /// 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, + [FFprobeSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null]) async => - FFprobeKit.executeWithArguments( - FFmpegKitConfig.parseArguments(command), - executeCallback, - logCallback); + FFprobeKit.executeWithArguments(FFmpegKitConfig.parseArguments(command), + completeCallback, logCallback); /// Synchronously executes FFprobe with arguments provided. static Future executeWithArguments( List commandArguments, - [ExecuteCallback? executeCallback = null, + [FFprobeSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null]) async { final session = await FFprobeSession.create( - commandArguments, executeCallback, logCallback, null); + commandArguments, completeCallback, logCallback, null); await FFmpegKitConfig.ffprobeExecute(session); @@ -59,25 +58,25 @@ class FFprobeKit { /// 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 - /// [ExecuteCallback] if you want to be notified about the result. + /// [FFprobeSessionCompleteCallback] if you want to be notified about the result. static Future executeAsync(String command, - [ExecuteCallback? executeCallback = null, + [FFprobeSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null]) async => FFprobeKit.executeWithArgumentsAsync( FFmpegKitConfig.parseArguments(command), - executeCallback, + completeCallback, logCallback); /// 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 - /// [ExecuteCallback] if you want to be notified about the result. + /// [FFprobeSessionCompleteCallback] if you want to be notified about the result. static Future executeWithArgumentsAsync( List commandArguments, - [ExecuteCallback? executeCallback = null, + [FFprobeSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null]) async { final session = await FFprobeSession.create( - commandArguments, executeCallback, logCallback, null); + commandArguments, completeCallback, logCallback, null); await FFmpegKitConfig.asyncFFprobeExecute(session); @@ -86,7 +85,7 @@ class FFprobeKit { /// Extracts media information for the file specified with path. static Future getMediaInformation(String path, - [ExecuteCallback? executeCallback = null, + [MediaInformationSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null, int? waitTimeout = null]) async { final commandArguments = [ @@ -102,7 +101,7 @@ class FFprobeKit { path ]; return FFprobeKit.getMediaInformationFromCommandArguments( - commandArguments, executeCallback, logCallback, waitTimeout); + commandArguments, completeCallback, logCallback, waitTimeout); } /// Extracts media information using the command provided. The command @@ -110,12 +109,12 @@ class FFprobeKit { /// successfully extract media information from it. static Future getMediaInformationFromCommand( String command, - [ExecuteCallback? executeCallback = null, + [MediaInformationSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null, int? waitTimeout = null]) async => FFprobeKit.getMediaInformationFromCommandArguments( FFmpegKitConfig.parseArguments(command), - executeCallback, + completeCallback, logCallback, waitTimeout); @@ -123,13 +122,12 @@ class FFprobeKit { /// 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, + getMediaInformationFromCommandArguments(List commandArguments, + [MediaInformationSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null, int? waitTimeout = null]) async { final session = await MediaInformationSession.create( - commandArguments, executeCallback, logCallback); + commandArguments, completeCallback, logCallback); await FFmpegKitConfig.getMediaInformationExecute(session, waitTimeout); @@ -139,9 +137,9 @@ class FFprobeKit { /// 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 - /// [ExecuteCallback] if you want to be notified about the result. + /// [MediaInformationSessionCompleteCallback] if you want to be notified about the result. static Future getMediaInformationAsync(String path, - [ExecuteCallback? executeCallback = null, + [MediaInformationSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null, int? waitTimeout = null]) async { final commandArguments = [ @@ -157,22 +155,22 @@ class FFprobeKit { path ]; 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 /// 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. + /// [MediaInformationSessionCompleteCallback] if you want to be notified about the result. static Future getMediaInformationFromCommandAsync( String command, - [ExecuteCallback? executeCallback = null, + [MediaInformationSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null, int? waitTimeout = null]) async => FFprobeKit.getMediaInformationFromCommandArgumentsAsync( FFmpegKitConfig.parseArguments(command), - executeCallback, + completeCallback, logCallback, waitTimeout); @@ -182,16 +180,16 @@ class FFprobeKit { /// 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 + /// to complete. You must use an [MediaInformationSessionCompleteCallback] if you want to be /// notified about the result. static Future getMediaInformationFromCommandArgumentsAsync( List commandArguments, - [ExecuteCallback? executeCallback = null, + [MediaInformationSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null, int? waitTimeout = null]) async { final session = await MediaInformationSession.create( - commandArguments, executeCallback, logCallback); + commandArguments, completeCallback, logCallback); await FFmpegKitConfig.asyncGetMediaInformationExecute(session, waitTimeout); @@ -199,10 +197,10 @@ class FFprobeKit { } /// Lists all FFprobe sessions in the session history. - static Future> listSessions() async { + static Future> listFFprobeSessions() async { try { await FFmpegKitConfig.init(); - return _platform.ffprobeKitListSessions().then((sessions) { + return _platform.ffprobeKitListFFprobeSessions().then((sessions) { if (sessions == null) { return List.empty(); } else { @@ -214,8 +212,32 @@ class FFprobeKit { } }); } on PlatformException catch (e, stack) { - print("Plugin listSessions error: ${e.message}"); - return Future.error("listSessions failed.", stack); + print("Plugin listFFprobeSessions error: ${e.message}"); + return Future.error("listFFprobeSessions failed.", stack); + } + } + + /// Lists all MediaInformation sessions in the session history. + static Future> + 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)) + .map((session) => session as MediaInformationSession) + .toList(); + } + }); + } on PlatformException catch (e, stack) { + print("Plugin listMediaInformationSessions error: ${e.message}"); + return Future.error("listMediaInformationSessions failed.", stack); } } } diff --git a/flutter/flutter/lib/ffprobe_session.dart b/flutter/flutter/lib/ffprobe_session.dart index 74769ce..af35a38 100644 --- a/flutter/flutter/lib/ffprobe_session.dart +++ b/flutter/flutter/lib/ffprobe_session.dart @@ -18,7 +18,7 @@ */ import 'abstract_session.dart'; -import 'execute_callback.dart'; +import 'ffprobe_session_complete_callback.dart'; import 'log_callback.dart'; import 'log_redirection_strategy.dart'; import 'src/ffmpeg_kit_factory.dart'; @@ -27,14 +27,15 @@ import 'src/ffmpeg_kit_factory.dart'; class FFprobeSession extends AbstractSession { /// Creates a new FFprobe session with [argumentsArray]. static Future create(List argumentsArray, - [ExecuteCallback? executeCallback = null, + [FFprobeSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null, LogRedirectionStrategy? logRedirectionStrategy = null]) async { final session = await AbstractSession.createFFprobeSession( argumentsArray, logRedirectionStrategy); final sessionId = session.getSessionId(); - FFmpegKitFactory.setExecuteCallback(sessionId, executeCallback); + FFmpegKitFactory.setFFprobeSessionCompleteCallback( + sessionId, completeCallback); FFmpegKitFactory.setLogCallback(sessionId, logCallback); return session; @@ -45,7 +46,13 @@ class FFprobeSession extends AbstractSession { static FFprobeSession fromMap(Map sessionMap) => AbstractSession.createFFprobeSessionFromMap(sessionMap); + /// Returns the session specific complete callback. + FFprobeSessionCompleteCallback? getCompleteCallback() => + FFmpegKitFactory.getFFprobeSessionCompleteCallback(this.getSessionId()); + bool isFFmpeg() => false; bool isFFprobe() => true; + + bool isMediaInformation() => false; } diff --git a/flutter/flutter/lib/ffprobe_session_complete_callback.dart b/flutter/flutter/lib/ffprobe_session_complete_callback.dart new file mode 100644 index 0000000..cfdca17 --- /dev/null +++ b/flutter/flutter/lib/ffprobe_session_complete_callback.dart @@ -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 . + */ + +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); diff --git a/flutter/flutter/lib/media_information_session.dart b/flutter/flutter/lib/media_information_session.dart index 8d9b7bf..c550ca8 100644 --- a/flutter/flutter/lib/media_information_session.dart +++ b/flutter/flutter/lib/media_information_session.dart @@ -18,26 +18,26 @@ */ import 'abstract_session.dart'; -import 'execute_callback.dart'; -import 'ffprobe_session.dart'; import 'log_callback.dart'; import 'media_information.dart'; +import 'media_information_session_complete_callback.dart'; import 'src/ffmpeg_kit_factory.dart'; /// A custom FFprobe session, which produces a "MediaInformation" object /// using the FFprobe output. -class MediaInformationSession extends FFprobeSession { +class MediaInformationSession extends AbstractSession { MediaInformation? _mediaInformation; /// Creates a new MediaInformation session with [argumentsArray]. static Future create(List argumentsArray, - [ExecuteCallback? executeCallback = null, + [MediaInformationSessionCompleteCallback? completeCallback = null, LogCallback? logCallback = null]) async { final session = await AbstractSession.createMediaInformationSession(argumentsArray); final sessionId = session.getSessionId(); - FFmpegKitFactory.setExecuteCallback(sessionId, executeCallback); + FFmpegKitFactory.setMediaInformationSessionCompleteCallback( + sessionId, completeCallback); FFmpegKitFactory.setLogCallback(sessionId, logCallback); return session; @@ -55,4 +55,15 @@ class MediaInformationSession extends FFprobeSession { void setMediaInformation(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; } diff --git a/flutter/flutter/lib/media_information_session_complete_callback.dart b/flutter/flutter/lib/media_information_session_complete_callback.dart new file mode 100644 index 0000000..213900f --- /dev/null +++ b/flutter/flutter/lib/media_information_session_complete_callback.dart @@ -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 . + */ + +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); diff --git a/flutter/flutter/lib/session.dart b/flutter/flutter/lib/session.dart index fe095e4..7fe16ae 100644 --- a/flutter/flutter/lib/session.dart +++ b/flutter/flutter/lib/session.dart @@ -17,7 +17,6 @@ * along with FFmpegKit. If not, see . */ -import 'execute_callback.dart'; import 'log.dart'; import 'log_callback.dart'; import 'log_redirection_strategy.dart'; @@ -26,10 +25,7 @@ import 'session_state.dart'; /// Common interface for all "FFmpegKit" sessions. abstract class Session { - /// Returns the session specific execute callback function. - ExecuteCallback? getExecuteCallback(); - - /// Returns the session specific log callback function. + /// Returns the session specific log callback. LogCallback? getLogCallback(); /// Returns the session identifier. @@ -106,6 +102,9 @@ abstract class Session { /// Returns whether it is an "FFprobe" session or not. bool isFFprobe(); + /// Returns whether it is an "MediaInformation" session or not. + bool isMediaInformation(); + /// Cancels running the session. void cancel(); } diff --git a/flutter/flutter/lib/src/ffmpeg_kit_factory.dart b/flutter/flutter/lib/src/ffmpeg_kit_factory.dart index 0a6aa1a..6140c53 100644 --- a/flutter/flutter/lib/src/ffmpeg_kit_factory.dart +++ b/flutter/flutter/lib/src/ffmpeg_kit_factory.dart @@ -17,18 +17,25 @@ * along with FFmpegKit. If not, see . */ -import '../execute_callback.dart'; import '../ffmpeg_session.dart'; +import '../ffmpeg_session_complete_callback.dart'; import '../ffprobe_session.dart'; +import '../ffprobe_session_complete_callback.dart'; import '../log.dart'; import '../log_callback.dart'; import '../log_redirection_strategy.dart'; import '../media_information_session.dart'; +import '../media_information_session_complete_callback.dart'; import '../session.dart'; import '../statistics.dart'; import '../statistics_callback.dart'; -final executeCallbackMap = new Map(); +final ffmpegSessionCompleteCallbackMap = + new Map(); +final ffprobeSessionCompleteCallbackMap = + new Map(); +final mediaInformationSessionCompleteCallbackMap = + new Map(); final logCallbackMap = new Map(); final statisticsCallbackMap = new Map(); final logRedirectionStrategyMap = new Map(); @@ -36,7 +43,10 @@ final logRedirectionStrategyMap = new Map(); class FFmpegKitFactory { static LogCallback? _logCallback; static StatisticsCallback? _statisticsCallback; - static ExecuteCallback? _executeCallback; + static FFmpegSessionCompleteCallback? _ffmpegSessionCompleteCallback; + static FFprobeSessionCompleteCallback? _ffprobeSessionCompleteCallback; + static MediaInformationSessionCompleteCallback? + _mediaInformationSessionCompleteCallback; static Statistics mapToStatistics(Map statisticsMap) => new Statistics( @@ -125,20 +135,64 @@ class FFmpegKitFactory { _statisticsCallback = statisticsCallback; } - static ExecuteCallback? getExecuteCallback(int? sessionId) => - executeCallbackMap[sessionId]; + static FFmpegSessionCompleteCallback? getFFmpegSessionCompleteCallback( + int? sessionId) => + ffmpegSessionCompleteCallbackMap[sessionId]; - static void setExecuteCallback( - int? sessionId, ExecuteCallback? executeCallback) { - if (sessionId != null && executeCallback != null) { - executeCallbackMap[sessionId] = executeCallback; + static void setFFmpegSessionCompleteCallback( + int? sessionId, FFmpegSessionCompleteCallback? completeCallback) { + if (sessionId != null && completeCallback != null) { + ffmpegSessionCompleteCallbackMap[sessionId] = completeCallback; } } - static ExecuteCallback? getGlobalExecuteCallback() => _executeCallback; + static FFmpegSessionCompleteCallback? + getGlobalFFmpegSessionCompleteCallback() => + _ffmpegSessionCompleteCallback; - static void setGlobalExecuteCallback(ExecuteCallback? executeCallback) { - _executeCallback = executeCallback; + static void setGlobalFFmpegSessionCompleteCallback( + 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) { diff --git a/flutter/flutter/lib/src/ffmpeg_kit_flutter_initializer.dart b/flutter/flutter/lib/src/ffmpeg_kit_flutter_initializer.dart index ed8de92..a8d8628 100644 --- a/flutter/flutter/lib/src/ffmpeg_kit_flutter_initializer.dart +++ b/flutter/flutter/lib/src/ffmpeg_kit_flutter_initializer.dart @@ -19,16 +19,20 @@ import 'dart:io'; +import 'package:ffmpeg_kit_flutter/ffprobe_session.dart'; +import 'package:ffmpeg_kit_flutter/media_information_session.dart'; import 'package:ffmpeg_kit_flutter_platform_interface/ffmpeg_kit_flutter_platform_interface.dart'; import 'package:flutter/services.dart'; import '../arch_detect.dart'; -import '../execute_callback.dart'; import '../ffmpeg_kit_config.dart'; import '../ffmpeg_session.dart'; +import '../ffmpeg_session_complete_callback.dart'; +import '../ffprobe_session_complete_callback.dart'; import '../level.dart'; import '../log_callback.dart'; import '../log_redirection_strategy.dart'; +import '../media_information_session_complete_callback.dart'; import '../packages.dart'; import '../session.dart'; import '../statistics.dart'; @@ -59,8 +63,8 @@ class FFmpegKitInitializer { eventMap['FFmpegKitLogCallbackEvent']; final Map? statisticsEvent = eventMap['FFmpegKitStatisticsCallbackEvent']; - final Map? executeEvent = - eventMap['FFmpegKitExecuteCallbackEvent']; + final Map? completeEvent = + eventMap['FFmpegKitCompleteCallbackEvent']; if (logEvent != null) { _processLogCallbackEvent(logEvent); @@ -70,8 +74,8 @@ class FFmpegKitInitializer { _processStatisticsCallbackEvent(statisticsEvent); } - if (executeEvent != null) { - _processExecuteCallbackEvent(executeEvent); + if (completeEvent != null) { + _processCompleteCallbackEvent(completeEvent); } } } @@ -110,7 +114,7 @@ class FFmpegKitInitializer { // NOTIFY SESSION CALLBACK DEFINED logCallback(log); } on Exception catch (e, stack) { - print("Exception thrown inside session LogCallback block. $e"); + print("Exception thrown inside session log callback. $e"); print(stack); } } @@ -123,7 +127,7 @@ class FFmpegKitInitializer { // NOTIFY GLOBAL CALLBACK DEFINED globalLogCallbackFunction(log); } on Exception catch (e, stack) { - print("Exception thrown inside global LogCallback block. $e"); + print("Exception thrown inside global log callback. $e"); print(stack); } } @@ -185,7 +189,7 @@ class FFmpegKitInitializer { // NOTIFY SESSION CALLBACK DEFINED statisticsCallback(statistics); } on Exception catch (e, stack) { - print("Exception thrown inside session StatisticsCallback block. $e"); + print("Exception thrown inside session statistics callback. $e"); print(stack); } } @@ -197,37 +201,96 @@ class FFmpegKitInitializer { // NOTIFY GLOBAL CALLBACK DEFINED globalStatisticsCallbackFunction(statistics); } on Exception catch (e, stack) { - print("Exception thrown inside global StatisticsCallback block. $e"); + print("Exception thrown inside global statistics callback. $e"); print(stack); } } } - void _processExecuteCallbackEvent(Map event) { + void _processCompleteCallbackEvent(Map event) { final int sessionId = event["sessionId"]; 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) { - try { - // NOTIFY SESSION CALLBACK DEFINED - executeCallback(session); - } on Exception catch (e, stack) { - print("Exception thrown inside session ExecuteCallback block. $e"); - print(stack); - } - } + if (completeCallback != null) { + try { + // NOTIFY SESSION CALLBACK DEFINED + completeCallback(ffmpegSession); + } on Exception catch (e, stack) { + print("Exception thrown inside session complete callback. $e"); + print(stack); + } + } - final globalExecuteCallbackFunction = - FFmpegKitFactory.getGlobalExecuteCallback(); - if (globalExecuteCallbackFunction != null && session != null) { - try { - // NOTIFY GLOBAL CALLBACK DEFINED - globalExecuteCallbackFunction(session); - } on Exception catch (e, stack) { - print("Exception thrown inside global ExecuteCallback block. $e"); - print(stack); + final globalFFmpegSessionCompleteCallback = + FFmpegKitFactory.getGlobalFFmpegSessionCompleteCallback(); + if (globalFFmpegSessionCompleteCallback != null) { + try { + // NOTIFY GLOBAL CALLBACK DEFINED + globalFFmpegSessionCompleteCallback(ffmpegSession); + } on Exception catch (e, stack) { + print("Exception thrown inside global complete callback. $e"); + 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); + } + } } } }); diff --git a/flutter/flutter/lib/statistics_callback.dart b/flutter/flutter/lib/statistics_callback.dart index 9b0a01c..de988a6 100644 --- a/flutter/flutter/lib/statistics_callback.dart +++ b/flutter/flutter/lib/statistics_callback.dart @@ -19,5 +19,5 @@ 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); diff --git a/flutter/flutter/macos/Classes/FFmpegKitFlutterPlugin.m b/flutter/flutter/macos/Classes/FFmpegKitFlutterPlugin.m index d12bdf4..1618616 100644 --- a/flutter/flutter/macos/Classes/FFmpegKitFlutterPlugin.m +++ b/flutter/flutter/macos/Classes/FFmpegKitFlutterPlugin.m @@ -57,7 +57,7 @@ static int const SESSION_TYPE_MEDIA_INFORMATION = 3; // EVENTS static NSString *const EVENT_LOG_CALLBACK_EVENT = @"FFmpegKitLogCallbackEvent"; static NSString *const EVENT_STATISTICS_CALLBACK_EVENT = @"FFmpegKitStatisticsCallbackEvent"; -static NSString *const EVENT_EXECUTE_CALLBACK_EVENT = @"FFmpegKitExecuteCallbackEvent"; +static NSString *const EVENT_EXECUTE_CALLBACK_EVENT = @"FFmpegKitCompleteCallbackEvent"; // ARGUMENT NAMES static NSString *const ARGUMENT_SESSION_ID = @"sessionId"; 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 daf485b..24c42b1 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 @@ -364,9 +364,14 @@ abstract class FFmpegKitPlatform extends PlatformInterface { // FFprobeKit - Future?> ffprobeKitListSessions() async { + Future?> ffprobeKitListFFprobeSessions() async { throw UnimplementedError( - 'ffprobeKitListSessions() has not been implemented!'); + 'ffprobeKitListFFprobeSessions() has not been implemented!'); + } + + Future?> ffprobeKitListMediaInformationSessions() async { + throw UnimplementedError( + 'ffprobeKitListMediaInformationSessions() has not been implemented!'); } // MediaInformationJsonParser 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 7ec5914..88b435b 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 @@ -334,9 +334,13 @@ class MethodChannelFFmpegKit extends FFmpegKitPlatform { // FFprobeKit @override - Future?> ffprobeKitListSessions() async => + Future?> ffprobeKitListFFprobeSessions() async => _channel.invokeMethod>('getFFprobeSessions'); + @override + Future?> ffprobeKitListMediaInformationSessions() async => + _channel.invokeMethod>('getMediaInformationSessions'); + // MediaInformationJsonParser @override