fix android runtime errors
This commit is contained in:
parent
90b5fca4ee
commit
18a6a9c066
@ -50,6 +50,7 @@ struct CallbackData {
|
|||||||
/** Session map variables */
|
/** Session map variables */
|
||||||
const int SESSION_MAP_SIZE = 1000;
|
const int SESSION_MAP_SIZE = 1000;
|
||||||
static volatile int sessionMap[SESSION_MAP_SIZE];
|
static volatile int sessionMap[SESSION_MAP_SIZE];
|
||||||
|
static volatile int sessionInTransitMessageCountMap[SESSION_MAP_SIZE];
|
||||||
static pthread_mutex_t sessionMapMutex;
|
static pthread_mutex_t sessionMapMutex;
|
||||||
|
|
||||||
/** Redirection control variables */
|
/** Redirection control variables */
|
||||||
@ -113,11 +114,12 @@ JNINativeMethod configMethods[] = {
|
|||||||
{"getNativeVersion", "()Ljava/lang/String;", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeVersion},
|
{"getNativeVersion", "()Ljava/lang/String;", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeVersion},
|
||||||
{"nativeFFmpegExecute", "(J[Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute},
|
{"nativeFFmpegExecute", "(J[Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute},
|
||||||
{"nativeFFmpegCancel", "(J)V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegCancel},
|
{"nativeFFmpegCancel", "(J)V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegCancel},
|
||||||
{"nativeFFprobeExecute", "([Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprobeExecute},
|
{"nativeFFprobeExecute", "(J[Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprobeExecute},
|
||||||
{"registerNewNativeFFmpegPipe", "(Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_registerNewNativeFFmpegPipe},
|
{"registerNewNativeFFmpegPipe", "(Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_registerNewNativeFFmpegPipe},
|
||||||
{"getNativeBuildDate", "()Ljava/lang/String;", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeBuildDate},
|
{"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},
|
{"setNativeEnvironmentVariable", "(Ljava/lang/String;Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeEnvironmentVariable},
|
||||||
{"ignoreNativeSignal", "(I)V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal}
|
{"ignoreNativeSignal", "(I)V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal},
|
||||||
|
{"messagesInTransmit", "(J)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_messagesInTransmit}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Forward declaration for function defined in fftools_ffmpeg.c */
|
/** Forward declaration for function defined in fftools_ffmpeg.c */
|
||||||
@ -213,7 +215,7 @@ void monitorInit() {
|
|||||||
pthread_condattr_destroy(&cattributes);
|
pthread_condattr_destroy(&cattributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void executionMapLockInit() {
|
void sessionMapLockInit() {
|
||||||
pthread_mutexattr_t attributes;
|
pthread_mutexattr_t attributes;
|
||||||
pthread_mutexattr_init(&attributes);
|
pthread_mutexattr_init(&attributes);
|
||||||
pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
|
pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
|
||||||
@ -231,7 +233,7 @@ void monitorUnInit() {
|
|||||||
pthread_cond_destroy(&monitorCondition);
|
pthread_cond_destroy(&monitorCondition);
|
||||||
}
|
}
|
||||||
|
|
||||||
void executionMapLockUnInit() {
|
void sessionMapLockUnInit() {
|
||||||
pthread_mutex_destroy(&sessionMapMutex);
|
pthread_mutex_destroy(&sessionMapMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,6 +316,9 @@ void logCallbackDataAdd(int level, AVBPrint *data) {
|
|||||||
callbackDataTail = newData;
|
callbackDataTail = newData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int key = sessionId % SESSION_MAP_SIZE;
|
||||||
|
sessionInTransitMessageCountMap[key] += 1;
|
||||||
|
|
||||||
mutexUnlock();
|
mutexUnlock();
|
||||||
|
|
||||||
monitorNotify();
|
monitorNotify();
|
||||||
@ -356,6 +361,9 @@ void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_
|
|||||||
callbackDataTail = newData;
|
callbackDataTail = newData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int key = sessionId % SESSION_MAP_SIZE;
|
||||||
|
sessionInTransitMessageCountMap[key] += 1;
|
||||||
|
|
||||||
mutexUnlock();
|
mutexUnlock();
|
||||||
|
|
||||||
monitorNotify();
|
monitorNotify();
|
||||||
@ -456,6 +464,20 @@ int cancelRequested(long id) {
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the number of messages in transmit for this session.
|
||||||
|
*
|
||||||
|
* @param id session id
|
||||||
|
*/
|
||||||
|
void resetMessagesInTransmit(long id) {
|
||||||
|
mutexLock();
|
||||||
|
|
||||||
|
int key = id % SESSION_MAP_SIZE;
|
||||||
|
sessionInTransitMessageCountMap[key] = 0;
|
||||||
|
|
||||||
|
mutexUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback function for FFmpeg logs.
|
* Callback function for FFmpeg logs.
|
||||||
*
|
*
|
||||||
@ -566,6 +588,9 @@ void *callbackThreadFunction() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int key = callbackData->sessionId % SESSION_MAP_SIZE;
|
||||||
|
sessionInTransitMessageCountMap[key] -= 1;
|
||||||
|
|
||||||
// CLEAN STRUCT
|
// CLEAN STRUCT
|
||||||
callbackData->next = NULL;
|
callbackData->next = NULL;
|
||||||
av_free(callbackData);
|
av_free(callbackData);
|
||||||
@ -611,7 +636,7 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|||||||
return JNI_FALSE;
|
return JNI_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*env)->RegisterNatives(env, localConfigClass, configMethods, 13) < 0) {
|
if ((*env)->RegisterNatives(env, localConfigClass, configMethods, 14) < 0) {
|
||||||
LOGE("OnLoad failed to RegisterNatives for class %s.\n", configClassName);
|
LOGE("OnLoad failed to RegisterNatives for class %s.\n", configClassName);
|
||||||
return JNI_FALSE;
|
return JNI_FALSE;
|
||||||
}
|
}
|
||||||
@ -664,7 +689,7 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|||||||
|
|
||||||
mutexInit();
|
mutexInit();
|
||||||
monitorInit();
|
monitorInit();
|
||||||
executionMapLockInit();
|
sessionMapLockInit();
|
||||||
|
|
||||||
return JNI_VERSION_1_6;
|
return JNI_VERSION_1_6;
|
||||||
}
|
}
|
||||||
@ -805,10 +830,12 @@ JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpeg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// REGISTER THE ID BEFORE STARTING EXECUTION
|
// REGISTER THE ID BEFORE STARTING THE EXECUTION
|
||||||
sessionId = (long) id;
|
sessionId = (long) id;
|
||||||
addSession((long) id);
|
addSession((long) id);
|
||||||
|
|
||||||
|
resetMessagesInTransmit(sessionId);
|
||||||
|
|
||||||
// RUN
|
// RUN
|
||||||
int retCode = ffmpeg_execute(argumentCount, argv);
|
int retCode = ffmpeg_execute(argumentCount, argv);
|
||||||
|
|
||||||
@ -907,3 +934,22 @@ JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNative
|
|||||||
handleSIGPIPE = 0;
|
handleSIGPIPE = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of native messages which are not transmitted to the Java callbacks for the
|
||||||
|
* given session.
|
||||||
|
*
|
||||||
|
* @param env pointer to native method interface
|
||||||
|
* @param object reference to the class on which this method is invoked
|
||||||
|
* @param id session id
|
||||||
|
*/
|
||||||
|
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_messagesInTransmit(JNIEnv *env, jclass object, jlong id) {
|
||||||
|
mutexLock();
|
||||||
|
|
||||||
|
int key = id % SESSION_MAP_SIZE;
|
||||||
|
int count = sessionInTransitMessageCountMap[key];
|
||||||
|
|
||||||
|
mutexUnlock();
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
@ -131,4 +131,11 @@ JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeEnvi
|
|||||||
*/
|
*/
|
||||||
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal(JNIEnv *env, jclass object, jint signum);
|
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal(JNIEnv *env, jclass object, jint signum);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: com_arthenica_ffmpegkit_FFmpegKitConfig
|
||||||
|
* Method: messagesInTransmit
|
||||||
|
* Signature: (J)I
|
||||||
|
*/
|
||||||
|
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_messagesInTransmit(JNIEnv *env, jclass object, jlong id);
|
||||||
|
|
||||||
#endif /* FFMPEG_KIT_H */
|
#endif /* FFMPEG_KIT_H */
|
@ -33,6 +33,7 @@ extern int configuredLogLevel;
|
|||||||
extern __thread volatile long sessionId;
|
extern __thread volatile long sessionId;
|
||||||
extern void addSession(long id);
|
extern void addSession(long id);
|
||||||
extern void removeSession(long id);
|
extern void removeSession(long id);
|
||||||
|
extern void resetMessagesInTransmit(long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronously executes FFprobe natively with arguments provided.
|
* Synchronously executes FFprobe natively with arguments provided.
|
||||||
@ -76,10 +77,12 @@ JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprob
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// REGISTER THE ID BEFORE STARTING EXECUTION
|
// REGISTER THE ID BEFORE STARTING THE EXECUTION
|
||||||
sessionId = (long) id;
|
sessionId = (long) id;
|
||||||
addSession((long) id);
|
addSession((long) id);
|
||||||
|
|
||||||
|
resetMessagesInTransmit(sessionId);
|
||||||
|
|
||||||
// RUN
|
// RUN
|
||||||
int retCode = ffprobe_execute(argumentCount, argv);
|
int retCode = ffprobe_execute(argumentCount, argv);
|
||||||
|
|
||||||
|
@ -1846,12 +1846,6 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
|
|||||||
int ret;
|
int ret;
|
||||||
float t;
|
float t;
|
||||||
|
|
||||||
// FORWARD IT BEFORE PROCESSING
|
|
||||||
forward_report(is_last_report, timer_start, cur_time);
|
|
||||||
|
|
||||||
if (!print_stats && !is_last_report && !progress_avio)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!is_last_report) {
|
if (!is_last_report) {
|
||||||
if (last_time == -1) {
|
if (last_time == -1) {
|
||||||
last_time = cur_time;
|
last_time = cur_time;
|
||||||
@ -1862,6 +1856,11 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
|
|||||||
last_time = cur_time;
|
last_time = cur_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forward_report(is_last_report, timer_start, cur_time);
|
||||||
|
|
||||||
|
if (!print_stats && !is_last_report && !progress_avio)
|
||||||
|
return;
|
||||||
|
|
||||||
t = (cur_time-timer_start) / 1000000.0;
|
t = (cur_time-timer_start) / 1000000.0;
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,22 +22,22 @@ package com.arthenica.ffmpegkit;
|
|||||||
import com.arthenica.smartexception.java.Exceptions;
|
import com.arthenica.smartexception.java.Exceptions;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
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 {
|
public abstract class AbstractSession implements Session {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates ids for execute sessions.
|
* Generates ids for execute sessions.
|
||||||
*/
|
*/
|
||||||
private static final AtomicLong sessionIdGenerator = new AtomicLong(1);
|
protected static final AtomicLong sessionIdGenerator = new AtomicLong(1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines how long default `getAll` methods wait.
|
||||||
|
*/
|
||||||
|
protected static final int DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT = 5000;
|
||||||
|
|
||||||
protected final ExecuteCallback executeCallback;
|
protected final ExecuteCallback executeCallback;
|
||||||
protected final LogCallback logCallback;
|
protected final LogCallback logCallback;
|
||||||
@ -52,11 +52,13 @@ public abstract class AbstractSession implements Session {
|
|||||||
protected SessionState state;
|
protected SessionState state;
|
||||||
protected int returnCode;
|
protected int returnCode;
|
||||||
protected String failStackTrace;
|
protected String failStackTrace;
|
||||||
|
protected final LogRedirectionStrategy logRedirectionStrategy;
|
||||||
|
|
||||||
public AbstractSession(final String[] arguments,
|
public AbstractSession(final String[] arguments,
|
||||||
final ExecuteCallback executeCallback,
|
final ExecuteCallback executeCallback,
|
||||||
final LogCallback logCallback,
|
final LogCallback logCallback,
|
||||||
final StatisticsCallback statisticsCallback) {
|
final StatisticsCallback statisticsCallback,
|
||||||
|
final LogRedirectionStrategy logRedirectionStrategy) {
|
||||||
this.sessionId = sessionIdGenerator.getAndIncrement();
|
this.sessionId = sessionIdGenerator.getAndIncrement();
|
||||||
this.createTime = new Date();
|
this.createTime = new Date();
|
||||||
this.startTime = null;
|
this.startTime = null;
|
||||||
@ -69,36 +71,45 @@ public abstract class AbstractSession implements Session {
|
|||||||
this.state = SessionState.CREATED;
|
this.state = SessionState.CREATED;
|
||||||
this.returnCode = ReturnCode.NOT_SET;
|
this.returnCode = ReturnCode.NOT_SET;
|
||||||
this.failStackTrace = null;
|
this.failStackTrace = null;
|
||||||
|
this.logRedirectionStrategy = logRedirectionStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ExecuteCallback getExecuteCallback() {
|
public ExecuteCallback getExecuteCallback() {
|
||||||
return executeCallback;
|
return executeCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public LogCallback getLogCallback() {
|
public LogCallback getLogCallback() {
|
||||||
return logCallback;
|
return logCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public StatisticsCallback getStatisticsCallback() {
|
public StatisticsCallback getStatisticsCallback() {
|
||||||
return statisticsCallback;
|
return statisticsCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public long getSessionId() {
|
public long getSessionId() {
|
||||||
return sessionId;
|
return sessionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Date getCreateTime() {
|
public Date getCreateTime() {
|
||||||
return createTime;
|
return createTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Date getStartTime() {
|
public Date getStartTime() {
|
||||||
return startTime;
|
return startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Date getEndTime() {
|
public Date getEndTime() {
|
||||||
return endTime;
|
return endTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public long getDuration() {
|
public long getDuration() {
|
||||||
final Date startTime = this.startTime;
|
final Date startTime = this.startTime;
|
||||||
final Date endTime = this.endTime;
|
final Date endTime = this.endTime;
|
||||||
@ -109,85 +120,141 @@ public abstract class AbstractSession implements Session {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String[] getArguments() {
|
public String[] getArguments() {
|
||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getCommand() {
|
public String getCommand() {
|
||||||
return FFmpegKit.argumentsToString(arguments);
|
return FFmpegKit.argumentsToString(arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void waitForCallbackMessagesInTransmit(final int timeout) {
|
||||||
|
final long start = System.currentTimeMillis();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WE GIVE MAX 5 SECONDS TO TRANSMIT ALL NATIVE MESSAGES
|
||||||
|
*/
|
||||||
|
while (thereAreCallbackMessagesInTransmit() && (System.currentTimeMillis() < (start + timeout))) {
|
||||||
|
synchronized (this) {
|
||||||
|
try {
|
||||||
|
wait(100);
|
||||||
|
} catch (InterruptedException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Queue<Log> getAllLogs(final int waitTimeout) {
|
||||||
|
waitForCallbackMessagesInTransmit(waitTimeout);
|
||||||
|
|
||||||
|
if (thereAreCallbackMessagesInTransmit()) {
|
||||||
|
android.util.Log.i(FFmpegKitConfig.TAG, String.format("getAllLogs was asked to return all logs but there are still logs being transmitted for session id %d.", sessionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
return logs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Queue<Log> getAllLogs() {
|
||||||
|
return getAllLogs(DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Queue<Log> getLogs() {
|
public Queue<Log> getLogs() {
|
||||||
return logs;
|
return logs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream<Log> getLogsAsStream() {
|
@Override
|
||||||
return logs.stream();
|
public String getAllLogsAsString(final int waitTimeout) {
|
||||||
|
waitForCallbackMessagesInTransmit(waitTimeout);
|
||||||
|
|
||||||
|
if (thereAreCallbackMessagesInTransmit()) {
|
||||||
|
android.util.Log.i(FFmpegKitConfig.TAG, String.format("getAllLogsAsString was asked to return all logs but there are still logs being transmitted for session id %d.", sessionId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return getLogsAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAllLogsAsString() {
|
||||||
|
return getAllLogsAsString(DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getLogsAsString() {
|
public String getLogsAsString() {
|
||||||
final Optional<String> concatenatedStringOption = logs.stream().map(new Function<Log, String>() {
|
final StringBuilder concatenatedString = new StringBuilder();
|
||||||
@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>() {
|
for (Log log : logs) {
|
||||||
|
concatenatedString.append(log.getMessage());
|
||||||
@Override
|
|
||||||
public String get() {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return concatenatedString.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public SessionState getState() {
|
public SessionState getState() {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getReturnCode() {
|
public int getReturnCode() {
|
||||||
return returnCode;
|
return returnCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getFailStackTrace() {
|
public String getFailStackTrace() {
|
||||||
return failStackTrace;
|
return failStackTrace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LogRedirectionStrategy getLogRedirectionStrategy() {
|
||||||
|
return logRedirectionStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean thereAreCallbackMessagesInTransmit() {
|
||||||
|
return (FFmpegKitConfig.messagesInTransmit(sessionId) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void addLog(final Log log) {
|
public void addLog(final Log log) {
|
||||||
this.logs.add(log);
|
this.logs.add(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Future<?> getFuture() {
|
public Future<?> getFuture() {
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setFuture(final Future<?> future) {
|
public void setFuture(final Future<?> future) {
|
||||||
this.future = future;
|
this.future = future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void startRunning() {
|
public void startRunning() {
|
||||||
this.state = SessionState.RUNNING;
|
this.state = SessionState.RUNNING;
|
||||||
this.startTime = new Date();
|
this.startTime = new Date();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void complete(final int returnCode) {
|
public void complete(final int returnCode) {
|
||||||
this.returnCode = returnCode;
|
this.returnCode = returnCode;
|
||||||
this.state = SessionState.COMPLETED;
|
this.state = SessionState.COMPLETED;
|
||||||
this.endTime = new Date();
|
this.endTime = new Date();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void fail(final Exception exception) {
|
public void fail(final Exception exception) {
|
||||||
this.failStackTrace = Exceptions.getStackTraceString(exception);
|
this.failStackTrace = Exceptions.getStackTraceString(exception);
|
||||||
this.state = SessionState.FAILED;
|
this.state = SessionState.FAILED;
|
||||||
this.endTime = new Date();
|
this.endTime = new Date();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void cancel() {
|
public void cancel() {
|
||||||
if (state == SessionState.RUNNING) {
|
if (state == SessionState.RUNNING) {
|
||||||
FFmpegKit.cancel(sessionId);
|
FFmpegKit.cancel(sessionId);
|
||||||
|
@ -35,6 +35,11 @@ public class AsyncFFprobeExecuteTask implements Runnable {
|
|||||||
public void run() {
|
public void run() {
|
||||||
FFmpegKitConfig.ffprobeExecute(ffprobeSession);
|
FFmpegKitConfig.ffprobeExecute(ffprobeSession);
|
||||||
|
|
||||||
|
final ExecuteCallback globalExecuteCallbackFunction = FFmpegKitConfig.getGlobalExecuteCallbackFunction();
|
||||||
|
if (globalExecuteCallbackFunction != null) {
|
||||||
|
globalExecuteCallbackFunction.apply(ffprobeSession);
|
||||||
|
}
|
||||||
|
|
||||||
if (executeCallback != null) {
|
if (executeCallback != null) {
|
||||||
executeCallback.apply(ffprobeSession);
|
executeCallback.apply(ffprobeSession);
|
||||||
}
|
}
|
||||||
|
@ -25,15 +25,26 @@ package com.arthenica.ffmpegkit;
|
|||||||
public class AsyncGetMediaInformationTask implements Runnable {
|
public class AsyncGetMediaInformationTask implements Runnable {
|
||||||
private final MediaInformationSession mediaInformationSession;
|
private final MediaInformationSession mediaInformationSession;
|
||||||
private final ExecuteCallback executeCallback;
|
private final ExecuteCallback executeCallback;
|
||||||
|
private final Integer waitTimeout;
|
||||||
|
|
||||||
public AsyncGetMediaInformationTask(final MediaInformationSession mediaInformationSession) {
|
public AsyncGetMediaInformationTask(final MediaInformationSession mediaInformationSession) {
|
||||||
|
this(mediaInformationSession, AbstractSession.DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncGetMediaInformationTask(final MediaInformationSession mediaInformationSession, final Integer waitTimeout) {
|
||||||
this.mediaInformationSession = mediaInformationSession;
|
this.mediaInformationSession = mediaInformationSession;
|
||||||
this.executeCallback = mediaInformationSession.getExecuteCallback();
|
this.executeCallback = mediaInformationSession.getExecuteCallback();
|
||||||
|
this.waitTimeout = waitTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
FFmpegKitConfig.getMediaInformationExecute(mediaInformationSession);
|
FFmpegKitConfig.getMediaInformationExecute(mediaInformationSession, waitTimeout);
|
||||||
|
|
||||||
|
final ExecuteCallback globalExecuteCallbackFunction = FFmpegKitConfig.getGlobalExecuteCallbackFunction();
|
||||||
|
if (globalExecuteCallbackFunction != null) {
|
||||||
|
globalExecuteCallbackFunction.apply(mediaInformationSession);
|
||||||
|
}
|
||||||
|
|
||||||
if (executeCallback != null) {
|
if (executeCallback != null) {
|
||||||
executeCallback.apply(mediaInformationSession);
|
executeCallback.apply(mediaInformationSession);
|
||||||
|
@ -27,12 +27,12 @@ import java.util.concurrent.Executor;
|
|||||||
* <p>Main class for FFmpeg operations. Supports synchronous {@link #execute(String...)} and
|
* <p>Main class for FFmpeg operations. Supports synchronous {@link #execute(String...)} and
|
||||||
* asynchronous {@link #executeAsync(String, ExecuteCallback)} methods to execute FFmpeg commands.
|
* asynchronous {@link #executeAsync(String, ExecuteCallback)} methods to execute FFmpeg commands.
|
||||||
* <pre>
|
* <pre>
|
||||||
* int rc = FFmpeg.execute("-i file1.mp4 -c:v libxvid file1.avi");
|
* FFmpegSession session = FFmpeg.execute("-i file1.mp4 -c:v libxvid file1.avi");
|
||||||
* Log.i(Config.TAG, String.format("Command execution %s.", (rc == 0?"completed successfully":"failed with rc=" + rc));
|
* Log.i(Config.TAG, String.format("Command execution completed with %d.", session.getReturnCode());
|
||||||
* </pre>
|
* </pre>
|
||||||
* <pre>
|
* <pre>
|
||||||
* long executionId = FFmpeg.executeAsync("-i file1.mp4 -c:v libxvid file1.avi", executeCallback);
|
* FFmpegSession session = FFmpeg.executeAsync("-i file1.mp4 -c:v libxvid file1.avi", executeCallback);
|
||||||
* Log.i(Config.TAG, String.format("Asynchronous execution %d started.", executionId));
|
* Log.i(Config.TAG, String.format("Asynchronous session %d started.", session.getSessionId()));
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public class FFmpegKit {
|
public class FFmpegKit {
|
||||||
@ -231,17 +231,18 @@ public class FFmpegKit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Cancels the last execution started.
|
* <p>Cancels all ongoing executions.
|
||||||
*
|
*
|
||||||
* <p>This function does not wait for termination to complete and returns immediately.
|
* <p>This function does not wait for termination to complete and returns immediately.
|
||||||
*/
|
*/
|
||||||
public static void cancel() {
|
public static void cancel() {
|
||||||
Session lastSession = FFmpegKitConfig.getLastSession();
|
|
||||||
if (lastSession != null) {
|
/*
|
||||||
FFmpegKitConfig.nativeFFmpegCancel(lastSession.getSessionId());
|
* ZERO (0) IS A SPECIAL SESSION ID
|
||||||
} else {
|
* WHEN IT IS PASSED TO THIS METHOD, A SIGINT IS GENERATED WHICH CANCELS ALL ONGOING
|
||||||
android.util.Log.w(FFmpegKitConfig.TAG, "FFmpegKit cancel skipped. The last execution does not exist.");
|
* EXECUTIONS
|
||||||
}
|
*/
|
||||||
|
FFmpegKitConfig.nativeFFmpegCancel(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -249,7 +250,7 @@ public class FFmpegKit {
|
|||||||
*
|
*
|
||||||
* <p>This function does not wait for termination to complete and returns immediately.
|
* <p>This function does not wait for termination to complete and returns immediately.
|
||||||
*
|
*
|
||||||
* @param sessionId id of the session that will be stopped
|
* @param sessionId id of the session that will be cancelled
|
||||||
*/
|
*/
|
||||||
public static void cancel(final long sessionId) {
|
public static void cancel(final long sessionId) {
|
||||||
FFmpegKitConfig.nativeFFmpegCancel(sessionId);
|
FFmpegKitConfig.nativeFFmpegCancel(sessionId);
|
||||||
|
@ -45,10 +45,6 @@ import java.util.concurrent.Executors;
|
|||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>This class is used to configure FFmpegKit library and tools coming with it.
|
* <p>This class is used to configure FFmpegKit library and tools coming with it.
|
||||||
@ -85,11 +81,12 @@ public class FFmpegKitConfig {
|
|||||||
* Generates ids for named ffmpeg kit pipes.
|
* Generates ids for named ffmpeg kit pipes.
|
||||||
*/
|
*/
|
||||||
private static final AtomicLong pipeIndexGenerator;
|
private static final AtomicLong pipeIndexGenerator;
|
||||||
|
|
||||||
|
/* SESSION HISTORY VARIABLES */
|
||||||
|
private static int sessionHistorySize;
|
||||||
private static final Map<Long, Session> sessionHistoryMap;
|
private static final Map<Long, Session> sessionHistoryMap;
|
||||||
private static final Queue<Session> sessionHistoryQueue;
|
private static final Queue<Session> sessionHistoryQueue;
|
||||||
private static final Object sessionHistoryLock;
|
private static final Object sessionHistoryLock;
|
||||||
private static int asyncConcurrencyLimit;
|
|
||||||
private static final SparseArray<ParcelFileDescriptor> pfdMap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executor service for async executions.
|
* Executor service for async executions.
|
||||||
@ -99,9 +96,9 @@ public class FFmpegKitConfig {
|
|||||||
private static StatisticsCallback globalStatisticsCallbackFunction;
|
private static StatisticsCallback globalStatisticsCallbackFunction;
|
||||||
private static ExecuteCallback globalExecuteCallbackFunction;
|
private static ExecuteCallback globalExecuteCallbackFunction;
|
||||||
private static Level activeLogLevel;
|
private static Level activeLogLevel;
|
||||||
|
private static int asyncConcurrencyLimit;
|
||||||
/* SESSION HISTORY VARIABLES */
|
private static final SparseArray<ParcelFileDescriptor> pfdMap;
|
||||||
private static int sessionHistorySize;
|
private static LogRedirectionStrategy logRedirectionStrategy;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|
||||||
@ -192,6 +189,7 @@ public class FFmpegKitConfig {
|
|||||||
sessionHistoryLock = new Object();
|
sessionHistoryLock = new Object();
|
||||||
|
|
||||||
pfdMap = new SparseArray<>();
|
pfdMap = new SparseArray<>();
|
||||||
|
logRedirectionStrategy = LogRedirectionStrategy.PRINT_LOGS_WHEN_NO_CALLBACKS_DEFINED;
|
||||||
|
|
||||||
enableRedirection();
|
enableRedirection();
|
||||||
}
|
}
|
||||||
@ -236,6 +234,9 @@ public class FFmpegKitConfig {
|
|||||||
final Level level = Level.from(levelValue);
|
final Level level = Level.from(levelValue);
|
||||||
final String text = new String(logMessage);
|
final String text = new String(logMessage);
|
||||||
final Log log = new Log(sessionId, level, text);
|
final Log log = new Log(sessionId, level, text);
|
||||||
|
boolean globalCallbackDefined = false;
|
||||||
|
boolean sessionCallbackDefined = false;
|
||||||
|
LogRedirectionStrategy activeLogRedirectionStrategy = FFmpegKitConfig.logRedirectionStrategy;
|
||||||
|
|
||||||
// AV_LOG_STDERR logs are always redirected
|
// AV_LOG_STDERR logs are always redirected
|
||||||
if ((activeLogLevel == Level.AV_LOG_QUIET && levelValue != Level.AV_LOG_STDERR.getValue()) || levelValue > activeLogLevel.getValue()) {
|
if ((activeLogLevel == Level.AV_LOG_QUIET && levelValue != Level.AV_LOG_STDERR.getValue()) || levelValue > activeLogLevel.getValue()) {
|
||||||
@ -244,7 +245,13 @@ public class FFmpegKitConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Session session = getSession(sessionId);
|
final Session session = getSession(sessionId);
|
||||||
if (session != null && session.getLogCallback() != null) {
|
if (session != null) {
|
||||||
|
activeLogRedirectionStrategy = session.getLogRedirectionStrategy();
|
||||||
|
session.addLog(log);
|
||||||
|
|
||||||
|
if (session.getLogCallback() != null) {
|
||||||
|
sessionCallbackDefined = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// NOTIFY SESSION CALLBACK IF DEFINED
|
// NOTIFY SESSION CALLBACK IF DEFINED
|
||||||
session.getLogCallback().apply(log);
|
session.getLogCallback().apply(log);
|
||||||
@ -252,16 +259,44 @@ public class FFmpegKitConfig {
|
|||||||
android.util.Log.e(FFmpegKitConfig.TAG, String.format("Exception thrown inside session LogCallback block.%s", Exceptions.getStackTraceString(e)));
|
android.util.Log.e(FFmpegKitConfig.TAG, String.format("Exception thrown inside session LogCallback block.%s", Exceptions.getStackTraceString(e)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final LogCallback globalLogCallbackFunction = FFmpegKitConfig.globalLogCallbackFunction;
|
final LogCallback globalLogCallbackFunction = FFmpegKitConfig.globalLogCallbackFunction;
|
||||||
if (globalLogCallbackFunction != null) {
|
if (globalLogCallbackFunction != null) {
|
||||||
|
globalCallbackDefined = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// NOTIFY GLOBAL CALLBACK IF DEFINED
|
// NOTIFY GLOBAL CALLBACK IF DEFINED
|
||||||
globalLogCallbackFunction.apply(log);
|
globalLogCallbackFunction.apply(log);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
android.util.Log.e(FFmpegKitConfig.TAG, String.format("Exception thrown inside global LogCallback block.%s", Exceptions.getStackTraceString(e)));
|
android.util.Log.e(FFmpegKitConfig.TAG, String.format("Exception thrown inside global LogCallback block.%s", Exceptions.getStackTraceString(e)));
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
// EXECUTE THE LOG STRATEGY
|
||||||
|
switch (activeLogRedirectionStrategy) {
|
||||||
|
case NEVER_PRINT_LOGS: {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case PRINT_LOGS_WHEN_GLOBAL_CALLBACK_NOT_DEFINED: {
|
||||||
|
if (globalCallbackDefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PRINT_LOGS_WHEN_SESSION_CALLBACK_NOT_DEFINED: {
|
||||||
|
if (sessionCallbackDefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case PRINT_LOGS_WHEN_NO_CALLBACKS_DEFINED: {
|
||||||
|
if (globalCallbackDefined || sessionCallbackDefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRINT LOGS
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case AV_LOG_QUIET: {
|
case AV_LOG_QUIET: {
|
||||||
// PRINT NO OUTPUT
|
// PRINT NO OUTPUT
|
||||||
@ -272,11 +307,6 @@ public class FFmpegKitConfig {
|
|||||||
android.util.Log.d(TAG, text);
|
android.util.Log.d(TAG, text);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AV_LOG_STDERR:
|
|
||||||
case AV_LOG_VERBOSE: {
|
|
||||||
android.util.Log.v(TAG, text);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AV_LOG_INFO: {
|
case AV_LOG_INFO: {
|
||||||
android.util.Log.i(TAG, text);
|
android.util.Log.i(TAG, text);
|
||||||
}
|
}
|
||||||
@ -291,13 +321,14 @@ public class FFmpegKitConfig {
|
|||||||
android.util.Log.e(TAG, text);
|
android.util.Log.e(TAG, text);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case AV_LOG_STDERR:
|
||||||
|
case AV_LOG_VERBOSE:
|
||||||
default: {
|
default: {
|
||||||
android.util.Log.v(TAG, text);
|
android.util.Log.v(TAG, text);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Statistics redirection method called by JNI/native part.
|
* <p>Statistics redirection method called by JNI/native part.
|
||||||
@ -314,23 +345,27 @@ public class FFmpegKitConfig {
|
|||||||
private static void statistics(final long sessionId, final int videoFrameNumber,
|
private static void statistics(final long sessionId, final int videoFrameNumber,
|
||||||
final float videoFps, final float videoQuality, final long size,
|
final float videoFps, final float videoQuality, final long size,
|
||||||
final int time, final double bitrate, final double speed) {
|
final int time, final double bitrate, final double speed) {
|
||||||
final Statistics newStatistics = new Statistics(sessionId, videoFrameNumber, videoFps, videoQuality, size, time, bitrate, speed);
|
final Statistics statistics = new Statistics(sessionId, videoFrameNumber, videoFps, videoQuality, size, time, bitrate, speed);
|
||||||
|
|
||||||
final Session session = getSession(sessionId);
|
final Session session = getSession(sessionId);
|
||||||
if (session != null && session.getStatisticsCallback() != null) {
|
if (session != null) {
|
||||||
|
session.addStatistics(statistics);
|
||||||
|
|
||||||
|
if (session.getStatisticsCallback() != null) {
|
||||||
try {
|
try {
|
||||||
// NOTIFY SESSION CALLBACK IF DEFINED
|
// NOTIFY SESSION CALLBACK IF DEFINED
|
||||||
session.getStatisticsCallback().apply(newStatistics);
|
session.getStatisticsCallback().apply(statistics);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
android.util.Log.e(FFmpegKitConfig.TAG, String.format("Exception thrown inside session StatisticsCallback block.%s", Exceptions.getStackTraceString(e)));
|
android.util.Log.e(FFmpegKitConfig.TAG, String.format("Exception thrown inside session StatisticsCallback block.%s", Exceptions.getStackTraceString(e)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final StatisticsCallback globalStatisticsCallbackFunction = FFmpegKitConfig.globalStatisticsCallbackFunction;
|
final StatisticsCallback globalStatisticsCallbackFunction = FFmpegKitConfig.globalStatisticsCallbackFunction;
|
||||||
if (globalStatisticsCallbackFunction != null) {
|
if (globalStatisticsCallbackFunction != null) {
|
||||||
try {
|
try {
|
||||||
// NOTIFY GLOBAL CALLBACK IF DEFINED
|
// NOTIFY GLOBAL CALLBACK IF DEFINED
|
||||||
globalStatisticsCallbackFunction.apply(newStatistics);
|
globalStatisticsCallbackFunction.apply(statistics);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
android.util.Log.e(FFmpegKitConfig.TAG, String.format("Exception thrown inside global StatisticsCallback block.%s", Exceptions.getStackTraceString(e)));
|
android.util.Log.e(FFmpegKitConfig.TAG, String.format("Exception thrown inside global StatisticsCallback block.%s", Exceptions.getStackTraceString(e)));
|
||||||
}
|
}
|
||||||
@ -589,7 +624,7 @@ public class FFmpegKitConfig {
|
|||||||
if (lastSession != null) {
|
if (lastSession != null) {
|
||||||
|
|
||||||
// REPLACING CH(13) WITH CH(10)
|
// REPLACING CH(13) WITH CH(10)
|
||||||
return lastSession.getLogsAsString().replace('\r', '\n');
|
return lastSession.getAllLogsAsString().replace('\r', '\n');
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -687,8 +722,9 @@ public class FFmpegKitConfig {
|
|||||||
* <p>Synchronously executes the media information session provided.
|
* <p>Synchronously executes the media information session provided.
|
||||||
*
|
*
|
||||||
* @param mediaInformationSession media information session which includes command options/arguments
|
* @param mediaInformationSession media information session which includes command options/arguments
|
||||||
|
* @param waitTimeout max time to wait until media information is transmitted
|
||||||
*/
|
*/
|
||||||
static void getMediaInformationExecute(final MediaInformationSession mediaInformationSession) {
|
static void getMediaInformationExecute(final MediaInformationSession mediaInformationSession, final int waitTimeout) {
|
||||||
addSession(mediaInformationSession);
|
addSession(mediaInformationSession);
|
||||||
mediaInformationSession.startRunning();
|
mediaInformationSession.startRunning();
|
||||||
|
|
||||||
@ -696,7 +732,7 @@ public class FFmpegKitConfig {
|
|||||||
final int returnCode = nativeFFprobeExecute(mediaInformationSession.getSessionId(), mediaInformationSession.getArguments());
|
final int returnCode = nativeFFprobeExecute(mediaInformationSession.getSessionId(), mediaInformationSession.getArguments());
|
||||||
mediaInformationSession.complete(returnCode);
|
mediaInformationSession.complete(returnCode);
|
||||||
if (returnCode == ReturnCode.SUCCESS) {
|
if (returnCode == ReturnCode.SUCCESS) {
|
||||||
MediaInformation mediaInformation = MediaInformationParser.fromWithError(mediaInformationSession.getLogsAsString());
|
MediaInformation mediaInformation = MediaInformationParser.fromWithError(mediaInformationSession.getAllLogsAsString(waitTimeout));
|
||||||
mediaInformationSession.setMediaInformation(mediaInformation);
|
mediaInformationSession.setMediaInformation(mediaInformation);
|
||||||
}
|
}
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
@ -731,9 +767,10 @@ public class FFmpegKitConfig {
|
|||||||
* <p>Asynchronously executes the media information session provided.
|
* <p>Asynchronously executes the media information session provided.
|
||||||
*
|
*
|
||||||
* @param mediaInformationSession media information session which includes command options/arguments
|
* @param mediaInformationSession media information session which includes command options/arguments
|
||||||
|
* @param waitTimeout max time to wait until media information is transmitted
|
||||||
*/
|
*/
|
||||||
static void asyncGetMediaInformationExecute(final MediaInformationSession mediaInformationSession) {
|
static void asyncGetMediaInformationExecute(final MediaInformationSession mediaInformationSession, final Integer waitTimeout) {
|
||||||
AsyncGetMediaInformationTask asyncGetMediaInformationTask = new AsyncGetMediaInformationTask(mediaInformationSession);
|
AsyncGetMediaInformationTask asyncGetMediaInformationTask = new AsyncGetMediaInformationTask(mediaInformationSession, waitTimeout);
|
||||||
Future<?> future = asyncExecutorService.submit(asyncGetMediaInformationTask);
|
Future<?> future = asyncExecutorService.submit(asyncGetMediaInformationTask);
|
||||||
mediaInformationSession.setFuture(future);
|
mediaInformationSession.setFuture(future);
|
||||||
}
|
}
|
||||||
@ -804,7 +841,7 @@ public class FFmpegKitConfig {
|
|||||||
*
|
*
|
||||||
* @return global execute callback function
|
* @return global execute callback function
|
||||||
*/
|
*/
|
||||||
public static ExecuteCallback getGlobalExecuteCallbackFunction() {
|
static ExecuteCallback getGlobalExecuteCallbackFunction() {
|
||||||
return globalExecuteCallbackFunction;
|
return globalExecuteCallbackFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -833,9 +870,16 @@ public class FFmpegKitConfig {
|
|||||||
* <p>Converts the given Structured Access Framework Uri (<code>"content:…"</code>) into an
|
* <p>Converts the given Structured Access Framework Uri (<code>"content:…"</code>) into an
|
||||||
* input/output url that can be used in FFmpegKit and FFprobeKit.
|
* input/output url that can be used in FFmpegKit and FFprobeKit.
|
||||||
*
|
*
|
||||||
|
* <p>Requires API Level >= 19. On older API levels it returns an empty url.
|
||||||
|
*
|
||||||
* @return input/output url that can be passed to FFmpegKit or FFprobeKit
|
* @return input/output url that can be passed to FFmpegKit or FFprobeKit
|
||||||
*/
|
*/
|
||||||
private static String getSafParameter(final Context context, final Uri uri, final String openMode) {
|
private static String getSafParameter(final Context context, final Uri uri, final String openMode) {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||||
|
android.util.Log.i(TAG, String.format("getSafParameter is not supported on API Level %d", Build.VERSION.SDK_INT));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
String displayName = "unknown";
|
String displayName = "unknown";
|
||||||
try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
|
try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
@ -868,6 +912,8 @@ public class FFmpegKitConfig {
|
|||||||
* <p>Converts the given Structured Access Framework Uri (<code>"content:…"</code>) into an
|
* <p>Converts the given Structured Access Framework Uri (<code>"content:…"</code>) into an
|
||||||
* input url that can be used in FFmpegKit and FFprobeKit.
|
* input url that can be used in FFmpegKit and FFprobeKit.
|
||||||
*
|
*
|
||||||
|
* <p>Requires API Level >= 19. On older API levels it returns an empty url.
|
||||||
|
*
|
||||||
* @return input url that can be passed to FFmpegKit or FFprobeKit
|
* @return input url that can be passed to FFmpegKit or FFprobeKit
|
||||||
*/
|
*/
|
||||||
public static String getSafParameterForRead(final Context context, final Uri uri) {
|
public static String getSafParameterForRead(final Context context, final Uri uri) {
|
||||||
@ -878,6 +924,8 @@ public class FFmpegKitConfig {
|
|||||||
* <p>Converts the given Structured Access Framework Uri (<code>"content:…"</code>) into an
|
* <p>Converts the given Structured Access Framework Uri (<code>"content:…"</code>) into an
|
||||||
* output url that can be used in FFmpegKit and FFprobeKit.
|
* output url that can be used in FFmpegKit and FFprobeKit.
|
||||||
*
|
*
|
||||||
|
* <p>Requires API Level >= 19. On older API levels it returns an empty url.
|
||||||
|
*
|
||||||
* @return output url that can be passed to FFmpegKit or FFprobeKit
|
* @return output url that can be passed to FFmpegKit or FFprobeKit
|
||||||
*/
|
*/
|
||||||
public static String getSafParameterForWrite(final Context context, final Uri uri) {
|
public static String getSafParameterForWrite(final Context context, final Uri uri) {
|
||||||
@ -913,9 +961,16 @@ public class FFmpegKitConfig {
|
|||||||
/**
|
/**
|
||||||
* Sets the session history size.
|
* Sets the session history size.
|
||||||
*
|
*
|
||||||
* @param sessionHistorySize new session history size
|
* @param sessionHistorySize new session history size, should be smaller than 1000
|
||||||
*/
|
*/
|
||||||
public static void setSessionHistorySize(int sessionHistorySize) {
|
public static void setSessionHistorySize(final int sessionHistorySize) {
|
||||||
|
if (sessionHistorySize >= 1000) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* THERE IS A HARD LIMIT ON THE NATIVE SIDE. HISTORY SIZE MUST BE SMALLER THAN 1000
|
||||||
|
*/
|
||||||
|
throw new IllegalArgumentException("Session history size must not exceed the hard limit!");
|
||||||
|
}
|
||||||
FFmpegKitConfig.sessionHistorySize = sessionHistorySize;
|
FFmpegKitConfig.sessionHistorySize = sessionHistorySize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -978,27 +1033,17 @@ public class FFmpegKitConfig {
|
|||||||
* @return all FFmpeg sessions in the session history
|
* @return all FFmpeg sessions in the session history
|
||||||
*/
|
*/
|
||||||
static List<FFmpegSession> getFFmpegSessions() {
|
static List<FFmpegSession> getFFmpegSessions() {
|
||||||
|
final LinkedList<FFmpegSession> list = new LinkedList<>();
|
||||||
|
|
||||||
synchronized (sessionHistoryLock) {
|
synchronized (sessionHistoryLock) {
|
||||||
return sessionHistoryQueue.stream().filter(new Predicate<Session>() {
|
for (Session session : sessionHistoryQueue) {
|
||||||
|
if (session.isFFmpeg()) {
|
||||||
|
list.add((FFmpegSession) session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
return list;
|
||||||
public boolean test(final Session session) {
|
|
||||||
return (session.isFFmpeg());
|
|
||||||
}
|
|
||||||
}).map(new Function<Session, FFmpegSession>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FFmpegSession apply(final Session session) {
|
|
||||||
return (FFmpegSession) session;
|
|
||||||
}
|
|
||||||
}).collect(Collectors.toCollection(new Supplier<List<FFmpegSession>>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<FFmpegSession> get() {
|
|
||||||
return new LinkedList<>();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1007,27 +1052,17 @@ public class FFmpegKitConfig {
|
|||||||
* @return all FFprobe sessions in the session history
|
* @return all FFprobe sessions in the session history
|
||||||
*/
|
*/
|
||||||
static List<FFprobeSession> getFFprobeSessions() {
|
static List<FFprobeSession> getFFprobeSessions() {
|
||||||
|
final LinkedList<FFprobeSession> list = new LinkedList<>();
|
||||||
|
|
||||||
synchronized (sessionHistoryLock) {
|
synchronized (sessionHistoryLock) {
|
||||||
return sessionHistoryQueue.stream().filter(new Predicate<Session>() {
|
for (Session session : sessionHistoryQueue) {
|
||||||
|
if (session.isFFprobe()) {
|
||||||
|
list.add((FFprobeSession) session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
return list;
|
||||||
public boolean test(final Session session) {
|
|
||||||
return (session.isFFprobe());
|
|
||||||
}
|
|
||||||
}).map(new Function<Session, FFprobeSession>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FFprobeSession apply(final Session session) {
|
|
||||||
return (FFprobeSession) session;
|
|
||||||
}
|
|
||||||
}).collect(Collectors.toCollection(new Supplier<List<FFprobeSession>>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<FFprobeSession> get() {
|
|
||||||
return new LinkedList<>();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1036,21 +1071,35 @@ public class FFmpegKitConfig {
|
|||||||
* @return sessions that have the given state from the session history
|
* @return sessions that have the given state from the session history
|
||||||
*/
|
*/
|
||||||
public static List<Session> getSessionsByState(final SessionState state) {
|
public static List<Session> getSessionsByState(final SessionState state) {
|
||||||
|
final LinkedList<Session> list = new LinkedList<>();
|
||||||
|
|
||||||
synchronized (sessionHistoryLock) {
|
synchronized (sessionHistoryLock) {
|
||||||
return sessionHistoryQueue.stream().filter(new Predicate<Session>() {
|
for (Session session : sessionHistoryQueue) {
|
||||||
|
if (session.getState() == state) {
|
||||||
|
list.add(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
return list;
|
||||||
public boolean test(final Session session) {
|
|
||||||
return (session.getState() == state);
|
|
||||||
}
|
}
|
||||||
}).collect(Collectors.toCollection(new Supplier<List<Session>>() {
|
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public List<Session> get() {
|
* Returns the active log redirection strategy.
|
||||||
return new LinkedList<>();
|
*
|
||||||
}
|
* @return log redirection strategy
|
||||||
}));
|
*/
|
||||||
|
public static LogRedirectionStrategy getLogRedirectionStrategy() {
|
||||||
|
return logRedirectionStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the log redirection strategy
|
||||||
|
*
|
||||||
|
* @param logRedirectionStrategy new log redirection strategy
|
||||||
|
*/
|
||||||
|
public static void setLogRedirectionStrategy(final LogRedirectionStrategy logRedirectionStrategy) {
|
||||||
|
FFmpegKitConfig.logRedirectionStrategy = logRedirectionStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1096,7 +1145,9 @@ public class FFmpegKitConfig {
|
|||||||
*
|
*
|
||||||
* @param sessionId id of the session
|
* @param sessionId id of the session
|
||||||
* @param arguments FFmpeg command options/arguments as string array
|
* @param arguments FFmpeg command options/arguments as string array
|
||||||
* @return zero on successful execution, 255 on user cancel and non-zero on error
|
* @return {@link ReturnCode#SUCCESS} on successful execution and {@link ReturnCode#CANCEL} on
|
||||||
|
* user cancel. Other non-zero values are returned on error. Use {@link ReturnCode} class to
|
||||||
|
* handle the value
|
||||||
*/
|
*/
|
||||||
private native static int nativeFFmpegExecute(final long sessionId, final String[] arguments);
|
private native static int nativeFFmpegExecute(final long sessionId, final String[] arguments);
|
||||||
|
|
||||||
@ -1113,10 +1164,22 @@ public class FFmpegKitConfig {
|
|||||||
*
|
*
|
||||||
* @param sessionId id of the session
|
* @param sessionId id of the session
|
||||||
* @param arguments FFprobe command options/arguments as string array
|
* @param arguments FFprobe command options/arguments as string array
|
||||||
* @return zero on successful execution, 255 on user cancel and non-zero on error
|
* @return {@link ReturnCode#SUCCESS} on successful execution and {@link ReturnCode#CANCEL} on
|
||||||
|
* user cancel. Other non-zero values are returned on error. Use {@link ReturnCode} class to
|
||||||
|
* handle the value
|
||||||
*/
|
*/
|
||||||
native static int nativeFFprobeExecute(final long sessionId, final String[] arguments);
|
native static int nativeFFprobeExecute(final long sessionId, final String[] arguments);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the number of native messages which are not transmitted to the Java callbacks for
|
||||||
|
* this session natively.
|
||||||
|
*
|
||||||
|
* @param sessionId id of the session
|
||||||
|
* @return number of native messages which are not transmitted to the Java callbacks for
|
||||||
|
* this session natively
|
||||||
|
*/
|
||||||
|
native static int messagesInTransmit(final long sessionId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Creates a new named pipe to use in <code>FFmpeg</code> operations natively.
|
* <p>Creates a new named pipe to use in <code>FFmpeg</code> operations natively.
|
||||||
*
|
*
|
||||||
|
@ -21,7 +21,6 @@ package com.arthenica.ffmpegkit;
|
|||||||
|
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>An FFmpeg execute session.
|
* <p>An FFmpeg execute session.
|
||||||
@ -33,19 +32,33 @@ public class FFmpegSession extends AbstractSession implements Session {
|
|||||||
final ExecuteCallback executeCallback,
|
final ExecuteCallback executeCallback,
|
||||||
final LogCallback logCallback,
|
final LogCallback logCallback,
|
||||||
final StatisticsCallback statisticsCallback) {
|
final StatisticsCallback statisticsCallback) {
|
||||||
super(arguments, executeCallback, logCallback, statisticsCallback);
|
super(arguments, executeCallback, logCallback, statisticsCallback, FFmpegKitConfig.getLogRedirectionStrategy());
|
||||||
|
|
||||||
this.statistics = new ConcurrentLinkedQueue<>();
|
this.statistics = new ConcurrentLinkedQueue<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Queue<Statistics> getAllStatistics(final int waitTimeout) {
|
||||||
|
waitForCallbackMessagesInTransmit(waitTimeout);
|
||||||
|
|
||||||
|
if (thereAreCallbackMessagesInTransmit()) {
|
||||||
|
android.util.Log.i(FFmpegKitConfig.TAG, String.format("getAllStatistics was asked to return all statistics but there are still statistics being transmitted for session id %d.", sessionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
return getStatistics();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Queue<Statistics> getAllStatistics() {
|
||||||
|
return getAllStatistics(DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Queue<Statistics> getStatistics() {
|
public Queue<Statistics> getStatistics() {
|
||||||
return statistics;
|
return statistics;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream<Statistics> getStatisticsAsStream() {
|
@Override
|
||||||
return statistics.stream();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addStatistics(final Statistics statistics) {
|
public void addStatistics(final Statistics statistics) {
|
||||||
this.statistics.add(statistics);
|
this.statistics.add(statistics);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package com.arthenica.ffmpegkit;
|
package com.arthenica.ffmpegkit;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -183,6 +184,15 @@ public class FFprobeKit {
|
|||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Lists all FFprobe sessions in the session history
|
||||||
|
*
|
||||||
|
* @return all FFprobe sessions in the session history
|
||||||
|
*/
|
||||||
|
public static List<FFprobeSession> listSessions() {
|
||||||
|
return FFmpegKitConfig.getFFprobeSessions();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns media information for the given path.
|
* <p>Returns media information for the given path.
|
||||||
*
|
*
|
||||||
@ -190,7 +200,18 @@ public class FFprobeKit {
|
|||||||
* @return media information session created for this execution
|
* @return media information session created for this execution
|
||||||
*/
|
*/
|
||||||
public static MediaInformationSession getMediaInformation(final String path) {
|
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);
|
return getMediaInformationFromCommandArguments(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, null, null, null, AbstractSession.DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns media information for the given path.
|
||||||
|
*
|
||||||
|
* @param path path or uri of a media file
|
||||||
|
* @param waitTimeout max time to wait until media information is transmitted
|
||||||
|
* @return media information session created for this execution
|
||||||
|
*/
|
||||||
|
public static MediaInformationSession getMediaInformation(final String path, final Integer waitTimeout) {
|
||||||
|
return getMediaInformationFromCommandArguments(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, null, null, null, waitTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -204,7 +225,7 @@ public class FFprobeKit {
|
|||||||
final ExecuteCallback executeCallback) {
|
final ExecuteCallback executeCallback) {
|
||||||
final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback, null, null);
|
final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback, null, null);
|
||||||
|
|
||||||
FFmpegKitConfig.asyncGetMediaInformationExecute(session);
|
FFmpegKitConfig.asyncGetMediaInformationExecute(session, AbstractSession.DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT);
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
@ -216,15 +237,17 @@ public class FFprobeKit {
|
|||||||
* @param executeCallback callback that will be notified when execution is completed
|
* @param executeCallback callback that will be notified when execution is completed
|
||||||
* @param logCallback callback that will receive log entries
|
* @param logCallback callback that will receive log entries
|
||||||
* @param statisticsCallback callback that will receive statistics
|
* @param statisticsCallback callback that will receive statistics
|
||||||
|
* @param waitTimeout max time to wait until media information is transmitted
|
||||||
* @return media information session created for this execution
|
* @return media information session created for this execution
|
||||||
*/
|
*/
|
||||||
public static MediaInformationSession getMediaInformationAsync(final String path,
|
public static MediaInformationSession getMediaInformationAsync(final String path,
|
||||||
final ExecuteCallback executeCallback,
|
final ExecuteCallback executeCallback,
|
||||||
final LogCallback logCallback,
|
final LogCallback logCallback,
|
||||||
final StatisticsCallback statisticsCallback) {
|
final StatisticsCallback statisticsCallback,
|
||||||
|
final Integer waitTimeout) {
|
||||||
final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback, logCallback, statisticsCallback);
|
final 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);
|
FFmpegKitConfig.asyncGetMediaInformationExecute(session, waitTimeout);
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
@ -256,16 +279,18 @@ public class FFprobeKit {
|
|||||||
* @param logCallback callback that will receive log entries
|
* @param logCallback callback that will receive log entries
|
||||||
* @param statisticsCallback callback that will receive statistics
|
* @param statisticsCallback callback that will receive statistics
|
||||||
* @param executor executor that will be used to run this asynchronous operation
|
* @param executor executor that will be used to run this asynchronous operation
|
||||||
|
* @param waitTimeout max time to wait until media information is transmitted
|
||||||
* @return media information session created for this execution
|
* @return media information session created for this execution
|
||||||
*/
|
*/
|
||||||
public static MediaInformationSession getMediaInformationAsync(final String path,
|
public static MediaInformationSession getMediaInformationAsync(final String path,
|
||||||
final ExecuteCallback executeCallback,
|
final ExecuteCallback executeCallback,
|
||||||
final LogCallback logCallback,
|
final LogCallback logCallback,
|
||||||
final StatisticsCallback statisticsCallback,
|
final StatisticsCallback statisticsCallback,
|
||||||
final Executor executor) {
|
final Executor executor,
|
||||||
|
final Integer waitTimeout) {
|
||||||
final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback, logCallback, statisticsCallback);
|
final 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);
|
AsyncGetMediaInformationTask asyncGetMediaInformationTask = new AsyncGetMediaInformationTask(session, waitTimeout);
|
||||||
executor.execute(asyncGetMediaInformationTask);
|
executor.execute(asyncGetMediaInformationTask);
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
@ -278,7 +303,7 @@ public class FFprobeKit {
|
|||||||
* @return media information session created for this execution
|
* @return media information session created for this execution
|
||||||
*/
|
*/
|
||||||
public static MediaInformationSession getMediaInformationFromCommand(final String command) {
|
public static MediaInformationSession getMediaInformationFromCommand(final String command) {
|
||||||
return getMediaInformationFromCommandArguments(FFmpegKit.parseArguments(command), null, null, null);
|
return getMediaInformationFromCommandArguments(FFmpegKit.parseArguments(command), null, null, null, AbstractSession.DEFAULT_TIMEOUT_FOR_CALLBACK_MESSAGES_IN_TRANSMIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -289,22 +314,25 @@ public class FFprobeKit {
|
|||||||
* @param executeCallback callback that will be notified when execution is completed
|
* @param executeCallback callback that will be notified when execution is completed
|
||||||
* @param logCallback callback that will receive log entries
|
* @param logCallback callback that will receive log entries
|
||||||
* @param statisticsCallback callback that will receive statistics
|
* @param statisticsCallback callback that will receive statistics
|
||||||
|
* @param waitTimeout max time to wait until media information is transmitted
|
||||||
* @return media information session created for this execution
|
* @return media information session created for this execution
|
||||||
*/
|
*/
|
||||||
public static MediaInformationSession getMediaInformationFromCommand(final String command,
|
public static MediaInformationSession getMediaInformationFromCommand(final String command,
|
||||||
final ExecuteCallback executeCallback,
|
final ExecuteCallback executeCallback,
|
||||||
final LogCallback logCallback,
|
final LogCallback logCallback,
|
||||||
final StatisticsCallback statisticsCallback) {
|
final StatisticsCallback statisticsCallback,
|
||||||
return getMediaInformationFromCommandArguments(FFmpegKit.parseArguments(command), executeCallback, logCallback, statisticsCallback);
|
final Integer waitTimeout) {
|
||||||
|
return getMediaInformationFromCommandArguments(FFmpegKit.parseArguments(command), executeCallback, logCallback, statisticsCallback, waitTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MediaInformationSession getMediaInformationFromCommandArguments(final String[] arguments,
|
private static MediaInformationSession getMediaInformationFromCommandArguments(final String[] arguments,
|
||||||
final ExecuteCallback executeCallback,
|
final ExecuteCallback executeCallback,
|
||||||
final LogCallback logCallback,
|
final LogCallback logCallback,
|
||||||
final StatisticsCallback statisticsCallback) {
|
final StatisticsCallback statisticsCallback,
|
||||||
|
final Integer waitTimeout) {
|
||||||
final MediaInformationSession session = new MediaInformationSession(arguments, executeCallback, logCallback, statisticsCallback);
|
final MediaInformationSession session = new MediaInformationSession(arguments, executeCallback, logCallback, statisticsCallback);
|
||||||
|
|
||||||
FFmpegKitConfig.getMediaInformationExecute(session);
|
FFmpegKitConfig.getMediaInformationExecute(session, waitTimeout);
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ package com.arthenica.ffmpegkit;
|
|||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>An FFprobe execute session.
|
* <p>An FFprobe execute session.
|
||||||
@ -33,7 +32,25 @@ public class FFprobeSession extends AbstractSession implements Session {
|
|||||||
final ExecuteCallback executeCallback,
|
final ExecuteCallback executeCallback,
|
||||||
final LogCallback logCallback,
|
final LogCallback logCallback,
|
||||||
final StatisticsCallback statisticsCallback) {
|
final StatisticsCallback statisticsCallback) {
|
||||||
super(arguments, executeCallback, logCallback, statisticsCallback);
|
this(arguments, executeCallback, logCallback, statisticsCallback, FFmpegKitConfig.getLogRedirectionStrategy());
|
||||||
|
}
|
||||||
|
|
||||||
|
FFprobeSession(final String[] arguments,
|
||||||
|
final ExecuteCallback executeCallback,
|
||||||
|
final LogCallback logCallback,
|
||||||
|
final StatisticsCallback statisticsCallback,
|
||||||
|
final LogRedirectionStrategy logRedirectionStrategy) {
|
||||||
|
super(arguments, executeCallback, logCallback, statisticsCallback, logRedirectionStrategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Queue<Statistics> getAllStatistics(final int waitTimeout) {
|
||||||
|
return new LinkedList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Queue<Statistics> getAllStatistics() {
|
||||||
|
return new LinkedList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -41,11 +58,6 @@ public class FFprobeSession extends AbstractSession implements Session {
|
|||||||
return new LinkedList<>();
|
return new LinkedList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Stream<Statistics> getStatisticsAsStream() {
|
|
||||||
return new LinkedList<Statistics>().stream();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addStatistics(final Statistics statistics) {
|
public void addStatistics(final Statistics statistics) {
|
||||||
/*
|
/*
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
public enum LogRedirectionStrategy {
|
||||||
|
ALWAYS_PRINT_LOGS,
|
||||||
|
PRINT_LOGS_WHEN_NO_CALLBACKS_DEFINED,
|
||||||
|
PRINT_LOGS_WHEN_GLOBAL_CALLBACK_NOT_DEFINED,
|
||||||
|
PRINT_LOGS_WHEN_SESSION_CALLBACK_NOT_DEFINED,
|
||||||
|
NEVER_PRINT_LOGS
|
||||||
|
}
|
@ -30,7 +30,7 @@ public class MediaInformationSession extends FFprobeSession implements Session {
|
|||||||
final ExecuteCallback executeCallback,
|
final ExecuteCallback executeCallback,
|
||||||
final LogCallback logCallback,
|
final LogCallback logCallback,
|
||||||
final StatisticsCallback statisticsCallback) {
|
final StatisticsCallback statisticsCallback) {
|
||||||
super(arguments, executeCallback, logCallback, statisticsCallback);
|
super(arguments, executeCallback, logCallback, statisticsCallback, LogRedirectionStrategy.NEVER_PRINT_LOGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MediaInformation getMediaInformation() {
|
public MediaInformation getMediaInformation() {
|
||||||
|
@ -22,7 +22,6 @@ package com.arthenica.ffmpegkit;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Interface for ffmpeg and ffprobe execute sessions.
|
* <p>Interface for ffmpeg and ffprobe execute sessions.
|
||||||
@ -49,15 +48,23 @@ public interface Session {
|
|||||||
|
|
||||||
String getCommand();
|
String getCommand();
|
||||||
|
|
||||||
|
Queue<Log> getAllLogs(final int waitTimeout);
|
||||||
|
|
||||||
|
Queue<Log> getAllLogs();
|
||||||
|
|
||||||
Queue<Log> getLogs();
|
Queue<Log> getLogs();
|
||||||
|
|
||||||
Stream<Log> getLogsAsStream();
|
String getAllLogsAsString(final int waitTimeout);
|
||||||
|
|
||||||
|
String getAllLogsAsString();
|
||||||
|
|
||||||
String getLogsAsString();
|
String getLogsAsString();
|
||||||
|
|
||||||
Queue<Statistics> getStatistics();
|
Queue<Statistics> getAllStatistics(final int waitTimeout);
|
||||||
|
|
||||||
Stream<Statistics> getStatisticsAsStream();
|
Queue<Statistics> getAllStatistics();
|
||||||
|
|
||||||
|
Queue<Statistics> getStatistics();
|
||||||
|
|
||||||
SessionState getState();
|
SessionState getState();
|
||||||
|
|
||||||
@ -65,6 +72,10 @@ public interface Session {
|
|||||||
|
|
||||||
String getFailStackTrace();
|
String getFailStackTrace();
|
||||||
|
|
||||||
|
LogRedirectionStrategy getLogRedirectionStrategy();
|
||||||
|
|
||||||
|
boolean thereAreCallbackMessagesInTransmit();
|
||||||
|
|
||||||
void addLog(final Log log);
|
void addLog(final Log log);
|
||||||
|
|
||||||
void addStatistics(final Statistics statistics);
|
void addStatistics(final Statistics statistics);
|
||||||
|
@ -28,7 +28,7 @@ public class AbstractSessionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getLogsAsStringTest() {
|
public void getLogsAsStringTest() {
|
||||||
final FFprobeSession ffprobeSession = new FFprobeSession(TEST_ARGUMENTS, null, null, null);
|
final FFprobeSession ffprobeSession = new FFprobeSession(TEST_ARGUMENTS, null, null, null, LogRedirectionStrategy.ALWAYS_PRINT_LOGS);
|
||||||
|
|
||||||
String logMessage1 = "i am log one";
|
String logMessage1 = "i am log one";
|
||||||
String logMessage2 = "i am log two";
|
String logMessage2 = "i am log two";
|
||||||
|
Loading…
Reference in New Issue
Block a user