26#include "libavcodec/jni.h"
27#include "libavutil/bprint.h"
28#include "libavutil/file.h"
34# define StatisticsType 2
56#define SESSION_MAP_SIZE 1000
160static void avutil_log_format_line(
void *avcl,
int level,
const char *fmt, va_list vl, AVBPrint part[4],
int *print_prefix) {
161 int flags = av_log_get_flags();
162 AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
163 av_bprint_init(part+0, 0, 1);
164 av_bprint_init(part+1, 0, 1);
165 av_bprint_init(part+2, 0, 1);
166 av_bprint_init(part+3, 0, 65536);
168 if (*print_prefix && avc) {
169 if (avc->parent_log_context_offset) {
170 AVClass** parent = *(AVClass ***) (((uint8_t *) avcl) +
171 avc->parent_log_context_offset);
172 if (parent && *parent) {
173 av_bprintf(part+0,
"[%s @ %p] ",
174 (*parent)->item_name(parent), parent);
177 av_bprintf(part+1,
"[%s @ %p] ",
178 avc->item_name(avcl), avcl);
181 if (*print_prefix && (level > AV_LOG_QUIET) && (flags & AV_LOG_PRINT_LEVEL))
184 av_vbprintf(part+3, fmt, vl);
186 if(*part[0].str || *part[1].str || *part[2].str || *part[3].str) {
187 char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0;
188 *print_prefix = lastc ==
'\n' || lastc ==
'\r';
194 if(*line < 0x08 || (*line > 0x0D && *line < 0x20))
201 pthread_mutexattr_t attributes;
202 pthread_mutexattr_init(&attributes);
203 pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
205 pthread_mutex_init(&
lockMutex, &attributes);
206 pthread_mutexattr_destroy(&attributes);
210 pthread_mutexattr_t attributes;
211 pthread_mutexattr_init(&attributes);
212 pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
214 pthread_condattr_t cattributes;
215 pthread_condattr_init(&cattributes);
216 pthread_condattr_setpshared(&cattributes, PTHREAD_PROCESS_PRIVATE);
219 pthread_mutexattr_destroy(&attributes);
222 pthread_condattr_destroy(&cattributes);
247 rc = gettimeofday(&tp, NULL);
252 ts.tv_sec = tp.tv_sec;
253 ts.tv_nsec = tp.tv_usec * 1000;
254 ts.tv_sec += milliSeconds / 1000;
255 ts.tv_nsec += (milliSeconds % 1000)*1000000;
256 ts.tv_sec += ts.tv_nsec / 1000000000L;
257 ts.tv_nsec = ts.tv_nsec % 1000000000L;
283 av_bprint_init(&newData->
logData, 0, AV_BPRINT_SIZE_UNLIMITED);
284 av_bprintf(&newData->
logData,
"%s", data->str);
285 newData->
next = NULL;
294 LOGE(
"Dangling callback data head detected. This can cause memory leak.");
300 oldTail->
next = newData;
329 newData->
next = NULL;
338 LOGE(
"Dangling callback data head detected. This can cause memory leak.");
344 oldTail->
next = newData;
379 if (nextHead == NULL) {
381 LOGE(
"Head and tail callback data pointers do not match for single callback data element. This can cause memory leak.");
449 int print_prefix = 1;
454 int activeLogLevel = av_log_get_level();
457 if ((activeLogLevel == AV_LOG_QUIET && level !=
AV_LOG_STDERR) || (level > activeLogLevel)) {
461 av_bprint_init(&fullLine, 0, AV_BPRINT_SIZE_UNLIMITED);
470 av_bprintf(&fullLine,
"%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
472 if (fullLine.len > 0) {
476 av_bprint_finalize(part, NULL);
477 av_bprint_finalize(part+1, NULL);
478 av_bprint_finalize(part+2, NULL);
479 av_bprint_finalize(part+3, NULL);
480 av_bprint_finalize(&fullLine, NULL);
503 jint getEnvRc = (*globalVm)->GetEnv(
globalVm, (
void**) &env, JNI_VERSION_1_6);
504 if (getEnvRc != JNI_OK) {
505 if (getEnvRc != JNI_EDETACHED) {
506 LOGE(
"Callback thread failed to GetEnv for class %s with rc %d.\n",
configClassName, getEnvRc);
510 if ((*globalVm)->AttachCurrentThread(
globalVm, &env, NULL) != 0) {
516 LOGD(
"Async callback block started.\n");
521 if (callbackData != NULL) {
526 int size = callbackData->
logData.len;
528 jbyteArray byteArray = (jbyteArray) (*env)->NewByteArray(env, size);
529 (*env)->SetByteArrayRegion(env, byteArray, 0, size, callbackData->
logData.str);
531 (*env)->DeleteLocalRef(env, byteArray);
534 av_bprint_finalize(&callbackData->
logData, NULL);
551 callbackData->
next = NULL;
552 av_free(callbackData);
559 (*globalVm)->DetachCurrentThread(
globalVm);
561 LOGD(
"Async callback block stopped.\n");
571 (*globalVm)->GetEnv(
globalVm, (
void**) &env, JNI_VERSION_1_6);
580 (*globalVm)->GetEnv(
globalVm, (
void**) &env, JNI_VERSION_1_6);
593 if ((*vm)->GetEnv(vm, (
void**)(&env), JNI_VERSION_1_6) != JNI_OK) {
599 if (localConfigClass == NULL) {
604 if ((*env)->RegisterNatives(env, localConfigClass,
configMethods, 14) < 0) {
610 if (localStringClass == NULL) {
617 logMethod = (*env)->GetStaticMethodID(env, localConfigClass,
"log",
"(JI[B)V");
619 LOGE(
"OnLoad thread failed to GetStaticMethodID for %s.\n",
"log");
623 statisticsMethod = (*env)->GetStaticMethodID(env, localConfigClass,
"statistics",
"(JIFFJIDD)V");
625 LOGE(
"OnLoad thread failed to GetStaticMethodID for %s.\n",
"statistics");
629 safOpenMethod = (*env)->GetStaticMethodID(env, localConfigClass,
"safOpen",
"(I)I");
631 LOGE(
"OnLoad thread failed to GetStaticMethodID for %s.\n",
"safOpen");
635 safCloseMethod = (*env)->GetStaticMethodID(env, localConfigClass,
"safClose",
"(I)I");
637 LOGE(
"OnLoad thread failed to GetStaticMethodID for %s.\n",
"safClose");
641 stringConstructor = (*env)->GetMethodID(env, localStringClass,
"<init>",
"([BLjava/lang/String;)V");
643 LOGE(
"OnLoad thread failed to GetMethodID for %s.\n",
"<init>");
647 av_jni_set_java_vm(vm, NULL);
649 configClass = (jclass) ((*env)->NewGlobalRef(env, localConfigClass));
650 stringClass = (jclass) ((*env)->NewGlobalRef(env, localStringClass));
668 return JNI_VERSION_1_6;
711 LOGE(
"Failed to create callback thread (rc=%d).\n", rc);
737 av_log_set_callback(av_log_default_callback);
751 return (*env)->NewStringUTF(env, FFMPEG_VERSION);
775 jstring *tempArray = NULL;
776 int argumentCount = 1;
783 int programArgumentCount = (*env)->GetArrayLength(env, stringArray);
784 argumentCount = programArgumentCount + 1;
786 tempArray = (jstring *) av_malloc(
sizeof(jstring) * programArgumentCount);
793 argv = (
char **)av_malloc(
sizeof(
char*) * (argumentCount));
794 argv[0] = (
char *)av_malloc(
sizeof(
char) * (strlen(
LIB_NAME) + 1));
799 for (
int i = 0; i < (argumentCount - 1); i++) {
800 tempArray[i] = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i);
801 if (tempArray[i] != NULL) {
802 argv[i + 1] = (
char *) (*env)->GetStringUTFChars(env, tempArray[i], 0);
821 for (
int i = 0; i < (argumentCount - 1); i++) {
822 (*env)->ReleaseStringUTFChars(env, tempArray[i], argv[i + 1]);
853 const char *ffmpegPipePathString = (*env)->GetStringUTFChars(env, ffmpegPipePath, 0);
855 return mkfifo(ffmpegPipePathString, S_IRWXU | S_IRWXG | S_IROTH);
867 sprintf(buildDate,
"%d", FFMPEG_KIT_BUILD_DATE);
868 return (*env)->NewStringUTF(env, buildDate);
881 const char *variableNameString = (*env)->GetStringUTFChars(env, variableName, 0);
882 const char *variableValueString = (*env)->GetStringUTFChars(env, variableValue, 0);
884 int rc = setenv(variableNameString, variableValueString, 1);
886 (*env)->ReleaseStringUTFChars(env, variableName, variableNameString);
887 (*env)->ReleaseStringUTFChars(env, variableValue, variableValueString);
899 if (signum == SIGQUIT) {
901 }
else if (signum == SIGINT) {
903 }
else if (signum == SIGTERM) {
905 }
else if (signum == SIGXCPU) {
907 }
else if (signum == SIGPIPE) {
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeBuildDate(JNIEnv *env, jclass object)
void ffmpegkit_log_callback_function(void *ptr, int level, const char *format, va_list vargs)
static atomic_short sessionMap[SESSION_MAP_SIZE]
static jclass stringClass
static pthread_mutex_t lockMutex
struct CallbackData * callbackDataRemove()
struct CallbackData * callbackDataTail
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute(JNIEnv *env, jclass object, jlong id, jobjectArray stringArray)
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_enableNativeRedirection(JNIEnv *env, jclass object)
static void avutil_log_sanitize(uint8_t *line)
volatile int handleSIGINT
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeLogLevel(JNIEnv *env, jclass object, jint level)
volatile int handleSIGTERM
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegCancel(JNIEnv *env, jclass object, jlong id)
const char * configClassName
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeLogLevel(JNIEnv *env, jclass object)
static const char * avutil_log_get_level_str(int level)
void ffmpegkit_statistics_callback_function(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed)
static void avutil_log_format_line(void *avcl, int level, const char *fmt, va_list vl, AVBPrint part[4], int *print_prefix)
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeFFmpegVersion(JNIEnv *env, jclass object)
void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed)
const char * stringClassName
JNINativeMethod configMethods[]
void monitorWait(int milliSeconds)
struct CallbackData * callbackDataHead
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal(JNIEnv *env, jclass object, jint signum)
static pthread_cond_t monitorCondition
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeVersion(JNIEnv *env, jclass object)
void cancelSession(long id)
__thread long globalSessionId
int cancelRequested(long id)
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_registerNewNativeFFmpegPipe(JNIEnv *env, jclass object, jstring ffmpegPipePath)
static jmethodID safOpenMethod
void * callbackThreadFunction()
volatile int handleSIGPIPE
static pthread_mutex_t monitorMutex
jint JNI_OnLoad(JavaVM *vm, void *reserved)
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_disableNativeRedirection(JNIEnv *env, jclass object)
static jmethodID logMethod
volatile int handleSIGXCPU
static jmethodID safCloseMethod
void resetMessagesInTransmit(long id)
static jclass configClass
static atomic_int sessionInTransitMessageCountMap[SESSION_MAP_SIZE]
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeEnvironmentVariable(JNIEnv *env, jclass object, jstring variableName, jstring variableValue)
int ffmpeg_execute(int argc, char **argv)
static jmethodID stringConstructor
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_messagesInTransmit(JNIEnv *env, jclass object, jlong id)
static jmethodID statisticsMethod
volatile int handleSIGQUIT
void logCallbackDataAdd(int level, AVBPrint *data)
void removeSession(long id)
#define FFMPEG_KIT_VERSION
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprobeExecute(JNIEnv *env, jclass object, jlong id, jobjectArray stringArray)
struct CallbackData * next
int statisticsFrameNumber