diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegKit.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegKit.java index ccc32a6..7b9cafe 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegKit.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegKit.java @@ -269,7 +269,7 @@ public class FFmpegKit { * @param command string command * @return array of arguments */ - static String[] parseArguments(final String command) { + public static String[] parseArguments(final String command) { final List argumentList = new ArrayList<>(); StringBuilder currentArgument = new StringBuilder(); @@ -326,7 +326,7 @@ public class FFmpegKit { * @param arguments arguments * @return concatenated string containing all arguments */ - static String argumentsToString(final String[] arguments) { + public static String argumentsToString(final String[] arguments) { if (arguments == null) { return "null"; } diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegKitConfig.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegKitConfig.java index 019ac4c..3bd70cb 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegKitConfig.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegKitConfig.java @@ -664,6 +664,8 @@ public class FFmpegKitConfig { * @param ffmpegSession FFmpeg session which includes command options/arguments */ public static void asyncFFmpegExecute(final FFmpegSession ffmpegSession) { + addSession(ffmpegSession); + AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(ffmpegSession); Future future = asyncExecutorService.submit(asyncFFmpegExecuteTask); ffmpegSession.setFuture(future); @@ -676,6 +678,8 @@ public class FFmpegKitConfig { * @param executorService executor service that will be used to run this asynchronous operation */ public static void asyncFFmpegExecute(final FFmpegSession ffmpegSession, final ExecutorService executorService) { + addSession(ffmpegSession); + AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(ffmpegSession); Future future = executorService.submit(asyncFFmpegExecuteTask); ffmpegSession.setFuture(future); @@ -687,6 +691,8 @@ public class FFmpegKitConfig { * @param ffprobeSession FFprobe session which includes command options/arguments */ public static void asyncFFprobeExecute(final FFprobeSession ffprobeSession) { + addSession(ffprobeSession); + AsyncFFprobeExecuteTask asyncFFmpegExecuteTask = new AsyncFFprobeExecuteTask(ffprobeSession); Future future = asyncExecutorService.submit(asyncFFmpegExecuteTask); ffprobeSession.setFuture(future); @@ -699,6 +705,8 @@ public class FFmpegKitConfig { * @param executorService executor service that will be used to run this asynchronous operation */ public static void asyncFFprobeExecute(final FFprobeSession ffprobeSession, final ExecutorService executorService) { + addSession(ffprobeSession); + AsyncFFprobeExecuteTask asyncFFmpegExecuteTask = new AsyncFFprobeExecuteTask(ffprobeSession); Future future = executorService.submit(asyncFFmpegExecuteTask); ffprobeSession.setFuture(future); @@ -711,6 +719,8 @@ public class FFmpegKitConfig { * @param waitTimeout max time to wait until media information is transmitted */ public static void asyncGetMediaInformationExecute(final MediaInformationSession mediaInformationSession, final int waitTimeout) { + addSession(mediaInformationSession); + AsyncGetMediaInformationTask asyncGetMediaInformationTask = new AsyncGetMediaInformationTask(mediaInformationSession, waitTimeout); Future future = asyncExecutorService.submit(asyncGetMediaInformationTask); mediaInformationSession.setFuture(future); @@ -724,6 +734,8 @@ public class FFmpegKitConfig { * @param waitTimeout max time to wait until media information is transmitted */ public static void asyncGetMediaInformationExecute(final MediaInformationSession mediaInformationSession, final ExecutorService executorService, final int waitTimeout) { + addSession(mediaInformationSession); + AsyncGetMediaInformationTask asyncGetMediaInformationTask = new AsyncGetMediaInformationTask(mediaInformationSession, waitTimeout); Future future = executorService.submit(asyncGetMediaInformationTask); mediaInformationSession.setFuture(future); @@ -936,12 +948,20 @@ public class FFmpegKitConfig { */ static void addSession(final Session session) { synchronized (sessionHistoryLock) { - sessionHistoryMap.put(session.getSessionId(), session); - sessionHistoryList.add(session); - if (sessionHistoryList.size() > sessionHistorySize) { - try { - sessionHistoryList.remove(0); - } catch (final IndexOutOfBoundsException ignored) { + + /* + * ASYNC SESSIONS CALL THIS METHOD TWICE + * THIS CHECK PREVENTS ADDING THE SAME SESSION TWICE + */ + final boolean sessionAlreadyAdded = sessionHistoryMap.containsKey(session.getSessionId()); + if (!sessionAlreadyAdded) { + sessionHistoryMap.put(session.getSessionId(), session); + sessionHistoryList.add(session); + if (sessionHistoryList.size() > sessionHistorySize) { + try { + sessionHistoryList.remove(0); + } catch (final IndexOutOfBoundsException ignored) { + } } } } diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFprobeSession.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFprobeSession.java index 84be6cb..50a16d9 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFprobeSession.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFprobeSession.java @@ -50,9 +50,9 @@ public class FFprobeSession extends AbstractSession implements Session { * @param executeCallback session specific execute callback function * @param logCallback session specific log callback function */ - FFprobeSession(final String[] arguments, - final ExecuteCallback executeCallback, - final LogCallback logCallback) { + public FFprobeSession(final String[] arguments, + final ExecuteCallback executeCallback, + final LogCallback logCallback) { this(arguments, executeCallback, logCallback, FFmpegKitConfig.getLogRedirectionStrategy()); } @@ -64,10 +64,10 @@ public class FFprobeSession extends AbstractSession implements Session { * @param logCallback session specific log callback function * @param logRedirectionStrategy session specific log redirection strategy */ - FFprobeSession(final String[] arguments, - final ExecuteCallback executeCallback, - final LogCallback logCallback, - final LogRedirectionStrategy logRedirectionStrategy) { + public FFprobeSession(final String[] arguments, + final ExecuteCallback executeCallback, + final LogCallback logCallback, + final LogRedirectionStrategy logRedirectionStrategy) { super(arguments, executeCallback, logCallback, logRedirectionStrategy); } diff --git a/apple/src/AbstractSession.m b/apple/src/AbstractSession.m index 8fadf9e..2663de0 100644 --- a/apple/src/AbstractSession.m +++ b/apple/src/AbstractSession.m @@ -52,7 +52,7 @@ static AtomicLong *sessionIdGenerator = nil; - (instancetype)init:(NSArray*)arguments withExecuteCallback:(ExecuteCallback)executeCallback withLogCallback:(LogCallback)logCallback withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy { self = [super init]; if (self) { - _sessionId = [sessionIdGenerator incrementAndGet]; + _sessionId = [sessionIdGenerator getAndIncrement]; _executeCallback = executeCallback; _logCallback = logCallback; _createTime = [NSDate date]; @@ -150,7 +150,7 @@ static AtomicLong *sessionIdGenerator = nil; NSLog(@"getAllLogsAsStringWithTimeout was called to return all logs but there are still logs being transmitted for session id %ld.", _sessionId); } - return [self getAllLogsAsString]; + return [self getLogsAsString]; } - (NSString*)getAllLogsAsString { diff --git a/apple/src/AtomicLong.m b/apple/src/AtomicLong.m index 2bb0796..e87c03a 100644 --- a/apple/src/AtomicLong.m +++ b/apple/src/AtomicLong.m @@ -17,48 +17,28 @@ * along with FFmpegKit. If not, see . */ +#import #import "AtomicLong.h" -@interface AtomicLong() - -@property (strong) NSRecursiveLock* lock; - -@end - @implementation AtomicLong { - long _value; + atomic_int _value; } - (instancetype)initWithValue:(long)value { self = [super init]; if (self) { - _value = value; - _lock = [[NSRecursiveLock alloc] init]; + atomic_init(&_value, value); } return self; } - (long)incrementAndGet { - long returnValue; - - [self.lock lock]; - _value += 1; - returnValue = _value; - [self.lock unlock]; - - return returnValue; + return (long)atomic_fetch_add(&_value, 1) + 1; } - (long)getAndIncrement { - long returnValue; - - [self.lock lock]; - returnValue = _value; - _value += 1; - [self.lock unlock]; - - return returnValue; + return (long)atomic_fetch_add(&_value, 1); } @end diff --git a/apple/src/FFmpegKit.m b/apple/src/FFmpegKit.m index 3621d5e..46f25e0 100644 --- a/apple/src/FFmpegKit.m +++ b/apple/src/FFmpegKit.m @@ -27,6 +27,8 @@ @implementation FFmpegKit + (void)initialize { + NSLog(@"Loading ffmpeg-kit.\n"); + [FFmpegKitConfig class]; NSLog(@"Loaded ffmpeg-kit-%@-%@-%@-%@\n", [Packages getPackageName], [ArchDetect getArch], [FFmpegKitConfig getVersion], [FFmpegKitConfig getBuildDate]); diff --git a/apple/src/FFmpegKitConfig.h b/apple/src/FFmpegKitConfig.h index c3ebeaa..c4da16a 100644 --- a/apple/src/FFmpegKitConfig.h +++ b/apple/src/FFmpegKitConfig.h @@ -373,6 +373,14 @@ typedef NS_ENUM(NSUInteger, Signal) { */ + (int)messagesInTransmit:(long)sessionId; +/** + * Converts session state to string. + * + * @param state session state + * @return string value + */ ++ (NSString*)sessionStateToString:(SessionState)state; + @end #endif // FFMPEG_KIT_CONFIG_H diff --git a/apple/src/FFmpegKitConfig.m b/apple/src/FFmpegKitConfig.m index c361023..8c9bef2 100644 --- a/apple/src/FFmpegKitConfig.m +++ b/apple/src/FFmpegKitConfig.m @@ -894,6 +894,8 @@ int executeFFprobe(long sessionId, NSArray* arguments) { } + (void)asyncFFmpegExecute:(FFmpegSession*)ffmpegSession onDispatchQueue:(dispatch_queue_t)queue { + [FFmpegKitConfig addSession:ffmpegSession]; + dispatch_async(queue, ^{ [FFmpegKitConfig ffmpegExecute:ffmpegSession]; ExecuteCallback globalExecuteCallback = [FFmpegKitConfig getExecuteCallback]; @@ -913,6 +915,8 @@ int executeFFprobe(long sessionId, NSArray* arguments) { } + (void)asyncFFprobeExecute:(FFprobeSession*)ffprobeSession onDispatchQueue:(dispatch_queue_t)queue { + [FFmpegKitConfig addSession:ffprobeSession]; + dispatch_async(queue, ^{ [FFmpegKitConfig ffprobeExecute:ffprobeSession]; ExecuteCallback globalExecuteCallback = [FFmpegKitConfig getExecuteCallback]; @@ -932,6 +936,8 @@ int executeFFprobe(long sessionId, NSArray* arguments) { } + (void)asyncGetMediaInformationExecute:(MediaInformationSession*)mediaInformationSession onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout { + [FFmpegKitConfig addSession:mediaInformationSession]; + dispatch_async(queue, ^{ [FFmpegKitConfig getMediaInformationExecute:mediaInformationSession withTimeout:waitTimeout]; ExecuteCallback globalExecuteCallback = [FFmpegKitConfig getExecuteCallback]; @@ -1003,19 +1009,27 @@ int executeFFprobe(long sessionId, NSArray* arguments) { } + (void)addSession:(id)session { + NSNumber* sessionIdNumber = [NSNumber numberWithLong:[session getSessionId]]; + [sessionHistoryLock lock]; - [sessionHistoryMap setObject:session forKey:[NSNumber numberWithLong:[session getSessionId]]]; - [sessionHistoryList addObject:session]; - if ([sessionHistoryList count] > sessionHistorySize) { - id first = [sessionHistoryList firstObject]; - if (first != nil) { - NSNumber* key = [NSNumber numberWithLong:[first getSessionId]]; - [sessionHistoryList removeObject:key]; - [sessionHistoryMap removeObjectForKey:key]; + /* + * ASYNC SESSIONS CALL THIS METHOD TWICE + * THIS CHECK PREVENTS ADDING THE SAME SESSION TWICE + */ + if ([sessionHistoryMap objectForKey:sessionIdNumber] == nil) { + [sessionHistoryMap setObject:session forKey:sessionIdNumber]; + [sessionHistoryList addObject:session]; + if ([sessionHistoryList count] > sessionHistorySize) { + id first = [sessionHistoryList firstObject]; + if (first != nil) { + NSNumber* key = [NSNumber numberWithLong:[first getSessionId]]; + [sessionHistoryList removeObject:key]; + [sessionHistoryMap removeObjectForKey:key]; + } } } - + [sessionHistoryLock unlock]; } @@ -1130,4 +1144,14 @@ int executeFFprobe(long sessionId, NSArray* arguments) { return atomic_load(&sessionInTransitMessageCountMap[sessionId % SESSION_MAP_SIZE]); } ++ (NSString*)sessionStateToString:(SessionState)state { + switch (state) { + case SessionStateCreated: return @"CREATED"; + case SessionStateRunning: return @"RUNNING"; + case SessionStateFailed: return @"FAILED"; + case SessionStateCompleted: return @"COMPLETED"; + default: return @""; + } +} + @end diff --git a/apple/src/FFmpegSession.m b/apple/src/FFmpegSession.m index c4b381e..b274125 100644 --- a/apple/src/FFmpegSession.m +++ b/apple/src/FFmpegSession.m @@ -29,6 +29,10 @@ NSRecursiveLock* _statisticsLock; } ++ (void)initialize { + // EMPTY INITIALIZE +} + - (instancetype)init:(NSArray*)arguments { self = [super init:arguments withExecuteCallback:nil withLogCallback:nil withLogRedirectionStrategy:[FFmpegKitConfig getLogRedirectionStrategy]]; diff --git a/apple/src/FFprobeSession.m b/apple/src/FFprobeSession.m index 391b2d9..f6c1582 100644 --- a/apple/src/FFprobeSession.m +++ b/apple/src/FFprobeSession.m @@ -31,6 +31,10 @@ return self; } ++ (void)initialize { + // EMPTY INITIALIZE +} + - (instancetype)init:(NSArray*)arguments withExecuteCallback:(ExecuteCallback)executeCallback { self = [super init:arguments withExecuteCallback:executeCallback withLogCallback:nil withLogRedirectionStrategy:[FFmpegKitConfig getLogRedirectionStrategy]]; diff --git a/apple/src/MediaInformationSession.m b/apple/src/MediaInformationSession.m index 0876329..da59e42 100644 --- a/apple/src/MediaInformationSession.m +++ b/apple/src/MediaInformationSession.m @@ -26,6 +26,10 @@ MediaInformation* _mediaInformation; } ++ (void)initialize { + // EMPTY INITIALIZE +} + - (instancetype)init:(NSArray*)arguments { self = [super init:arguments withExecuteCallback:nil withLogCallback:nil withLogRedirectionStrategy:LogRedirectionStrategyNeverPrintLogs]; diff --git a/apple/src/ReturnCode.m b/apple/src/ReturnCode.m index 3f65732..c2e6c3c 100644 --- a/apple/src/ReturnCode.m +++ b/apple/src/ReturnCode.m @@ -56,4 +56,8 @@ return (_value == ReturnCodeCancel); } +- (NSString*)description { + return [NSString stringWithFormat:@"%d", _value]; +} + @end diff --git a/scripts/apple/ffmpeg.sh b/scripts/apple/ffmpeg.sh index f74310f..d93a06d 100755 --- a/scripts/apple/ffmpeg.sh +++ b/scripts/apple/ffmpeg.sh @@ -89,14 +89,7 @@ x86-64) TARGET_CPU="x86_64" TARGET_ARCH="x86_64" ASM_OPTIONS=" --disable-neon --disable-asm" - case $FFMPEG_KIT_BUILD_TYPE in - macos) - BITCODE_FLAGS="-fembed-bitcode -Wc,-fembed-bitcode" - ;; - *) - BITCODE_FLAGS="" - ;; - esac + BITCODE_FLAGS="" ;; x86-64-mac-catalyst) TARGET_CPU="x86_64" diff --git a/scripts/apple/sdl.sh b/scripts/apple/sdl.sh index 08033aa..e63ac94 100755 --- a/scripts/apple/sdl.sh +++ b/scripts/apple/sdl.sh @@ -4,7 +4,7 @@ ASM_OPTIONS="" case ${ARCH} in *-mac-catalyst) - ASM_OPTIONS="--disable-video-cocoa --disable-render-metal --disable-haptic --disable-diskaudio --disable-joystick" + ASM_OPTIONS="--disable-video-cocoa --disable-render-metal --disable-diskaudio" ;; esac @@ -33,6 +33,8 @@ overwrite_file "${FFMPEG_KIT_TMPDIR}"/source/config/config.sub "${BASEDIR}"/src/ --enable-static \ --disable-shared \ --disable-video-opengl \ + --disable-joystick \ + --disable-haptic \ ${ASM_OPTIONS} \ --host="${HOST}" || return 1