From 4680721cef462c328931d0933282a2d9bd1845dc Mon Sep 17 00:00:00 2001 From: Taner Sener Date: Sun, 31 Jan 2021 15:56:14 +0000 Subject: [PATCH] refactor api --- .../src/main/cpp/ffmpegkit.c | 133 +- .../src/main/cpp/ffmpegkit_exception.c | 3 +- .../src/main/cpp/ffprobekit.c | 16 +- .../src/main/cpp/saf_wrapper.c | 36 +- .../java/com/arthenica/ffmpegkit/Abi.java | 12 +- .../com/arthenica/ffmpegkit/AbiDetect.java | 36 +- .../arthenica/ffmpegkit/AbstractSession.java | 241 ++- .../ffmpegkit/AsyncFFmpegExecuteTask.java | 2 +- .../ffmpegkit/AsyncFFprobeExecuteTask.java | 4 +- .../AsyncGetMediaInformationTask.java | 4 +- .../arthenica/ffmpegkit/CameraSupport.java | 10 +- .../arthenica/ffmpegkit/ExecuteCallback.java | 22 +- .../com/arthenica/ffmpegkit/FFmpegKit.java | 120 +- .../arthenica/ffmpegkit/FFmpegKitConfig.java | 476 +++--- .../arthenica/ffmpegkit/FFmpegSession.java | 150 +- .../com/arthenica/ffmpegkit/FFprobeKit.java | 338 +++-- .../arthenica/ffmpegkit/FFprobeSession.java | 76 +- .../java/com/arthenica/ffmpegkit/Level.java | 6 +- .../java/com/arthenica/ffmpegkit/Log.java | 2 +- .../com/arthenica/ffmpegkit/LogCallback.java | 2 +- ...r.java => MediaInformationJsonParser.java} | 10 +- .../ffmpegkit/MediaInformationSession.java | 54 +- .../com/arthenica/ffmpegkit/NativeLoader.java | 183 +++ .../com/arthenica/ffmpegkit/Packages.java | 48 +- .../com/arthenica/ffmpegkit/ReturnCode.java | 29 +- .../java/com/arthenica/ffmpegkit/Session.java | 193 ++- .../com/arthenica/ffmpegkit/Statistics.java | 11 - .../ffmpegkit/StatisticsCallback.java | 2 +- .../ffmpegkit/StreamInformation.java | 36 +- .../ffmpegkit/AbstractSessionTest.java | 44 - .../arthenica/ffmpegkit/FFmpegKitTest.java | 12 +- .../ffmpegkit/FFmpegSessionTest.java | 350 +++++ .../ffmpegkit/FFprobeSessionTest.java | 334 +++++ android/settings.gradle | 2 - apple/Makefile.in | 6 +- apple/aclocal.m4 | 13 +- apple/config.guess | 221 ++- apple/config.sub | 59 +- apple/configure | 7 +- apple/install-sh | 148 +- apple/src/AbstractSession.h | 56 + apple/src/AbstractSession.m | 235 +++ apple/src/ArchDetect.h | 27 +- apple/src/ArchDetect.m | 48 +- apple/src/AtomicLong.h | 11 +- apple/src/AtomicLong.m | 35 +- apple/src/ExecuteDelegate.h | 37 +- apple/src/FFmpegExecution.h | 35 - apple/src/FFmpegExecution.m | 52 - apple/src/FFmpegKit.h | 179 ++- apple/src/FFmpegKit.m | 252 +--- apple/src/FFmpegKitConfig.h | 362 +++-- apple/src/FFmpegKitConfig.m | 1334 +++++++++-------- apple/src/FFmpegSession.h | 119 ++ apple/src/FFmpegSession.m | 137 ++ apple/src/FFprobeKit.h | 228 ++- apple/src/FFprobeKit.m | 200 +-- apple/src/FFprobeSession.h | 67 + apple/src/FFprobeSession.m | 64 + apple/src/Level.h | 85 ++ apple/src/Log.h | 40 + apple/src/Log.m | 51 + apple/src/LogDelegate.h | 19 +- apple/src/LogRedirectionStrategy.h | 31 + apple/src/Makefile.am | 42 +- apple/src/Makefile.in | 243 ++- apple/src/MediaInformation.h | 19 +- apple/src/MediaInformation.m | 40 +- ...nParser.h => MediaInformationJsonParser.h} | 25 +- ...nParser.m => MediaInformationJsonParser.m} | 4 +- apple/src/MediaInformationSession.h | 74 + apple/src/MediaInformationSession.m | 59 + apple/src/Packages.h | 46 + apple/src/Packages.m | 263 ++++ apple/src/ReturnCode.h | 44 + apple/src/ReturnCode.m | 51 + apple/src/Session.h | 255 ++++ apple/src/SessionState.h | 30 + apple/src/Statistics.h | 17 +- apple/src/Statistics.m | 99 +- apple/src/StatisticsDelegate.h | 17 +- apple/src/StreamInformation.h | 26 +- apple/src/StreamInformation.m | 76 +- apple/src/fftools_ffmpeg.c | 18 +- ios.sh | 4 +- macos.sh | 4 +- tvos.sh | 4 +- 87 files changed, 5928 insertions(+), 2687 deletions(-) rename android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/{MediaInformationParser.java => MediaInformationJsonParser.java} (89%) create mode 100644 android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/NativeLoader.java delete mode 100644 android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/AbstractSessionTest.java create mode 100644 android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFmpegSessionTest.java create mode 100644 android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFprobeSessionTest.java create mode 100644 apple/src/AbstractSession.h create mode 100644 apple/src/AbstractSession.m delete mode 100644 apple/src/FFmpegExecution.h delete mode 100644 apple/src/FFmpegExecution.m create mode 100644 apple/src/FFmpegSession.h create mode 100644 apple/src/FFmpegSession.m create mode 100644 apple/src/FFprobeSession.h create mode 100644 apple/src/FFprobeSession.m create mode 100644 apple/src/Level.h create mode 100644 apple/src/Log.h create mode 100644 apple/src/Log.m create mode 100644 apple/src/LogRedirectionStrategy.h rename apple/src/{MediaInformationParser.h => MediaInformationJsonParser.h} (53%) rename apple/src/{MediaInformationParser.m => MediaInformationJsonParser.m} (95%) create mode 100644 apple/src/MediaInformationSession.h create mode 100644 apple/src/MediaInformationSession.m create mode 100644 apple/src/Packages.h create mode 100644 apple/src/Packages.m create mode 100644 apple/src/ReturnCode.h create mode 100644 apple/src/ReturnCode.m create mode 100644 apple/src/Session.h create mode 100644 apple/src/SessionState.h diff --git a/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.c b/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.c index 991a91b..c99b141 100644 --- a/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.c +++ b/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.c @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -28,6 +29,9 @@ #include "ffmpegkit.h" #include "ffprobekit.h" +# define LogType 1 +# define StatisticsType 2 + /** Callback data structure */ struct CallbackData { int type; // 1 (log callback) or 2 (statistics callback) @@ -47,11 +51,10 @@ struct CallbackData { struct CallbackData *next; }; -/** Session map variables */ +/** Session control variables */ const int SESSION_MAP_SIZE = 1000; -static volatile int sessionMap[SESSION_MAP_SIZE]; -static volatile int sessionInTransitMessageCountMap[SESSION_MAP_SIZE]; -static pthread_mutex_t sessionMapMutex; +static atomic_short sessionMap[SESSION_MAP_SIZE]; +static atomic_int sessionInTransitMessageCountMap[SESSION_MAP_SIZE]; /** Redirection control variables */ static pthread_mutex_t lockMutex; @@ -215,15 +218,6 @@ void monitorInit() { pthread_condattr_destroy(&cattributes); } -void sessionMapLockInit() { - pthread_mutexattr_t attributes; - pthread_mutexattr_init(&attributes); - pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP); - - pthread_mutex_init(&sessionMapMutex, &attributes); - pthread_mutexattr_destroy(&attributes); -} - void mutexUnInit() { pthread_mutex_destroy(&lockMutex); } @@ -233,26 +227,14 @@ void monitorUnInit() { pthread_cond_destroy(&monitorCondition); } -void sessionMapLockUnInit() { - pthread_mutex_destroy(&sessionMapMutex); -} - void mutexLock() { pthread_mutex_lock(&lockMutex); } -void sessionMapLock() { - pthread_mutex_lock(&sessionMapMutex); -} - void mutexUnlock() { pthread_mutex_unlock(&lockMutex); } -void sessionMapUnlock() { - pthread_mutex_unlock(&sessionMapMutex); -} - void monitorWait(int milliSeconds) { struct timeval tp; struct timespec ts; @@ -291,7 +273,7 @@ void logCallbackDataAdd(int level, AVBPrint *data) { // CREATE DATA STRUCT FIRST struct CallbackData *newData = (struct CallbackData*)av_malloc(sizeof(struct CallbackData)); - newData->type = 1; + newData->type = LogType; newData->sessionId = sessionId; newData->logLevel = level; av_bprint_init(&newData->logData, 0, AV_BPRINT_SIZE_UNLIMITED); @@ -316,12 +298,11 @@ void logCallbackDataAdd(int level, AVBPrint *data) { callbackDataTail = newData; } - int key = sessionId % SESSION_MAP_SIZE; - sessionInTransitMessageCountMap[key] += 1; - mutexUnlock(); monitorNotify(); + + atomic_fetch_add(&sessionInTransitMessageCountMap[sessionId % SESSION_MAP_SIZE], 1); } /** @@ -331,7 +312,7 @@ void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_ // CREATE DATA STRUCT FIRST struct CallbackData *newData = (struct CallbackData*)av_malloc(sizeof(struct CallbackData)); - newData->type = 2; + newData->type = StatisticsType; newData->sessionId = sessionId; newData->statisticsFrameNumber = frameNumber; newData->statisticsFps = fps; @@ -361,12 +342,11 @@ void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_ callbackDataTail = newData; } - int key = sessionId % SESSION_MAP_SIZE; - sessionInTransitMessageCountMap[key] += 1; - mutexUnlock(); monitorNotify(); + + atomic_fetch_add(&sessionInTransitMessageCountMap[sessionId % SESSION_MAP_SIZE], 1); } /** @@ -375,12 +355,7 @@ void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_ * @param id session id */ void addSession(long id) { - sessionMapLock(); - - int key = id % SESSION_MAP_SIZE; - sessionMap[key] = 1; - - sessionMapUnlock(); + atomic_store(&sessionMap[id % SESSION_MAP_SIZE], 1); } /** @@ -421,12 +396,7 @@ struct CallbackData *callbackDataRemove() { * @param id session id */ void removeSession(long id) { - sessionMapLock(); - - int key = id % SESSION_MAP_SIZE; - sessionMap[key] = 0; - - sessionMapUnlock(); + atomic_store(&sessionMap[id % SESSION_MAP_SIZE], 0); } /** @@ -435,12 +405,7 @@ void removeSession(long id) { * @param id session id */ void cancelSession(long id) { - sessionMapLock(); - - int key = id % SESSION_MAP_SIZE; - sessionMap[key] = 2; - - sessionMapUnlock(); + atomic_store(&sessionMap[id % SESSION_MAP_SIZE], 2); } /** @@ -450,18 +415,11 @@ void cancelSession(long id) { * @return 1 if exists, false otherwise */ int cancelRequested(long id) { - int found = 0; - - sessionMapLock(); - - int key = id % SESSION_MAP_SIZE; - if (sessionMap[key] == 2) { - found = 1; + if (atomic_load(&sessionMap[id % SESSION_MAP_SIZE]) == 2) { + return 1; + } else { + return 0; } - - sessionMapUnlock(); - - return found; } /** @@ -470,12 +428,7 @@ int cancelRequested(long id) { * @param id session id */ void resetMessagesInTransmit(long id) { - mutexLock(); - - int key = id % SESSION_MAP_SIZE; - sessionInTransitMessageCountMap[key] = 0; - - mutexUnlock(); + atomic_store(&sessionInTransitMessageCountMap[id % SESSION_MAP_SIZE], 0); } /** @@ -556,13 +509,13 @@ void *callbackThreadFunction() { } } - LOGD("Callback thread started.\n"); + LOGD("Async callback block started.\n"); while(redirectionEnabled) { struct CallbackData *callbackData = callbackDataRemove(); if (callbackData != NULL) { - if (callbackData->type == 1) { + if (callbackData->type == LogType) { // LOG CALLBACK @@ -588,8 +541,7 @@ void *callbackThreadFunction() { } - int key = callbackData->sessionId % SESSION_MAP_SIZE; - sessionInTransitMessageCountMap[key] -= 1; + atomic_fetch_sub(&sessionInTransitMessageCountMap[callbackData->sessionId % SESSION_MAP_SIZE], 1); // CLEAN STRUCT callbackData->next = NULL; @@ -602,7 +554,7 @@ void *callbackThreadFunction() { (*globalVm)->DetachCurrentThread(globalVm); - LOGD("Callback thread stopped.\n"); + LOGD("Async callback block stopped.\n"); return NULL; } @@ -678,18 +630,18 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) { configClass = (jclass) ((*env)->NewGlobalRef(env, localConfigClass)); stringClass = (jclass) ((*env)->NewGlobalRef(env, localStringClass)); - redirectionEnabled = 0; - callbackDataHead = NULL; callbackDataTail = NULL; for(int i = 0; iGetArrayLength(env, stringArray); argumentCount = programArgumentCount + 1; @@ -820,8 +772,8 @@ JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpeg argv[0] = (char *)av_malloc(sizeof(char) * (strlen(LIB_NAME) + 1)); strcpy(argv[0], LIB_NAME); - // PREPARE - if (stringArray != NULL) { + // PREPARE ARRAY ELEMENTS + if (stringArray) { for (int i = 0; i < (argumentCount - 1); i++) { tempArray[i] = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i); if (tempArray[i] != NULL) { @@ -830,20 +782,20 @@ JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpeg } } - // REGISTER THE ID BEFORE STARTING THE EXECUTION + // REGISTER THE ID BEFORE STARTING THE SESSION sessionId = (long) id; addSession((long) id); resetMessagesInTransmit(sessionId); // RUN - int retCode = ffmpeg_execute(argumentCount, argv); + int returnCode = ffmpeg_execute(argumentCount, argv); // ALWAYS REMOVE THE ID FROM THE MAP removeSession((long) id); // CLEANUP - if (tempArray != NULL) { + if (tempArray) { for (int i = 0; i < (argumentCount - 1); i++) { (*env)->ReleaseStringUTFChars(env, tempArray[i], argv[i + 1]); } @@ -853,7 +805,7 @@ JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpeg av_free(argv[0]); av_free(argv); - return retCode; + return returnCode; } /** @@ -944,12 +896,5 @@ JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNative * @param id session id */ JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_messagesInTransmit(JNIEnv *env, jclass object, jlong id) { - mutexLock(); - - int key = id % SESSION_MAP_SIZE; - int count = sessionInTransitMessageCountMap[key]; - - mutexUnlock(); - - return count; + return atomic_load(&sessionInTransitMessageCountMap[id % SESSION_MAP_SIZE]); } diff --git a/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit_exception.c b/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit_exception.c index 722fb96..a13a9ab 100644 --- a/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit_exception.c +++ b/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit_exception.c @@ -17,8 +17,7 @@ * along with FFmpegKit. If not, see . */ -#include -#include +#include "ffmpegkit_exception.h" /** Holds information to implement exception handling. */ __thread jmp_buf ex_buf__; diff --git a/android/ffmpeg-kit-android-lib/src/main/cpp/ffprobekit.c b/android/ffmpeg-kit-android-lib/src/main/cpp/ffprobekit.c index 5097a6c..57d6ee6 100644 --- a/android/ffmpeg-kit-android-lib/src/main/cpp/ffprobekit.c +++ b/android/ffmpeg-kit-android-lib/src/main/cpp/ffprobekit.c @@ -49,10 +49,10 @@ JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprob int argumentCount = 1; char **argv = NULL; - // SETS DEFAULT LOG LEVEL BEFORE STARTING A NEW EXECUTION + // SETS DEFAULT LOG LEVEL BEFORE STARTING A NEW RUN av_log_set_level(configuredLogLevel); - if (stringArray != NULL) { + if (stringArray) { int programArgumentCount = (*env)->GetArrayLength(env, stringArray); argumentCount = programArgumentCount + 1; @@ -67,8 +67,8 @@ JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprob argv[0] = (char *)av_malloc(sizeof(char) * (strlen(LIB_NAME) + 1)); strcpy(argv[0], LIB_NAME); - // PREPARE - if (stringArray != NULL) { + // PREPARE ARRAY ELEMENTS + if (stringArray) { for (int i = 0; i < (argumentCount - 1); i++) { tempArray[i] = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i); if (tempArray[i] != NULL) { @@ -77,20 +77,20 @@ JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprob } } - // REGISTER THE ID BEFORE STARTING THE EXECUTION + // REGISTER THE ID BEFORE STARTING THE SESSION sessionId = (long) id; addSession((long) id); resetMessagesInTransmit(sessionId); // RUN - int retCode = ffprobe_execute(argumentCount, argv); + int returnCode = ffprobe_execute(argumentCount, argv); // ALWAYS REMOVE THE ID FROM THE MAP removeSession((long) id); // CLEANUP - if (tempArray != NULL) { + if (tempArray) { for (int i = 0; i < (argumentCount - 1); i++) { (*env)->ReleaseStringUTFChars(env, tempArray[i], argv[i + 1]); } @@ -100,5 +100,5 @@ JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprob av_free(argv[0]); av_free(argv); - return retCode; + return returnCode; } diff --git a/android/ffmpeg-kit-android-lib/src/main/cpp/saf_wrapper.c b/android/ffmpeg-kit-android-lib/src/main/cpp/saf_wrapper.c index 73144cb..68b0c69 100644 --- a/android/ffmpeg-kit-android-lib/src/main/cpp/saf_wrapper.c +++ b/android/ffmpeg-kit-android-lib/src/main/cpp/saf_wrapper.c @@ -38,13 +38,11 @@ void closeParcelFileDescriptor(int fd); #undef avformat_open_input static int fd_read_packet(void* opaque, uint8_t* buf, int buf_size) { - int *fd = opaque; - return read(*fd, buf, buf_size); + return read(*(int*)opaque, buf, buf_size); } static int fd_write_packet(void* opaque, uint8_t* buf, int buf_size) { - int *fd = opaque; - return write(*fd, buf, buf_size); + return write(*(int*)opaque, buf, buf_size); } static int64_t fd_seek(void *opaque, int64_t offset, int whence) { @@ -70,31 +68,36 @@ static int64_t fd_seek(void *opaque, int64_t offset, int whence) { * returns NULL if the filename is not of expected format (e.g. 'saf:72/video.md4') */ static AVIOContext *create_fd_avio_context(const char *filename, int flags) { - int *fd = av_mallocz(sizeof(int)); - *fd = -1; - const char *fd_ptr = NULL; + int fd = -1; + const char* fd_ptr = NULL; + if (av_strstart(filename, "saf:", &fd_ptr)) { char *final; - *fd = strtol(fd_ptr, &final, 10); + fd = strtol(fd_ptr, &final, 10); if (fd_ptr == final) { /* No digits found */ - *fd = -1; + fd = -1; } } - if (*fd >= 0) { + if (fd >= 0) { + int *opaque = av_mallocz(sizeof(int)); + *opaque = fd; int write_flag = flags & AVIO_FLAG_WRITE ? 1 : 0; - return avio_alloc_context(av_malloc(4096), 4096, write_flag, fd, fd_read_packet, write_flag ? fd_write_packet : NULL, fd_seek); + return avio_alloc_context(av_malloc(4096), 4096, write_flag, opaque, fd_read_packet, write_flag ? fd_write_packet : NULL, fd_seek); } + return NULL; } static void close_fd_avio_context(AVIOContext *ctx) { - if (fd_seek(ctx->opaque, 0, AVSEEK_SIZE) >= 0) { - int *fd = ctx->opaque; - closeParcelFileDescriptor(*fd); - av_freep(&fd); + if (ctx) { + if (fd_seek(ctx->opaque, 0, AVSEEK_SIZE) >= 0) { + int *fd = ctx->opaque; + closeParcelFileDescriptor(*fd); + av_freep(&fd); + } + ctx->opaque = NULL; } - ctx->opaque = NULL; } int android_avformat_open_input(AVFormatContext **ps, const char *filename, @@ -115,6 +118,7 @@ int android_avio_open2(AVIOContext **s, const char *filename, int flags, *s = fd_context; return 0; } + return avio_open2(s, filename, flags, int_cb, options); } diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Abi.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Abi.java index a0c8688..5cd9126 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Abi.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Abi.java @@ -20,9 +20,7 @@ package com.arthenica.ffmpegkit; /** - *

Enumeration type for Android ABIs. - * - * @author Taner Sener + *

Enumeration for Android ABIs. */ public enum Abi { @@ -64,10 +62,10 @@ public enum Abi { private final String name; /** - *

Returns enumeration defined by ABI name. + *

Returns the enumeration defined for the given ABI name. * * @param abiName ABI name - * @return enumeration defined by ABI name + * @return enumeration defined for the ABI name */ public static Abi from(final String abiName) { if (abiName == null) { @@ -90,9 +88,9 @@ public enum Abi { } /** - * Returns ABI name as defined in Android NDK documentation. + * Returns the ABI name. * - * @return ABI name + * @return ABI name as defined in Android NDK documentation */ public String getName() { return name; diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AbiDetect.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AbiDetect.java index 08b9a8d..c2e0010 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AbiDetect.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AbiDetect.java @@ -20,18 +20,19 @@ package com.arthenica.ffmpegkit; /** - *

Detects running ABI name using Google cpu-features library. + *

Detects the running ABI name natively using Google cpu-features library. */ public class AbiDetect { static { armV7aNeonLoaded = false; - System.loadLibrary("ffmpegkit_abidetect"); + NativeLoader.loadFFmpegKitAbiDetect(); /* ALL LIBRARIES LOADED AT STARTUP */ - FFmpegKitConfig.class.getName(); FFmpegKit.class.getName(); + FFmpegKitConfig.class.getName(); + FFprobeKit.class.getName(); } static final String ARM_V7A = "arm-v7a"; @@ -51,9 +52,9 @@ public class AbiDetect { } /** - *

Returns loaded ABI name. + *

Returns the ABI name loaded. * - * @return loaded ABI name + * @return ABI name loaded */ public static String getAbi() { if (armV7aNeonLoaded) { @@ -64,28 +65,37 @@ public class AbiDetect { } /** - *

Returns loaded ABI name. + *

Returns the ABI name of the cpu running. + * + * @return ABI name of the cpu running + */ + public static String getCpuAbi() { + return getNativeCpuAbi(); + } + + /** + *

Returns the ABI name loaded natively. * - * @return loaded ABI name + * @return ABI name loaded */ - public native static String getNativeAbi(); + native static String getNativeAbi(); /** - *

Returns ABI name of the running cpu. + *

Returns the ABI name of the cpu running natively. * - * @return ABI name of the running cpu + * @return ABI name of the cpu running */ - public native static String getNativeCpuAbi(); + native static String getNativeCpuAbi(); /** - *

Returns whether FFmpegKit release is a long term release or not. + *

Returns whether FFmpegKit release is a long term release or not natively. * * @return yes or no */ native static boolean isNativeLTSBuild(); /** - *

Returns build configuration for FFmpeg. + *

Returns the build configuration for FFmpeg natively. * * @return build configuration string */ diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AbstractSession.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AbstractSession.java index 3c094f6..c9697a0 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AbstractSession.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AbstractSession.java @@ -22,54 +22,121 @@ package com.arthenica.ffmpegkit; import com.arthenica.smartexception.java.Exceptions; import java.util.Date; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.LinkedList; +import java.util.List; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicLong; +/** + * Abstract session implementation which includes common features shared by FFmpeg + * and FFprobe sessions. + */ public abstract class AbstractSession implements Session { /** - * Generates ids for execute sessions. + * Generates unique ids for sessions. */ protected static final AtomicLong sessionIdGenerator = new AtomicLong(1); /** - * Defines how long default `getAll` methods wait. + * Defines how long default "getAll" methods wait, in milliseconds. */ - protected static final int DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT = 5000; + public static final int DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT = 5000; + /** + * Session identifier. + */ + protected final long sessionId; + + /** + * Session specific execute callback function. + */ protected final ExecuteCallback executeCallback; + + /** + * Session specific log callback function. + */ protected final LogCallback logCallback; - protected final StatisticsCallback statisticsCallback; - protected final long sessionId; + + /** + * Date and time the session was created. + */ protected final Date createTime; + + /** + * Date and time the session was started. + */ protected Date startTime; + + /** + * Date and time the session has ended. + */ protected Date endTime; + + /** + * Command arguments as an array. + */ protected final String[] arguments; - protected final Queue logs; + + /** + * Log entries received for this session. + */ + protected final List logs; + + /** + * Log entry lock. + */ + protected final Object logsLock; + + /** + * Future created for sessions executed asynchronously. + */ protected Future future; + + /** + * State of the session. + */ protected SessionState state; - protected int returnCode; + + /** + * Return code for the completed sessions. + */ + protected ReturnCode returnCode; + + /** + * Stack trace of the error received while trying to execute this session. + */ protected String failStackTrace; + + /** + * Session specific log redirection strategy. + */ protected final LogRedirectionStrategy logRedirectionStrategy; + /** + * Creates a new abstract session. + * + * @param arguments command arguments + * @param executeCallback session specific execute callback function + * @param logCallback session specific log callback function + * @param logRedirectionStrategy session specific log redirection strategy + */ public AbstractSession(final String[] arguments, final ExecuteCallback executeCallback, final LogCallback logCallback, - final StatisticsCallback statisticsCallback, final LogRedirectionStrategy logRedirectionStrategy) { this.sessionId = sessionIdGenerator.getAndIncrement(); + this.executeCallback = executeCallback; + this.logCallback = logCallback; this.createTime = new Date(); this.startTime = null; + this.endTime = null; this.arguments = arguments; - this.executeCallback = executeCallback; - this.logCallback = logCallback; - this.statisticsCallback = statisticsCallback; - this.logs = new ConcurrentLinkedQueue<>(); + this.logs = new LinkedList<>(); + this.logsLock = new Object(); this.future = null; this.state = SessionState.CREATED; - this.returnCode = ReturnCode.NOT_SET; + this.returnCode = null; this.failStackTrace = null; this.logRedirectionStrategy = logRedirectionStrategy; } @@ -84,11 +151,6 @@ public abstract class AbstractSession implements Session { return logCallback; } - @Override - public StatisticsCallback getStatisticsCallback() { - return statisticsCallback; - } - @Override public long getSessionId() { return sessionId; @@ -117,7 +179,7 @@ public abstract class AbstractSession implements Session { return (endTime.getTime() - startTime.getTime()); } - return -1; + return 0; } @Override @@ -130,77 +192,84 @@ public abstract class AbstractSession implements Session { return FFmpegKit.argumentsToString(arguments); } - protected void waitForCallbackMessagesInTransmit(final int timeout) { - final long start = System.currentTimeMillis(); - - /* - * WE GIVE MAX 5 SECONDS TO TRANSMIT ALL NATIVE MESSAGES - */ - while (thereAreCallbackMessagesInTransmit() && (System.currentTimeMillis() < (start + timeout))) { - synchronized (this) { - try { - wait(100); - } catch (InterruptedException ignored) { - } - } - } - } - @Override - public Queue getAllLogs(final int waitTimeout) { - waitForCallbackMessagesInTransmit(waitTimeout); + public List getAllLogs(final int waitTimeout) { + waitForAsynchronousMessagesInTransmit(waitTimeout); - if (thereAreCallbackMessagesInTransmit()) { - android.util.Log.i(FFmpegKitConfig.TAG, String.format("getAllLogs was asked to return all logs but there are still logs being transmitted for session id %d.", sessionId)); + if (thereAreAsynchronousMessagesInTransmit()) { + android.util.Log.i(FFmpegKitConfig.TAG, String.format("getAllLogs was called to return all logs but there are still logs being transmitted for session id %d.", sessionId)); } - return logs; + return getLogs(); } + /** + * Returns all log entries generated for this session. If there are asynchronous + * messages that are not delivered yet, this method waits for them until + * {@link #DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT} expires. + * + * @return list of log entries generated for this session + */ @Override - public Queue getAllLogs() { - return getAllLogs(DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT); + public List getAllLogs() { + return getAllLogs(DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT); } @Override - public Queue getLogs() { - return logs; + public List getLogs() { + synchronized (logsLock) { + return new LinkedList<>(logs); + } } @Override public String getAllLogsAsString(final int waitTimeout) { - waitForCallbackMessagesInTransmit(waitTimeout); + waitForAsynchronousMessagesInTransmit(waitTimeout); - if (thereAreCallbackMessagesInTransmit()) { - android.util.Log.i(FFmpegKitConfig.TAG, String.format("getAllLogsAsString was asked to return all logs but there are still logs being transmitted for session id %d.", sessionId)); + if (thereAreAsynchronousMessagesInTransmit()) { + android.util.Log.i(FFmpegKitConfig.TAG, String.format("getAllLogsAsString was called to return all logs but there are still logs being transmitted for session id %d.", sessionId)); } return getLogsAsString(); } + /** + * Returns all log entries generated for this session as a concatenated string. If there are + * asynchronous messages that are not delivered yet, this method waits for them until + * {@link #DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT} expires. + * + * @return all log entries generated for this session as a concatenated string + */ @Override public String getAllLogsAsString() { - return getAllLogsAsString(DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT); + return getAllLogsAsString(DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT); } @Override public String getLogsAsString() { final StringBuilder concatenatedString = new StringBuilder(); - for (Log log : logs) { - concatenatedString.append(log.getMessage()); + synchronized (logsLock) { + for (Log log : logs) { + concatenatedString.append(log.getMessage()); + } } return concatenatedString.toString(); } + @Override + public String getOutput() { + return getAllLogsAsString(); + } + @Override public SessionState getState() { return state; } @Override - public int getReturnCode() { + public ReturnCode getReturnCode() { return returnCode; } @@ -215,13 +284,15 @@ public abstract class AbstractSession implements Session { } @Override - public boolean thereAreCallbackMessagesInTransmit() { + public boolean thereAreAsynchronousMessagesInTransmit() { return (FFmpegKitConfig.messagesInTransmit(sessionId) != 0); } @Override public void addLog(final Log log) { - this.logs.add(log); + synchronized (logsLock) { + this.logs.add(log); + } } @Override @@ -230,35 +301,67 @@ public abstract class AbstractSession implements Session { } @Override - public void setFuture(final Future future) { + public void cancel() { + if (state == SessionState.RUNNING) { + FFmpegKit.cancel(sessionId); + } + } + + /** + * Waits for all asynchronous messages to be transmitted until the given timeout. + * + * @param timeout wait timeout in milliseconds + */ + protected void waitForAsynchronousMessagesInTransmit(final int timeout) { + final long start = System.currentTimeMillis(); + + while (thereAreAsynchronousMessagesInTransmit() && (System.currentTimeMillis() < (start + timeout))) { + synchronized (this) { + try { + wait(100); + } catch (InterruptedException ignored) { + } + } + } + } + + /** + * Sets the future created for this session. + * + * @param future future that runs this session asynchronously + */ + void setFuture(final Future future) { this.future = future; } - @Override - public void startRunning() { + /** + * Starts running the session. + */ + void startRunning() { this.state = SessionState.RUNNING; this.startTime = new Date(); } - @Override - public void complete(final int returnCode) { + /** + * Completes running the session with the provided return code. + * + * @param returnCode return code of the execution + */ + void complete(final ReturnCode returnCode) { this.returnCode = returnCode; this.state = SessionState.COMPLETED; this.endTime = new Date(); } - @Override - public void fail(final Exception exception) { + /** + * Ends running the session with a failure. + * + * @param exception execution received + */ + void fail(final Exception exception) { this.failStackTrace = Exceptions.getStackTraceString(exception); this.state = SessionState.FAILED; this.endTime = new Date(); } - @Override - public void cancel() { - if (state == SessionState.RUNNING) { - FFmpegKit.cancel(sessionId); - } - } - } diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AsyncFFmpegExecuteTask.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AsyncFFmpegExecuteTask.java index f7148f9..f1f0cce 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AsyncFFmpegExecuteTask.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AsyncFFmpegExecuteTask.java @@ -35,7 +35,7 @@ public class AsyncFFmpegExecuteTask implements Runnable { public void run() { FFmpegKitConfig.ffmpegExecute(ffmpegSession); - final ExecuteCallback globalExecuteCallbackFunction = FFmpegKitConfig.getGlobalExecuteCallbackFunction(); + final ExecuteCallback globalExecuteCallbackFunction = FFmpegKitConfig.getExecuteCallback(); if (globalExecuteCallbackFunction != null) { globalExecuteCallbackFunction.apply(ffmpegSession); } diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AsyncFFprobeExecuteTask.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AsyncFFprobeExecuteTask.java index ebe7c26..dafb86d 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AsyncFFprobeExecuteTask.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AsyncFFprobeExecuteTask.java @@ -20,7 +20,7 @@ package com.arthenica.ffmpegkit; /** - *

Executes an FFprobe execution asynchronously. + *

Executes an FFprobe session asynchronously. */ public class AsyncFFprobeExecuteTask implements Runnable { private final FFprobeSession ffprobeSession; @@ -35,7 +35,7 @@ public class AsyncFFprobeExecuteTask implements Runnable { public void run() { FFmpegKitConfig.ffprobeExecute(ffprobeSession); - final ExecuteCallback globalExecuteCallbackFunction = FFmpegKitConfig.getGlobalExecuteCallbackFunction(); + final ExecuteCallback globalExecuteCallbackFunction = FFmpegKitConfig.getExecuteCallback(); if (globalExecuteCallbackFunction != null) { globalExecuteCallbackFunction.apply(ffprobeSession); } diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AsyncGetMediaInformationTask.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AsyncGetMediaInformationTask.java index 5c78a94..fe3368f 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AsyncGetMediaInformationTask.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/AsyncGetMediaInformationTask.java @@ -28,7 +28,7 @@ public class AsyncGetMediaInformationTask implements Runnable { private final Integer waitTimeout; public AsyncGetMediaInformationTask(final MediaInformationSession mediaInformationSession) { - this(mediaInformationSession, AbstractSession.DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT); + this(mediaInformationSession, AbstractSession.DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT); } public AsyncGetMediaInformationTask(final MediaInformationSession mediaInformationSession, final Integer waitTimeout) { @@ -41,7 +41,7 @@ public class AsyncGetMediaInformationTask implements Runnable { public void run() { FFmpegKitConfig.getMediaInformationExecute(mediaInformationSession, waitTimeout); - final ExecuteCallback globalExecuteCallbackFunction = FFmpegKitConfig.getGlobalExecuteCallbackFunction(); + final ExecuteCallback globalExecuteCallbackFunction = FFmpegKitConfig.getExecuteCallback(); if (globalExecuteCallbackFunction != null) { globalExecuteCallbackFunction.apply(mediaInformationSession); } diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/CameraSupport.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/CameraSupport.java index cf127bc..1c4c4c9 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/CameraSupport.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/CameraSupport.java @@ -34,17 +34,17 @@ import static android.content.Context.CAMERA_SERVICE; import static com.arthenica.ffmpegkit.FFmpegKitConfig.TAG; /** - *

Helper class to find camera devices supported. - *

Note that camera devices can only be detected on Android API Level 24+. On older API levels - * an empty list will be returned. + *

Helper class to detect camera devices that can be used in + * FFmpeg/FFprobe commands. */ class CameraSupport { /** - *

Compatibility method for extracting supported camera ids. + *

Lists camera ids that can be used in FFmpeg/FFprobe commands. * * @param context application context - * @return returns the list of supported camera ids + * @return the list of supported camera ids on Android API Level 24+, an empty list on older + * API levels */ static List extractSupportedCameraIds(final Context context) { final List detectedCameraIdList = new ArrayList<>(); diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/ExecuteCallback.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/ExecuteCallback.java index 6e460bd..2d1af84 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/ExecuteCallback.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/ExecuteCallback.java @@ -20,15 +20,31 @@ package com.arthenica.ffmpegkit; /** - *

Callback function to receive execution results. + *

Callback function invoked when an asynchronous session ends running. + *

Session has either {@link SessionState#COMPLETED} or {@link SessionState#FAILED} state when + * the callback is invoked. + *

If it has {@link SessionState#COMPLETED} state, ReturnCode should be checked to + * see the execution result. + *

If getState returns {@link SessionState#FAILED} then + * getFailStackTrace should be used to get the failure reason. + *

+ *  switch (session.getState()) {
+ *      case COMPLETED: {
+ *          ReturnCode returnCode = session.getReturnCode();
+ *      } break;
+ *      case FAILED: {
+ *          String failStackTrace = session.getFailStackTrace();
+ *      } break;
+ *  }
+ * 
*/ @FunctionalInterface public interface ExecuteCallback { /** - *

Called when an execution is completed. + *

Called when an asynchronous session ends running. * - * @param session of with completed execution + * @param session session */ void apply(final Session session); 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 391df84..ccc32a6 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 @@ -21,18 +21,19 @@ package com.arthenica.ffmpegkit; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; /** - *

Main class for FFmpeg operations. Supports synchronous {@link #execute(String...)} and - * asynchronous {@link #executeAsync(String, ExecuteCallback)} methods to execute FFmpeg commands. + *

Main class to run FFmpeg commands. Supports executing commands both + * synchronously and asynchronously. *

- *      FFmpegSession session = FFmpeg.execute("-i file1.mp4 -c:v libxvid file1.avi");
- *      Log.i(Config.TAG, String.format("Command execution completed with %d.", session.getReturnCode());
+ * FFmpegSession session = FFmpegKit.execute("-i file1.mp4 -c:v libxvid file1.avi");
+ *
+ * FFmpegSession asyncSession = FFmpegKit.executeAsync("-i file1.mp4 -c:v libxvid file1.avi", executeCallback);
  * 
+ *

Provides overloaded execute methods to define session specific callbacks. *

- *      FFmpegSession session = FFmpeg.executeAsync("-i file1.mp4 -c:v libxvid file1.avi", executeCallback);
- *      Log.i(Config.TAG, String.format("Asynchronous session %d started.", session.getSessionId()));
+ * FFmpegSession asyncSession = FFmpegKit.executeAsync("-i file1.mp4 -c:v libxvid file1.avi", executeCallback, logCallback, statisticsCallback);
  * 
*/ public class FFmpegKit { @@ -52,10 +53,10 @@ public class FFmpegKit { *

Synchronously executes FFmpeg with arguments provided. * * @param arguments FFmpeg command options/arguments as string array - * @return ffmpeg session created for this execution + * @return FFmpeg session created for this execution */ public static FFmpegSession execute(final String[] arguments) { - final FFmpegSession session = new FFmpegSession(arguments, null, null, null); + final FFmpegSession session = new FFmpegSession(arguments); FFmpegKitConfig.ffmpegExecute(session); @@ -66,12 +67,12 @@ public class FFmpegKit { *

Asynchronously executes FFmpeg with arguments provided. * * @param arguments FFmpeg command options/arguments as string array - * @param executeCallback callback that will be notified when the execution is completed - * @return ffmpeg session created for this execution + * @param executeCallback callback that will be called when the execution is completed + * @return FFmpeg session created for this execution */ public static FFmpegSession executeAsync(final String[] arguments, final ExecuteCallback executeCallback) { - final FFmpegSession session = new FFmpegSession(arguments, executeCallback, null, null); + final FFmpegSession session = new FFmpegSession(arguments, executeCallback); FFmpegKitConfig.asyncFFmpegExecute(session); @@ -82,10 +83,10 @@ public class FFmpegKit { *

Asynchronously executes FFmpeg with arguments provided. * * @param arguments FFmpeg command options/arguments as string array - * @param executeCallback callback that will be notified when execution is completed - * @param logCallback callback that will receive log entries + * @param executeCallback callback that will be called when the execution is completed + * @param logCallback callback that will receive logs * @param statisticsCallback callback that will receive statistics - * @return ffmpeg session created for this execution + * @return FFmpeg session created for this execution */ public static FFmpegSession executeAsync(final String[] arguments, final ExecuteCallback executeCallback, @@ -102,17 +103,16 @@ public class FFmpegKit { *

Asynchronously executes FFmpeg with arguments provided. * * @param arguments FFmpeg command options/arguments as string array - * @param executeCallback callback that will be notified when execution is completed - * @param executor executor that will be used to run this asynchronous operation - * @return ffmpeg session created for this execution + * @param executeCallback callback that will be called when the execution is completed + * @param executorService executor service that will be used to run this asynchronous operation + * @return FFmpeg session created for this execution */ public static FFmpegSession executeAsync(final String[] arguments, final ExecuteCallback executeCallback, - final Executor executor) { - final FFmpegSession session = new FFmpegSession(arguments, executeCallback, null, null); + final ExecutorService executorService) { + final FFmpegSession session = new FFmpegSession(arguments, executeCallback); - AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(session); - executor.execute(asyncFFmpegExecuteTask); + FFmpegKitConfig.asyncFFmpegExecute(session, executorService); return session; } @@ -121,32 +121,31 @@ public class FFmpegKit { *

Asynchronously executes FFmpeg with arguments provided. * * @param arguments FFmpeg command options/arguments as string array - * @param executeCallback callback that will be notified when execution is completed - * @param logCallback callback that will receive log entries + * @param executeCallback callback that will be called when the execution is completed + * @param logCallback callback that will receive logs * @param statisticsCallback callback that will receive statistics - * @param executor executor that will be used to run this asynchronous operation - * @return ffmpeg session created for this execution + * @param executorService executor service that will be used to run this asynchronous operation + * @return FFmpeg session created for this execution */ public static FFmpegSession executeAsync(final String[] arguments, final ExecuteCallback executeCallback, final LogCallback logCallback, final StatisticsCallback statisticsCallback, - final Executor executor) { + final ExecutorService executorService) { final FFmpegSession session = new FFmpegSession(arguments, executeCallback, logCallback, statisticsCallback); - AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(session); - executor.execute(asyncFFmpegExecuteTask); + FFmpegKitConfig.asyncFFmpegExecute(session, executorService); return session; } /** *

Synchronously executes FFmpeg command provided. Space character is used to split command - * into arguments. You can use single and double quote characters to specify arguments inside + * into arguments. You can use single or double quote characters to specify arguments inside * your command. * * @param command FFmpeg command - * @return ffmpeg session created for this execution + * @return FFmpeg session created for this execution */ public static FFmpegSession execute(final String command) { return execute(parseArguments(command)); @@ -154,12 +153,12 @@ public class FFmpegKit { /** *

Asynchronously executes FFmpeg command provided. Space character is used to split command - * into arguments. You can use single and double quote characters to specify arguments inside + * into arguments. You can use single or double quote characters to specify arguments inside * your command. * * @param command FFmpeg command - * @param executeCallback callback that will be notified when execution is completed - * @return ffmpeg session created for this execution + * @param executeCallback callback that will be called when the execution is completed + * @return FFmpeg session created for this execution */ public static FFmpegSession executeAsync(final String command, final ExecuteCallback executeCallback) { @@ -168,14 +167,14 @@ public class FFmpegKit { /** *

Asynchronously executes FFmpeg command provided. Space character is used to split command - * into arguments. You can use single and double quote characters to specify arguments inside + * into arguments. You can use single or double quote characters to specify arguments inside * your command. * * @param command FFmpeg command - * @param executeCallback callback that will be notified when execution is completed - * @param logCallback callback that will receive log entries + * @param executeCallback callback that will be called when the execution is completed + * @param logCallback callback that will receive logs * @param statisticsCallback callback that will receive statistics - * @return ffmpeg session created for this execution + * @return FFmpeg session created for this execution */ public static FFmpegSession executeAsync(final String command, final ExecuteCallback executeCallback, @@ -186,52 +185,50 @@ public class FFmpegKit { /** *

Asynchronously executes FFmpeg command provided. Space character is used to split command - * into arguments. You can use single and double quote characters to specify arguments inside + * into arguments. You can use single or double quote characters to specify arguments inside * your command. * * @param command FFmpeg command - * @param executeCallback callback that will be notified when execution is completed - * @param executor executor that will be used to run this asynchronous operation - * @return ffmpeg session created for this execution + * @param executeCallback callback that will be called when the execution is completed + * @param executorService executor service that will be used to run this asynchronous operation + * @return FFmpeg session created for this execution */ public static FFmpegSession executeAsync(final String command, final ExecuteCallback executeCallback, - final Executor executor) { - final FFmpegSession session = new FFmpegSession(parseArguments(command), executeCallback, null, null); + final ExecutorService executorService) { + final FFmpegSession session = new FFmpegSession(parseArguments(command), executeCallback); - AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(session); - executor.execute(asyncFFmpegExecuteTask); + FFmpegKitConfig.asyncFFmpegExecute(session, executorService); return session; } /** *

Asynchronously executes FFmpeg command provided. Space character is used to split command - * into arguments. You can use single and double quote characters to specify arguments inside + * into arguments. You can use single or double quote characters to specify arguments inside * your command. * * @param command FFmpeg command - * @param executeCallback callback that will be notified when execution is completed - * @param logCallback callback that will receive log entries + * @param executeCallback callback that will be called when the execution is completed + * @param logCallback callback that will receive logs * @param statisticsCallback callback that will receive statistics - * @param executor executor that will be used to run this asynchronous operation - * @return ffmpeg session created for this execution + * @param executorService executor service that will be used to run this asynchronous operation + * @return FFmpeg session created for this execution */ public static FFmpegSession executeAsync(final String command, final ExecuteCallback executeCallback, final LogCallback logCallback, final StatisticsCallback statisticsCallback, - final Executor executor) { + final ExecutorService executorService) { final FFmpegSession session = new FFmpegSession(parseArguments(command), executeCallback, logCallback, statisticsCallback); - AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(session); - executor.execute(asyncFFmpegExecuteTask); + FFmpegKitConfig.asyncFFmpegExecute(session, executorService); return session; } /** - *

Cancels all ongoing executions. + *

Cancels all running sessions. * *

This function does not wait for termination to complete and returns immediately. */ @@ -240,13 +237,13 @@ public class FFmpegKit { /* * ZERO (0) IS A SPECIAL SESSION ID * WHEN IT IS PASSED TO THIS METHOD, A SIGINT IS GENERATED WHICH CANCELS ALL ONGOING - * EXECUTIONS + * SESSIONS */ FFmpegKitConfig.nativeFFmpegCancel(0); } /** - *

Cancels the given execution. + *

Cancels the session specified with sessionId. * *

This function does not wait for termination to complete and returns immediately. * @@ -257,7 +254,7 @@ public class FFmpegKit { } /** - *

Lists all FFmpeg sessions in the session history + *

Lists all FFmpeg sessions in the session history. * * @return all FFmpeg sessions in the session history */ @@ -266,7 +263,8 @@ public class FFmpegKit { } /** - *

Parses the given command into arguments. + *

Parses the given command into arguments. Uses space character to split the arguments. + * Supports single and double quote characters. * * @param command string command * @return array of arguments @@ -323,10 +321,10 @@ public class FFmpegKit { } /** - *

Combines arguments into a string. + *

Concatenates arguments into a string adding a space character between two arguments. * * @param arguments arguments - * @return string containing all arguments + * @return concatenated string containing all arguments */ static String argumentsToString(final String[] arguments) { if (arguments == 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 ff308c3..019ac4c 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 @@ -40,7 +40,6 @@ import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Queue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -48,58 +47,43 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; /** - *

This class is used to configure FFmpegKit library and tools coming with it. - * - *

1. {@link LogCallback}: This class redirects FFmpeg/FFprobe output to Logcat by default. As - * an alternative, it is possible not to print messages to Logcat and pass them to a - * {@link LogCallback} function. This function can decide whether to print these logs, show them - * inside another container or ignore them. - * - *

2. {@link #setLogLevel(Level)}/{@link #getLogLevel()}: Use this methods to set/get - * FFmpeg/FFprobe log severity. - * - *

3. {@link StatisticsCallback}: It is possible to receive statistics about an ongoing - * operation by defining a {@link StatisticsCallback} function or by calling - * {@link #getLastReceivedStatistics()} method. - * - *

4. Font configuration: It is possible to register custom fonts with - * {@link #setFontconfigConfigurationPath(String)} and - * {@link #setFontDirectory(Context, String, Map)} methods. + *

Configuration class of FFmpegKit library. Allows customizing the global library + * options. Provides helper methods to support additional resources. */ public class FFmpegKitConfig { /** * The tag used for logging. */ - public static final String TAG = "ffmpeg-kit"; + static final String TAG = "ffmpeg-kit"; /** * Prefix of named pipes created by ffmpeg kit. */ - public static final String FFMPEG_KIT_NAMED_PIPE_PREFIX = "fk_pipe_"; + static final String FFMPEG_KIT_NAMED_PIPE_PREFIX = "fk_pipe_"; /** * Generates ids for named ffmpeg kit pipes. */ private static final AtomicLong pipeIndexGenerator; - /* SESSION HISTORY VARIABLES */ + private static Level activeLogLevel; + + /* Session history variables */ private static int sessionHistorySize; private static final Map sessionHistoryMap; - private static final Queue sessionHistoryQueue; + private static final List sessionHistoryList; private static final Object sessionHistoryLock; - /** - * Executor service for async executions. - */ + private static int asyncConcurrencyLimit; private static ExecutorService asyncExecutorService; + + /* Global callbacks */ private static LogCallback globalLogCallbackFunction; private static StatisticsCallback globalStatisticsCallbackFunction; private static ExecuteCallback globalExecuteCallbackFunction; - private static Level activeLogLevel; - private static int asyncConcurrencyLimit; private static final SparseArray pfdMap; - private static LogRedirectionStrategy logRedirectionStrategy; + private static LogRedirectionStrategy globalLogRedirectionStrategy; static { @@ -107,92 +91,44 @@ public class FFmpegKitConfig { android.util.Log.i(FFmpegKitConfig.TAG, "Loading ffmpeg-kit."); - boolean nativeFFmpegLoaded = false; - boolean nativeFFmpegTriedAndFailed = false; - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - - /* LOADING LIBRARIES MANUALLY ON API < 21 */ - final List externalLibrariesEnabled = getExternalLibraries(); - if (externalLibrariesEnabled.contains("tesseract") || externalLibrariesEnabled.contains("x265") || externalLibrariesEnabled.contains("snappy") || externalLibrariesEnabled.contains("openh264") || externalLibrariesEnabled.contains("rubberband")) { - System.loadLibrary("c++_shared"); - } - - if (AbiDetect.ARM_V7A.equals(AbiDetect.getNativeAbi())) { - try { - System.loadLibrary("avutil_neon"); - System.loadLibrary("swscale_neon"); - System.loadLibrary("swresample_neon"); - System.loadLibrary("avcodec_neon"); - System.loadLibrary("avformat_neon"); - System.loadLibrary("avfilter_neon"); - System.loadLibrary("avdevice_neon"); - nativeFFmpegLoaded = true; - } catch (final UnsatisfiedLinkError e) { - android.util.Log.i(FFmpegKitConfig.TAG, String.format("NEON supported armeabi-v7a ffmpeg library not found. Loading default armeabi-v7a library.%s", Exceptions.getStackTraceString(e))); - nativeFFmpegTriedAndFailed = true; - } - } - - if (!nativeFFmpegLoaded) { - System.loadLibrary("avutil"); - System.loadLibrary("swscale"); - System.loadLibrary("swresample"); - System.loadLibrary("avcodec"); - System.loadLibrary("avformat"); - System.loadLibrary("avfilter"); - System.loadLibrary("avdevice"); - } - } + final boolean nativeFFmpegTriedAndFailed = NativeLoader.loadFFmpeg(); /* ALL FFMPEG-KIT LIBRARIES LOADED AT STARTUP */ Abi.class.getName(); FFmpegKit.class.getName(); FFprobeKit.class.getName(); - boolean nativeFFmpegKitLoaded = false; - if (!nativeFFmpegTriedAndFailed && AbiDetect.ARM_V7A.equals(AbiDetect.getNativeAbi())) { - try { - - /* - * THE TRY TO LOAD ARM-V7A-NEON FIRST. IF NOT LOAD DEFAULT ARM-V7A - */ + NativeLoader.loadFFmpegKit(nativeFFmpegTriedAndFailed); - System.loadLibrary("ffmpegkit_armv7a_neon"); - nativeFFmpegKitLoaded = true; - AbiDetect.setArmV7aNeonLoaded(); - } catch (final UnsatisfiedLinkError e) { - android.util.Log.i(FFmpegKitConfig.TAG, String.format("NEON supported armeabi-v7a ffmpegkit library not found. Loading default armeabi-v7a library.%s", Exceptions.getStackTraceString(e))); - } - } + android.util.Log.i(FFmpegKitConfig.TAG, String.format("Loaded ffmpeg-kit-%s-%s-%s-%s.", NativeLoader.loadPackageName(), NativeLoader.loadAbi(), NativeLoader.loadVersion(), NativeLoader.loadBuildDate())); - if (!nativeFFmpegKitLoaded) { - System.loadLibrary("ffmpegkit"); - } + pipeIndexGenerator = new AtomicLong(1); - android.util.Log.i(FFmpegKitConfig.TAG, String.format("Loaded ffmpeg-kit-%s-%s-%s-%s.", getPackageName(), AbiDetect.getAbi(), getVersion(), getBuildDate())); + /* NATIVE LOG LEVEL IS RECEIVED ONLY ON STARTUP */ + activeLogLevel = Level.from(NativeLoader.loadLogLevel()); - pipeIndexGenerator = new AtomicLong(1); asyncConcurrencyLimit = 10; asyncExecutorService = Executors.newFixedThreadPool(asyncConcurrencyLimit); - /* NATIVE LOG LEVEL IS RECEIVED ONLY ON STARTUP */ - activeLogLevel = Level.from(getNativeLogLevel()); - sessionHistorySize = 10; - sessionHistoryMap = Collections.synchronizedMap(new LinkedHashMap() { + sessionHistoryMap = new LinkedHashMap() { @Override protected boolean removeEldestEntry(Map.Entry eldest) { return (this.size() > sessionHistorySize); } - }); - sessionHistoryQueue = new LinkedList<>(); + }; + sessionHistoryList = new LinkedList<>(); sessionHistoryLock = new Object(); + globalLogCallbackFunction = null; + globalStatisticsCallbackFunction = null; + globalExecuteCallbackFunction = null; + pfdMap = new SparseArray<>(); - logRedirectionStrategy = LogRedirectionStrategy.PRINT_LOGS_WHEN_NO_CALLBACKS_DEFINED; + globalLogRedirectionStrategy = LogRedirectionStrategy.PRINT_LOGS_WHEN_NO_CALLBACKS_DEFINED; - enableRedirection(); + NativeLoader.enableRedirection(); } /** @@ -203,13 +139,11 @@ public class FFmpegKitConfig { /** *

Enables log and statistics redirection. - *

When redirection is not enabled FFmpeg/FFprobe logs are printed to stderr. By enabling - * redirection, they are routed to Logcat and can be routed further to a callback function. - *

Statistics redirection behaviour is similar. Statistics are not printed at all if - * redirection is not enabled. If it is enabled then it is possible to define a statistics - * callback function but if you don't, they are not printed anywhere and only saved as - * lastReceivedStatistics data which can be polled with - * {@link #getLastReceivedStatistics()}. + * + *

When redirection is enabled FFmpeg/FFprobe logs are redirected to Logcat and sessions + * collect log and statistics entries for the executions. It is possible to define global or + * session specific log/statistics callbacks as well. + * *

Note that redirection is enabled by default. If you do not want to use its functionality * please use {@link #disableRedirection()} to disable it. */ @@ -219,17 +153,22 @@ public class FFmpegKitConfig { /** *

Disables log and statistics redirection. + * + *

When redirection is disabled logs are printed to stderr, all logs and statistics + * callbacks are disabled and FFprobe's getMediaInformation methods + * do not work. */ public static void disableRedirection() { disableNativeRedirection(); } /** - *

Log redirection method called by JNI/native part. + *

Log redirection method called by the native library. * - * @param sessionId id of the session that generated this log, 0 by default + * @param sessionId id of the session that generated this log, 0 for logs that do not belong + * to a specific session * @param levelValue log level as defined in {@link Level} - * @param logMessage redirected log message + * @param logMessage redirected log message data */ private static void log(final long sessionId, final int levelValue, final byte[] logMessage) { final Level level = Level.from(levelValue); @@ -237,7 +176,7 @@ public class FFmpegKitConfig { final Log log = new Log(sessionId, level, text); boolean globalCallbackDefined = false; boolean sessionCallbackDefined = false; - LogRedirectionStrategy activeLogRedirectionStrategy = FFmpegKitConfig.logRedirectionStrategy; + LogRedirectionStrategy activeLogRedirectionStrategy = globalLogRedirectionStrategy; // AV_LOG_STDERR logs are always redirected if ((activeLogLevel == Level.AV_LOG_QUIET && levelValue != Level.AV_LOG_STDERR.getValue()) || levelValue > activeLogLevel.getValue()) { @@ -254,7 +193,7 @@ public class FFmpegKitConfig { sessionCallbackDefined = true; try { - // NOTIFY SESSION CALLBACK IF DEFINED + // NOTIFY SESSION CALLBACK DEFINED session.getLogCallback().apply(log); } catch (final Exception e) { android.util.Log.e(FFmpegKitConfig.TAG, String.format("Exception thrown inside session LogCallback block.%s", Exceptions.getStackTraceString(e))); @@ -267,7 +206,7 @@ public class FFmpegKitConfig { globalCallbackDefined = true; try { - // NOTIFY GLOBAL CALLBACK IF DEFINED + // NOTIFY GLOBAL CALLBACK DEFINED globalLogCallbackFunction.apply(log); } catch (final Exception e) { android.util.Log.e(FFmpegKitConfig.TAG, String.format("Exception thrown inside global LogCallback block.%s", Exceptions.getStackTraceString(e))); @@ -295,6 +234,8 @@ public class FFmpegKitConfig { return; } } + case ALWAYS_PRINT_LOGS: { + } } // PRINT LOGS @@ -332,11 +273,11 @@ public class FFmpegKitConfig { } /** - *

Statistics redirection method called by JNI/native part. + *

Statistics redirection method called by the native library. * * @param sessionId id of the session that generated this statistics, 0 by default - * @param videoFrameNumber last processed frame number for videos - * @param videoFps frames processed per second for videos + * @param videoFrameNumber frame number for videos + * @param videoFps frames per second value for videos * @param videoQuality quality of the video stream * @param size size in bytes * @param time processed duration in milliseconds @@ -349,13 +290,14 @@ public class FFmpegKitConfig { final Statistics statistics = new Statistics(sessionId, videoFrameNumber, videoFps, videoQuality, size, time, bitrate, speed); final Session session = getSession(sessionId); - if (session != null) { - session.addStatistics(statistics); + if (session != null && session.isFFmpeg()) { + FFmpegSession ffmpegSession = (FFmpegSession) session; + ffmpegSession.addStatistics(statistics); - if (session.getStatisticsCallback() != null) { + if (ffmpegSession.getStatisticsCallback() != null) { try { // NOTIFY SESSION CALLBACK IF DEFINED - session.getStatisticsCallback().apply(statistics); + ffmpegSession.getStatisticsCallback().apply(statistics); } catch (final Exception e) { android.util.Log.e(FFmpegKitConfig.TAG, String.format("Exception thrown inside session StatisticsCallback block.%s", Exceptions.getStackTraceString(e))); } @@ -373,24 +315,10 @@ public class FFmpegKitConfig { } } - /** - *

Returns the last received statistics data. - * - * @return last received statistics data or null if no statistics data is available - */ - public static Statistics getLastReceivedStatistics() { - final Session lastSession = getLastSession(); - if (lastSession != null) { - return lastSession.getStatistics().peek(); - } else { - return null; - } - } - /** *

Sets and overrides fontconfig configuration directory. * - * @param path directory which contains fontconfig configuration (fonts.conf) + * @param path directory that contains fontconfig configuration (fonts.conf) * @return zero on success, non-zero on error */ public static int setFontconfigConfigurationPath(final String path) { @@ -402,10 +330,11 @@ public class FFmpegKitConfig { * filters. * *

Note that you need to build FFmpegKit with fontconfig - * enabled or use a prebuilt package with fontconfig inside to use this feature. + * enabled or use a prebuilt package with fontconfig inside to be able to use + * fonts in FFmpeg. * * @param context application context to access application data - * @param fontDirectoryPath directory which contains fonts (.ttf and .otf files) + * @param fontDirectoryPath directory that contains fonts (.ttf and .otf files) * @param fontNameMapping custom font name mappings, useful to access your fonts with more * friendly names */ @@ -418,10 +347,11 @@ public class FFmpegKitConfig { * to use in FFmpeg filters. * *

Note that you need to build FFmpegKit with fontconfig - * enabled or use a prebuilt package with fontconfig inside to use this feature. + * enabled or use a prebuilt package with fontconfig inside to be able to use + * fonts in FFmpeg. * * @param context application context to access application data - * @param fontDirectoryList list of directories which contain fonts (.ttf and .otf files) + * @param fontDirectoryList list of directories that contain fonts (.ttf and .otf files) * @param fontNameMapping custom font name mappings, useful to access your fonts with more * friendly names */ @@ -506,24 +436,6 @@ public class FFmpegKitConfig { } } - /** - *

Returns FFmpegKit package name. - * - * @return FFmpegKit package name - */ - public static String getPackageName() { - return Packages.getPackageName(); - } - - /** - *

Returns the list of supported external libraries. - * - * @return list of supported external libraries - */ - public static List getExternalLibraries() { - return Packages.getExternalLibraries(); - } - /** *

Creates a new named pipe to use in FFmpeg operations. * @@ -563,7 +475,7 @@ public class FFmpegKitConfig { /** *

Closes a previously created FFmpeg pipe. * - * @param ffmpegPipePath full path of ffmpeg pipe + * @param ffmpegPipePath full path of the FFmpeg pipe */ public static void closeFFmpegPipe(final String ffmpegPipePath) { final File file = new File(ffmpegPipePath); @@ -573,13 +485,14 @@ public class FFmpegKitConfig { } /** - * Returns the list of camera ids supported. + * Returns the list of camera ids supported. These devices can be used in FFmpeg + * commands. * *

Note that this method requires API Level >= 24. On older API levels it returns an empty * list. * * @param context application context - * @return the list of camera ids supported or an empty list if no supported cameras are found + * @return list of camera ids supported or an empty list if no supported cameras are found */ public static List getSupportedCameraIds(final Context context) { final List detectedCameraIdList = new ArrayList<>(); @@ -592,9 +505,9 @@ public class FFmpegKitConfig { } /** - *

Returns FFmpeg version bundled within the library. + *

Returns the version of FFmpeg bundled within FFmpegKit library. * - * @return FFmpeg version + * @return the version of FFmpeg */ public static String getFFmpegVersion() { return getNativeFFmpegVersion(); @@ -632,41 +545,8 @@ public class FFmpegKitConfig { } /** - *

Returns the return code of the last completed execution. - * - * @return return code of the last completed execution - */ - public static int getLastReturnCode() { - final Session lastSession = getLastSession(); - if (lastSession != null) { - return lastSession.getReturnCode(); - } else { - return 0; - } - } - - /** - *

Returns the log output of the last executed FFmpeg/FFprobe command. - * - *

Please note that disabling redirection using {@link FFmpegKitConfig#disableRedirection()} - * method also disables this functionality. - * - * @return output of the last executed command - */ - public static String getLastCommandOutput() { - final Session lastSession = getLastSession(); - if (lastSession != null) { - - // REPLACING CH(13) WITH CH(10) - return lastSession.getAllLogsAsString().replace('\r', '\n'); - } else { - return ""; - } - } - - /** - *

Prints the output of the last executed FFmpeg/FFprobe command to the Logcat at the - * specified priority. + *

Prints the given string to Logcat using the given priority. If string provided is bigger + * than the Logcat buffer, the string is printed in multiple lines. * * @param logPriority one of {@link android.util.Log#VERBOSE}, * {@link android.util.Log#DEBUG}, @@ -674,26 +554,27 @@ public class FFmpegKitConfig { * {@link android.util.Log#WARN}, * {@link android.util.Log#ERROR}, * {@link android.util.Log#ASSERT} + * @param string string to be printed */ - public static void printLastCommandOutput(final int logPriority) { + public static void printToLogcat(final int logPriority, final String string) { final int LOGGER_ENTRY_MAX_LEN = 4 * 1000; - String buffer = getLastCommandOutput(); + String remainingString = string; do { - if (buffer.length() <= LOGGER_ENTRY_MAX_LEN) { - android.util.Log.println(logPriority, FFmpegKitConfig.TAG, buffer); - buffer = ""; + if (remainingString.length() <= LOGGER_ENTRY_MAX_LEN) { + android.util.Log.println(logPriority, FFmpegKitConfig.TAG, remainingString); + remainingString = ""; } else { - final int index = buffer.substring(0, LOGGER_ENTRY_MAX_LEN).lastIndexOf('\n'); + final int index = remainingString.substring(0, LOGGER_ENTRY_MAX_LEN).lastIndexOf('\n'); if (index < 0) { - android.util.Log.println(logPriority, FFmpegKitConfig.TAG, buffer.substring(0, LOGGER_ENTRY_MAX_LEN)); - buffer = buffer.substring(LOGGER_ENTRY_MAX_LEN); + android.util.Log.println(logPriority, FFmpegKitConfig.TAG, remainingString.substring(0, LOGGER_ENTRY_MAX_LEN)); + remainingString = remainingString.substring(LOGGER_ENTRY_MAX_LEN); } else { - android.util.Log.println(logPriority, FFmpegKitConfig.TAG, buffer.substring(0, index)); - buffer = buffer.substring(index); + android.util.Log.println(logPriority, FFmpegKitConfig.TAG, remainingString.substring(0, index)); + remainingString = remainingString.substring(index); } } - } while (buffer.length() > 0); + } while (remainingString.length() > 0); } /** @@ -708,26 +589,27 @@ public class FFmpegKitConfig { } /** - *

Registers a new ignored signal. Ignored signals are not handled by the library. + *

Registers a new ignored signal. Ignored signals are not handled by FFmpegKit + * library. * - * @param signal signal number to ignore + * @param signal signal to be ignored */ public static void ignoreSignal(final Signal signal) { ignoreNativeSignal(signal.getValue()); } /** - *

Synchronously executes the ffmpeg session provided. + *

Synchronously executes the FFmpeg session provided. * * @param ffmpegSession FFmpeg session which includes command options/arguments */ - static void ffmpegExecute(final FFmpegSession ffmpegSession) { + public static void ffmpegExecute(final FFmpegSession ffmpegSession) { addSession(ffmpegSession); ffmpegSession.startRunning(); try { final int returnCode = nativeFFmpegExecute(ffmpegSession.getSessionId(), ffmpegSession.getArguments()); - ffmpegSession.complete(returnCode); + ffmpegSession.complete(new ReturnCode(returnCode)); } catch (final Exception e) { ffmpegSession.fail(e); android.util.Log.w(FFmpegKitConfig.TAG, String.format("FFmpeg execute failed: %s.%s", FFmpegKit.argumentsToString(ffmpegSession.getArguments()), Exceptions.getStackTraceString(e))); @@ -735,17 +617,17 @@ public class FFmpegKitConfig { } /** - *

Synchronously executes the ffprobe session provided. + *

Synchronously executes the FFprobe session provided. * * @param ffprobeSession FFprobe session which includes command options/arguments */ - static void ffprobeExecute(final FFprobeSession ffprobeSession) { + public static void ffprobeExecute(final FFprobeSession ffprobeSession) { addSession(ffprobeSession); ffprobeSession.startRunning(); try { final int returnCode = nativeFFprobeExecute(ffprobeSession.getSessionId(), ffprobeSession.getArguments()); - ffprobeSession.complete(returnCode); + ffprobeSession.complete(new ReturnCode(returnCode)); } catch (final Exception e) { ffprobeSession.fail(e); android.util.Log.w(FFmpegKitConfig.TAG, String.format("FFprobe execute failed: %s.%s", FFmpegKit.argumentsToString(ffprobeSession.getArguments()), Exceptions.getStackTraceString(e))); @@ -758,15 +640,16 @@ public class FFmpegKitConfig { * @param mediaInformationSession media information session which includes command options/arguments * @param waitTimeout max time to wait until media information is transmitted */ - static void getMediaInformationExecute(final MediaInformationSession mediaInformationSession, final int waitTimeout) { + public static void getMediaInformationExecute(final MediaInformationSession mediaInformationSession, final int waitTimeout) { addSession(mediaInformationSession); mediaInformationSession.startRunning(); try { - final int returnCode = nativeFFprobeExecute(mediaInformationSession.getSessionId(), mediaInformationSession.getArguments()); + final int returnCodeValue = nativeFFprobeExecute(mediaInformationSession.getSessionId(), mediaInformationSession.getArguments()); + final ReturnCode returnCode = new ReturnCode(returnCodeValue); mediaInformationSession.complete(returnCode); - if (returnCode == ReturnCode.SUCCESS) { - MediaInformation mediaInformation = MediaInformationParser.fromWithError(mediaInformationSession.getAllLogsAsString(waitTimeout)); + if (returnCode.isSuccess()) { + MediaInformation mediaInformation = MediaInformationJsonParser.fromWithError(mediaInformationSession.getAllLogsAsString(waitTimeout)); mediaInformationSession.setMediaInformation(mediaInformation); } } catch (final Exception e) { @@ -776,51 +659,88 @@ public class FFmpegKitConfig { } /** - *

Asynchronously executes the ffmpeg session provided. + *

Asynchronously executes the FFmpeg session provided. * * @param ffmpegSession FFmpeg session which includes command options/arguments */ - static void asyncFFmpegExecute(final FFmpegSession ffmpegSession) { + public static void asyncFFmpegExecute(final FFmpegSession ffmpegSession) { AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(ffmpegSession); Future future = asyncExecutorService.submit(asyncFFmpegExecuteTask); ffmpegSession.setFuture(future); } /** - *

Asynchronously executes the ffprobe session provided. + *

Asynchronously executes the FFmpeg session provided. + * + * @param ffmpegSession FFmpeg session which includes command options/arguments + * @param executorService executor service that will be used to run this asynchronous operation + */ + public static void asyncFFmpegExecute(final FFmpegSession ffmpegSession, final ExecutorService executorService) { + AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(ffmpegSession); + Future future = executorService.submit(asyncFFmpegExecuteTask); + ffmpegSession.setFuture(future); + } + + /** + *

Asynchronously executes the FFprobe session provided. * * @param ffprobeSession FFprobe session which includes command options/arguments */ - static void asyncFFprobeExecute(final FFprobeSession ffprobeSession) { + public static void asyncFFprobeExecute(final FFprobeSession ffprobeSession) { AsyncFFprobeExecuteTask asyncFFmpegExecuteTask = new AsyncFFprobeExecuteTask(ffprobeSession); Future future = asyncExecutorService.submit(asyncFFmpegExecuteTask); ffprobeSession.setFuture(future); } + /** + *

Asynchronously executes the FFprobe session provided. + * + * @param ffprobeSession FFprobe session which includes command options/arguments + * @param executorService executor service that will be used to run this asynchronous operation + */ + public static void asyncFFprobeExecute(final FFprobeSession ffprobeSession, final ExecutorService executorService) { + AsyncFFprobeExecuteTask asyncFFmpegExecuteTask = new AsyncFFprobeExecuteTask(ffprobeSession); + Future future = executorService.submit(asyncFFmpegExecuteTask); + ffprobeSession.setFuture(future); + } + /** *

Asynchronously executes the media information session provided. * * @param mediaInformationSession media information session which includes command options/arguments * @param waitTimeout max time to wait until media information is transmitted */ - static void asyncGetMediaInformationExecute(final MediaInformationSession mediaInformationSession, final Integer waitTimeout) { + public static void asyncGetMediaInformationExecute(final MediaInformationSession mediaInformationSession, final int waitTimeout) { AsyncGetMediaInformationTask asyncGetMediaInformationTask = new AsyncGetMediaInformationTask(mediaInformationSession, waitTimeout); Future future = asyncExecutorService.submit(asyncGetMediaInformationTask); mediaInformationSession.setFuture(future); } /** - * Returns the maximum number of async operations that will be executed in parallel. + *

Asynchronously executes the media information session provided. * - * @return maximum number of async operations that will be executed in parallel + * @param mediaInformationSession media information session which includes command options/arguments + * @param executorService executor service that will be used to run this asynchronous operation + * @param waitTimeout max time to wait until media information is transmitted + */ + public static void asyncGetMediaInformationExecute(final MediaInformationSession mediaInformationSession, final ExecutorService executorService, final int waitTimeout) { + AsyncGetMediaInformationTask asyncGetMediaInformationTask = new AsyncGetMediaInformationTask(mediaInformationSession, waitTimeout); + Future future = executorService.submit(asyncGetMediaInformationTask); + mediaInformationSession.setFuture(future); + } + + /** + * Returns the maximum number of async sessions that will be executed in parallel. + * + * @return maximum number of async sessions that will be executed in parallel */ public static int getAsyncConcurrencyLimit() { return asyncConcurrencyLimit; } /** - * Sets the maximum number of async operations that will be executed in parallel. If more - * operations are submitted those will be queued. + * Sets the maximum number of async sessions that will be executed in parallel. If more + * sessions are submitted those will be queued. * * @param asyncConcurrencyLimit new async concurrency limit */ @@ -843,17 +763,17 @@ public class FFmpegKitConfig { /** *

Sets a global callback function to redirect FFmpeg/FFprobe logs. * - * @param newLogCallback new log callback function or null to disable a previously defined - * callback + * @param logCallback log callback function or null to disable a previously defined + * callback */ - public static void enableLogCallback(final LogCallback newLogCallback) { - globalLogCallbackFunction = newLogCallback; + public static void enableLogCallback(final LogCallback logCallback) { + globalLogCallbackFunction = logCallback; } /** *

Sets a global callback function to redirect FFmpeg statistics. * - * @param statisticsCallback new statistics callback function or null to disable a previously + * @param statisticsCallback statistics callback function or null to disable a previously * defined callback */ public static void enableStatisticsCallback(final StatisticsCallback statisticsCallback) { @@ -863,7 +783,7 @@ public class FFmpegKitConfig { /** *

Sets a global callback function to receive execution results. * - * @param executeCallback new execute callback function or null to disable a previously + * @param executeCallback execute callback function or null to disable a previously * defined callback */ public static void enableExecuteCallback(final ExecuteCallback executeCallback) { @@ -871,11 +791,11 @@ public class FFmpegKitConfig { } /** - *

Returns global execute callback function. + *

Returns the global execute callback function. * * @return global execute callback function */ - static ExecuteCallback getGlobalExecuteCallbackFunction() { + static ExecuteCallback getExecuteCallback() { return globalExecuteCallbackFunction; } @@ -902,7 +822,7 @@ public class FFmpegKitConfig { /** *

Converts the given Structured Access Framework Uri ("content:…") into an - * input/output url that can be used in FFmpegKit and FFprobeKit. + * input/output url that can be used in FFmpeg and FFprobe commands. * *

Requires API Level >= 19. On older API levels it returns an empty url. * @@ -944,7 +864,7 @@ public class FFmpegKitConfig { /** *

Converts the given Structured Access Framework Uri ("content:…") into an - * input url that can be used in FFmpegKit and FFprobeKit. + * input url that can be used in FFmpeg and FFprobe commands. * *

Requires API Level >= 19. On older API levels it returns an empty url. * @@ -956,7 +876,7 @@ public class FFmpegKitConfig { /** *

Converts the given Structured Access Framework Uri ("content:…") into an - * output url that can be used in FFmpegKit and FFprobeKit. + * output url that can be used in FFmpeg and FFprobe commands. * *

Requires API Level >= 19. On older API levels it returns an empty url. * @@ -967,7 +887,7 @@ public class FFmpegKitConfig { } /** - * Called by saf_wrapper from JNI/native part to close a parcel file descriptor. + * Called by saf_wrapper from native library to close a parcel file descriptor. * * @param fd parcel file descriptor created for a saf uri */ @@ -995,7 +915,7 @@ public class FFmpegKitConfig { /** * Sets the session history size. * - * @param sessionHistorySize new session history size, should be smaller than 1000 + * @param sessionHistorySize session history size, should be smaller than 1000 */ public static void setSessionHistorySize(final int sessionHistorySize) { if (sessionHistorySize >= 1000) { @@ -1004,8 +924,9 @@ public class FFmpegKitConfig { * THERE IS A HARD LIMIT ON THE NATIVE SIDE. HISTORY SIZE MUST BE SMALLER THAN 1000 */ throw new IllegalArgumentException("Session history size must not exceed the hard limit!"); + } else if (sessionHistorySize > 0) { + FFmpegKitConfig.sessionHistorySize = sessionHistorySize; } - FFmpegKitConfig.sessionHistorySize = sessionHistorySize; } /** @@ -1016,19 +937,18 @@ public class FFmpegKitConfig { static void addSession(final Session session) { synchronized (sessionHistoryLock) { sessionHistoryMap.put(session.getSessionId(), session); - sessionHistoryQueue.offer(session); - - if (sessionHistoryQueue.size() > sessionHistorySize) { - final Session oldestElement = sessionHistoryQueue.poll(); - if (oldestElement != null) { - sessionHistoryMap.remove(oldestElement.getSessionId()); + sessionHistoryList.add(session); + if (sessionHistoryList.size() > sessionHistorySize) { + try { + sessionHistoryList.remove(0); + } catch (final IndexOutOfBoundsException ignored) { } } } } /** - * Returns the session specified with sessionId from the session history. + * Returns the session specified with sessionId from the session history. * * @param sessionId session identifier * @return session specified with sessionId or null if it is not found in the history @@ -1040,14 +960,37 @@ public class FFmpegKitConfig { } /** - * Returns the last session from the session history. + * Returns the last session created from the session history. * - * @return the last session from the session history + * @return the last session created or null if session history is empty */ public static Session getLastSession() { synchronized (sessionHistoryLock) { - return sessionHistoryQueue.peek(); + if (sessionHistoryList.size() > 0) { + return sessionHistoryList.get(sessionHistoryList.size() - 1); + } + } + + return null; + } + + /** + * Returns the last session completed from the session history. + * + * @return the last session completed. If there are no completed sessions in the history this + * method will return null + */ + public static Session getLastCompletedSession() { + synchronized (sessionHistoryLock) { + for (int i = sessionHistoryList.size() - 1; i >= 0; i--) { + final Session session = sessionHistoryList.get(i); + if (session.getState() == SessionState.COMPLETED) { + return session; + } + } } + + return null; } /** @@ -1057,7 +1000,7 @@ public class FFmpegKitConfig { */ public static List getSessions() { synchronized (sessionHistoryLock) { - return new LinkedList<>(sessionHistoryQueue); + return new LinkedList<>(sessionHistoryList); } } @@ -1070,7 +1013,7 @@ public class FFmpegKitConfig { final LinkedList list = new LinkedList<>(); synchronized (sessionHistoryLock) { - for (Session session : sessionHistoryQueue) { + for (Session session : sessionHistoryList) { if (session.isFFmpeg()) { list.add((FFmpegSession) session); } @@ -1089,7 +1032,7 @@ public class FFmpegKitConfig { final LinkedList list = new LinkedList<>(); synchronized (sessionHistoryLock) { - for (Session session : sessionHistoryQueue) { + for (Session session : sessionHistoryList) { if (session.isFFprobe()) { list.add((FFprobeSession) session); } @@ -1108,7 +1051,7 @@ public class FFmpegKitConfig { final LinkedList list = new LinkedList<>(); synchronized (sessionHistoryLock) { - for (Session session : sessionHistoryQueue) { + for (Session session : sessionHistoryList) { if (session.getState() == state) { list.add(session); } @@ -1124,25 +1067,25 @@ public class FFmpegKitConfig { * @return log redirection strategy */ public static LogRedirectionStrategy getLogRedirectionStrategy() { - return logRedirectionStrategy; + return globalLogRedirectionStrategy; } /** *

Sets the log redirection strategy * - * @param logRedirectionStrategy new log redirection strategy + * @param logRedirectionStrategy log redirection strategy */ public static void setLogRedirectionStrategy(final LogRedirectionStrategy logRedirectionStrategy) { - FFmpegKitConfig.logRedirectionStrategy = logRedirectionStrategy; + FFmpegKitConfig.globalLogRedirectionStrategy = logRedirectionStrategy; } /** - *

Enables native redirection. Necessary for log and statistics callback functions. + *

Enables redirection natively. */ private static native void enableNativeRedirection(); /** - *

Disables native redirection + *

Disables redirection natively. */ private static native void disableNativeRedirection(); @@ -1151,7 +1094,7 @@ public class FFmpegKitConfig { * * @return log level */ - private static native int getNativeLogLevel(); + static native int getNativeLogLevel(); /** * Sets native log level @@ -1185,14 +1128,6 @@ public class FFmpegKitConfig { */ private native static int nativeFFmpegExecute(final long sessionId, final String[] arguments); - /** - *

Cancels an ongoing FFmpeg operation natively. This function does not wait for termination - * to complete and returns immediately. - * - * @param sessionId id of the session - */ - native static void nativeFFmpegCancel(final long sessionId); - /** *

Synchronously executes FFprobe natively. * @@ -1205,14 +1140,22 @@ public class FFmpegKitConfig { native static int nativeFFprobeExecute(final long sessionId, final String[] arguments); /** - *

Returns the number of native messages which are not transmitted to the Java callbacks for + *

Cancels an ongoing FFmpeg operation natively. This function does not wait for termination + * to complete and returns immediately. + * + * @param sessionId id of the session + */ + native static void nativeFFmpegCancel(final long sessionId); + + /** + *

Returns the number of native messages that are not transmitted to the Java callbacks for * this session natively. * * @param sessionId id of the session - * @return number of native messages which are not transmitted to the Java callbacks for + * @return number of native messages that are not transmitted to the Java callbacks for * this session natively */ - native static int messagesInTransmit(final long sessionId); + public native static int messagesInTransmit(final long sessionId); /** *

Creates a new named pipe to use in FFmpeg operations natively. @@ -1241,7 +1184,8 @@ public class FFmpegKitConfig { private native static int setNativeEnvironmentVariable(final String variableName, final String variableValue); /** - *

Registers a new ignored signal natively. Ignored signals are not handled by the library. + *

Registers a new ignored signal natively. Ignored signals are not handled by + * FFmpegKit library. * * @param signum signal number */ diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegSession.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegSession.java index b9c2fe8..8bc0e8d 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegSession.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegSession.java @@ -19,48 +19,160 @@ package com.arthenica.ffmpegkit; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.LinkedList; +import java.util.List; /** - *

An FFmpeg execute session. + *

An FFmpeg session. */ public class FFmpegSession extends AbstractSession implements Session { - private final Queue statistics; + /** + * Session specific statistics callback function. + */ + private final StatisticsCallback statisticsCallback; + + /** + * Statistics entries received for this session. + */ + private final List statistics; + + /** + * Statistics entry lock. + */ + private final Object statisticsLock; + + /** + * Builds a new FFmpeg session. + * + * @param arguments command arguments + */ + public FFmpegSession(final String[] arguments) { + this(arguments, null); + } + + /** + * Builds a new FFmpeg session. + * + * @param arguments command arguments + * @param executeCallback session specific execute callback function + */ + public FFmpegSession(final String[] arguments, final ExecuteCallback executeCallback) { + this(arguments, executeCallback, null, null); + } + + /** + * Builds a new FFmpeg session. + * + * @param arguments command arguments + * @param executeCallback session specific execute callback function + * @param logCallback session specific log callback function + * @param statisticsCallback session specific statistics callback function + */ public FFmpegSession(final String[] arguments, final ExecuteCallback executeCallback, final LogCallback logCallback, final StatisticsCallback statisticsCallback) { - super(arguments, executeCallback, logCallback, statisticsCallback, FFmpegKitConfig.getLogRedirectionStrategy()); + this(arguments, executeCallback, logCallback, statisticsCallback, FFmpegKitConfig.getLogRedirectionStrategy()); + } + + /** + * Builds a new FFmpeg session. + * + * @param arguments command arguments + * @param executeCallback session specific execute callback function + * @param logCallback session specific log callback function + * @param statisticsCallback session specific statistics callback function + * @param logRedirectionStrategy session specific log redirection strategy + */ + public FFmpegSession(final String[] arguments, + final ExecuteCallback executeCallback, + final LogCallback logCallback, + final StatisticsCallback statisticsCallback, + final LogRedirectionStrategy logRedirectionStrategy) { + super(arguments, executeCallback, logCallback, logRedirectionStrategy); + + this.statisticsCallback = statisticsCallback; - this.statistics = new ConcurrentLinkedQueue<>(); + this.statistics = new LinkedList<>(); + this.statisticsLock = new Object(); } - @Override - public Queue getAllStatistics(final int waitTimeout) { - waitForCallbackMessagesInTransmit(waitTimeout); + /** + * Returns the session specific statistics callback function. + * + * @return session specific statistics callback function + */ + public StatisticsCallback getStatisticsCallback() { + return statisticsCallback; + } - if (thereAreCallbackMessagesInTransmit()) { - android.util.Log.i(FFmpegKitConfig.TAG, String.format("getAllStatistics was asked to return all statistics but there are still statistics being transmitted for session id %d.", sessionId)); + /** + * Returns all statistics entries generated for this session. If there are asynchronous + * messages that are not delivered yet, this method waits for them until the given timeout. + * + * @param waitTimeout wait timeout for asynchronous messages in milliseconds + * @return list of statistics entries generated for this session + */ + public List getAllStatistics(final int waitTimeout) { + waitForAsynchronousMessagesInTransmit(waitTimeout); + + if (thereAreAsynchronousMessagesInTransmit()) { + android.util.Log.i(FFmpegKitConfig.TAG, String.format("getAllStatistics was called to return all statistics but there are still statistics being transmitted for session id %d.", sessionId)); } return getStatistics(); } - @Override - public Queue getAllStatistics() { - return getAllStatistics(DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT); + /** + * Returns all statistics entries generated for this session. If there are asynchronous + * messages that are not delivered yet, this method waits for them until + * {@link #DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT} expires. + * + * @return list of statistics entries generated for this session + */ + public List getAllStatistics() { + return getAllStatistics(DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT); } - @Override - public Queue getStatistics() { - return statistics; + /** + * Returns all statistics entries delivered for this session. Note that if there are + * asynchronous messages that are not delivered yet, this method will not wait for + * them and will return immediately. + * + * @return list of statistics entries received for this session + */ + public List getStatistics() { + synchronized (statisticsLock) { + return statistics; + } } - @Override + /** + * Returns the last received statistics entry. + * + * @return the last received statistics entry or null if there are not any statistics entries + * received + */ + public Statistics getLastReceivedStatistics() { + synchronized (statisticsLock) { + if (statistics.size() > 0) { + return statistics.get(0); + } else { + return null; + } + } + } + + /** + * Adds a new statistics entry for this session. + * + * @param statistics statistics entry + */ public void addStatistics(final Statistics statistics) { - this.statistics.add(statistics); + synchronized (statisticsLock) { + this.statistics.add(statistics); + } } @Override diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFprobeKit.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFprobeKit.java index da5f00d..a8e5b6d 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFprobeKit.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFprobeKit.java @@ -20,19 +20,23 @@ package com.arthenica.ffmpegkit; import java.util.List; -import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; /** - *

Main class for FFprobe operations. - *

Supports running FFprobe commands using {@link #execute(String...)} method. + *

Main class to run FFprobe commands. Supports executing commands both + * synchronously and asynchronously. *

- *      FFprobeSession session = FFprobe.execute("-hide_banner -v error -show_entries format=size -of default=noprint_wrappers=1 file1.mp4");
- *      Log.i(FFmpegKitConfig.TAG, String.format("Command execution %s.", (session.getReturnCode() == 0?"completed successfully":"failed with rc=" + session.getReturnCode()));
+ * FFprobeSession session = FFprobeKit.execute("-hide_banner -v error -show_entries format=size -of default=noprint_wrappers=1 file1.mp4");
+ *
+ * FFprobeSession asyncSession = FFprobeKit.executeAsync("-hide_banner -v error -show_entries format=size -of default=noprint_wrappers=1 file1.mp4", executeCallback);
+ * 
+ *

Provides overloaded execute methods to define session specific callbacks. + *

+ * FFprobeSession session = FFprobeKit.executeAsync("-hide_banner -v error -show_entries format=size -of default=noprint_wrappers=1 file1.mp4", executeCallback, logCallback);
  * 
- *

It can also extract media information for a file or a url, using {@link #getMediaInformation(String)} method. + *

It can extract media information for a file or a url, using {@link #getMediaInformation(String)} method. *

- *      MediaInformationSession session = FFprobe.getMediaInformation("file1.mp4");
- *      Log.i(FFmpegKitConfig.TAG, String.format("Media information %s.", (session.getReturnCode() == 0?"extracted successfully":"was not extracted due to rc=" + session.getReturnCode()));
+ *      MediaInformationSession session = FFprobeKit.getMediaInformation("file1.mp4");
  * 
*/ public class FFprobeKit { @@ -52,10 +56,10 @@ public class FFprobeKit { *

Synchronously executes FFprobe with arguments provided. * * @param arguments FFprobe command options/arguments as string array - * @return ffprobe session created for this execution + * @return FFprobe session created for this execution */ public static FFprobeSession execute(final String[] arguments) { - final FFprobeSession session = new FFprobeSession(arguments, null, null, null); + final FFprobeSession session = new FFprobeSession(arguments); FFmpegKitConfig.ffprobeExecute(session); @@ -63,41 +67,33 @@ public class FFprobeKit { } /** - *

Synchronously executes FFprobe command provided. Space character is used to split command - * into arguments. You can use single and double quote characters to specify arguments inside - * your command. - * - * @param command FFprobe command - * @return ffprobe session created for this execution - */ - public static FFprobeSession execute(final String command) { - return execute(FFmpegKit.parseArguments(command)); - } - - /** - *

Asynchronously executes FFprobe command provided. Space character is used to split command - * into arguments. You can use single and double quote characters to specify arguments inside - * your command. + *

Asynchronously executes FFprobe with arguments provided. * - * @param command FFprobe command - * @param executeCallback callback that will be notified when the execution is completed - * @return ffprobe session created for this execution + * @param arguments FFprobe command options/arguments as string array + * @param executeCallback callback that will be called when the execution is completed + * @return FFprobe session created for this execution */ - public static FFprobeSession executeAsync(final String command, + public static FFprobeSession executeAsync(final String[] arguments, final ExecuteCallback executeCallback) { - return executeAsync(FFmpegKit.parseArguments(command), executeCallback); + final FFprobeSession session = new FFprobeSession(arguments, executeCallback); + + FFmpegKitConfig.asyncFFprobeExecute(session); + + return session; } /** *

Asynchronously executes FFprobe with arguments provided. * * @param arguments FFprobe command options/arguments as string array - * @param executeCallback callback that will be notified when the execution is completed - * @return ffprobe session created for this execution + * @param executeCallback callback that will be notified when execution is completed + * @param logCallback callback that will receive logs + * @return FFprobe session created for this execution */ public static FFprobeSession executeAsync(final String[] arguments, - final ExecuteCallback executeCallback) { - final FFprobeSession session = new FFprobeSession(arguments, executeCallback, null, null); + final ExecuteCallback executeCallback, + final LogCallback logCallback) { + final FFprobeSession session = new FFprobeSession(arguments, executeCallback, logCallback); FFmpegKitConfig.asyncFFprobeExecute(session); @@ -105,147 +101,187 @@ public class FFprobeKit { } /** - *

Asynchronously executes FFprobe command provided. Space character is used to split command - * into arguments. You can use single and double quote characters to specify arguments inside - * your command. + *

Asynchronously executes FFprobe with arguments provided. * - * @param command FFprobe command - * @param executeCallback callback that will be notified when execution is completed - * @param logCallback callback that will receive log entries - * @param statisticsCallback callback that will receive statistics - * @return ffprobe session created for this execution + * @param arguments FFprobe command options/arguments as string array + * @param executeCallback callback that will be called when the execution is completed + * @param executorService executor service that will be used to run this asynchronous operation + * @return FFprobe session created for this execution */ - public static FFprobeSession executeAsync(final String command, + public static FFprobeSession executeAsync(final String[] arguments, final ExecuteCallback executeCallback, - final LogCallback logCallback, - final StatisticsCallback statisticsCallback) { - return executeAsync(FFmpegKit.parseArguments(command), executeCallback, logCallback, statisticsCallback); + final ExecutorService executorService) { + final FFprobeSession session = new FFprobeSession(arguments, executeCallback); + + FFmpegKitConfig.asyncFFprobeExecute(session, executorService); + + return session; } /** *

Asynchronously executes FFprobe with arguments provided. * - * @param arguments FFprobe command options/arguments as string array - * @param executeCallback callback that will be notified when execution is completed - * @param logCallback callback that will receive log entries - * @param statisticsCallback callback that will receive statistics - * @return ffprobe session created for this execution + * @param arguments FFprobe command options/arguments as string array + * @param executeCallback callback that will be notified when execution is completed + * @param logCallback callback that will receive logs + * @param executorService executor service that will be used to run this asynchronous operation + * @return FFprobe session created for this execution */ public static FFprobeSession executeAsync(final String[] arguments, final ExecuteCallback executeCallback, final LogCallback logCallback, - final StatisticsCallback statisticsCallback) { - final FFprobeSession session = new FFprobeSession(arguments, executeCallback, logCallback, statisticsCallback); + final ExecutorService executorService) { + final FFprobeSession session = new FFprobeSession(arguments, executeCallback, logCallback); - FFmpegKitConfig.asyncFFprobeExecute(session); + FFmpegKitConfig.asyncFFprobeExecute(session, executorService); return session; } /** - *

Asynchronously executes FFprobe with arguments provided. + *

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. * - * @param arguments FFprobe command options/arguments as string array - * @param executeCallback callback that will be notified when the execution is completed - * @param executor executor that will be used to run this asynchronous operation - * @return ffprobe session created for this execution + * @param command FFprobe command + * @return FFprobe session created for this execution */ - public static FFprobeSession executeAsync(final String[] arguments, - final ExecuteCallback executeCallback, - final Executor executor) { - final FFprobeSession session = new FFprobeSession(arguments, executeCallback, null, null); + public static FFprobeSession execute(final String command) { + return execute(FFmpegKit.parseArguments(command)); + } - AsyncFFprobeExecuteTask asyncFFprobeExecuteTask = new AsyncFFprobeExecuteTask(session); - executor.execute(asyncFFprobeExecuteTask); + /** + *

Asynchronously 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. + * + * @param command FFprobe command + * @param executeCallback callback that will be called when the execution is completed + * @return FFprobe session created for this execution + */ + public static FFprobeSession executeAsync(final String command, + final ExecuteCallback executeCallback) { + return executeAsync(FFmpegKit.parseArguments(command), executeCallback); + } - return session; + /** + *

Asynchronously 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. + * + * @param command FFprobe command + * @param executeCallback callback that will be notified when execution is completed + * @param logCallback callback that will receive logs + * @return FFprobe session created for this execution + */ + public static FFprobeSession executeAsync(final String command, + final ExecuteCallback executeCallback, + final LogCallback logCallback) { + return executeAsync(FFmpegKit.parseArguments(command), executeCallback, logCallback); } /** - *

Asynchronously executes FFprobe with arguments provided. + *

Asynchronously 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. * - * @param arguments FFprobe command options/arguments as string array - * @param executeCallback callback that will be notified when execution is completed - * @param logCallback callback that will receive log entries - * @param statisticsCallback callback that will receive statistics - * @param executor executor that will be used to run this asynchronous operation - * @return ffprobe session created for this execution + * @param command FFprobe command + * @param executeCallback callback that will be called when the execution is completed + * @param executorService executor service that will be used to run this asynchronous operation + * @return FFprobe session created for this execution */ - public static FFprobeSession executeAsync(final String[] arguments, + public static FFprobeSession executeAsync(final String command, final ExecuteCallback executeCallback, - final LogCallback logCallback, - final StatisticsCallback statisticsCallback, - final Executor executor) { - final FFprobeSession session = new FFprobeSession(arguments, executeCallback, logCallback, statisticsCallback); + final ExecutorService executorService) { + final FFprobeSession session = new FFprobeSession(FFmpegKit.parseArguments(command), executeCallback); - AsyncFFprobeExecuteTask asyncFFprobeExecuteTask = new AsyncFFprobeExecuteTask(session); - executor.execute(asyncFFprobeExecuteTask); + FFmpegKitConfig.asyncFFprobeExecute(session, executorService); return session; } /** - *

Lists all FFprobe sessions in the session history + *

Asynchronously 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. * - * @return all FFprobe sessions in the session history + * @param command FFprobe command + * @param executeCallback callback that will be called when the execution is completed + * @param logCallback callback that will receive logs + * @param executorService executor service that will be used to run this asynchronous operation + * @return FFprobe session created for this execution */ - public static List listSessions() { - return FFmpegKitConfig.getFFprobeSessions(); + public static FFprobeSession executeAsync(final String command, + final ExecuteCallback executeCallback, + final LogCallback logCallback, + final ExecutorService executorService) { + final FFprobeSession session = new FFprobeSession(FFmpegKit.parseArguments(command), executeCallback, logCallback); + + FFmpegKitConfig.asyncFFprobeExecute(session, executorService); + + return session; } /** - *

Returns media information for the given path. + *

Extracts media information for the file specified with path. * * @param path path or uri of a media file * @return media information session created for this execution */ public static MediaInformationSession getMediaInformation(final String path) { - return getMediaInformationFromCommandArguments(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, null, null, null, AbstractSession.DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT); + final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}); + + FFmpegKitConfig.getMediaInformationExecute(session, AbstractSession.DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT); + + return session; } /** - *

Returns media information for the given path. + *

Extracts media information for the file specified with path. * * @param path path or uri of a media file * @param waitTimeout max time to wait until media information is transmitted * @return media information session created for this execution */ - public static MediaInformationSession getMediaInformation(final String path, final Integer waitTimeout) { - return getMediaInformationFromCommandArguments(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, null, null, null, waitTimeout); + public static MediaInformationSession getMediaInformation(final String path, + final int waitTimeout) { + final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}); + + FFmpegKitConfig.getMediaInformationExecute(session, waitTimeout); + + return session; } /** - *

Returns media information for the given path asynchronously. + *

Extracts media information for the file specified with path asynchronously. * * @param path path or uri of a media file - * @param executeCallback callback that will be notified when the execution is completed + * @param executeCallback callback that will be called when the execution is completed * @return media information session created for this execution */ public static MediaInformationSession getMediaInformationAsync(final String path, final ExecuteCallback executeCallback) { - final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback, null, null); + final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback); - FFmpegKitConfig.asyncGetMediaInformationExecute(session, AbstractSession.DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT); + FFmpegKitConfig.asyncGetMediaInformationExecute(session, AbstractSession.DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT); return session; } /** - *

Returns media information for the given path asynchronously. + *

Extracts media information for the file specified with path asynchronously. * - * @param path path or uri of a media file - * @param executeCallback callback that will be notified when execution is completed - * @param logCallback callback that will receive log entries - * @param statisticsCallback callback that will receive statistics - * @param waitTimeout max time to wait until media information is transmitted + * @param path path or uri of a media file + * @param executeCallback callback that will be notified when execution is completed + * @param logCallback callback that will receive logs + * @param waitTimeout max time to wait until media information is transmitted * @return media information session created for this execution */ public static MediaInformationSession getMediaInformationAsync(final String path, final ExecuteCallback executeCallback, final LogCallback logCallback, - final StatisticsCallback statisticsCallback, - final Integer waitTimeout) { - final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback, logCallback, statisticsCallback); + final int waitTimeout) { + final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback, logCallback); FFmpegKitConfig.asyncGetMediaInformationExecute(session, waitTimeout); @@ -253,88 +289,102 @@ public class FFprobeKit { } /** - *

Returns media information for the given path asynchronously. + *

Extracts media information for the file specified with path asynchronously. * * @param path path or uri of a media file - * @param executeCallback callback that will be notified when the execution is completed - * @param executor executor that will be used to run this asynchronous operation + * @param executeCallback callback that will be called when the execution is completed + * @param executorService executor service that will be used to run this asynchronous operation * @return media information session created for this execution */ public static MediaInformationSession getMediaInformationAsync(final String path, final ExecuteCallback executeCallback, - final Executor executor) { - final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback, null, null); + final ExecutorService executorService) { + final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback); - AsyncGetMediaInformationTask asyncGetMediaInformationTask = new AsyncGetMediaInformationTask(session); - executor.execute(asyncGetMediaInformationTask); + FFmpegKitConfig.asyncGetMediaInformationExecute(session, executorService, AbstractSession.DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT); return session; } /** - *

Returns media information for the given path asynchronously. + *

Extracts media information for the file specified with path asynchronously. * - * @param path path or uri of a media file - * @param executeCallback callback that will be notified when execution is completed - * @param logCallback callback that will receive log entries - * @param statisticsCallback callback that will receive statistics - * @param executor executor that will be used to run this asynchronous operation - * @param waitTimeout max time to wait until media information is transmitted + * @param path path or uri of a media file + * @param executeCallback callback that will be notified when execution is completed + * @param logCallback callback that will receive logs + * @param executorService executor service that will be used to run this asynchronous operation + * @param waitTimeout max time to wait until media information is transmitted * @return media information session created for this execution */ public static MediaInformationSession getMediaInformationAsync(final String path, final ExecuteCallback executeCallback, final LogCallback logCallback, - final StatisticsCallback statisticsCallback, - final Executor executor, - final Integer waitTimeout) { - final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback, logCallback, statisticsCallback); + final ExecutorService executorService, + final int waitTimeout) { + final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback, logCallback); - AsyncGetMediaInformationTask asyncGetMediaInformationTask = new AsyncGetMediaInformationTask(session, waitTimeout); - executor.execute(asyncGetMediaInformationTask); + FFmpegKitConfig.asyncGetMediaInformationExecute(session, executorService, waitTimeout); return session; } /** - *

Returns media information for the given command. + *

Extracts media information using the command provided asynchronously. * - * @param command command to execute + * @param command FFprobe command that prints media information for a file in JSON format * @return media information session created for this execution */ public static MediaInformationSession getMediaInformationFromCommand(final String command) { - return getMediaInformationFromCommandArguments(FFmpegKit.parseArguments(command), null, null, null, AbstractSession.DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT); - } + final MediaInformationSession session = new MediaInformationSession(FFmpegKit.parseArguments(command)); + + FFmpegKitConfig.asyncGetMediaInformationExecute(session, AbstractSession.DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT); + return session; + } /** - *

Returns media information for the given command. + *

Extracts media information using the command provided asynchronously. * - * @param command command to execute - * @param executeCallback callback that will be notified when execution is completed - * @param logCallback callback that will receive log entries - * @param statisticsCallback callback that will receive statistics - * @param waitTimeout max time to wait until media information is transmitted + * @param command FFprobe command that prints media information for a file in JSON format + * @param executeCallback callback that will be notified when execution is completed + * @param logCallback callback that will receive logs + * @param waitTimeout max time to wait until media information is transmitted * @return media information session created for this execution */ - public static MediaInformationSession getMediaInformationFromCommand(final String command, - final ExecuteCallback executeCallback, - final LogCallback logCallback, - final StatisticsCallback statisticsCallback, - final Integer waitTimeout) { - return getMediaInformationFromCommandArguments(FFmpegKit.parseArguments(command), executeCallback, logCallback, statisticsCallback, waitTimeout); + public static MediaInformationSession getMediaInformationFromCommandAsync(final String command, + final ExecuteCallback executeCallback, + final LogCallback logCallback, + final int waitTimeout) { + return getMediaInformationFromCommandArgumentsAsync(FFmpegKit.parseArguments(command), executeCallback, logCallback, waitTimeout); } - private static MediaInformationSession getMediaInformationFromCommandArguments(final String[] arguments, - final ExecuteCallback executeCallback, - final LogCallback logCallback, - final StatisticsCallback statisticsCallback, - final Integer waitTimeout) { - final MediaInformationSession session = new MediaInformationSession(arguments, executeCallback, logCallback, statisticsCallback); + /** + * Extracts media information using the command arguments provided asynchronously. + * + * @param arguments FFprobe command arguments that print media information for a file in JSON format + * @param executeCallback callback that will be notified when execution is completed + * @param logCallback callback that will receive logs + * @param waitTimeout max time to wait until media information is transmitted + * @return media information session created for this execution + */ + private static MediaInformationSession getMediaInformationFromCommandArgumentsAsync(final String[] arguments, + final ExecuteCallback executeCallback, + final LogCallback logCallback, + final int waitTimeout) { + final MediaInformationSession session = new MediaInformationSession(arguments, executeCallback, logCallback); FFmpegKitConfig.getMediaInformationExecute(session, waitTimeout); return session; } + /** + *

Lists all FFprobe sessions in the session history. + * + * @return all FFprobe sessions in the session history + */ + public static List listSessions() { + return FFmpegKitConfig.getFFprobeSessions(); + } + } 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 5f81488..84be6cb 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 @@ -19,52 +19,56 @@ package com.arthenica.ffmpegkit; -import java.text.MessageFormat; -import java.util.LinkedList; -import java.util.Queue; - /** - *

An FFprobe execute session. + *

An FFprobe session. */ public class FFprobeSession extends AbstractSession implements Session { - public FFprobeSession(final String[] arguments, - final ExecuteCallback executeCallback, - final LogCallback logCallback, - final StatisticsCallback statisticsCallback) { - this(arguments, executeCallback, logCallback, statisticsCallback, FFmpegKitConfig.getLogRedirectionStrategy()); - } - - FFprobeSession(final String[] arguments, - final ExecuteCallback executeCallback, - final LogCallback logCallback, - final StatisticsCallback statisticsCallback, - final LogRedirectionStrategy logRedirectionStrategy) { - super(arguments, executeCallback, logCallback, statisticsCallback, logRedirectionStrategy); + /** + * Builds a new FFprobe session. + * + * @param arguments command arguments + */ + public FFprobeSession(final String[] arguments) { + this(arguments, null); } - @Override - public Queue getAllStatistics(final int waitTimeout) { - return new LinkedList<>(); + /** + * Builds a new FFprobe session. + * + * @param arguments command arguments + * @param executeCallback session specific execute callback function + */ + public FFprobeSession(final String[] arguments, final ExecuteCallback executeCallback) { + this(arguments, executeCallback, null); } - @Override - public Queue getAllStatistics() { - return new LinkedList<>(); - } - - @Override - public Queue getStatistics() { - return new LinkedList<>(); + /** + * Builds a new FFprobe session. + * + * @param arguments command arguments + * @param executeCallback session specific execute callback function + * @param logCallback session specific log callback function + */ + FFprobeSession(final String[] arguments, + final ExecuteCallback executeCallback, + final LogCallback logCallback) { + this(arguments, executeCallback, logCallback, FFmpegKitConfig.getLogRedirectionStrategy()); } - @Override - public void addStatistics(final Statistics statistics) { - /* - * ffprobe does not support statistics. - * So, this method should never have been called. - */ - android.util.Log.w(FFmpegKitConfig.TAG, MessageFormat.format("FFprobe execute session {0} received statistics.", sessionId)); + /** + * Builds a new FFprobe session. + * + * @param arguments command arguments + * @param executeCallback session specific execute callback function + * @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) { + super(arguments, executeCallback, logCallback, logRedirectionStrategy); } @Override diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Level.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Level.java index f107b44..3748619 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Level.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Level.java @@ -26,7 +26,7 @@ public enum Level { /** * This log level is defined by FFmpegKit. It is used to specify logs printed to stderr by - * ffmpeg. Logs that has this level are not filtered and always redirected. + * FFmpeg. Logs that has this level are not filtered and always redirected. */ AV_LOG_STDERR(-16), @@ -82,7 +82,7 @@ public enum Level { private final int value; /** - *

Returns enumeration defined by value. + *

Returns the enumeration defined by provided value. * * @param value level value * @return enumeration defined by value @@ -121,7 +121,7 @@ public enum Level { } /** - * Creates new enum. + * Creates a new enum. * * @param value level value */ diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Log.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Log.java index 2b5d09e..86be123 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Log.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Log.java @@ -20,7 +20,7 @@ package com.arthenica.ffmpegkit; /** - *

Log entry for an execute session. + *

Log entry for an FFmpegKit session. */ public class Log { private final long sessionId; diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/LogCallback.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/LogCallback.java index aa10572..e8ce3af 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/LogCallback.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/LogCallback.java @@ -20,7 +20,7 @@ package com.arthenica.ffmpegkit; /** - *

Callback function to receive logs for executions. + *

Callback function that receives logs generated for FFmpegKit sessions. */ @FunctionalInterface public interface LogCallback { diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformationParser.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformationJsonParser.java similarity index 89% rename from android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformationParser.java rename to android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformationJsonParser.java index de5734b..2d78e6c 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformationParser.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformationJsonParser.java @@ -30,16 +30,16 @@ import org.json.JSONObject; import java.util.ArrayList; /** - * Parser for {@link MediaInformation}. + * A parser that constructs {@link MediaInformation} from FFprobe's json output. */ -public class MediaInformationParser { +public class MediaInformationJsonParser { /** - * Extracts MediaInformation from the given ffprobe json output. Note that this + * Extracts MediaInformation from the given FFprobe json output. Note that this * method does not throw {@link JSONException} as {@link #fromWithError(String)} does and * handles errors internally. * - * @param ffprobeJsonOutput ffprobe json output + * @param ffprobeJsonOutput FFprobe json output * @return created {@link MediaInformation} instance of null if a parsing error occurs */ public static MediaInformation from(final String ffprobeJsonOutput) { @@ -52,7 +52,7 @@ public class MediaInformationParser { } /** - * Extracts MediaInformation from the given ffprobe json output. + * Extracts MediaInformation from the given FFprobe json output. * * @param ffprobeJsonOutput ffprobe json output * @return created {@link MediaInformation} instance diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformationSession.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformationSession.java index e5d3fbd..6f3ace6 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformationSession.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformationSession.java @@ -20,24 +20,62 @@ package com.arthenica.ffmpegkit; /** - *

A custom FFprobe execute session, which produces a MediaInformation object - * using the output of the execution. + *

A custom FFprobe session, which produces a MediaInformation object using the + * FFprobe output. */ public class MediaInformationSession extends FFprobeSession implements Session { + + /** + * Media information extracted in the session. + */ private MediaInformation mediaInformation; - public MediaInformationSession(final String[] arguments, - final ExecuteCallback executeCallback, - final LogCallback logCallback, - final StatisticsCallback statisticsCallback) { - super(arguments, executeCallback, logCallback, statisticsCallback, LogRedirectionStrategy.NEVER_PRINT_LOGS); + /** + * Creates a new media information session. + * + * @param arguments command arguments + */ + public MediaInformationSession(final String[] arguments) { + this(arguments, null); + } + + /** + * Creates a new media information session. + * + * @param arguments command arguments + * @param executeCallback session specific execute callback function + */ + public MediaInformationSession(final String[] arguments, final ExecuteCallback executeCallback) { + this(arguments, executeCallback, null); + } + + /** + * Creates a new media information session. + * + * @param arguments command arguments + * @param executeCallback session specific execute callback function + * @param logCallback session specific log callback function + */ + public MediaInformationSession(final String[] arguments, final ExecuteCallback executeCallback, final LogCallback logCallback) { + super(arguments, executeCallback, logCallback, LogRedirectionStrategy.NEVER_PRINT_LOGS); } + /** + * Returns the media information extracted in this session. + * + * @return media information extracted or null if the command failed or the output can not be + * parsed + */ public MediaInformation getMediaInformation() { return mediaInformation; } - public void setMediaInformation(MediaInformation mediaInformation) { + /** + * Sets the media information extracted in this session. + * + * @param mediaInformation media information extracted + */ + public void setMediaInformation(final MediaInformation mediaInformation) { this.mediaInformation = mediaInformation; } diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/NativeLoader.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/NativeLoader.java new file mode 100644 index 0000000..0bea42b --- /dev/null +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/NativeLoader.java @@ -0,0 +1,183 @@ +/* + * 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; + +import android.os.Build; + +import com.arthenica.smartexception.java.Exceptions; + +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +/** + *

Responsible of loading native libraries. + */ +public class NativeLoader { + + static final String[] FFMPEG_LIBRARIES = {"avutil", "swscale", "swresample", "avcodec", "avformat", "avfilter", "avdevice"}; + + static boolean isTestModeDisabled() { + return (System.getProperty("enable.ffmpeg.kit.test.mode") == null); + } + + private static void loadLibrary(final String libraryName) { + if (isTestModeDisabled()) { + System.loadLibrary(libraryName); + } + } + + private static List loadExternalLibraries() { + if (isTestModeDisabled()) { + return Packages.getExternalLibraries(); + } else { + return Collections.emptyList(); + } + } + + private static String loadNativeAbi() { + if (isTestModeDisabled()) { + return AbiDetect.getNativeAbi(); + } else { + return Abi.ABI_X86_64.getName(); + } + } + + static String loadAbi() { + if (isTestModeDisabled()) { + return AbiDetect.getAbi(); + } else { + return Abi.ABI_X86_64.getName(); + } + } + + static String loadPackageName() { + if (isTestModeDisabled()) { + return Packages.getPackageName(); + } else { + return "test"; + } + } + + static String loadVersion() { + final String version = "4.4"; + + if (isTestModeDisabled()) { + return FFmpegKitConfig.getVersion(); + } else if (loadIsLTSBuild()) { + return String.format("%s-lts", version); + } else { + return version; + } + } + + static boolean loadIsLTSBuild() { + if (isTestModeDisabled()) { + return AbiDetect.isNativeLTSBuild(); + } else { + return true; + } + } + + static int loadLogLevel() { + if (isTestModeDisabled()) { + return FFmpegKitConfig.getNativeLogLevel(); + } else { + return Level.AV_LOG_DEBUG.getValue(); + } + } + + static String loadBuildDate() { + if (isTestModeDisabled()) { + return FFmpegKitConfig.getBuildDate(); + } else { + return new SimpleDateFormat("yyyyMMdd").format(new Date()); + } + } + + static void enableRedirection() { + if (isTestModeDisabled()) { + FFmpegKitConfig.enableRedirection(); + } + } + + static void loadFFmpegKitAbiDetect() { + loadLibrary("ffmpegkit_abidetect"); + } + + static boolean loadFFmpeg() { + boolean nativeFFmpegLoaded = false; + boolean nativeFFmpegTriedAndFailed = false; + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + + /* LOADING LINKED LIBRARIES MANUALLY ON API < 21 */ + final List externalLibrariesEnabled = loadExternalLibraries(); + if (externalLibrariesEnabled.contains("tesseract") || externalLibrariesEnabled.contains("x265") || externalLibrariesEnabled.contains("snappy") || externalLibrariesEnabled.contains("openh264") || externalLibrariesEnabled.contains("rubberband")) { + loadLibrary("c++_shared"); + } + + if (AbiDetect.ARM_V7A.equals(loadNativeAbi())) { + try { + for (String ffmpegLibrary : FFMPEG_LIBRARIES) { + loadLibrary(ffmpegLibrary + "_neon"); + } + nativeFFmpegLoaded = true; + } catch (final UnsatisfiedLinkError e) { + android.util.Log.i(FFmpegKitConfig.TAG, String.format("NEON supported armeabi-v7a ffmpeg library not found. Loading default armeabi-v7a library.%s", Exceptions.getStackTraceString(e))); + nativeFFmpegTriedAndFailed = true; + } + } + + if (!nativeFFmpegLoaded) { + for (String ffmpegLibrary : FFMPEG_LIBRARIES) { + loadLibrary(ffmpegLibrary); + } + } + } + + return nativeFFmpegTriedAndFailed; + } + + static void loadFFmpegKit(final boolean nativeFFmpegTriedAndFailed) { + boolean nativeFFmpegKitLoaded = false; + + if (!nativeFFmpegTriedAndFailed && AbiDetect.ARM_V7A.equals(loadNativeAbi())) { + try { + + /* + * THE TRY TO LOAD ARM-V7A-NEON FIRST. IF NOT LOAD DEFAULT ARM-V7A + */ + + loadLibrary("ffmpegkit_armv7a_neon"); + nativeFFmpegKitLoaded = true; + AbiDetect.setArmV7aNeonLoaded(); + } catch (final UnsatisfiedLinkError e) { + android.util.Log.i(FFmpegKitConfig.TAG, String.format("NEON supported armeabi-v7a ffmpegkit library not found. Loading default armeabi-v7a library.%s", Exceptions.getStackTraceString(e))); + } + } + + if (!nativeFFmpegKitLoaded) { + loadLibrary("ffmpegkit"); + } + } + +} diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Packages.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Packages.java index b963238..6f0f271 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Packages.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Packages.java @@ -66,32 +66,11 @@ class Packages { } /** - * Returns enabled external libraries by FFmpeg. - * - * @return enabled external libraries - */ - static List getExternalLibraries() { - final String buildConfiguration = AbiDetect.getNativeBuildConf(); - - final List enabledLibraryList = new ArrayList<>(); - for (String supportedExternalLibrary : supportedExternalLibraries) { - if (buildConfiguration.contains("enable-" + supportedExternalLibrary) || - buildConfiguration.contains("enable-lib" + supportedExternalLibrary)) { - enabledLibraryList.add(supportedExternalLibrary); - } - } - - Collections.sort(enabledLibraryList); - - return enabledLibraryList; - } - - /** - * Returns FFmpegKit binary package name. + * Returns the FFmpegKit binary package name. * - * @return guessed FFmpegKit binary package name + * @return predicted FFmpegKit binary package name */ - static String getPackageName() { + public static String getPackageName() { final List externalLibraryList = getExternalLibraries(); final boolean speex = externalLibraryList.contains("speex"); final boolean fribidi = externalLibraryList.contains("fribidi"); @@ -266,4 +245,25 @@ class Packages { } } + /** + * Returns enabled external libraries by FFmpeg. + * + * @return enabled external libraries + */ + public static List getExternalLibraries() { + final String buildConfiguration = AbiDetect.getNativeBuildConf(); + + final List enabledLibraryList = new ArrayList<>(); + for (String supportedExternalLibrary : supportedExternalLibraries) { + if (buildConfiguration.contains("enable-" + supportedExternalLibrary) || + buildConfiguration.contains("enable-lib" + supportedExternalLibrary)) { + enabledLibraryList.add(supportedExternalLibrary); + } + } + + Collections.sort(enabledLibraryList); + + return enabledLibraryList; + } + } diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/ReturnCode.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/ReturnCode.java index 7affedf..cdd1094 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/ReturnCode.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/ReturnCode.java @@ -21,22 +21,35 @@ package com.arthenica.ffmpegkit; public class ReturnCode { - public static int NOT_SET = -999; - public static int SUCCESS = 0; public static int CANCEL = 255; - public static boolean isSuccess(final int returnCode) { - return (returnCode == SUCCESS); + private final int value; + + public ReturnCode(final int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public boolean isSuccess() { + return (value == SUCCESS); + } + + public boolean isError() { + return ((value != SUCCESS) && (value != CANCEL)); } - public static boolean isFailure(final int returnCode) { - return (returnCode != NOT_SET) && (returnCode != SUCCESS) && (returnCode != CANCEL); + public boolean isCancel() { + return (value == CANCEL); } - public static boolean isCancel(final int returnCode) { - return (returnCode == CANCEL); + @Override + public String toString() { + return String.valueOf(value); } } diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Session.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Session.java index 3bcec42..2dc73fa 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Session.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Session.java @@ -20,80 +20,213 @@ package com.arthenica.ffmpegkit; import java.util.Date; -import java.util.Queue; +import java.util.List; import java.util.concurrent.Future; /** - *

Interface for ffmpeg and ffprobe execute sessions. + *

Common interface for all FFmpegKit sessions. */ public interface Session { + /** + * Returns the session specific execute callback function. + * + * @return session specific execute callback function + */ ExecuteCallback getExecuteCallback(); + /** + * Returns the session specific log callback function. + * + * @return session specific log callback function + */ LogCallback getLogCallback(); - StatisticsCallback getStatisticsCallback(); - + /** + * Returns the session identifier. + * + * @return session identifier + */ long getSessionId(); + /** + * Returns session create time. + * + * @return session create time + */ Date getCreateTime(); + /** + * Returns session start time. + * + * @return session start time + */ Date getStartTime(); + /** + * Returns session end time. + * + * @return session end time + */ Date getEndTime(); + /** + * Returns the time taken to execute this session. + * + * @return time taken to execute this session in milliseconds or zero (0) if the session is + * not over yet + */ long getDuration(); + /** + * Returns command arguments as an array. + * + * @return command arguments as an array + */ String[] getArguments(); + /** + * Returns command arguments as a concatenated string. + * + * @return command arguments as a concatenated string + */ String getCommand(); - Queue getAllLogs(final int waitTimeout); - - Queue getAllLogs(); - - Queue getLogs(); - + /** + * Returns all log entries generated for this session. If there are asynchronous + * messages that are not delivered yet, this method waits for them until the given timeout. + * + * @param waitTimeout wait timeout for asynchronous messages in milliseconds + * @return list of log entries generated for this session + */ + List getAllLogs(final int waitTimeout); + + /** + * Returns all log entries generated for this session. If there are asynchronous + * messages that are not delivered yet, this method waits for them. + * + * @return list of log entries generated for this session + */ + List getAllLogs(); + + /** + * Returns all log entries delivered for this session. Note that if there are asynchronous log + * messages that are not delivered yet, this method will not wait for them and will return + * immediately. + * + * @return list of log entries received for this session + */ + List getLogs(); + + /** + * Returns all log entries generated for this session as a concatenated string. If there are + * asynchronous messages that are not delivered yet, this method waits for them until + * the given timeout. + * + * @param waitTimeout wait timeout for asynchronous messages in milliseconds + * @return all log entries generated for this session as a concatenated string + */ String getAllLogsAsString(final int waitTimeout); + /** + * Returns all log entries generated for this session as a concatenated string. If there are + * asynchronous messages that are not delivered yet, this method waits for them. + * + * @return all log entries generated for this session as a concatenated string + */ String getAllLogsAsString(); + /** + * Returns all log entries delivered for this session as a concatenated string. Note that if + * there are asynchronous log messages that are not delivered yet, this method will not wait + * for them and will return immediately. + * + * @return list of log entries received for this session + */ String getLogsAsString(); - Queue getAllStatistics(final int waitTimeout); - - Queue getAllStatistics(); - - Queue getStatistics(); - + /** + * Returns the log output generated while running the session. + * + * @return log output generated + */ + String getOutput(); + + /** + * Returns the state of the session. + * + * @return state of the session + */ SessionState getState(); - int getReturnCode(); - + /** + * Returns the return code for this session. Note that return code is only set for sessions + * that end with COMPLETED state. If a session is not started, still running or failed then + * this method returns null. + * + * @return the return code for this session if the session is COMPLETED, null if session is + * not started, still running or failed + */ + ReturnCode getReturnCode(); + + /** + * Returns the stack trace of the exception received while executing this session. + *

+ * The stack trace is only set for sessions that end with FAILED state. For sessions that has + * COMPLETED state this method returns null. + * + * @return stack trace of the exception received while executing this session, null if session + * is not started, still running or completed + */ String getFailStackTrace(); + /** + * Returns session specific log redirection strategy. + * + * @return session specific log redirection strategy + */ LogRedirectionStrategy getLogRedirectionStrategy(); - boolean thereAreCallbackMessagesInTransmit(); - + /** + * Returns whether there are still asynchronous messages being transmitted for this + * session or not. + * + * @return true if there are still asynchronous messages being transmitted, false + * otherwise + */ + boolean thereAreAsynchronousMessagesInTransmit(); + + /** + * Adds a new log entry for this session. + * + * @param log log entry + */ void addLog(final Log log); - void addStatistics(final Statistics statistics); - + /** + * Returns the future created for this session, if it is executed asynchronously. + * + * @return future that runs this session asynchronously + */ Future getFuture(); - void setFuture(final Future future); - - void startRunning(); - - void complete(final int returnCode); - - void fail(final Exception exception); - + /** + * Returns whether it is an FFmpeg session or not. + * + * @return true if it is an FFmpeg session, false otherwise + */ boolean isFFmpeg(); + /** + * Returns whether it is an FFprobe session or not. + * + * @return true if it is an FFprobe session, false otherwise + */ boolean isFFprobe(); + /** + * Cancels running the session. + */ void cancel(); } diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Statistics.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Statistics.java index 710c62f..f65f1f7 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Statistics.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Statistics.java @@ -32,17 +32,6 @@ public class Statistics { private double bitrate; private double speed; - public Statistics() { - sessionId = 0; - videoFrameNumber = 0; - videoFps = 0; - videoQuality = 0; - size = 0; - time = 0; - bitrate = 0; - speed = 0; - } - public Statistics(final long sessionId, final int videoFrameNumber, final float videoFps, final float videoQuality, final long size, final int time, final double bitrate, final double speed) { this.sessionId = sessionId; this.videoFrameNumber = videoFrameNumber; diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/StatisticsCallback.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/StatisticsCallback.java index 940a74d..3902465 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/StatisticsCallback.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/StatisticsCallback.java @@ -20,7 +20,7 @@ package com.arthenica.ffmpegkit; /** - *

Callback function to receive statistics for executions. + *

Callback function that receives statistics generated for FFmpegKit sessions. */ @FunctionalInterface public interface StatisticsCallback { diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/StreamInformation.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/StreamInformation.java index 012b712..f0bbc2e 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/StreamInformation.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/StreamInformation.java @@ -27,24 +27,24 @@ import org.json.JSONObject; public class StreamInformation { /* COMMON KEYS */ - private static final String KEY_INDEX = "index"; - private static final String KEY_TYPE = "codec_type"; - private static final String KEY_CODEC = "codec_name"; - private static final String KEY_CODEC_LONG = "codec_long_name"; - private static final String KEY_FORMAT = "pix_fmt"; - private static final String KEY_WIDTH = "width"; - private static final String KEY_HEIGHT = "height"; - private static final String KEY_BIT_RATE = "bit_rate"; - private static final String KEY_SAMPLE_RATE = "sample_rate"; - private static final String KEY_SAMPLE_FORMAT = "sample_fmt"; - private static final String KEY_CHANNEL_LAYOUT = "channel_layout"; - private static final String KEY_SAMPLE_ASPECT_RATIO = "sample_aspect_ratio"; - private static final String KEY_DISPLAY_ASPECT_RATIO = "display_aspect_ratio"; - private static final String KEY_AVERAGE_FRAME_RATE = "avg_frame_rate"; - private static final String KEY_REAL_FRAME_RATE = "r_frame_rate"; - private static final String KEY_TIME_BASE = "time_base"; - private static final String KEY_CODEC_TIME_BASE = "codec_time_base"; - private static final String KEY_TAGS = "tags"; + public static final String KEY_INDEX = "index"; + public static final String KEY_TYPE = "codec_type"; + public static final String KEY_CODEC = "codec_name"; + public static final String KEY_CODEC_LONG = "codec_long_name"; + public static final String KEY_FORMAT = "pix_fmt"; + public static final String KEY_WIDTH = "width"; + public static final String KEY_HEIGHT = "height"; + public static final String KEY_BIT_RATE = "bit_rate"; + public static final String KEY_SAMPLE_RATE = "sample_rate"; + public static final String KEY_SAMPLE_FORMAT = "sample_fmt"; + public static final String KEY_CHANNEL_LAYOUT = "channel_layout"; + public static final String KEY_SAMPLE_ASPECT_RATIO = "sample_aspect_ratio"; + public static final String KEY_DISPLAY_ASPECT_RATIO = "display_aspect_ratio"; + public static final String KEY_AVERAGE_FRAME_RATE = "avg_frame_rate"; + public static final String KEY_REAL_FRAME_RATE = "r_frame_rate"; + public static final String KEY_TIME_BASE = "time_base"; + public static final String KEY_CODEC_TIME_BASE = "codec_time_base"; + public static final String KEY_TAGS = "tags"; /** * Stores all properties. diff --git a/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/AbstractSessionTest.java b/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/AbstractSessionTest.java deleted file mode 100644 index 3c749ba..0000000 --- a/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/AbstractSessionTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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; - -import org.junit.Assert; -import org.junit.Test; - -public class AbstractSessionTest { - - private static final String[] TEST_ARGUMENTS = new String[]{"argument1", "argument2"}; - - @Test - public void getLogsAsStringTest() { - final FFprobeSession ffprobeSession = new FFprobeSession(TEST_ARGUMENTS, null, null, null, LogRedirectionStrategy.ALWAYS_PRINT_LOGS); - - String logMessage1 = "i am log one"; - String logMessage2 = "i am log two"; - - ffprobeSession.addLog(new Log(ffprobeSession.getSessionId(), Level.AV_LOG_DEBUG, logMessage1)); - ffprobeSession.addLog(new Log(ffprobeSession.getSessionId(), Level.AV_LOG_DEBUG, logMessage2)); - - String logsAsString = ffprobeSession.getLogsAsString(); - - Assert.assertEquals(logMessage1 + logMessage2, logsAsString); - } - -} diff --git a/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFmpegKitTest.java b/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFmpegKitTest.java index 96dae1f..198006c 100644 --- a/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFmpegKitTest.java +++ b/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFmpegKitTest.java @@ -445,7 +445,7 @@ public class FFmpegKitTest { @Test public void mediaInformationMp3() { - MediaInformation mediaInformation = MediaInformationParser.from(MEDIA_INFORMATION_MP3); + MediaInformation mediaInformation = MediaInformationJsonParser.from(MEDIA_INFORMATION_MP3); Assert.assertNotNull(mediaInformation); assertMediaInput(mediaInformation, "mp3", "sample.mp3"); @@ -463,7 +463,7 @@ public class FFmpegKitTest { @Test public void mediaInformationJpg() { - MediaInformation mediaInformation = MediaInformationParser.from(MEDIA_INFORMATION_JPG); + MediaInformation mediaInformation = MediaInformationJsonParser.from(MEDIA_INFORMATION_JPG); Assert.assertNotNull(mediaInformation); assertMediaInput(mediaInformation, "image2", "sample.jpg"); @@ -475,7 +475,7 @@ public class FFmpegKitTest { @Test public void mediaInformationGif() { - MediaInformation mediaInformation = MediaInformationParser.from(MEDIA_INFORMATION_GIF); + MediaInformation mediaInformation = MediaInformationJsonParser.from(MEDIA_INFORMATION_GIF); Assert.assertNotNull(mediaInformation); assertMediaInput(mediaInformation, "gif", "sample.gif"); @@ -487,7 +487,7 @@ public class FFmpegKitTest { @Test public void mediaInformationMp4() { - MediaInformation mediaInformation = MediaInformationParser.from(MEDIA_INFORMATION_MP4); + MediaInformation mediaInformation = MediaInformationJsonParser.from(MEDIA_INFORMATION_MP4); Assert.assertNotNull(mediaInformation); assertMediaInput(mediaInformation, "mov,mp4,m4a,3gp,3g2,mj2", "sample.mp4"); @@ -508,7 +508,7 @@ public class FFmpegKitTest { @Test public void mediaInformationPng() { - MediaInformation mediaInformation = MediaInformationParser.from(MEDIA_INFORMATION_PNG); + MediaInformation mediaInformation = MediaInformationJsonParser.from(MEDIA_INFORMATION_PNG); Assert.assertNotNull(mediaInformation); assertMediaInput(mediaInformation, "png_pipe", "sample.png"); @@ -520,7 +520,7 @@ public class FFmpegKitTest { @Test public void mediaInformationOgg() { - MediaInformation mediaInformation = MediaInformationParser.from(MEDIA_INFORMATION_OGG); + MediaInformation mediaInformation = MediaInformationJsonParser.from(MEDIA_INFORMATION_OGG); Assert.assertNotNull(mediaInformation); assertMediaInput(mediaInformation, "ogg", "sample.ogg"); diff --git a/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFmpegSessionTest.java b/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFmpegSessionTest.java new file mode 100644 index 0000000..6f35797 --- /dev/null +++ b/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFmpegSessionTest.java @@ -0,0 +1,350 @@ +/* + * 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; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.List; + +public class FFmpegSessionTest { + + static { + System.setProperty("enable.ffmpeg.kit.test.mode", "true"); + } + + private static final String[] TEST_ARGUMENTS = new String[]{"argument1", "argument2"}; + + @Test + public void constructorTest() { + FFmpegSession ffmpegSession = new FFmpegSession(TEST_ARGUMENTS); + + // 1. getExecuteCallback + Assert.assertNull(ffmpegSession.getExecuteCallback()); + + // 2. getLogCallback + Assert.assertNull(ffmpegSession.getLogCallback()); + + // 3. getStatisticsCallback + Assert.assertNull(ffmpegSession.getStatisticsCallback()); + + // 4. getSessionId + Assert.assertTrue(ffmpegSession.getSessionId() > 0); + + // 5. getCreateTime + Assert.assertTrue(ffmpegSession.getCreateTime().getTime() <= System.currentTimeMillis()); + + // 6. getStartTime + Assert.assertNull(ffmpegSession.getStartTime()); + + // 7. getEndTime + Assert.assertNull(ffmpegSession.getEndTime()); + + // 8. getDuration + Assert.assertEquals(0, ffmpegSession.getDuration()); + + // 9. getArguments + Assert.assertArrayEquals(TEST_ARGUMENTS, ffmpegSession.getArguments()); + + // 10. getCommand + StringBuilder commandBuilder = new StringBuilder(); + for (int i = 0; i < TEST_ARGUMENTS.length; i++) { + if (i > 0) { + commandBuilder.append(" "); + } + commandBuilder.append(TEST_ARGUMENTS[i]); + } + Assert.assertEquals(commandBuilder.toString(), ffmpegSession.getCommand()); + + // 11. getLogs + Assert.assertEquals(0, ffmpegSession.getLogs().size()); + + // 12. getLogsAsString + Assert.assertEquals("", ffmpegSession.getLogsAsString()); + + // 13. getState + Assert.assertEquals(SessionState.CREATED, ffmpegSession.getState()); + + // 14. getState + Assert.assertNull(ffmpegSession.getReturnCode()); + + // 15. getFailStackTrace + Assert.assertNull(ffmpegSession.getFailStackTrace()); + + // 16. getLogRedirectionStrategy + Assert.assertEquals(FFmpegKitConfig.getLogRedirectionStrategy(), ffmpegSession.getLogRedirectionStrategy()); + + // 17. getFuture + Assert.assertNull(ffmpegSession.getFuture()); + } + + @Test + public void constructorTest2() { + ExecuteCallback executeCallback = new ExecuteCallback() { + + @Override + public void apply(Session session) { + } + }; + + FFmpegSession ffmpegSession = new FFmpegSession(TEST_ARGUMENTS, executeCallback); + + // 1. getExecuteCallback + Assert.assertEquals(ffmpegSession.getExecuteCallback(), executeCallback); + + // 2. getLogCallback + Assert.assertNull(ffmpegSession.getLogCallback()); + + // 3. getStatisticsCallback + Assert.assertNull(ffmpegSession.getStatisticsCallback()); + + // 4. getSessionId + Assert.assertTrue(ffmpegSession.getSessionId() > 0); + + // 5. getCreateTime + Assert.assertTrue(ffmpegSession.getCreateTime().getTime() <= System.currentTimeMillis()); + + // 6. getStartTime + Assert.assertNull(ffmpegSession.getStartTime()); + + // 7. getEndTime + Assert.assertNull(ffmpegSession.getEndTime()); + + // 8. getDuration + Assert.assertEquals(0, ffmpegSession.getDuration()); + + // 9. getArguments + Assert.assertArrayEquals(TEST_ARGUMENTS, ffmpegSession.getArguments()); + + // 10. getCommand + StringBuilder commandBuilder = new StringBuilder(); + for (int i = 0; i < TEST_ARGUMENTS.length; i++) { + if (i > 0) { + commandBuilder.append(" "); + } + commandBuilder.append(TEST_ARGUMENTS[i]); + } + Assert.assertEquals(commandBuilder.toString(), ffmpegSession.getCommand()); + + // 11. getLogs + Assert.assertEquals(0, ffmpegSession.getLogs().size()); + + // 12. getLogsAsString + Assert.assertEquals("", ffmpegSession.getLogsAsString()); + + // 13. getState + Assert.assertEquals(SessionState.CREATED, ffmpegSession.getState()); + + // 14. getState + Assert.assertNull(ffmpegSession.getReturnCode()); + + // 15. getFailStackTrace + Assert.assertNull(ffmpegSession.getFailStackTrace()); + + // 16. getLogRedirectionStrategy + Assert.assertEquals(FFmpegKitConfig.getLogRedirectionStrategy(), ffmpegSession.getLogRedirectionStrategy()); + + // 17. getFuture + Assert.assertNull(ffmpegSession.getFuture()); + } + + @Test + public void constructorTest3() { + ExecuteCallback executeCallback = new ExecuteCallback() { + + @Override + public void apply(Session session) { + } + }; + + LogCallback logCallback = new LogCallback() { + @Override + public void apply(Log log) { + + } + }; + + StatisticsCallback statisticsCallback = new StatisticsCallback() { + @Override + public void apply(Statistics statistics) { + + } + }; + + FFmpegSession ffmpegSession = new FFmpegSession(TEST_ARGUMENTS, executeCallback, logCallback, statisticsCallback); + + // 1. getExecuteCallback + Assert.assertEquals(ffmpegSession.getExecuteCallback(), executeCallback); + + // 2. getLogCallback + Assert.assertEquals(ffmpegSession.getLogCallback(), logCallback); + + // 3. getStatisticsCallback + Assert.assertEquals(ffmpegSession.getStatisticsCallback(), statisticsCallback); + + // 4. getSessionId + Assert.assertTrue(ffmpegSession.getSessionId() > 0); + + // 5. getCreateTime + Assert.assertTrue(ffmpegSession.getCreateTime().getTime() <= System.currentTimeMillis()); + + // 6. getStartTime + Assert.assertNull(ffmpegSession.getStartTime()); + + // 7. getEndTime + Assert.assertNull(ffmpegSession.getEndTime()); + + // 8. getDuration + Assert.assertEquals(0, ffmpegSession.getDuration()); + + // 9. getArguments + Assert.assertArrayEquals(TEST_ARGUMENTS, ffmpegSession.getArguments()); + + // 10. getCommand + StringBuilder commandBuilder = new StringBuilder(); + for (int i = 0; i < TEST_ARGUMENTS.length; i++) { + if (i > 0) { + commandBuilder.append(" "); + } + commandBuilder.append(TEST_ARGUMENTS[i]); + } + Assert.assertEquals(commandBuilder.toString(), ffmpegSession.getCommand()); + + // 11. getLogs + Assert.assertEquals(0, ffmpegSession.getLogs().size()); + + // 12. getLogsAsString + Assert.assertEquals("", ffmpegSession.getLogsAsString()); + + // 13. getState + Assert.assertEquals(SessionState.CREATED, ffmpegSession.getState()); + + // 14. getState + Assert.assertNull(ffmpegSession.getReturnCode()); + + // 15. getFailStackTrace + Assert.assertNull(ffmpegSession.getFailStackTrace()); + + // 16. getLogRedirectionStrategy + Assert.assertEquals(FFmpegKitConfig.getLogRedirectionStrategy(), ffmpegSession.getLogRedirectionStrategy()); + + // 17. getFuture + Assert.assertNull(ffmpegSession.getFuture()); + } + + @Test + public void getSessionIdTest() { + FFmpegSession ffmpegSession1 = new FFmpegSession(TEST_ARGUMENTS); + FFmpegSession ffmpegSession2 = new FFmpegSession(TEST_ARGUMENTS); + FFmpegSession ffmpegSession3 = new FFmpegSession(TEST_ARGUMENTS); + + Assert.assertTrue(ffmpegSession3.getSessionId() > ffmpegSession2.getSessionId()); + Assert.assertTrue(ffmpegSession3.getSessionId() > ffmpegSession1.getSessionId()); + Assert.assertTrue(ffmpegSession2.getSessionId() > ffmpegSession1.getSessionId()); + + Assert.assertTrue(ffmpegSession1.getSessionId() > 0); + Assert.assertTrue(ffmpegSession2.getSessionId() > 0); + Assert.assertTrue(ffmpegSession3.getSessionId() > 0); + } + + @Test + public void getLogs() { + final FFmpegSession ffmpegSession = new FFmpegSession(TEST_ARGUMENTS); + + String logMessage1 = "i am log one"; + String logMessage2 = "i am log two"; + String logMessage3 = "i am log three"; + + ffmpegSession.addLog(new Log(ffmpegSession.getSessionId(), Level.AV_LOG_INFO, logMessage1)); + ffmpegSession.addLog(new Log(ffmpegSession.getSessionId(), Level.AV_LOG_DEBUG, logMessage2)); + ffmpegSession.addLog(new Log(ffmpegSession.getSessionId(), Level.AV_LOG_TRACE, logMessage3)); + + List logs = ffmpegSession.getLogs(); + + Assert.assertEquals(3, logs.size()); + } + + @Test + public void getLogsAsStringTest() { + final FFmpegSession ffmpegSession = new FFmpegSession(TEST_ARGUMENTS); + + String logMessage1 = "i am log one"; + String logMessage2 = "i am log two"; + + ffmpegSession.addLog(new Log(ffmpegSession.getSessionId(), Level.AV_LOG_DEBUG, logMessage1)); + ffmpegSession.addLog(new Log(ffmpegSession.getSessionId(), Level.AV_LOG_DEBUG, logMessage2)); + + String logsAsString = ffmpegSession.getLogsAsString(); + + Assert.assertEquals(logMessage1 + logMessage2, logsAsString); + } + + @Test + public void getLogRedirectionStrategy() { + FFmpegKitConfig.setLogRedirectionStrategy(LogRedirectionStrategy.NEVER_PRINT_LOGS); + + final FFmpegSession ffmpegSession1 = new FFmpegSession(TEST_ARGUMENTS); + Assert.assertEquals(FFmpegKitConfig.getLogRedirectionStrategy(), ffmpegSession1.getLogRedirectionStrategy()); + + FFmpegKitConfig.setLogRedirectionStrategy(LogRedirectionStrategy.PRINT_LOGS_WHEN_SESSION_CALLBACK_NOT_DEFINED); + + final FFmpegSession ffmpegSession2 = new FFmpegSession(TEST_ARGUMENTS); + Assert.assertEquals(FFmpegKitConfig.getLogRedirectionStrategy(), ffmpegSession2.getLogRedirectionStrategy()); + } + + @Test + public void startRunningTest() { + FFmpegSession ffmpegSession = new FFmpegSession(TEST_ARGUMENTS); + + ffmpegSession.startRunning(); + + Assert.assertEquals(SessionState.RUNNING, ffmpegSession.getState()); + Assert.assertTrue(ffmpegSession.getStartTime().getTime() <= System.currentTimeMillis()); + Assert.assertTrue(ffmpegSession.getCreateTime().getTime() <= ffmpegSession.getStartTime().getTime()); + } + + @Test + public void completeTest() { + FFmpegSession ffmpegSession = new FFmpegSession(TEST_ARGUMENTS); + + ffmpegSession.startRunning(); + ffmpegSession.complete(new ReturnCode(100)); + + Assert.assertEquals(SessionState.COMPLETED, ffmpegSession.getState()); + Assert.assertEquals(100, ffmpegSession.getReturnCode().getValue()); + Assert.assertTrue(ffmpegSession.getStartTime().getTime() <= ffmpegSession.getEndTime().getTime()); + Assert.assertTrue(ffmpegSession.getDuration() >= 0); + } + + @Test + public void failTest() { + FFmpegSession ffmpegSession = new FFmpegSession(TEST_ARGUMENTS); + + ffmpegSession.startRunning(); + ffmpegSession.fail(new Exception("")); + + Assert.assertEquals(SessionState.FAILED, ffmpegSession.getState()); + Assert.assertNull(ffmpegSession.getReturnCode()); + Assert.assertTrue(ffmpegSession.getStartTime().getTime() <= ffmpegSession.getEndTime().getTime()); + Assert.assertTrue(ffmpegSession.getDuration() >= 0); + Assert.assertNotNull(ffmpegSession.getFailStackTrace()); + } + +} diff --git a/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFprobeSessionTest.java b/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFprobeSessionTest.java new file mode 100644 index 0000000..2ba21d1 --- /dev/null +++ b/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFprobeSessionTest.java @@ -0,0 +1,334 @@ +/* + * 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; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.List; + +public class FFprobeSessionTest { + + static { + System.setProperty("enable.ffmpeg.kit.test.mode", "true"); + } + + private static final String[] TEST_ARGUMENTS = new String[]{"argument1", "argument2"}; + + @Test + public void constructorTest() { + FFprobeSession ffprobeSession = new FFprobeSession(TEST_ARGUMENTS); + + // 1. getExecuteCallback + Assert.assertNull(ffprobeSession.getExecuteCallback()); + + // 2. getLogCallback + Assert.assertNull(ffprobeSession.getLogCallback()); + + // 3. getSessionId + Assert.assertTrue(ffprobeSession.getSessionId() > 0); + + // 4. getCreateTime + Assert.assertTrue(ffprobeSession.getCreateTime().getTime() <= System.currentTimeMillis()); + + // 5. getStartTime + Assert.assertNull(ffprobeSession.getStartTime()); + + // 6. getEndTime + Assert.assertNull(ffprobeSession.getEndTime()); + + // 7. getDuration + Assert.assertEquals(0, ffprobeSession.getDuration()); + + // 8. getArguments + Assert.assertArrayEquals(TEST_ARGUMENTS, ffprobeSession.getArguments()); + + // 9. getCommand + StringBuilder commandBuilder = new StringBuilder(); + for (int i = 0; i < TEST_ARGUMENTS.length; i++) { + if (i > 0) { + commandBuilder.append(" "); + } + commandBuilder.append(TEST_ARGUMENTS[i]); + } + Assert.assertEquals(commandBuilder.toString(), ffprobeSession.getCommand()); + + // 10. getLogs + Assert.assertEquals(0, ffprobeSession.getLogs().size()); + + // 11. getLogsAsString + Assert.assertEquals("", ffprobeSession.getLogsAsString()); + + // 12. getState + Assert.assertEquals(SessionState.CREATED, ffprobeSession.getState()); + + // 13. getState + Assert.assertNull(ffprobeSession.getReturnCode()); + + // 14. getFailStackTrace + Assert.assertNull(ffprobeSession.getFailStackTrace()); + + // 15. getLogRedirectionStrategy + Assert.assertEquals(FFmpegKitConfig.getLogRedirectionStrategy(), ffprobeSession.getLogRedirectionStrategy()); + + // 16. getFuture + Assert.assertNull(ffprobeSession.getFuture()); + } + + @Test + public void constructorTest2() { + ExecuteCallback executeCallback = new ExecuteCallback() { + + @Override + public void apply(Session session) { + } + }; + + FFprobeSession ffprobeSession = new FFprobeSession(TEST_ARGUMENTS, executeCallback); + + // 1. getExecuteCallback + Assert.assertEquals(ffprobeSession.getExecuteCallback(), executeCallback); + + // 2. getLogCallback + Assert.assertNull(ffprobeSession.getLogCallback()); + + // 3. getSessionId + Assert.assertTrue(ffprobeSession.getSessionId() > 0); + + // 4. getCreateTime + Assert.assertTrue(ffprobeSession.getCreateTime().getTime() <= System.currentTimeMillis()); + + // 5. getStartTime + Assert.assertNull(ffprobeSession.getStartTime()); + + // 6. getEndTime + Assert.assertNull(ffprobeSession.getEndTime()); + + // 7. getDuration + Assert.assertEquals(0, ffprobeSession.getDuration()); + + // 8. getArguments + Assert.assertArrayEquals(TEST_ARGUMENTS, ffprobeSession.getArguments()); + + // 9. getCommand + StringBuilder commandBuilder = new StringBuilder(); + for (int i = 0; i < TEST_ARGUMENTS.length; i++) { + if (i > 0) { + commandBuilder.append(" "); + } + commandBuilder.append(TEST_ARGUMENTS[i]); + } + Assert.assertEquals(commandBuilder.toString(), ffprobeSession.getCommand()); + + // 10. getLogs + Assert.assertEquals(0, ffprobeSession.getLogs().size()); + + // 11. getLogsAsString + Assert.assertEquals("", ffprobeSession.getLogsAsString()); + + // 12. getState + Assert.assertEquals(SessionState.CREATED, ffprobeSession.getState()); + + // 13. getState + Assert.assertNull(ffprobeSession.getReturnCode()); + + // 14. getFailStackTrace + Assert.assertNull(ffprobeSession.getFailStackTrace()); + + // 15. getLogRedirectionStrategy + Assert.assertEquals(FFmpegKitConfig.getLogRedirectionStrategy(), ffprobeSession.getLogRedirectionStrategy()); + + // 16. getFuture + Assert.assertNull(ffprobeSession.getFuture()); + } + + @Test + public void constructorTest3() { + ExecuteCallback executeCallback = new ExecuteCallback() { + + @Override + public void apply(Session session) { + } + }; + + LogCallback logCallback = new LogCallback() { + @Override + public void apply(Log log) { + + } + }; + + FFprobeSession ffprobeSession = new FFprobeSession(TEST_ARGUMENTS, executeCallback, logCallback); + + // 1. getExecuteCallback + Assert.assertEquals(ffprobeSession.getExecuteCallback(), executeCallback); + + // 2. getLogCallback + Assert.assertEquals(ffprobeSession.getLogCallback(), logCallback); + + // 3. getSessionId + Assert.assertTrue(ffprobeSession.getSessionId() > 0); + + // 4. getCreateTime + Assert.assertTrue(ffprobeSession.getCreateTime().getTime() <= System.currentTimeMillis()); + + // 5. getStartTime + Assert.assertNull(ffprobeSession.getStartTime()); + + // 6. getEndTime + Assert.assertNull(ffprobeSession.getEndTime()); + + // 7. getDuration + Assert.assertEquals(0, ffprobeSession.getDuration()); + + // 8. getArguments + Assert.assertArrayEquals(TEST_ARGUMENTS, ffprobeSession.getArguments()); + + // 9. getCommand + StringBuilder commandBuilder = new StringBuilder(); + for (int i = 0; i < TEST_ARGUMENTS.length; i++) { + if (i > 0) { + commandBuilder.append(" "); + } + commandBuilder.append(TEST_ARGUMENTS[i]); + } + Assert.assertEquals(commandBuilder.toString(), ffprobeSession.getCommand()); + + // 10. getLogs + Assert.assertEquals(0, ffprobeSession.getLogs().size()); + + // 11. getLogsAsString + Assert.assertEquals("", ffprobeSession.getLogsAsString()); + + // 12. getState + Assert.assertEquals(SessionState.CREATED, ffprobeSession.getState()); + + // 13. getState + Assert.assertNull(ffprobeSession.getReturnCode()); + + // 14. getFailStackTrace + Assert.assertNull(ffprobeSession.getFailStackTrace()); + + // 15. getLogRedirectionStrategy + Assert.assertEquals(FFmpegKitConfig.getLogRedirectionStrategy(), ffprobeSession.getLogRedirectionStrategy()); + + // 16. getFuture + Assert.assertNull(ffprobeSession.getFuture()); + } + + @Test + public void getSessionIdTest() { + FFprobeSession ffprobeSession1 = new FFprobeSession(TEST_ARGUMENTS); + FFprobeSession ffprobeSession2 = new FFprobeSession(TEST_ARGUMENTS); + FFprobeSession ffprobeSession3 = new FFprobeSession(TEST_ARGUMENTS); + + Assert.assertTrue(ffprobeSession3.getSessionId() > ffprobeSession2.getSessionId()); + Assert.assertTrue(ffprobeSession3.getSessionId() > ffprobeSession1.getSessionId()); + Assert.assertTrue(ffprobeSession2.getSessionId() > ffprobeSession1.getSessionId()); + + Assert.assertTrue(ffprobeSession1.getSessionId() > 0); + Assert.assertTrue(ffprobeSession2.getSessionId() > 0); + Assert.assertTrue(ffprobeSession3.getSessionId() > 0); + } + + @Test + public void getLogs() { + final FFprobeSession ffprobeSession = new FFprobeSession(TEST_ARGUMENTS); + + String logMessage1 = "i am log one"; + String logMessage2 = "i am log two"; + String logMessage3 = "i am log three"; + + ffprobeSession.addLog(new Log(ffprobeSession.getSessionId(), Level.AV_LOG_INFO, logMessage1)); + ffprobeSession.addLog(new Log(ffprobeSession.getSessionId(), Level.AV_LOG_DEBUG, logMessage2)); + ffprobeSession.addLog(new Log(ffprobeSession.getSessionId(), Level.AV_LOG_TRACE, logMessage3)); + + List logs = ffprobeSession.getLogs(); + + Assert.assertEquals(3, logs.size()); + } + + @Test + public void getLogsAsStringTest() { + final FFprobeSession ffprobeSession = new FFprobeSession(TEST_ARGUMENTS); + + String logMessage1 = "i am log one"; + String logMessage2 = "i am log two"; + + ffprobeSession.addLog(new Log(ffprobeSession.getSessionId(), Level.AV_LOG_DEBUG, logMessage1)); + ffprobeSession.addLog(new Log(ffprobeSession.getSessionId(), Level.AV_LOG_DEBUG, logMessage2)); + + String logsAsString = ffprobeSession.getLogsAsString(); + + Assert.assertEquals(logMessage1 + logMessage2, logsAsString); + } + + @Test + public void getLogRedirectionStrategy() { + FFmpegKitConfig.setLogRedirectionStrategy(LogRedirectionStrategy.NEVER_PRINT_LOGS); + + final FFprobeSession ffprobeSession1 = new FFprobeSession(TEST_ARGUMENTS); + Assert.assertEquals(FFmpegKitConfig.getLogRedirectionStrategy(), ffprobeSession1.getLogRedirectionStrategy()); + + FFmpegKitConfig.setLogRedirectionStrategy(LogRedirectionStrategy.PRINT_LOGS_WHEN_SESSION_CALLBACK_NOT_DEFINED); + + final FFprobeSession ffprobeSession2 = new FFprobeSession(TEST_ARGUMENTS); + Assert.assertEquals(FFmpegKitConfig.getLogRedirectionStrategy(), ffprobeSession2.getLogRedirectionStrategy()); + } + + @Test + public void startRunningTest() { + FFprobeSession ffprobeSession = new FFprobeSession(TEST_ARGUMENTS); + + ffprobeSession.startRunning(); + + Assert.assertEquals(SessionState.RUNNING, ffprobeSession.getState()); + Assert.assertTrue(ffprobeSession.getStartTime().getTime() <= System.currentTimeMillis()); + Assert.assertTrue(ffprobeSession.getCreateTime().getTime() <= ffprobeSession.getStartTime().getTime()); + } + + @Test + public void completeTest() { + FFprobeSession ffprobeSession = new FFprobeSession(TEST_ARGUMENTS); + + ffprobeSession.startRunning(); + ffprobeSession.complete(new ReturnCode(100)); + + Assert.assertEquals(SessionState.COMPLETED, ffprobeSession.getState()); + Assert.assertEquals(100, ffprobeSession.getReturnCode().getValue()); + Assert.assertTrue(ffprobeSession.getStartTime().getTime() <= ffprobeSession.getEndTime().getTime()); + Assert.assertTrue(ffprobeSession.getDuration() >= 0); + } + + @Test + public void failTest() { + FFprobeSession ffprobeSession = new FFprobeSession(TEST_ARGUMENTS); + + ffprobeSession.startRunning(); + ffprobeSession.fail(new Exception("")); + + Assert.assertEquals(SessionState.FAILED, ffprobeSession.getState()); + Assert.assertNull(ffprobeSession.getReturnCode()); + Assert.assertTrue(ffprobeSession.getStartTime().getTime() <= ffprobeSession.getEndTime().getTime()); + Assert.assertTrue(ffprobeSession.getDuration() >= 0); + Assert.assertNotNull(ffprobeSession.getFailStackTrace()); + } + +} diff --git a/android/settings.gradle b/android/settings.gradle index 70af3f7..eaf298d 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,4 +1,2 @@ include ':ffmpeg-kit-android-lib' -include ':ffmpeg-kit' -project(':ffmpeg-kit').projectDir = new File('..') rootProject.name = 'ffmpeg-kit-android' diff --git a/apple/Makefile.in b/apple/Makefile.in index cdbe0e8..044d789 100644 --- a/apple/Makefile.in +++ b/apple/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.16.2 from Makefile.am. +# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. @@ -198,6 +198,8 @@ am__relativize = \ DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip +# Exists only to be overridden by the user if desired. +AM_DISTCHECK_DVI_TARGET = dvi distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' @@ -623,7 +625,7 @@ distcheck: dist $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ diff --git a/apple/aclocal.m4 b/apple/aclocal.m4 index b86fa0b..7afd8cc 100644 --- a/apple/aclocal.m4 +++ b/apple/aclocal.m4 @@ -1,4 +1,4 @@ -# generated automatically by aclocal 1.16.2 -*- Autoconf -*- +# generated automatically by aclocal 1.16.3 -*- Autoconf -*- # Copyright (C) 1996-2020 Free Software Foundation, Inc. @@ -35,7 +35,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.16.2], [], +m4_if([$1], [1.16.3], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -51,7 +51,7 @@ m4_define([_AM_AUTOCONF_VERSION], []) # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.16.2])dnl +[AM_AUTOMAKE_VERSION([1.16.3])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) @@ -799,12 +799,7 @@ AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac + MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then diff --git a/apple/config.guess b/apple/config.guess index 699b3a1..9aff91c 100755 --- a/apple/config.guess +++ b/apple/config.guess @@ -2,7 +2,7 @@ # Attempt to guess a canonical system name. # Copyright 1992-2020 Free Software Foundation, Inc. -timestamp='2020-11-19' +timestamp='2020-08-17' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -27,12 +27,12 @@ timestamp='2020-11-19' # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: -# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to . -me=$(echo "$0" | sed -e 's,.*/,,') +me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] @@ -103,7 +103,7 @@ set_cc_for_build() { test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039 - { tmp=$( (umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null) && test -n "$tmp" && test -d "$tmp" ; } || + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } @@ -131,14 +131,16 @@ if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi -UNAME_MACHINE=$( (uname -m) 2>/dev/null) || UNAME_MACHINE=unknown -UNAME_RELEASE=$( (uname -r) 2>/dev/null) || UNAME_RELEASE=unknown -UNAME_SYSTEM=$( (uname -s) 2>/dev/null) || UNAME_SYSTEM=unknown -UNAME_VERSION=$( (uname -v) 2>/dev/null) || UNAME_VERSION=unknown +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "$UNAME_SYSTEM" in Linux|GNU|GNU/*) - LIBC=unknown + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu set_cc_for_build cat <<-EOF > "$dummy.c" @@ -147,29 +149,17 @@ Linux|GNU|GNU/*) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc - #elif defined(__GLIBC__) - LIBC=gnu #else - #include - /* First heuristic to detect musl libc. */ - #ifdef __DEFINED_va_list - LIBC=musl - #endif + LIBC=gnu #endif EOF - eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g')" + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" - # Second heuristic to detect musl libc. - if [ "$LIBC" = unknown ] && - command -v ldd >/dev/null && - ldd --version 2>&1 | grep -q ^musl; then - LIBC=musl - fi - - # If the system lacks a compiler, then just pick glibc. - # We could probably try harder. - if [ "$LIBC" = unknown ]; then - LIBC=gnu + # If ldd exists, use it to detect musl libc. + if command -v ldd >/dev/null && \ + ldd --version 2>&1 | grep -q ^musl + then + LIBC=musl fi ;; esac @@ -189,20 +179,19 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \ + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ "/sbin/$sysctl" 2>/dev/null || \ "/usr/sbin/$sysctl" 2>/dev/null || \ - echo unknown)) + echo unknown)` case "$UNAME_MACHINE_ARCH" in - aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) - arch=$(echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,') - endian=$(echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p') + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine="${arch}${endian}"-unknown ;; *) machine="$UNAME_MACHINE_ARCH"-unknown ;; @@ -233,7 +222,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in case "$UNAME_MACHINE_ARCH" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' - abi=$(echo "$UNAME_MACHINE_ARCH" | sed -e "$expr") + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release @@ -246,7 +235,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in release='-gnu' ;; *) - release=$(echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2) + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: @@ -255,15 +244,15 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in echo "$machine-${os}${release}${abi-}" exit ;; *:Bitrig:*:*) - UNAME_MACHINE_ARCH=$(arch | sed 's/Bitrig.//') + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" exit ;; *:OpenBSD:*:*) - UNAME_MACHINE_ARCH=$(arch | sed 's/OpenBSD.//') + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" exit ;; *:LibertyBSD:*:*) - UNAME_MACHINE_ARCH=$(arch | sed 's/^.*BSD\.//') + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" exit ;; *:MidnightBSD:*:*) @@ -299,17 +288,17 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) - UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $3}') + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) - UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $4}') + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. - ALPHA_CPU_TYPE=$(/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1) + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE=alpha ;; @@ -347,7 +336,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo "$UNAME_MACHINE"-dec-osf"$(echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)" + echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 @@ -381,7 +370,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - if test "$( (/bin/universe) 2>/dev/null)" = att ; then + if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd @@ -394,17 +383,17 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) - case $(/usr/bin/uname -p) in + case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) - echo "$UNAME_MACHINE"-ibm-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')" + echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" + echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')" + echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux"$UNAME_RELEASE" @@ -423,30 +412,30 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in SUN_ARCH=x86_64 fi fi - echo "$SUN_ARCH"-pc-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" + echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" + echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:*:*) - case "$(/usr/bin/arch -k)" in + case "`/usr/bin/arch -k`" in Series*|S4*) - UNAME_RELEASE=$(uname -v) + UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/')" + echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos"$UNAME_RELEASE" exit ;; sun*:*:4.2BSD:*) - UNAME_RELEASE=$( (sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 - case "$(/bin/arch)" in + case "`/bin/arch`" in sun3) echo m68k-sun-sunos"$UNAME_RELEASE" ;; @@ -526,8 +515,8 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && - dummyarg=$(echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p') && - SYSTEM_NAME=$("$dummy" "$dummyarg") && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos"$UNAME_RELEASE" exit ;; @@ -554,7 +543,7 @@ EOF exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=$(/usr/bin/uname -p) + UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ @@ -582,17 +571,17 @@ EOF echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) - echo mips-sgi-irix"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/g')" + echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit ;; # Note that: echo "'$(uname -s)'" gives 'AIX ' + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then - IBM_REV=$(/usr/bin/oslevel) + IBM_REV=`/usr/bin/oslevel` else IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi @@ -612,7 +601,7 @@ EOF exit(0); } EOF - if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then echo "$SYSTEM_NAME" else @@ -625,15 +614,15 @@ EOF fi exit ;; *:AIX:*:[4567]) - IBM_CPU_ID=$(/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }') + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if test -x /usr/bin/lslpp ; then - IBM_REV=$(/usr/bin/lslpp -Lqc bos.rte.libc | - awk -F: '{ print $3 }' | sed s/[0-9]*$/0/) + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi @@ -661,14 +650,14 @@ EOF echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) - HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//') + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` case "$UNAME_MACHINE" in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if test -x /usr/bin/getconf; then - sc_cpu_version=$(/usr/bin/getconf SC_CPU_VERSION 2>/dev/null) - sc_kernel_bits=$(/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null) + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "$sc_cpu_version" in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 @@ -715,7 +704,7 @@ EOF exit (0); } EOF - (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=$("$dummy") + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac @@ -743,7 +732,7 @@ EOF echo "$HP_ARCH"-hp-hpux"$HPUX_REV" exit ;; ia64:HP-UX:*:*) - HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//') + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux"$HPUX_REV" exit ;; 3050*:HI-UX:*:*) @@ -773,7 +762,7 @@ EOF exit (0); } EOF - $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") && + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; @@ -842,14 +831,14 @@ EOF echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=$(uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz) - FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///') - FUJITSU_REL=$(echo "$UNAME_RELEASE" | sed -e 's/ /_/') + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///') - FUJITSU_REL=$(echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/') + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) @@ -862,25 +851,25 @@ EOF echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" exit ;; arm:FreeBSD:*:*) - UNAME_PROCESSOR=$(uname -p) + UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then - echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabi + echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi else - echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabihf + echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf fi exit ;; *:FreeBSD:*:*) - UNAME_PROCESSOR=$(/usr/bin/uname -p) + UNAME_PROCESSOR=`/usr/bin/uname -p` case "$UNAME_PROCESSOR" in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac - echo "$UNAME_PROCESSOR"-unknown-freebsd"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')" + echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; i*:CYGWIN*:*) echo "$UNAME_MACHINE"-pc-cygwin @@ -916,15 +905,15 @@ EOF echo x86_64-pc-cygwin exit ;; prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" + echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; *:GNU:*:*) # the GNU system - echo "$(echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,')-unknown-$LIBC$(echo "$UNAME_RELEASE"|sed -e 's,/.*$,,')" + echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo "$UNAME_MACHINE-unknown-$(echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]")$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')-$LIBC" + echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" exit ;; *:Minix:*:*) echo "$UNAME_MACHINE"-unknown-minix @@ -937,7 +926,7 @@ EOF echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; alpha:Linux:*:*) - case $(sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null) in + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; @@ -1046,7 +1035,7 @@ EOF #endif #endif EOF - eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI')" + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) @@ -1066,7 +1055,7 @@ EOF exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level - case $(grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2) in + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; *) echo hppa-unknown-linux-"$LIBC" ;; @@ -1156,7 +1145,7 @@ EOF echo "$UNAME_MACHINE"-pc-msdosdjgpp exit ;; i*86:*:4.*:*) - UNAME_REL=$(echo "$UNAME_RELEASE" | sed 's/\/MP$//') + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" else @@ -1165,7 +1154,7 @@ EOF exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. - case $(/bin/uname -X | grep "^Machine") in + case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; @@ -1174,10 +1163,10 @@ EOF exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then - UNAME_REL=$(sed -n 's/.*Version //p' /dev/null >/dev/null ; then - UNAME_REL=$( (/bin/uname -X|grep Release|sed -e 's/.*= //')) + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 @@ -1227,7 +1216,7 @@ EOF 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ - && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid) + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ @@ -1238,7 +1227,7 @@ EOF NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ - && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid) + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ @@ -1271,7 +1260,7 @@ EOF exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then - UNAME_MACHINE=$( (uname -p) 2>/dev/null) + UNAME_MACHINE=`(uname -p) 2>/dev/null` echo "$UNAME_MACHINE"-sni-sysv4 else echo ns32k-sni-sysv @@ -1357,7 +1346,7 @@ EOF echo aarch64-apple-darwin"$UNAME_RELEASE" exit ;; *:Darwin:*:*) - UNAME_PROCESSOR=$(uname -p) + UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac @@ -1394,7 +1383,7 @@ EOF echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) - UNAME_PROCESSOR=$(uname -p) + UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc @@ -1462,10 +1451,10 @@ EOF echo mips-sei-seiux"$UNAME_RELEASE" exit ;; *:DragonFly:*:*) - echo "$UNAME_MACHINE"-unknown-dragonfly"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')" + echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; *:*VMS:*:*) - UNAME_MACHINE=$( (uname -p) 2>/dev/null) + UNAME_MACHINE=`(uname -p) 2>/dev/null` case "$UNAME_MACHINE" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; @@ -1475,7 +1464,7 @@ EOF echo i386-pc-xenix exit ;; i*86:skyos:*:*) - echo "$UNAME_MACHINE"-pc-skyos"$(echo "$UNAME_RELEASE" | sed -e 's/ .*$//')" + echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" exit ;; i*86:rdos:*:*) echo "$UNAME_MACHINE"-pc-rdos @@ -1533,7 +1522,7 @@ main () #define __ARCHITECTURE__ "m68k" #endif int version; - version=$( (hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null); + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else @@ -1625,7 +1614,7 @@ main () } EOF -$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=$($dummy) && +$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. @@ -1650,14 +1639,14 @@ This script (version $timestamp), has failed to recognize the operating system you are using. If your script is old, overwrite *all* copies of config.guess and config.sub with the latest versions from: - https://git.savannah.gnu.org/cgit/config.git/plain/config.guess + https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess and - https://git.savannah.gnu.org/cgit/config.git/plain/config.sub + https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub EOF -year=$(echo $timestamp | sed 's,-.*,,') +year=`echo $timestamp | sed 's,-.*,,'` # shellcheck disable=SC2003 -if test "$(expr "$(date +%Y)" - "$year")" -lt 3 ; then +if test "`expr "\`date +%Y\`" - "$year"`" -lt 3 ; then cat >&2 </dev/null || echo unknown) -uname -r = $( (uname -r) 2>/dev/null || echo unknown) -uname -s = $( (uname -s) 2>/dev/null || echo unknown) -uname -v = $( (uname -v) 2>/dev/null || echo unknown) +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` -/usr/bin/uname -p = $( (/usr/bin/uname -p) 2>/dev/null) -/bin/uname -X = $( (/bin/uname -X) 2>/dev/null) +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` -hostinfo = $( (hostinfo) 2>/dev/null) -/bin/universe = $( (/bin/universe) 2>/dev/null) -/usr/bin/arch -k = $( (/usr/bin/arch -k) 2>/dev/null) -/bin/arch = $( (/bin/arch) 2>/dev/null) -/usr/bin/oslevel = $( (/usr/bin/oslevel) 2>/dev/null) -/usr/convex/getsysinfo = $( (/usr/convex/getsysinfo) 2>/dev/null) +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" diff --git a/apple/config.sub b/apple/config.sub index 19c9553..0753e30 100755 --- a/apple/config.sub +++ b/apple/config.sub @@ -2,7 +2,7 @@ # Configuration validation subroutine script. # Copyright 1992-2020 Free Software Foundation, Inc. -timestamp='2020-12-02' +timestamp='2020-08-17' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -33,7 +33,7 @@ timestamp='2020-12-02' # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: -# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases @@ -50,7 +50,7 @@ timestamp='2020-12-02' # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. -me=$(echo "$0" | sed -e 's,.*/,,') +me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS @@ -769,22 +769,22 @@ case $basic_machine in vendor=hp ;; i*86v32) - cpu=$(echo "$1" | sed -e 's/86.*/86/') + cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) - cpu=$(echo "$1" | sed -e 's/86.*/86/') + cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) - cpu=$(echo "$1" | sed -e 's/86.*/86/') + cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) - cpu=$(echo "$1" | sed -e 's/86.*/86/') + cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; @@ -917,7 +917,7 @@ case $basic_machine in ;; leon-*|leon[3-9]-*) cpu=sparc - vendor=$(echo "$basic_machine" | sed 's/-.*//') + vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) @@ -1084,7 +1084,7 @@ case $cpu-$vendor in cpu=mipsisa64sb1el ;; sh5e[lb]-*) - cpu=$(echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/') + cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'` ;; spur-*) cpu=spur @@ -1102,7 +1102,7 @@ case $cpu-$vendor in cpu=x86_64 ;; xscale-* | xscalee[bl]-*) - cpu=$(echo "$cpu" | sed 's/^xscale/arm/') + cpu=`echo "$cpu" | sed 's/^xscale/arm/'` ;; arm64-*) cpu=aarch64 @@ -1241,7 +1241,6 @@ case $cpu-$vendor in | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \ | spu \ | tahoe \ - | thumbv7* \ | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \ | tron \ | ubicom32 \ @@ -1287,15 +1286,11 @@ then case $basic_os in gnu/linux*) kernel=linux - os=$(echo $basic_os | sed -e 's|gnu/linux|gnu|') - ;; - os2-emx) - kernel=os2 - os=$(echo $basic_os | sed -e 's|os2-emx|emx|') + os=`echo $basic_os | sed -e 's|gnu/linux|gnu|'` ;; nto-qnx*) kernel=nto - os=$(echo $basic_os | sed -e 's|nto-qnx|qnx|') + os=`echo $basic_os | sed -e 's|nto-qnx|qnx|'` ;; *-*) # shellcheck disable=SC2162 @@ -1306,11 +1301,11 @@ EOF # Default OS when just kernel was specified nto*) kernel=nto - os=$(echo $basic_os | sed -e 's|nto|qnx|') + os=`echo $basic_os | sed -e 's|nto|qnx|'` ;; linux*) kernel=linux - os=$(echo $basic_os | sed -e 's|linux|gnu|') + os=`echo $basic_os | sed -e 's|linux|gnu|'` ;; *) kernel= @@ -1331,7 +1326,7 @@ case $os in os=cnk ;; solaris1 | solaris1.*) - os=$(echo $os | sed -e 's|solaris1|sunos4|') + os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; solaris) os=solaris2 @@ -1360,7 +1355,7 @@ case $os in os=sco3.2v4 ;; sco3.2.[4-9]*) - os=$(echo $os | sed -e 's/sco3.2./sco3.2v/') + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` ;; sco*v* | scout) # Don't match below @@ -1372,7 +1367,13 @@ case $os in os=psos ;; qnx*) - os=qnx + case $cpu in + x86 | i*86) + ;; + *) + os=nto-$os + ;; + esac ;; hiux*) os=hiuxwe2 @@ -1390,7 +1391,7 @@ case $os in os=lynxos ;; mac[0-9]*) - os=$(echo "$os" | sed -e 's|mac|macos|') + os=`echo "$os" | sed -e 's|mac|macos|'` ;; opened*) os=openedition @@ -1399,10 +1400,10 @@ case $os in os=os400 ;; sunos5*) - os=$(echo "$os" | sed -e 's|sunos5|solaris2|') + os=`echo "$os" | sed -e 's|sunos5|solaris2|'` ;; sunos6*) - os=$(echo "$os" | sed -e 's|sunos6|solaris3|') + os=`echo "$os" | sed -e 's|sunos6|solaris3|'` ;; wince*) os=wince @@ -1436,7 +1437,7 @@ case $os in ;; # Preserve the version number of sinix5. sinix5.*) - os=$(echo $os | sed -e 's|sinix|sysv|') + os=`echo $os | sed -e 's|sinix|sysv|'` ;; sinix*) os=sysv4 @@ -1721,7 +1722,7 @@ case $os in | skyos* | haiku* | rdos* | toppers* | drops* | es* \ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ - | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*) + | nsk* | powerunix* | genode* | zvmoe* ) ;; # This one is extra strict with allowed versions sco3.2v2 | sco3.2v[4-9]* | sco5v6*) @@ -1740,8 +1741,6 @@ esac case $kernel-$os in linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* ) ;; - uclinux-uclibc* ) - ;; -dietlibc* | -newlib* | -musl* | -uclibc* ) # These are just libc implementations, not actual OSes, and thus # require a kernel. @@ -1752,8 +1751,6 @@ case $kernel-$os in ;; nto-qnx*) ;; - os2-emx) - ;; *-eabi* | *-gnueabi*) ;; -*) diff --git a/apple/configure b/apple/configure index bf19655..505c466 100755 --- a/apple/configure +++ b/apple/configure @@ -2663,12 +2663,7 @@ program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac + MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then diff --git a/apple/install-sh b/apple/install-sh index 20d8b2e..ec298b5 100755 --- a/apple/install-sh +++ b/apple/install-sh @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2018-03-11.20; # UTC +scriptversion=2020-11-14.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -69,6 +69,11 @@ posix_mkdir= # Desired mode of installed file. mode=0755 +# Create dirs (including intermediate dirs) using mode 755. +# This is like GNU 'install' as of coreutils 8.32 (2020). +mkdir_umask=22 + +backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= @@ -99,18 +104,28 @@ Options: --version display version info and exit. -c (ignored) - -C install only if different (preserve the last data modification time) + -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. + -p pass -p to $cpprog. -s $stripprog installed files. + -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG + +By default, rm is invoked with -f; when overridden with RMPROG, +it's up to you to specify -f if you want it. + +If -S is not specified, no backups are attempted. + +Email bug reports to bug-automake@gnu.org. +Automake home page: https://www.gnu.org/software/automake/ " while test $# -ne 0; do @@ -137,8 +152,13 @@ while test $# -ne 0; do -o) chowncmd="$chownprog $2" shift;; + -p) cpprog="$cpprog -p";; + -s) stripcmd=$stripprog;; + -S) backupsuffix="$2" + shift;; + -t) is_target_a_directory=always dst_arg=$2 @@ -255,6 +275,10 @@ do dstdir=$dst test -d "$dstdir" dstdir_status=$? + # Don't chown directories that already exist. + if test $dstdir_status = 0; then + chowncmd="" + fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command @@ -301,22 +325,6 @@ do if test $dstdir_status != 0; then case $posix_mkdir in '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; - - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac - # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then @@ -326,52 +334,49 @@ do fi posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - # Note that $RANDOM variable is not portable (e.g. dash); Use it - # here however when possible just to lower collision chance. - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - - trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 - - # Because "mkdir -p" follows existing symlinks and we likely work - # directly in world-writeable /tmp, make sure that the '$tmpdir' - # directory is successfully created first before we actually test - # 'mkdir -p' feature. - if (umask $mkdir_umask && - $mkdirprog $mkdir_mode "$tmpdir" && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - test_tmpdir="$tmpdir/a" - ls_ld_tmpdir=`ls -ld "$test_tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null - fi - trap '' 0;; - esac;; + # The $RANDOM variable is not portable (e.g., dash). Use it + # here however when possible just to lower collision chance. + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + + trap ' + ret=$? + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null + exit $ret + ' 0 + + # Because "mkdir -p" follows existing symlinks and we likely work + # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directory is successfully created first before we actually test + # 'mkdir -p'. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null + fi + trap '' 0;; esac if @@ -382,7 +387,7 @@ do then : else - # The umask is ridiculous, or mkdir does not conform to POSIX, + # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. @@ -411,7 +416,7 @@ do prefixes= else if $posix_mkdir; then - (umask=$mkdir_umask && + (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 @@ -488,6 +493,13 @@ do then rm -f "$dsttmp" else + # If $backupsuffix is set, and the file being installed + # already exists, attempt a backup. Don't worry if it fails, + # e.g., if mv doesn't support -f. + if test -n "$backupsuffix" && test -f "$dst"; then + $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null + fi + # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || @@ -502,9 +514,9 @@ do # file should still install successfully. { test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || + $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 diff --git a/apple/src/AbstractSession.h b/apple/src/AbstractSession.h new file mode 100644 index 0000000..d1e2566 --- /dev/null +++ b/apple/src/AbstractSession.h @@ -0,0 +1,56 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#ifndef FFMPEG_KIT_ABSTRACT_SESSION_H +#define FFMPEG_KIT_ABSTRACT_SESSION_H + +#import +#import "Session.h" + +/** + * Defines how long default "getAll" methods wait, in milliseconds. + */ +extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit; + +/** + * Abstract session implementation which includes common features shared by FFmpeg + * and FFprobe sessions. + */ +@interface AbstractSession : NSObject + +/** + * Creates a new abstract session. + * + * @param arguments command arguments + * @param executeDelegate session specific execute delegate + * @param logDelegate session specific log delegate + * @param logRedirectionStrategy session specific log redirection strategy + */ +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy; + +/** + * Waits for all asynchronous messages to be transmitted until the given timeout. + * + * @param timeout wait timeout in milliseconds + */ +- (void)waitForAsynchronousMessagesInTransmit:(int)timeout; + +@end + +#endif // FFMPEG_KIT_ABSTRACT_SESSION_H diff --git a/apple/src/AbstractSession.m b/apple/src/AbstractSession.m new file mode 100644 index 0000000..f7b17d0 --- /dev/null +++ b/apple/src/AbstractSession.m @@ -0,0 +1,235 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#import "AbstractSession.h" +#import "AtomicLong.h" +#import "ExecuteDelegate.h" +#import "FFmpegKit.h" +#import "FFmpegKitConfig.h" +#import "LogDelegate.h" +#import "ReturnCode.h" + +int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit = 5000; + +static AtomicLong *sessionIdGenerator = nil; + +@implementation AbstractSession { + long _sessionId; + id _executeDelegate; + id _logDelegate; + NSDate* _createTime; + NSDate* _startTime; + NSDate* _endTime; + NSArray* _arguments; + NSMutableArray* _logs; + NSRecursiveLock* _logsLock; + SessionState _state; + ReturnCode* _returnCode; + NSString* _failStackTrace; + LogRedirectionStrategy _logRedirectionStrategy; +} + ++ (void)initialize { + sessionIdGenerator = [[AtomicLong alloc] initWithValue:1]; +} + +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy { + self = [super init]; + if (self) { + _sessionId = [sessionIdGenerator incrementAndGet]; + _executeDelegate = executeDelegate; + _logDelegate = logDelegate; + _createTime = [NSDate date]; + _startTime = nil; + _endTime = nil; + _arguments = arguments; + _logs = [[NSMutableArray alloc] init]; + _logsLock = [[NSRecursiveLock alloc] init]; + _state = SessionStateCreated; + _returnCode = nil; + _failStackTrace = nil; + _logRedirectionStrategy = logRedirectionStrategy; + } + + return self; +} + +- (id)getExecuteDelegate { + return _executeDelegate; +} + +- (id)getLogDelegate { + return _logDelegate; +} + +- (long)getSessionId { + return _sessionId; +} + +- (NSDate*)getCreateTime { + return _createTime; +} + +- (NSDate*)getStartTime { + return _startTime; +} + +- (NSDate*)getEndTime { + return _endTime; +} + +- (long)getDuration { + NSDate* startTime = _startTime; + NSDate* endTime = _endTime; + if (startTime != nil && endTime != nil) { + return [[NSNumber numberWithDouble:([endTime timeIntervalSinceDate:startTime]*1000)] longValue]; + } + + return 0; +} + +- (NSArray*)getArguments { + return _arguments; +} + +- (NSString*)getCommand { + return [FFmpegKit argumentsToString:_arguments]; +} + +- (void)waitForAsynchronousMessagesInTransmit:(int)timeout { + NSDate* expireDate = [[NSDate date] dateByAddingTimeInterval:((double)timeout)/1000]; + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + while ([self thereAreAsynchronousMessagesInTransmit] && ([[NSDate date] timeIntervalSinceDate:expireDate] < 0)) { + dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 100 * NSEC_PER_MSEC)); + } +} + +- (NSArray*)getAllLogsWithTimeout:(int)waitTimeout { + [self waitForAsynchronousMessagesInTransmit:waitTimeout]; + + if ([self thereAreAsynchronousMessagesInTransmit]) { + NSLog(@"getAllLogsWithTimeout was called to return all logs but there are still logs being transmitted for session id %ld.", _sessionId); + } + + return [self getLogs]; +} + +- (NSArray*)getAllLogs { + return [self getAllLogsWithTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit]; +} + +- (NSArray*)getLogs { + [_logsLock lock]; + NSArray* logsCopy = [_logs copy]; + [_logsLock unlock]; + + return logsCopy; +} + +- (NSString*)getAllLogsAsStringWithTimeout:(int)waitTimeout { + [self waitForAsynchronousMessagesInTransmit:waitTimeout]; + + if ([self thereAreAsynchronousMessagesInTransmit]) { + NSLog(@"getAllLogsAsStringWithTimeout was called to return all logs but there are still logs being transmitted for session id %ld.", _sessionId); + } + + return [self getAllLogsAsString]; +} + +- (NSString*)getAllLogsAsString { + return [self getAllLogsAsStringWithTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit]; +} + +- (NSString*)getLogsAsString { + NSMutableString* concatenatedString = [[NSMutableString alloc] init]; + + [_logsLock lock]; + for (int i=0; i < [_logs count]; i++) { + [concatenatedString appendString:[[_logs objectAtIndex:i] getMessage]]; + } + [_logsLock unlock]; + + return concatenatedString; +} + +- (NSString*)getOutput { + return [self getAllLogsAsString]; +} + +- (SessionState)getState { + return _state; +} + +- (ReturnCode*)getReturnCode { + return _returnCode; +} + +- (NSString*)getFailStackTrace { + return _failStackTrace; +} + +- (LogRedirectionStrategy)getLogRedirectionStrategy { + return _logRedirectionStrategy; +} + +- (BOOL)thereAreAsynchronousMessagesInTransmit { + return ([FFmpegKitConfig messagesInTransmit:_sessionId] != 0); +} + +- (void)addLog:(Log*)log { + [_logsLock lock]; + [_logs addObject:log]; + [_logsLock unlock]; +} + +- (void)startRunning { + _state = SessionStateRunning; + _startTime = [NSDate date]; +} + +- (void)complete:(ReturnCode*)returnCode { + _returnCode = returnCode; + _state = SessionStateCompleted; + _endTime = [NSDate date]; +} + +- (void)fail:(NSException*)exception { + _failStackTrace = [NSString stringWithFormat:@"%@", [exception callStackSymbols]]; + _state = SessionStateFailed; + _endTime = [NSDate date]; +} + +- (BOOL)isFFmpeg { + // IMPLEMENTED IN SUBCLASSES + return false; +} + +- (BOOL)isFFprobe { + // IMPLEMENTED IN SUBCLASSES + return false; +} + +- (void)cancel { + if (_state == SessionStateRunning) { + [FFmpegKit cancel:_sessionId]; + } +} + +@end diff --git a/apple/src/ArchDetect.h b/apple/src/ArchDetect.h index cc935f9..25a6533 100644 --- a/apple/src/ArchDetect.h +++ b/apple/src/ArchDetect.h @@ -17,35 +17,30 @@ * along with FFmpegKit. If not, see . */ -#include -#include -#include -#include +#ifndef FFMPEG_KIT_ARCH_DETECT_H +#define FFMPEG_KIT_ARCH_DETECT_H + +#import /** - * This class is used to detect running architecture. + * Detects the running architecture. */ @interface ArchDetect : NSObject /** - * Returns running cpu architecture name. + * Returns architecture name of the cpu running. * - * @return running cpu architecture name as NSString + * @return architecture name of the cpu running */ + (NSString*)getCpuArch; /** - * Returns loaded architecture name. + * Returns architecture name loaded. * - * @return loaded architecture name as NSString + * @return architecture name loaded */ + (NSString*)getArch; -/** - * Returns whether FFmpegKit release is a long term release or not. - * - * @return yes=1 or no=0 - */ -+ (int)isLTSBuild; - @end + +#endif // FFMPEG_KIT_ARCH_DETECT_H diff --git a/apple/src/ArchDetect.m b/apple/src/ArchDetect.m index 128606b..5a7ec3e 100644 --- a/apple/src/ArchDetect.m +++ b/apple/src/ArchDetect.m @@ -17,32 +17,32 @@ * along with FFmpegKit. If not, see . */ -#include "ArchDetect.h" -#include "FFmpegKitConfig.h" -#include "FFmpegKit.h" +#import +#import +#import +#import "ArchDetect.h" +#import "FFmpegKitConfig.h" +#import "FFmpegKit.h" +#import "FFprobeKit.h" @implementation ArchDetect + (void)initialize { - [FFmpegKitConfig class]; [FFmpegKit class]; + [FFmpegKitConfig class]; + [FFprobeKit class]; } -/** - * Returns running cpu architecture name. - * - * @return running cpu architecture name as NSString - */ + (NSString*)getCpuArch { - NSMutableString *cpu = [[NSMutableString alloc] init]; + NSMutableString* cpu = [[NSMutableString alloc] init]; size_t size; cpu_type_t type; cpu_subtype_t subtype; size = sizeof(type); - sysctlbyname("hw.cputype", &type, &size, NULL, 0); + sysctlbyname("hw.cputype", &type, &size, nil, 0); size = sizeof(subtype); - sysctlbyname("hw.cpusubtype", &subtype, &size, NULL, 0); + sysctlbyname("hw.cpusubtype", &subtype, &size, nil, 0); if (type == CPU_TYPE_X86_64) { [cpu appendString:@"x86_64"]; @@ -118,9 +118,11 @@ case CPU_SUBTYPE_ARM_V7S: [cpu appendString:@"v7s"]; break; +#ifndef FFMPEG_KIT_LTS case CPU_SUBTYPE_ARM_V8: [cpu appendString:@"v8"]; break; +#endif } #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 120100 @@ -141,11 +143,6 @@ return cpu; } -/** - * Returns loaded architecture name. - * - * @return loaded architecture name as NSString - */ + (NSString*)getArch { NSMutableString *arch = [[NSMutableString alloc] init]; @@ -155,6 +152,10 @@ [arch appendString:@"armv7s"]; #elif FFMPEG_KIT_ARM64 [arch appendString:@"arm64"]; +#elif FFMPEG_KIT_ARM64_MAC_CATALYST + [arch appendString:@"arm64_mac_catalyst"]; +#elif FFMPEG_KIT_ARM64_SIMULATOR + [arch appendString:@"arm64_simulator"]; #elif FFMPEG_KIT_ARM64E [arch appendString:@"arm64e"]; #elif FFMPEG_KIT_I386 @@ -168,17 +169,4 @@ return arch; } -/** - * Returns whether FFmpegKit release is a long term release or not. - * - * @return yes=1 or no=0 - */ -+ (int)isLTSBuild { - #if defined(FFMPEG_KIT_LTS) - return 1; - #else - return 0; - #endif -} - @end diff --git a/apple/src/AtomicLong.h b/apple/src/AtomicLong.h index 2bb1622..5acd5ae 100644 --- a/apple/src/AtomicLong.h +++ b/apple/src/AtomicLong.h @@ -17,15 +17,22 @@ * along with FFmpegKit. If not, see . */ -#include +#ifndef FFMPEG_KIT_ATOMIC_LONG_H +#define FFMPEG_KIT_ATOMIC_LONG_H + +#import /** * Represents an atomic long data type. */ @interface AtomicLong : NSObject -- (instancetype)initWithInitialValue:(long)initialValue; +- (instancetype)initWithValue:(long)value; - (long)incrementAndGet; +- (long)getAndIncrement; + @end + +#endif // FFMPEG_KIT_ATOMIC_LONG_H diff --git a/apple/src/AtomicLong.m b/apple/src/AtomicLong.m index f084fe2..2bb0796 100644 --- a/apple/src/AtomicLong.m +++ b/apple/src/AtomicLong.m @@ -17,17 +17,23 @@ * along with FFmpegKit. If not, see . */ -#include "AtomicLong.h" +#import "AtomicLong.h" + +@interface AtomicLong() + +@property (strong) NSRecursiveLock* lock; + +@end @implementation AtomicLong { - NSRecursiveLock *lock; - long value; + long _value; } -- (instancetype)initWithInitialValue:(long)initialValue { +- (instancetype)initWithValue:(long)value { self = [super init]; if (self) { - value = initialValue; + _value = value; + _lock = [[NSRecursiveLock alloc] init]; } return self; @@ -36,10 +42,21 @@ - (long)incrementAndGet { long returnValue; - [lock lock]; - value += 1; - returnValue = value; - [lock unlock]; + [self.lock lock]; + _value += 1; + returnValue = _value; + [self.lock unlock]; + + return returnValue; +} + +- (long)getAndIncrement { + long returnValue; + + [self.lock lock]; + returnValue = _value; + _value += 1; + [self.lock unlock]; return returnValue; } diff --git a/apple/src/ExecuteDelegate.h b/apple/src/ExecuteDelegate.h index e7cfff1..706fab9 100644 --- a/apple/src/ExecuteDelegate.h +++ b/apple/src/ExecuteDelegate.h @@ -17,10 +17,43 @@ * along with FFmpegKit. If not, see . */ +#ifndef FFMPEG_KIT_EXECUTE_DELEGATE_H +#define FFMPEG_KIT_EXECUTE_DELEGATE_H + +#import +#import "Session.h" + +@protocol Session; + /** - * Use this delegate to receive an asynchronous execution result. + *

Delegate invoked when an asynchronous session ends running. + *

Session has either SessionStateCompleted or SessionStateFailed state when + * the delegate is invoked. + *

If it has SessionStateCompleted state, ReturnCode should be checked to + * see the execution result. + *

If getState returns SessionStateFailed then + * getFailStackTrace should be used to get the failure reason. + *

+ *  switch ([session getState]) {
+ *      case SessionStateCompleted:
+ *          ReturnCode *returnCode = [session getReturnCode];
+ *          break;
+ *      case SessionStateFailed:
+ *          NSString *failStackTrace = [session getFailStackTrace];
+ *          break;
+ *  }
+ * 
*/ @protocol ExecuteDelegate @required -- (void)executeCallback:(long)executionId :(int)returnCode; + +/** + * Called when an execution is completed. + * + * @param session session of the completed execution + */ +- (void)executeCallback:(id)session; + @end + +#endif // FFMPEG_KIT_EXECUTE_DELEGATE_H diff --git a/apple/src/FFmpegExecution.h b/apple/src/FFmpegExecution.h deleted file mode 100644 index c7b047c..0000000 --- a/apple/src/FFmpegExecution.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2020-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 . - */ - -#include - -/** - * Represents an ongoing FFmpeg execution. - */ -@interface FFmpegExecution : NSObject - -- (instancetype)initWithExecutionId:(long)newExecutionId andArguments:(NSArray*)arguments; - -- (NSDate*)getStartTime; - -- (long)getExecutionId; - -- (NSString*)getCommand; - -@end \ No newline at end of file diff --git a/apple/src/FFmpegExecution.m b/apple/src/FFmpegExecution.m deleted file mode 100644 index a314e5d..0000000 --- a/apple/src/FFmpegExecution.m +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2020-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 . - */ - -#include "FFmpegExecution.h" -#include "FFmpegKit.h" - -@implementation FFmpegExecution { - NSDate* startTime; - long executionId; - NSString* command; -} - -- (instancetype)initWithExecutionId:(long)newExecutionId andArguments:(NSArray*)arguments { - self = [super init]; - if (self) { - startTime = [NSDate date]; - executionId = newExecutionId; - command = [FFmpegKit argumentsToString:arguments]; - } - - return self; -} - -- (NSDate*)getStartTime { - return startTime; -} - -- (long)getExecutionId { - return executionId; -} - -- (NSString*)getCommand { - return command; -} - -@end \ No newline at end of file diff --git a/apple/src/FFmpegKit.h b/apple/src/FFmpegKit.h index d18c53d..50be34f 100644 --- a/apple/src/FFmpegKit.h +++ b/apple/src/FFmpegKit.h @@ -17,102 +17,168 @@ * along with FFmpegKit. If not, see . */ -#include -#include -#include -#include "ExecuteDelegate.h" +#ifndef FFMPEG_KIT_H +#define FFMPEG_KIT_H -/** Global library version */ -extern NSString *const FFMPEG_KIT_VERSION; +#import +#import +#import +#import "ExecuteDelegate.h" +#import "LogDelegate.h" +#import "FFmpegSession.h" +#import "StatisticsDelegate.h" /** - * Main class for FFmpeg operations. + *

Main class to run FFmpeg commands. Supports executing commands both + * synchronously and asynchronously. + *

+ * FFmpegSession *session = [FFmpegKit execute:@"-i file1.mp4 -c:v libxvid file1.avi"];
+ *
+ * FFmpegSession *asyncSession = [FFmpegKit executeAsync:@"-i file1.mp4 -c:v libxvid file1.avi" withExecuteDelegate:executeDelegate];
+ * 
+ *

Provides overloaded execute methods to define session specific delegates. + *

+ * FFmpegSession *asyncSession = [FFmpegKit executeAsync:@"-i file1.mp4 -c:v libxvid file1.avi" withExecuteDelegate:executeDelegate withLogDelegate:logDelegate withStatisticsDelegate:statisticsDelegate];
+ * 
*/ @interface FFmpegKit : NSObject /** - * Synchronously executes FFmpeg with arguments provided. + *

Synchronously executes FFmpeg with arguments provided. * * @param arguments FFmpeg command options/arguments as string array - * @return zero on successful execution, 255 on user cancel and non-zero on error + * @return FFmpeg session created for this execution */ -+ (int)executeWithArguments:(NSArray*)arguments; ++ (FFmpegSession*)executeWithArguments:(NSArray*)arguments; /** - * Asynchronously executes FFmpeg with arguments provided. Space character is used to split command into arguments. + *

Asynchronously executes FFmpeg with arguments provided. * - * @param arguments FFmpeg command options/arguments as string array - * @param delegate delegate that will be notified when execution is completed - * @return returns a unique id that represents this execution + * @param arguments FFmpeg command options/arguments as string array + * @param executeDelegate delegate that will be called when the execution is completed + * @return FFmpeg session created for this execution */ -+ (int)executeWithArgumentsAsync:(NSArray*)arguments withCallback:(id)delegate; ++ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate; /** - * Asynchronously executes FFmpeg with arguments provided. Space character is used to split command into arguments. + *

Asynchronously executes FFmpeg with arguments provided. * - * @param arguments FFmpeg command options/arguments as string array - * @param delegate delegate that will be notified when execution is completed - * @param queue dispatch queue that will be used to run this asynchronous operation - * @return returns a unique id that represents this execution + * @param arguments FFmpeg command options/arguments as string array + * @param executeDelegate delegate that will be called when the execution is completed + * @param logDelegate delegate that will receive logs + * @param statisticsDelegate delegate that will receive statistics + * @return FFmpeg session created for this execution */ -+ (int)executeWithArgumentsAsync:(NSArray*)arguments withCallback:(id)delegate andDispatchQueue:(dispatch_queue_t)queue; ++ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withStatisticsDelegate:(id)statisticsDelegate; /** - * Synchronously executes FFmpeg command provided. Space character is used to split command into arguments. + *

Asynchronously executes FFmpeg with arguments provided. * - * @param command FFmpeg command - * @return zero on successful execution, 255 on user cancel and non-zero on error + * @param arguments FFmpeg command options/arguments as string array + * @param executeDelegate delegate that will be called when the execution is completed + * @param queue dispatch queue that will be used to run this asynchronous operation + * @return FFmpeg session created for this execution */ -+ (int)execute:(NSString*)command; ++ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate onDispatchQueue:(dispatch_queue_t)queue; /** - * Asynchronously executes FFmpeg command provided. Space character is used to split command into arguments. - * - * @param command FFmpeg command - * @param delegate delegate that will be notified when execution is completed - * @return returns a unique id that represents this execution + *

Asynchronously executes FFmpeg with arguments provided. + * + * @param arguments FFmpeg command options/arguments as string array + * @param executeDelegate delegate that will be called when the execution is completed + * @param logDelegate delegate that will receive logs + * @param statisticsDelegate delegate that will receive statistics + * @param queue dispatch queue that will be used to run this asynchronous operation + * @return FFmpeg session created for this execution */ -+ (int)executeAsync:(NSString*)command withCallback:(id)delegate; ++ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withStatisticsDelegate:(id)statisticsDelegate onDispatchQueue:(dispatch_queue_t)queue; /** - * Asynchronously executes FFmpeg command provided. Space character is used to split command into arguments. + *

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. * * @param command FFmpeg command - * @param delegate delegate that will be notified when execution is completed - * @param queue dispatch queue that will be used to run this asynchronous operation - * @return returns a unique id that represents this execution + * @return FFmpeg session created for this execution */ -+ (int)executeAsync:(NSString*)command withCallback:(id)delegate andDispatchQueue:(dispatch_queue_t)queue; ++ (FFmpegSession*)execute:(NSString*)command; /** - * Synchronously executes FFmpeg command provided. Delimiter parameter is used to split command into arguments. + *

Asynchronously 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. * - * @param command FFmpeg command - * @param delimiter arguments delimiter - * @deprecated argument splitting mechanism used in this method is pretty simple and prone to errors. Consider - * using a more advanced method like execute or executeWithArguments - * @return zero on successful execution, 255 on user cancel and non-zero on error + * @param command FFmpeg command + * @param executeDelegate delegate that will be called when the execution is completed + * @return FFmpeg session created for this execution + */ ++ (FFmpegSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate; + +/** + *

Asynchronously 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. + * + * @param command FFmpeg command + * @param executeDelegate delegate that will be called when the execution is completed + * @param logDelegate delegate that will receive logs + * @param statisticsDelegate delegate that will receive statistics + * @return FFmpeg session created for this execution + */ ++ (FFmpegSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withStatisticsDelegate:(id)statisticsDelegate; + +/** + *

Asynchronously 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. + * + * @param command FFmpeg command + * @param executeDelegate delegate that will be called when the execution is completed + * @param queue dispatch queue that will be used to run this asynchronous operation + * @return FFmpeg session created for this execution + */ ++ (FFmpegSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate onDispatchQueue:(dispatch_queue_t)queue; + +/** + *

Asynchronously 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. + * + * @param command FFmpeg command + * @param executeDelegate delegate that will be called when the execution is completed + * @param logDelegate delegate that will receive logs + * @param statisticsDelegate delegate that will receive statistics + * @param queue dispatch queue that will be used to run this asynchronous operation + * @return FFmpeg session created for this execution */ -+ (int)execute:(NSString*)command delimiter:(NSString*)delimiter __attribute__((deprecated)); ++ (FFmpegSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withStatisticsDelegate:(id)statisticsDelegate onDispatchQueue:(dispatch_queue_t)queue; /** - * Cancels an ongoing operation. + *

Cancels all running sessions. * - * This function does not wait for termination to complete and returns immediately. + *

This function does not wait for termination to complete and returns immediately. */ + (void)cancel; /** - * Cancels an ongoing operation. + *

Cancels the session specified with sessionId. * - * This function does not wait for termination to complete and returns immediately. + *

This function does not wait for termination to complete and returns immediately. * - * @param executionId execution id + * @param sessionId id of the session that will be cancelled */ -+ (void)cancel:(long)executionId; ++ (void)cancel:(long)sessionId; /** - * Parses the given command into arguments. + *

Lists all FFmpeg sessions in the session history. + * + * @return all FFmpeg sessions in the session history + */ ++ (NSArray*)listSessions; + +/** + *

Parses the given command into arguments. Uses space character to split the arguments. + * Supports single and double quote characters. * * @param command string command * @return array of arguments @@ -120,18 +186,13 @@ extern NSString *const FFMPEG_KIT_VERSION; + (NSArray*)parseArguments:(NSString*)command; /** - *

Combines arguments into a string. + *

Concatenates arguments into a string adding a space character between two arguments. * * @param arguments arguments - * @return string containing all arguments + * @return concatenated string containing all arguments */ + (NSString*)argumentsToString:(NSArray*)arguments; -/** - *

Lists ongoing executions. - * - * @return list of ongoing executions - */ -+ (NSArray*)listExecutions; +@end -@end \ No newline at end of file +#endif // FFMPEG_KIT_H diff --git a/apple/src/FFmpegKit.m b/apple/src/FFmpegKit.m index 0f503e7..c5e957f 100644 --- a/apple/src/FFmpegKit.m +++ b/apple/src/FFmpegKit.m @@ -17,210 +17,98 @@ * along with FFmpegKit. If not, see . */ -#include "fftools_ffmpeg.h" - -#include "FFmpegKit.h" -#include "ArchDetect.h" -#include "AtomicLong.h" -#include "FFmpegExecution.h" -#include "FFmpegKitConfig.h" - -/** Forward declaration for function defined in fftools_ffmpeg.c */ -int ffmpeg_execute(int argc, char **argv); +#import "fftools_ffmpeg.h" +#import "ArchDetect.h" +#import "AtomicLong.h" +#import "FFmpegKit.h" +#import "FFmpegKitConfig.h" +#import "Packages.h" @implementation FFmpegKit -/** Global library version */ -NSString *const FFMPEG_KIT_VERSION = @"4.4"; - -extern int lastReturnCode; -extern NSMutableString *lastCommandOutput; - -long const DEFAULT_EXECUTION_ID = 0; -AtomicLong *executionIdCounter; - -extern __thread volatile long executionId; -int cancelRequested(long executionId); -void addExecution(long executionId); -void removeExecution(long executionId); - -NSMutableArray *executions; -NSLock *executionsLock; - -extern int configuredLogLevel; - + (void)initialize { [FFmpegKitConfig class]; - executionIdCounter = [[AtomicLong alloc] initWithInitialValue:3000]; - - executions = [[NSMutableArray alloc] init]; - executionsLock = [[NSLock alloc] init]; - - NSLog(@"Loaded ffmpeg-kit-%@-%@-%@-%@\n", [FFmpegKitConfig getPackageName], [ArchDetect getArch], [FFmpegKitConfig getVersion], [FFmpegKitConfig getBuildDate]); + NSLog(@"Loaded ffmpeg-kit-%@-%@-%@-%@\n", [Packages getPackageName], [ArchDetect getArch], [FFmpegKitConfig getVersion], [FFmpegKitConfig getBuildDate]); } -+ (int)executeWithId:(long)newExecutionId andArguments:(NSArray*)arguments { - lastCommandOutput = [[NSMutableString alloc] init]; - - // SETS DEFAULT LOG LEVEL BEFORE STARTING A NEW EXECUTION - av_log_set_level(configuredLogLevel); - - FFmpegExecution* currentFFmpegExecution = [[FFmpegExecution alloc] initWithExecutionId:newExecutionId andArguments:arguments]; - [executionsLock lock]; - [executions addObject: currentFFmpegExecution]; - [executionsLock unlock]; - - char **commandCharPArray = (char **)av_malloc(sizeof(char*) * ([arguments count] + 1)); - - /* PRESERVING CALLING FORMAT - * - * ffmpeg - */ - commandCharPArray[0] = (char *)av_malloc(sizeof(char) * ([LIB_NAME length] + 1)); - strcpy(commandCharPArray[0], [LIB_NAME UTF8String]); - - for (int i=0; i < [arguments count]; i++) { - NSString *argument = [arguments objectAtIndex:i]; - commandCharPArray[i + 1] = (char *) [argument UTF8String]; - } - - // REGISTER THE ID BEFORE STARTING EXECUTION - executionId = newExecutionId; - addExecution(newExecutionId); - - // RUN - lastReturnCode = ffmpeg_execute(([arguments count] + 1), commandCharPArray); - - // ALWAYS REMOVE THE ID FROM THE MAP - removeExecution(newExecutionId); - - // CLEANUP - av_free(commandCharPArray[0]); - av_free(commandCharPArray); - - [executionsLock lock]; - [executions removeObject: currentFFmpegExecution]; - [executionsLock unlock]; ++ (FFmpegSession*)executeWithArguments:(NSArray*)arguments { + FFmpegSession* session = [[FFmpegSession alloc] init:arguments]; + [FFmpegKitConfig ffmpegExecute:session]; + return session; +} - return lastReturnCode; ++ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate { + FFmpegSession* session = [[FFmpegSession alloc] init:arguments withExecuteDelegate:executeDelegate]; + [FFmpegKitConfig asyncFFmpegExecute:session]; + return session; } -/** - * Synchronously executes FFmpeg with arguments provided. - * - * @param arguments FFmpeg command options/arguments as string array - * @return zero on successful execution, 255 on user cancel and non-zero on error - */ -+ (int)executeWithArguments:(NSArray*)arguments { - return [self executeWithId:DEFAULT_EXECUTION_ID andArguments:arguments]; ++ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withStatisticsDelegate:(id)statisticsDelegate { + FFmpegSession* session = [[FFmpegSession alloc] init:arguments withExecuteDelegate:executeDelegate withLogDelegate:logDelegate withStatisticsDelegate:statisticsDelegate]; + [FFmpegKitConfig asyncFFmpegExecute:session]; + return session; } -/** - * Asynchronously executes FFmpeg with arguments provided. Space character is used to split command into arguments. - * - * @param arguments FFmpeg command options/arguments as string array - * @param delegate delegate that will be notified when execution is completed - * @return a unique id that represents this execution - */ -+ (int)executeWithArgumentsAsync:(NSArray*)arguments withCallback:(id)delegate { - return [self executeWithArgumentsAsync:arguments withCallback:delegate andDispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; ++ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate onDispatchQueue:(dispatch_queue_t)queue { + FFmpegSession* session = [[FFmpegSession alloc] init:arguments withExecuteDelegate:executeDelegate]; + [FFmpegKitConfig asyncFFmpegExecute:session onDispatchQueue:queue]; + return session; } -/** - * Asynchronously executes FFmpeg with arguments provided. Space character is used to split command into arguments. - * - * @param arguments FFmpeg command options/arguments as string array - * @param delegate delegate that will be notified when execution is completed - * @param queue dispatch queue that will be used to run this asynchronous operation - * @return a unique id that represents this execution - */ -+ (int)executeWithArgumentsAsync:(NSArray*)arguments withCallback:(id)delegate andDispatchQueue:(dispatch_queue_t)queue { - const long newExecutionId = [executionIdCounter incrementAndGet]; ++ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withStatisticsDelegate:(id)statisticsDelegate onDispatchQueue:(dispatch_queue_t)queue { + FFmpegSession* session = [[FFmpegSession alloc] init:arguments withExecuteDelegate:executeDelegate withLogDelegate:logDelegate withStatisticsDelegate:statisticsDelegate]; + [FFmpegKitConfig asyncFFmpegExecute:session onDispatchQueue:queue]; + return session; +} - dispatch_async(queue, ^{ - const int returnCode = [self executeWithId:newExecutionId andArguments:arguments]; - if (delegate != nil) { - [delegate executeCallback:executionId:returnCode]; - } - }); ++ (FFmpegSession*)execute:(NSString*)command { + FFmpegSession* session = [[FFmpegSession alloc] init:[FFmpegKit parseArguments:command]]; + [FFmpegKitConfig ffmpegExecute:session]; + return session; +} - return newExecutionId; ++ (FFmpegSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate { + FFmpegSession* session = [[FFmpegSession alloc] init:[FFmpegKit parseArguments:command] withExecuteDelegate:executeDelegate]; + [FFmpegKitConfig asyncFFmpegExecute:session]; + return session; } -/** - * Synchronously executes FFmpeg command provided. Space character is used to split command into arguments. - * - * @param command FFmpeg command - * @return zero on successful execution, 255 on user cancel and non-zero on error - */ -+ (int)execute:(NSString*)command { - return [self executeWithArguments: [self parseArguments: command]]; ++ (FFmpegSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withStatisticsDelegate:(id)statisticsDelegate { + FFmpegSession* session = [[FFmpegSession alloc] init:[FFmpegKit parseArguments:command] withExecuteDelegate:executeDelegate withLogDelegate:logDelegate withStatisticsDelegate:statisticsDelegate]; + [FFmpegKitConfig asyncFFmpegExecute:session]; + return session; } -/** - * Asynchronously executes FFmpeg command provided. Space character is used to split command into arguments. - * - * @param command FFmpeg command - * @param delegate delegate that will be notified when execution is completed - * @return a unique id that represents this execution - */ -+ (int)executeAsync:(NSString*)command withCallback:(id)delegate { - return [self executeAsync:command withCallback:delegate andDispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; ++ (FFmpegSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate onDispatchQueue:(dispatch_queue_t)queue { + FFmpegSession* session = [[FFmpegSession alloc] init:[FFmpegKit parseArguments:command] withExecuteDelegate:executeDelegate]; + [FFmpegKitConfig asyncFFmpegExecute:session onDispatchQueue:queue]; + return session; } -/** - * Asynchronously executes FFmpeg command provided. Space character is used to split command into arguments. - * - * @param command FFmpeg command - * @param delegate delegate that will be notified when execution is completed - * @param queue dispatch queue that will be used to run this asynchronous operation - * @return a unique id that represents this execution - */ -+ (int)executeAsync:(NSString*)command withCallback:(id)delegate andDispatchQueue:(dispatch_queue_t)queue { - return [self executeWithArgumentsAsync:[self parseArguments:command] withCallback:delegate andDispatchQueue:queue]; ++ (FFmpegSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withStatisticsDelegate:(id)statisticsDelegate onDispatchQueue:(dispatch_queue_t)queue { + FFmpegSession* session = [[FFmpegSession alloc] init:[FFmpegKit parseArguments:command] withExecuteDelegate:executeDelegate withLogDelegate:logDelegate withStatisticsDelegate:statisticsDelegate]; + [FFmpegKitConfig asyncFFmpegExecute:session onDispatchQueue:queue]; + return session; } -/** - * Synchronously executes FFmpeg command provided. Delimiter parameter is used to split command into arguments. - * - * @param command FFmpeg command - * @param delimiter arguments delimiter - * @return zero on successful execution, 255 on user cancel and non-zero on error - */ -+ (int)execute:(NSString*)command delimiter:(NSString*)delimiter { ++ (void)cancel { - // SPLITTING ARGUMENTS - NSArray* argumentArray = [command componentsSeparatedByString:(delimiter == nil ? @" ": delimiter)]; - return [self executeWithArguments:argumentArray]; + /* + * ZERO (0) IS A SPECIAL SESSION ID + * WHEN IT IS PASSED TO THIS METHOD, A SIGINT IS GENERATED WHICH CANCELS ALL ONGOING SESSIONS + */ + cancel_operation(0); } -/** - * Cancels an ongoing operation. - * - * This function does not wait for termination to complete and returns immediately. - */ -+ (void)cancel { - cancel_operation(DEFAULT_EXECUTION_ID); ++ (void)cancel:(long)sessionId { + cancel_operation(sessionId); } -/** - * Cancels an ongoing operation. - * - * This function does not wait for termination to complete and returns immediately. - * - * @param executionId execution id - */ -+ (void)cancel:(long)executionId { - cancel_operation(executionId); ++ (NSArray*)listSessions { + return [FFmpegKitConfig getFFmpegSessions]; } -/** - * Parses the given command into arguments. - * - * @param command string command - * @return array of arguments - */ + (NSArray*)parseArguments:(NSString*)command { NSMutableArray *argumentArray = [[NSMutableArray alloc] init]; NSMutableString *currentArgument = [[NSMutableString alloc] init]; @@ -272,15 +160,9 @@ extern int configuredLogLevel; return argumentArray; } -/** - *

Combines arguments into a string. - * - * @param arguments arguments - * @return string containing all arguments - */ + (NSString*)argumentsToString:(NSArray*)arguments { if (arguments == nil) { - return @"null"; + return @"nil"; } NSMutableString *string = [NSMutableString stringWithString:@""]; @@ -295,16 +177,4 @@ extern int configuredLogLevel; return string; } -/** - *

Lists ongoing executions. - * - * @return list of ongoing executions - */ -+ (NSArray*)listExecutions { - [executionsLock lock]; - NSArray *array = [NSArray arrayWithArray:executions]; - [executionsLock unlock]; - return array; -} - @end diff --git a/apple/src/FFmpegKitConfig.h b/apple/src/FFmpegKitConfig.h index f457298..dda9863 100644 --- a/apple/src/FFmpegKitConfig.h +++ b/apple/src/FFmpegKitConfig.h @@ -17,250 +17,362 @@ * along with FFmpegKit. If not, see . */ -#include -#include -#include -#include -#include "LogDelegate.h" -#include "StatisticsDelegate.h" +#ifndef FFMPEG_KIT_CONFIG_H +#define FFMPEG_KIT_CONFIG_H + +#import +#import +#import +#import +#import "ExecuteDelegate.h" +#import "FFmpegSession.h" +#import "FFprobeSession.h" +#import "LogDelegate.h" +#import "MediaInformationSession.h" +#import "StatisticsDelegate.h" + +/** Global library version */ +extern NSString* const FFmpegKitVersion; + +typedef NS_ENUM(NSUInteger, Signal) { + SignalInt = 2, + SignalQuit = 3, + SignalPipe = 13, + SignalTerm = 15, + SignalXcpu = 24 +}; -/** Common return code values */ -extern int const RETURN_CODE_SUCCESS; -extern int const RETURN_CODE_CANCEL; +/** + *

Configuration class of FFmpegKit library. Allows customizing the global library + * options. Provides helper methods to support additional resources. + */ +@interface FFmpegKitConfig : NSObject -/** Identifier used for IOS logging. */ -extern NSString *const LIB_NAME; +/** + *

Enables log and statistics redirection. + * + *

When redirection is enabled FFmpeg/FFprobe logs are redirected to NSLog and sessions + * collect log and statistics entries for the executions. It is possible to define global or + * session specific log/statistics delegates as well. + * + *

Note that redirection is enabled by default. If you do not want to use its functionality + * please use disableRedirection method to disable it. + */ ++ (void)enableRedirection; /** - * Print no output. + *

Disables log and statistics redirection. + * + *

When redirection is disabled logs are printed to stderr, all logs and statistics + * delegates are disabled and FFprobe's getMediaInformation methods + * do not work. */ -#define AV_LOG_QUIET -8 ++ (void)disableRedirection; /** - * Something went really wrong and we will crash now. + *

Sets and overrides fontconfig configuration directory. + * + * @param path directory that contains fontconfig configuration (fonts.conf) + * @return zero on success, non-zero on error */ -#define AV_LOG_PANIC 0 ++ (int)setFontconfigConfigurationPath:(NSString*)path; /** - * Something went wrong and recovery is not possible. - * For example, no header was found for a format which depends - * on headers or an illegal combination of parameters is used. + *

Registers the fonts inside the given path, so they become available to use in FFmpeg + * filters. + * + *

Note that you need to build FFmpegKit with fontconfig + * enabled or use a prebuilt package with fontconfig inside to be able to use + * fonts in FFmpeg. + * + * @param fontDirectoryPath directory that contains fonts (.ttf and .otf files) + * @param fontNameMapping custom font name mappings, useful to access your fonts with more + * friendly names */ -#define AV_LOG_FATAL 8 ++ (void)setFontDirectory:(NSString*)fontDirectoryPath with:(NSDictionary*)fontNameMapping; /** - * Something went wrong and cannot losslessly be recovered. - * However, not all future data is affected. + *

Registers the fonts inside the given array of font directories, so they become available + * to use in FFmpeg filters. + * + *

Note that you need to build FFmpegKit with fontconfig + * enabled or use a prebuilt package with fontconfig inside to be able to use + * fonts in FFmpeg. + * + * @param fontDirectoryList array of directories that contain fonts (.ttf and .otf files) + * @param fontNameMapping custom font name mappings, useful to access your fonts with more + * friendly names */ -#define AV_LOG_ERROR 16 ++ (void)setFontDirectoryList:(NSArray*)fontDirectoryList with:(NSDictionary*)fontNameMapping; /** - * Something somehow does not look correct. This may or may not - * lead to problems. An example would be the use of '-vstrict -2'. + *

Creates a new named pipe to use in FFmpeg operations. + * + *

Please note that creator is responsible of closing created pipes. + * + * @return the full path of the named pipe */ -#define AV_LOG_WARNING 24 ++ (NSString*)registerNewFFmpegPipe; /** - * Standard information. + *

Closes a previously created FFmpeg pipe. + * + * @param ffmpegPipePath full path of the FFmpeg pipe */ -#define AV_LOG_INFO 32 ++ (void)closeFFmpegPipe:(NSString*)ffmpegPipePath; /** - * Detailed information. + *

Returns the version of FFmpeg bundled within FFmpegKit library. + * + * @return the version of FFmpeg */ -#define AV_LOG_VERBOSE 40 ++ (NSString*)getFFmpegVersion; /** - * Stuff which is only useful for libav* developers. + * Returns FFmpegKit library version. + * + * @return FFmpegKit version */ -#define AV_LOG_DEBUG 48 ++ (NSString*)getVersion; /** - * This class is used to configure FFmpegKit library utilities/tools. + *

Returns whether FFmpegKit release is a Long Term Release or not. * - * 1. LogDelegate: This class redirects FFmpeg/FFprobe output to NSLog by default. As - * an alternative, it is possible not to print messages to NSLog and pass them to a - * LogDelegate function. This function can decide whether to print these logs, show them - * inside another container or ignore them. + * @return true/yes or false/no + */ ++ (int)isLTSBuild; + +/** + * Returns FFmpegKit library build date. * - * 2. setLogLevel:/getLogLevel: Use this methods to set/get - * FFmpeg/FFprobe log severity. + * @return FFmpegKit library build date + */ ++ (NSString*)getBuildDate; + +/** + *

Sets an environment variable. * - * 3. StatsDelegate: It is possible to receive statistics about ongoing - * operation by defining a StatsDelegate or by calling - * getLastReceivedStats method. + * @param variableName environment variable name + * @param variableValue environment variable value + * @return zero on success, non-zero on error + */ ++ (int)setEnvironmentVariable:(NSString*)variableName value:(NSString*)variableValue; + +/** + *

Registers a new ignored signal. Ignored signals are not handled by FFmpegKit + * library. * - * 4. Font configuration: It is possible to register custom fonts with - * setFontconfigConfigurationPath: and - * setFontDirectory:with: methods. + * @param signal signal to be ignored + */ ++ (void)ignoreSignal:(Signal)signal; + +/** + *

Synchronously executes the FFmpeg session provided. * + * @param ffmpegSession FFmpeg session which includes command options/arguments */ -@interface FFmpegKitConfig : NSObject ++ (void)ffmpegExecute:(FFmpegSession*)ffmpegSession; /** - * Enables log and statistics redirection. - * When redirection is not enabled FFmpeg/FFprobe logs are printed to stderr. By enabling - * redirection, they are routed to NSLog and can be routed further to a log delegate. - * Statistics redirection behaviour is similar. Statistics are not printed at all if - * redirection is not enabled. If it is enabled then it is possible to define a statistics - * delegate but if you don't, they are not printed anywhere and only saved as - * 'lastReceivedStatistics' data which can be polled with - * '{@link #'getLastReceivedStatistics()'. - * Note that redirection is enabled by default. If you do not want to use its functionality - * please use 'disableRedirection()' to disable it. + *

Synchronously executes the FFprobe session provided. + * + * @param ffprobeSession FFprobe session which includes command options/arguments */ -+ (void)enableRedirection; ++ (void)ffprobeExecute:(FFprobeSession*)ffprobeSession; /** - * Disables log and statistics redirection. + *

Synchronously executes the media information session provided. + * + * @param mediaInformationSession media information session which includes command options/arguments + * @param waitTimeout max time to wait until media information is transmitted */ -+ (void)disableRedirection; ++ (void)getMediaInformationExecute:(MediaInformationSession*)mediaInformationSession withTimeout:(int)waitTimeout; /** - * Returns log level. + *

Asynchronously executes the FFmpeg session provided. * - * @return log level + * @param ffmpegSession FFmpeg session which includes command options/arguments */ -+ (int)getLogLevel; ++ (void)asyncFFmpegExecute:(FFmpegSession*)ffmpegSession; /** - * Sets log level. + *

Asynchronously executes the FFmpeg session provided. * - * @param level log level + * @param ffmpegSession FFmpeg session which includes command options/arguments + * @param queue dispatch queue that will be used to run this asynchronous operation */ -+ (void)setLogLevel:(int)level; ++ (void)asyncFFmpegExecute:(FFmpegSession*)ffmpegSession onDispatchQueue:(dispatch_queue_t)queue; /** - * Converts int log level to string. + *

Asynchronously executes the FFprobe session provided. * - * @param level value - * @return string value + * @param ffprobeSession FFprobe session which includes command options/arguments */ -+ (NSString*)logLevelToString:(int)level; ++ (void)asyncFFprobeExecute:(FFprobeSession*)ffprobeSession; /** - * Sets a LogDelegate. logCallback method inside LogDelegate is used to redirect logs. + *

Asynchronously executes the FFprobe session provided. * - * @param newLogDelegate log delegate or nil to disable a previously defined delegate + * @param ffprobeSession FFprobe session which includes command options/arguments + * @param queue dispatch queue that will be used to run this asynchronous operation */ -+ (void)setLogDelegate:(id)newLogDelegate; ++ (void)asyncFFprobeExecute:(FFprobeSession*)ffprobeSession onDispatchQueue:(dispatch_queue_t)queue; /** - * Sets a StatisticsDelegate. statisticsCallback method inside StatisticsDelegate is used to redirect statistics. + *

Asynchronously executes the media information session provided. * - * @param newStatisticsDelegate statistics delegate or nil to disable a previously defined delegate + * @param mediaInformationSession media information session which includes command options/arguments + * @param waitTimeout max time to wait until media information is transmitted */ -+ (void)setStatisticsDelegate:(id)newStatisticsDelegate; ++ (void)asyncGetMediaInformationExecute:(MediaInformationSession*)mediaInformationSession withTimeout:(int)waitTimeout; /** - * Returns the last received statistics data. It is recommended to call it before starting a new execution. + *

Asynchronously executes the media information session provided. * - * @return last received statistics data + * @param mediaInformationSession media information session which includes command options/arguments + * @param queue dispatch queue that will be used to run this asynchronous operation + * @param waitTimeout max time to wait until media information is transmitted */ -+ (Statistics*)getLastReceivedStatistics; ++ (void)asyncGetMediaInformationExecute:(MediaInformationSession*)mediaInformationSession onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout; /** - * Resets last received statistics. + *

Sets a global log delegate to redirect FFmpeg/FFprobe logs. + * + * @param logDelegate log delegate or nil to disable a previously defined log delegate */ -+ (void)resetStatistics; ++ (void)enableLogDelegate:(id)logDelegate; /** - * Sets and overrides fontconfig configuration directory. + *

Sets a global statistics delegate to redirect FFmpeg statistics. * - * @param path directory which contains fontconfig configuration (fonts.conf) + * @param statisticsDelegate statistics delegate or nil to disable a previously defined statistics delegate */ -+ (void)setFontconfigConfigurationPath:(NSString*)path; ++ (void)enableStatisticsDelegate:(id)statisticsDelegate; /** - * Registers fonts inside the given path, so they are available to use in FFmpeg filters. + *

Sets a global execute delegate to receive execution results. * - * Note that you need to build FFmpegKit with fontconfig - * enabled or use a prebuilt package with fontconfig inside to use this feature. + * @param executeDelegate execute delegate or nil to disable a previously execute delegate + */ ++ (void)enableExecuteDelegate:(id)executeDelegate; + +/** + *

Returns the global execute delegate. * - * @param fontDirectoryPath directory which contains fonts (.ttf and .otf files) - * @param fontNameMapping custom font name mappings, useful to access your fonts with more friendly names + * @return global execute delegate */ -+ (void)setFontDirectory:(NSString*)fontDirectoryPath with:(NSDictionary*)fontNameMapping; ++ (id)getExecuteDelegate; /** - * Returns package name. + * Returns the current log level. * - * @return guessed package name according to supported external libraries + * @return current log level */ -+ (NSString*)getPackageName; ++ (int)getLogLevel; /** - * Returns supported external libraries. + * Sets the log level. * - * @return array of supported external libraries + * @param level new log level */ -+ (NSArray*)getExternalLibraries; ++ (void)setLogLevel:(int)level; /** - * Creates a new named pipe to use in FFmpeg operations. + * Converts int log level to string. * - * Please note that creator is responsible of closing created pipes. + * @param level value + * @return string value + */ ++ (NSString*)logLevelToString:(int)level; + +/** + * Returns the session history size. * - * @return the full path of named pipe + * @return session history size */ -+ (NSString*)registerNewFFmpegPipe; ++ (int)getSessionHistorySize; /** - * Closes a previously created FFmpeg pipe. + * Sets the session history size. * - * @param ffmpegPipePath full path of ffmpeg pipe + * @param sessionHistorySize session history size, should be smaller than 1000 */ -+ (void)closeFFmpegPipe:(NSString*)ffmpegPipePath; ++ (void)setSessionHistorySize:(int)sessionHistorySize; /** - * Returns FFmpeg version bundled within the library. + * Returns the session specified with sessionId from the session history. * - * @return FFmpeg version + * @param sessionId session identifier + * @return session specified with sessionId or nil if it is not found in the history */ -+ (NSString*)getFFmpegVersion; ++ (id)getSession:(long)sessionId; /** - * Returns FFmpegKit library version. + * Returns the last session created from the session history. * - * @return FFmpegKit version + * @return the last session created or nil if session history is empty */ -+ (NSString*)getVersion; ++ (id)getLastSession; /** - * Returns FFmpegKit library build date. + * Returns the last session completed from the session history. * - * @return FFmpegKit library build date + * @return the last session completed. If there are no completed sessions in the history this + * method will return nil */ -+ (NSString*)getBuildDate; ++ (id)getLastCompletedSession; + +/** + *

Returns all sessions in the session history. + * + * @return all sessions in the session history + */ ++ (NSArray*)getSessions; /** - * Returns return code of last executed command. + *

Returns all FFmpeg sessions in the session history. * - * @return return code of last executed command + * @return all FFmpeg sessions in the session history */ -+ (int)getLastReturnCode; ++ (NSArray*)getFFmpegSessions; /** - * Returns log output of last executed single FFmpeg/FFprobe command. + *

Returns all FFprobe sessions in the session history. * - * This method does not support executing multiple concurrent commands. If you execute - * multiple commands at the same time, this method will return output from all executions. + * @return all FFprobe sessions in the session history + */ ++ (NSArray*)getFFprobeSessions; + +/** + *

Returns sessions that have the given state. * - * Please note that disabling redirection using FFmpegKitConfig.disableRedirection() method - * also disables this functionality. + * @return sessions that have the given state from the session history + */ ++ (NSArray*)getSessionsByState:(SessionState)state; + +/** + * Returns the active log redirection strategy. * - * @return output of last executed command + * @return log redirection strategy */ -+ (NSString*)getLastCommandOutput; ++ (LogRedirectionStrategy)getLogRedirectionStrategy; /** - * Registers a new ignored signal. Ignored signals are not handled by the library. + *

Sets the log redirection strategy * - * By default, the following 5 signals are handled: SIGINT, SIGQUIT, SIGPIPE, SIGTERM and SIGXCPU. Any of them can be - * ignored. + * @param logRedirectionStrategy log redirection strategy + */ ++ (void)setLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy; + +/** + *

Returns the number of async messages that are not transmitted to the delegates for + * this session. * - * @param signum signal number to ignore + * @param sessionId id of the session + * @return number of async messages that are not transmitted to the delegates for this session */ -+ (void)ignoreSignal:(int)signum; ++ (int)messagesInTransmit:(long)sessionId; @end + +#endif // FFMPEG_KIT_CONFIG_H diff --git a/apple/src/FFmpegKitConfig.m b/apple/src/FFmpegKitConfig.m index 41152fe..cf379ef 100644 --- a/apple/src/FFmpegKitConfig.m +++ b/apple/src/FFmpegKitConfig.m @@ -17,18 +17,89 @@ * along with FFmpegKit. If not, see . */ -#include -#include -#include "libavutil/ffversion.h" -#include "fftools_ffmpeg.h" -#include "ArchDetect.h" -#include "FFmpegKitConfig.h" -#include "FFmpegKit.h" - -typedef enum { - LogType = 1, - StatisticsType = 2 -} CallbackType; +#import +#import +#import +#import "libavutil/ffversion.h" +#import "fftools_ffmpeg.h" +#import "ArchDetect.h" +#import "AtomicLong.h" +#import "FFmpegKit.h" +#import "FFmpegKitConfig.h" +#import "FFmpegSession.h" +#import "FFprobeKit.h" +#import "FFprobeSession.h" +#import "Level.h" +#import "LogRedirectionStrategy.h" +#import "MediaInformationSession.h" +#import "SessionState.h" + +/** Global library version */ +NSString* const FFmpegKitVersion = @"4.4"; + +/** + * Prefix of named pipes created by ffmpeg-kit. + */ +NSString* const FFmpegKitNamedPipePrefix = @"fk_pipe_"; + +/** + * Generates ids for named ffmpeg kit pipes. + */ +static AtomicLong* pipeIndexGenerator; + +/* Session history variables */ +static int sessionHistorySize; +static volatile NSMutableDictionary* sessionHistoryMap; +static NSMutableArray* sessionHistoryList; +static NSRecursiveLock* sessionHistoryLock; + +/** Session control variables */ +const int SESSION_MAP_SIZE = 1000; +static atomic_short sessionMap[SESSION_MAP_SIZE]; +static atomic_int sessionInTransitMessageCountMap[SESSION_MAP_SIZE]; + +static dispatch_queue_t asyncDispatchQueue; + +/** Holds delegate defined to redirect logs */ +static id logDelegate; + +/** Holds delegate defined to redirect statistics */ +static id statisticsDelegate; + +/** Holds delegate defined to redirect asynchronous execution results */ +static id executeDelegate; + +static LogRedirectionStrategy globalLogRedirectionStrategy; + +/** Redirection control variables */ +static int redirectionEnabled; +static NSRecursiveLock *lock; +static dispatch_semaphore_t semaphore; +static NSMutableArray *callbackDataArray; + +/** Fields that control the handling of SIGNALs */ +volatile int handleSIGQUIT = 1; +volatile int handleSIGINT = 1; +volatile int handleSIGTERM = 1; +volatile int handleSIGXCPU = 1; +volatile int handleSIGPIPE = 1; + +/** Holds the id of the current execution */ +__thread volatile long _sessionId = 0; + +/** Holds the default log level */ +int configuredLogLevel = LevelAVLogInfo; + +/** Forward declaration for function defined in fftools_ffmpeg.c */ +int ffmpeg_execute(int argc, char **argv); + +/** Forward declaration for function defined in fftools_ffprobe.c */ +int ffprobe_execute(int argc, char **argv); + +typedef NS_ENUM(NSUInteger, CallbackType) { + LogType, + StatisticsType +}; /** * Callback data class. @@ -38,35 +109,34 @@ typedef enum { @end @implementation CallbackData { - - CallbackType type; - long executionId; // execution id - - int logLevel; // log level - NSString *logData; // log data - - int statisticsFrameNumber; // statistics frame number - float statisticsFps; // statistics fps - float statisticsQuality; // statistics quality - int64_t statisticsSize; // statistics size - int statisticsTime; // statistics time - double statisticsBitrate; // statistics bitrate - double statisticsSpeed; // statistics speed + CallbackType _type; + long _sessionId; // session id + + int _logLevel; // log level + NSString* _logData; // log data + + int _statisticsFrameNumber; // statistics frame number + float _statisticsFps; // statistics fps + float _statisticsQuality; // statistics quality + int64_t _statisticsSize; // statistics size + int _statisticsTime; // statistics time + double _statisticsBitrate; // statistics bitrate + double _statisticsSpeed; // statistics speed } - - (instancetype)initWithId:(long)currentExecutionId logLevel:(int)newLogLevel data:(NSString*)newData { + - (instancetype)init:(long)sessionId logLevel:(int)logLevel data:(NSString*)logData { self = [super init]; if (self) { - type = LogType; - executionId = currentExecutionId; - logLevel = newLogLevel; - logData = newData; + _type = LogType; + _sessionId = sessionId; + _logLevel = logLevel; + _logData = logData; } return self; } - - (instancetype)initWithId:(long)currentExecutionId + - (instancetype)init:(long)sessionId videoFrameNumber:(int)videoFrameNumber fps:(float)videoFps quality:(float)videoQuality @@ -76,116 +146,78 @@ typedef enum { speed:(double)speed { self = [super init]; if (self) { - type = StatisticsType; - executionId = currentExecutionId; - statisticsFrameNumber = videoFrameNumber; - statisticsFps = videoFps; - statisticsQuality = videoQuality; - statisticsSize = size; - statisticsTime = time; - statisticsBitrate = bitrate; - statisticsSpeed = speed; + _type = StatisticsType; + _sessionId = sessionId; + _statisticsFrameNumber = videoFrameNumber; + _statisticsFps = videoFps; + _statisticsQuality = videoQuality; + _statisticsSize = size; + _statisticsTime = time; + _statisticsBitrate = bitrate; + _statisticsSpeed = speed; } return self; } - (CallbackType)getType { - return type; + return _type; } -- (long)getExecutionId { - return executionId; +- (long)getSessionId { + return _sessionId; } - (int)getLogLevel { - return logLevel; + return _logLevel; } - (NSString*)getLogData { - return logData; + return _logData; } - (int)getStatisticsFrameNumber { - return statisticsFrameNumber; + return _statisticsFrameNumber; } - (float)getStatisticsFps { - return statisticsFps; + return _statisticsFps; } - (float)getStatisticsQuality { - return statisticsQuality; + return _statisticsQuality; } - (int64_t)getStatisticsSize { - return statisticsSize; + return _statisticsSize; } - (int)getStatisticsTime { - return statisticsTime; + return _statisticsTime; } - (double)getStatisticsBitrate { - return statisticsBitrate; + return _statisticsBitrate; } - (double)getStatisticsSpeed { - return statisticsSpeed; + return _statisticsSpeed; } @end -/** Execution map variables */ -const int EXECUTION_MAP_SIZE = 1000; -static volatile int executionMap[EXECUTION_MAP_SIZE]; -static NSRecursiveLock *executionMapLock; - -/** Redirection control variables */ -static int redirectionEnabled; -static NSRecursiveLock *lock; -static dispatch_semaphore_t semaphore; -static NSMutableArray *callbackDataArray; - -/** Holds delegate defined to redirect logs */ -static id logDelegate = nil; - -/** Holds delegate defined to redirect statistics */ -static id statisticsDelegate = nil; - -/** Common return code values */ -int const RETURN_CODE_SUCCESS = 0; -int const RETURN_CODE_CANCEL = 255; - -int lastReturnCode; -NSMutableString *lastCommandOutput; - -NSString *const LIB_NAME = @"ffmpeg-kit"; -NSString *const FFMPEG_KIT_PIPE_PREFIX = @"mf_pipe_"; - -static Statistics *lastReceivedStatistics = nil; - -static NSMutableArray *supportedExternalLibraries; - -static int lastCreatedPipeIndex; - -/** Fields that control the handling of SIGNALs */ -volatile int handleSIGQUIT = 1; -volatile int handleSIGINT = 1; -volatile int handleSIGTERM = 1; -volatile int handleSIGXCPU = 1; -volatile int handleSIGPIPE = 1; - -/** Holds the id of the current execution */ -__thread volatile long executionId = 0; - -/** Holds the default log level */ -int configuredLogLevel = AV_LOG_INFO; - +/** + * Waits on the callback semaphore for the given time. + * + * @param milliSeconds wait time in milliseconds + */ void callbackWait(int milliSeconds) { dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(milliSeconds * NSEC_PER_MSEC))); } +/** + * Notifies threads waiting on callback semaphore. + */ void callbackNotify() { dispatch_semaphore_signal(semaphore); } @@ -197,41 +229,30 @@ void callbackNotify() { * @param logData log data */ void logCallbackDataAdd(int level, NSString *logData) { - CallbackData *callbackData = [[CallbackData alloc] initWithId:executionId logLevel:level data:logData]; - + CallbackData* callbackData = [[CallbackData alloc] init:_sessionId logLevel:level data:logData]; + [lock lock]; [callbackDataArray addObject:callbackData]; - [lastCommandOutput appendString:logData]; [lock unlock]; callbackNotify(); + + atomic_fetch_add(&sessionInTransitMessageCountMap[_sessionId % SESSION_MAP_SIZE], 1); } /** * Adds statistics data to the end of callback data list. */ void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed) { - CallbackData *callbackData = [[CallbackData alloc] initWithId:executionId videoFrameNumber:frameNumber fps:fps quality:quality size:size time:time bitrate:bitrate speed:speed]; + CallbackData *callbackData = [[CallbackData alloc] init:_sessionId videoFrameNumber:frameNumber fps:fps quality:quality size:size time:time bitrate:bitrate speed:speed]; [lock lock]; [callbackDataArray addObject:callbackData]; [lock unlock]; callbackNotify(); -} - -/** - * Adds an execution id to the execution map. - * - * @param id execution id - */ -void addExecution(long id) { - [executionMapLock lock]; - - int key = id % EXECUTION_MAP_SIZE; - executionMap[key] = 1; - - [executionMapLock unlock]; + + atomic_fetch_add(&sessionInTransitMessageCountMap[_sessionId % SESSION_MAP_SIZE], 1); } /** @@ -243,8 +264,10 @@ CallbackData *callbackDataRemove() { [lock lock]; @try { - newData = [callbackDataArray objectAtIndex:0]; - [callbackDataArray removeObjectAtIndex:0]; + if ([callbackDataArray count] > 0) { + newData = [callbackDataArray objectAtIndex:0]; + [callbackDataArray removeObjectAtIndex:0]; + } } @catch(NSException *exception) { // DO NOTHING } @finally { @@ -255,42 +278,48 @@ CallbackData *callbackDataRemove() { } /** - * Removes an execution id from the execution map. + * Adds a session id to the session map. * - * @param id execution id + * @param sessionId session id */ -void removeExecution(long id) { - [executionMapLock lock]; - - int key = id % EXECUTION_MAP_SIZE; - executionMap[key] = 0; +void addSession(long sessionId) { + atomic_store(&sessionMap[sessionId % SESSION_MAP_SIZE], 1); +} - [executionMapLock unlock]; +/** + * Removes a session id from the session map. + * + * @param sessionId session id + */ +void removeSession(long sessionId) { + atomic_store(&sessionMap[sessionId % SESSION_MAP_SIZE], 0); } /** - * Checks whether a cancel request for the given execution id exists in the execution map. + * Checks whether a cancel request for the given session id exists in the session map. * - * @param id execution id + * @param sessionId session id * @return 1 if exists, false otherwise */ -int cancelRequested(long id) { - int found = 0; - - [executionMapLock lock]; - - int key = id % EXECUTION_MAP_SIZE; - if (executionMap[key] == 0) { - found = 1; +int cancelRequested(long sessionId) { + if (atomic_load(&sessionMap[sessionId % SESSION_MAP_SIZE]) == 2) { + return 1; + } else { + return 0; } +} - [executionMapLock unlock]; - - return found; +/** + * Resets the number of messages in transmit for this session. + * + * @param sessionId session id + */ +void resetMessagesInTransmit(long sessionId) { + atomic_store(&sessionInTransitMessageCountMap[sessionId % SESSION_MAP_SIZE], 0); } /** - * Callback function for FFmpeg logs. + * Callback function for FFmpeg/FFprobe logs. * * @param ptr pointer to AVClass struct * @param level log level @@ -305,8 +334,8 @@ void ffmpegkit_log_callback_function(void *ptr, int level, const char* format, v } int activeLogLevel = av_log_get_level(); - // AV_LOG_STDERR logs are always redirected - if ((activeLogLevel == AV_LOG_QUIET && level != AV_LOG_STDERR) || (level > activeLogLevel)) { + // LevelAVLogStdErr logs are always redirected + if ((activeLogLevel == LevelAVLogQuiet && level != LevelAVLogStdErr) || (level > activeLogLevel)) { return; } @@ -332,12 +361,123 @@ void ffmpegkit_statistics_callback_function(int frameNumber, float fps, float qu statisticsCallbackDataAdd(frameNumber, fps, quality, size, time, bitrate, speed); } +void process_log(long sessionId, int levelValue, NSString* logMessage) { + int activeLogLevel = av_log_get_level(); + Log* log = [[Log alloc] init:sessionId:levelValue:logMessage]; + BOOL globalDelegateDefined = false; + BOOL sessionDelegateDefined = false; + LogRedirectionStrategy activeLogRedirectionStrategy = globalLogRedirectionStrategy; + + // LevelAVLogStdErr logs are always redirected + if ((activeLogLevel == LevelAVLogQuiet && levelValue != LevelAVLogStdErr) || (levelValue > activeLogLevel)) { + // LOG NEITHER PRINTED NOR FORWARDED + return; + } + + id session = [FFmpegKitConfig getSession:sessionId]; + if (session != nil) { + activeLogRedirectionStrategy = [session getLogRedirectionStrategy]; + [session addLog:log]; + + if ([session getLogDelegate] != nil) { + sessionDelegateDefined = TRUE; + + @try { + // NOTIFY SESSION DELEGATE DEFINED + [[session getLogDelegate] logCallback:log]; + } + @catch(NSException* exception) { + NSLog(@"Exception thrown inside session LogDelegate block. %@", [exception callStackSymbols]); + } + } + } + + id activeLogDelegate = logDelegate; + if (activeLogDelegate != nil) { + globalDelegateDefined = TRUE; + + @try { + // NOTIFY GLOBAL DELEGATE DEFINED + [activeLogDelegate logCallback:log]; + } + @catch(NSException* exception) { + NSLog(@"Exception thrown inside global LogDelegate block. %@", [exception callStackSymbols]); + } + } + + // EXECUTE THE LOG STRATEGY + switch (activeLogRedirectionStrategy) { + case LogRedirectionStrategyNeverPrintLogs: { + return; + } + case LogRedirectionStrategyPrintLogsWhenGlobalDelegateNotDefined: { + if (globalDelegateDefined) { + return; + } + } + break; + case LogRedirectionStrategyPrintLogsWhenSessionDelegateNotDefined: { + if (sessionDelegateDefined) { + return; + } + } + case LogRedirectionStrategyPrintLogsWhenNoDelegatesDefined: { + if (globalDelegateDefined || sessionDelegateDefined) { + return; + } + } + case LogRedirectionStrategyAlwaysPrintLogs: { + } + } + + // PRINT LOGS + switch (levelValue) { + case LevelAVLogQuiet: + // PRINT NO OUTPUT + break; + default: + // WRITE TO NSLOG + NSLog(@"%@: %@", [FFmpegKitConfig logLevelToString:levelValue], logMessage); + break; + } +} + +void process_statistics(long sessionId, int videoFrameNumber, float videoFps, float videoQuality, long size, int time, double bitrate, double speed) { + + Statistics *statistics = [[Statistics alloc] init:sessionId videoFrameNumber:videoFrameNumber videoFps:videoFps videoQuality:videoQuality size:size time:time bitrate:bitrate speed:speed]; + + id session = [FFmpegKitConfig getSession:sessionId]; + if (session != nil && [session isFFmpeg]) { + FFmpegSession *ffmpegSession = (FFmpegSession*)session; + [ffmpegSession addStatistics:statistics]; + + if ([ffmpegSession getStatisticsDelegate] != nil) { + @try { + [[ffmpegSession getStatisticsDelegate] statisticsCallback:statistics]; + } + @catch(NSException* exception) { + NSLog(@"Exception thrown inside session StatisticsDelegate block. %@", [exception callStackSymbols]); + } + } + } + + id activeStatisticsDelegate = statisticsDelegate; + if (activeStatisticsDelegate != nil) { + @try { + [activeStatisticsDelegate statisticsCallback:statistics]; + } + @catch(NSException* exception) { + NSLog(@"Exception thrown inside global StatisticsDelegate block. %@", [exception callStackSymbols]); + } + } +} + /** - * Forwards callback messages to Delegates. + * Forwards asynchronous messages to Delegates. */ void callbackBlockFunction() { int activeLogLevel = av_log_get_level(); - if ((activeLogLevel != AV_LOG_QUIET) && (AV_LOG_DEBUG <= activeLogLevel)) { + if ((activeLogLevel != LevelAVLogQuiet) && (LevelAVLogDebug <= activeLogLevel)) { NSLog(@"Async callback block started.\n"); } @@ -349,45 +489,19 @@ void callbackBlockFunction() { if (callbackData != nil) { if ([callbackData getType] == LogType) { - - // LOG CALLBACK - int activeLogLevel = av_log_get_level(); - int levelValue = [callbackData getLogLevel]; - - if ((activeLogLevel == AV_LOG_QUIET && levelValue != AV_LOG_STDERR) || (levelValue > activeLogLevel)) { - - // LOG NEITHER PRINTED NOR FORWARDED - } else { - if (logDelegate != nil) { - - // FORWARD LOG TO DELEGATE - [logDelegate logCallback:[callbackData getExecutionId]:[callbackData getLogLevel]:[callbackData getLogData]]; - - } else { - switch (levelValue) { - case AV_LOG_QUIET: - // PRINT NO OUTPUT - break; - default: - // WRITE TO NSLOG - NSLog(@"%@: %@", [FFmpegKitConfig logLevelToString:[callbackData getLogLevel]], [callbackData getLogData]); - break; - } - } - } - + process_log([callbackData getSessionId], [callbackData getLogLevel], [callbackData getLogData]); } else { - - // STATISTICS CALLBACK - Statistics *newStatistics = [[Statistics alloc] initWithId:[callbackData getExecutionId] videoFrameNumber:[callbackData getStatisticsFrameNumber] fps:[callbackData getStatisticsFps] quality:[callbackData getStatisticsQuality] size:[callbackData getStatisticsSize] time:[callbackData getStatisticsTime] bitrate:[callbackData getStatisticsBitrate] speed:[callbackData getStatisticsSpeed]]; - [lastReceivedStatistics update:newStatistics]; - - if (logDelegate != nil) { - - // FORWARD STATISTICS TO DELEGATE - [statisticsDelegate statisticsCallback:lastReceivedStatistics]; - } + process_statistics([callbackData getSessionId], + [callbackData getStatisticsFrameNumber], + [callbackData getStatisticsFps], + [callbackData getStatisticsQuality], + [callbackData getStatisticsSize], + [callbackData getStatisticsTime], + [callbackData getStatisticsBitrate], + [callbackData getStatisticsSpeed]); } + + atomic_fetch_sub(&sessionInTransitMessageCountMap[[callbackData getSessionId] % SESSION_MAP_SIZE], 1); } else { callbackWait(100); @@ -395,7 +509,7 @@ void callbackBlockFunction() { } @catch(NSException *exception) { activeLogLevel = av_log_get_level(); - if ((activeLogLevel != AV_LOG_QUIET) && (AV_LOG_WARNING <= activeLogLevel)) { + if ((activeLogLevel != LevelAVLogQuiet) && (LevelAVLogWarning <= activeLogLevel)) { NSLog(@"Async callback block received error: %@n\n", exception); NSLog(@"%@", [exception callStackSymbols]); } @@ -404,84 +518,126 @@ void callbackBlockFunction() { } activeLogLevel = av_log_get_level(); - if ((activeLogLevel != AV_LOG_QUIET) && (AV_LOG_DEBUG <= activeLogLevel)) { + if ((activeLogLevel != LevelAVLogQuiet) && (LevelAVLogDebug <= activeLogLevel)) { NSLog(@"Async callback block stopped.\n"); } } -@interface FFmpegKitConfig() +int executeFFmpeg(long sessionId, NSArray* arguments) { + NSString* const LIB_NAME = @"ffmpeg"; -/** - * Returns build configuration for FFmpeg. - * - * @return build configuration string - */ -+ (NSString*)getBuildConf; + // SETS DEFAULT LOG LEVEL BEFORE STARTING A NEW RUN + av_log_set_level(configuredLogLevel); -@end + char **commandCharPArray = (char **)av_malloc(sizeof(char*) * ([arguments count] + 1)); -@implementation FFmpegKitConfig + /* PRESERVE USAGE FORMAT + * + * ffmpeg + */ + commandCharPArray[0] = (char *)av_malloc(sizeof(char) * ([LIB_NAME length] + 1)); + strcpy(commandCharPArray[0], [LIB_NAME UTF8String]); -+ (void)initialize { - supportedExternalLibraries = [[NSMutableArray alloc] init]; - [supportedExternalLibraries addObject:@"dav1d"]; - [supportedExternalLibraries addObject:@"fontconfig"]; - [supportedExternalLibraries addObject:@"freetype"]; - [supportedExternalLibraries addObject:@"fribidi"]; - [supportedExternalLibraries addObject:@"gmp"]; - [supportedExternalLibraries addObject:@"gnutls"]; - [supportedExternalLibraries addObject:@"kvazaar"]; - [supportedExternalLibraries addObject:@"mp3lame"]; - [supportedExternalLibraries addObject:@"libaom"]; - [supportedExternalLibraries addObject:@"libass"]; - [supportedExternalLibraries addObject:@"iconv"]; - [supportedExternalLibraries addObject:@"libilbc"]; - [supportedExternalLibraries addObject:@"libtheora"]; - [supportedExternalLibraries addObject:@"libvidstab"]; - [supportedExternalLibraries addObject:@"libvorbis"]; - [supportedExternalLibraries addObject:@"libvpx"]; - [supportedExternalLibraries addObject:@"libwebp"]; - [supportedExternalLibraries addObject:@"libxml2"]; - [supportedExternalLibraries addObject:@"opencore-amr"]; - [supportedExternalLibraries addObject:@"openh264"]; - [supportedExternalLibraries addObject:@"opus"]; - [supportedExternalLibraries addObject:@"rubberband"]; - [supportedExternalLibraries addObject:@"sdl2"]; - [supportedExternalLibraries addObject:@"shine"]; - [supportedExternalLibraries addObject:@"snappy"]; - [supportedExternalLibraries addObject:@"soxr"]; - [supportedExternalLibraries addObject:@"speex"]; - [supportedExternalLibraries addObject:@"tesseract"]; - [supportedExternalLibraries addObject:@"twolame"]; - [supportedExternalLibraries addObject:@"x264"]; - [supportedExternalLibraries addObject:@"x265"]; - [supportedExternalLibraries addObject:@"xvid"]; - - for(int i = 0; i + */ + commandCharPArray[0] = (char *)av_malloc(sizeof(char) * ([LIB_NAME length] + 1)); + strcpy(commandCharPArray[0], [LIB_NAME UTF8String]); + + // PREPARE ARRAY ELEMENTS + for (int i=0; i < [arguments count]; i++) { + NSString *argument = [arguments objectAtIndex:i]; + commandCharPArray[i + 1] = (char *) [argument UTF8String]; + } + + // REGISTER THE ID BEFORE STARTING THE SESSION + _sessionId = sessionId; + addSession(sessionId); + + resetMessagesInTransmit(sessionId); + + // RUN + int returnCode = ffprobe_execute(([arguments count] + 1), commandCharPArray); + + // ALWAYS REMOVE THE ID FROM THE MAP + removeSession(sessionId); + + // CLEANUP + av_free(commandCharPArray[0]); + av_free(commandCharPArray); + + return returnCode; +} + +@implementation FFmpegKitConfig + ++ (void)initialize { [ArchDetect class]; [FFmpegKit class]; + [FFprobeKit class]; + pipeIndexGenerator = [[AtomicLong alloc] initWithValue:1]; + + sessionHistorySize = 10; + sessionHistoryMap = [[NSMutableDictionary alloc] init]; + sessionHistoryList = [[NSMutableArray alloc] init]; + sessionHistoryLock = [[NSRecursiveLock alloc] init]; + + for(int i = 0; i)newLogDelegate { - logDelegate = newLogDelegate; -} - -/** - * Sets a StatisticsDelegate. - * - * @param newStatisticsDelegate statistics delegate - */ -+ (void)setStatisticsDelegate:(id)newStatisticsDelegate { - statisticsDelegate = newStatisticsDelegate; -} - -/** - * Returns the last received statistics data. - * - * @return last received statistics data - */ -+ (Statistics*)getLastReceivedStatistics { - return lastReceivedStatistics; -} - -/** - * Resets last received statistics. - */ -+ (void)resetStatistics { - lastReceivedStatistics = [[Statistics alloc] init]; -} - -/** - * Sets and overrides fontconfig configuration directory. - * - * @param path directory which contains fontconfig configuration (fonts.conf) - */ -+ (void)setFontconfigConfigurationPath:(NSString*)path { - if (path != nil) { - setenv("FONTCONFIG_PATH", [path UTF8String], true); - } ++ (int)setFontconfigConfigurationPath:(NSString*)path { + return [FFmpegKitConfig setEnvironmentVariable:@"FONTCONFIG_PATH" value:path]; } -/** - * Registers the fonts inside the given path, so they become available to use in FFmpeg filters. - * - * Note that you need to build FFmpegKit with fontconfig enabled or use a prebuilt package with - * fontconfig inside to use this feature. - * - * @param fontDirectoryPath directory which contains fonts (.ttf and .otf files) - * @param fontNameMapping custom font name mappings, useful to access your fonts with more friendly names - */ + (void)setFontDirectory:(NSString*)fontDirectoryPath with:(NSDictionary*)fontNameMapping { [FFmpegKitConfig setFontDirectoryList:[NSArray arrayWithObject:fontDirectoryPath] with:fontNameMapping]; } -/** - * Registers the fonts inside the given array of font directories, so they become available to use - * in FFmpeg filters. - * - * Note that you need to build FFmpegKit with fontconfig enabled or use a prebuilt package with - * fontconfig inside to use this feature. - * - * @param fontDirectoryArray array of directories which contain fonts (.ttf and .otf files) - * @param fontNameMapping custom font name mappings, useful to access your fonts with more friendly names - */ + (void)setFontDirectoryList:(NSArray*)fontDirectoryArray with:(NSDictionary*)fontNameMapping { NSError *error = nil; BOOL isDirectory = YES; @@ -646,7 +699,7 @@ void callbackBlockFunction() { } if ([[NSFileManager defaultManager] fileExistsAtPath:fontConfigurationFile isDirectory:&isFile]) { - BOOL fontConfigurationDeleted = [[NSFileManager defaultManager] removeItemAtPath:fontConfigurationFile error:NULL]; + BOOL fontConfigurationDeleted = [[NSFileManager defaultManager] removeItemAtPath:fontConfigurationFile error:nil]; NSLog(@"Deleted old temporary font configuration: %s.", fontConfigurationDeleted?"TRUE":"FALSE"); } @@ -700,229 +753,6 @@ void callbackBlockFunction() { } } -/** - * Returns build configuration for FFmpeg. - * - * @return build configuration string - */ -+ (NSString*)getBuildConf { - return [NSString stringWithUTF8String:FFMPEG_CONFIGURATION]; -} - -/** - * Returns package name. - * - * @return guessed package name according to supported external libraries - */ -+ (NSString*)getPackageName { - NSArray *enabledLibraryArray = [FFmpegKitConfig getExternalLibraries]; - Boolean speex = [enabledLibraryArray containsObject:@"speex"]; - Boolean fribidi = [enabledLibraryArray containsObject:@"fribidi"]; - Boolean gnutls = [enabledLibraryArray containsObject:@"gnutls"]; - Boolean xvid = [enabledLibraryArray containsObject:@"xvid"]; - - Boolean min = false; - Boolean minGpl = false; - Boolean https = false; - Boolean httpsGpl = false; - Boolean audio = false; - Boolean video = false; - Boolean full = false; - Boolean fullGpl = false; - - if (speex && fribidi) { - if (xvid) { - fullGpl = true; - } else { - full = true; - } - } else if (speex) { - audio = true; - } else if (fribidi) { - video = true; - } else if (xvid) { - if (gnutls) { - httpsGpl = true; - } else { - minGpl = true; - } - } else { - if (gnutls) { - https = true; - } else { - min = true; - } - } - - if (fullGpl) { - if ([enabledLibraryArray containsObject:@"dav1d"] && - [enabledLibraryArray containsObject:@"fontconfig"] && - [enabledLibraryArray containsObject:@"freetype"] && - [enabledLibraryArray containsObject:@"fribidi"] && - [enabledLibraryArray containsObject:@"gmp"] && - [enabledLibraryArray containsObject:@"gnutls"] && - [enabledLibraryArray containsObject:@"kvazaar"] && - [enabledLibraryArray containsObject:@"mp3lame"] && - [enabledLibraryArray containsObject:@"libaom"] && - [enabledLibraryArray containsObject:@"libass"] && - [enabledLibraryArray containsObject:@"iconv"] && - [enabledLibraryArray containsObject:@"libilbc"] && - [enabledLibraryArray containsObject:@"libtheora"] && - [enabledLibraryArray containsObject:@"libvidstab"] && - [enabledLibraryArray containsObject:@"libvorbis"] && - [enabledLibraryArray containsObject:@"libvpx"] && - [enabledLibraryArray containsObject:@"libwebp"] && - [enabledLibraryArray containsObject:@"libxml2"] && - [enabledLibraryArray containsObject:@"opencore-amr"] && - [enabledLibraryArray containsObject:@"opus"] && - [enabledLibraryArray containsObject:@"shine"] && - [enabledLibraryArray containsObject:@"snappy"] && - [enabledLibraryArray containsObject:@"soxr"] && - [enabledLibraryArray containsObject:@"speex"] && - [enabledLibraryArray containsObject:@"twolame"] && - [enabledLibraryArray containsObject:@"x264"] && - [enabledLibraryArray containsObject:@"x265"] && - [enabledLibraryArray containsObject:@"xvid"]) { - return @"full-gpl"; - } else { - return @"custom"; - } - } - - if (full) { - if ([enabledLibraryArray containsObject:@"dav1d"] && - [enabledLibraryArray containsObject:@"fontconfig"] && - [enabledLibraryArray containsObject:@"freetype"] && - [enabledLibraryArray containsObject:@"fribidi"] && - [enabledLibraryArray containsObject:@"gmp"] && - [enabledLibraryArray containsObject:@"gnutls"] && - [enabledLibraryArray containsObject:@"kvazaar"] && - [enabledLibraryArray containsObject:@"mp3lame"] && - [enabledLibraryArray containsObject:@"libaom"] && - [enabledLibraryArray containsObject:@"libass"] && - [enabledLibraryArray containsObject:@"iconv"] && - [enabledLibraryArray containsObject:@"libilbc"] && - [enabledLibraryArray containsObject:@"libtheora"] && - [enabledLibraryArray containsObject:@"libvorbis"] && - [enabledLibraryArray containsObject:@"libvpx"] && - [enabledLibraryArray containsObject:@"libwebp"] && - [enabledLibraryArray containsObject:@"libxml2"] && - [enabledLibraryArray containsObject:@"opencore-amr"] && - [enabledLibraryArray containsObject:@"opus"] && - [enabledLibraryArray containsObject:@"shine"] && - [enabledLibraryArray containsObject:@"snappy"] && - [enabledLibraryArray containsObject:@"soxr"] && - [enabledLibraryArray containsObject:@"speex"] && - [enabledLibraryArray containsObject:@"twolame"]) { - return @"full"; - } else { - return @"custom"; - } - } - - if (video) { - if ([enabledLibraryArray containsObject:@"dav1d"] && - [enabledLibraryArray containsObject:@"fontconfig"] && - [enabledLibraryArray containsObject:@"freetype"] && - [enabledLibraryArray containsObject:@"fribidi"] && - [enabledLibraryArray containsObject:@"kvazaar"] && - [enabledLibraryArray containsObject:@"libaom"] && - [enabledLibraryArray containsObject:@"libass"] && - [enabledLibraryArray containsObject:@"iconv"] && - [enabledLibraryArray containsObject:@"libtheora"] && - [enabledLibraryArray containsObject:@"libvpx"] && - [enabledLibraryArray containsObject:@"libwebp"] && - [enabledLibraryArray containsObject:@"snappy"]) { - return @"video"; - } else { - return @"custom"; - } - } - - if (audio) { - if ([enabledLibraryArray containsObject:@"mp3lame"] && - [enabledLibraryArray containsObject:@"libilbc"] && - [enabledLibraryArray containsObject:@"libvorbis"] && - [enabledLibraryArray containsObject:@"opencore-amr"] && - [enabledLibraryArray containsObject:@"opus"] && - [enabledLibraryArray containsObject:@"shine"] && - [enabledLibraryArray containsObject:@"soxr"] && - [enabledLibraryArray containsObject:@"speex"] && - [enabledLibraryArray containsObject:@"twolame"]) { - return @"audio"; - } else { - return @"custom"; - } - } - - if (httpsGpl) { - if ([enabledLibraryArray containsObject:@"gmp"] && - [enabledLibraryArray containsObject:@"gnutls"] && - [enabledLibraryArray containsObject:@"libvidstab"] && - [enabledLibraryArray containsObject:@"x264"] && - [enabledLibraryArray containsObject:@"x265"] && - [enabledLibraryArray containsObject:@"xvid"]) { - return @"https-gpl"; - } else { - return @"custom"; - } - } - - if (https) { - if ([enabledLibraryArray containsObject:@"gmp"] && - [enabledLibraryArray containsObject:@"gnutls"]) { - return @"https"; - } else { - return @"custom"; - } - } - - if (minGpl) { - if ([enabledLibraryArray containsObject:@"libvidstab"] && - [enabledLibraryArray containsObject:@"x264"] && - [enabledLibraryArray containsObject:@"x265"] && - [enabledLibraryArray containsObject:@"xvid"]) { - return @"min-gpl"; - } else { - return @"custom"; - } - } - - return @"min"; -} - -/** - * Returns supported external libraries. - * - * @return array of supported external libraries - */ -+ (NSArray*)getExternalLibraries { - NSString *buildConfiguration = [FFmpegKitConfig getBuildConf]; - NSMutableArray *enabledLibraryArray = [[NSMutableArray alloc] init]; - - for (int i=0; i < [supportedExternalLibraries count]; i++) { - NSString *supportedExternalLibrary = [supportedExternalLibraries objectAtIndex:i]; - - NSString *libraryName1 = [NSString stringWithFormat:@"enable-%@", supportedExternalLibrary]; - NSString *libraryName2 = [NSString stringWithFormat:@"enable-lib%@", supportedExternalLibrary]; - - if ([buildConfiguration rangeOfString:libraryName1].location != NSNotFound || [buildConfiguration rangeOfString:libraryName2].location != NSNotFound) { - [enabledLibraryArray addObject:supportedExternalLibrary]; - } - } - - [enabledLibraryArray sortUsingSelector:@selector(compare:)]; - - return enabledLibraryArray; -} - -/** - * Creates a new named pipe to use in FFmpeg operations. - * - * Please note that creator is responsible of closing created pipes. - * - * @return the full path of named pipe - */ + (NSString*)registerNewFFmpegPipe { NSError *error = nil; BOOL isDirectory; @@ -938,7 +768,7 @@ void callbackBlockFunction() { } } - NSString *newFFmpegPipePath = [NSString stringWithFormat:@"%@/%@%d", pipesDir, FFMPEG_KIT_PIPE_PREFIX, (++lastCreatedPipeIndex)]; + NSString *newFFmpegPipePath = [NSString stringWithFormat:@"%@/%@%ld", pipesDir, FFmpegKitNamedPipePrefix, [pipeIndexGenerator getAndIncrement]]; // FIRST CLOSE OLD PIPES WITH THE SAME NAME [FFmpegKitConfig closeFFmpegPipe:newFFmpegPipePath]; @@ -952,93 +782,341 @@ void callbackBlockFunction() { } } -/** - * Closes a previously created FFmpeg pipe. - * - * @param ffmpegPipePath full path of ffmpeg pipe - */ + (void)closeFFmpegPipe:(NSString*)ffmpegPipePath { NSFileManager *fileManager = [NSFileManager defaultManager]; if ([fileManager fileExistsAtPath:ffmpegPipePath]){ - [fileManager removeItemAtPath:ffmpegPipePath error:NULL]; + [fileManager removeItemAtPath:ffmpegPipePath error:nil]; } } -/** - * Returns FFmpeg version bundled within the library. - * - * @return FFmpeg version string - */ + (NSString*)getFFmpegVersion { return [NSString stringWithUTF8String:FFMPEG_VERSION]; } -/** - * Returns FFmpegKit library version. - * - * @return FFmpegKit version string - */ + (NSString*)getVersion { - if ([ArchDetect isLTSBuild] == 1) { - return [NSString stringWithFormat:@"%@-lts", FFMPEG_KIT_VERSION]; + if ([FFmpegKitConfig isLTSBuild] == 1) { + return [NSString stringWithFormat:@"%@-lts", FFmpegKitVersion]; } else { - return FFMPEG_KIT_VERSION; + return FFmpegKitVersion; } } -/** - * Returns FFmpegKit library build date. - * - * @return FFmpegKit library build date - */ ++ (int)isLTSBuild { + #if defined(FFMPEG_KIT_LTS) + return 1; + #else + return 0; + #endif +} + + (NSString*)getBuildDate { char buildDate[10]; sprintf(buildDate, "%d", FFMPEG_KIT_BUILD_DATE); return [NSString stringWithUTF8String:buildDate]; } -/** - * Returns return code of last executed command. - * - * @return return code of last executed command - */ -+ (int)getLastReturnCode { - return lastReturnCode; -} - -/** - * Returns log output of last executed single FFmpeg/FFprobe command. - * - * This method does not support executing multiple concurrent commands. If you execute - * multiple commands at the same time, this method will return output from all executions. - * - * Please note that disabling redirection using FFmpegKitConfig.disableRedirection() method - * also disables this functionality. - * - * @return output of last executed command - */ -+ (NSString*)getLastCommandOutput { - return lastCommandOutput; ++ (int)setEnvironmentVariable:(NSString*)variableName value:(NSString*)variableValue { + return setenv([variableName UTF8String], [variableValue UTF8String], true); } -/** - * Registers a new ignored signal. Ignored signals are not handled by the library. - * - * @param signum signal number to ignore - */ -+ (void)ignoreSignal:(int)signum { - if (signum == SIGQUIT) { ++ (void)ignoreSignal:(Signal)signal { + if (signal == SignalQuit) { handleSIGQUIT = 0; - } else if (signum == SIGINT) { + } else if (signal == SignalInt) { handleSIGINT = 0; - } else if (signum == SIGTERM) { + } else if (signal == SignalTerm) { handleSIGTERM = 0; - } else if (signum == SIGXCPU) { + } else if (signal == SignalXcpu) { handleSIGXCPU = 0; - } else if (signum == SIGPIPE) { + } else if (signal == SignalPipe) { handleSIGPIPE = 0; } } ++ (void)ffmpegExecute:(FFmpegSession*)ffmpegSession { + [FFmpegKitConfig addSession:ffmpegSession]; + [ffmpegSession startRunning]; + + @try { + int returnCode = executeFFmpeg([ffmpegSession getSessionId], [ffmpegSession getArguments]); + [ffmpegSession complete:[[ReturnCode alloc] init:returnCode]]; + } @catch (NSException *exception) { + [ffmpegSession fail:exception]; + NSLog(@"FFmpeg execute failed: %@.%@", [FFmpegKit argumentsToString:[ffmpegSession getArguments]], [NSString stringWithFormat:@"%@", [exception callStackSymbols]]); + } +} + ++ (void)ffprobeExecute:(FFprobeSession*)ffprobeSession { + [FFmpegKitConfig addSession:ffprobeSession]; + [ffprobeSession startRunning]; + + @try { + int returnCode = executeFFprobe([ffprobeSession getSessionId], [ffprobeSession getArguments]); + [ffprobeSession complete:[[ReturnCode alloc] init:returnCode]]; + } @catch (NSException *exception) { + [ffprobeSession fail:exception]; + NSLog(@"FFprobe execute failed: %@.%@", [FFmpegKit argumentsToString:[ffprobeSession getArguments]], [NSString stringWithFormat:@"%@", [exception callStackSymbols]]); + } +} + ++ (void)getMediaInformationExecute:(MediaInformationSession*)mediaInformationSession withTimeout:(int)waitTimeout { + [FFmpegKitConfig addSession:mediaInformationSession]; + [mediaInformationSession startRunning]; + + @try { + int returnCodeValue = executeFFprobe([mediaInformationSession getSessionId], [mediaInformationSession getArguments]); + ReturnCode* returnCode = [[ReturnCode alloc] init:returnCodeValue]; + [mediaInformationSession complete:returnCode]; + if ([returnCode isSuccess]) { + MediaInformation* mediaInformation = [MediaInformationJsonParser from:[mediaInformationSession getAllLogsAsStringWithTimeout:waitTimeout]]; + [mediaInformationSession setMediaInformation:mediaInformation]; + } + } @catch (NSException *exception) { + [mediaInformationSession fail:exception]; + NSLog(@"Get media information execute failed: %@.%@", [FFmpegKit argumentsToString:[mediaInformationSession getArguments]], [NSString stringWithFormat:@"%@", [exception callStackSymbols]]); + } +} + ++ (void)asyncFFmpegExecute:(FFmpegSession*)ffmpegSession { + [FFmpegKitConfig asyncFFmpegExecute:ffmpegSession onDispatchQueue:asyncDispatchQueue]; +} + ++ (void)asyncFFmpegExecute:(FFmpegSession*)ffmpegSession onDispatchQueue:(dispatch_queue_t)queue { + dispatch_async(queue, ^{ + [FFmpegKitConfig ffmpegExecute:ffmpegSession]; + id globalExecuteDelegate = [FFmpegKitConfig getExecuteDelegate]; + if (globalExecuteDelegate != nil) { + [globalExecuteDelegate executeCallback:ffmpegSession]; + } + + id executeDelegate = [ffmpegSession getExecuteDelegate]; + if (executeDelegate != nil) { + [executeDelegate executeCallback:ffmpegSession]; + } + }); +} + ++ (void)asyncFFprobeExecute:(FFprobeSession*)ffprobeSession { + [FFmpegKitConfig asyncFFprobeExecute:ffprobeSession onDispatchQueue:asyncDispatchQueue]; +} + ++ (void)asyncFFprobeExecute:(FFprobeSession*)ffprobeSession onDispatchQueue:(dispatch_queue_t)queue { + dispatch_async(queue, ^{ + [FFmpegKitConfig ffprobeExecute:ffprobeSession]; + id globalExecuteDelegate = [FFmpegKitConfig getExecuteDelegate]; + if (globalExecuteDelegate != nil) { + [globalExecuteDelegate executeCallback:ffprobeSession]; + } + + id executeDelegate = [ffprobeSession getExecuteDelegate]; + if (executeDelegate != nil) { + [executeDelegate executeCallback:ffprobeSession]; + } + }); +} + ++ (void)asyncGetMediaInformationExecute:(MediaInformationSession*)mediaInformationSession withTimeout:(int)waitTimeout { + [FFmpegKitConfig asyncGetMediaInformationExecute:mediaInformationSession onDispatchQueue:asyncDispatchQueue withTimeout:waitTimeout]; +} + ++ (void)asyncGetMediaInformationExecute:(MediaInformationSession*)mediaInformationSession onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout { + dispatch_async(queue, ^{ + [FFmpegKitConfig getMediaInformationExecute:mediaInformationSession withTimeout:waitTimeout]; + id globalExecuteDelegate = [FFmpegKitConfig getExecuteDelegate]; + if (globalExecuteDelegate != nil) { + [globalExecuteDelegate executeCallback:mediaInformationSession]; + } + + id executeDelegate = [mediaInformationSession getExecuteDelegate]; + if (executeDelegate != nil) { + [executeDelegate executeCallback:mediaInformationSession]; + } + }); +} + ++ (void)enableLogDelegate:(id)delegate { + logDelegate = delegate; +} + ++ (void)enableStatisticsDelegate:(id)delegate { + statisticsDelegate = delegate; +} + ++ (void)enableExecuteDelegate:(id)delegate { + executeDelegate = delegate; +} + ++ (id)getExecuteDelegate { + return executeDelegate; +} + ++ (int)getLogLevel { + return configuredLogLevel; +} + ++ (void)setLogLevel:(int)level { + configuredLogLevel = level; +} + ++ (NSString*)logLevelToString:(int)level { + switch (level) { + case LevelAVLogStdErr: return @"STDERR"; + case LevelAVLogTrace: return @"TRACE"; + case LevelAVLogDebug: return @"DEBUG"; + case LevelAVLogVerbose: return @"VERBOSE"; + case LevelAVLogInfo: return @"INFO"; + case LevelAVLogWarning: return @"WARNING"; + case LevelAVLogError: return @"ERROR"; + case LevelAVLogFatal: return @"FATAL"; + case LevelAVLogPanic: return @"PANIC"; + case LevelAVLogQuiet: return @"QUIET"; + default: return @""; + } +} + ++ (int)getSessionHistorySize { + return sessionHistorySize; +} + ++ (void)setSessionHistorySize:(int)pSessionHistorySize { + if (pSessionHistorySize >= SESSION_MAP_SIZE) { + + /* + * THERE IS A HARD LIMIT ON THE NATIVE SIDE. HISTORY SIZE MUST BE SMALLER THAN SESSION_MAP_SIZE + */ + @throw([NSException exceptionWithName:NSInvalidArgumentException reason:@"Session history size must not exceed the hard limit!" userInfo:nil]); + } else if (pSessionHistorySize > 0) { + sessionHistorySize = pSessionHistorySize; + } +} + ++ (void)addSession:(id)session { + [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]; + } + } + + [sessionHistoryLock unlock]; +} + ++ (id)getSession:(long)sessionId { + [sessionHistoryLock lock]; + + id session = [sessionHistoryMap objectForKey:[NSNumber numberWithLong:sessionId]]; + + [sessionHistoryLock unlock]; + + return session; +} + ++ (id)getLastSession { + [sessionHistoryLock lock]; + + id lastSession = [sessionHistoryList lastObject]; + + [sessionHistoryLock unlock]; + + return lastSession; +} + ++ (id)getLastCompletedSession { + id lastCompletedSession = nil; + + [sessionHistoryLock lock]; + + for(int i = [sessionHistoryList count] - 1; i >= 0; i--) { + id session = [sessionHistoryList objectAtIndex:i]; + if ([session getState] == SessionStateCompleted) { + lastCompletedSession = session; + break; + } + } + + [sessionHistoryLock unlock]; + + return lastCompletedSession; +} + ++ (NSArray*)getSessions { + [sessionHistoryLock lock]; + + NSArray* sessionsCopy = [sessionHistoryList copy]; + + [sessionHistoryLock unlock]; + + return sessionsCopy; +} + ++ (NSArray*)getFFmpegSessions { + NSMutableArray* ffmpegSessions = [[NSMutableArray alloc] init]; + + [sessionHistoryLock lock]; + + for(int i = 0; i < [sessionHistoryList count]; i++) { + id session = [sessionHistoryList objectAtIndex:i]; + if ([session isFFmpeg]) { + [ffmpegSessions addObject:session]; + } + } + + [sessionHistoryLock unlock]; + + return ffmpegSessions; +} + ++ (NSArray*)getFFprobeSessions { + NSMutableArray* ffprobeSessions = [[NSMutableArray alloc] init]; + + [sessionHistoryLock lock]; + + for(int i = 0; i < [sessionHistoryList count]; i++) { + id session = [sessionHistoryList objectAtIndex:i]; + if ([session isFFprobe]) { + [ffprobeSessions addObject:session]; + } + } + + [sessionHistoryLock unlock]; + + return ffprobeSessions; +} + ++ (NSArray*)getSessionsByState:(SessionState)state { + NSMutableArray* sessions = [[NSMutableArray alloc] init]; + + [sessionHistoryLock lock]; + + for(int i = 0; i < [sessionHistoryList count]; i++) { + id session = [sessionHistoryList objectAtIndex:i]; + if ([session getState] == state) { + [sessions addObject:session]; + } + } + + [sessionHistoryLock unlock]; + + return sessions; +} + ++ (LogRedirectionStrategy)getLogRedirectionStrategy { + return globalLogRedirectionStrategy; +} + ++ (void)setLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy { + globalLogRedirectionStrategy = logRedirectionStrategy; +} + ++ (int)messagesInTransmit:(long)sessionId { + return atomic_load(&sessionInTransitMessageCountMap[sessionId % SESSION_MAP_SIZE]); +} + @end diff --git a/apple/src/FFmpegSession.h b/apple/src/FFmpegSession.h new file mode 100644 index 0000000..e90ee33 --- /dev/null +++ b/apple/src/FFmpegSession.h @@ -0,0 +1,119 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#ifndef FFMPEG_KIT_FFMPEG_SESSION_H +#define FFMPEG_KIT_FFMPEG_SESSION_H + +#import +#import "AbstractSession.h" +#import "StatisticsDelegate.h" + +/** + *

An FFmpeg session. + */ +@interface FFmpegSession : AbstractSession + +/** + * Builds a new FFmpeg session. + * + * @param arguments command arguments + */ +- (instancetype)init:(NSArray*)arguments; + +/** + * Builds a new FFmpeg session. + * + * @param arguments command arguments + * @param executeDelegate session specific execute delegate + */ +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate; + +/** + * Builds a new FFmpeg session. + * + * @param arguments command arguments + * @param executeDelegate session specific execute delegate + * @param logDelegate session specific log delegate + * @param statisticsDelegate session specific statistics delegate + */ +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withStatisticsDelegate:(id)statisticsDelegate; + +/** + * Builds a new FFmpeg session. + * + * @param arguments command arguments + * @param executeDelegate session specific execute delegate + * @param logDelegate session specific log delegate + * @param statisticsDelegate session specific statistics delegate + * @param logRedirectionStrategy session specific log redirection strategy + */ +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withStatisticsDelegate:(id)statisticsDelegate withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy; + +/** + * Returns the session specific statistics delegate. + * + * @return session specific statistics delegate + */ +- (id)getStatisticsDelegate; + +/** + * Returns all statistics entries generated for this session. If there are asynchronous + * messages that are not delivered yet, this method waits for them until the given timeout. + * + * @param waitTimeout wait timeout for asynchronous messages in milliseconds + * @return list of statistics entries generated for this session + */ +- (NSArray*)getAllStatisticsWithTimeout:(int)waitTimeout; + +/** + * Returns all statistics entries generated for this session. If there are asynchronous + * messages that are not delivered yet, this method waits for them until + * AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit expires. + * + * @return list of statistics entries generated for this session + */ +- (NSArray*)getAllStatistics; + +/** + * Returns all statistics entries delivered for this session. Note that if there are + * asynchronous messages that are not delivered yet, this method will not wait for + * them and will return immediately. + * + * @return list of statistics entries received for this session + */ +- (NSArray*)getStatistics; + +/** + * Returns the last received statistics entry. + * + * @return the last received statistics entry or nil if there are not any statistics entries + * received + */ +- (Statistics*)getLastReceivedStatistics; + +/** + * Adds a new statistics entry for this session. + * + * @param statistics statistics entry + */ +- (void)addStatistics:(Statistics*)statistics; + +@end + +#endif // FFMPEG_KIT_FFMPEG_SESSION_H diff --git a/apple/src/FFmpegSession.m b/apple/src/FFmpegSession.m new file mode 100644 index 0000000..e8f6926 --- /dev/null +++ b/apple/src/FFmpegSession.m @@ -0,0 +1,137 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#import "ExecuteDelegate.h" +#import "FFmpegSession.h" +#import "FFmpegKitConfig.h" +#import "LogDelegate.h" +#import "StatisticsDelegate.h" + +@implementation FFmpegSession { + id _statisticsDelegate; + NSMutableArray* _statistics; + NSRecursiveLock* _statisticsLock; +} + +- (instancetype)init:(NSArray*)arguments { + + self = [super init:arguments withExecuteDelegate:nil withLogDelegate:nil withLogRedirectionStrategy:[FFmpegKitConfig getLogRedirectionStrategy]]; + + if (self) { + _statisticsDelegate = nil; + _statistics = [[NSMutableArray alloc] init]; + _statisticsLock = [[NSRecursiveLock alloc] init]; + } + + return self; +} + +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate { + + self = [super init:arguments withExecuteDelegate:executeDelegate withLogDelegate:nil withLogRedirectionStrategy:[FFmpegKitConfig getLogRedirectionStrategy]]; + + if (self) { + _statisticsDelegate = nil; + _statistics = [[NSMutableArray alloc] init]; + _statisticsLock = [[NSRecursiveLock alloc] init]; + } + + return self; +} + +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withStatisticsDelegate:(id)statisticsDelegate { + + self = [super init:arguments withExecuteDelegate:executeDelegate withLogDelegate:logDelegate withLogRedirectionStrategy:[FFmpegKitConfig getLogRedirectionStrategy]]; + + if (self) { + _statisticsDelegate = statisticsDelegate; + _statistics = [[NSMutableArray alloc] init]; + _statisticsLock = [[NSRecursiveLock alloc] init]; + } + + return self; +} + +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withStatisticsDelegate:(id)statisticsDelegate withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy { + + self = [super init:arguments withExecuteDelegate:executeDelegate withLogDelegate:logDelegate withLogRedirectionStrategy:logRedirectionStrategy]; + + if (self) { + _statisticsDelegate = statisticsDelegate; + _statistics = [[NSMutableArray alloc] init]; + _statisticsLock = [[NSRecursiveLock alloc] init]; + } + + return self; +} + +- (id)getStatisticsDelegate { + return _statisticsDelegate; +} + +- (NSArray*)getAllStatisticsWithTimeout:(int)waitTimeout { + [self waitForAsynchronousMessagesInTransmit:waitTimeout]; + + if ([self thereAreAsynchronousMessagesInTransmit]) { + NSLog(@"getAllStatisticsWithTimeout was called to return all statistics but there are still statistics being transmitted for session id %ld.", [self getSessionId]); + } + + return [self getStatistics]; +} + +- (NSArray*)getAllStatistics { + return [self getAllStatisticsWithTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit]; +} + +- (NSArray*)getStatistics { + [_statisticsLock lock]; + NSArray* statisticsCopy = [_statistics copy]; + [_statisticsLock unlock]; + + return statisticsCopy; +} + +- (Statistics*)getLastReceivedStatistics { + Statistics* lastStatistics = nil; + + [_statisticsLock lock]; + if ([_statistics count] > 0) { + lastStatistics = [_statistics objectAtIndex:0]; + } + [_statisticsLock unlock]; + + return lastStatistics; +} + +- (void)addStatistics:(Statistics*)statistics { + [_statisticsLock lock]; + [_statistics addObject:statistics]; + [_statisticsLock unlock]; +} + +- (BOOL)isFFmpeg { + return true; +} + +- (BOOL)isFFprobe { + return false; +} + +@end + diff --git a/apple/src/FFprobeKit.h b/apple/src/FFprobeKit.h index b6215c4..bf9a2df 100644 --- a/apple/src/FFprobeKit.h +++ b/apple/src/FFprobeKit.h @@ -17,71 +17,225 @@ * along with FFmpegKit. If not, see . */ -#include -#include -#include +#ifndef FFPROBE_KIT_H +#define FFPROBE_KIT_H -#include "MediaInformationParser.h" +#import +#import +#import +#import "FFprobeSession.h" +#import "MediaInformationJsonParser.h" /** - * Main class for FFprobe operations. + *

Main class to run FFprobe commands. Supports executing commands both + * synchronously and asynchronously. + *

+ * FFprobeSession *session = [FFprobeKit execute:@"-hide_banner -v error -show_entries format=size -of default=noprint_wrappers=1 file1.mp4"];
+ *
+ * FFprobeSession *asyncSession = [FFprobeKit executeAsync:@"-hide_banner -v error -show_entries format=size -of default=noprint_wrappers=1 file1.mp4" withExecuteDelegate:executeDelegate];
+ * 
+ *

Provides overloaded execute methods to define session specific delegates. + *

+ * FFprobeSession *session = [FFprobeKit executeAsync:@"-hide_banner -v error -show_entries format=size -of default=noprint_wrappers=1 file1.mp4" withExecuteDelegate:executeDelegate withLogDelegate:logDelegate];
+ * 
+ *

It can extract media information for a file or a url, using getMediaInformation method. + *

+ *      MediaInformationSession *session = [FFprobeKit getMediaInformation:@"file1.mp4"];
+ * 
*/ @interface FFprobeKit : NSObject /** - * Synchronously executes FFprobe with arguments provided. + *

Synchronously executes FFprobe with arguments provided. * * @param arguments FFprobe command options/arguments as string array - * @return zero on successful execution, 255 on user cancel and non-zero on error + * @return FFprobe session created for this execution + */ ++ (FFprobeSession*)executeWithArguments:(NSArray*)arguments; + +/** + *

Asynchronously executes FFprobe with arguments provided. + * + * @param arguments FFprobe command options/arguments as string array + * @param executeDelegate delegate that will be called when the execution is completed + * @return FFprobe session created for this execution + */ ++ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate; + +/** + *

Asynchronously executes FFprobe with arguments provided. + * + * @param arguments FFprobe command options/arguments as string array + * @param executeDelegate delegate that will be notified when execution is completed + * @param logDelegate delegate that will receive logs + * @return FFprobe session created for this execution + */ ++ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate; + +/** + *

Asynchronously executes FFprobe with arguments provided. + * + * @param arguments FFprobe command options/arguments as string array + * @param executeDelegate delegate that will be called when the execution is completed + * @param queue dispatch queue that will be used to run this asynchronous operation + * @return FFprobe session created for this execution + */ ++ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate onDispatchQueue:(dispatch_queue_t)queue; + +/** + *

Asynchronously executes FFprobe with arguments provided. + * + * @param arguments FFprobe command options/arguments as string array + * @param executeDelegate delegate that will be notified when execution is completed + * @param logDelegate delegate that will receive logs + * @param queue dispatch queue that will be used to run this asynchronous operation + * @return FFprobe session created for this execution */ -+ (int)executeWithArguments:(NSArray*)arguments; ++ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate onDispatchQueue:(dispatch_queue_t)queue; /** - * Synchronously executes FFprobe command provided. Space character is used to split command - * into arguments. + *

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. * * @param command FFprobe command - * @return zero on successful execution, 255 on user cancel and non-zero on error + * @return FFprobe session created for this execution */ -+ (int)execute:(NSString*)command; ++ (FFprobeSession*)execute:(NSString*)command; /** - * Returns media information for the given file. + *

Asynchronously 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. * - * This method does not support executing multiple concurrent operations. If you execute - * multiple operations (execute or getMediaInformation) at the same time, the response of this - * method is not predictable. + * @param command FFprobe command + * @param executeDelegate delegate that will be called when the execution is completed + * @return FFprobe session created for this execution + */ ++ (FFprobeSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate; + +/** + *

Asynchronously 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. * - * @param path or uri of media file - * @return media information + * @param command FFprobe command + * @param executeDelegate delegate that will be notified when execution is completed + * @param logDelegate delegate that will receive logs + * @return FFprobe session created for this execution */ -+ (MediaInformation*)getMediaInformation:(NSString*)path; ++ (FFprobeSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate; /** - * Returns media information for the given command. + *

Asynchronously 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. * - * This method does not support executing multiple concurrent operations. If you execute - * multiple operations (execute or getMediaInformation) at the same time, the response of this - * method is not predictable. + * @param command FFprobe command + * @param executeDelegate delegate that will be called when the execution is completed + * @param queue dispatch queue that will be used to run this asynchronous operation + * @return FFprobe session created for this execution + */ ++ (FFprobeSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate onDispatchQueue:(dispatch_queue_t)queue; + +/** + *

Asynchronously 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. * - * @param command ffprobe command - * @return media information + * @param command FFprobe command + * @param executeDelegate delegate that will be called when the execution is completed + * @param logDelegate delegate that will receive logs + * @param queue dispatch queue that will be used to run this asynchronous operation + * @return FFprobe session created for this execution */ -+ (MediaInformation*)getMediaInformationFromCommand:(NSString*)command; ++ (FFprobeSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate onDispatchQueue:(dispatch_queue_t)queue; /** - * Returns media information for given file. + *

Extracts media information for the file specified with path. * - * This method does not support executing multiple concurrent operations. If you execute - * multiple operations (execute or getMediaInformation) at the same time, the response of this - * method is not predictable. + * @param path path or uri of a media file + * @return media information session created for this execution + */ ++ (MediaInformationSession*)getMediaInformation:(NSString*)path; + +/** + *

Extracts media information for the file specified with path. * - * @param path path or uri of media file - * @param timeout complete timeout - * @deprecated this method is deprecated since v4.3.1. You can still use this method but - * timeout parameter is not effective anymore. - * @return media information + * @param path path or uri of a media file + * @param waitTimeout max time to wait until media information is transmitted + * @return media information session created for this execution */ -+ (MediaInformation*)getMediaInformation:(NSString*)path timeout:(long)timeout __attribute__((deprecated)); ++ (MediaInformationSession*)getMediaInformation:(NSString*)path withTimeout:(int)waitTimeout; + +/** + *

Extracts media information for the file specified with path asynchronously. + * + * @param path path or uri of a media file + * @param executeDelegate delegate that will be called when the execution is completed + * @return media information session created for this execution + */ ++ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withExecuteDelegate:(id)executeDelegate; + +/** + *

Extracts media information for the file specified with path asynchronously. + * + * @param path path or uri of a media file + * @param executeDelegate delegate that will be notified when execution is completed + * @param logDelegate delegate that will receive logs + * @param waitTimeout max time to wait until media information is transmitted + * @return media information session created for this execution + */ ++ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withTimeout:(int)waitTimeout; + +/** + *

Extracts media information for the file specified with path asynchronously. + * + * @param path path or uri of a media file + * @param executeDelegate delegate that will be called when the execution is completed + * @param queue dispatch queue that will be used to run this asynchronous operation + * @return media information session created for this execution + */ ++ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withExecuteDelegate:(id)executeDelegate onDispatchQueue:(dispatch_queue_t)queue; + +/** + *

Extracts media information for the file specified with path asynchronously. + * + * @param path path or uri of a media file + * @param executeDelegate delegate that will be notified when execution is completed + * @param logDelegate delegate that will receive logs + * @param queue dispatch queue that will be used to run this asynchronous operation + * @param waitTimeout max time to wait until media information is transmitted + * @return media information session created for this execution + */ ++ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout; + +/** + *

Extracts media information using the command provided asynchronously. + * + * @param command FFprobe command that prints media information for a file in JSON format + * @return media information session created for this execution + */ ++ (MediaInformationSession*)getMediaInformationFromCommand:(NSString*)command; + +/** + *

Extracts media information using the command provided asynchronously. + * + * @param command FFprobe command that prints media information for a file in JSON format + * @param executeDelegate delegate that will be notified when execution is completed + * @param logDelegate delegate that will receive logs + * @param waitTimeout max time to wait until media information is transmitted + * @return media information session created for this execution + */ ++ (MediaInformationSession*)getMediaInformationFromCommandAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout; + +/** + *

Lists all FFprobe sessions in the session history. + * + * @return all FFprobe sessions in the session history + */ ++ (NSArray*)listSessions; + +@end -@end \ No newline at end of file +#endif // FFPROBE_KIT_H diff --git a/apple/src/FFprobeKit.m b/apple/src/FFprobeKit.m index 9eda150..20fb136 100644 --- a/apple/src/FFprobeKit.m +++ b/apple/src/FFprobeKit.m @@ -17,131 +17,133 @@ * along with FFmpegKit. If not, see . */ -#include "libavutil/ffversion.h" -#include "fftools_ffmpeg.h" - -#include "FFmpegKit.h" -#include "FFmpegKitConfig.h" -#include "FFprobeKit.h" - -/** Forward declaration for function defined in fftools_ffprobe.c */ -int ffprobe_execute(int argc, char **argv); +#import "fftools_ffmpeg.h" +#import "FFmpegKit.h" +#import "FFmpegKitConfig.h" +#import "FFprobeKit.h" @implementation FFprobeKit -extern int lastReturnCode; -extern NSMutableString *lastCommandOutput; -extern int configuredLogLevel; - + (void)initialize { [FFmpegKitConfig class]; } -/** - * Synchronously executes FFprobe with arguments provided. - * - * @param arguments FFprobe command options/arguments as string array - * @return zero on successful execution, 255 on user cancel and non-zero on error - */ -+ (int)executeWithArguments:(NSArray*)arguments { - lastCommandOutput = [[NSMutableString alloc] init]; ++ (FFprobeSession*)executeWithArguments:(NSArray*)arguments { + FFprobeSession* session = [[FFprobeSession alloc] init:arguments]; + [FFmpegKitConfig ffprobeExecute:session]; + return session; +} - // SETS DEFAULT LOG LEVEL BEFORE STARTING A NEW EXECUTION - av_log_set_level(configuredLogLevel); ++ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate { + FFprobeSession* session = [[FFprobeSession alloc] init:arguments withExecuteDelegate:executeDelegate]; + [FFmpegKitConfig asyncFFprobeExecute:session]; + return session; +} - char **commandCharPArray = (char **)av_malloc(sizeof(char*) * ([arguments count] + 1)); ++ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate { + FFprobeSession* session = [[FFprobeSession alloc] init:arguments withExecuteDelegate:executeDelegate withLogDelegate:logDelegate]; + [FFmpegKitConfig asyncFFprobeExecute:session]; + return session; +} - /* PRESERVING CALLING FORMAT - * - * ffprobe - */ - commandCharPArray[0] = (char *)av_malloc(sizeof(char) * ([LIB_NAME length] + 1)); - strcpy(commandCharPArray[0], [LIB_NAME UTF8String]); ++ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate onDispatchQueue:(dispatch_queue_t)queue { + FFprobeSession* session = [[FFprobeSession alloc] init:arguments withExecuteDelegate:executeDelegate]; + [FFmpegKitConfig asyncFFprobeExecute:session onDispatchQueue:queue]; + return session; +} - for (int i=0; i < [arguments count]; i++) { - NSString *argument = [arguments objectAtIndex:i]; - commandCharPArray[i + 1] = (char *) [argument UTF8String]; - } ++ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate onDispatchQueue:(dispatch_queue_t)queue { + FFprobeSession* session = [[FFprobeSession alloc] init:arguments withExecuteDelegate:executeDelegate withLogDelegate:logDelegate]; + [FFmpegKitConfig asyncFFprobeExecute:session onDispatchQueue:queue]; + return session; +} - // RUN - lastReturnCode = ffprobe_execute(([arguments count] + 1), commandCharPArray); ++ (FFprobeSession*)execute:(NSString*)command { + FFprobeSession* session = [[FFprobeSession alloc] init:[FFmpegKit parseArguments:command]]; + [FFmpegKitConfig ffprobeExecute:session]; + return session; +} - // CLEANUP - av_free(commandCharPArray[0]); - av_free(commandCharPArray); ++ (FFprobeSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate { + FFprobeSession* session = [[FFprobeSession alloc] init:[FFmpegKit parseArguments:command] withExecuteDelegate:executeDelegate]; + [FFmpegKitConfig asyncFFprobeExecute:session]; + return session; +} - return lastReturnCode; ++ (FFprobeSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate { + FFprobeSession* session = [[FFprobeSession alloc] init:[FFmpegKit parseArguments:command] withExecuteDelegate:executeDelegate withLogDelegate:logDelegate]; + [FFmpegKitConfig asyncFFprobeExecute:session]; + return session; } -/** - * Synchronously executes FFprobe command provided. Space character is used to split command - * into arguments. - * - * @param command FFprobe command - * @return zero on successful execution, 255 on user cancel and non-zero on error - */ -+ (int)execute:(NSString*)command { - return [FFprobeKit executeWithArguments: [FFmpegKit parseArguments: command]]; ++ (FFprobeSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate onDispatchQueue:(dispatch_queue_t)queue { + FFprobeSession* session = [[FFprobeSession alloc] init:[FFmpegKit parseArguments:command] withExecuteDelegate:executeDelegate]; + [FFmpegKitConfig asyncFFprobeExecute:session onDispatchQueue:queue]; + return session; } -/** - * Returns media information for the given file. - * - * This method does not support executing multiple concurrent operations. If you execute - * multiple operations (execute or getMediaInformation) at the same time, the response of this - * method is not predictable. - * - * @param path or uri of media file - * @return media information - */ -+ (MediaInformation*)getMediaInformation:(NSString*)path { - return [FFprobeKit getMediaInformationFromCommandArguments:[[NSArray alloc] initWithObjects:@"-v", @"error", @"-hide_banner", @"-print_format", @"json", @"-show_format", @"-show_streams", @"-i", path, nil]]; ++ (FFprobeSession*)executeAsync:(NSString*)command withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate onDispatchQueue:(dispatch_queue_t)queue { + FFprobeSession* session = [[FFprobeSession alloc] init:[FFmpegKit parseArguments:command] withExecuteDelegate:executeDelegate withLogDelegate:logDelegate]; + [FFmpegKitConfig asyncFFprobeExecute:session onDispatchQueue:queue]; + return session; } -/** - * Returns media information for the given command. - * - * This method does not support executing multiple concurrent operations. If you execute - * multiple operations (execute or getMediaInformation) at the same time, the response of this - * method is not predictable. - * - * @param command - * @return media information - */ -+ (MediaInformation*)getMediaInformationFromCommand:(NSString*)command { - return [FFprobeKit getMediaInformationFromCommandArguments:[FFmpegKit parseArguments: command]]; ++ (MediaInformationSession*)getMediaInformation:(NSString*)path { + NSArray* arguments = [[NSArray alloc] initWithObjects:@"-v", @"error", @"-hide_banner", @"-print_format", @"json", @"-show_format", @"-show_streams", @"-i", path, nil]; + MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments]; + [FFmpegKitConfig getMediaInformationExecute:session withTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit]; + return session; } -/** - * Returns media information for given file. - * - * This method does not support executing multiple concurrent operations. If you execute - * multiple operations (execute or getMediaInformation) at the same time, the response of this - * method is not predictable. - * - * @param path path or uri of media file - * @param timeout complete timeout - * @deprecated this method is deprecated since v4.3.1. You can still use this method but - * timeout parameter is not effective anymore. - * @return media information - */ -+ (MediaInformation*)getMediaInformation:(NSString*)path timeout:(long)timeout { - return [FFprobeKit getMediaInformation:path]; ++ (MediaInformationSession*)getMediaInformation:(NSString*)path withTimeout:(int)waitTimeout { + NSArray* arguments = [[NSArray alloc] initWithObjects:@"-v", @"error", @"-hide_banner", @"-print_format", @"json", @"-show_format", @"-show_streams", @"-i", path, nil]; + MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments]; + [FFmpegKitConfig getMediaInformationExecute:session withTimeout:waitTimeout]; + return session; +} + ++ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withExecuteDelegate:(id)executeDelegate { + NSArray* arguments = [[NSArray alloc] initWithObjects:@"-v", @"error", @"-hide_banner", @"-print_format", @"json", @"-show_format", @"-show_streams", @"-i", path, nil]; + MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments withExecuteDelegate:executeDelegate]; + [FFmpegKitConfig asyncGetMediaInformationExecute:session withTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit]; + return session; } -+ (MediaInformation*)getMediaInformationFromCommandArguments:(NSArray*)arguments { - int rc = [FFprobeKit executeWithArguments:arguments]; ++ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withTimeout:(int)waitTimeout { + NSArray* arguments = [[NSArray alloc] initWithObjects:@"-v", @"error", @"-hide_banner", @"-print_format", @"json", @"-show_format", @"-show_streams", @"-i", path, nil]; + MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments withExecuteDelegate:executeDelegate withLogDelegate:logDelegate]; + [FFmpegKitConfig asyncGetMediaInformationExecute:session withTimeout:waitTimeout]; + return session; +} + ++ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withExecuteDelegate:(id)executeDelegate onDispatchQueue:(dispatch_queue_t)queue { + NSArray* arguments = [[NSArray alloc] initWithObjects:@"-v", @"error", @"-hide_banner", @"-print_format", @"json", @"-show_format", @"-show_streams", @"-i", path, nil]; + MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments withExecuteDelegate:executeDelegate]; + [FFmpegKitConfig asyncGetMediaInformationExecute:session onDispatchQueue:queue withTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit]; + return session; +} + ++ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout { + NSArray* arguments = [[NSArray alloc] initWithObjects:@"-v", @"error", @"-hide_banner", @"-print_format", @"json", @"-show_format", @"-show_streams", @"-i", path, nil]; + MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments withExecuteDelegate:executeDelegate]; + [FFmpegKitConfig asyncGetMediaInformationExecute:session onDispatchQueue:queue withTimeout:waitTimeout]; + return session; +} + ++ (MediaInformationSession*)getMediaInformationFromCommand:(NSString*)command { + MediaInformationSession* session = [[MediaInformationSession alloc] init:[FFmpegKit parseArguments:command]]; + [FFmpegKitConfig getMediaInformationExecute:session withTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit]; + return session; +} - if (rc == 0) { - return [MediaInformationParser from:[FFmpegKitConfig getLastCommandOutput]]; - } else { - int activeLogLevel = av_log_get_level(); - if ((activeLogLevel != AV_LOG_QUIET) && (AV_LOG_WARNING <= activeLogLevel)) { - NSLog(@"%@", [FFmpegKitConfig getLastCommandOutput]); - } ++ (MediaInformationSession*)getMediaInformationFromCommandAsync:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout { + MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments withExecuteDelegate:executeDelegate withLogDelegate:logDelegate]; + [FFmpegKitConfig asyncGetMediaInformationExecute:session onDispatchQueue:queue withTimeout:waitTimeout]; + return session; +} - return nil; - } ++ (NSArray*)listSessions { + return [FFmpegKitConfig getFFprobeSessions]; } @end diff --git a/apple/src/FFprobeSession.h b/apple/src/FFprobeSession.h new file mode 100644 index 0000000..16d898d --- /dev/null +++ b/apple/src/FFprobeSession.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021 Taner Sener + * + * This file is part of FFmpegKit. + * + * FFmpegKit is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#ifndef FFMPEG_KIT_FFPROBE_SESSION_H +#define FFMPEG_KIT_FFPROBE_SESSION_H + +#import +#import "AbstractSession.h" + +/** + *

An FFprobe session. + */ +@interface FFprobeSession : AbstractSession + +/** + * Builds a new FFprobe session. + * + * @param arguments command arguments + */ +- (instancetype)init:(NSArray*)arguments; + +/** + * Builds a new FFprobe session. + * + * @param arguments command arguments + * @param executeDelegate session specific execute delegate + */ +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate; + +/** + * Builds a new FFprobe session. + * + * @param arguments command arguments + * @param executeDelegate session specific execute delegate + * @param logDelegate session specific log delegate + */ +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate; + +/** + * Builds a new FFprobe session. + * + * @param arguments command arguments + * @param executeDelegate session specific execute delegate + * @param logDelegate session specific log delegate + * @param logRedirectionStrategy session specific log redirection strategy + */ +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy; + +@end + +#endif // FFMPEG_KIT_FFPROBE_SESSION_H diff --git a/apple/src/FFprobeSession.m b/apple/src/FFprobeSession.m new file mode 100644 index 0000000..9471456 --- /dev/null +++ b/apple/src/FFprobeSession.m @@ -0,0 +1,64 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#import "ExecuteDelegate.h" +#import "FFprobeSession.h" +#import "FFmpegKitConfig.h" +#import "LogDelegate.h" + +@implementation FFprobeSession + +- (instancetype)init:(NSArray*)arguments { + + self = [super init:arguments withExecuteDelegate:nil withLogDelegate:nil withLogRedirectionStrategy:[FFmpegKitConfig getLogRedirectionStrategy]]; + + return self; +} + +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate { + + self = [super init:arguments withExecuteDelegate:executeDelegate withLogDelegate:nil withLogRedirectionStrategy:[FFmpegKitConfig getLogRedirectionStrategy]]; + + return self; +} + +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate { + + self = [super init:arguments withExecuteDelegate:executeDelegate withLogDelegate:logDelegate withLogRedirectionStrategy:[FFmpegKitConfig getLogRedirectionStrategy]]; + + return self; +} + +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy { + + self = [super init:arguments withExecuteDelegate:executeDelegate withLogDelegate:logDelegate withLogRedirectionStrategy:logRedirectionStrategy]; + + return self; +} + +- (BOOL)isFFmpeg { + return false; +} + +- (BOOL)isFFprobe { + return true; +} + +@end + diff --git a/apple/src/Level.h b/apple/src/Level.h new file mode 100644 index 0000000..98cf43e --- /dev/null +++ b/apple/src/Level.h @@ -0,0 +1,85 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#ifndef FFMPEG_KIT_LEVEL_H +#define FFMPEG_KIT_LEVEL_H + +/** + *

Enumeration type for log levels. + */ +typedef NS_ENUM(NSUInteger, Level) { + + /** + * This log level is defined by FFmpegKit. It is used to specify logs printed to stderr by + * FFmpeg. Logs that has this level are not filtered and always redirected. + */ + LevelAVLogStdErr = -16, + + /** + * Print no output. + */ + LevelAVLogQuiet = -8, + + /** + * Something went really wrong and we will crash now. + */ + LevelAVLogPanic = 0, + + /** + * Something went wrong and recovery is not possible. + * For example, no header was found for a format which depends + * on headers or an illegal combination of parameters is used. + */ + LevelAVLogFatal = 8, + + /** + * Something went wrong and cannot losslessly be recovered. + * However, not all future data is affected. + */ + LevelAVLogError = 16, + + /** + * Something somehow does not look correct. This may or may not + * lead to problems. An example would be the use of '-vstrict -2'. + */ + LevelAVLogWarning = 24, + + /** + * Standard information. + */ + LevelAVLogInfo = 32, + + /** + * Detailed information. + */ + LevelAVLogVerbose = 40, + + /** + * Stuff which is only useful for libav* developers. + */ + LevelAVLogDebug = 48, + + /** + * Extremely verbose debugging, useful for libav* development. + */ + LevelAVLogTrace = 56 + +}; + +#endif // FFMPEG_KIT_LEVEL_H diff --git a/apple/src/Log.h b/apple/src/Log.h new file mode 100644 index 0000000..4199f92 --- /dev/null +++ b/apple/src/Log.h @@ -0,0 +1,40 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#ifndef FFMPEG_KIT_LOG_H +#define FFMPEG_KIT_LOG_H + +#import + +/** + *

Log entry for an FFmpegKit session. + */ +@interface Log : NSObject + +- (instancetype)init:(long)sessionId :(int)level :(NSString*)message; + +- (long)getSessionId; + +- (int)getLevel; + +- (NSString*)getMessage; + +@end + +#endif // FFMPEG_KIT_LOG_H diff --git a/apple/src/Log.m b/apple/src/Log.m new file mode 100644 index 0000000..812c2ad --- /dev/null +++ b/apple/src/Log.m @@ -0,0 +1,51 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#import "Log.h" + +@implementation Log { + long _sessionId; + int _level; + NSString *_message; +} + +- (instancetype)init:(long)sessionId :(int)level :(NSString*)message { + self = [super init]; + if (self) { + _sessionId = sessionId; + _level = level; + _message = message; + } + + return self; +} + +- (long)getSessionId { + return _sessionId; +} + +- (int)getLevel { + return _level; +} + +- (NSString*)getMessage { + return _message; +} + +@end diff --git a/apple/src/LogDelegate.h b/apple/src/LogDelegate.h index 18a0c36..e9d9596 100644 --- a/apple/src/LogDelegate.h +++ b/apple/src/LogDelegate.h @@ -17,10 +17,25 @@ * along with FFmpegKit. If not, see . */ +#ifndef FFMPEG_KIT_LOG_DELEGATE_H +#define FFMPEG_KIT_LOG_DELEGATE_H + +#import +#import "Log.h" + /** - * Use this delegate to receive logs from running executions. + *

Delegate that receives logs generated for FFmpegKit sessions. */ @protocol LogDelegate @required -- (void)logCallback:(long)executionId :(int)level :(NSString*)message; + +/** + *

Called when a log entry is received. + * + * @param log log entry + */ +- (void)logCallback:(Log*)log; + @end + +#endif // FFMPEG_KIT_LOG_DELEGATE_H diff --git a/apple/src/LogRedirectionStrategy.h b/apple/src/LogRedirectionStrategy.h new file mode 100644 index 0000000..53c696f --- /dev/null +++ b/apple/src/LogRedirectionStrategy.h @@ -0,0 +1,31 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#ifndef FFMPEG_KIT_LOG_REDIRECTION_STRATEGY_H +#define FFMPEG_KIT_LOG_REDIRECTION_STRATEGY_H + +typedef NS_ENUM(NSUInteger, LogRedirectionStrategy) { + LogRedirectionStrategyAlwaysPrintLogs, + LogRedirectionStrategyPrintLogsWhenNoDelegatesDefined, + LogRedirectionStrategyPrintLogsWhenGlobalDelegateNotDefined, + LogRedirectionStrategyPrintLogsWhenSessionDelegateNotDefined, + LogRedirectionStrategyNeverPrintLogs +}; + +#endif // FFMPEG_KIT_LOG_REDIRECTION_STRATEGY_H diff --git a/apple/src/Makefile.am b/apple/src/Makefile.am index 52d35c0..04a6e6c 100644 --- a/apple/src/Makefile.am +++ b/apple/src/Makefile.am @@ -3,45 +3,61 @@ lib_LTLIBRARIES = libffmpegkit.la libffmpegkit_la_LIBADD = @FFMPEG_LIBS@ libffmpegkit_la_SOURCES = \ + AbstractSession.m \ ArchDetect.m \ AtomicLong.m \ - FFmpegExecution.m \ FFmpegKit.m \ - ffmpegkit_exception.m \ FFmpegKitConfig.m \ + FFmpegSession.m \ FFprobeKit.m \ + FFprobeSession.m \ + Log.m \ + MediaInformation.m \ + MediaInformationJsonParser.m \ + MediaInformationSession.m \ + Packages.m \ + ReturnCode.m \ + Statistics.m \ + StreamInformation.m \ + ffmpegkit_exception.m \ fftools_cmdutils.c \ fftools_ffmpeg.c \ fftools_ffmpeg_filter.c \ fftools_ffmpeg_hw.c \ fftools_ffmpeg_opt.c \ - fftools_ffprobe.c \ - MediaInformation.m \ - MediaInformationParser.m \ - Statistics.m \ - StreamInformation.m + fftools_ffprobe.c if FFMPEGKIT_VIDEOTOOLBOX libffmpegkit_la_SOURCES += fftools_ffmpeg_videotoolbox.c endif include_HEADERS = \ + AbstractSession.h \ ArchDetect.h \ AtomicLong.h \ ExecuteDelegate.h \ - FFmpegExecution.h \ FFmpegKit.h \ - ffmpegkit_exception.h \ FFmpegKitConfig.h \ + FFmpegSession.h \ FFprobeKit.h \ - fftools_cmdutils.h \ - fftools_ffmpeg.h \ + FFprobeSession.h \ + Level.h \ + Log.h \ LogDelegate.h \ + LogRedirectionStrategy.h \ MediaInformation.h \ - MediaInformationParser.h \ + MediaInformationJsonParser.h \ + MediaInformationSession.h \ + Packages.h \ + ReturnCode.h \ + Session.h \ + SessionState.h \ Statistics.h \ StatisticsDelegate.h \ - StreamInformation.h + StreamInformation.h \ + ffmpegkit_exception.h \ + fftools_cmdutils.h \ + fftools_ffmpeg.h libffmpegkit_la_CFLAGS = $(CFLAGS) libffmpegkit_la_OBJCFLAGS = $(CFLAGS) diff --git a/apple/src/Makefile.in b/apple/src/Makefile.in index 143d650..0ca66ae 100644 --- a/apple/src/Makefile.in +++ b/apple/src/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.16.2 from Makefile.am. +# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. @@ -133,31 +133,35 @@ am__uninstall_files_from_dir = { \ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" LTLIBRARIES = $(lib_LTLIBRARIES) libffmpegkit_la_DEPENDENCIES = -am__libffmpegkit_la_SOURCES_DIST = ArchDetect.m AtomicLong.m \ - fftools_cmdutils.c fftools_ffmpeg.c fftools_ffmpeg_filter.c \ - fftools_ffmpeg_hw.c fftools_ffmpeg_opt.c fftools_ffprobe.c \ - FFmpegExecution.m MediaInformation.m MediaInformationParser.m \ - FFmpegKit.m FFmpegKitConfig.m ffmpegkit_exception.m \ - FFprobeKit.m Statistics.m StreamInformation.m \ +am__libffmpegkit_la_SOURCES_DIST = AbstractSession.m ArchDetect.m \ + AtomicLong.m FFmpegKit.m FFmpegKitConfig.m FFmpegSession.m \ + FFprobeKit.m FFprobeSession.m Log.m MediaInformation.m \ + MediaInformationJsonParser.m MediaInformationSession.m \ + Packages.m ReturnCode.m Statistics.m StreamInformation.m \ + ffmpegkit_exception.m fftools_cmdutils.c fftools_ffmpeg.c \ + fftools_ffmpeg_filter.c fftools_ffmpeg_hw.c \ + fftools_ffmpeg_opt.c fftools_ffprobe.c \ fftools_ffmpeg_videotoolbox.c @FFMPEGKIT_VIDEOTOOLBOX_TRUE@am__objects_1 = libffmpegkit_la-fftools_ffmpeg_videotoolbox.lo -am_libffmpegkit_la_OBJECTS = libffmpegkit_la-ArchDetect.lo \ - libffmpegkit_la-AtomicLong.lo \ +am_libffmpegkit_la_OBJECTS = libffmpegkit_la-AbstractSession.lo \ + libffmpegkit_la-ArchDetect.lo libffmpegkit_la-AtomicLong.lo \ + libffmpegkit_la-FFmpegKit.lo \ + libffmpegkit_la-FFmpegKitConfig.lo \ + libffmpegkit_la-FFmpegSession.lo libffmpegkit_la-FFprobeKit.lo \ + libffmpegkit_la-FFprobeSession.lo libffmpegkit_la-Log.lo \ + libffmpegkit_la-MediaInformation.lo \ + libffmpegkit_la-MediaInformationJsonParser.lo \ + libffmpegkit_la-MediaInformationSession.lo \ + libffmpegkit_la-Packages.lo libffmpegkit_la-ReturnCode.lo \ + libffmpegkit_la-Statistics.lo \ + libffmpegkit_la-StreamInformation.lo \ + libffmpegkit_la-ffmpegkit_exception.lo \ libffmpegkit_la-fftools_cmdutils.lo \ libffmpegkit_la-fftools_ffmpeg.lo \ libffmpegkit_la-fftools_ffmpeg_filter.lo \ libffmpegkit_la-fftools_ffmpeg_hw.lo \ libffmpegkit_la-fftools_ffmpeg_opt.lo \ - libffmpegkit_la-fftools_ffprobe.lo \ - libffmpegkit_la-FFmpegExecution.lo \ - libffmpegkit_la-MediaInformation.lo \ - libffmpegkit_la-MediaInformationParser.lo \ - libffmpegkit_la-FFmpegKit.lo \ - libffmpegkit_la-FFmpegKitConfig.lo \ - libffmpegkit_la-ffmpegkit_exception.lo \ - libffmpegkit_la-FFprobeKit.lo \ - libffmpegkit_la-Statistics.lo \ - libffmpegkit_la-StreamInformation.lo $(am__objects_1) + libffmpegkit_la-fftools_ffprobe.lo $(am__objects_1) libffmpegkit_la_OBJECTS = $(am_libffmpegkit_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -182,24 +186,30 @@ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles -am__depfiles_remade = ./$(DEPDIR)/libffmpegkit_la-ArchDetect.Plo \ +am__depfiles_remade = ./$(DEPDIR)/libffmpegkit_la-AbstractSession.Plo \ + ./$(DEPDIR)/libffmpegkit_la-ArchDetect.Plo \ ./$(DEPDIR)/libffmpegkit_la-AtomicLong.Plo \ - ./$(DEPDIR)/libffmpegkit_la-FFmpegExecution.Plo \ - ./$(DEPDIR)/libffmpegkit_la-MediaInformation.Plo \ - ./$(DEPDIR)/libffmpegkit_la-MediaInformationParser.Plo \ ./$(DEPDIR)/libffmpegkit_la-FFmpegKit.Plo \ ./$(DEPDIR)/libffmpegkit_la-FFmpegKitConfig.Plo \ + ./$(DEPDIR)/libffmpegkit_la-FFmpegSession.Plo \ ./$(DEPDIR)/libffmpegkit_la-FFprobeKit.Plo \ + ./$(DEPDIR)/libffmpegkit_la-FFprobeSession.Plo \ + ./$(DEPDIR)/libffmpegkit_la-Log.Plo \ + ./$(DEPDIR)/libffmpegkit_la-MediaInformation.Plo \ + ./$(DEPDIR)/libffmpegkit_la-MediaInformationJsonParser.Plo \ + ./$(DEPDIR)/libffmpegkit_la-MediaInformationSession.Plo \ + ./$(DEPDIR)/libffmpegkit_la-Packages.Plo \ + ./$(DEPDIR)/libffmpegkit_la-ReturnCode.Plo \ ./$(DEPDIR)/libffmpegkit_la-Statistics.Plo \ ./$(DEPDIR)/libffmpegkit_la-StreamInformation.Plo \ + ./$(DEPDIR)/libffmpegkit_la-ffmpegkit_exception.Plo \ ./$(DEPDIR)/libffmpegkit_la-fftools_cmdutils.Plo \ ./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg.Plo \ ./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg_filter.Plo \ ./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg_hw.Plo \ ./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg_opt.Plo \ ./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg_videotoolbox.Plo \ - ./$(DEPDIR)/libffmpegkit_la-fftools_ffprobe.Plo \ - ./$(DEPDIR)/libffmpegkit_la-ffmpegkit_exception.Plo + ./$(DEPDIR)/libffmpegkit_la-fftools_ffprobe.Plo am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) @@ -389,30 +399,41 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ lib_LTLIBRARIES = libffmpegkit.la libffmpegkit_la_LIBADD = @FFMPEG_LIBS@ -libffmpegkit_la_SOURCES = ArchDetect.m AtomicLong.m \ - fftools_cmdutils.c fftools_ffmpeg.c fftools_ffmpeg_filter.c \ - fftools_ffmpeg_hw.c fftools_ffmpeg_opt.c fftools_ffprobe.c \ - FFmpegExecution.m MediaInformation.m MediaInformationParser.m \ - FFmpegKit.m FFmpegKitConfig.m ffmpegkit_exception.m \ - FFprobeKit.m Statistics.m StreamInformation.m \ - $(am__append_1) +libffmpegkit_la_SOURCES = AbstractSession.m ArchDetect.m AtomicLong.m \ + FFmpegKit.m FFmpegKitConfig.m FFmpegSession.m FFprobeKit.m \ + FFprobeSession.m Log.m MediaInformation.m \ + MediaInformationJsonParser.m MediaInformationSession.m \ + Packages.m ReturnCode.m Statistics.m StreamInformation.m \ + ffmpegkit_exception.m fftools_cmdutils.c fftools_ffmpeg.c \ + fftools_ffmpeg_filter.c fftools_ffmpeg_hw.c \ + fftools_ffmpeg_opt.c fftools_ffprobe.c $(am__append_1) include_HEADERS = \ + AbstractSession.h \ ArchDetect.h \ AtomicLong.h \ ExecuteDelegate.h \ - FFmpegExecution.h \ - fftools_cmdutils.h \ - fftools_ffmpeg.h \ - LogDelegate.h \ - MediaInformation.h \ - MediaInformationParser.h \ FFmpegKit.h \ FFmpegKitConfig.h \ - ffmpegkit_exception.h \ + FFmpegSession.h \ FFprobeKit.h \ + FFprobeSession.h \ + Level.h \ + Log.h \ + LogDelegate.h \ + LogRedirectionStrategy.h \ + MediaInformation.h \ + MediaInformationJsonParser.h \ + MediaInformationSession.h \ + Packages.h \ + ReturnCode.h \ + Session.h \ + SessionState.h \ Statistics.h \ StatisticsDelegate.h \ - StreamInformation.h + StreamInformation.h \ + ffmpegkit_exception.h \ + fftools_cmdutils.h \ + fftools_ffmpeg.h libffmpegkit_la_CFLAGS = $(CFLAGS) libffmpegkit_la_OBJCFLAGS = $(CFLAGS) @@ -487,7 +508,7 @@ clean-libLTLIBRARIES: rm -f $${locs}; \ } -libffmpegkit.la: $(libffmpegkit_la_OBJECTS) $(libffmpegkit_la_DEPENDENCIES) $(EXTRA_libffmpegkit_la_DEPENDENCIES) +libffmpegkit.la: $(libffmpegkit_la_OBJECTS) $(libffmpegkit_la_DEPENDENCIES) $(EXTRA_libffmpegkit_la_DEPENDENCIES) $(AM_V_OBJCLD)$(libffmpegkit_la_LINK) -rpath $(libdir) $(libffmpegkit_la_OBJECTS) $(libffmpegkit_la_LIBADD) $(LIBS) mostlyclean-compile: @@ -496,16 +517,23 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-AbstractSession.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-ArchDetect.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-AtomicLong.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-FFmpegExecution.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-MediaInformation.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-MediaInformationParser.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-FFmpegKit.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-FFmpegKitConfig.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-FFmpegSession.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-FFprobeKit.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-FFprobeSession.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-Log.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-MediaInformation.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-MediaInformationJsonParser.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-MediaInformationSession.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-Packages.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-ReturnCode.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-Statistics.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-StreamInformation.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-ffmpegkit_exception.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-fftools_cmdutils.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg_filter.Plo@am__quote@ # am--include-marker @@ -513,7 +541,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg_opt.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg_videotoolbox.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-fftools_ffprobe.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-ffmpegkit_exception.Plo@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @@ -618,6 +645,13 @@ libffmpegkit_la-fftools_ffmpeg_videotoolbox.lo: fftools_ffmpeg_videotoolbox.c @AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LTOBJCCOMPILE) -c -o $@ $< +libffmpegkit_la-AbstractSession.lo: AbstractSession.m +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-AbstractSession.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-AbstractSession.Tpo -c -o libffmpegkit_la-AbstractSession.lo `test -f 'AbstractSession.m' || echo '$(srcdir)/'`AbstractSession.m +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-AbstractSession.Tpo $(DEPDIR)/libffmpegkit_la-AbstractSession.Plo +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='AbstractSession.m' object='libffmpegkit_la-AbstractSession.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-AbstractSession.lo `test -f 'AbstractSession.m' || echo '$(srcdir)/'`AbstractSession.m + libffmpegkit_la-ArchDetect.lo: ArchDetect.m @am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-ArchDetect.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-ArchDetect.Tpo -c -o libffmpegkit_la-ArchDetect.lo `test -f 'ArchDetect.m' || echo '$(srcdir)/'`ArchDetect.m @am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-ArchDetect.Tpo $(DEPDIR)/libffmpegkit_la-ArchDetect.Plo @@ -632,27 +666,6 @@ libffmpegkit_la-AtomicLong.lo: AtomicLong.m @AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-AtomicLong.lo `test -f 'AtomicLong.m' || echo '$(srcdir)/'`AtomicLong.m -libffmpegkit_la-FFmpegExecution.lo: FFmpegExecution.m -@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-FFmpegExecution.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-FFmpegExecution.Tpo -c -o libffmpegkit_la-FFmpegExecution.lo `test -f 'FFmpegExecution.m' || echo '$(srcdir)/'`FFmpegExecution.m -@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-FFmpegExecution.Tpo $(DEPDIR)/libffmpegkit_la-FFmpegExecution.Plo -@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='FFmpegExecution.m' object='libffmpegkit_la-FFmpegExecution.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-FFmpegExecution.lo `test -f 'FFmpegExecution.m' || echo '$(srcdir)/'`FFmpegExecution.m - -libffmpegkit_la-MediaInformation.lo: MediaInformation.m -@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-MediaInformation.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-MediaInformation.Tpo -c -o libffmpegkit_la-MediaInformation.lo `test -f 'MediaInformation.m' || echo '$(srcdir)/'`MediaInformation.m -@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-MediaInformation.Tpo $(DEPDIR)/libffmpegkit_la-MediaInformation.Plo -@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='MediaInformation.m' object='libffmpegkit_la-MediaInformation.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-MediaInformation.lo `test -f 'MediaInformation.m' || echo '$(srcdir)/'`MediaInformation.m - -libffmpegkit_la-MediaInformationParser.lo: MediaInformationParser.m -@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-MediaInformationParser.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-MediaInformationParser.Tpo -c -o libffmpegkit_la-MediaInformationParser.lo `test -f 'MediaInformationParser.m' || echo '$(srcdir)/'`MediaInformationParser.m -@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-MediaInformationParser.Tpo $(DEPDIR)/libffmpegkit_la-MediaInformationParser.Plo -@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='MediaInformationParser.m' object='libffmpegkit_la-MediaInformationParser.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-MediaInformationParser.lo `test -f 'MediaInformationParser.m' || echo '$(srcdir)/'`MediaInformationParser.m - libffmpegkit_la-FFmpegKit.lo: FFmpegKit.m @am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-FFmpegKit.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-FFmpegKit.Tpo -c -o libffmpegkit_la-FFmpegKit.lo `test -f 'FFmpegKit.m' || echo '$(srcdir)/'`FFmpegKit.m @am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-FFmpegKit.Tpo $(DEPDIR)/libffmpegkit_la-FFmpegKit.Plo @@ -667,12 +680,12 @@ libffmpegkit_la-FFmpegKitConfig.lo: FFmpegKitConfig.m @AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-FFmpegKitConfig.lo `test -f 'FFmpegKitConfig.m' || echo '$(srcdir)/'`FFmpegKitConfig.m -libffmpegkit_la-ffmpegkit_exception.lo: ffmpegkit_exception.m -@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-ffmpegkit_exception.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-ffmpegkit_exception.Tpo -c -o libffmpegkit_la-ffmpegkit_exception.lo `test -f 'ffmpegkit_exception.m' || echo '$(srcdir)/'`ffmpegkit_exception.m -@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-ffmpegkit_exception.Tpo $(DEPDIR)/libffmpegkit_la-ffmpegkit_exception.Plo -@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='ffmpegkit_exception.m' object='libffmpegkit_la-ffmpegkit_exception.lo' libtool=yes @AMDEPBACKSLASH@ +libffmpegkit_la-FFmpegSession.lo: FFmpegSession.m +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-FFmpegSession.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-FFmpegSession.Tpo -c -o libffmpegkit_la-FFmpegSession.lo `test -f 'FFmpegSession.m' || echo '$(srcdir)/'`FFmpegSession.m +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-FFmpegSession.Tpo $(DEPDIR)/libffmpegkit_la-FFmpegSession.Plo +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='FFmpegSession.m' object='libffmpegkit_la-FFmpegSession.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-ffmpegkit_exception.lo `test -f 'ffmpegkit_exception.m' || echo '$(srcdir)/'`ffmpegkit_exception.m +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-FFmpegSession.lo `test -f 'FFmpegSession.m' || echo '$(srcdir)/'`FFmpegSession.m libffmpegkit_la-FFprobeKit.lo: FFprobeKit.m @am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-FFprobeKit.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-FFprobeKit.Tpo -c -o libffmpegkit_la-FFprobeKit.lo `test -f 'FFprobeKit.m' || echo '$(srcdir)/'`FFprobeKit.m @@ -681,6 +694,55 @@ libffmpegkit_la-FFprobeKit.lo: FFprobeKit.m @AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-FFprobeKit.lo `test -f 'FFprobeKit.m' || echo '$(srcdir)/'`FFprobeKit.m +libffmpegkit_la-FFprobeSession.lo: FFprobeSession.m +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-FFprobeSession.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-FFprobeSession.Tpo -c -o libffmpegkit_la-FFprobeSession.lo `test -f 'FFprobeSession.m' || echo '$(srcdir)/'`FFprobeSession.m +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-FFprobeSession.Tpo $(DEPDIR)/libffmpegkit_la-FFprobeSession.Plo +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='FFprobeSession.m' object='libffmpegkit_la-FFprobeSession.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-FFprobeSession.lo `test -f 'FFprobeSession.m' || echo '$(srcdir)/'`FFprobeSession.m + +libffmpegkit_la-Log.lo: Log.m +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-Log.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-Log.Tpo -c -o libffmpegkit_la-Log.lo `test -f 'Log.m' || echo '$(srcdir)/'`Log.m +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-Log.Tpo $(DEPDIR)/libffmpegkit_la-Log.Plo +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='Log.m' object='libffmpegkit_la-Log.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-Log.lo `test -f 'Log.m' || echo '$(srcdir)/'`Log.m + +libffmpegkit_la-MediaInformation.lo: MediaInformation.m +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-MediaInformation.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-MediaInformation.Tpo -c -o libffmpegkit_la-MediaInformation.lo `test -f 'MediaInformation.m' || echo '$(srcdir)/'`MediaInformation.m +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-MediaInformation.Tpo $(DEPDIR)/libffmpegkit_la-MediaInformation.Plo +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='MediaInformation.m' object='libffmpegkit_la-MediaInformation.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-MediaInformation.lo `test -f 'MediaInformation.m' || echo '$(srcdir)/'`MediaInformation.m + +libffmpegkit_la-MediaInformationJsonParser.lo: MediaInformationJsonParser.m +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-MediaInformationJsonParser.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-MediaInformationJsonParser.Tpo -c -o libffmpegkit_la-MediaInformationJsonParser.lo `test -f 'MediaInformationJsonParser.m' || echo '$(srcdir)/'`MediaInformationJsonParser.m +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-MediaInformationJsonParser.Tpo $(DEPDIR)/libffmpegkit_la-MediaInformationJsonParser.Plo +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='MediaInformationJsonParser.m' object='libffmpegkit_la-MediaInformationJsonParser.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-MediaInformationJsonParser.lo `test -f 'MediaInformationJsonParser.m' || echo '$(srcdir)/'`MediaInformationJsonParser.m + +libffmpegkit_la-MediaInformationSession.lo: MediaInformationSession.m +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-MediaInformationSession.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-MediaInformationSession.Tpo -c -o libffmpegkit_la-MediaInformationSession.lo `test -f 'MediaInformationSession.m' || echo '$(srcdir)/'`MediaInformationSession.m +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-MediaInformationSession.Tpo $(DEPDIR)/libffmpegkit_la-MediaInformationSession.Plo +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='MediaInformationSession.m' object='libffmpegkit_la-MediaInformationSession.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-MediaInformationSession.lo `test -f 'MediaInformationSession.m' || echo '$(srcdir)/'`MediaInformationSession.m + +libffmpegkit_la-Packages.lo: Packages.m +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-Packages.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-Packages.Tpo -c -o libffmpegkit_la-Packages.lo `test -f 'Packages.m' || echo '$(srcdir)/'`Packages.m +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-Packages.Tpo $(DEPDIR)/libffmpegkit_la-Packages.Plo +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='Packages.m' object='libffmpegkit_la-Packages.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-Packages.lo `test -f 'Packages.m' || echo '$(srcdir)/'`Packages.m + +libffmpegkit_la-ReturnCode.lo: ReturnCode.m +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-ReturnCode.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-ReturnCode.Tpo -c -o libffmpegkit_la-ReturnCode.lo `test -f 'ReturnCode.m' || echo '$(srcdir)/'`ReturnCode.m +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-ReturnCode.Tpo $(DEPDIR)/libffmpegkit_la-ReturnCode.Plo +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='ReturnCode.m' object='libffmpegkit_la-ReturnCode.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-ReturnCode.lo `test -f 'ReturnCode.m' || echo '$(srcdir)/'`ReturnCode.m + libffmpegkit_la-Statistics.lo: Statistics.m @am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-Statistics.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-Statistics.Tpo -c -o libffmpegkit_la-Statistics.lo `test -f 'Statistics.m' || echo '$(srcdir)/'`Statistics.m @am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-Statistics.Tpo $(DEPDIR)/libffmpegkit_la-Statistics.Plo @@ -695,6 +757,13 @@ libffmpegkit_la-StreamInformation.lo: StreamInformation.m @AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-StreamInformation.lo `test -f 'StreamInformation.m' || echo '$(srcdir)/'`StreamInformation.m +libffmpegkit_la-ffmpegkit_exception.lo: ffmpegkit_exception.m +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-ffmpegkit_exception.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-ffmpegkit_exception.Tpo -c -o libffmpegkit_la-ffmpegkit_exception.lo `test -f 'ffmpegkit_exception.m' || echo '$(srcdir)/'`ffmpegkit_exception.m +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-ffmpegkit_exception.Tpo $(DEPDIR)/libffmpegkit_la-ffmpegkit_exception.Plo +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='ffmpegkit_exception.m' object='libffmpegkit_la-ffmpegkit_exception.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-ffmpegkit_exception.lo `test -f 'ffmpegkit_exception.m' || echo '$(srcdir)/'`ffmpegkit_exception.m + mostlyclean-libtool: -rm -f *.lo @@ -850,16 +919,23 @@ clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am - -rm -f ./$(DEPDIR)/libffmpegkit_la-ArchDetect.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-AbstractSession.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-ArchDetect.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-AtomicLong.Plo - -rm -f ./$(DEPDIR)/libffmpegkit_la-FFmpegExecution.Plo - -rm -f ./$(DEPDIR)/libffmpegkit_la-MediaInformation.Plo - -rm -f ./$(DEPDIR)/libffmpegkit_la-MediaInformationParser.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-FFmpegKit.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-FFmpegKitConfig.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-FFmpegSession.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-FFprobeKit.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-FFprobeSession.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-Log.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-MediaInformation.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-MediaInformationJsonParser.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-MediaInformationSession.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-Packages.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-ReturnCode.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-Statistics.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-StreamInformation.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-ffmpegkit_exception.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-fftools_cmdutils.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg_filter.Plo @@ -867,7 +943,6 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg_opt.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg_videotoolbox.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-fftools_ffprobe.Plo - -rm -f ./$(DEPDIR)/libffmpegkit_la-ffmpegkit_exception.Plo -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags @@ -913,16 +988,23 @@ install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am - -rm -f ./$(DEPDIR)/libffmpegkit_la-ArchDetect.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-AbstractSession.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-ArchDetect.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-AtomicLong.Plo - -rm -f ./$(DEPDIR)/libffmpegkit_la-FFmpegExecution.Plo - -rm -f ./$(DEPDIR)/libffmpegkit_la-MediaInformation.Plo - -rm -f ./$(DEPDIR)/libffmpegkit_la-MediaInformationParser.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-FFmpegKit.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-FFmpegKitConfig.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-FFmpegSession.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-FFprobeKit.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-FFprobeSession.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-Log.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-MediaInformation.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-MediaInformationJsonParser.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-MediaInformationSession.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-Packages.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-ReturnCode.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-Statistics.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-StreamInformation.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-ffmpegkit_exception.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-fftools_cmdutils.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg_filter.Plo @@ -930,7 +1012,6 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg_opt.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-fftools_ffmpeg_videotoolbox.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-fftools_ffprobe.Plo - -rm -f ./$(DEPDIR)/libffmpegkit_la-ffmpegkit_exception.Plo -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/apple/src/MediaInformation.h b/apple/src/MediaInformation.h index 164c925..20813cf 100644 --- a/apple/src/MediaInformation.h +++ b/apple/src/MediaInformation.h @@ -17,8 +17,21 @@ * along with FFmpegKit. If not, see . */ -#include -#include "StreamInformation.h" +#ifndef FFMPEG_KIT_MEDIA_INFORMATION_H +#define FFMPEG_KIT_MEDIA_INFORMATION_H + +#import +#import "StreamInformation.h" + +extern NSString* const MediaKeyMediaProperties; +extern NSString* const MediaKeyFilename; +extern NSString* const MediaKeyFormat; +extern NSString* const MediaKeyFormatLong; +extern NSString* const MediaKeyStartTime; +extern NSString* const MediaKeyDuration; +extern NSString* const MediaKeySize; +extern NSString* const MediaKeyBitRate; +extern NSString* const MediaKeyTags; /** * Media information class. @@ -126,3 +139,5 @@ - (NSDictionary*)getAllProperties; @end + +#endif // FFMPEG_KIT_MEDIA_INFORMATION_H diff --git a/apple/src/MediaInformation.m b/apple/src/MediaInformation.m index a44f0b6..c8ba7a9 100644 --- a/apple/src/MediaInformation.m +++ b/apple/src/MediaInformation.m @@ -17,17 +17,17 @@ * along with FFmpegKit. If not, see . */ -#include "MediaInformation.h" - -#define KEY_MEDIA_PROPERTIES @"format" -#define KEY_FILENAME @"filename" -#define KEY_FORMAT @"format_name" -#define KEY_FORMAT_LONG @"format_long_name" -#define KEY_START_TIME @"start_time" -#define KEY_DURATION @"duration" -#define KEY_SIZE @"size" -#define KEY_BIT_RATE @"bit_rate" -#define KEY_TAGS @"tags" +#import "MediaInformation.h" + +NSString* const MediaKeyMediaProperties = @"format"; +NSString* const MediaKeyFilename = @"filename"; +NSString* const MediaKeyFormat = @"format_name"; +NSString* const MediaKeyFormatLong = @"format_long_name"; +NSString* const MediaKeyStartTime = @"start_time"; +NSString* const MediaKeyDuration = @"duration"; +NSString* const MediaKeySize = @"size"; +NSString* const MediaKeyBitRate = @"bit_rate"; +NSString* const MediaKeyTags = @"tags"; @implementation MediaInformation { @@ -54,35 +54,35 @@ } - (NSString*)getFilename { - return [self getStringProperty:KEY_FILENAME]; + return [self getStringProperty:MediaKeyFilename]; } - (NSString*)getFormat { - return [self getStringProperty:KEY_FORMAT]; + return [self getStringProperty:MediaKeyFormat]; } - (NSString*)getLongFormat { - return [self getStringProperty:KEY_FORMAT_LONG]; + return [self getStringProperty:MediaKeyFormatLong]; } - (NSString*)getStartTime { - return [self getStringProperty:KEY_START_TIME]; + return [self getStringProperty:MediaKeyStartTime]; } - (NSString*)getDuration { - return [self getStringProperty:KEY_DURATION]; + return [self getStringProperty:MediaKeyDuration]; } - (NSString*)getSize { - return [self getStringProperty:KEY_SIZE]; + return [self getStringProperty:MediaKeySize]; } - (NSString*)getBitrate { - return [self getStringProperty:KEY_BIT_RATE]; + return [self getStringProperty:MediaKeyBitRate]; } - (NSDictionary*)getTags { - return [self getProperties:KEY_TAGS]; + return [self getProperties:MediaKeyTags]; } - (NSArray*)getStreams { @@ -117,7 +117,7 @@ } - (NSDictionary*)getMediaProperties { - return dictionary[KEY_MEDIA_PROPERTIES]; + return dictionary[MediaKeyMediaProperties]; } - (NSDictionary*)getAllProperties { diff --git a/apple/src/MediaInformationParser.h b/apple/src/MediaInformationJsonParser.h similarity index 53% rename from apple/src/MediaInformationParser.h rename to apple/src/MediaInformationJsonParser.h index 271551d..91f3db8 100644 --- a/apple/src/MediaInformationParser.h +++ b/apple/src/MediaInformationJsonParser.h @@ -17,19 +17,34 @@ * along with FFmpegKit. If not, see . */ -#include -#include "MediaInformation.h" +#ifndef FFMPEG_KIT_MEDIA_INFORMATION_PARSER_H +#define FFMPEG_KIT_MEDIA_INFORMATION_PARSER_H -@interface MediaInformationParser : NSObject +#import +#import "MediaInformation.h" /** - * Extracts MediaInformation from the given ffprobe json output. + * A parser that constructs MediaInformation from FFprobe's json output. + */ +@interface MediaInformationJsonParser : NSObject + +/** + * Extracts MediaInformation from the given FFprobe json output. + * + * @param ffprobeJsonOutput FFprobe json output + * @return created MediaInformation instance of nil if a parsing error occurs */ + (MediaInformation*)from:(NSString*)ffprobeJsonOutput; /** - * Extracts MediaInformation from the given ffprobe json output and saves parsing errors in error parameter. + * Extracts MediaInformation from the given FFprobe json output. + * + * @param ffprobeJsonOutput FFprobe json output + * @param error error to save the parsing error if a parsing error occurs + * @return created MediaInformation instance */ + (MediaInformation*)from:(NSString*)ffprobeJsonOutput with:(NSError*)error; @end + +#endif // FFMPEG_KIT_MEDIA_INFORMATION_PARSER_H diff --git a/apple/src/MediaInformationParser.m b/apple/src/MediaInformationJsonParser.m similarity index 95% rename from apple/src/MediaInformationParser.m rename to apple/src/MediaInformationJsonParser.m index 2405832..e7fa171 100644 --- a/apple/src/MediaInformationParser.m +++ b/apple/src/MediaInformationJsonParser.m @@ -17,9 +17,9 @@ * along with FFmpegKit. If not, see . */ -#include "MediaInformationParser.h" +#import "MediaInformationJsonParser.h" -@implementation MediaInformationParser +@implementation MediaInformationJsonParser + (MediaInformation*)from:(NSString*)ffprobeJsonOutput { NSError *error; diff --git a/apple/src/MediaInformationSession.h b/apple/src/MediaInformationSession.h new file mode 100644 index 0000000..4b37dd1 --- /dev/null +++ b/apple/src/MediaInformationSession.h @@ -0,0 +1,74 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#ifndef FFMPEG_KIT_MEDIA_INFORMATION_SESSION_H +#define FFMPEG_KIT_MEDIA_INFORMATION_SESSION_H + +#import +#import "FFprobeSession.h" +#import "MediaInformation.h" + +/** + *

A custom FFprobe session, which produces a MediaInformation object using the + * FFprobe output. + */ +@interface MediaInformationSession : FFprobeSession + +/** + * Creates a new media information session. + * + * @param arguments command arguments + */ +- (instancetype)init:(NSArray*)arguments; + +/** + * Creates a new media information session. + * + * @param arguments command arguments + * @param executeDelegate session specific execute delegate + */ +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate; + +/** + * Creates a new media information session. + * + * @param arguments command arguments + * @param executeDelegate session specific execute delegate + * @param logDelegate session specific log delegate + */ +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate; + +/** + * Returns the media information extracted in this session. + * + * @return media information extracted or nil if the command failed or the output can not be + * parsed + */ +- (MediaInformation*)getMediaInformation; + +/** + * Sets the media information extracted in this session. + * + * @param mediaInformation media information extracted + */ +- (void)setMediaInformation:(MediaInformation*)mediaInformation; + +@end + +#endif // FFMPEG_KIT_MEDIA_INFORMATION_SESSION_H diff --git a/apple/src/MediaInformationSession.m b/apple/src/MediaInformationSession.m new file mode 100644 index 0000000..95b687d --- /dev/null +++ b/apple/src/MediaInformationSession.m @@ -0,0 +1,59 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#import "ExecuteDelegate.h" +#import "LogDelegate.h" +#import "MediaInformation.h" +#import "MediaInformationSession.h" + +@implementation MediaInformationSession { + MediaInformation* _mediaInformation; +} + +- (instancetype)init:(NSArray*)arguments { + + self = [super init:arguments withExecuteDelegate:nil withLogDelegate:nil withLogRedirectionStrategy:LogRedirectionStrategyNeverPrintLogs]; + + return self; +} + +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate { + + self = [super init:arguments withExecuteDelegate:executeDelegate withLogDelegate:nil withLogRedirectionStrategy:LogRedirectionStrategyNeverPrintLogs]; + + return self; +} + +- (instancetype)init:(NSArray*)arguments withExecuteDelegate:(id)executeDelegate withLogDelegate:(id)logDelegate { + + self = [super init:arguments withExecuteDelegate:executeDelegate withLogDelegate:logDelegate withLogRedirectionStrategy:LogRedirectionStrategyNeverPrintLogs]; + + return self; +} + +- (MediaInformation*)getMediaInformation { + return _mediaInformation; +} + +- (void)setMediaInformation:(MediaInformation*)mediaInformation { + _mediaInformation = mediaInformation; +} + +@end + diff --git a/apple/src/Packages.h b/apple/src/Packages.h new file mode 100644 index 0000000..83d6068 --- /dev/null +++ b/apple/src/Packages.h @@ -0,0 +1,46 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#ifndef FFMPEG_KIT_PACKAGES_H +#define FFMPEG_KIT_PACKAGES_H + +#import + +/** + *

Helper class to extract binary package information. + */ +@interface Packages : NSObject + +/** + * Returns the FFmpegKit binary package name. + * + * @return predicted FFmpegKit binary package name + */ ++ (NSString*)getPackageName; + +/** + * Returns enabled external libraries by FFmpeg. + * + * @return enabled external libraries + */ ++ (NSArray*)getExternalLibraries; + +@end + +#endif // FFMPEG_KIT_PACKAGES_H diff --git a/apple/src/Packages.m b/apple/src/Packages.m new file mode 100644 index 0000000..f401f75 --- /dev/null +++ b/apple/src/Packages.m @@ -0,0 +1,263 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#import "config.h" +#import "libavutil/ffversion.h" +#import "FFmpegKitConfig.h" +#import "Packages.h" + +static NSMutableArray *supportedExternalLibraries; + +@implementation Packages + ++ (void)initialize { + supportedExternalLibraries = [[NSMutableArray alloc] init]; + [supportedExternalLibraries addObject:@"dav1d"]; + [supportedExternalLibraries addObject:@"fontconfig"]; + [supportedExternalLibraries addObject:@"freetype"]; + [supportedExternalLibraries addObject:@"fribidi"]; + [supportedExternalLibraries addObject:@"gmp"]; + [supportedExternalLibraries addObject:@"gnutls"]; + [supportedExternalLibraries addObject:@"kvazaar"]; + [supportedExternalLibraries addObject:@"mp3lame"]; + [supportedExternalLibraries addObject:@"libaom"]; + [supportedExternalLibraries addObject:@"libass"]; + [supportedExternalLibraries addObject:@"iconv"]; + [supportedExternalLibraries addObject:@"libilbc"]; + [supportedExternalLibraries addObject:@"libtheora"]; + [supportedExternalLibraries addObject:@"libvidstab"]; + [supportedExternalLibraries addObject:@"libvorbis"]; + [supportedExternalLibraries addObject:@"libvpx"]; + [supportedExternalLibraries addObject:@"libwebp"]; + [supportedExternalLibraries addObject:@"libxml2"]; + [supportedExternalLibraries addObject:@"opencore-amr"]; + [supportedExternalLibraries addObject:@"openh264"]; + [supportedExternalLibraries addObject:@"opus"]; + [supportedExternalLibraries addObject:@"rubberband"]; + [supportedExternalLibraries addObject:@"sdl2"]; + [supportedExternalLibraries addObject:@"shine"]; + [supportedExternalLibraries addObject:@"snappy"]; + [supportedExternalLibraries addObject:@"soxr"]; + [supportedExternalLibraries addObject:@"speex"]; + [supportedExternalLibraries addObject:@"tesseract"]; + [supportedExternalLibraries addObject:@"twolame"]; + [supportedExternalLibraries addObject:@"x264"]; + [supportedExternalLibraries addObject:@"x265"]; + [supportedExternalLibraries addObject:@"xvid"]; +} + ++ (NSString*)getBuildConf { + return [NSString stringWithUTF8String:FFMPEG_CONFIGURATION]; +} + ++ (NSString*)getPackageName { + NSArray *enabledLibraryArray = [Packages getExternalLibraries]; + Boolean speex = [enabledLibraryArray containsObject:@"speex"]; + Boolean fribidi = [enabledLibraryArray containsObject:@"fribidi"]; + Boolean gnutls = [enabledLibraryArray containsObject:@"gnutls"]; + Boolean xvid = [enabledLibraryArray containsObject:@"xvid"]; + + Boolean min = false; + Boolean minGpl = false; + Boolean https = false; + Boolean httpsGpl = false; + Boolean audio = false; + Boolean video = false; + Boolean full = false; + Boolean fullGpl = false; + + if (speex && fribidi) { + if (xvid) { + fullGpl = true; + } else { + full = true; + } + } else if (speex) { + audio = true; + } else if (fribidi) { + video = true; + } else if (xvid) { + if (gnutls) { + httpsGpl = true; + } else { + minGpl = true; + } + } else { + if (gnutls) { + https = true; + } else { + min = true; + } + } + + if (fullGpl) { + if ([enabledLibraryArray containsObject:@"dav1d"] && + [enabledLibraryArray containsObject:@"fontconfig"] && + [enabledLibraryArray containsObject:@"freetype"] && + [enabledLibraryArray containsObject:@"fribidi"] && + [enabledLibraryArray containsObject:@"gmp"] && + [enabledLibraryArray containsObject:@"gnutls"] && + [enabledLibraryArray containsObject:@"kvazaar"] && + [enabledLibraryArray containsObject:@"mp3lame"] && + [enabledLibraryArray containsObject:@"libass"] && + [enabledLibraryArray containsObject:@"iconv"] && + [enabledLibraryArray containsObject:@"libilbc"] && + [enabledLibraryArray containsObject:@"libtheora"] && + [enabledLibraryArray containsObject:@"libvidstab"] && + [enabledLibraryArray containsObject:@"libvorbis"] && + [enabledLibraryArray containsObject:@"libvpx"] && + [enabledLibraryArray containsObject:@"libwebp"] && + [enabledLibraryArray containsObject:@"libxml2"] && + [enabledLibraryArray containsObject:@"opencore-amr"] && + [enabledLibraryArray containsObject:@"opus"] && + [enabledLibraryArray containsObject:@"shine"] && + [enabledLibraryArray containsObject:@"snappy"] && + [enabledLibraryArray containsObject:@"soxr"] && + [enabledLibraryArray containsObject:@"speex"] && + [enabledLibraryArray containsObject:@"twolame"] && + [enabledLibraryArray containsObject:@"x264"] && + [enabledLibraryArray containsObject:@"x265"] && + [enabledLibraryArray containsObject:@"xvid"]) { + return @"full-gpl"; + } else { + return @"custom"; + } + } + + if (full) { + if ([enabledLibraryArray containsObject:@"dav1d"] && + [enabledLibraryArray containsObject:@"fontconfig"] && + [enabledLibraryArray containsObject:@"freetype"] && + [enabledLibraryArray containsObject:@"fribidi"] && + [enabledLibraryArray containsObject:@"gmp"] && + [enabledLibraryArray containsObject:@"gnutls"] && + [enabledLibraryArray containsObject:@"kvazaar"] && + [enabledLibraryArray containsObject:@"mp3lame"] && + [enabledLibraryArray containsObject:@"libass"] && + [enabledLibraryArray containsObject:@"iconv"] && + [enabledLibraryArray containsObject:@"libilbc"] && + [enabledLibraryArray containsObject:@"libtheora"] && + [enabledLibraryArray containsObject:@"libvorbis"] && + [enabledLibraryArray containsObject:@"libvpx"] && + [enabledLibraryArray containsObject:@"libwebp"] && + [enabledLibraryArray containsObject:@"libxml2"] && + [enabledLibraryArray containsObject:@"opencore-amr"] && + [enabledLibraryArray containsObject:@"opus"] && + [enabledLibraryArray containsObject:@"shine"] && + [enabledLibraryArray containsObject:@"snappy"] && + [enabledLibraryArray containsObject:@"soxr"] && + [enabledLibraryArray containsObject:@"speex"] && + [enabledLibraryArray containsObject:@"twolame"]) { + return @"full"; + } else { + return @"custom"; + } + } + + if (video) { + if ([enabledLibraryArray containsObject:@"dav1d"] && + [enabledLibraryArray containsObject:@"fontconfig"] && + [enabledLibraryArray containsObject:@"freetype"] && + [enabledLibraryArray containsObject:@"fribidi"] && + [enabledLibraryArray containsObject:@"kvazaar"] && + [enabledLibraryArray containsObject:@"libass"] && + [enabledLibraryArray containsObject:@"iconv"] && + [enabledLibraryArray containsObject:@"libtheora"] && + [enabledLibraryArray containsObject:@"libvpx"] && + [enabledLibraryArray containsObject:@"libwebp"] && + [enabledLibraryArray containsObject:@"snappy"]) { + return @"video"; + } else { + return @"custom"; + } + } + + if (audio) { + if ([enabledLibraryArray containsObject:@"mp3lame"] && + [enabledLibraryArray containsObject:@"libilbc"] && + [enabledLibraryArray containsObject:@"libvorbis"] && + [enabledLibraryArray containsObject:@"opencore-amr"] && + [enabledLibraryArray containsObject:@"opus"] && + [enabledLibraryArray containsObject:@"shine"] && + [enabledLibraryArray containsObject:@"soxr"] && + [enabledLibraryArray containsObject:@"speex"] && + [enabledLibraryArray containsObject:@"twolame"]) { + return @"audio"; + } else { + return @"custom"; + } + } + + if (httpsGpl) { + if ([enabledLibraryArray containsObject:@"gmp"] && + [enabledLibraryArray containsObject:@"gnutls"] && + [enabledLibraryArray containsObject:@"libvidstab"] && + [enabledLibraryArray containsObject:@"x264"] && + [enabledLibraryArray containsObject:@"x265"] && + [enabledLibraryArray containsObject:@"xvid"]) { + return @"https-gpl"; + } else { + return @"custom"; + } + } + + if (https) { + if ([enabledLibraryArray containsObject:@"gmp"] && + [enabledLibraryArray containsObject:@"gnutls"]) { + return @"https"; + } else { + return @"custom"; + } + } + + if (minGpl) { + if ([enabledLibraryArray containsObject:@"libvidstab"] && + [enabledLibraryArray containsObject:@"x264"] && + [enabledLibraryArray containsObject:@"x265"] && + [enabledLibraryArray containsObject:@"xvid"]) { + return @"min-gpl"; + } else { + return @"custom"; + } + } + + return @"min"; +} + ++ (NSArray*)getExternalLibraries { + NSString *buildConfiguration = [Packages getBuildConf]; + NSMutableArray *enabledLibraryArray = [[NSMutableArray alloc] init]; + + for (int i=0; i < [supportedExternalLibraries count]; i++) { + NSString *supportedExternalLibrary = [supportedExternalLibraries objectAtIndex:i]; + + NSString *libraryName1 = [NSString stringWithFormat:@"enable-%@", supportedExternalLibrary]; + NSString *libraryName2 = [NSString stringWithFormat:@"enable-lib%@", supportedExternalLibrary]; + + if ([buildConfiguration rangeOfString:libraryName1].location != NSNotFound || [buildConfiguration rangeOfString:libraryName2].location != NSNotFound) { + [enabledLibraryArray addObject:supportedExternalLibrary]; + } + } + + [enabledLibraryArray sortUsingSelector:@selector(compare:)]; + + return enabledLibraryArray; +} + +@end diff --git a/apple/src/ReturnCode.h b/apple/src/ReturnCode.h new file mode 100644 index 0000000..76fba7c --- /dev/null +++ b/apple/src/ReturnCode.h @@ -0,0 +1,44 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#ifndef FFMPEG_KIT_RETURN_CODE_H +#define FFMPEG_KIT_RETURN_CODE_H + +#import + +typedef NS_ENUM(NSUInteger, ReturnCodeEnum) { + ReturnCodeSuccess = 0, + ReturnCodeCancel = 255 +}; + +@interface ReturnCode : NSObject + +- (instancetype)init:(int)value; + +- (int)getValue; + +- (BOOL)isSuccess; + +- (BOOL)isError; + +- (BOOL)isCancel; + +@end + +#endif // FFMPEG_KIT_RETURN_CODE_H diff --git a/apple/src/ReturnCode.m b/apple/src/ReturnCode.m new file mode 100644 index 0000000..3253007 --- /dev/null +++ b/apple/src/ReturnCode.m @@ -0,0 +1,51 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#import "ReturnCode.h" + +@implementation ReturnCode { + int _value; +} + +- (instancetype)init:(int)value { + self = [super init]; + if (self) { + _value = value; + } + + return self; +} + +- (int)getValue { + return _value; +} + +- (BOOL)isSuccess { + return (_value == ReturnCodeSuccess); +} + +- (BOOL)isError { + return ((_value != ReturnCodeSuccess) && (_value != ReturnCodeCancel)); +} + +- (BOOL)isCancel { + return (_value == ReturnCodeCancel); +} + +@end diff --git a/apple/src/Session.h b/apple/src/Session.h new file mode 100644 index 0000000..eb6ad79 --- /dev/null +++ b/apple/src/Session.h @@ -0,0 +1,255 @@ +/* + * 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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#ifndef FFMPEG_KIT_SESSION_H +#define FFMPEG_KIT_SESSION_H + +#import +#import "ExecuteDelegate.h" +#import "Log.h" +#import "LogDelegate.h" +#import "LogRedirectionStrategy.h" +#import "ReturnCode.h" +#import "SessionState.h" + +@protocol ExecuteDelegate; + +/** + *

Common interface for all FFmpegKit sessions. + */ +@protocol Session + +@required + +/** + * Returns the session specific execute delegate. + * + * @return session specific execute delegate + */ +- (id)getExecuteDelegate; + +/** + * Returns the session specific log delegate. + * + * @return session specific log delegate + */ +- (id)getLogDelegate; + +/** + * Returns the session identifier. + * + * @return session identifier + */ +- (long)getSessionId; + +/** + * Returns session create time. + * + * @return session create time + */ +- (NSDate*)getCreateTime; + +/** + * Returns session start time. + * + * @return session start time + */ +- (NSDate*)getStartTime; + +/** + * Returns session end time. + * + * @return session end time + */ +- (NSDate*)getEndTime; + +/** + * Returns the time taken to execute this session. + * + * @return time taken to execute this session in milliseconds or zero (0) if the session is + * not over yet + */ +- (long)getDuration; + +/** + * Returns command arguments as an array. + * + * @return command arguments as an array + */ +- (NSArray*)getArguments; + +/** + * Returns command arguments as a concatenated string. + * + * @return command arguments as a concatenated string + */ +- (NSString*)getCommand; + +/** + * Returns all log entries generated for this session. If there are asynchronous + * messages that are not delivered yet, this method waits for them until the given timeout. + * + * @param waitTimeout wait timeout for asynchronous messages in milliseconds + * @return list of log entries generated for this session + */ +- (NSArray*)getAllLogsWithTimeout:(int)waitTimeout; + +/** + * Returns all log entries generated for this session. If there are asynchronous + * messages that are not delivered yet, this method waits for them. + * + * @return list of log entries generated for this session + */ +- (NSArray*)getAllLogs; + +/** + * Returns all log entries delivered for this session. Note that if there are asynchronous + * messages that are not delivered yet, this method will not wait for them and will return + * immediately. + * + * @return list of log entries received for this session + */ +- (NSArray*)getLogs; + +/** + * Returns all log entries generated for this session as a concatenated string. If there are + * asynchronous messages that are not delivered yet, this method waits for them until + * the given timeout. + * + * @param waitTimeout wait timeout for asynchronous messages in milliseconds + * @return all log entries generated for this session as a concatenated string + */ +- (NSString*)getAllLogsAsStringWithTimeout:(int)waitTimeout; + +/** + * Returns all log entries generated for this session as a concatenated string. If there are + * asynchronous messages that are not delivered yet, this method waits for them. + * + * @return all log entries generated for this session as a concatenated string + */ +- (NSString*)getAllLogsAsString; + +/** + * Returns all log entries delivered for this session as a concatenated string. Note that if + * there are asynchronous messages that are not delivered yet, this method will not wait + * for them and will return immediately. + * + * @return list of log entries received for this session + */ +- (NSString*)getLogsAsString; + +/** + * Returns the log output generated while running the session. + * + * @return log output generated + */ +- (NSString*)getOutput; + +/** + * Returns the state of the session. + * + * @return state of the session + */ +- (SessionState)getState; + +/** + * Returns the return code for this session. Note that return code is only set for sessions + * that end with SessionStateCompleted state. If a session is not started, still running or failed then + * this method returns nil. + * + * @return the return code for this session if the session is completed, nil if session is + * not started, still running or failed + */ +- (ReturnCode*)getReturnCode; + +/** + * Returns the stack trace of the exception received while executing this session. + *

+ * The stack trace is only set for sessions that end with SessionStateFailed state. For sessions that has + * SessionStateCompleted state this method returns nil. + * + * @return stack trace of the exception received while executing this session, nil if session + * is not started, still running or completed + */ +- (NSString*)getFailStackTrace; + +/** + * Returns session specific log redirection strategy. + * + * @return session specific log redirection strategy + */ +- (LogRedirectionStrategy)getLogRedirectionStrategy; + +/** + * Returns whether there are still asynchronous messages being transmitted for this + * session or not. + * + * @return true if there are still asynchronous messages being transmitted, false + * otherwise + */ +- (BOOL)thereAreAsynchronousMessagesInTransmit; + +/** + * Adds a new log entry for this session. + * + * @param log log entry + */ +- (void)addLog:(Log*)log; + +/** + * Starts running the session. + */ +- (void)startRunning; + +/** + * Completes running the session with the provided return code. + * + * @param returnCode return code of the execution + */ +- (void)complete:(ReturnCode*)returnCode; + +/** + * Ends running the session with a failure. + * + * @param exception execution received + */ +- (void)fail:(NSException*)exception; + +/** + * Returns whether it is an FFmpeg session or not. + * + * @return true if it is an FFmpeg session, false otherwise + */ +- (BOOL)isFFmpeg; + +/** + * Returns whether it is an FFprobe session or not. + * + * @return true if it is an FFprobe session, false otherwise + */ +- (BOOL)isFFprobe; + +/** + * Cancels running the session. + */ +- (void)cancel; + +@end + +#endif // FFMPEG_KIT_SESSION_H diff --git a/apple/src/SessionState.h b/apple/src/SessionState.h new file mode 100644 index 0000000..46eec4d --- /dev/null +++ b/apple/src/SessionState.h @@ -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 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 License for more details. + * + * You should have received a copy of the GNU Lesser General License + * along with FFmpegKit. If not, see . + */ + +#ifndef FFMPEG_KIT_SESSION_STATE_H +#define FFMPEG_KIT_SESSION_STATE_H + +typedef NS_ENUM(NSUInteger, SessionState) { + SessionStateCreated, + SessionStateRunning, + SessionStateFailed, + SessionStateCompleted +}; + +#endif // FFMPEG_KIT_SESSION_STATE_H diff --git a/apple/src/Statistics.h b/apple/src/Statistics.h index 5fab2af..3b4f786 100644 --- a/apple/src/Statistics.h +++ b/apple/src/Statistics.h @@ -17,20 +17,19 @@ * along with FFmpegKit. If not, see . */ -#include +#ifndef FFMPEG_KIT_STATISTICS_H +#define FFMPEG_KIT_STATISTICS_H + +#import /** - * Statistics for running executions. + * Statistics entry for an FFmpeg execute session. */ @interface Statistics : NSObject -- (instancetype)init; - -- (instancetype)initWithId:(long)currentExecutionId videoFrameNumber:(int)newVideoFrameNumber fps:(float)newVideoFps quality:(float)newVideoQuality size:(int64_t)newSize time:(int)newTime bitrate:(double)newBitrate speed:(double)newSpeed; +- (instancetype)init:(long)sessionId videoFrameNumber:(int)videoFrameNumber videoFps:(float)videoFps videoQuality:(float)videoQuality size:(int64_t)size time:(int)time bitrate:(double)bitrate speed:(double)speed; -- (void)update:(Statistics*)statistics; - -- (long)getExecutionId; +- (long)getSessionId; - (int)getVideoFrameNumber; @@ -47,3 +46,5 @@ - (double)getSpeed; @end + +#endif // FFMPEG_KIT_STATISTICS_H diff --git a/apple/src/Statistics.m b/apple/src/Statistics.m index 87b68e7..4016ab9 100644 --- a/apple/src/Statistics.m +++ b/apple/src/Statistics.m @@ -17,108 +17,65 @@ * along with FFmpegKit. If not, see . */ -#include "Statistics.h" +#import "Statistics.h" @implementation Statistics { - long executionId; - int videoFrameNumber; - float videoFps; - float videoQuality; - long size; - int time; - double bitrate; - double speed; + long _sessionId; + int _videoFrameNumber; + float _videoFps; + float _videoQuality; + long _size; + int _time; + double _bitrate; + double _speed; } -- (instancetype)init { +- (instancetype)init:(long)sessionId videoFrameNumber:(int)videoFrameNumber videoFps:(float)videoFps videoQuality:(float)videoQuality size:(int64_t)size time:(int)time bitrate:(double)bitrate speed:(double)speed { self = [super init]; if (self) { - executionId = 0; - videoFrameNumber = 0; - videoFps = 0; - videoQuality = 0; - size = 0; - time = 0; - bitrate = 0; - speed = 0; + _sessionId = sessionId; + _videoFrameNumber = videoFrameNumber; + _videoFps = videoFps; + _videoQuality = videoQuality; + _size = size; + _time = time; + _bitrate = bitrate; + _speed = speed; } return self; } -- (instancetype)initWithId:(long)currentExecutionId videoFrameNumber:(int)newVideoFrameNumber fps:(float)newVideoFps quality:(float)newVideoQuality size:(int64_t)newSize time:(int)newTime bitrate:(double)newBitrate speed:(double)newSpeed { - self = [super init]; - if (self) { - executionId = currentExecutionId; - videoFrameNumber = newVideoFrameNumber; - videoFps = newVideoFps; - videoQuality = newVideoQuality; - size = newSize; - time = newTime; - bitrate = newBitrate; - speed = newSpeed; - } - - return self; -} - -- (void)update:(Statistics*)statistics { - if (statistics != nil) { - executionId = [statistics getExecutionId]; - if ([statistics getVideoFrameNumber] > 0) { - videoFrameNumber = [statistics getVideoFrameNumber]; - } - if ([statistics getVideoFps] > 0) { - videoFps = [statistics getVideoFps]; - } - if ([statistics getVideoQuality] > 0) { - videoQuality = [statistics getVideoQuality]; - } - if ([statistics getSize] > 0) { - size = [statistics getSize]; - } - if ([statistics getTime] > 0) { - time = [statistics getTime]; - } - if ([statistics getBitrate] > 0) { - bitrate = [statistics getBitrate]; - } - if ([statistics getSpeed] > 0) { - speed = [statistics getSpeed]; - } - } -} - -- (long)getExecutionId { - return executionId; +- (long)getSessionId { + return _sessionId; } - (int)getVideoFrameNumber { - return videoFrameNumber; + return _videoFrameNumber; } - (float)getVideoFps { - return videoFps; + return _videoFps; } - (float)getVideoQuality { - return videoQuality; + return _videoQuality; } - (long)getSize { - return size; + return _size; } - (int)getTime { - return time; + return _time; } - (double)getBitrate { - return bitrate; + return _bitrate; } - (double)getSpeed { - return speed; + return _speed; } -@end \ No newline at end of file +@end diff --git a/apple/src/StatisticsDelegate.h b/apple/src/StatisticsDelegate.h index b366f05..b0c5556 100644 --- a/apple/src/StatisticsDelegate.h +++ b/apple/src/StatisticsDelegate.h @@ -17,12 +17,25 @@ * along with FFmpegKit. If not, see . */ -#include "Statistics.h" +#ifndef FFMPEG_KIT_STATISTICS_DELEGATE_H +#define FFMPEG_KIT_STATISTICS_DELEGATE_H + +#import +#import "Statistics.h" /** - * Use this delegate to receive statistics from running executions. + *

Delegate that receives statistics generated for FFmpegKit sessions. */ @protocol StatisticsDelegate @required + +/** + *

Called when a statistics entry is received. + * + * @param statistics statistics entry + */ - (void)statisticsCallback:(Statistics*)statistics; + @end + +#endif // FFMPEG_KIT_STATISTICS_DELEGATE_H diff --git a/apple/src/StreamInformation.h b/apple/src/StreamInformation.h index 59657f1..a5c213c 100644 --- a/apple/src/StreamInformation.h +++ b/apple/src/StreamInformation.h @@ -17,7 +17,29 @@ * along with FFmpegKit. If not, see . */ -#include +#ifndef FFMPEG_KIT_STREAM_INFORMATION_H +#define FFMPEG_KIT_STREAM_INFORMATION_H + +#import + +extern NSString* const StreamKeyIndex; +extern NSString* const StreamKeyType; +extern NSString* const StreamKeyCodec; +extern NSString* const StreamKeyCodecLong; +extern NSString* const StreamKeyFormat; +extern NSString* const StreamKeyWidth; +extern NSString* const StreamKeyHeight; +extern NSString* const StreamKeyBitRate; +extern NSString* const StreamKeySampleRate; +extern NSString* const StreamKeySampleFormat; +extern NSString* const StreamKeyChannelLayout; +extern NSString* const StreamKeySampleAspectRatio; +extern NSString* const StreamKeyDisplayAspectRatio; +extern NSString* const StreamKeyAverageFrameRate; +extern NSString* const StreamKeyRealFrameRate; +extern NSString* const StreamKeyTimeBase; +extern NSString* const StreamKeyCodecTimeBase; +extern NSString* const StreamKeyTags; /** * Stream information class. @@ -181,3 +203,5 @@ - (NSDictionary*)getAllProperties; @end + +#endif // FFMPEG_KIT_STREAM_INFORMATION_H diff --git a/apple/src/StreamInformation.m b/apple/src/StreamInformation.m index 861d1e7..ffaec6b 100644 --- a/apple/src/StreamInformation.m +++ b/apple/src/StreamInformation.m @@ -17,26 +17,26 @@ * along with FFmpegKit. If not, see . */ -#include "StreamInformation.h" - -#define KEY_INDEX @"index" -#define KEY_TYPE @"codec_type" -#define KEY_CODEC @"codec_name" -#define KEY_CODEC_LONG @"codec_long_name" -#define KEY_FORMAT @"pix_fmt" -#define KEY_WIDTH @"width" -#define KEY_HEIGHT @"height" -#define KEY_BIT_RATE @"bit_rate" -#define KEY_SAMPLE_RATE @"sample_rate" -#define KEY_SAMPLE_FORMAT @"sample_fmt" -#define KEY_CHANNEL_LAYOUT @"channel_layout" -#define KEY_SAMPLE_ASPECT_RATIO @"sample_aspect_ratio" -#define KEY_DISPLAY_ASPECT_RATIO @"display_aspect_ratio" -#define KEY_AVERAGE_FRAME_RATE @"avg_frame_rate" -#define KEY_REAL_FRAME_RATE @"r_frame_rate" -#define KEY_TIME_BASE @"time_base" -#define KEY_CODEC_TIME_BASE @"codec_time_base" -#define KEY_TAGS @"tags" +#import "StreamInformation.h" + +NSString* const StreamKeyIndex = @"index"; +NSString* const StreamKeyType = @"codec_type"; +NSString* const StreamKeyCodec = @"codec_name"; +NSString* const StreamKeyCodecLong = @"codec_long_name"; +NSString* const StreamKeyFormat = @"pix_fmt"; +NSString* const StreamKeyWidth = @"width"; +NSString* const StreamKeyHeight = @"height"; +NSString* const StreamKeyBitRate = @"bit_rate"; +NSString* const StreamKeySampleRate = @"sample_rate"; +NSString* const StreamKeySampleFormat = @"sample_fmt"; +NSString* const StreamKeyChannelLayout = @"channel_layout"; +NSString* const StreamKeySampleAspectRatio = @"sample_aspect_ratio"; +NSString* const StreamKeyDisplayAspectRatio = @"display_aspect_ratio"; +NSString* const StreamKeyAverageFrameRate = @"avg_frame_rate"; +NSString* const StreamKeyRealFrameRate = @"r_frame_rate"; +NSString* const StreamKeyTimeBase = @"time_base"; +NSString* const StreamKeyCodecTimeBase = @"codec_time_base"; +NSString* const StreamKeyTags = @"tags"; @implementation StreamInformation { @@ -57,75 +57,75 @@ } - (NSNumber*)getIndex { - return [self getNumberProperty:KEY_INDEX]; + return [self getNumberProperty:StreamKeyIndex]; } - (NSString*)getType { - return [self getStringProperty:KEY_TYPE]; + return [self getStringProperty:StreamKeyType]; } - (NSString*)getCodec { - return [self getStringProperty:KEY_CODEC]; + return [self getStringProperty:StreamKeyCodec]; } - (NSString*)getFullCodec { - return [self getStringProperty:KEY_CODEC_LONG]; + return [self getStringProperty:StreamKeyCodecLong]; } - (NSString*)getFormat { - return [self getStringProperty:KEY_FORMAT]; + return [self getStringProperty:StreamKeyFormat]; } - (NSNumber*)getWidth { - return [self getNumberProperty:KEY_WIDTH]; + return [self getNumberProperty:StreamKeyWidth]; } - (NSNumber*)getHeight { - return [self getNumberProperty:KEY_HEIGHT]; + return [self getNumberProperty:StreamKeyHeight]; } - (NSString*)getBitrate { - return [self getStringProperty:KEY_BIT_RATE]; + return [self getStringProperty:StreamKeyBitRate]; } - (NSString*)getSampleRate { - return [self getStringProperty:KEY_SAMPLE_RATE]; + return [self getStringProperty:StreamKeySampleRate]; } - (NSString*)getSampleFormat { - return [self getStringProperty:KEY_SAMPLE_FORMAT]; + return [self getStringProperty:StreamKeySampleFormat]; } - (NSString*)getChannelLayout { - return [self getStringProperty:KEY_CHANNEL_LAYOUT]; + return [self getStringProperty:StreamKeyChannelLayout]; } - (NSString*)getSampleAspectRatio { - return [self getStringProperty:KEY_SAMPLE_ASPECT_RATIO]; + return [self getStringProperty:StreamKeySampleAspectRatio]; } - (NSString*)getDisplayAspectRatio { - return [self getStringProperty:KEY_DISPLAY_ASPECT_RATIO]; + return [self getStringProperty:StreamKeyDisplayAspectRatio]; } - (NSString*)getAverageFrameRate { - return [self getStringProperty:KEY_AVERAGE_FRAME_RATE]; + return [self getStringProperty:StreamKeyAverageFrameRate]; } - (NSString*)getRealFrameRate { - return [self getStringProperty:KEY_REAL_FRAME_RATE]; + return [self getStringProperty:StreamKeyRealFrameRate]; } - (NSString*)getTimeBase { - return [self getStringProperty:KEY_TIME_BASE]; + return [self getStringProperty:StreamKeyTimeBase]; } - (NSString*)getCodecTimeBase { - return [self getStringProperty:KEY_CODEC_TIME_BASE]; + return [self getStringProperty:StreamKeyCodecTimeBase]; } - (NSDictionary*)getTags { - return [self getProperties:KEY_TAGS]; + return [self getProperties:StreamKeyTags]; } - (NSString*)getStringProperty:(NSString*)key { diff --git a/apple/src/fftools_ffmpeg.c b/apple/src/fftools_ffmpeg.c index 2d2ca9f..ae221ae 100644 --- a/apple/src/fftools_ffmpeg.c +++ b/apple/src/fftools_ffmpeg.c @@ -257,9 +257,9 @@ extern volatile int handleSIGTERM; extern volatile int handleSIGXCPU; extern volatile int handleSIGPIPE; -extern __thread volatile long executionId; -extern int cancelRequested(long executionId); -extern void removeExecution(long executionId); +extern __thread volatile long _sessionId; +extern void cancelSession(long sessionId); +extern int cancelRequested(long sessionId); /* sub2video hack: Convert subtitles to video with alpha to insert them in filter graphs. @@ -768,7 +768,7 @@ static void ffmpeg_cleanup(int ret) if (received_sigterm) { av_log(NULL, AV_LOG_INFO, "Exiting normally, received signal %d.\n", (int) received_sigterm); - } else if (cancelRequested(executionId)) { + } else if (cancelRequested(_sessionId)) { av_log(NULL, AV_LOG_INFO, "Exiting normally, received cancel request.\n"); } else if (ret && atomic_load(&transcode_init_done)) { av_log(NULL, AV_LOG_INFO, "Conversion failed!\n"); @@ -2431,7 +2431,7 @@ static int ifilter_send_eof(InputFilter *ifilter, int64_t pts) if (ifilter->filter) { /* THIS VALIDATION IS REQUIRED TO COMPLETE CANCELLATION */ - if (!received_sigterm && !cancelRequested(executionId)) { + if (!received_sigterm && !cancelRequested(_sessionId)) { ret = av_buffersrc_close(ifilter->filter, pts, AV_BUFFERSRC_FLAG_PUSH); } if (ret < 0) @@ -4934,7 +4934,7 @@ static int transcode(void) goto fail; #endif - while (!received_sigterm && !cancelRequested(executionId)) { + while (!received_sigterm && !cancelRequested(_sessionId)) { int64_t cur_time= av_gettime_relative(); /* if 'q' pressed, exits */ @@ -5148,7 +5148,7 @@ void cancel_operation(long id) if (id == 0) { sigterm_handler(SIGINT); } else { - removeExecution(id); + cancelSession(id); } } @@ -5672,10 +5672,10 @@ int ffmpeg_execute(int argc, char **argv) if ((decode_error_stat[0] + decode_error_stat[1]) * max_error_rate < decode_error_stat[1]) exit_program(69); - exit_program((received_nb_signals || cancelRequested(executionId))? 255 : main_ffmpeg_return_code); + exit_program((received_nb_signals || cancelRequested(_sessionId))? 255 : main_ffmpeg_return_code); } else { - main_ffmpeg_return_code = (received_nb_signals || cancelRequested(executionId)) ? 255 : longjmp_value; + main_ffmpeg_return_code = (received_nb_signals || cancelRequested(_sessionId)) ? 255 : longjmp_value; } return main_ffmpeg_return_code; diff --git a/ios.sh b/ios.sh index dc35341..89a186c 100755 --- a/ios.sh +++ b/ios.sh @@ -22,14 +22,14 @@ enable_default_ios_architectures enable_main_build # SELECT XCODE VERSION USED FOR BUILDING -XCODE_FOR_FFMPEG_KIT=$(ls ~/.xcode.for.ffmpeg.kit.sh) +XCODE_FOR_FFMPEG_KIT=$(ls ~/.xcode.for.ffmpeg.kit.sh 2>>"${BASEDIR}"/build.log) if [[ -f ${XCODE_FOR_FFMPEG_KIT} ]]; then source "${XCODE_FOR_FFMPEG_KIT}" 1>>"${BASEDIR}"/build.log 2>&1 fi # DETECT IOS SDK VERSION DETECTED_IOS_SDK_VERSION="$(xcrun --sdk iphoneos --show-sdk-version)" -echo -e "INFO: Using SDK ${DETECTED_IOS_SDK_VERSION} by Xcode provided at $(xcode-select -p)\n" 1>>"${BASEDIR}"/build.log 2>&1 +echo -e "\nINFO: Using SDK ${DETECTED_IOS_SDK_VERSION} by Xcode provided at $(xcode-select -p)\n" 1>>"${BASEDIR}"/build.log 2>&1 echo -e "INFO: Build options: $*\n" 1>>"${BASEDIR}"/build.log 2>&1 # SET DEFAULT BUILD OPTIONS diff --git a/macos.sh b/macos.sh index 058927f..564c6d3 100755 --- a/macos.sh +++ b/macos.sh @@ -22,14 +22,14 @@ enable_default_macos_architectures enable_main_build # SELECT XCODE VERSION USED FOR BUILDING -XCODE_FOR_FFMPEG_KIT=$(ls ~/.xcode.for.ffmpeg.kit.sh) +XCODE_FOR_FFMPEG_KIT=$(ls ~/.xcode.for.ffmpeg.kit.sh 2>>"${BASEDIR}"/build.log) if [[ -f ${XCODE_FOR_FFMPEG_KIT} ]]; then source "${XCODE_FOR_FFMPEG_KIT}" 1>>"${BASEDIR}"/build.log 2>&1 fi # DETECT MACOS SDK VERSION DETECTED_MACOS_SDK_VERSION="$(xcrun --sdk macosx --show-sdk-version)" -echo -e "INFO: Using SDK ${DETECTED_MACOS_SDK_VERSION} by Xcode provided at $(xcode-select -p)\n" 1>>"${BASEDIR}"/build.log 2>&1 +echo -e "\nINFO: Using SDK ${DETECTED_MACOS_SDK_VERSION} by Xcode provided at $(xcode-select -p)\n" 1>>"${BASEDIR}"/build.log 2>&1 echo -e "\nINFO: Build options: $*\n" 1>>"${BASEDIR}"/build.log 2>&1 # SET DEFAULT BUILD OPTIONS diff --git a/tvos.sh b/tvos.sh index 7d920ea..f30d792 100755 --- a/tvos.sh +++ b/tvos.sh @@ -22,14 +22,14 @@ enable_default_tvos_architectures enable_main_build # SELECT XCODE VERSION USED FOR BUILDING -XCODE_FOR_FFMPEG_KIT=$(ls ~/.xcode.for.ffmpeg.kit.sh) +XCODE_FOR_FFMPEG_KIT=$(ls ~/.xcode.for.ffmpeg.kit.sh 2>>"${BASEDIR}"/build.log) if [[ -f ${XCODE_FOR_FFMPEG_KIT} ]]; then source "${XCODE_FOR_FFMPEG_KIT}" 1>>"${BASEDIR}"/build.log 2>&1 fi # DETECT TVOS SDK VERSION DETECTED_TVOS_SDK_VERSION="$(xcrun --sdk appletvos --show-sdk-version)" -echo -e "INFO: Using SDK ${DETECTED_TVOS_SDK_VERSION} by Xcode provided at $(xcode-select -p)\n" 1>>"${BASEDIR}"/build.log 2>&1 +echo -e "\nINFO: Using SDK ${DETECTED_TVOS_SDK_VERSION} by Xcode provided at $(xcode-select -p)\n" 1>>"${BASEDIR}"/build.log 2>&1 echo -e "\nINFO: Build options: $*\n" 1>>"${BASEDIR}"/build.log 2>&1 # SET DEFAULT BUILD OPTIONS