MobileFFmpeg Android API  4.4
mobileffmpeg.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 Taner Sener
3  *
4  * This file is part of MobileFFmpeg.
5  *
6  * MobileFFmpeg 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  * MobileFFmpeg 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 MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <pthread.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 
24 #include "config.h"
25 #include "libavcodec/jni.h"
26 #include "libavutil/bprint.h"
27 #include "fftools_ffmpeg.h"
28 #include "mobileffmpeg.h"
29 #include "mobileffprobe.h"
30 
32 struct CallbackData {
33  int type; // 1 (log callback) or 2 (statistics callback)
34  long executionId; // execution id
35 
36  int logLevel; // log level
37  AVBPrint logData; // log data
38 
39  int statisticsFrameNumber; // statistics frame number
40  float statisticsFps; // statistics fps
41  float statisticsQuality; // statistics quality
42  int64_t statisticsSize; // statistics size
43  int statisticsTime; // statistics time
44  double statisticsBitrate; // statistics bitrate
45  double statisticsSpeed; // statistics speed
46 
47  struct CallbackData *next;
48 };
49 
51 const int EXECUTION_MAP_SIZE = 1000;
52 static volatile int executionMap[EXECUTION_MAP_SIZE];
53 static pthread_mutex_t executionMapMutex;
54 
56 static pthread_mutex_t lockMutex;
57 static pthread_mutex_t monitorMutex;
58 static pthread_cond_t monitorCondition;
59 
61 static pthread_mutex_t logMutex;
62 static AVBPrint lastCommandOutput;
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 
83 static jclass stringClass;
84 
86 static jmethodID stringConstructor;
87 
89 const char *configClassName = "com/arthenica/mobileffmpeg/Config";
90 
92 const char *stringClassName = "java/lang/String";
93 
95 volatile int handleSIGQUIT = 1;
96 volatile int handleSIGINT = 1;
97 volatile int handleSIGTERM = 1;
98 volatile int handleSIGXCPU = 1;
99 volatile int handleSIGPIPE = 1;
100 
102 __thread volatile long executionId = 0;
103 
105 JNINativeMethod configMethods[] = {
106  {"enableNativeRedirection", "()V", (void*) Java_com_arthenica_mobileffmpeg_Config_enableNativeRedirection},
107  {"disableNativeRedirection", "()V", (void*) Java_com_arthenica_mobileffmpeg_Config_disableNativeRedirection},
108  {"setNativeLogLevel", "(I)V", (void*) Java_com_arthenica_mobileffmpeg_Config_setNativeLogLevel},
109  {"getNativeLogLevel", "()I", (void*) Java_com_arthenica_mobileffmpeg_Config_getNativeLogLevel},
110  {"getNativeFFmpegVersion", "()Ljava/lang/String;", (void*) Java_com_arthenica_mobileffmpeg_Config_getNativeFFmpegVersion},
111  {"getNativeVersion", "()Ljava/lang/String;", (void*) Java_com_arthenica_mobileffmpeg_Config_getNativeVersion},
112  {"nativeFFmpegExecute", "(J[Ljava/lang/String;)I", (void*) Java_com_arthenica_mobileffmpeg_Config_nativeFFmpegExecute},
113  {"nativeFFmpegCancel", "(J)V", (void*) Java_com_arthenica_mobileffmpeg_Config_nativeFFmpegCancel},
114  {"nativeFFprobeExecute", "([Ljava/lang/String;)I", (void*) Java_com_arthenica_mobileffmpeg_Config_nativeFFprobeExecute},
115  {"registerNewNativeFFmpegPipe", "(Ljava/lang/String;)I", (void*) Java_com_arthenica_mobileffmpeg_Config_registerNewNativeFFmpegPipe},
116  {"getNativeBuildDate", "()Ljava/lang/String;", (void*) Java_com_arthenica_mobileffmpeg_Config_getNativeBuildDate},
117  {"setNativeEnvironmentVariable", "(Ljava/lang/String;Ljava/lang/String;)I", (void*) Java_com_arthenica_mobileffmpeg_Config_setNativeEnvironmentVariable},
118  {"getNativeLastCommandOutput", "()Ljava/lang/String;", (void*) Java_com_arthenica_mobileffmpeg_Config_getNativeLastCommandOutput},
119  {"ignoreNativeSignal", "(I)V", (void*) Java_com_arthenica_mobileffmpeg_Config_ignoreNativeSignal}
120 };
121 
123 int ffmpeg_execute(int argc, char **argv);
124 
125 static const char *avutil_log_get_level_str(int level) {
126  switch (level) {
127  case AV_LOG_STDERR:
128  return "stderr";
129  case AV_LOG_QUIET:
130  return "quiet";
131  case AV_LOG_DEBUG:
132  return "debug";
133  case AV_LOG_VERBOSE:
134  return "verbose";
135  case AV_LOG_INFO:
136  return "info";
137  case AV_LOG_WARNING:
138  return "warning";
139  case AV_LOG_ERROR:
140  return "error";
141  case AV_LOG_FATAL:
142  return "fatal";
143  case AV_LOG_PANIC:
144  return "panic";
145  default:
146  return "";
147  }
148 }
149 
150 static void avutil_log_format_line(void *avcl, int level, const char *fmt, va_list vl, AVBPrint part[4], int *print_prefix) {
151  int flags = av_log_get_flags();
152  AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
153  av_bprint_init(part+0, 0, 1);
154  av_bprint_init(part+1, 0, 1);
155  av_bprint_init(part+2, 0, 1);
156  av_bprint_init(part+3, 0, 65536);
157 
158  if (*print_prefix && avc) {
159  if (avc->parent_log_context_offset) {
160  AVClass** parent = *(AVClass ***) (((uint8_t *) avcl) +
161  avc->parent_log_context_offset);
162  if (parent && *parent) {
163  av_bprintf(part+0, "[%s @ %p] ",
164  (*parent)->item_name(parent), parent);
165  }
166  }
167  av_bprintf(part+1, "[%s @ %p] ",
168  avc->item_name(avcl), avcl);
169  }
170 
171  if (*print_prefix && (level > AV_LOG_QUIET) && (flags & AV_LOG_PRINT_LEVEL))
172  av_bprintf(part+2, "[%s] ", avutil_log_get_level_str(level));
173 
174  av_vbprintf(part+3, fmt, vl);
175 
176  if(*part[0].str || *part[1].str || *part[2].str || *part[3].str) {
177  char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0;
178  *print_prefix = lastc == '\n' || lastc == '\r';
179  }
180 }
181 
182 static void avutil_log_sanitize(uint8_t *line) {
183  while(*line){
184  if(*line < 0x08 || (*line > 0x0D && *line < 0x20))
185  *line='?';
186  line++;
187  }
188 }
189 
190 void mutexInit() {
191  pthread_mutexattr_t attributes;
192  pthread_mutexattr_init(&attributes);
193  pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
194 
195  pthread_mutex_init(&lockMutex, &attributes);
196  pthread_mutexattr_destroy(&attributes);
197 }
198 
199 void monitorInit() {
200  pthread_mutexattr_t attributes;
201  pthread_mutexattr_init(&attributes);
202  pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
203 
204  pthread_condattr_t cattributes;
205  pthread_condattr_init(&cattributes);
206  pthread_condattr_setpshared(&cattributes, PTHREAD_PROCESS_PRIVATE);
207 
208  pthread_mutex_init(&monitorMutex, &attributes);
209  pthread_mutexattr_destroy(&attributes);
210 
211  pthread_cond_init(&monitorCondition, &cattributes);
212  pthread_condattr_destroy(&cattributes);
213 }
214 
215 void logInit() {
216  pthread_mutexattr_t attributes;
217  pthread_mutexattr_init(&attributes);
218  pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
219 
220  pthread_mutex_init(&logMutex, &attributes);
221  pthread_mutexattr_destroy(&attributes);
222 
223  av_bprint_init(&lastCommandOutput, 0, AV_BPRINT_SIZE_UNLIMITED);
224 }
225 
227  pthread_mutexattr_t attributes;
228  pthread_mutexattr_init(&attributes);
229  pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
230 
231  pthread_mutex_init(&executionMapMutex, &attributes);
232  pthread_mutexattr_destroy(&attributes);
233 }
234 
235 void mutexUnInit() {
236  pthread_mutex_destroy(&lockMutex);
237 }
238 
240  pthread_mutex_destroy(&monitorMutex);
241  pthread_cond_destroy(&monitorCondition);
242 }
243 
244 void logUnInit() {
245  pthread_mutex_destroy(&logMutex);
246 }
247 
249  pthread_mutex_destroy(&executionMapMutex);
250 }
251 
252 void mutexLock() {
254 }
255 
258 }
259 
262 }
263 
264 void mutexUnlock() {
266 }
267 
270 }
271 
274 }
275 
278  av_bprint_clear(&lastCommandOutput);
280 }
281 
282 void appendLastCommandOutput(AVBPrint *logMessage) {
283  if (logMessage->len <= 0) {
284  return;
285  }
286 
288  av_bprintf(&lastCommandOutput, "%s", logMessage->str);
290 }
291 
292 void monitorWait(int milliSeconds) {
293  struct timeval tp;
294  struct timespec ts;
295  int rc;
296 
297  rc = gettimeofday(&tp, NULL);
298  if (rc) {
299  return;
300  }
301 
302  ts.tv_sec = tp.tv_sec;
303  ts.tv_nsec = tp.tv_usec * 1000;
304  ts.tv_sec += milliSeconds / 1000;
305  ts.tv_nsec += (milliSeconds % 1000)*1000000;
306 
308  pthread_cond_timedwait(&monitorCondition, &monitorMutex, &ts);
310 }
311 
314  pthread_cond_signal(&monitorCondition);
316 }
317 
324 void logCallbackDataAdd(int level, AVBPrint *data) {
325 
326  // CREATE DATA STRUCT FIRST
327  struct CallbackData *newData = (struct CallbackData*)av_malloc(sizeof(struct CallbackData));
328  newData->type = 1;
329  newData->executionId = executionId;
330  newData->logLevel = level;
331  av_bprint_init(&newData->logData, 0, AV_BPRINT_SIZE_UNLIMITED);
332  av_bprintf(&newData->logData, "%s", data->str);
333  newData->next = NULL;
334 
335  mutexLock();
336 
337  // INSERT IT TO THE END OF QUEUE
338  if (callbackDataTail == NULL) {
339  callbackDataTail = newData;
340 
341  if (callbackDataHead != NULL) {
342  LOGE("Dangling callback data head detected. This can cause memory leak.");
343  } else {
344  callbackDataHead = newData;
345  }
346  } else {
347  struct CallbackData *oldTail = callbackDataTail;
348  oldTail->next = newData;
349 
350  callbackDataTail = newData;
351  }
352 
353  mutexUnlock();
354 
355  monitorNotify();
356 }
357 
361 void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed) {
362 
363  // CREATE DATA STRUCT FIRST
364  struct CallbackData *newData = (struct CallbackData*)av_malloc(sizeof(struct CallbackData));
365  newData->type = 2;
366  newData->executionId = executionId;
367  newData->statisticsFrameNumber = frameNumber;
368  newData->statisticsFps = fps;
369  newData->statisticsQuality = quality;
370  newData->statisticsSize = size;
371  newData->statisticsTime = time;
372  newData->statisticsBitrate = bitrate;
373  newData->statisticsSpeed = speed;
374 
375  newData->next = NULL;
376 
377  mutexLock();
378 
379  // INSERT IT TO THE END OF QUEUE
380  if (callbackDataTail == NULL) {
381  callbackDataTail = newData;
382 
383  if (callbackDataHead != NULL) {
384  LOGE("Dangling callback data head detected. This can cause memory leak.");
385  } else {
386  callbackDataHead = newData;
387  }
388  } else {
389  struct CallbackData *oldTail = callbackDataTail;
390  oldTail->next = newData;
391 
392  callbackDataTail = newData;
393  }
394 
395  mutexUnlock();
396 
397  monitorNotify();
398 }
399 
405 void addExecution(long id) {
407 
408  int key = id % EXECUTION_MAP_SIZE;
409  executionMap[key] = 1;
410 
412 }
413 
418  struct CallbackData *currentData;
419 
420  mutexLock();
421 
422  if (callbackDataHead == NULL) {
423  currentData = NULL;
424  } else {
425  currentData = callbackDataHead;
426 
427  struct CallbackData *nextHead = currentData->next;
428  if (nextHead == NULL) {
430  LOGE("Head and tail callback data pointers do not match for single callback data element. This can cause memory leak.");
431  } else {
432  callbackDataTail = NULL;
433  }
434  callbackDataHead = NULL;
435 
436  } else {
437  callbackDataHead = nextHead;
438  }
439  }
440 
441  mutexUnlock();
442 
443  return currentData;
444 }
445 
451 void removeExecution(long id) {
453 
454  int key = id % EXECUTION_MAP_SIZE;
455  executionMap[key] = 0;
456 
458 }
459 
466 int cancelRequested(long id) {
467  int found = 0;
468 
470 
471  int key = id % EXECUTION_MAP_SIZE;
472  if (executionMap[key] == 0) {
473  found = 1;
474  }
475 
477 
478  return found;
479 }
480 
489 void mobileffmpeg_log_callback_function(void *ptr, int level, const char* format, va_list vargs) {
490  AVBPrint fullLine;
491  AVBPrint part[4];
492  int print_prefix = 1;
493 
494  if (level >= 0) {
495  level &= 0xff;
496  }
497  int activeLogLevel = av_log_get_level();
498 
499  // AV_LOG_STDERR logs are always redirected
500  if ((activeLogLevel == AV_LOG_QUIET && level != AV_LOG_STDERR) || (level > activeLogLevel)) {
501  return;
502  }
503 
504  av_bprint_init(&fullLine, 0, AV_BPRINT_SIZE_UNLIMITED);
505 
506  avutil_log_format_line(ptr, level, format, vargs, part, &print_prefix);
507  avutil_log_sanitize(part[0].str);
508  avutil_log_sanitize(part[1].str);
509  avutil_log_sanitize(part[2].str);
510  avutil_log_sanitize(part[3].str);
511 
512  // COMBINE ALL 4 LOG PARTS
513  av_bprintf(&fullLine, "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
514 
515  if (fullLine.len > 0) {
516  logCallbackDataAdd(level, &fullLine);
517  appendLastCommandOutput(&fullLine);
518  }
519 
520  av_bprint_finalize(part, NULL);
521  av_bprint_finalize(part+1, NULL);
522  av_bprint_finalize(part+2, NULL);
523  av_bprint_finalize(part+3, NULL);
524  av_bprint_finalize(&fullLine, NULL);
525 }
526 
538 void mobileffmpeg_statistics_callback_function(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed) {
539  statisticsCallbackDataAdd(frameNumber, fps, quality, size, time, bitrate, speed);
540 }
541 
546  JNIEnv *env;
547  jint getEnvRc = (*globalVm)->GetEnv(globalVm, (void**) &env, JNI_VERSION_1_6);
548  if (getEnvRc != JNI_OK) {
549  if (getEnvRc != JNI_EDETACHED) {
550  LOGE("Callback thread failed to GetEnv for class %s with rc %d.\n", configClassName, getEnvRc);
551  return NULL;
552  }
553 
554  if ((*globalVm)->AttachCurrentThread(globalVm, &env, NULL) != 0) {
555  LOGE("Callback thread failed to AttachCurrentThread for class %s.\n", configClassName);
556  return NULL;
557  }
558  }
559 
560  LOGD("Callback thread started.\n");
561 
562  while(redirectionEnabled) {
563 
564  struct CallbackData *callbackData = callbackDataRemove();
565  if (callbackData != NULL) {
566  if (callbackData->type == 1) {
567 
568  // LOG CALLBACK
569 
570  int size = callbackData->logData.len;
571 
572  jbyteArray byteArray = (jbyteArray) (*env)->NewByteArray(env, size);
573  (*env)->SetByteArrayRegion(env, byteArray, 0, size, callbackData->logData.str);
574  (*env)->CallStaticVoidMethod(env, configClass, logMethod, (jlong) callbackData->executionId, callbackData->logLevel, byteArray);
575  (*env)->DeleteLocalRef(env, byteArray);
576 
577  // CLEAN LOG DATA
578  av_bprint_finalize(&callbackData->logData, NULL);
579 
580  } else {
581 
582  // STATISTICS CALLBACK
583 
584  (*env)->CallStaticVoidMethod(env, configClass, statisticsMethod,
585  (jlong) callbackData->executionId, callbackData->statisticsFrameNumber,
586  callbackData->statisticsFps, callbackData->statisticsQuality,
587  callbackData->statisticsSize, callbackData->statisticsTime,
588  callbackData->statisticsBitrate, callbackData->statisticsSpeed);
589 
590  }
591 
592  // CLEAN STRUCT
593  callbackData->next = NULL;
594  av_free(callbackData);
595 
596  } else {
597  monitorWait(100);
598  }
599  }
600 
601  (*globalVm)->DetachCurrentThread(globalVm);
602 
603  LOGD("Callback thread stopped.\n");
604 
605  return NULL;
606 }
607 
615 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
616  JNIEnv *env;
617  if ((*vm)->GetEnv(vm, (void**)(&env), JNI_VERSION_1_6) != JNI_OK) {
618  LOGE("OnLoad failed to GetEnv for class %s.\n", configClassName);
619  return JNI_FALSE;
620  }
621 
622  jclass localConfigClass = (*env)->FindClass(env, configClassName);
623  if (localConfigClass == NULL) {
624  LOGE("OnLoad failed to FindClass %s.\n", configClassName);
625  return JNI_FALSE;
626  }
627 
628  if ((*env)->RegisterNatives(env, localConfigClass, configMethods, 12) < 0) {
629  LOGE("OnLoad failed to RegisterNatives for class %s.\n", configClassName);
630  return JNI_FALSE;
631  }
632 
633  jclass localStringClass = (*env)->FindClass(env, stringClassName);
634  if (localStringClass == NULL) {
635  LOGE("OnLoad failed to FindClass %s.\n", stringClassName);
636  return JNI_FALSE;
637  }
638 
639  (*env)->GetJavaVM(env, &globalVm);
640 
641  logMethod = (*env)->GetStaticMethodID(env, localConfigClass, "log", "(JI[B)V");
642  if (logMethod == NULL) {
643  LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "log");
644  return JNI_FALSE;
645  }
646 
647  statisticsMethod = (*env)->GetStaticMethodID(env, localConfigClass, "statistics", "(JIFFJIDD)V");
648  if (logMethod == NULL) {
649  LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "statistics");
650  return JNI_FALSE;
651  }
652 
653  stringConstructor = (*env)->GetMethodID(env, localStringClass, "<init>", "([BLjava/lang/String;)V");
654  if (stringConstructor == NULL) {
655  LOGE("OnLoad thread failed to GetMethodID for %s.\n", "<init>");
656  return JNI_FALSE;
657  }
658 
659  av_jni_set_java_vm(vm, NULL);
660 
661  configClass = (jclass) ((*env)->NewGlobalRef(env, localConfigClass));
662  stringClass = (jclass) ((*env)->NewGlobalRef(env, localStringClass));
663 
664  redirectionEnabled = 0;
665 
666  callbackDataHead = NULL;
667  callbackDataTail = NULL;
668 
669  for(int i = 0; i<EXECUTION_MAP_SIZE; i++) {
670  executionMap[i] = 0;
671  }
672 
673  mutexInit();
674  monitorInit();
675  logInit();
677 
678  return JNI_VERSION_1_6;
679 }
680 
688 JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_setNativeLogLevel(JNIEnv *env, jclass object, jint level) {
689  av_log_set_level(level);
690 }
691 
698 JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeLogLevel(JNIEnv *env, jclass object) {
699  return av_log_get_level();
700 }
701 
708 JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_enableNativeRedirection(JNIEnv *env, jclass object) {
709  mutexLock();
710 
711  if (redirectionEnabled != 0) {
712  mutexUnlock();
713  return;
714  }
715  redirectionEnabled = 1;
716 
717  mutexUnlock();
718 
719  int rc = pthread_create(&callbackThread, 0, callbackThreadFunction, 0);
720  if (rc != 0) {
721  LOGE("Failed to create callback thread (rc=%d).\n", rc);
722  return;
723  }
724 
725  av_log_set_callback(mobileffmpeg_log_callback_function);
727 }
728 
735 JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_disableNativeRedirection(JNIEnv *env, jclass object) {
736 
737  mutexLock();
738 
739  if (redirectionEnabled != 1) {
740  mutexUnlock();
741  return;
742  }
743  redirectionEnabled = 0;
744 
745  mutexUnlock();
746 
747  av_log_set_callback(av_log_default_callback);
748  set_report_callback(NULL);
749 
750  monitorNotify();
751 }
752 
760 JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeFFmpegVersion(JNIEnv *env, jclass object) {
761  return (*env)->NewStringUTF(env, FFMPEG_VERSION);
762 }
763 
771 JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeVersion(JNIEnv *env, jclass object) {
772  return (*env)->NewStringUTF(env, MOBILE_FFMPEG_VERSION);
773 }
774 
784 JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Config_nativeFFmpegExecute(JNIEnv *env, jclass object, jlong id, jobjectArray stringArray) {
785  jstring *tempArray = NULL;
786  int argumentCount = 1;
787  char **argv = NULL;
788 
789  if (stringArray != NULL) {
790  int programArgumentCount = (*env)->GetArrayLength(env, stringArray);
791  argumentCount = programArgumentCount + 1;
792 
793  tempArray = (jstring *) av_malloc(sizeof(jstring) * programArgumentCount);
794  }
795 
796  /* PRESERVE USAGE FORMAT
797  *
798  * ffmpeg <arguments>
799  */
800  argv = (char **)av_malloc(sizeof(char*) * (argumentCount));
801  argv[0] = (char *)av_malloc(sizeof(char) * (strlen(LIB_NAME) + 1));
802  strcpy(argv[0], LIB_NAME);
803 
804  // PREPARE
805  if (stringArray != NULL) {
806  for (int i = 0; i < (argumentCount - 1); i++) {
807  tempArray[i] = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i);
808  if (tempArray[i] != NULL) {
809  argv[i + 1] = (char *) (*env)->GetStringUTFChars(env, tempArray[i], 0);
810  }
811  }
812  }
813 
814  // LAST COMMAND OUTPUT SHOULD BE CLEARED BEFORE STARTING A NEW EXECUTION
816 
817  // REGISTER THE ID BEFORE STARTING EXECUTION
818  executionId = (long) id;
819  addExecution((long) id);
820 
821  // RUN
822  int retCode = ffmpeg_execute(argumentCount, argv);
823 
824  // ALWAYS REMOVE THE ID FROM THE MAP
825  removeExecution((long) id);
826 
827  // CLEANUP
828  if (tempArray != NULL) {
829  for (int i = 0; i < (argumentCount - 1); i++) {
830  (*env)->ReleaseStringUTFChars(env, tempArray[i], argv[i + 1]);
831  }
832 
833  av_free(tempArray);
834  }
835  av_free(argv[0]);
836  av_free(argv);
837 
838  return retCode;
839 }
840 
848 JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_nativeFFmpegCancel(JNIEnv *env, jclass object, jlong id) {
849  cancel_operation(id);
850 }
851 
860 JNIEXPORT int JNICALL Java_com_arthenica_mobileffmpeg_Config_registerNewNativeFFmpegPipe(JNIEnv *env, jclass object, jstring ffmpegPipePath) {
861  const char *ffmpegPipePathString = (*env)->GetStringUTFChars(env, ffmpegPipePath, 0);
862 
863  return mkfifo(ffmpegPipePathString, S_IRWXU | S_IRWXG | S_IROTH);
864 }
865 
873 JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeBuildDate(JNIEnv *env, jclass object) {
874  char buildDate[10];
875  sprintf(buildDate, "%d", MOBILE_FFMPEG_BUILD_DATE);
876  return (*env)->NewStringUTF(env, buildDate);
877 }
878 
888 JNIEXPORT int JNICALL Java_com_arthenica_mobileffmpeg_Config_setNativeEnvironmentVariable(JNIEnv *env, jclass object, jstring variableName, jstring variableValue) {
889  const char *variableNameString = (*env)->GetStringUTFChars(env, variableName, 0);
890  const char *variableValueString = (*env)->GetStringUTFChars(env, variableValue, 0);
891 
892  int rc = setenv(variableNameString, variableValueString, 1);
893 
894  (*env)->ReleaseStringUTFChars(env, variableName, variableNameString);
895  (*env)->ReleaseStringUTFChars(env, variableValue, variableValueString);
896  return rc;
897 }
898 
906 JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeLastCommandOutput(JNIEnv *env, jclass object) {
907  int size = lastCommandOutput.len;
908  if (size > 0) {
909  jbyteArray byteArray = (*env)->NewByteArray(env, size);
910  (*env)->SetByteArrayRegion(env, byteArray, 0, size, lastCommandOutput.str);
911  jstring charsetName = (*env)->NewStringUTF(env, "UTF-8");
912  return (jstring) (*env)->NewObject(env, stringClass, stringConstructor, byteArray, charsetName);
913  }
914 
915  return (*env)->NewStringUTF(env, "");
916 }
917 
925 JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_ignoreNativeSignal(JNIEnv *env, jclass object, jint signum) {
926  if (signum == SIGQUIT) {
927  handleSIGQUIT = 0;
928  } else if (signum == SIGINT) {
929  handleSIGINT = 0;
930  } else if (signum == SIGTERM) {
931  handleSIGTERM = 0;
932  } else if (signum == SIGXCPU) {
933  handleSIGXCPU = 0;
934  } else if (signum == SIGPIPE) {
935  handleSIGPIPE = 0;
936  }
937 }
monitorNotify
void monitorNotify()
Definition: mobileffmpeg.c:312
monitorInit
void monitorInit()
Definition: mobileffmpeg.c:199
Java_com_arthenica_mobileffmpeg_Config_ignoreNativeSignal
JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_ignoreNativeSignal(JNIEnv *env, jclass object, jint signum)
Definition: mobileffmpeg.c:925
statisticsMethod
static jmethodID statisticsMethod
Definition: mobileffmpeg.c:80
configClass
static jclass configClass
Definition: mobileffmpeg.c:74
mobileffprobe.h
logInit
void logInit()
Definition: mobileffmpeg.c:215
Java_com_arthenica_mobileffmpeg_Config_setNativeEnvironmentVariable
JNIEXPORT int JNICALL Java_com_arthenica_mobileffmpeg_Config_setNativeEnvironmentVariable(JNIEnv *env, jclass object, jstring variableName, jstring variableValue)
Definition: mobileffmpeg.c:888
logMutex
static pthread_mutex_t logMutex
Definition: mobileffmpeg.c:61
CallbackData::logData
AVBPrint logData
Definition: mobileffmpeg.c:37
executionMapLockUnInit
void executionMapLockUnInit()
Definition: mobileffmpeg.c:248
Java_com_arthenica_mobileffmpeg_Config_enableNativeRedirection
JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_enableNativeRedirection(JNIEnv *env, jclass object)
Definition: mobileffmpeg.c:708
fftools_ffmpeg.h
Java_com_arthenica_mobileffmpeg_Config_getNativeLastCommandOutput
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeLastCommandOutput(JNIEnv *env, jclass object)
Definition: mobileffmpeg.c:906
CallbackData::logLevel
int logLevel
Definition: mobileffmpeg.c:36
CallbackData::statisticsFrameNumber
int statisticsFrameNumber
Definition: mobileffmpeg.c:39
configClassName
const char * configClassName
Definition: mobileffmpeg.c:89
handleSIGTERM
volatile int handleSIGTERM
Definition: mobileffmpeg.c:97
CallbackData::statisticsSpeed
double statisticsSpeed
Definition: mobileffmpeg.c:45
set_report_callback
void set_report_callback(void(*callback)(int, float, float, int64_t, int, double, double))
Definition: fftools_ffmpeg.c:5054
cancel_operation
void cancel_operation(long id)
Definition: fftools_ffmpeg.c:5059
callbackDataHead
struct CallbackData * callbackDataHead
Definition: mobileffmpeg.c:67
LOGE
#define LOGE(...)
Definition: mobileffmpeg.h:48
Java_com_arthenica_mobileffmpeg_Config_setNativeLogLevel
JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_setNativeLogLevel(JNIEnv *env, jclass object, jint level)
Definition: mobileffmpeg.c:688
executionMapLockInit
void executionMapLockInit()
Definition: mobileffmpeg.c:226
pthread_mutex_lock
#define pthread_mutex_lock(a)
Definition: fftools_ffprobe.c:69
addExecution
void addExecution(long id)
Definition: mobileffmpeg.c:405
redirectionEnabled
int redirectionEnabled
Definition: mobileffmpeg.c:65
executionMapLock
void executionMapLock()
Definition: mobileffmpeg.c:260
logUnInit
void logUnInit()
Definition: mobileffmpeg.c:244
CallbackData::next
struct CallbackData * next
Definition: mobileffmpeg.c:47
executionMapUnlock
void executionMapUnlock()
Definition: mobileffmpeg.c:272
cancelRequested
int cancelRequested(long id)
Definition: mobileffmpeg.c:466
clearLastCommandOutput
void clearLastCommandOutput()
Definition: mobileffmpeg.c:276
logCallbackDataAdd
void logCallbackDataAdd(int level, AVBPrint *data)
Definition: mobileffmpeg.c:324
handleSIGXCPU
volatile int handleSIGXCPU
Definition: mobileffmpeg.c:98
ffmpeg_execute
int ffmpeg_execute(int argc, char **argv)
Definition: fftools_ffmpeg.c:5070
LOGD
#define LOGD(...)
Definition: mobileffmpeg.h:39
Java_com_arthenica_mobileffmpeg_Config_getNativeFFmpegVersion
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeFFmpegVersion(JNIEnv *env, jclass object)
Definition: mobileffmpeg.c:760
monitorUnInit
void monitorUnInit()
Definition: mobileffmpeg.c:239
stringConstructor
static jmethodID stringConstructor
Definition: mobileffmpeg.c:86
Java_com_arthenica_mobileffmpeg_Config_nativeFFmpegExecute
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Config_nativeFFmpegExecute(JNIEnv *env, jclass object, jlong id, jobjectArray stringArray)
Definition: mobileffmpeg.c:784
stringClass
static jclass stringClass
Definition: mobileffmpeg.c:83
mobileffmpeg_statistics_callback_function
void mobileffmpeg_statistics_callback_function(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed)
Definition: mobileffmpeg.c:538
handleSIGINT
volatile int handleSIGINT
Definition: mobileffmpeg.c:96
avutil_log_get_level_str
static const char * avutil_log_get_level_str(int level)
Definition: mobileffmpeg.c:125
CallbackData::statisticsTime
int statisticsTime
Definition: mobileffmpeg.c:43
CallbackData::executionId
long executionId
Definition: mobileffmpeg.c:34
configMethods
JNINativeMethod configMethods[]
Definition: mobileffmpeg.c:105
JNI_OnLoad
jint JNI_OnLoad(JavaVM *vm, void *reserved)
Definition: mobileffmpeg.c:615
mobileffmpeg.h
CallbackData::statisticsQuality
float statisticsQuality
Definition: mobileffmpeg.c:41
Java_com_arthenica_mobileffmpeg_Config_getNativeLogLevel
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeLogLevel(JNIEnv *env, jclass object)
Definition: mobileffmpeg.c:698
handleSIGQUIT
volatile int handleSIGQUIT
Definition: mobileffmpeg.c:95
lastCommandOutputUnlock
void lastCommandOutputUnlock()
Definition: mobileffmpeg.c:268
mutexUnInit
void mutexUnInit()
Definition: mobileffmpeg.c:235
lockMutex
static pthread_mutex_t lockMutex
Definition: mobileffmpeg.c:56
mutexUnlock
void mutexUnlock()
Definition: mobileffmpeg.c:264
Java_com_arthenica_mobileffmpeg_Config_nativeFFmpegCancel
JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_nativeFFmpegCancel(JNIEnv *env, jclass object, jlong id)
Definition: mobileffmpeg.c:848
monitorCondition
static pthread_cond_t monitorCondition
Definition: mobileffmpeg.c:58
callbackDataRemove
struct CallbackData * callbackDataRemove()
Definition: mobileffmpeg.c:417
callbackThreadFunction
void * callbackThreadFunction()
Definition: mobileffmpeg.c:545
CallbackData
Definition: mobileffmpeg.c:32
statisticsCallbackDataAdd
void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed)
Definition: mobileffmpeg.c:361
callbackDataTail
struct CallbackData * callbackDataTail
Definition: mobileffmpeg.c:68
AV_LOG_STDERR
#define AV_LOG_STDERR
Definition: fftools_cmdutils.h:61
removeExecution
void removeExecution(long id)
Definition: mobileffmpeg.c:451
Java_com_arthenica_mobileffmpeg_Config_getNativeBuildDate
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeBuildDate(JNIEnv *env, jclass object)
Definition: mobileffmpeg.c:873
mobileffmpeg_log_callback_function
void mobileffmpeg_log_callback_function(void *ptr, int level, const char *format, va_list vargs)
Definition: mobileffmpeg.c:489
appendLastCommandOutput
void appendLastCommandOutput(AVBPrint *logMessage)
Definition: mobileffmpeg.c:282
handleSIGPIPE
volatile int handleSIGPIPE
Definition: mobileffmpeg.c:99
EXECUTION_MAP_SIZE
const int EXECUTION_MAP_SIZE
Definition: mobileffmpeg.c:51
executionMap
static volatile int executionMap[EXECUTION_MAP_SIZE]
Definition: mobileffmpeg.c:52
executionId
__thread volatile long executionId
Definition: mobileffmpeg.c:102
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: mobileffmpeg.c:150
CallbackData::statisticsSize
int64_t statisticsSize
Definition: mobileffmpeg.c:42
CallbackData::statisticsBitrate
double statisticsBitrate
Definition: mobileffmpeg.c:44
monitorWait
void monitorWait(int milliSeconds)
Definition: mobileffmpeg.c:292
LIB_NAME
#define LIB_NAME
Definition: mobileffmpeg.h:33
Java_com_arthenica_mobileffmpeg_Config_disableNativeRedirection
JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_disableNativeRedirection(JNIEnv *env, jclass object)
Definition: mobileffmpeg.c:735
mutexInit
void mutexInit()
Definition: mobileffmpeg.c:190
lastCommandOutput
static AVBPrint lastCommandOutput
Definition: mobileffmpeg.c:62
CallbackData::statisticsFps
float statisticsFps
Definition: mobileffmpeg.c:40
Java_com_arthenica_mobileffmpeg_Config_getNativeVersion
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeVersion(JNIEnv *env, jclass object)
Definition: mobileffmpeg.c:771
lastCommandOutputLock
void lastCommandOutputLock()
Definition: mobileffmpeg.c:256
callbackThread
pthread_t callbackThread
Definition: mobileffmpeg.c:64
Java_com_arthenica_mobileffmpeg_Config_registerNewNativeFFmpegPipe
JNIEXPORT int JNICALL Java_com_arthenica_mobileffmpeg_Config_registerNewNativeFFmpegPipe(JNIEnv *env, jclass object, jstring ffmpegPipePath)
Definition: mobileffmpeg.c:860
monitorMutex
static pthread_mutex_t monitorMutex
Definition: mobileffmpeg.c:57
MOBILE_FFMPEG_VERSION
#define MOBILE_FFMPEG_VERSION
Definition: mobileffmpeg.h:30
Java_com_arthenica_mobileffmpeg_Config_nativeFFprobeExecute
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Config_nativeFFprobeExecute(JNIEnv *env, jclass object, jobjectArray stringArray)
Definition: mobileffprobe.c:43
stringClassName
const char * stringClassName
Definition: mobileffmpeg.c:92
logMethod
static jmethodID logMethod
Definition: mobileffmpeg.c:77
avutil_log_sanitize
static void avutil_log_sanitize(uint8_t *line)
Definition: mobileffmpeg.c:182
executionMapMutex
static pthread_mutex_t executionMapMutex
Definition: mobileffmpeg.c:53
globalVm
static JavaVM * globalVm
Definition: mobileffmpeg.c:71
pthread_mutex_unlock
#define pthread_mutex_unlock(a)
Definition: fftools_ffprobe.c:73
CallbackData::type
int type
Definition: mobileffmpeg.c:33
mutexLock
void mutexLock()
Definition: mobileffmpeg.c:252