update android api, fixes #1
This commit is contained in:
parent
18f6dd0099
commit
a1e7a0b9da
|
@ -39,6 +39,7 @@ task javadoc(type: Javadoc) {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.arthenica:smart-exception-java:0.1.0'
|
||||
testImplementation "androidx.test.ext:junit:1.1.2"
|
||||
testImplementation "org.json:json:20190722"
|
||||
}
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
<manifest package="com.arthenica.ffmpegkit">
|
||||
</manifest>
|
||||
<manifest package="com.arthenica.ffmpegkit" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -31,7 +31,7 @@
|
|||
/** Callback data structure */
|
||||
struct CallbackData {
|
||||
int type; // 1 (log callback) or 2 (statistics callback)
|
||||
long executionId; // execution id
|
||||
long sessionId; // session identifier
|
||||
|
||||
int logLevel; // log level
|
||||
AVBPrint logData; // log data
|
||||
|
@ -47,20 +47,16 @@ struct CallbackData {
|
|||
struct CallbackData *next;
|
||||
};
|
||||
|
||||
/** Execution map variables */
|
||||
const int EXECUTION_MAP_SIZE = 1000;
|
||||
static volatile int executionMap[EXECUTION_MAP_SIZE];
|
||||
static pthread_mutex_t executionMapMutex;
|
||||
/** Session map variables */
|
||||
const int SESSION_MAP_SIZE = 1000;
|
||||
static volatile int sessionMap[SESSION_MAP_SIZE];
|
||||
static pthread_mutex_t sessionMapMutex;
|
||||
|
||||
/** Redirection control variables */
|
||||
static pthread_mutex_t lockMutex;
|
||||
static pthread_mutex_t monitorMutex;
|
||||
static pthread_cond_t monitorCondition;
|
||||
|
||||
/** Last command output variables */
|
||||
static pthread_mutex_t logMutex;
|
||||
static AVBPrint lastCommandOutput;
|
||||
|
||||
pthread_t callbackThread;
|
||||
int redirectionEnabled;
|
||||
|
||||
|
@ -79,6 +75,9 @@ static jmethodID logMethod;
|
|||
/** Global reference of statistics redirection method in Java */
|
||||
static jmethodID statisticsMethod;
|
||||
|
||||
/** Global reference of closeParcelFileDescriptor method in Java */
|
||||
static jmethodID closeParcelFileDescriptorMethod;
|
||||
|
||||
/** Global reference of String class in Java */
|
||||
static jclass stringClass;
|
||||
|
||||
|
@ -86,7 +85,7 @@ static jclass stringClass;
|
|||
static jmethodID stringConstructor;
|
||||
|
||||
/** Full name of the Config class */
|
||||
const char *configClassName = "com/arthenica/ffmpegkit/Config";
|
||||
const char *configClassName = "com/arthenica/ffmpegkit/FFmpegKitConfig";
|
||||
|
||||
/** Full name of String class */
|
||||
const char *stringClassName = "java/lang/String";
|
||||
|
@ -98,8 +97,8 @@ 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 id of the current session */
|
||||
__thread volatile long sessionId = 0;
|
||||
|
||||
/** Holds the default log level */
|
||||
int configuredLogLevel = AV_LOG_INFO;
|
||||
|
@ -118,7 +117,6 @@ JNINativeMethod configMethods[] = {
|
|||
{"registerNewNativeFFmpegPipe", "(Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_registerNewNativeFFmpegPipe},
|
||||
{"getNativeBuildDate", "()Ljava/lang/String;", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeBuildDate},
|
||||
{"setNativeEnvironmentVariable", "(Ljava/lang/String;Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeEnvironmentVariable},
|
||||
{"getNativeLastCommandOutput", "()Ljava/lang/String;", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeLastCommandOutput},
|
||||
{"ignoreNativeSignal", "(I)V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal}
|
||||
};
|
||||
|
||||
|
@ -215,23 +213,12 @@ void monitorInit() {
|
|||
pthread_condattr_destroy(&cattributes);
|
||||
}
|
||||
|
||||
void logInit() {
|
||||
pthread_mutexattr_t attributes;
|
||||
pthread_mutexattr_init(&attributes);
|
||||
pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
|
||||
|
||||
pthread_mutex_init(&logMutex, &attributes);
|
||||
pthread_mutexattr_destroy(&attributes);
|
||||
|
||||
av_bprint_init(&lastCommandOutput, 0, AV_BPRINT_SIZE_UNLIMITED);
|
||||
}
|
||||
|
||||
void executionMapLockInit() {
|
||||
pthread_mutexattr_t attributes;
|
||||
pthread_mutexattr_init(&attributes);
|
||||
pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
|
||||
|
||||
pthread_mutex_init(&executionMapMutex, &attributes);
|
||||
pthread_mutex_init(&sessionMapMutex, &attributes);
|
||||
pthread_mutexattr_destroy(&attributes);
|
||||
}
|
||||
|
||||
|
@ -244,52 +231,24 @@ void monitorUnInit() {
|
|||
pthread_cond_destroy(&monitorCondition);
|
||||
}
|
||||
|
||||
void logUnInit() {
|
||||
pthread_mutex_destroy(&logMutex);
|
||||
}
|
||||
|
||||
void executionMapLockUnInit() {
|
||||
pthread_mutex_destroy(&executionMapMutex);
|
||||
pthread_mutex_destroy(&sessionMapMutex);
|
||||
}
|
||||
|
||||
void mutexLock() {
|
||||
pthread_mutex_lock(&lockMutex);
|
||||
}
|
||||
|
||||
void lastCommandOutputLock() {
|
||||
pthread_mutex_lock(&logMutex);
|
||||
}
|
||||
|
||||
void executionMapLock() {
|
||||
pthread_mutex_lock(&executionMapMutex);
|
||||
void sessionMapLock() {
|
||||
pthread_mutex_lock(&sessionMapMutex);
|
||||
}
|
||||
|
||||
void mutexUnlock() {
|
||||
pthread_mutex_unlock(&lockMutex);
|
||||
}
|
||||
|
||||
void lastCommandOutputUnlock() {
|
||||
pthread_mutex_unlock(&logMutex);
|
||||
}
|
||||
|
||||
void executionMapUnlock() {
|
||||
pthread_mutex_unlock(&executionMapMutex);
|
||||
}
|
||||
|
||||
void clearLastCommandOutput() {
|
||||
lastCommandOutputLock();
|
||||
av_bprint_clear(&lastCommandOutput);
|
||||
lastCommandOutputUnlock();
|
||||
}
|
||||
|
||||
void appendLastCommandOutput(AVBPrint *logMessage) {
|
||||
if (logMessage->len <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastCommandOutputLock();
|
||||
av_bprintf(&lastCommandOutput, "%s", logMessage->str);
|
||||
lastCommandOutputUnlock();
|
||||
void sessionMapUnlock() {
|
||||
pthread_mutex_unlock(&sessionMapMutex);
|
||||
}
|
||||
|
||||
void monitorWait(int milliSeconds) {
|
||||
|
@ -331,7 +290,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->executionId = executionId;
|
||||
newData->sessionId = sessionId;
|
||||
newData->logLevel = level;
|
||||
av_bprint_init(&newData->logData, 0, AV_BPRINT_SIZE_UNLIMITED);
|
||||
av_bprintf(&newData->logData, "%s", data->str);
|
||||
|
@ -368,7 +327,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->executionId = executionId;
|
||||
newData->sessionId = sessionId;
|
||||
newData->statisticsFrameNumber = frameNumber;
|
||||
newData->statisticsFps = fps;
|
||||
newData->statisticsQuality = quality;
|
||||
|
@ -403,17 +362,17 @@ void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds an execution id to the execution map.
|
||||
* Adds a session id to the session map.
|
||||
*
|
||||
* @param id execution id
|
||||
* @param id session id
|
||||
*/
|
||||
void addExecution(long id) {
|
||||
executionMapLock();
|
||||
void addSession(long id) {
|
||||
sessionMapLock();
|
||||
|
||||
int key = id % EXECUTION_MAP_SIZE;
|
||||
executionMap[key] = 1;
|
||||
int key = id % SESSION_MAP_SIZE;
|
||||
sessionMap[key] = 1;
|
||||
|
||||
executionMapUnlock();
|
||||
sessionMapUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -449,36 +408,50 @@ struct CallbackData *callbackDataRemove() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Removes an execution id from the execution map.
|
||||
* Removes a session id from the session map.
|
||||
*
|
||||
* @param id execution id
|
||||
* @param id session id
|
||||
*/
|
||||
void removeExecution(long id) {
|
||||
executionMapLock();
|
||||
void removeSession(long id) {
|
||||
sessionMapLock();
|
||||
|
||||
int key = id % EXECUTION_MAP_SIZE;
|
||||
executionMap[key] = 0;
|
||||
int key = id % SESSION_MAP_SIZE;
|
||||
sessionMap[key] = 0;
|
||||
|
||||
executionMapUnlock();
|
||||
sessionMapUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a cancel request for the given execution id exists in the execution map.
|
||||
* Adds a cancel session request to the session map.
|
||||
*
|
||||
* @param id execution id
|
||||
* @param id session id
|
||||
*/
|
||||
void cancelSession(long id) {
|
||||
sessionMapLock();
|
||||
|
||||
int key = id % SESSION_MAP_SIZE;
|
||||
sessionMap[key] = 2;
|
||||
|
||||
sessionMapUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a cancel request for the given session id exists in the session map.
|
||||
*
|
||||
* @param id session id
|
||||
* @return 1 if exists, false otherwise
|
||||
*/
|
||||
int cancelRequested(long id) {
|
||||
int found = 0;
|
||||
|
||||
executionMapLock();
|
||||
sessionMapLock();
|
||||
|
||||
int key = id % EXECUTION_MAP_SIZE;
|
||||
if (executionMap[key] == 0) {
|
||||
int key = id % SESSION_MAP_SIZE;
|
||||
if (sessionMap[key] == 2) {
|
||||
found = 1;
|
||||
}
|
||||
|
||||
executionMapUnlock();
|
||||
sessionMapUnlock();
|
||||
|
||||
return found;
|
||||
}
|
||||
|
@ -519,7 +492,6 @@ void ffmpegkit_log_callback_function(void *ptr, int level, const char* format, v
|
|||
|
||||
if (fullLine.len > 0) {
|
||||
logCallbackDataAdd(level, &fullLine);
|
||||
appendLastCommandOutput(&fullLine);
|
||||
}
|
||||
|
||||
av_bprint_finalize(part, NULL);
|
||||
|
@ -576,7 +548,7 @@ void *callbackThreadFunction() {
|
|||
|
||||
jbyteArray byteArray = (jbyteArray) (*env)->NewByteArray(env, size);
|
||||
(*env)->SetByteArrayRegion(env, byteArray, 0, size, callbackData->logData.str);
|
||||
(*env)->CallStaticVoidMethod(env, configClass, logMethod, (jlong) callbackData->executionId, callbackData->logLevel, byteArray);
|
||||
(*env)->CallStaticVoidMethod(env, configClass, logMethod, (jlong) callbackData->sessionId, callbackData->logLevel, byteArray);
|
||||
(*env)->DeleteLocalRef(env, byteArray);
|
||||
|
||||
// CLEAN LOG DATA
|
||||
|
@ -587,7 +559,7 @@ void *callbackThreadFunction() {
|
|||
// STATISTICS CALLBACK
|
||||
|
||||
(*env)->CallStaticVoidMethod(env, configClass, statisticsMethod,
|
||||
(jlong) callbackData->executionId, callbackData->statisticsFrameNumber,
|
||||
(jlong) callbackData->sessionId, callbackData->statisticsFrameNumber,
|
||||
callbackData->statisticsFps, callbackData->statisticsQuality,
|
||||
callbackData->statisticsSize, callbackData->statisticsTime,
|
||||
callbackData->statisticsBitrate, callbackData->statisticsSpeed);
|
||||
|
@ -610,6 +582,15 @@ void *callbackThreadFunction() {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by saf_wrapper; is expected to be called from a Java thread, therefore we don't need attach/detach
|
||||
*/
|
||||
void closeParcelFileDescriptor(int fd) {
|
||||
JNIEnv *env = NULL;
|
||||
(*globalVm)->GetEnv(globalVm, (void**) &env, JNI_VERSION_1_6);
|
||||
(*env)->CallStaticVoidMethod(env, configClass, closeParcelFileDescriptorMethod, fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when 'ffmpegkit' native library is loaded.
|
||||
*
|
||||
|
@ -630,7 +611,7 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if ((*env)->RegisterNatives(env, localConfigClass, configMethods, 12) < 0) {
|
||||
if ((*env)->RegisterNatives(env, localConfigClass, configMethods, 13) < 0) {
|
||||
LOGE("OnLoad failed to RegisterNatives for class %s.\n", configClassName);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
@ -655,6 +636,12 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
closeParcelFileDescriptorMethod = (*env)->GetStaticMethodID(env, localConfigClass, "closeParcelFileDescriptor", "(I)V");
|
||||
if (logMethod == NULL) {
|
||||
LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "closeParcelFileDescriptor");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
stringConstructor = (*env)->GetMethodID(env, localStringClass, "<init>", "([BLjava/lang/String;)V");
|
||||
if (stringConstructor == NULL) {
|
||||
LOGE("OnLoad thread failed to GetMethodID for %s.\n", "<init>");
|
||||
|
@ -671,13 +658,12 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|||
callbackDataHead = NULL;
|
||||
callbackDataTail = NULL;
|
||||
|
||||
for(int i = 0; i<EXECUTION_MAP_SIZE; i++) {
|
||||
executionMap[i] = 0;
|
||||
for(int i = 0; i<SESSION_MAP_SIZE; i++) {
|
||||
sessionMap[i] = 0;
|
||||
}
|
||||
|
||||
mutexInit();
|
||||
monitorInit();
|
||||
logInit();
|
||||
executionMapLockInit();
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
|
@ -782,7 +768,7 @@ JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNative
|
|||
*
|
||||
* @param env pointer to native method interface
|
||||
* @param object reference to the class on which this method is invoked
|
||||
* @param id execution id
|
||||
* @param id session id
|
||||
* @param stringArray reference to the object holding FFmpeg command arguments
|
||||
* @return zero on successful execution, non-zero on error
|
||||
*/
|
||||
|
@ -819,18 +805,15 @@ JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpeg
|
|||
}
|
||||
}
|
||||
|
||||
// LAST COMMAND OUTPUT SHOULD BE CLEARED BEFORE STARTING A NEW EXECUTION
|
||||
clearLastCommandOutput();
|
||||
|
||||
// REGISTER THE ID BEFORE STARTING EXECUTION
|
||||
executionId = (long) id;
|
||||
addExecution((long) id);
|
||||
sessionId = (long) id;
|
||||
addSession((long) id);
|
||||
|
||||
// RUN
|
||||
int retCode = ffmpeg_execute(argumentCount, argv);
|
||||
|
||||
// ALWAYS REMOVE THE ID FROM THE MAP
|
||||
removeExecution((long) id);
|
||||
removeSession((long) id);
|
||||
|
||||
// CLEANUP
|
||||
if (tempArray != NULL) {
|
||||
|
@ -851,7 +834,7 @@ JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpeg
|
|||
*
|
||||
* @param env pointer to native method interface
|
||||
* @param object reference to the class on which this method is invoked
|
||||
* @param id execution id
|
||||
* @param id session id
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegCancel(JNIEnv *env, jclass object, jlong id) {
|
||||
cancel_operation(id);
|
||||
|
@ -904,25 +887,6 @@ JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeEnvi
|
|||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns log output of the last executed command natively.
|
||||
*
|
||||
* @param env pointer to native method interface
|
||||
* @param object reference to the class on which this method is invoked
|
||||
* @return output of the last executed command
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeLastCommandOutput(JNIEnv *env, jclass object) {
|
||||
int size = lastCommandOutput.len;
|
||||
if (size > 0) {
|
||||
jbyteArray byteArray = (*env)->NewByteArray(env, size);
|
||||
(*env)->SetByteArrayRegion(env, byteArray, 0, size, lastCommandOutput.str);
|
||||
jstring charsetName = (*env)->NewStringUTF(env, "UTF-8");
|
||||
return (jstring) (*env)->NewObject(env, stringClass, stringConstructor, byteArray, charsetName);
|
||||
}
|
||||
|
||||
return (*env)->NewStringUTF(env, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new ignored signal. Ignored signals are not handled by the library.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -94,7 +94,7 @@ JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNative
|
|||
* Method: nativeFFmpegExecute
|
||||
* Signature: (J[Ljava/lang/String;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute(JNIEnv *, jclass, jlong id, jobjectArray);
|
||||
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute(JNIEnv *, jclass, jlong, jobjectArray);
|
||||
|
||||
/*
|
||||
* Class: com_arthenica_ffmpegkit_FFmpegKitConfig
|
||||
|
@ -124,13 +124,6 @@ JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNative
|
|||
*/
|
||||
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeEnvironmentVariable(JNIEnv *env, jclass object, jstring variableName, jstring variableValue);
|
||||
|
||||
/*
|
||||
* Class: com_arthenica_ffmpegkit_FFmpegKitConfig
|
||||
* Method: getNativeLastCommandOutput
|
||||
* Signature: ()Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeLastCommandOutput(JNIEnv *env, jclass object);
|
||||
|
||||
/*
|
||||
* Class: com_arthenica_ffmpegkit_FFmpegKitConfig
|
||||
* Method: ignoreNativeSignal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Taner Sener
|
||||
* Copyright (c) 2020-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -29,20 +29,21 @@
|
|||
/** Forward declaration for function defined in fftools_ffprobe.c */
|
||||
int ffprobe_execute(int argc, char **argv);
|
||||
|
||||
/** Forward declaration for function defined in ffmpegkit.c */
|
||||
void clearLastCommandOutput();
|
||||
|
||||
extern int configuredLogLevel;
|
||||
extern __thread volatile long sessionId;
|
||||
extern void addSession(long id);
|
||||
extern void removeSession(long id);
|
||||
|
||||
/**
|
||||
* Synchronously executes FFprobe natively with arguments provided.
|
||||
*
|
||||
* @param env pointer to native method interface
|
||||
* @param object reference to the class on which this method is invoked
|
||||
* @param id session id
|
||||
* @param stringArray reference to the object holding FFprobe command arguments
|
||||
* @return zero on successful execution, non-zero on error
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprobeExecute(JNIEnv *env, jclass object, jobjectArray stringArray) {
|
||||
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprobeExecute(JNIEnv *env, jclass object, jlong id, jobjectArray stringArray) {
|
||||
jstring *tempArray = NULL;
|
||||
int argumentCount = 1;
|
||||
char **argv = NULL;
|
||||
|
@ -75,12 +76,16 @@ JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprob
|
|||
}
|
||||
}
|
||||
|
||||
// LAST COMMAND OUTPUT SHOULD BE CLEARED BEFORE STARTING A NEW EXECUTION
|
||||
clearLastCommandOutput();
|
||||
// REGISTER THE ID BEFORE STARTING EXECUTION
|
||||
sessionId = (long) id;
|
||||
addSession((long) id);
|
||||
|
||||
// RUN
|
||||
int retCode = ffprobe_execute(argumentCount, argv);
|
||||
|
||||
// ALWAYS REMOVE THE ID FROM THE MAP
|
||||
removeSession((long) id);
|
||||
|
||||
// CLEANUP
|
||||
if (tempArray != NULL) {
|
||||
for (int i = 0; i < (argumentCount - 1); i++) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Taner Sener
|
||||
* Copyright (c) 2020-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -25,8 +25,8 @@
|
|||
/*
|
||||
* Class: com_arthenica_ffmpegkit_FFmpegKitConfig
|
||||
* Method: nativeFFprobeExecute
|
||||
* Signature: ([Ljava/lang/String;)I
|
||||
* Signature: (J[Ljava/lang/String;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprobeExecute(JNIEnv *, jclass, jobjectArray);
|
||||
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprobeExecute(JNIEnv *, jclass, jlong, jobjectArray);
|
||||
|
||||
#endif /* FFPROBE_KIT_H */
|
|
@ -51,6 +51,8 @@
|
|||
#include "libavformat/avformat.h"
|
||||
#include "libswscale/swscale.h"
|
||||
|
||||
#include "saf_wrapper.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef main /* We don't want SDL to override our main() */
|
||||
#endif
|
||||
|
|
|
@ -253,8 +253,8 @@ extern volatile int handleSIGTERM;
|
|||
extern volatile int handleSIGXCPU;
|
||||
extern volatile int handleSIGPIPE;
|
||||
|
||||
extern __thread volatile long executionId;
|
||||
extern void removeExecution(long id);
|
||||
extern __thread volatile long sessionId;
|
||||
extern void cancelSession(long id);
|
||||
extern int cancelRequested(long id);
|
||||
|
||||
/* sub2video hack:
|
||||
|
@ -729,7 +729,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 signal.\n");
|
||||
} else if (ret && atomic_load(&transcode_init_done)) {
|
||||
av_log(NULL, AV_LOG_INFO, "Conversion failed!\n");
|
||||
|
@ -2392,7 +2392,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)
|
||||
|
@ -4859,7 +4859,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 */
|
||||
|
@ -5064,7 +5064,7 @@ void cancel_operation(long id)
|
|||
if (id == 0) {
|
||||
sigterm_handler(SIGINT);
|
||||
} else {
|
||||
removeExecution(id);
|
||||
cancelSession(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5575,10 +5575,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;
|
||||
|
|
135
android/app/src/main/cpp/saf_wrapper.c
Normal file
135
android/app/src/main/cpp/saf_wrapper.c
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "libavformat/avformat.h"
|
||||
#include "libavutil/avstring.h"
|
||||
|
||||
#include "saf_wrapper.h"
|
||||
|
||||
/** JNI wrapper in ffmpegkit.c */
|
||||
void closeParcelFileDescriptor(int fd);
|
||||
|
||||
// in these wrappers, we call the original functions, so we remove the shadow defines
|
||||
#undef avio_closep
|
||||
#undef avformat_close_input
|
||||
#undef avio_open
|
||||
#undef avio_open2
|
||||
#undef avformat_open_input
|
||||
|
||||
static int fd_read_packet(void* opaque, uint8_t* buf, int buf_size) {
|
||||
int fd = (int)opaque;
|
||||
return read(fd, buf, buf_size);
|
||||
}
|
||||
|
||||
static int fd_write_packet(void* opaque, uint8_t* buf, int buf_size) {
|
||||
int fd = (int)opaque;
|
||||
return write(fd, buf, buf_size);
|
||||
}
|
||||
|
||||
static int64_t fd_seek(void *opaque, int64_t offset, int whence) {
|
||||
int fd = (int)opaque;
|
||||
|
||||
if (fd < 0) {
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
int64_t ret;
|
||||
if (whence == AVSEEK_SIZE) {
|
||||
struct stat st;
|
||||
ret = fstat(fd, &st);
|
||||
return ret < 0 ? AVERROR(errno) : (S_ISFIFO(st.st_mode) ? 0 : st.st_size);
|
||||
}
|
||||
|
||||
ret = lseek(fd, offset, whence);
|
||||
|
||||
return ret < 0 ? AVERROR(errno) : ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
union {int fd; void* opaque;} fdunion;
|
||||
fdunion.fd = -1;
|
||||
const char *fd_ptr = NULL;
|
||||
if (av_strstart(filename, "saf:", &fd_ptr)) {
|
||||
char *final;
|
||||
fdunion.fd = strtol(fd_ptr, &final, 10);
|
||||
if (fd_ptr == final) { /* No digits found */
|
||||
fdunion.fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (fdunion.fd >= 0) {
|
||||
int write_flag = flags & AVIO_FLAG_WRITE ? 1 : 0;
|
||||
return avio_alloc_context(av_malloc(4096), 4096, write_flag, fdunion.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 = (int)ctx->opaque;
|
||||
close(fd);
|
||||
closeParcelFileDescriptor(fd);
|
||||
}
|
||||
ctx->opaque = NULL;
|
||||
}
|
||||
|
||||
int android_avformat_open_input(AVFormatContext **ps, const char *filename,
|
||||
ff_const59 AVInputFormat *fmt, AVDictionary **options) {
|
||||
if (!(*ps) && !(*ps = avformat_alloc_context()))
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
(*ps)->pb = create_fd_avio_context(filename, AVIO_FLAG_READ);
|
||||
|
||||
return avformat_open_input(ps, filename, fmt, options);
|
||||
}
|
||||
|
||||
int android_avio_open2(AVIOContext **s, const char *filename, int flags,
|
||||
const AVIOInterruptCB *int_cb, AVDictionary **options) {
|
||||
AVIOContext *fd_context = create_fd_avio_context(filename, flags);
|
||||
|
||||
if (fd_context) {
|
||||
*s = fd_context;
|
||||
return 0;
|
||||
}
|
||||
return avio_open2(s, filename, flags, int_cb, options);
|
||||
}
|
||||
|
||||
int android_avio_open(AVIOContext **s, const char *url, int flags) {
|
||||
return android_avio_open2(s, url, flags, NULL, NULL);
|
||||
}
|
||||
|
||||
int android_avio_closep(AVIOContext **s) {
|
||||
close_fd_avio_context(*s);
|
||||
return avio_closep(s);
|
||||
}
|
||||
|
||||
void android_avformat_close_input(AVFormatContext **ps) {
|
||||
if (*ps && (*ps)->pb) {
|
||||
close_fd_avio_context((*ps)->pb);
|
||||
}
|
||||
avformat_close_input(ps);
|
||||
}
|
46
android/app/src/main/cpp/saf_wrapper.h
Normal file
46
android/app/src/main/cpp/saf_wrapper.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_SAF_WRAPPER_H
|
||||
#define FFMPEG_KIT_SAF_WRAPPER_H
|
||||
|
||||
/*
|
||||
* These wrappers are intended to be used instead of the ffmpeg apis.
|
||||
* You don't even need to change the source to call them.
|
||||
* Instead, we redefine the public api names so that the wrapper be used.
|
||||
*/
|
||||
|
||||
int android_avio_closep(AVIOContext **s);
|
||||
#define avio_closep android_avio_closep
|
||||
|
||||
void android_avformat_close_input(AVFormatContext **s);
|
||||
#define avformat_close_input android_avformat_close_input
|
||||
|
||||
int android_avio_open(AVIOContext **s, const char *url, int flags);
|
||||
#define avio_open android_avio_open
|
||||
|
||||
int android_avio_open2(AVIOContext **s, const char *url, int flags,
|
||||
const AVIOInterruptCB *int_cb, AVDictionary **options);
|
||||
#define avio_open2 android_avio_open2
|
||||
|
||||
int android_avformat_open_input(AVFormatContext **ps, const char *filename,
|
||||
ff_const59 AVInputFormat *fmt, AVDictionary **options);
|
||||
#define avformat_open_input android_avformat_open_input
|
||||
|
||||
#endif //FFMPEG_KIT_SAF_WRAPPER_H
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -20,7 +20,9 @@
|
|||
package com.arthenica.ffmpegkit;
|
||||
|
||||
/**
|
||||
* <p>Helper enumeration type for Android ABIs; includes only supported ABIs.
|
||||
* <p>Enumeration type for Android ABIs.
|
||||
*
|
||||
* @author Taner Sener
|
||||
*/
|
||||
public enum Abi {
|
||||
|
||||
|
@ -59,7 +61,7 @@ public enum Abi {
|
|||
*/
|
||||
ABI_UNKNOWN("unknown");
|
||||
|
||||
private String name;
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* <p>Returns enumeration defined by ABI name.
|
||||
|
@ -97,7 +99,7 @@ public enum Abi {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates new enum.
|
||||
* Creates a new enum.
|
||||
*
|
||||
* @param abiName ABI name
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -20,7 +20,7 @@
|
|||
package com.arthenica.ffmpegkit;
|
||||
|
||||
/**
|
||||
* <p>This class is used to detect running ABI name using Google <code>cpu-features</code> library.
|
||||
* <p>Detects running ABI name using Google <code>cpu-features</code> library.
|
||||
*/
|
||||
public class AbiDetect {
|
||||
|
||||
|
@ -46,8 +46,8 @@ public class AbiDetect {
|
|||
private AbiDetect() {
|
||||
}
|
||||
|
||||
static void setArmV7aNeonLoaded(final boolean armV7aNeonLoaded) {
|
||||
AbiDetect.armV7aNeonLoaded = armV7aNeonLoaded;
|
||||
static void setArmV7aNeonLoaded() {
|
||||
armV7aNeonLoaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.arthenica.ffmpegkit;
|
||||
|
||||
import com.arthenica.smartexception.java.Exceptions;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public abstract class AbstractSession implements Session {
|
||||
|
||||
/**
|
||||
* Generates ids for execute sessions.
|
||||
*/
|
||||
private static final AtomicLong sessionIdGenerator = new AtomicLong(1);
|
||||
|
||||
protected final ExecuteCallback executeCallback;
|
||||
protected final LogCallback logCallback;
|
||||
protected final StatisticsCallback statisticsCallback;
|
||||
protected final long sessionId;
|
||||
protected final Date createTime;
|
||||
protected Date startTime;
|
||||
protected Date endTime;
|
||||
protected final String[] arguments;
|
||||
protected final Queue<Log> logs;
|
||||
protected Future<?> future;
|
||||
protected SessionState state;
|
||||
protected int returnCode;
|
||||
protected String failStackTrace;
|
||||
|
||||
public AbstractSession(final String[] arguments,
|
||||
final ExecuteCallback executeCallback,
|
||||
final LogCallback logCallback,
|
||||
final StatisticsCallback statisticsCallback) {
|
||||
this.sessionId = sessionIdGenerator.getAndIncrement();
|
||||
this.createTime = new Date();
|
||||
this.startTime = null;
|
||||
this.arguments = arguments;
|
||||
this.executeCallback = executeCallback;
|
||||
this.logCallback = logCallback;
|
||||
this.statisticsCallback = statisticsCallback;
|
||||
this.logs = new ConcurrentLinkedQueue<>();
|
||||
this.future = null;
|
||||
this.state = SessionState.CREATED;
|
||||
this.returnCode = ReturnCode.NOT_SET;
|
||||
this.failStackTrace = null;
|
||||
}
|
||||
|
||||
public ExecuteCallback getExecuteCallback() {
|
||||
return executeCallback;
|
||||
}
|
||||
|
||||
public LogCallback getLogCallback() {
|
||||
return logCallback;
|
||||
}
|
||||
|
||||
public StatisticsCallback getStatisticsCallback() {
|
||||
return statisticsCallback;
|
||||
}
|
||||
|
||||
public long getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public Date getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public Date getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public long getDuration() {
|
||||
final Date startTime = this.startTime;
|
||||
final Date endTime = this.endTime;
|
||||
if (startTime != null && endTime != null) {
|
||||
return (endTime.getTime() - startTime.getTime());
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public String[] getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return FFmpegKit.argumentsToString(arguments);
|
||||
}
|
||||
|
||||
public Queue<Log> getLogs() {
|
||||
return logs;
|
||||
}
|
||||
|
||||
public Stream<Log> getLogsAsStream() {
|
||||
return logs.stream();
|
||||
}
|
||||
|
||||
public String getLogsAsString() {
|
||||
final Optional<String> concatenatedStringOption = logs.stream().map(new Function<Log, String>() {
|
||||
@Override
|
||||
public String apply(final Log log) {
|
||||
return log.getMessage();
|
||||
}
|
||||
}).reduce(new BinaryOperator<String>() {
|
||||
@Override
|
||||
public String apply(final String s1, final String s2) {
|
||||
return s1 + s2;
|
||||
}
|
||||
});
|
||||
|
||||
return concatenatedStringOption.orElseGet(new Supplier<String>() {
|
||||
|
||||
@Override
|
||||
public String get() {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public SessionState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public int getReturnCode() {
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
public String getFailStackTrace() {
|
||||
return failStackTrace;
|
||||
}
|
||||
|
||||
public void addLog(final Log log) {
|
||||
this.logs.add(log);
|
||||
}
|
||||
|
||||
public Future<?> getFuture() {
|
||||
return future;
|
||||
}
|
||||
|
||||
public void setFuture(final Future<?> future) {
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
public void startRunning() {
|
||||
this.state = SessionState.RUNNING;
|
||||
this.startTime = new Date();
|
||||
}
|
||||
|
||||
public void complete(final int returnCode) {
|
||||
this.returnCode = returnCode;
|
||||
this.state = SessionState.COMPLETED;
|
||||
this.endTime = new Date();
|
||||
}
|
||||
|
||||
public void fail(final Exception exception) {
|
||||
this.failStackTrace = Exceptions.getStackTraceString(exception);
|
||||
this.state = SessionState.FAILED;
|
||||
this.endTime = new Date();
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
if (state == SessionState.RUNNING) {
|
||||
FFmpegKit.cancel(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -19,44 +19,29 @@
|
|||
|
||||
package com.arthenica.ffmpegkit;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
/**
|
||||
* <p>Utility class to execute an FFmpeg command asynchronously.
|
||||
* <p>Executes an FFmpeg session asynchronously.
|
||||
*/
|
||||
public class AsyncFFmpegExecuteTask extends AsyncTask<Void, Integer, Integer> {
|
||||
private final String[] arguments;
|
||||
public class AsyncFFmpegExecuteTask implements Runnable {
|
||||
private final FFmpegSession ffmpegSession;
|
||||
private final ExecuteCallback executeCallback;
|
||||
private final Long executionId;
|
||||
|
||||
public AsyncFFmpegExecuteTask(final String command, final ExecuteCallback executeCallback) {
|
||||
this(FFmpegKit.parseArguments(command), executeCallback);
|
||||
}
|
||||
|
||||
public AsyncFFmpegExecuteTask(final String[] arguments, final ExecuteCallback executeCallback) {
|
||||
this(FFmpegKit.DEFAULT_EXECUTION_ID, arguments, executeCallback);
|
||||
}
|
||||
|
||||
public AsyncFFmpegExecuteTask(final long executionId, final String command, final ExecuteCallback executeCallback) {
|
||||
this(executionId, FFmpegKit.parseArguments(command), executeCallback);
|
||||
}
|
||||
|
||||
public AsyncFFmpegExecuteTask(final long executionId, final String[] arguments, final ExecuteCallback executeCallback) {
|
||||
this.executionId = executionId;
|
||||
this.arguments = arguments;
|
||||
this.executeCallback = executeCallback;
|
||||
public AsyncFFmpegExecuteTask(final FFmpegSession ffmpegSession) {
|
||||
this.ffmpegSession = ffmpegSession;
|
||||
this.executeCallback = ffmpegSession.getExecuteCallback();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(final Void... unused) {
|
||||
return FFmpegKitConfig.ffmpegExecute(executionId, this.arguments);
|
||||
}
|
||||
public void run() {
|
||||
FFmpegKitConfig.ffmpegExecute(ffmpegSession);
|
||||
|
||||
final ExecuteCallback globalExecuteCallbackFunction = FFmpegKitConfig.getGlobalExecuteCallbackFunction();
|
||||
if (globalExecuteCallbackFunction != null) {
|
||||
globalExecuteCallbackFunction.apply(ffmpegSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final Integer rc) {
|
||||
if (executeCallback != null) {
|
||||
executeCallback.apply(executionId, rc);
|
||||
executeCallback.apply(ffmpegSession);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -19,34 +19,24 @@
|
|||
|
||||
package com.arthenica.ffmpegkit;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
/**
|
||||
* <p>Utility class to execute an FFprobe command asynchronously.
|
||||
* <p>Executes an FFprobe execution asynchronously.
|
||||
*/
|
||||
public class AsyncFFprobeExecuteTask extends AsyncTask<Void, Integer, Integer> {
|
||||
private final String[] arguments;
|
||||
private final ExecuteCallback ExecuteCallback;
|
||||
public class AsyncFFprobeExecuteTask implements Runnable {
|
||||
private final FFprobeSession ffprobeSession;
|
||||
private final ExecuteCallback executeCallback;
|
||||
|
||||
public AsyncFFprobeExecuteTask(final String command, final ExecuteCallback executeCallback) {
|
||||
this.arguments = FFmpegKit.parseArguments(command);
|
||||
this.ExecuteCallback = executeCallback;
|
||||
}
|
||||
|
||||
public AsyncFFprobeExecuteTask(final String[] arguments, final ExecuteCallback executeCallback) {
|
||||
this.arguments = arguments;
|
||||
ExecuteCallback = executeCallback;
|
||||
public AsyncFFprobeExecuteTask(final FFprobeSession ffprobeSession) {
|
||||
this.ffprobeSession = ffprobeSession;
|
||||
this.executeCallback = ffprobeSession.getExecuteCallback();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(final Void... unused) {
|
||||
return FFprobeKit.execute(this.arguments);
|
||||
}
|
||||
public void run() {
|
||||
FFmpegKitConfig.ffprobeExecute(ffprobeSession);
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final Integer rc) {
|
||||
if (ExecuteCallback != null) {
|
||||
ExecuteCallback.apply(FFmpegKit.DEFAULT_EXECUTION_ID, rc);
|
||||
if (executeCallback != null) {
|
||||
executeCallback.apply(ffprobeSession);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -19,29 +19,24 @@
|
|||
|
||||
package com.arthenica.ffmpegkit;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
/**
|
||||
* <p>Utility class to get media information asynchronously.
|
||||
* <p>Executes a MediaInformation session asynchronously.
|
||||
*/
|
||||
public class AsyncGetMediaInformationTask extends AsyncTask<String, MediaInformation, MediaInformation> {
|
||||
private final String path;
|
||||
private final GetMediaInformationCallback getMediaInformationCallback;
|
||||
public class AsyncGetMediaInformationTask implements Runnable {
|
||||
private final MediaInformationSession mediaInformationSession;
|
||||
private final ExecuteCallback executeCallback;
|
||||
|
||||
public AsyncGetMediaInformationTask(final String path, final GetMediaInformationCallback getMediaInformationCallback) {
|
||||
this.path = path;
|
||||
this.getMediaInformationCallback = getMediaInformationCallback;
|
||||
public AsyncGetMediaInformationTask(final MediaInformationSession mediaInformationSession) {
|
||||
this.mediaInformationSession = mediaInformationSession;
|
||||
this.executeCallback = mediaInformationSession.getExecuteCallback();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MediaInformation doInBackground(final String... arguments) {
|
||||
return FFprobeKit.getMediaInformation(path);
|
||||
}
|
||||
public void run() {
|
||||
FFmpegKitConfig.getMediaInformationExecute(mediaInformationSession);
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final MediaInformation mediaInformation) {
|
||||
if (getMediaInformationCallback != null) {
|
||||
getMediaInformationCallback.apply(mediaInformation);
|
||||
if (executeCallback != null) {
|
||||
executeCallback.apply(mediaInformationSession);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 Taner Sener
|
||||
* Copyright (c) 2019-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -34,7 +34,9 @@ import static android.content.Context.CAMERA_SERVICE;
|
|||
import static com.arthenica.ffmpegkit.FFmpegKitConfig.TAG;
|
||||
|
||||
/**
|
||||
* Utility class for camera devices.
|
||||
* <p>Helper class to find camera devices supported.
|
||||
* <p>Note that camera devices can only be detected on Android API Level 24+. On older API levels
|
||||
* an empty list will be returned.
|
||||
*/
|
||||
class CameraSupport {
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -20,18 +20,16 @@
|
|||
package com.arthenica.ffmpegkit;
|
||||
|
||||
/**
|
||||
* <p>Represents a callback function to receive an asynchronous execution result.
|
||||
* <p>Callback function to receive execution results.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ExecuteCallback {
|
||||
|
||||
/**
|
||||
* <p>Called when an asynchronous FFmpeg execution is completed.
|
||||
* <p>Called when an execution is completed.
|
||||
*
|
||||
* @param executionId id of the execution that completed
|
||||
* @param returnCode return code of the execution completed, 0 on successful completion, 255
|
||||
* on user cancel, other non-zero codes on error
|
||||
* @param session of with completed execution
|
||||
*/
|
||||
void apply(long executionId, int returnCode);
|
||||
void apply(final Session session);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -19,12 +19,9 @@
|
|||
|
||||
package com.arthenica.ffmpegkit;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* <p>Main class for FFmpeg operations. Supports synchronous {@link #execute(String...)} and
|
||||
|
@ -40,10 +37,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||
*/
|
||||
public class FFmpegKit {
|
||||
|
||||
static final long DEFAULT_EXECUTION_ID = 0;
|
||||
|
||||
private static final AtomicLong executionIdCounter = new AtomicLong(3000);
|
||||
|
||||
static {
|
||||
AbiDetect.class.getName();
|
||||
FFmpegKitConfig.class.getName();
|
||||
|
@ -59,26 +52,50 @@ public class FFmpegKit {
|
|||
* <p>Synchronously executes FFmpeg with arguments provided.
|
||||
*
|
||||
* @param arguments FFmpeg command options/arguments as string array
|
||||
* @return 0 on successful execution, 255 on user cancel, other non-zero codes on error
|
||||
* @return ffmpeg session created for this execution
|
||||
*/
|
||||
public static int execute(final String[] arguments) {
|
||||
return FFmpegKitConfig.ffmpegExecute(DEFAULT_EXECUTION_ID, arguments);
|
||||
public static FFmpegSession execute(final String[] arguments) {
|
||||
final FFmpegSession session = new FFmpegSession(arguments, null, null, null);
|
||||
|
||||
FFmpegKitConfig.ffmpegExecute(session);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>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
|
||||
* @return returns a unique id that represents this execution
|
||||
* @param executeCallback callback that will be notified when the execution is completed
|
||||
* @return ffmpeg session created for this execution
|
||||
*/
|
||||
public static long executeAsync(final String[] arguments, final ExecuteCallback executeCallback) {
|
||||
final long newExecutionId = executionIdCounter.incrementAndGet();
|
||||
public static FFmpegSession executeAsync(final String[] arguments,
|
||||
final ExecuteCallback executeCallback) {
|
||||
final FFmpegSession session = new FFmpegSession(arguments, executeCallback, null, null);
|
||||
|
||||
AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(newExecutionId, arguments, executeCallback);
|
||||
asyncFFmpegExecuteTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
FFmpegKitConfig.asyncFFmpegExecute(session);
|
||||
|
||||
return newExecutionId;
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>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 statisticsCallback callback that will receive statistics
|
||||
* @return ffmpeg session created for this execution
|
||||
*/
|
||||
public static FFmpegSession executeAsync(final String[] arguments,
|
||||
final ExecuteCallback executeCallback,
|
||||
final LogCallback logCallback,
|
||||
final StatisticsCallback statisticsCallback) {
|
||||
final FFmpegSession session = new FFmpegSession(arguments, executeCallback, logCallback, statisticsCallback);
|
||||
|
||||
FFmpegKitConfig.asyncFFmpegExecute(session);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,31 +104,40 @@ public class FFmpegKit {
|
|||
* @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 returns a unique id that represents this execution
|
||||
* @return ffmpeg session created for this execution
|
||||
*/
|
||||
public static long executeAsync(final String[] arguments, final ExecuteCallback executeCallback, final Executor executor) {
|
||||
final long newExecutionId = executionIdCounter.incrementAndGet();
|
||||
public static FFmpegSession executeAsync(final String[] arguments,
|
||||
final ExecuteCallback executeCallback,
|
||||
final Executor executor) {
|
||||
final FFmpegSession session = new FFmpegSession(arguments, executeCallback, null, null);
|
||||
|
||||
AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(newExecutionId, arguments, executeCallback);
|
||||
asyncFFmpegExecuteTask.executeOnExecutor(executor);
|
||||
AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(session);
|
||||
executor.execute(asyncFFmpegExecuteTask);
|
||||
|
||||
return newExecutionId;
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Synchronously executes FFmpeg command provided. Command is split into arguments using
|
||||
* provided delimiter character.
|
||||
* <p>Asynchronously executes FFmpeg with arguments provided.
|
||||
*
|
||||
* @param command FFmpeg command
|
||||
* @param delimiter delimiter used to split arguments
|
||||
* @return 0 on successful execution, 255 on user cancel, other non-zero codes on error
|
||||
* @since 3.0
|
||||
* @deprecated argument splitting mechanism used in this method is pretty simple and prone to
|
||||
* errors. Consider using a more advanced method like {@link #execute(String)} or
|
||||
* {@link #execute(String[])}
|
||||
* @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 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
|
||||
*/
|
||||
public static int execute(final String command, final String delimiter) {
|
||||
return execute((command == null) ? new String[]{""} : command.split((delimiter == null) ? " " : delimiter));
|
||||
public static FFmpegSession executeAsync(final String[] arguments,
|
||||
final ExecuteCallback executeCallback,
|
||||
final LogCallback logCallback,
|
||||
final StatisticsCallback statisticsCallback,
|
||||
final Executor executor) {
|
||||
final FFmpegSession session = new FFmpegSession(arguments, executeCallback, logCallback, statisticsCallback);
|
||||
|
||||
AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(session);
|
||||
executor.execute(asyncFFmpegExecuteTask);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,9 +146,9 @@ public class FFmpegKit {
|
|||
* your command.
|
||||
*
|
||||
* @param command FFmpeg command
|
||||
* @return 0 on successful execution, 255 on user cancel, other non-zero codes on error
|
||||
* @return ffmpeg session created for this execution
|
||||
*/
|
||||
public static int execute(final String command) {
|
||||
public static FFmpegSession execute(final String command) {
|
||||
return execute(parseArguments(command));
|
||||
}
|
||||
|
||||
|
@ -133,15 +159,29 @@ public class FFmpegKit {
|
|||
*
|
||||
* @param command FFmpeg command
|
||||
* @param executeCallback callback that will be notified when execution is completed
|
||||
* @return returns a unique id that represents this execution
|
||||
* @return ffmpeg session created for this execution
|
||||
*/
|
||||
public static long executeAsync(final String command, final ExecuteCallback executeCallback) {
|
||||
final long newExecutionId = executionIdCounter.incrementAndGet();
|
||||
public static FFmpegSession executeAsync(final String command,
|
||||
final ExecuteCallback executeCallback) {
|
||||
return executeAsync(parseArguments(command), executeCallback);
|
||||
}
|
||||
|
||||
AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(newExecutionId, command, executeCallback);
|
||||
asyncFFmpegExecuteTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
|
||||
return newExecutionId;
|
||||
/**
|
||||
* <p>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
|
||||
* 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 statisticsCallback callback that will receive statistics
|
||||
* @return ffmpeg session created for this execution
|
||||
*/
|
||||
public static FFmpegSession executeAsync(final String command,
|
||||
final ExecuteCallback executeCallback,
|
||||
final LogCallback logCallback,
|
||||
final StatisticsCallback statisticsCallback) {
|
||||
return executeAsync(parseArguments(command), executeCallback, logCallback, statisticsCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -152,44 +192,76 @@ public class FFmpegKit {
|
|||
* @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 returns a unique id that represents this execution
|
||||
* @return ffmpeg session created for this execution
|
||||
*/
|
||||
public static long executeAsync(final String command, final ExecuteCallback executeCallback, final Executor executor) {
|
||||
final long newExecutionId = executionIdCounter.incrementAndGet();
|
||||
public static FFmpegSession executeAsync(final String command,
|
||||
final ExecuteCallback executeCallback,
|
||||
final Executor executor) {
|
||||
final FFmpegSession session = new FFmpegSession(parseArguments(command), executeCallback, null, null);
|
||||
|
||||
AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(newExecutionId, command, executeCallback);
|
||||
asyncFFmpegExecuteTask.executeOnExecutor(executor);
|
||||
AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(session);
|
||||
executor.execute(asyncFFmpegExecuteTask);
|
||||
|
||||
return newExecutionId;
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Cancels an ongoing operation.
|
||||
* <p>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
|
||||
* 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 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
|
||||
*/
|
||||
public static FFmpegSession executeAsync(final String command,
|
||||
final ExecuteCallback executeCallback,
|
||||
final LogCallback logCallback,
|
||||
final StatisticsCallback statisticsCallback,
|
||||
final Executor executor) {
|
||||
final FFmpegSession session = new FFmpegSession(parseArguments(command), executeCallback, logCallback, statisticsCallback);
|
||||
|
||||
AsyncFFmpegExecuteTask asyncFFmpegExecuteTask = new AsyncFFmpegExecuteTask(session);
|
||||
executor.execute(asyncFFmpegExecuteTask);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Cancels the last execution started.
|
||||
*
|
||||
* <p>This function does not wait for termination to complete and returns immediately.
|
||||
*/
|
||||
public static void cancel() {
|
||||
FFmpegKitConfig.nativeFFmpegCancel(DEFAULT_EXECUTION_ID);
|
||||
Session lastSession = FFmpegKitConfig.getLastSession();
|
||||
if (lastSession != null) {
|
||||
FFmpegKitConfig.nativeFFmpegCancel(lastSession.getSessionId());
|
||||
} else {
|
||||
android.util.Log.w(FFmpegKitConfig.TAG, "FFmpegKit cancel skipped. The last execution does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Cancels an ongoing operation.
|
||||
* <p>Cancels the given execution.
|
||||
*
|
||||
* <p>This function does not wait for termination to complete and returns immediately.
|
||||
*
|
||||
* @param executionId id of the execution
|
||||
* @param sessionId id of the session that will be stopped
|
||||
*/
|
||||
public static void cancel(final long executionId) {
|
||||
FFmpegKitConfig.nativeFFmpegCancel(executionId);
|
||||
public static void cancel(final long sessionId) {
|
||||
FFmpegKitConfig.nativeFFmpegCancel(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Lists ongoing executions.
|
||||
* <p>Lists all FFmpeg sessions in the session history
|
||||
*
|
||||
* @return list of ongoing executions
|
||||
* @return all FFmpeg sessions in the session history
|
||||
*/
|
||||
public static List<FFmpegExecution> listExecutions() {
|
||||
return FFmpegKitConfig.listFFmpegExecutions();
|
||||
public static List<FFmpegSession> listSessions() {
|
||||
return FFmpegKitConfig.getFFmpegSessions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.arthenica.ffmpegkit;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* <p>An FFmpeg execute session.
|
||||
*/
|
||||
public class FFmpegSession extends AbstractSession implements Session {
|
||||
private final Queue<Statistics> statistics;
|
||||
|
||||
public FFmpegSession(final String[] arguments,
|
||||
final ExecuteCallback executeCallback,
|
||||
final LogCallback logCallback,
|
||||
final StatisticsCallback statisticsCallback) {
|
||||
super(arguments, executeCallback, logCallback, statisticsCallback);
|
||||
|
||||
this.statistics = new ConcurrentLinkedQueue<>();
|
||||
}
|
||||
|
||||
public Queue<Statistics> getStatistics() {
|
||||
return statistics;
|
||||
}
|
||||
|
||||
public Stream<Statistics> getStatisticsAsStream() {
|
||||
return statistics.stream();
|
||||
}
|
||||
|
||||
public void addStatistics(final Statistics statistics) {
|
||||
this.statistics.add(statistics);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFFmpeg() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFFprobe() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
stringBuilder.append("FFmpegSession{");
|
||||
stringBuilder.append("sessionId=");
|
||||
stringBuilder.append(sessionId);
|
||||
stringBuilder.append(", createTime=");
|
||||
stringBuilder.append(createTime);
|
||||
stringBuilder.append(", startTime=");
|
||||
stringBuilder.append(startTime);
|
||||
stringBuilder.append(", endTime=");
|
||||
stringBuilder.append(endTime);
|
||||
stringBuilder.append(", arguments=");
|
||||
stringBuilder.append(FFmpegKit.argumentsToString(arguments));
|
||||
stringBuilder.append(", logs=");
|
||||
stringBuilder.append(getLogsAsString());
|
||||
stringBuilder.append(", state=");
|
||||
stringBuilder.append(state);
|
||||
stringBuilder.append(", returnCode=");
|
||||
stringBuilder.append(returnCode);
|
||||
stringBuilder.append(", failStackTrace=");
|
||||
stringBuilder.append('\'');
|
||||
stringBuilder.append(failStackTrace);
|
||||
stringBuilder.append('\'');
|
||||
stringBuilder.append('}');
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Taner Sener
|
||||
* Copyright (c) 2020-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -19,14 +19,19 @@
|
|||
|
||||
package com.arthenica.ffmpegkit;
|
||||
|
||||
import android.util.Log;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* <p>Main class for FFprobe operations. Provides {@link #execute(String...)} method to execute
|
||||
* FFprobe commands.
|
||||
* <p>Main class for FFprobe operations.
|
||||
* <p>Supports running FFprobe commands using {@link #execute(String...)} method.
|
||||
* <pre>
|
||||
* int rc = FFprobe.execute("-hide_banner -v error -show_entries format=size -of default=noprint_wrappers=1 file1.mp4");
|
||||
* Log.i(Config.TAG, String.format("Command execution %s.", (rc == 0?"completed successfully":"failed with rc=" + rc));
|
||||
* 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()));
|
||||
* </pre>
|
||||
* <p>It can also extract media information for a file or a url, using {@link #getMediaInformation(String)} method.
|
||||
* <pre>
|
||||
* 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()));
|
||||
* </pre>
|
||||
*/
|
||||
public class FFprobeKit {
|
||||
|
@ -46,14 +51,14 @@ public class FFprobeKit {
|
|||
* <p>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
|
||||
*/
|
||||
public static int execute(final String[] arguments) {
|
||||
final int lastReturnCode = FFmpegKitConfig.nativeFFprobeExecute(arguments);
|
||||
public static FFprobeSession execute(final String[] arguments) {
|
||||
final FFprobeSession session = new FFprobeSession(arguments, null, null, null);
|
||||
|
||||
FFmpegKitConfig.setLastReturnCode(lastReturnCode);
|
||||
FFmpegKitConfig.ffprobeExecute(session);
|
||||
|
||||
return lastReturnCode;
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -62,69 +67,246 @@ public class FFprobeKit {
|
|||
* 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
|
||||
*/
|
||||
public static int execute(final String command) {
|
||||
public static FFprobeSession execute(final String command) {
|
||||
return execute(FFmpegKit.parseArguments(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns media information for the given file.
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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
|
||||
* @return media information
|
||||
* @since 3.0
|
||||
* @param command FFprobe command
|
||||
* @param executeCallback callback that will be notified when the execution is completed
|
||||
* @return ffprobe session created for this execution
|
||||
*/
|
||||
public static MediaInformation getMediaInformation(final String path) {
|
||||
return getMediaInformationFromCommandArguments(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path});
|
||||
public static FFprobeSession executeAsync(final String command,
|
||||
final ExecuteCallback executeCallback) {
|
||||
return executeAsync(FFmpegKit.parseArguments(command), executeCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>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
|
||||
*/
|
||||
public static FFprobeSession executeAsync(final String[] arguments,
|
||||
final ExecuteCallback executeCallback) {
|
||||
final FFprobeSession session = new FFprobeSession(arguments, executeCallback, null, null);
|
||||
|
||||
FFmpegKitConfig.asyncFFprobeExecute(session);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>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.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public static FFprobeSession executeAsync(final String command,
|
||||
final ExecuteCallback executeCallback,
|
||||
final LogCallback logCallback,
|
||||
final StatisticsCallback statisticsCallback) {
|
||||
return executeAsync(FFmpegKit.parseArguments(command), executeCallback, logCallback, statisticsCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>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
|
||||
*/
|
||||
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);
|
||||
|
||||
FFmpegKitConfig.asyncFFprobeExecute(session);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>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
|
||||
* @param executor executor 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 Executor executor) {
|
||||
final FFprobeSession session = new FFprobeSession(arguments, executeCallback, null, null);
|
||||
|
||||
AsyncFFprobeExecuteTask asyncFFprobeExecuteTask = new AsyncFFprobeExecuteTask(session);
|
||||
executor.execute(asyncFFprobeExecuteTask);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>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
|
||||
* @param executor executor 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 Executor executor) {
|
||||
final FFprobeSession session = new FFprobeSession(arguments, executeCallback, logCallback, statisticsCallback);
|
||||
|
||||
AsyncFFprobeExecuteTask asyncFFprobeExecuteTask = new AsyncFFprobeExecuteTask(session);
|
||||
executor.execute(asyncFFprobeExecuteTask);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns media information for the given 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns media information for the given path asynchronously.
|
||||
*
|
||||
* @param path path or uri of a media file
|
||||
* @param executeCallback callback that will be notified 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);
|
||||
|
||||
FFmpegKitConfig.asyncGetMediaInformationExecute(session);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns media information for the given 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
|
||||
* @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 MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback, logCallback, statisticsCallback);
|
||||
|
||||
FFmpegKitConfig.asyncGetMediaInformationExecute(session);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns media information for the given 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
|
||||
* @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);
|
||||
|
||||
AsyncGetMediaInformationTask asyncGetMediaInformationTask = new AsyncGetMediaInformationTask(session);
|
||||
executor.execute(asyncGetMediaInformationTask);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns media information for the given 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
|
||||
* @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 MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback, logCallback, statisticsCallback);
|
||||
|
||||
AsyncGetMediaInformationTask asyncGetMediaInformationTask = new AsyncGetMediaInformationTask(session);
|
||||
executor.execute(asyncGetMediaInformationTask);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns media information for the given command.
|
||||
*
|
||||
* <p>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 command to execute
|
||||
* @return media information
|
||||
* @since 4.3.3
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
public static MediaInformation getMediaInformationFromCommand(final String command) {
|
||||
return getMediaInformationFromCommandArguments(FFmpegKit.parseArguments(command));
|
||||
public static MediaInformationSession getMediaInformationFromCommand(final String command) {
|
||||
return getMediaInformationFromCommandArguments(FFmpegKit.parseArguments(command), null, null, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Returns media information for given file.
|
||||
* <p>Returns media information for the given command.
|
||||
*
|
||||
* <p>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
|
||||
* @return media information
|
||||
* @since 3.0
|
||||
* @deprecated this method is deprecated since v4.3.1. You can still use this method but
|
||||
* <code>timeout</code> parameter is not effective anymore.
|
||||
* @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
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
public static MediaInformation getMediaInformation(final String path, final Long timeout) {
|
||||
return getMediaInformation(path);
|
||||
public static MediaInformationSession getMediaInformationFromCommand(final String command,
|
||||
final ExecuteCallback executeCallback,
|
||||
final LogCallback logCallback,
|
||||
final StatisticsCallback statisticsCallback) {
|
||||
return getMediaInformationFromCommandArguments(FFmpegKit.parseArguments(command), executeCallback, logCallback, statisticsCallback);
|
||||
}
|
||||
|
||||
private static MediaInformation getMediaInformationFromCommandArguments(final String[] arguments) {
|
||||
final int rc = execute(arguments);
|
||||
private static MediaInformationSession getMediaInformationFromCommandArguments(final String[] arguments,
|
||||
final ExecuteCallback executeCallback,
|
||||
final LogCallback logCallback,
|
||||
final StatisticsCallback statisticsCallback) {
|
||||
final MediaInformationSession session = new MediaInformationSession(arguments, executeCallback, logCallback, statisticsCallback);
|
||||
|
||||
if (rc == 0) {
|
||||
return MediaInformationParser.from(FFmpegKitConfig.getLastCommandOutput());
|
||||
} else {
|
||||
Log.w(FFmpegKitConfig.TAG, FFmpegKitConfig.getLastCommandOutput());
|
||||
return null;
|
||||
}
|
||||
FFmpegKitConfig.getMediaInformationExecute(session);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.arthenica.ffmpegkit;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* <p>An FFprobe execute session.
|
||||
*/
|
||||
public class FFprobeSession extends AbstractSession implements Session {
|
||||
|
||||
public FFprobeSession(final String[] arguments,
|
||||
final ExecuteCallback executeCallback,
|
||||
final LogCallback logCallback,
|
||||
final StatisticsCallback statisticsCallback) {
|
||||
super(arguments, executeCallback, logCallback, statisticsCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Queue<Statistics> getStatistics() {
|
||||
return new LinkedList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<Statistics> getStatisticsAsStream() {
|
||||
return new LinkedList<Statistics>().stream();
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFFmpeg() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFFprobe() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
stringBuilder.append("FFprobeSession{");
|
||||
stringBuilder.append("sessionId=");
|
||||
stringBuilder.append(sessionId);
|
||||
stringBuilder.append(", createTime=");
|
||||
stringBuilder.append(createTime);
|
||||
stringBuilder.append(", startTime=");
|
||||
stringBuilder.append(startTime);
|
||||
stringBuilder.append(", endTime=");
|
||||
stringBuilder.append(endTime);
|
||||
stringBuilder.append(", arguments=");
|
||||
stringBuilder.append(FFmpegKit.argumentsToString(arguments));
|
||||
stringBuilder.append(", logs=");
|
||||
stringBuilder.append(getLogsAsString());
|
||||
stringBuilder.append(", state=");
|
||||
stringBuilder.append(state);
|
||||
stringBuilder.append(", returnCode=");
|
||||
stringBuilder.append(returnCode);
|
||||
stringBuilder.append(", failStackTrace=");
|
||||
stringBuilder.append('\'');
|
||||
stringBuilder.append(failStackTrace);
|
||||
stringBuilder.append('\'');
|
||||
stringBuilder.append('}');
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -20,7 +20,7 @@
|
|||
package com.arthenica.ffmpegkit;
|
||||
|
||||
/**
|
||||
* <p>Helper enumeration type for log levels.
|
||||
* <p>Enumeration type for log levels.
|
||||
*/
|
||||
public enum Level {
|
||||
|
||||
|
@ -79,7 +79,7 @@ public enum Level {
|
|||
*/
|
||||
AV_LOG_TRACE(56);
|
||||
|
||||
private int value;
|
||||
private final int value;
|
||||
|
||||
/**
|
||||
* <p>Returns enumeration defined by value.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -20,44 +20,43 @@
|
|||
package com.arthenica.ffmpegkit;
|
||||
|
||||
/**
|
||||
* <p>Logs for running executions.
|
||||
* <p>Log entry for an execute session.
|
||||
*/
|
||||
public class LogMessage {
|
||||
|
||||
private final long executionId;
|
||||
public class Log {
|
||||
private final long sessionId;
|
||||
private final Level level;
|
||||
private final String text;
|
||||
private final String message;
|
||||
|
||||
public LogMessage(final long executionId, final Level level, final String text) {
|
||||
this.executionId = executionId;
|
||||
public Log(final long sessionId, final Level level, final String message) {
|
||||
this.sessionId = sessionId;
|
||||
this.level = level;
|
||||
this.text = text;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public long getExecutionId() {
|
||||
return executionId;
|
||||
public long getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public Level getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
stringBuilder.append("LogMessage{");
|
||||
stringBuilder.append("executionId=");
|
||||
stringBuilder.append(executionId);
|
||||
stringBuilder.append("Log{");
|
||||
stringBuilder.append("sessionId=");
|
||||
stringBuilder.append(sessionId);
|
||||
stringBuilder.append(", level=");
|
||||
stringBuilder.append(level);
|
||||
stringBuilder.append(", text=");
|
||||
stringBuilder.append(", message=");
|
||||
stringBuilder.append("\'");
|
||||
stringBuilder.append(text);
|
||||
stringBuilder.append(message);
|
||||
stringBuilder.append('\'');
|
||||
stringBuilder.append('}');
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -20,11 +20,16 @@
|
|||
package com.arthenica.ffmpegkit;
|
||||
|
||||
/**
|
||||
* <p>Represents a callback function to receive logs from running executions
|
||||
* <p>Callback function to receive logs for executions.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface LogCallback {
|
||||
|
||||
void apply(final LogMessage message);
|
||||
/**
|
||||
* <p>Called when a log entry is received.
|
||||
*
|
||||
* @param log log entry
|
||||
*/
|
||||
void apply(final Log log);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -28,15 +28,16 @@ import java.util.List;
|
|||
*/
|
||||
public class MediaInformation {
|
||||
|
||||
private static final String KEY_MEDIA_PROPERTIES = "format";
|
||||
private static final String KEY_FILENAME = "filename";
|
||||
private static final String KEY_FORMAT = "format_name";
|
||||
private static final String KEY_FORMAT_LONG = "format_long_name";
|
||||
private static final String KEY_START_TIME = "start_time";
|
||||
private static final String KEY_DURATION = "duration";
|
||||
private static final String KEY_SIZE = "size";
|
||||
private static final String KEY_BIT_RATE = "bit_rate";
|
||||
private static final String KEY_TAGS = "tags";
|
||||
/* COMMON KEYS */
|
||||
public static final String KEY_MEDIA_PROPERTIES = "format";
|
||||
public static final String KEY_FILENAME = "filename";
|
||||
public static final String KEY_FORMAT = "format_name";
|
||||
public static final String KEY_FORMAT_LONG = "format_long_name";
|
||||
public static final String KEY_START_TIME = "start_time";
|
||||
public static final String KEY_DURATION = "duration";
|
||||
public static final String KEY_SIZE = "size";
|
||||
public static final String KEY_BIT_RATE = "bit_rate";
|
||||
public static final String KEY_TAGS = "tags";
|
||||
|
||||
/**
|
||||
* Stores all properties.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -21,6 +21,8 @@ package com.arthenica.ffmpegkit;
|
|||
|
||||
import android.util.Log;
|
||||
|
||||
import com.arthenica.smartexception.java.Exceptions;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
@ -28,12 +30,14 @@ import org.json.JSONObject;
|
|||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Helper class for parsing {@link MediaInformation}.
|
||||
* Parser for {@link MediaInformation}.
|
||||
*/
|
||||
public class MediaInformationParser {
|
||||
|
||||
/**
|
||||
* Extracts MediaInformation from the given ffprobe json output.
|
||||
* Extracts <code>MediaInformation</code> 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
|
||||
* @return created {@link MediaInformation} instance of null if a parsing error occurs
|
||||
|
@ -42,8 +46,7 @@ public class MediaInformationParser {
|
|||
try {
|
||||
return fromWithError(ffprobeJsonOutput);
|
||||
} catch (JSONException e) {
|
||||
Log.e(FFmpegKitConfig.TAG, "MediaInformation parsing failed.", e);
|
||||
e.printStackTrace();
|
||||
Log.e(FFmpegKitConfig.TAG, String.format("MediaInformation parsing failed.%s", Exceptions.getStackTraceString(e)));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.arthenica.ffmpegkit;
|
||||
|
||||
/**
|
||||
* <p>A custom FFprobe execute session, which produces a <code>MediaInformation</code> object
|
||||
* using the output of the execution.
|
||||
*/
|
||||
public class MediaInformationSession extends FFprobeSession implements Session {
|
||||
private MediaInformation mediaInformation;
|
||||
|
||||
public MediaInformationSession(final String[] arguments,
|
||||
final ExecuteCallback executeCallback,
|
||||
final LogCallback logCallback,
|
||||
final StatisticsCallback statisticsCallback) {
|
||||
super(arguments, executeCallback, logCallback, statisticsCallback);
|
||||
}
|
||||
|
||||
public MediaInformation getMediaInformation() {
|
||||
return mediaInformation;
|
||||
}
|
||||
|
||||
public void setMediaInformation(MediaInformation mediaInformation) {
|
||||
this.mediaInformation = mediaInformation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
stringBuilder.append("MediaInformationSession{");
|
||||
stringBuilder.append("sessionId=");
|
||||
stringBuilder.append(sessionId);
|
||||
stringBuilder.append(", createTime=");
|
||||
stringBuilder.append(createTime);
|
||||
stringBuilder.append(", startTime=");
|
||||
stringBuilder.append(startTime);
|
||||
stringBuilder.append(", endTime=");
|
||||
stringBuilder.append(endTime);
|
||||
stringBuilder.append(", arguments=");
|
||||
stringBuilder.append(FFmpegKit.argumentsToString(arguments));
|
||||
stringBuilder.append(", logs=");
|
||||
stringBuilder.append(getLogsAsString());
|
||||
stringBuilder.append(", state=");
|
||||
stringBuilder.append(state);
|
||||
stringBuilder.append(", returnCode=");
|
||||
stringBuilder.append(returnCode);
|
||||
stringBuilder.append(", failStackTrace=");
|
||||
stringBuilder.append('\'');
|
||||
stringBuilder.append(failStackTrace);
|
||||
stringBuilder.append('\'');
|
||||
stringBuilder.append('}');
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -24,7 +24,7 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Provides helper methods to extract binary package information.
|
||||
* <p>Helper class to extract binary package information.
|
||||
*/
|
||||
class Packages {
|
||||
|
||||
|
@ -39,7 +39,6 @@ class Packages {
|
|||
supportedExternalLibraries.add("gnutls");
|
||||
supportedExternalLibraries.add("kvazaar");
|
||||
supportedExternalLibraries.add("mp3lame");
|
||||
supportedExternalLibraries.add("libaom");
|
||||
supportedExternalLibraries.add("libass");
|
||||
supportedExternalLibraries.add("iconv");
|
||||
supportedExternalLibraries.add("libilbc");
|
||||
|
@ -137,7 +136,6 @@ class Packages {
|
|||
externalLibraryList.contains("gnutls") &&
|
||||
externalLibraryList.contains("kvazaar") &&
|
||||
externalLibraryList.contains("mp3lame") &&
|
||||
externalLibraryList.contains("libaom") &&
|
||||
externalLibraryList.contains("libass") &&
|
||||
externalLibraryList.contains("iconv") &&
|
||||
externalLibraryList.contains("libilbc") &&
|
||||
|
@ -172,7 +170,6 @@ class Packages {
|
|||
externalLibraryList.contains("gnutls") &&
|
||||
externalLibraryList.contains("kvazaar") &&
|
||||
externalLibraryList.contains("mp3lame") &&
|
||||
externalLibraryList.contains("libaom") &&
|
||||
externalLibraryList.contains("libass") &&
|
||||
externalLibraryList.contains("iconv") &&
|
||||
externalLibraryList.contains("libilbc") &&
|
||||
|
@ -200,7 +197,6 @@ class Packages {
|
|||
externalLibraryList.contains("freetype") &&
|
||||
externalLibraryList.contains("fribidi") &&
|
||||
externalLibraryList.contains("kvazaar") &&
|
||||
externalLibraryList.contains("libaom") &&
|
||||
externalLibraryList.contains("libass") &&
|
||||
externalLibraryList.contains("iconv") &&
|
||||
externalLibraryList.contains("libtheora") &&
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Taner Sener
|
||||
* Copyright (c) 2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -19,32 +19,24 @@
|
|||
|
||||
package com.arthenica.ffmpegkit;
|
||||
|
||||
import java.util.Date;
|
||||
public class ReturnCode {
|
||||
|
||||
/**
|
||||
* <p>Represents an ongoing FFmpeg execution.
|
||||
*/
|
||||
public class FFmpegExecution {
|
||||
private final Date startTime;
|
||||
private final long executionId;
|
||||
private final String command;
|
||||
public static int NOT_SET = -999;
|
||||
|
||||
public FFmpegExecution(final long executionId, final String[] arguments) {
|
||||
this.startTime = new Date();
|
||||
this.executionId = executionId;
|
||||
this.command = FFmpegKit.argumentsToString(arguments);
|
||||
public static int SUCCESS = 0;
|
||||
|
||||
public static int CANCEL = 255;
|
||||
|
||||
public static boolean isSuccess(final int returnCode) {
|
||||
return (returnCode == SUCCESS);
|
||||
}
|
||||
|
||||
public Date getStartTime() {
|
||||
return startTime;
|
||||
public static boolean isFailure(final int returnCode) {
|
||||
return (returnCode != NOT_SET) && (returnCode != SUCCESS) && (returnCode != CANCEL);
|
||||
}
|
||||
|
||||
public long getExecutionId() {
|
||||
return executionId;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return command;
|
||||
public static boolean isCancel(final int returnCode) {
|
||||
return (returnCode == CANCEL);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.arthenica.ffmpegkit;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* <p>Interface for ffmpeg and ffprobe execute sessions.
|
||||
*/
|
||||
public interface Session {
|
||||
|
||||
ExecuteCallback getExecuteCallback();
|
||||
|
||||
LogCallback getLogCallback();
|
||||
|
||||
StatisticsCallback getStatisticsCallback();
|
||||
|
||||
long getSessionId();
|
||||
|
||||
Date getCreateTime();
|
||||
|
||||
Date getStartTime();
|
||||
|
||||
Date getEndTime();
|
||||
|
||||
long getDuration();
|
||||
|
||||
String[] getArguments();
|
||||
|
||||
String getCommand();
|
||||
|
||||
Queue<Log> getLogs();
|
||||
|
||||
Stream<Log> getLogsAsStream();
|
||||
|
||||
String getLogsAsString();
|
||||
|
||||
Queue<Statistics> getStatistics();
|
||||
|
||||
Stream<Statistics> getStatisticsAsStream();
|
||||
|
||||
SessionState getState();
|
||||
|
||||
int getReturnCode();
|
||||
|
||||
String getFailStackTrace();
|
||||
|
||||
void addLog(final Log log);
|
||||
|
||||
void addStatistics(final Statistics statistics);
|
||||
|
||||
Future<?> getFuture();
|
||||
|
||||
void setFuture(final Future<?> future);
|
||||
|
||||
void startRunning();
|
||||
|
||||
void complete(final int returnCode);
|
||||
|
||||
void fail(final Exception exception);
|
||||
|
||||
boolean isFFmpeg();
|
||||
|
||||
boolean isFFprobe();
|
||||
|
||||
void cancel();
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -19,12 +19,9 @@
|
|||
|
||||
package com.arthenica.ffmpegkit;
|
||||
|
||||
/**
|
||||
* <p>Represents a callback function to receive asynchronous getMediaInformation result.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface GetMediaInformationCallback {
|
||||
|
||||
void apply(MediaInformation mediaInformation);
|
||||
|
||||
public enum SessionState {
|
||||
CREATED,
|
||||
RUNNING,
|
||||
FAILED,
|
||||
COMPLETED
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Taner Sener
|
||||
* Copyright (c) 2020-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -30,7 +30,7 @@ public enum Signal {
|
|||
SIGTERM(15),
|
||||
SIGXCPU(24);
|
||||
|
||||
private int value;
|
||||
private final int value;
|
||||
|
||||
Signal(int value) {
|
||||
this.value = value;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -20,11 +20,10 @@
|
|||
package com.arthenica.ffmpegkit;
|
||||
|
||||
/**
|
||||
* <p>Statistics for running executions.
|
||||
* <p>Statistics entry for an FFmpeg execute session.
|
||||
*/
|
||||
public class Statistics {
|
||||
|
||||
private long executionId;
|
||||
private long sessionId;
|
||||
private int videoFrameNumber;
|
||||
private float videoFps;
|
||||
private float videoQuality;
|
||||
|
@ -34,7 +33,7 @@ public class Statistics {
|
|||
private double speed;
|
||||
|
||||
public Statistics() {
|
||||
executionId = 0;
|
||||
sessionId = 0;
|
||||
videoFrameNumber = 0;
|
||||
videoFps = 0;
|
||||
videoQuality = 0;
|
||||
|
@ -44,8 +43,8 @@ public class Statistics {
|
|||
speed = 0;
|
||||
}
|
||||
|
||||
public Statistics(long executionId, int videoFrameNumber, float videoFps, float videoQuality, long size, int time, double bitrate, double speed) {
|
||||
this.executionId = executionId;
|
||||
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;
|
||||
this.videoFps = videoFps;
|
||||
this.videoQuality = videoQuality;
|
||||
|
@ -55,44 +54,12 @@ public class Statistics {
|
|||
this.speed = speed;
|
||||
}
|
||||
|
||||
public void update(final Statistics newStatistics) {
|
||||
if (newStatistics != null) {
|
||||
this.executionId = newStatistics.getExecutionId();
|
||||
if (newStatistics.getVideoFrameNumber() > 0) {
|
||||
this.videoFrameNumber = newStatistics.getVideoFrameNumber();
|
||||
}
|
||||
if (newStatistics.getVideoFps() > 0) {
|
||||
this.videoFps = newStatistics.getVideoFps();
|
||||
}
|
||||
|
||||
if (newStatistics.getVideoQuality() > 0) {
|
||||
this.videoQuality = newStatistics.getVideoQuality();
|
||||
}
|
||||
|
||||
if (newStatistics.getSize() > 0) {
|
||||
this.size = newStatistics.getSize();
|
||||
}
|
||||
|
||||
if (newStatistics.getTime() > 0) {
|
||||
this.time = newStatistics.getTime();
|
||||
}
|
||||
|
||||
if (newStatistics.getBitrate() > 0) {
|
||||
this.bitrate = newStatistics.getBitrate();
|
||||
}
|
||||
|
||||
if (newStatistics.getSpeed() > 0) {
|
||||
this.speed = newStatistics.getSpeed();
|
||||
}
|
||||
}
|
||||
public long getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public long getExecutionId() {
|
||||
return executionId;
|
||||
}
|
||||
|
||||
public void setExecutionId(long executionId) {
|
||||
this.executionId = executionId;
|
||||
public void setSessionId(long sessionId) {
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
public int getVideoFrameNumber() {
|
||||
|
@ -156,8 +123,8 @@ public class Statistics {
|
|||
final StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
stringBuilder.append("Statistics{");
|
||||
stringBuilder.append("executionId=");
|
||||
stringBuilder.append(executionId);
|
||||
stringBuilder.append("sessionId=");
|
||||
stringBuilder.append(sessionId);
|
||||
stringBuilder.append(", videoFrameNumber=");
|
||||
stringBuilder.append(videoFrameNumber);
|
||||
stringBuilder.append(", videoFps=");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -20,11 +20,16 @@
|
|||
package com.arthenica.ffmpegkit;
|
||||
|
||||
/**
|
||||
* <p>Represents a callback function to receive statistics from running executions.
|
||||
* <p>Callback function to receive statistics for executions.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface StatisticsCallback {
|
||||
|
||||
/**
|
||||
* <p>Called when a statistics entry is received.
|
||||
*
|
||||
* @param statistics statistics entry
|
||||
*/
|
||||
void apply(final Statistics statistics);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Taner Sener
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
|
@ -26,6 +26,7 @@ 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";
|
||||
|
|
|
@ -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 Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.arthenica.ffmpegkit;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -61,12 +61,12 @@ include $(BUILD_SHARED_LIBRARY)
|
|||
|
||||
$(call import-module, cpu-features)
|
||||
|
||||
MY_SRC_FILES := ffmpegkit.c ffprobekit.c ffmpegkit_exception.c fftools_cmdutils.c fftools_ffmpeg.c fftools_ffprobe.c fftools_ffmpeg_opt.c fftools_ffmpeg_hw.c fftools_ffmpeg_filter.c saf_wrapper.c
|
||||
|
||||
ifeq ($(TARGET_PLATFORM),android-16)
|
||||
MY_SRC_FILES := ffmpegkit.c ffprobekit.c android_lts_support.c ffmpegkit_exception.c fftools_cmdutils.c fftools_ffmpeg.c fftools_ffprobe.c fftools_ffmpeg_opt.c fftools_ffmpeg_hw.c fftools_ffmpeg_filter.c
|
||||
MY_SRC_FILES += android_lts_support.c
|
||||
else ifeq ($(TARGET_PLATFORM),android-17)
|
||||
MY_SRC_FILES := ffmpegkit.c ffprobekit.c android_lts_support.c ffmpegkit_exception.c fftools_cmdutils.c fftools_ffmpeg.c fftools_ffprobe.c fftools_ffmpeg_opt.c fftools_ffmpeg_hw.c fftools_ffmpeg_filter.c
|
||||
else
|
||||
MY_SRC_FILES := ffmpegkit.c ffprobekit.c ffmpegkit_exception.c fftools_cmdutils.c fftools_ffmpeg.c fftools_ffprobe.c fftools_ffmpeg_opt.c fftools_ffmpeg_hw.c fftools_ffmpeg_filter.c
|
||||
MY_SRC_FILES += android_lts_support.c
|
||||
endif
|
||||
|
||||
MY_CFLAGS := -Wall -Werror -Wno-unused-parameter -Wno-switch -Wno-sign-compare
|
||||
|
|
|
@ -39,6 +39,7 @@ task javadoc(type: Javadoc) {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.arthenica:smart-exception-java:0.1.0'
|
||||
testImplementation "androidx.test.ext:junit:1.1.2"
|
||||
testImplementation "org.json:json:20190722"
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ task javadoc(type: Javadoc) {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.arthenica:smart-exception-java:0.1.0'
|
||||
testImplementation "androidx.test.ext:junit:1.1.2"
|
||||
testImplementation "org.json:json:20190722"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user