21 #include <stdatomic.h>
22 #include <sys/types.h>
26 #include "libavcodec/jni.h"
27 #include "libavutil/bprint.h"
33 # define StatisticsType 2
156 static void avutil_log_format_line(
void *avcl,
int level,
const char *fmt, va_list vl, AVBPrint part[4],
int *print_prefix) {
157 int flags = av_log_get_flags();
158 AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
159 av_bprint_init(part+0, 0, 1);
160 av_bprint_init(part+1, 0, 1);
161 av_bprint_init(part+2, 0, 1);
162 av_bprint_init(part+3, 0, 65536);
164 if (*print_prefix && avc) {
165 if (avc->parent_log_context_offset) {
166 AVClass** parent = *(AVClass ***) (((uint8_t *) avcl) +
167 avc->parent_log_context_offset);
168 if (parent && *parent) {
169 av_bprintf(part+0,
"[%s @ %p] ",
170 (*parent)->item_name(parent), parent);
173 av_bprintf(part+1,
"[%s @ %p] ",
174 avc->item_name(avcl), avcl);
177 if (*print_prefix && (level > AV_LOG_QUIET) && (flags & AV_LOG_PRINT_LEVEL))
180 av_vbprintf(part+3, fmt, vl);
182 if(*part[0].str || *part[1].str || *part[2].str || *part[3].str) {
183 char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0;
184 *print_prefix = lastc ==
'\n' || lastc ==
'\r';
190 if(*line < 0x08 || (*line > 0x0D && *line < 0x20))
197 pthread_mutexattr_t attributes;
198 pthread_mutexattr_init(&attributes);
199 pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
201 pthread_mutex_init(&
lockMutex, &attributes);
202 pthread_mutexattr_destroy(&attributes);
206 pthread_mutexattr_t attributes;
207 pthread_mutexattr_init(&attributes);
208 pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
210 pthread_condattr_t cattributes;
211 pthread_condattr_init(&cattributes);
212 pthread_condattr_setpshared(&cattributes, PTHREAD_PROCESS_PRIVATE);
215 pthread_mutexattr_destroy(&attributes);
218 pthread_condattr_destroy(&cattributes);
243 rc = gettimeofday(&tp, NULL);
248 ts.tv_sec = tp.tv_sec;
249 ts.tv_nsec = tp.tv_usec * 1000;
250 ts.tv_sec += milliSeconds / 1000;
251 ts.tv_nsec += (milliSeconds % 1000)*1000000;
252 ts.tv_sec += ts.tv_nsec / 1000000000L;
253 ts.tv_nsec = ts.tv_nsec % 1000000000L;
279 av_bprint_init(&newData->
logData, 0, AV_BPRINT_SIZE_UNLIMITED);
280 av_bprintf(&newData->
logData,
"%s", data->str);
281 newData->
next = NULL;
290 LOGE(
"Dangling callback data head detected. This can cause memory leak.");
296 oldTail->
next = newData;
325 newData->
next = NULL;
334 LOGE(
"Dangling callback data head detected. This can cause memory leak.");
340 oldTail->
next = newData;
375 if (nextHead == NULL) {
377 LOGE(
"Head and tail callback data pointers do not match for single callback data element. This can cause memory leak.");
445 int print_prefix = 1;
450 int activeLogLevel = av_log_get_level();
453 if ((activeLogLevel == AV_LOG_QUIET && level !=
AV_LOG_STDERR) || (level > activeLogLevel)) {
457 av_bprint_init(&fullLine, 0, AV_BPRINT_SIZE_UNLIMITED);
466 av_bprintf(&fullLine,
"%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
468 if (fullLine.len > 0) {
472 av_bprint_finalize(part, NULL);
473 av_bprint_finalize(part+1, NULL);
474 av_bprint_finalize(part+2, NULL);
475 av_bprint_finalize(part+3, NULL);
476 av_bprint_finalize(&fullLine, NULL);
499 jint getEnvRc = (*globalVm)->GetEnv(
globalVm, (
void**) &env, JNI_VERSION_1_6);
500 if (getEnvRc != JNI_OK) {
501 if (getEnvRc != JNI_EDETACHED) {
502 LOGE(
"Callback thread failed to GetEnv for class %s with rc %d.\n",
configClassName, getEnvRc);
506 if ((*globalVm)->AttachCurrentThread(
globalVm, &env, NULL) != 0) {
512 LOGD(
"Async callback block started.\n");
517 if (callbackData != NULL) {
522 int size = callbackData->
logData.len;
524 jbyteArray byteArray = (jbyteArray) (*env)->NewByteArray(env, size);
525 (*env)->SetByteArrayRegion(env, byteArray, 0, size, callbackData->
logData.str);
527 (*env)->DeleteLocalRef(env, byteArray);
530 av_bprint_finalize(&callbackData->
logData, NULL);
547 callbackData->
next = NULL;
548 av_free(callbackData);
555 (*globalVm)->DetachCurrentThread(
globalVm);
557 LOGD(
"Async callback block stopped.\n");
567 (*globalVm)->GetEnv(
globalVm, (
void**) &env, JNI_VERSION_1_6);
580 if ((*vm)->GetEnv(vm, (
void**)(&env), JNI_VERSION_1_6) != JNI_OK) {
586 if (localConfigClass == NULL) {
591 if ((*env)->RegisterNatives(env, localConfigClass,
configMethods, 14) < 0) {
597 if (localStringClass == NULL) {
604 logMethod = (*env)->GetStaticMethodID(env, localConfigClass,
"log",
"(JI[B)V");
606 LOGE(
"OnLoad thread failed to GetStaticMethodID for %s.\n",
"log");
610 statisticsMethod = (*env)->GetStaticMethodID(env, localConfigClass,
"statistics",
"(JIFFJIDD)V");
612 LOGE(
"OnLoad thread failed to GetStaticMethodID for %s.\n",
"statistics");
618 LOGE(
"OnLoad thread failed to GetStaticMethodID for %s.\n",
"closeParcelFileDescriptor");
622 stringConstructor = (*env)->GetMethodID(env, localStringClass,
"<init>",
"([BLjava/lang/String;)V");
624 LOGE(
"OnLoad thread failed to GetMethodID for %s.\n",
"<init>");
628 av_jni_set_java_vm(vm, NULL);
630 configClass = (jclass) ((*env)->NewGlobalRef(env, localConfigClass));
631 stringClass = (jclass) ((*env)->NewGlobalRef(env, localStringClass));
646 return JNI_VERSION_1_6;
689 LOGE(
"Failed to create callback thread (rc=%d).\n", rc);
715 av_log_set_callback(av_log_default_callback);
729 return (*env)->NewStringUTF(env, FFMPEG_VERSION);
753 jstring *tempArray = NULL;
754 int argumentCount = 1;
761 int programArgumentCount = (*env)->GetArrayLength(env, stringArray);
762 argumentCount = programArgumentCount + 1;
764 tempArray = (jstring *) av_malloc(
sizeof(jstring) * programArgumentCount);
771 argv = (
char **)av_malloc(
sizeof(
char*) * (argumentCount));
772 argv[0] = (
char *)av_malloc(
sizeof(
char) * (strlen(
LIB_NAME) + 1));
777 for (
int i = 0; i < (argumentCount - 1); i++) {
778 tempArray[i] = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i);
779 if (tempArray[i] != NULL) {
780 argv[i + 1] = (
char *) (*env)->GetStringUTFChars(env, tempArray[i], 0);
799 for (
int i = 0; i < (argumentCount - 1); i++) {
800 (*env)->ReleaseStringUTFChars(env, tempArray[i], argv[i + 1]);
831 const char *ffmpegPipePathString = (*env)->GetStringUTFChars(env, ffmpegPipePath, 0);
833 return mkfifo(ffmpegPipePathString, S_IRWXU | S_IRWXG | S_IROTH);
845 sprintf(buildDate,
"%d", FFMPEG_KIT_BUILD_DATE);
846 return (*env)->NewStringUTF(env, buildDate);
859 const char *variableNameString = (*env)->GetStringUTFChars(env, variableName, 0);
860 const char *variableValueString = (*env)->GetStringUTFChars(env, variableValue, 0);
862 int rc = setenv(variableNameString, variableValueString, 1);
864 (*env)->ReleaseStringUTFChars(env, variableName, variableNameString);
865 (*env)->ReleaseStringUTFChars(env, variableValue, variableValueString);
877 if (signum == SIGQUIT) {
879 }
else if (signum == SIGINT) {
881 }
else if (signum == SIGTERM) {
883 }
else if (signum == SIGXCPU) {
885 }
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
__thread volatile long sessionId
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)
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)
void * callbackThreadFunction()
static pthread_cond_t monitorCondition
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeVersion(JNIEnv *env, jclass object)
void cancelSession(long id)
struct CallbackData * callbackDataRemove()
int cancelRequested(long id)
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_registerNewNativeFFmpegPipe(JNIEnv *env, jclass object, jstring ffmpegPipePath)
volatile int handleSIGPIPE
const int SESSION_MAP_SIZE
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
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
static jmethodID closeParcelFileDescriptorMethod
volatile int handleSIGQUIT
void logCallbackDataAdd(int level, AVBPrint *data)
static const char * avutil_log_get_level_str(int level)
void closeParcelFileDescriptor(int fd)
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