Loading...
Searching...
No Matches
ffmpegkit.c
Go to the documentation of this file.
/*
* Copyright (c) 2018-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 <pthread.h>
#include <stdatomic.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "config.h"
#include "libavcodec/jni.h"
#include "libavutil/bprint.h"
#include "libavutil/file.h"
#include "fftools_ffmpeg.h"
#include "ffmpegkit.h"
#include "ffprobekit.h"
# define LogType 1
# define StatisticsType 2
struct CallbackData {
int type; // 1 (log callback) or 2 (statistics callback)
long sessionId; // session identifier
int logLevel; // log level
AVBPrint logData; // log data
int statisticsFrameNumber; // statistics frame number
float statisticsFps; // statistics fps
float statisticsQuality; // statistics quality
int64_t statisticsSize; // statistics size
double statisticsTime; // statistics time
double statisticsBitrate; // statistics bitrate
double statisticsSpeed; // statistics speed
struct CallbackData *next;
};
#define SESSION_MAP_SIZE 1000
static atomic_short sessionMap[SESSION_MAP_SIZE];
static atomic_int sessionInTransitMessageCountMap[SESSION_MAP_SIZE];
static pthread_mutex_t lockMutex;
static pthread_mutex_t monitorMutex;
static pthread_cond_t monitorCondition;
pthread_t callbackThread;
int redirectionEnabled;
struct CallbackData *callbackDataHead;
struct CallbackData *callbackDataTail;
static JavaVM *globalVm;
static jclass configClass;
static jmethodID logMethod;
static jmethodID statisticsMethod;
static jmethodID safOpenMethod;
static jmethodID safCloseMethod;
static jclass stringClass;
static jmethodID stringConstructor;
const char *configClassName = "com/arthenica/ffmpegkit/FFmpegKitConfig";
const char *stringClassName = "java/lang/String";
volatile int handleSIGQUIT = 1;
volatile int handleSIGINT = 1;
volatile int handleSIGTERM = 1;
volatile int handleSIGXCPU = 1;
volatile int handleSIGPIPE = 1;
__thread long globalSessionId = 0;
int configuredLogLevel = AV_LOG_INFO;
JNINativeMethod configMethods[] = {
{"enableNativeRedirection", "()V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_enableNativeRedirection},
{"disableNativeRedirection", "()V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_disableNativeRedirection},
{"setNativeLogLevel", "(I)V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeLogLevel},
{"getNativeLogLevel", "()I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeLogLevel},
{"getNativeFFmpegVersion", "()Ljava/lang/String;", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeFFmpegVersion},
{"getNativeVersion", "()Ljava/lang/String;", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeVersion},
{"nativeFFmpegExecute", "(J[Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute},
{"nativeFFmpegCancel", "(J)V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegCancel},
{"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},
{"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},
{"ignoreNativeSignal", "(I)V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal},
{"messagesInTransmit", "(J)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_messagesInTransmit}
};
int ffmpeg_execute(int argc, char **argv);
static const char *avutil_log_get_level_str(int level) {
switch (level) {
case AV_LOG_STDERR:
return "stderr";
case AV_LOG_QUIET:
return "quiet";
case AV_LOG_DEBUG:
return "debug";
case AV_LOG_VERBOSE:
return "verbose";
case AV_LOG_INFO:
return "info";
case AV_LOG_WARNING:
return "warning";
case AV_LOG_ERROR:
return "error";
case AV_LOG_FATAL:
return "fatal";
case AV_LOG_PANIC:
return "panic";
default:
return "";
}
}
static void avutil_log_format_line(void *avcl, int level, const char *fmt, va_list vl, AVBPrint part[4], int *print_prefix) {
int flags = av_log_get_flags();
AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
av_bprint_init(part+0, 0, 1);
av_bprint_init(part+1, 0, 1);
av_bprint_init(part+2, 0, 1);
av_bprint_init(part+3, 0, 65536);
if (*print_prefix && avc) {
if (avc->parent_log_context_offset) {
AVClass** parent = *(AVClass ***) (((uint8_t *) avcl) +
avc->parent_log_context_offset);
if (parent && *parent) {
av_bprintf(part+0, "[%s @ %p] ",
(*parent)->item_name(parent), parent);
}
}
av_bprintf(part+1, "[%s @ %p] ",
avc->item_name(avcl), avcl);
}
if (*print_prefix && (level > AV_LOG_QUIET) && (flags & AV_LOG_PRINT_LEVEL))
av_bprintf(part+2, "[%s] ", avutil_log_get_level_str(level));
av_vbprintf(part+3, fmt, vl);
if(*part[0].str || *part[1].str || *part[2].str || *part[3].str) {
char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0;
*print_prefix = lastc == '\n' || lastc == '\r';
}
}
static void avutil_log_sanitize(uint8_t *line) {
while(*line){
if(*line < 0x08 || (*line > 0x0D && *line < 0x20))
*line='?';
line++;
}
}
void mutexInit() {
pthread_mutexattr_t attributes;
pthread_mutexattr_init(&attributes);
pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
pthread_mutex_init(&lockMutex, &attributes);
pthread_mutexattr_destroy(&attributes);
}
void monitorInit() {
pthread_mutexattr_t attributes;
pthread_mutexattr_init(&attributes);
pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
pthread_condattr_t cattributes;
pthread_condattr_init(&cattributes);
pthread_condattr_setpshared(&cattributes, PTHREAD_PROCESS_PRIVATE);
pthread_mutex_init(&monitorMutex, &attributes);
pthread_mutexattr_destroy(&attributes);
pthread_cond_init(&monitorCondition, &cattributes);
pthread_condattr_destroy(&cattributes);
}
void mutexUnInit() {
pthread_mutex_destroy(&lockMutex);
}
void monitorUnInit() {
pthread_mutex_destroy(&monitorMutex);
pthread_cond_destroy(&monitorCondition);
}
void mutexLock() {
pthread_mutex_lock(&lockMutex);
}
void mutexUnlock() {
pthread_mutex_unlock(&lockMutex);
}
void monitorWait(int milliSeconds) {
struct timeval tp;
struct timespec ts;
int rc;
rc = gettimeofday(&tp, NULL);
if (rc) {
return;
}
ts.tv_sec = tp.tv_sec;
ts.tv_nsec = tp.tv_usec * 1000;
ts.tv_sec += milliSeconds / 1000;
ts.tv_nsec += (milliSeconds % 1000)*1000000;
ts.tv_sec += ts.tv_nsec / 1000000000L;
ts.tv_nsec = ts.tv_nsec % 1000000000L;
pthread_mutex_lock(&monitorMutex);
pthread_cond_timedwait(&monitorCondition, &monitorMutex, &ts);
pthread_mutex_unlock(&monitorMutex);
}
void monitorNotify() {
pthread_mutex_lock(&monitorMutex);
pthread_cond_signal(&monitorCondition);
pthread_mutex_unlock(&monitorMutex);
}
void logCallbackDataAdd(int level, AVBPrint *data) {
// CREATE DATA STRUCT FIRST
struct CallbackData *newData = (struct CallbackData*)av_malloc(sizeof(struct CallbackData));
newData->type = LogType;
newData->sessionId = globalSessionId;
newData->logLevel = level;
av_bprint_init(&newData->logData, 0, AV_BPRINT_SIZE_UNLIMITED);
av_bprintf(&newData->logData, "%s", data->str);
newData->next = NULL;
mutexLock();
// INSERT IT TO THE END OF QUEUE
if (callbackDataTail == NULL) {
callbackDataTail = newData;
if (callbackDataHead != NULL) {
LOGE("Dangling callback data head detected. This can cause memory leak.");
} else {
callbackDataHead = newData;
}
} else {
struct CallbackData *oldTail = callbackDataTail;
oldTail->next = newData;
callbackDataTail = newData;
}
mutexUnlock();
monitorNotify();
atomic_fetch_add(&sessionInTransitMessageCountMap[globalSessionId % SESSION_MAP_SIZE], 1);
}
void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, double time, double bitrate, double speed) {
// CREATE DATA STRUCT FIRST
struct CallbackData *newData = (struct CallbackData*)av_malloc(sizeof(struct CallbackData));
newData->type = StatisticsType;
newData->sessionId = globalSessionId;
newData->statisticsFrameNumber = frameNumber;
newData->statisticsFps = fps;
newData->statisticsQuality = quality;
newData->statisticsSize = size;
newData->statisticsTime = time;
newData->statisticsBitrate = bitrate;
newData->statisticsSpeed = speed;
newData->next = NULL;
mutexLock();
// INSERT IT TO THE END OF QUEUE
if (callbackDataTail == NULL) {
callbackDataTail = newData;
if (callbackDataHead != NULL) {
LOGE("Dangling callback data head detected. This can cause memory leak.");
} else {
callbackDataHead = newData;
}
} else {
struct CallbackData *oldTail = callbackDataTail;
oldTail->next = newData;
callbackDataTail = newData;
}
mutexUnlock();
monitorNotify();
atomic_fetch_add(&sessionInTransitMessageCountMap[globalSessionId % SESSION_MAP_SIZE], 1);
}
void addSession(long id) {
atomic_store(&sessionMap[id % SESSION_MAP_SIZE], 1);
}
struct CallbackData *callbackDataRemove() {
struct CallbackData *currentData;
mutexLock();
if (callbackDataHead == NULL) {
currentData = NULL;
} else {
currentData = callbackDataHead;
struct CallbackData *nextHead = currentData->next;
if (nextHead == NULL) {
if (callbackDataHead != callbackDataTail) {
LOGE("Head and tail callback data pointers do not match for single callback data element. This can cause memory leak.");
} else {
callbackDataTail = NULL;
}
callbackDataHead = NULL;
} else {
callbackDataHead = nextHead;
}
}
mutexUnlock();
return currentData;
}
void removeSession(long id) {
atomic_store(&sessionMap[id % SESSION_MAP_SIZE], 0);
}
void cancelSession(long id) {
atomic_store(&sessionMap[id % SESSION_MAP_SIZE], 2);
}
int cancelRequested(long id) {
if (atomic_load(&sessionMap[id % SESSION_MAP_SIZE]) == 2) {
return 1;
} else {
return 0;
}
}
void resetMessagesInTransmit(long id) {
atomic_store(&sessionInTransitMessageCountMap[id % SESSION_MAP_SIZE], 0);
}
void ffmpegkit_log_callback_function(void *ptr, int level, const char* format, va_list vargs) {
AVBPrint fullLine;
AVBPrint part[4];
int print_prefix = 1;
if (level >= 0) {
level &= 0xff;
}
int activeLogLevel = av_log_get_level();
// AV_LOG_STDERR logs are always redirected
if ((activeLogLevel == AV_LOG_QUIET && level != AV_LOG_STDERR) || (level > activeLogLevel)) {
return;
}
av_bprint_init(&fullLine, 0, AV_BPRINT_SIZE_UNLIMITED);
avutil_log_format_line(ptr, level, format, vargs, part, &print_prefix);
avutil_log_sanitize(part[0].str);
avutil_log_sanitize(part[1].str);
avutil_log_sanitize(part[2].str);
avutil_log_sanitize(part[3].str);
// COMBINE ALL 4 LOG PARTS
av_bprintf(&fullLine, "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
if (fullLine.len > 0) {
logCallbackDataAdd(level, &fullLine);
}
av_bprint_finalize(part, NULL);
av_bprint_finalize(part+1, NULL);
av_bprint_finalize(part+2, NULL);
av_bprint_finalize(part+3, NULL);
av_bprint_finalize(&fullLine, NULL);
}
void ffmpegkit_statistics_callback_function(int frameNumber, float fps, float quality, int64_t size, double time, double bitrate, double speed) {
statisticsCallbackDataAdd(frameNumber, fps, quality, size, time, bitrate, speed);
}
void *callbackThreadFunction() {
JNIEnv *env;
jint getEnvRc = (*globalVm)->GetEnv(globalVm, (void**) &env, JNI_VERSION_1_6);
if (getEnvRc != JNI_OK) {
if (getEnvRc != JNI_EDETACHED) {
LOGE("Callback thread failed to GetEnv for class %s with rc %d.\n", configClassName, getEnvRc);
return NULL;
}
if ((*globalVm)->AttachCurrentThread(globalVm, &env, NULL) != 0) {
LOGE("Callback thread failed to AttachCurrentThread for class %s.\n", configClassName);
return NULL;
}
}
LOGD("Async callback block started.\n");
while(redirectionEnabled) {
struct CallbackData *callbackData = callbackDataRemove();
if (callbackData != NULL) {
if (callbackData->type == LogType) {
// LOG CALLBACK
int size = callbackData->logData.len;
jbyteArray byteArray = (jbyteArray) (*env)->NewByteArray(env, size);
(*env)->SetByteArrayRegion(env, byteArray, 0, size, callbackData->logData.str);
(*env)->CallStaticVoidMethod(env, configClass, logMethod, (jlong) callbackData->sessionId, callbackData->logLevel, byteArray);
(*env)->DeleteLocalRef(env, byteArray);
// CLEAN LOG DATA
av_bprint_finalize(&callbackData->logData, NULL);
} else {
// STATISTICS CALLBACK
(*env)->CallStaticVoidMethod(env, configClass, statisticsMethod,
(jlong) callbackData->sessionId, callbackData->statisticsFrameNumber,
callbackData->statisticsFps, callbackData->statisticsQuality,
callbackData->statisticsSize, callbackData->statisticsTime,
callbackData->statisticsBitrate, callbackData->statisticsSpeed);
}
atomic_fetch_sub(&sessionInTransitMessageCountMap[callbackData->sessionId % SESSION_MAP_SIZE], 1);
// CLEAN STRUCT
callbackData->next = NULL;
av_free(callbackData);
} else {
monitorWait(100);
}
}
(*globalVm)->DetachCurrentThread(globalVm);
LOGD("Async callback block stopped.\n");
return NULL;
}
int saf_open(int safId) {
JNIEnv *env = NULL;
(*globalVm)->GetEnv(globalVm, (void**) &env, JNI_VERSION_1_6);
return (*env)->CallStaticIntMethod(env, configClass, safOpenMethod, safId);
}
int saf_close(int fd) {
JNIEnv *env = NULL;
(*globalVm)->GetEnv(globalVm, (void**) &env, JNI_VERSION_1_6);
return (*env)->CallStaticIntMethod(env, configClass, safCloseMethod, fd);
}
static void enableNativeRedirection() {
mutexLock();
if (redirectionEnabled != 0) {
mutexUnlock();
return;
}
redirectionEnabled = 1;
mutexUnlock();
int rc = pthread_create(&callbackThread, 0, callbackThreadFunction, 0);
if (rc != 0) {
LOGE("Failed to create callback thread (rc=%d).\n", rc);
return;
}
av_log_set_callback(ffmpegkit_log_callback_function);
set_report_callback(ffmpegkit_statistics_callback_function);
}
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
if ((*vm)->GetEnv(vm, (void**)(&env), JNI_VERSION_1_6) != JNI_OK) {
LOGE("OnLoad failed to GetEnv for class %s.\n", configClassName);
return JNI_FALSE;
}
jclass localConfigClass = (*env)->FindClass(env, configClassName);
if (localConfigClass == NULL) {
LOGE("OnLoad failed to FindClass %s.\n", configClassName);
return JNI_FALSE;
}
if ((*env)->RegisterNatives(env, localConfigClass, configMethods, 14) < 0) {
LOGE("OnLoad failed to RegisterNatives for class %s.\n", configClassName);
return JNI_FALSE;
}
jclass localStringClass = (*env)->FindClass(env, stringClassName);
if (localStringClass == NULL) {
LOGE("OnLoad failed to FindClass %s.\n", stringClassName);
return JNI_FALSE;
}
(*env)->GetJavaVM(env, &globalVm);
logMethod = (*env)->GetStaticMethodID(env, localConfigClass, "log", "(JI[B)V");
if (logMethod == NULL) {
LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "log");
return JNI_FALSE;
}
statisticsMethod = (*env)->GetStaticMethodID(env, localConfigClass, "statistics", "(JIFFJDDD)V");
if (statisticsMethod == NULL) {
LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "statistics");
return JNI_FALSE;
}
safOpenMethod = (*env)->GetStaticMethodID(env, localConfigClass, "safOpen", "(I)I");
if (safOpenMethod == NULL) {
LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "safOpen");
return JNI_FALSE;
}
safCloseMethod = (*env)->GetStaticMethodID(env, localConfigClass, "safClose", "(I)I");
if (safCloseMethod == NULL) {
LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "safClose");
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>");
return JNI_FALSE;
}
av_jni_set_java_vm(vm, NULL);
configClass = (jclass) ((*env)->NewGlobalRef(env, localConfigClass));
stringClass = (jclass) ((*env)->NewGlobalRef(env, localStringClass));
callbackDataHead = NULL;
callbackDataTail = NULL;
for(int i = 0; i<SESSION_MAP_SIZE; i++) {
atomic_init(&sessionMap[i], 0);
atomic_init(&sessionInTransitMessageCountMap[i], 0);
}
mutexInit();
monitorInit();
redirectionEnabled = 0;
av_set_saf_open(saf_open);
av_set_saf_close(saf_close);
enableNativeRedirection();
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeLogLevel(JNIEnv *env, jclass object, jint level) {
configuredLogLevel = level;
}
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeLogLevel(JNIEnv *env, jclass object) {
return configuredLogLevel;
}
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_enableNativeRedirection(JNIEnv *env, jclass object) {
enableNativeRedirection();
}
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_disableNativeRedirection(JNIEnv *env, jclass object) {
mutexLock();
if (redirectionEnabled != 1) {
mutexUnlock();
return;
}
redirectionEnabled = 0;
mutexUnlock();
av_log_set_callback(av_log_default_callback);
set_report_callback(NULL);
monitorNotify();
}
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeFFmpegVersion(JNIEnv *env, jclass object) {
return (*env)->NewStringUTF(env, FFMPEG_VERSION);
}
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeVersion(JNIEnv *env, jclass object) {
return (*env)->NewStringUTF(env, FFMPEG_KIT_VERSION);
}
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute(JNIEnv *env, jclass object, jlong id, jobjectArray stringArray) {
jstring *tempArray = NULL;
int argumentCount = 1;
char **argv = NULL;
// SETS DEFAULT LOG LEVEL BEFORE STARTING A NEW RUN
av_log_set_level(configuredLogLevel);
if (stringArray) {
int programArgumentCount = (*env)->GetArrayLength(env, stringArray);
argumentCount = programArgumentCount + 1;
tempArray = (jstring *) av_malloc(sizeof(jstring) * programArgumentCount);
}
/* PRESERVE USAGE FORMAT
*
* ffmpeg <arguments>
*/
argv = (char **)av_malloc(sizeof(char*) * (argumentCount));
argv[0] = (char *)av_malloc(sizeof(char) * (strlen(LIB_NAME) + 1));
strcpy(argv[0], LIB_NAME);
// PREPARE ARRAY ELEMENTS
if (stringArray) {
for (int i = 0; i < (argumentCount - 1); i++) {
tempArray[i] = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i);
if (tempArray[i] != NULL) {
argv[i + 1] = (char *) (*env)->GetStringUTFChars(env, tempArray[i], 0);
}
}
}
// REGISTER THE ID BEFORE STARTING THE SESSION
globalSessionId = (long) id;
addSession((long) id);
resetMessagesInTransmit(globalSessionId);
// RUN
int returnCode = ffmpeg_execute(argumentCount, argv);
// ALWAYS REMOVE THE ID FROM THE MAP
removeSession((long) id);
// CLEANUP
if (tempArray) {
for (int i = 0; i < (argumentCount - 1); i++) {
(*env)->ReleaseStringUTFChars(env, tempArray[i], argv[i + 1]);
}
av_free(tempArray);
}
av_free(argv[0]);
av_free(argv);
return returnCode;
}
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegCancel(JNIEnv *env, jclass object, jlong id) {
cancel_operation(id);
}
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_registerNewNativeFFmpegPipe(JNIEnv *env, jclass object, jstring ffmpegPipePath) {
const char *ffmpegPipePathString = (*env)->GetStringUTFChars(env, ffmpegPipePath, 0);
return mkfifo(ffmpegPipePathString, S_IRWXU | S_IRWXG | S_IROTH);
}
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeBuildDate(JNIEnv *env, jclass object) {
char buildDate[10];
sprintf(buildDate, "%d", FFMPEG_KIT_BUILD_DATE);
return (*env)->NewStringUTF(env, buildDate);
}
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeEnvironmentVariable(JNIEnv *env, jclass object, jstring variableName, jstring variableValue) {
const char *variableNameString = (*env)->GetStringUTFChars(env, variableName, 0);
const char *variableValueString = (*env)->GetStringUTFChars(env, variableValue, 0);
int rc = setenv(variableNameString, variableValueString, 1);
(*env)->ReleaseStringUTFChars(env, variableName, variableNameString);
(*env)->ReleaseStringUTFChars(env, variableValue, variableValueString);
return rc;
}
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal(JNIEnv *env, jclass object, jint signum) {
if (signum == SIGQUIT) {
handleSIGQUIT = 0;
} else if (signum == SIGINT) {
handleSIGINT = 0;
} else if (signum == SIGTERM) {
handleSIGTERM = 0;
} else if (signum == SIGXCPU) {
handleSIGXCPU = 0;
} else if (signum == SIGPIPE) {
handleSIGPIPE = 0;
}
}
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_messagesInTransmit(JNIEnv *env, jclass object, jlong id) {
return atomic_load(&sessionInTransitMessageCountMap[id % SESSION_MAP_SIZE]);
}
monitorUnInit
void monitorUnInit()
Definition ffmpegkit.c:229
statisticsCallbackDataAdd
void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, double time, double bitrate, double speed)
Definition ffmpegkit.c:315
Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeBuildDate
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeBuildDate(JNIEnv *env, jclass object)
Definition ffmpegkit.c:874
ffmpegkit_log_callback_function
void ffmpegkit_log_callback_function(void *ptr, int level, const char *format, va_list vargs)
Definition ffmpegkit.c:446
sessionMap
static atomic_short sessionMap[SESSION_MAP_SIZE]
Definition ffmpegkit.c:57
stringClass
static jclass stringClass
Definition ffmpegkit.c:90
lockMutex
static pthread_mutex_t lockMutex
Definition ffmpegkit.c:61
callbackDataRemove
struct CallbackData * callbackDataRemove()
Definition ffmpegkit.c:368
SESSION_MAP_SIZE
#define SESSION_MAP_SIZE
Definition ffmpegkit.c:56
callbackDataTail
struct CallbackData * callbackDataTail
Definition ffmpegkit.c:69
addSession
void addSession(long id)
Definition ffmpegkit.c:361
Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute(JNIEnv *env, jclass object, jlong id, jobjectArray stringArray)
Definition ffmpegkit.c:783
monitorNotify
void monitorNotify()
Definition ffmpegkit.c:264
Java_com_arthenica_ffmpegkit_FFmpegKitConfig_enableNativeRedirection
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_enableNativeRedirection(JNIEnv *env, jclass object)
Definition ffmpegkit.c:724
avutil_log_sanitize
static void avutil_log_sanitize(uint8_t *line)
Definition ffmpegkit.c:192
handleSIGINT
volatile int handleSIGINT
Definition ffmpegkit.c:103
Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeLogLevel
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeLogLevel(JNIEnv *env, jclass object, jint level)
Definition ffmpegkit.c:704
handleSIGTERM
volatile int handleSIGTERM
Definition ffmpegkit.c:104
saf_close
int saf_close(int fd)
Definition ffmpegkit.c:578
ffmpegkit_statistics_callback_function
void ffmpegkit_statistics_callback_function(int frameNumber, float fps, float quality, int64_t size, double time, double bitrate, double speed)
Definition ffmpegkit.c:494
Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegCancel
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegCancel(JNIEnv *env, jclass object, jlong id)
Definition ffmpegkit.c:849
configClassName
const char * configClassName
Definition ffmpegkit.c:96
Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeLogLevel
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeLogLevel(JNIEnv *env, jclass object)
Definition ffmpegkit.c:714
avutil_log_get_level_str
static const char * avutil_log_get_level_str(int level)
Definition ffmpegkit.c:135
avutil_log_format_line
static void avutil_log_format_line(void *avcl, int level, const char *fmt, va_list vl, AVBPrint part[4], int *print_prefix)
Definition ffmpegkit.c:160
Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeFFmpegVersion
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeFFmpegVersion(JNIEnv *env, jclass object)
Definition ffmpegkit.c:759
stringClassName
const char * stringClassName
Definition ffmpegkit.c:99
configMethods
JNINativeMethod configMethods[]
Definition ffmpegkit.c:115
monitorWait
void monitorWait(int milliSeconds)
Definition ffmpegkit.c:242
globalVm
static JavaVM * globalVm
Definition ffmpegkit.c:72
callbackDataHead
struct CallbackData * callbackDataHead
Definition ffmpegkit.c:68
callbackThread
pthread_t callbackThread
Definition ffmpegkit.c:65
Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal(JNIEnv *env, jclass object, jint signum)
Definition ffmpegkit.c:907
monitorCondition
static pthread_cond_t monitorCondition
Definition ffmpegkit.c:63
Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeVersion
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeVersion(JNIEnv *env, jclass object)
Definition ffmpegkit.c:770
monitorInit
void monitorInit()
Definition ffmpegkit.c:209
cancelSession
void cancelSession(long id)
Definition ffmpegkit.c:411
saf_open
int saf_open(int safId)
Definition ffmpegkit.c:569
globalSessionId
__thread long globalSessionId
Definition ffmpegkit.c:109
redirectionEnabled
int redirectionEnabled
Definition ffmpegkit.c:66
cancelRequested
int cancelRequested(long id)
Definition ffmpegkit.c:421
mutexUnlock
void mutexUnlock()
Definition ffmpegkit.c:238
Java_com_arthenica_ffmpegkit_FFmpegKitConfig_registerNewNativeFFmpegPipe
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_registerNewNativeFFmpegPipe(JNIEnv *env, jclass object, jstring ffmpegPipePath)
Definition ffmpegkit.c:861
safOpenMethod
static jmethodID safOpenMethod
Definition ffmpegkit.c:84
mutexUnInit
void mutexUnInit()
Definition ffmpegkit.c:225
LogType
#define LogType
Definition ffmpegkit.c:33
enableNativeRedirection
static void enableNativeRedirection()
Definition ffmpegkit.c:587
callbackThreadFunction
void * callbackThreadFunction()
Definition ffmpegkit.c:501
handleSIGPIPE
volatile int handleSIGPIPE
Definition ffmpegkit.c:106
monitorMutex
static pthread_mutex_t monitorMutex
Definition ffmpegkit.c:62
JNI_OnLoad
jint JNI_OnLoad(JavaVM *vm, void *reserved)
Definition ffmpegkit.c:615
Java_com_arthenica_ffmpegkit_FFmpegKitConfig_disableNativeRedirection
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_disableNativeRedirection(JNIEnv *env, jclass object)
Definition ffmpegkit.c:734
logMethod
static jmethodID logMethod
Definition ffmpegkit.c:78
handleSIGXCPU
volatile int handleSIGXCPU
Definition ffmpegkit.c:105
safCloseMethod
static jmethodID safCloseMethod
Definition ffmpegkit.c:87
resetMessagesInTransmit
void resetMessagesInTransmit(long id)
Definition ffmpegkit.c:434
configClass
static jclass configClass
Definition ffmpegkit.c:75
sessionInTransitMessageCountMap
static atomic_int sessionInTransitMessageCountMap[SESSION_MAP_SIZE]
Definition ffmpegkit.c:58
Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeEnvironmentVariable
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeEnvironmentVariable(JNIEnv *env, jclass object, jstring variableName, jstring variableValue)
Definition ffmpegkit.c:889
mutexLock
void mutexLock()
Definition ffmpegkit.c:234
mutexInit
void mutexInit()
Definition ffmpegkit.c:200
configuredLogLevel
int configuredLogLevel
Definition ffmpegkit.c:112
StatisticsType
#define StatisticsType
Definition ffmpegkit.c:34
ffmpeg_execute
int ffmpeg_execute(int argc, char **argv)
Definition fftools_ffmpeg.c:4378
stringConstructor
static jmethodID stringConstructor
Definition ffmpegkit.c:93
Java_com_arthenica_ffmpegkit_FFmpegKitConfig_messagesInTransmit
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_messagesInTransmit(JNIEnv *env, jclass object, jlong id)
Definition ffmpegkit.c:929
statisticsMethod
static jmethodID statisticsMethod
Definition ffmpegkit.c:81
handleSIGQUIT
volatile int handleSIGQUIT
Definition ffmpegkit.c:102
logCallbackDataAdd
void logCallbackDataAdd(int level, AVBPrint *data)
Definition ffmpegkit.c:276
removeSession
void removeSession(long id)
Definition ffmpegkit.c:402
ffmpegkit.h
FFMPEG_KIT_VERSION
#define FFMPEG_KIT_VERSION
Definition ffmpegkit.h:30
LIB_NAME
#define LIB_NAME
Definition ffmpegkit.h:33
LOGD
#define LOGD(...)
Definition ffmpegkit.h:39
LOGE
#define LOGE(...)
Definition ffmpegkit.h:48
Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprobeExecute
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprobeExecute(JNIEnv *env, jclass object, jlong id, jobjectArray stringArray)
Definition ffprobekit.c:48
ffprobekit.h
AV_LOG_STDERR
#define AV_LOG_STDERR
Definition fftools_cmdutils.h:82
set_report_callback
void set_report_callback(void(*callback)(int, float, float, int64_t, double, double, double))
Definition fftools_ffmpeg.c:4362
cancel_operation
void cancel_operation(long id)
Definition fftools_ffmpeg.c:4367
fftools_ffmpeg.h
pthread_mutex_lock
#define pthread_mutex_lock(a)
Definition fftools_ffprobe.c:102
pthread_mutex_unlock
#define pthread_mutex_unlock(a)
Definition fftools_ffprobe.c:106
CallbackData
Definition ffmpegkit.c:37
CallbackData::logLevel
int logLevel
Definition ffmpegkit.c:41
CallbackData::statisticsBitrate
double statisticsBitrate
Definition ffmpegkit.c:49
CallbackData::statisticsQuality
float statisticsQuality
Definition ffmpegkit.c:46
CallbackData::statisticsTime
double statisticsTime
Definition ffmpegkit.c:48
CallbackData::type
int type
Definition ffmpegkit.c:38
CallbackData::next
struct CallbackData * next
Definition ffmpegkit.c:52
CallbackData::statisticsSpeed
double statisticsSpeed
Definition ffmpegkit.c:50
CallbackData::statisticsFrameNumber
int statisticsFrameNumber
Definition ffmpegkit.c:44
CallbackData::statisticsFps
float statisticsFps
Definition ffmpegkit.c:45
CallbackData::sessionId
long sessionId
Definition ffmpegkit.c:39
CallbackData::logData
AVBPrint logData
Definition ffmpegkit.c:42
CallbackData::statisticsSize
int64_t statisticsSize
Definition ffmpegkit.c:47