FFmpegKit Android API  4.4
ffmpegkit.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-2021 Taner Sener
3  *
4  * This file is part of FFmpegKit.
5  *
6  * FFmpegKit is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * FFmpegKit is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <pthread.h>
21 #include <stdatomic.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 
25 #include "config.h"
26 #include "libavcodec/jni.h"
27 #include "libavutil/bprint.h"
28 #include "fftools_ffmpeg.h"
29 #include "ffmpegkit.h"
30 #include "ffprobekit.h"
31 
32 # define LogType 1
33 # define StatisticsType 2
34 
36 struct CallbackData {
37  int type; // 1 (log callback) or 2 (statistics callback)
38  long sessionId; // session identifier
39 
40  int logLevel; // log level
41  AVBPrint logData; // log data
42 
43  int statisticsFrameNumber; // statistics frame number
44  float statisticsFps; // statistics fps
45  float statisticsQuality; // statistics quality
46  int64_t statisticsSize; // statistics size
47  int statisticsTime; // statistics time
48  double statisticsBitrate; // statistics bitrate
49  double statisticsSpeed; // statistics speed
50 
51  struct CallbackData *next;
52 };
53 
55 const int SESSION_MAP_SIZE = 1000;
56 static atomic_short sessionMap[SESSION_MAP_SIZE];
58 
60 static pthread_mutex_t lockMutex;
61 static pthread_mutex_t monitorMutex;
62 static pthread_cond_t monitorCondition;
63 
64 pthread_t callbackThread;
66 
69 
71 static JavaVM *globalVm;
72 
74 static jclass configClass;
75 
77 static jmethodID logMethod;
78 
80 static jmethodID statisticsMethod;
81 
84 
86 static jclass stringClass;
87 
89 static jmethodID stringConstructor;
90 
92 const char *configClassName = "com/arthenica/ffmpegkit/FFmpegKitConfig";
93 
95 const char *stringClassName = "java/lang/String";
96 
98 volatile int handleSIGQUIT = 1;
99 volatile int handleSIGINT = 1;
100 volatile int handleSIGTERM = 1;
101 volatile int handleSIGXCPU = 1;
102 volatile int handleSIGPIPE = 1;
103 
105 __thread volatile long sessionId = 0;
106 
108 int configuredLogLevel = AV_LOG_INFO;
109 
111 JNINativeMethod configMethods[] = {
112  {"enableNativeRedirection", "()V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_enableNativeRedirection},
113  {"disableNativeRedirection", "()V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_disableNativeRedirection},
114  {"setNativeLogLevel", "(I)V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeLogLevel},
115  {"getNativeLogLevel", "()I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeLogLevel},
116  {"getNativeFFmpegVersion", "()Ljava/lang/String;", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeFFmpegVersion},
117  {"getNativeVersion", "()Ljava/lang/String;", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeVersion},
118  {"nativeFFmpegExecute", "(J[Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute},
119  {"nativeFFmpegCancel", "(J)V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegCancel},
120  {"nativeFFprobeExecute", "(J[Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprobeExecute},
121  {"registerNewNativeFFmpegPipe", "(Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_registerNewNativeFFmpegPipe},
122  {"getNativeBuildDate", "()Ljava/lang/String;", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeBuildDate},
123  {"setNativeEnvironmentVariable", "(Ljava/lang/String;Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeEnvironmentVariable},
124  {"ignoreNativeSignal", "(I)V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal},
125  {"messagesInTransmit", "(J)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_messagesInTransmit}
126 };
127 
129 int ffmpeg_execute(int argc, char **argv);
130 
131 static const char *avutil_log_get_level_str(int level) {
132  switch (level) {
133  case AV_LOG_STDERR:
134  return "stderr";
135  case AV_LOG_QUIET:
136  return "quiet";
137  case AV_LOG_DEBUG:
138  return "debug";
139  case AV_LOG_VERBOSE:
140  return "verbose";
141  case AV_LOG_INFO:
142  return "info";
143  case AV_LOG_WARNING:
144  return "warning";
145  case AV_LOG_ERROR:
146  return "error";
147  case AV_LOG_FATAL:
148  return "fatal";
149  case AV_LOG_PANIC:
150  return "panic";
151  default:
152  return "";
153  }
154 }
155 
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);
163 
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);
171  }
172  }
173  av_bprintf(part+1, "[%s @ %p] ",
174  avc->item_name(avcl), avcl);
175  }
176 
177  if (*print_prefix && (level > AV_LOG_QUIET) && (flags & AV_LOG_PRINT_LEVEL))
178  av_bprintf(part+2, "[%s] ", avutil_log_get_level_str(level));
179 
180  av_vbprintf(part+3, fmt, vl);
181 
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';
185  }
186 }
187 
188 static void avutil_log_sanitize(uint8_t *line) {
189  while(*line){
190  if(*line < 0x08 || (*line > 0x0D && *line < 0x20))
191  *line='?';
192  line++;
193  }
194 }
195 
196 void mutexInit() {
197  pthread_mutexattr_t attributes;
198  pthread_mutexattr_init(&attributes);
199  pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
200 
201  pthread_mutex_init(&lockMutex, &attributes);
202  pthread_mutexattr_destroy(&attributes);
203 }
204 
205 void monitorInit() {
206  pthread_mutexattr_t attributes;
207  pthread_mutexattr_init(&attributes);
208  pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
209 
210  pthread_condattr_t cattributes;
211  pthread_condattr_init(&cattributes);
212  pthread_condattr_setpshared(&cattributes, PTHREAD_PROCESS_PRIVATE);
213 
214  pthread_mutex_init(&monitorMutex, &attributes);
215  pthread_mutexattr_destroy(&attributes);
216 
217  pthread_cond_init(&monitorCondition, &cattributes);
218  pthread_condattr_destroy(&cattributes);
219 }
220 
221 void mutexUnInit() {
222  pthread_mutex_destroy(&lockMutex);
223 }
224 
226  pthread_mutex_destroy(&monitorMutex);
227  pthread_cond_destroy(&monitorCondition);
228 }
229 
230 void mutexLock() {
232 }
233 
234 void mutexUnlock() {
236 }
237 
238 void monitorWait(int milliSeconds) {
239  struct timeval tp;
240  struct timespec ts;
241  int rc;
242 
243  rc = gettimeofday(&tp, NULL);
244  if (rc) {
245  return;
246  }
247 
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;
254 
256  pthread_cond_timedwait(&monitorCondition, &monitorMutex, &ts);
258 }
259 
262  pthread_cond_signal(&monitorCondition);
264 }
265 
272 void logCallbackDataAdd(int level, AVBPrint *data) {
273 
274  // CREATE DATA STRUCT FIRST
275  struct CallbackData *newData = (struct CallbackData*)av_malloc(sizeof(struct CallbackData));
276  newData->type = LogType;
277  newData->sessionId = sessionId;
278  newData->logLevel = level;
279  av_bprint_init(&newData->logData, 0, AV_BPRINT_SIZE_UNLIMITED);
280  av_bprintf(&newData->logData, "%s", data->str);
281  newData->next = NULL;
282 
283  mutexLock();
284 
285  // INSERT IT TO THE END OF QUEUE
286  if (callbackDataTail == NULL) {
287  callbackDataTail = newData;
288 
289  if (callbackDataHead != NULL) {
290  LOGE("Dangling callback data head detected. This can cause memory leak.");
291  } else {
292  callbackDataHead = newData;
293  }
294  } else {
295  struct CallbackData *oldTail = callbackDataTail;
296  oldTail->next = newData;
297 
298  callbackDataTail = newData;
299  }
300 
301  mutexUnlock();
302 
303  monitorNotify();
304 
306 }
307 
311 void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed) {
312 
313  // CREATE DATA STRUCT FIRST
314  struct CallbackData *newData = (struct CallbackData*)av_malloc(sizeof(struct CallbackData));
315  newData->type = StatisticsType;
316  newData->sessionId = sessionId;
317  newData->statisticsFrameNumber = frameNumber;
318  newData->statisticsFps = fps;
319  newData->statisticsQuality = quality;
320  newData->statisticsSize = size;
321  newData->statisticsTime = time;
322  newData->statisticsBitrate = bitrate;
323  newData->statisticsSpeed = speed;
324 
325  newData->next = NULL;
326 
327  mutexLock();
328 
329  // INSERT IT TO THE END OF QUEUE
330  if (callbackDataTail == NULL) {
331  callbackDataTail = newData;
332 
333  if (callbackDataHead != NULL) {
334  LOGE("Dangling callback data head detected. This can cause memory leak.");
335  } else {
336  callbackDataHead = newData;
337  }
338  } else {
339  struct CallbackData *oldTail = callbackDataTail;
340  oldTail->next = newData;
341 
342  callbackDataTail = newData;
343  }
344 
345  mutexUnlock();
346 
347  monitorNotify();
348 
350 }
351 
357 void addSession(long id) {
358  atomic_store(&sessionMap[id % SESSION_MAP_SIZE], 1);
359 }
360 
365  struct CallbackData *currentData;
366 
367  mutexLock();
368 
369  if (callbackDataHead == NULL) {
370  currentData = NULL;
371  } else {
372  currentData = callbackDataHead;
373 
374  struct CallbackData *nextHead = currentData->next;
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.");
378  } else {
379  callbackDataTail = NULL;
380  }
381  callbackDataHead = NULL;
382 
383  } else {
384  callbackDataHead = nextHead;
385  }
386  }
387 
388  mutexUnlock();
389 
390  return currentData;
391 }
392 
398 void removeSession(long id) {
399  atomic_store(&sessionMap[id % SESSION_MAP_SIZE], 0);
400 }
401 
407 void cancelSession(long id) {
408  atomic_store(&sessionMap[id % SESSION_MAP_SIZE], 2);
409 }
410 
417 int cancelRequested(long id) {
418  if (atomic_load(&sessionMap[id % SESSION_MAP_SIZE]) == 2) {
419  return 1;
420  } else {
421  return 0;
422  }
423 }
424 
430 void resetMessagesInTransmit(long id) {
431  atomic_store(&sessionInTransitMessageCountMap[id % SESSION_MAP_SIZE], 0);
432 }
433 
442 void ffmpegkit_log_callback_function(void *ptr, int level, const char* format, va_list vargs) {
443  AVBPrint fullLine;
444  AVBPrint part[4];
445  int print_prefix = 1;
446 
447  if (level >= 0) {
448  level &= 0xff;
449  }
450  int activeLogLevel = av_log_get_level();
451 
452  // AV_LOG_STDERR logs are always redirected
453  if ((activeLogLevel == AV_LOG_QUIET && level != AV_LOG_STDERR) || (level > activeLogLevel)) {
454  return;
455  }
456 
457  av_bprint_init(&fullLine, 0, AV_BPRINT_SIZE_UNLIMITED);
458 
459  avutil_log_format_line(ptr, level, format, vargs, part, &print_prefix);
460  avutil_log_sanitize(part[0].str);
461  avutil_log_sanitize(part[1].str);
462  avutil_log_sanitize(part[2].str);
463  avutil_log_sanitize(part[3].str);
464 
465  // COMBINE ALL 4 LOG PARTS
466  av_bprintf(&fullLine, "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
467 
468  if (fullLine.len > 0) {
469  logCallbackDataAdd(level, &fullLine);
470  }
471 
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);
477 }
478 
490 void ffmpegkit_statistics_callback_function(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed) {
491  statisticsCallbackDataAdd(frameNumber, fps, quality, size, time, bitrate, speed);
492 }
493 
498  JNIEnv *env;
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);
503  return NULL;
504  }
505 
506  if ((*globalVm)->AttachCurrentThread(globalVm, &env, NULL) != 0) {
507  LOGE("Callback thread failed to AttachCurrentThread for class %s.\n", configClassName);
508  return NULL;
509  }
510  }
511 
512  LOGD("Async callback block started.\n");
513 
514  while(redirectionEnabled) {
515 
516  struct CallbackData *callbackData = callbackDataRemove();
517  if (callbackData != NULL) {
518  if (callbackData->type == LogType) {
519 
520  // LOG CALLBACK
521 
522  int size = callbackData->logData.len;
523 
524  jbyteArray byteArray = (jbyteArray) (*env)->NewByteArray(env, size);
525  (*env)->SetByteArrayRegion(env, byteArray, 0, size, callbackData->logData.str);
526  (*env)->CallStaticVoidMethod(env, configClass, logMethod, (jlong) callbackData->sessionId, callbackData->logLevel, byteArray);
527  (*env)->DeleteLocalRef(env, byteArray);
528 
529  // CLEAN LOG DATA
530  av_bprint_finalize(&callbackData->logData, NULL);
531 
532  } else {
533 
534  // STATISTICS CALLBACK
535 
536  (*env)->CallStaticVoidMethod(env, configClass, statisticsMethod,
537  (jlong) callbackData->sessionId, callbackData->statisticsFrameNumber,
538  callbackData->statisticsFps, callbackData->statisticsQuality,
539  callbackData->statisticsSize, callbackData->statisticsTime,
540  callbackData->statisticsBitrate, callbackData->statisticsSpeed);
541 
542  }
543 
544  atomic_fetch_sub(&sessionInTransitMessageCountMap[callbackData->sessionId % SESSION_MAP_SIZE], 1);
545 
546  // CLEAN STRUCT
547  callbackData->next = NULL;
548  av_free(callbackData);
549 
550  } else {
551  monitorWait(100);
552  }
553  }
554 
555  (*globalVm)->DetachCurrentThread(globalVm);
556 
557  LOGD("Async callback block stopped.\n");
558 
559  return NULL;
560 }
561 
566  JNIEnv *env = NULL;
567  (*globalVm)->GetEnv(globalVm, (void**) &env, JNI_VERSION_1_6);
568  (*env)->CallStaticVoidMethod(env, configClass, closeParcelFileDescriptorMethod, fd);
569 }
570 
578 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
579  JNIEnv *env;
580  if ((*vm)->GetEnv(vm, (void**)(&env), JNI_VERSION_1_6) != JNI_OK) {
581  LOGE("OnLoad failed to GetEnv for class %s.\n", configClassName);
582  return JNI_FALSE;
583  }
584 
585  jclass localConfigClass = (*env)->FindClass(env, configClassName);
586  if (localConfigClass == NULL) {
587  LOGE("OnLoad failed to FindClass %s.\n", configClassName);
588  return JNI_FALSE;
589  }
590 
591  if ((*env)->RegisterNatives(env, localConfigClass, configMethods, 14) < 0) {
592  LOGE("OnLoad failed to RegisterNatives for class %s.\n", configClassName);
593  return JNI_FALSE;
594  }
595 
596  jclass localStringClass = (*env)->FindClass(env, stringClassName);
597  if (localStringClass == NULL) {
598  LOGE("OnLoad failed to FindClass %s.\n", stringClassName);
599  return JNI_FALSE;
600  }
601 
602  (*env)->GetJavaVM(env, &globalVm);
603 
604  logMethod = (*env)->GetStaticMethodID(env, localConfigClass, "log", "(JI[B)V");
605  if (logMethod == NULL) {
606  LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "log");
607  return JNI_FALSE;
608  }
609 
610  statisticsMethod = (*env)->GetStaticMethodID(env, localConfigClass, "statistics", "(JIFFJIDD)V");
611  if (logMethod == NULL) {
612  LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "statistics");
613  return JNI_FALSE;
614  }
615 
616  closeParcelFileDescriptorMethod = (*env)->GetStaticMethodID(env, localConfigClass, "closeParcelFileDescriptor", "(I)V");
617  if (logMethod == NULL) {
618  LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "closeParcelFileDescriptor");
619  return JNI_FALSE;
620  }
621 
622  stringConstructor = (*env)->GetMethodID(env, localStringClass, "<init>", "([BLjava/lang/String;)V");
623  if (stringConstructor == NULL) {
624  LOGE("OnLoad thread failed to GetMethodID for %s.\n", "<init>");
625  return JNI_FALSE;
626  }
627 
628  av_jni_set_java_vm(vm, NULL);
629 
630  configClass = (jclass) ((*env)->NewGlobalRef(env, localConfigClass));
631  stringClass = (jclass) ((*env)->NewGlobalRef(env, localStringClass));
632 
633  callbackDataHead = NULL;
634  callbackDataTail = NULL;
635 
636  for(int i = 0; i<SESSION_MAP_SIZE; i++) {
637  atomic_init(&sessionMap[i], 0);
638  atomic_init(&sessionInTransitMessageCountMap[i], 0);
639  }
640 
641  mutexInit();
642  monitorInit();
643 
644  redirectionEnabled = 0;
645 
646  return JNI_VERSION_1_6;
647 }
648 
656 JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeLogLevel(JNIEnv *env, jclass object, jint level) {
657  configuredLogLevel = level;
658 }
659 
666 JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeLogLevel(JNIEnv *env, jclass object) {
667  return configuredLogLevel;
668 }
669 
676 JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_enableNativeRedirection(JNIEnv *env, jclass object) {
677  mutexLock();
678 
679  if (redirectionEnabled != 0) {
680  mutexUnlock();
681  return;
682  }
683  redirectionEnabled = 1;
684 
685  mutexUnlock();
686 
687  int rc = pthread_create(&callbackThread, 0, callbackThreadFunction, 0);
688  if (rc != 0) {
689  LOGE("Failed to create callback thread (rc=%d).\n", rc);
690  return;
691  }
692 
693  av_log_set_callback(ffmpegkit_log_callback_function);
695 }
696 
703 JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_disableNativeRedirection(JNIEnv *env, jclass object) {
704 
705  mutexLock();
706 
707  if (redirectionEnabled != 1) {
708  mutexUnlock();
709  return;
710  }
711  redirectionEnabled = 0;
712 
713  mutexUnlock();
714 
715  av_log_set_callback(av_log_default_callback);
716  set_report_callback(NULL);
717 
718  monitorNotify();
719 }
720 
728 JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeFFmpegVersion(JNIEnv *env, jclass object) {
729  return (*env)->NewStringUTF(env, FFMPEG_VERSION);
730 }
731 
739 JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeVersion(JNIEnv *env, jclass object) {
740  return (*env)->NewStringUTF(env, FFMPEG_KIT_VERSION);
741 }
742 
752 JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute(JNIEnv *env, jclass object, jlong id, jobjectArray stringArray) {
753  jstring *tempArray = NULL;
754  int argumentCount = 1;
755  char **argv = NULL;
756 
757  // SETS DEFAULT LOG LEVEL BEFORE STARTING A NEW RUN
758  av_log_set_level(configuredLogLevel);
759 
760  if (stringArray) {
761  int programArgumentCount = (*env)->GetArrayLength(env, stringArray);
762  argumentCount = programArgumentCount + 1;
763 
764  tempArray = (jstring *) av_malloc(sizeof(jstring) * programArgumentCount);
765  }
766 
767  /* PRESERVE USAGE FORMAT
768  *
769  * ffmpeg <arguments>
770  */
771  argv = (char **)av_malloc(sizeof(char*) * (argumentCount));
772  argv[0] = (char *)av_malloc(sizeof(char) * (strlen(LIB_NAME) + 1));
773  strcpy(argv[0], LIB_NAME);
774 
775  // PREPARE ARRAY ELEMENTS
776  if (stringArray) {
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);
781  }
782  }
783  }
784 
785  // REGISTER THE ID BEFORE STARTING THE SESSION
786  sessionId = (long) id;
787  addSession((long) id);
788 
790 
791  // RUN
792  int returnCode = ffmpeg_execute(argumentCount, argv);
793 
794  // ALWAYS REMOVE THE ID FROM THE MAP
795  removeSession((long) id);
796 
797  // CLEANUP
798  if (tempArray) {
799  for (int i = 0; i < (argumentCount - 1); i++) {
800  (*env)->ReleaseStringUTFChars(env, tempArray[i], argv[i + 1]);
801  }
802 
803  av_free(tempArray);
804  }
805  av_free(argv[0]);
806  av_free(argv);
807 
808  return returnCode;
809 }
810 
818 JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegCancel(JNIEnv *env, jclass object, jlong id) {
819  cancel_operation(id);
820 }
821 
830 JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_registerNewNativeFFmpegPipe(JNIEnv *env, jclass object, jstring ffmpegPipePath) {
831  const char *ffmpegPipePathString = (*env)->GetStringUTFChars(env, ffmpegPipePath, 0);
832 
833  return mkfifo(ffmpegPipePathString, S_IRWXU | S_IRWXG | S_IROTH);
834 }
835 
843 JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeBuildDate(JNIEnv *env, jclass object) {
844  char buildDate[10];
845  sprintf(buildDate, "%d", FFMPEG_KIT_BUILD_DATE);
846  return (*env)->NewStringUTF(env, buildDate);
847 }
848 
858 JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeEnvironmentVariable(JNIEnv *env, jclass object, jstring variableName, jstring variableValue) {
859  const char *variableNameString = (*env)->GetStringUTFChars(env, variableName, 0);
860  const char *variableValueString = (*env)->GetStringUTFChars(env, variableValue, 0);
861 
862  int rc = setenv(variableNameString, variableValueString, 1);
863 
864  (*env)->ReleaseStringUTFChars(env, variableName, variableNameString);
865  (*env)->ReleaseStringUTFChars(env, variableValue, variableValueString);
866  return rc;
867 }
868 
876 JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal(JNIEnv *env, jclass object, jint signum) {
877  if (signum == SIGQUIT) {
878  handleSIGQUIT = 0;
879  } else if (signum == SIGINT) {
880  handleSIGINT = 0;
881  } else if (signum == SIGTERM) {
882  handleSIGTERM = 0;
883  } else if (signum == SIGXCPU) {
884  handleSIGXCPU = 0;
885  } else if (signum == SIGPIPE) {
886  handleSIGPIPE = 0;
887  }
888 }
889 
898 JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_messagesInTransmit(JNIEnv *env, jclass object, jlong id) {
899  return atomic_load(&sessionInTransitMessageCountMap[id % SESSION_MAP_SIZE]);
900 }
void monitorUnInit()
Definition: ffmpegkit.c:225
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeBuildDate(JNIEnv *env, jclass object)
Definition: ffmpegkit.c:843
void ffmpegkit_log_callback_function(void *ptr, int level, const char *format, va_list vargs)
Definition: ffmpegkit.c:442
static atomic_short sessionMap[SESSION_MAP_SIZE]
Definition: ffmpegkit.c:56
static jclass stringClass
Definition: ffmpegkit.c:86
static pthread_mutex_t lockMutex
Definition: ffmpegkit.c:60
__thread volatile long sessionId
Definition: ffmpegkit.c:105
struct CallbackData * callbackDataTail
Definition: ffmpegkit.c:68
void addSession(long id)
Definition: ffmpegkit.c:357
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute(JNIEnv *env, jclass object, jlong id, jobjectArray stringArray)
Definition: ffmpegkit.c:752
void monitorNotify()
Definition: ffmpegkit.c:260
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_enableNativeRedirection(JNIEnv *env, jclass object)
Definition: ffmpegkit.c:676
static void avutil_log_sanitize(uint8_t *line)
Definition: ffmpegkit.c:188
volatile int handleSIGINT
Definition: ffmpegkit.c:99
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeLogLevel(JNIEnv *env, jclass object, jint level)
Definition: ffmpegkit.c:656
volatile int handleSIGTERM
Definition: ffmpegkit.c:100
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegCancel(JNIEnv *env, jclass object, jlong id)
Definition: ffmpegkit.c:818
const char * configClassName
Definition: ffmpegkit.c:92
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeLogLevel(JNIEnv *env, jclass object)
Definition: ffmpegkit.c:666
void ffmpegkit_statistics_callback_function(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed)
Definition: ffmpegkit.c:490
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:156
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeFFmpegVersion(JNIEnv *env, jclass object)
Definition: ffmpegkit.c:728
void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed)
Definition: ffmpegkit.c:311
const char * stringClassName
Definition: ffmpegkit.c:95
JNINativeMethod configMethods[]
Definition: ffmpegkit.c:111
void monitorWait(int milliSeconds)
Definition: ffmpegkit.c:238
static JavaVM * globalVm
Definition: ffmpegkit.c:71
struct CallbackData * callbackDataHead
Definition: ffmpegkit.c:67
pthread_t callbackThread
Definition: ffmpegkit.c:64
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal(JNIEnv *env, jclass object, jint signum)
Definition: ffmpegkit.c:876
void * callbackThreadFunction()
Definition: ffmpegkit.c:497
static pthread_cond_t monitorCondition
Definition: ffmpegkit.c:62
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeVersion(JNIEnv *env, jclass object)
Definition: ffmpegkit.c:739
void monitorInit()
Definition: ffmpegkit.c:205
void cancelSession(long id)
Definition: ffmpegkit.c:407
struct CallbackData * callbackDataRemove()
Definition: ffmpegkit.c:364
int redirectionEnabled
Definition: ffmpegkit.c:65
int cancelRequested(long id)
Definition: ffmpegkit.c:417
void mutexUnlock()
Definition: ffmpegkit.c:234
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_registerNewNativeFFmpegPipe(JNIEnv *env, jclass object, jstring ffmpegPipePath)
Definition: ffmpegkit.c:830
void mutexUnInit()
Definition: ffmpegkit.c:221
#define LogType
Definition: ffmpegkit.c:32
volatile int handleSIGPIPE
Definition: ffmpegkit.c:102
const int SESSION_MAP_SIZE
Definition: ffmpegkit.c:55
static pthread_mutex_t monitorMutex
Definition: ffmpegkit.c:61
jint JNI_OnLoad(JavaVM *vm, void *reserved)
Definition: ffmpegkit.c:578
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_disableNativeRedirection(JNIEnv *env, jclass object)
Definition: ffmpegkit.c:703
static jmethodID logMethod
Definition: ffmpegkit.c:77
volatile int handleSIGXCPU
Definition: ffmpegkit.c:101
void resetMessagesInTransmit(long id)
Definition: ffmpegkit.c:430
static jclass configClass
Definition: ffmpegkit.c:74
static atomic_int sessionInTransitMessageCountMap[SESSION_MAP_SIZE]
Definition: ffmpegkit.c:57
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeEnvironmentVariable(JNIEnv *env, jclass object, jstring variableName, jstring variableValue)
Definition: ffmpegkit.c:858
void mutexLock()
Definition: ffmpegkit.c:230
void mutexInit()
Definition: ffmpegkit.c:196
int configuredLogLevel
Definition: ffmpegkit.c:108
#define StatisticsType
Definition: ffmpegkit.c:33
int ffmpeg_execute(int argc, char **argv)
static jmethodID stringConstructor
Definition: ffmpegkit.c:89
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_messagesInTransmit(JNIEnv *env, jclass object, jlong id)
Definition: ffmpegkit.c:898
static jmethodID statisticsMethod
Definition: ffmpegkit.c:80
static jmethodID closeParcelFileDescriptorMethod
Definition: ffmpegkit.c:83
volatile int handleSIGQUIT
Definition: ffmpegkit.c:98
void logCallbackDataAdd(int level, AVBPrint *data)
Definition: ffmpegkit.c:272
static const char * avutil_log_get_level_str(int level)
Definition: ffmpegkit.c:131
void closeParcelFileDescriptor(int fd)
Definition: ffmpegkit.c:565
void removeSession(long id)
Definition: ffmpegkit.c:398
#define FFMPEG_KIT_VERSION
Definition: ffmpegkit.h:30
#define LIB_NAME
Definition: ffmpegkit.h:33
#define LOGD(...)
Definition: ffmpegkit.h:39
#define LOGE(...)
Definition: ffmpegkit.h:48
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprobeExecute(JNIEnv *env, jclass object, jlong id, jobjectArray stringArray)
Definition: ffprobekit.c:47
#define AV_LOG_STDERR
void set_report_callback(void(*callback)(int, float, float, int64_t, int, double, double))
void cancel_operation(long id)
#define pthread_mutex_lock(a)
#define pthread_mutex_unlock(a)
int logLevel
Definition: ffmpegkit.c:40
double statisticsBitrate
Definition: ffmpegkit.c:48
float statisticsQuality
Definition: ffmpegkit.c:45
struct CallbackData * next
Definition: ffmpegkit.c:51
double statisticsSpeed
Definition: ffmpegkit.c:49
int statisticsFrameNumber
Definition: ffmpegkit.c:43
int statisticsTime
Definition: ffmpegkit.c:47
float statisticsFps
Definition: ffmpegkit.c:44
long sessionId
Definition: ffmpegkit.c:38
AVBPrint logData
Definition: ffmpegkit.c:41
int64_t statisticsSize
Definition: ffmpegkit.c:46