FFmpegKit Android API 4.5
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 "libavutil/file.h"
29#include "fftools_ffmpeg.h"
30#include "ffmpegkit.h"
31#include "ffprobekit.h"
32
33# define LogType 1
34# define StatisticsType 2
35
38 int type; // 1 (log callback) or 2 (statistics callback)
39 long sessionId; // session identifier
40
41 int logLevel; // log level
42 AVBPrint logData; // log data
43
44 int statisticsFrameNumber; // statistics frame number
45 float statisticsFps; // statistics fps
46 float statisticsQuality; // statistics quality
47 int64_t statisticsSize; // statistics size
48 int statisticsTime; // statistics time
49 double statisticsBitrate; // statistics bitrate
50 double statisticsSpeed; // statistics speed
51
53};
54
56#define SESSION_MAP_SIZE 1000
57static atomic_short sessionMap[SESSION_MAP_SIZE];
59
61static pthread_mutex_t lockMutex;
62static pthread_mutex_t monitorMutex;
63static pthread_cond_t monitorCondition;
64
67
70
72static JavaVM *globalVm;
73
75static jclass configClass;
76
78static jmethodID logMethod;
79
81static jmethodID statisticsMethod;
82
85
87static jclass stringClass;
88
90static jmethodID stringConstructor;
91
93const char *configClassName = "com/arthenica/ffmpegkit/FFmpegKitConfig";
94
96const char *stringClassName = "java/lang/String";
97
99volatile int handleSIGQUIT = 1;
100volatile int handleSIGINT = 1;
101volatile int handleSIGTERM = 1;
102volatile int handleSIGXCPU = 1;
103volatile int handleSIGPIPE = 1;
104
106__thread volatile long globalSessionId = 0;
107
109int configuredLogLevel = AV_LOG_INFO;
110
112JNINativeMethod configMethods[] = {
113 {"enableNativeRedirection", "()V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_enableNativeRedirection},
114 {"disableNativeRedirection", "()V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_disableNativeRedirection},
115 {"setNativeLogLevel", "(I)V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeLogLevel},
116 {"getNativeLogLevel", "()I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeLogLevel},
117 {"getNativeFFmpegVersion", "()Ljava/lang/String;", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeFFmpegVersion},
118 {"getNativeVersion", "()Ljava/lang/String;", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeVersion},
119 {"nativeFFmpegExecute", "(J[Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute},
120 {"nativeFFmpegCancel", "(J)V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegCancel},
121 {"nativeFFprobeExecute", "(J[Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprobeExecute},
122 {"registerNewNativeFFmpegPipe", "(Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_registerNewNativeFFmpegPipe},
123 {"getNativeBuildDate", "()Ljava/lang/String;", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeBuildDate},
124 {"setNativeEnvironmentVariable", "(Ljava/lang/String;Ljava/lang/String;)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeEnvironmentVariable},
125 {"ignoreNativeSignal", "(I)V", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal},
126 {"messagesInTransmit", "(J)I", (void*) Java_com_arthenica_ffmpegkit_FFmpegKitConfig_messagesInTransmit}
127};
128
130int ffmpeg_execute(int argc, char **argv);
131
132static const char *avutil_log_get_level_str(int level) {
133 switch (level) {
134 case AV_LOG_STDERR:
135 return "stderr";
136 case AV_LOG_QUIET:
137 return "quiet";
138 case AV_LOG_DEBUG:
139 return "debug";
140 case AV_LOG_VERBOSE:
141 return "verbose";
142 case AV_LOG_INFO:
143 return "info";
144 case AV_LOG_WARNING:
145 return "warning";
146 case AV_LOG_ERROR:
147 return "error";
148 case AV_LOG_FATAL:
149 return "fatal";
150 case AV_LOG_PANIC:
151 return "panic";
152 default:
153 return "";
154 }
155}
156
157static void avutil_log_format_line(void *avcl, int level, const char *fmt, va_list vl, AVBPrint part[4], int *print_prefix) {
158 int flags = av_log_get_flags();
159 AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
160 av_bprint_init(part+0, 0, 1);
161 av_bprint_init(part+1, 0, 1);
162 av_bprint_init(part+2, 0, 1);
163 av_bprint_init(part+3, 0, 65536);
164
165 if (*print_prefix && avc) {
166 if (avc->parent_log_context_offset) {
167 AVClass** parent = *(AVClass ***) (((uint8_t *) avcl) +
168 avc->parent_log_context_offset);
169 if (parent && *parent) {
170 av_bprintf(part+0, "[%s @ %p] ",
171 (*parent)->item_name(parent), parent);
172 }
173 }
174 av_bprintf(part+1, "[%s @ %p] ",
175 avc->item_name(avcl), avcl);
176 }
177
178 if (*print_prefix && (level > AV_LOG_QUIET) && (flags & AV_LOG_PRINT_LEVEL))
179 av_bprintf(part+2, "[%s] ", avutil_log_get_level_str(level));
180
181 av_vbprintf(part+3, fmt, vl);
182
183 if(*part[0].str || *part[1].str || *part[2].str || *part[3].str) {
184 char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0;
185 *print_prefix = lastc == '\n' || lastc == '\r';
186 }
187}
188
189static void avutil_log_sanitize(uint8_t *line) {
190 while(*line){
191 if(*line < 0x08 || (*line > 0x0D && *line < 0x20))
192 *line='?';
193 line++;
194 }
195}
196
197void mutexInit() {
198 pthread_mutexattr_t attributes;
199 pthread_mutexattr_init(&attributes);
200 pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
201
202 pthread_mutex_init(&lockMutex, &attributes);
203 pthread_mutexattr_destroy(&attributes);
204}
205
207 pthread_mutexattr_t attributes;
208 pthread_mutexattr_init(&attributes);
209 pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
210
211 pthread_condattr_t cattributes;
212 pthread_condattr_init(&cattributes);
213 pthread_condattr_setpshared(&cattributes, PTHREAD_PROCESS_PRIVATE);
214
215 pthread_mutex_init(&monitorMutex, &attributes);
216 pthread_mutexattr_destroy(&attributes);
217
218 pthread_cond_init(&monitorCondition, &cattributes);
219 pthread_condattr_destroy(&cattributes);
220}
221
223 pthread_mutex_destroy(&lockMutex);
224}
225
227 pthread_mutex_destroy(&monitorMutex);
228 pthread_cond_destroy(&monitorCondition);
229}
230
231void mutexLock() {
233}
234
237}
238
239void monitorWait(int milliSeconds) {
240 struct timeval tp;
241 struct timespec ts;
242 int rc;
243
244 rc = gettimeofday(&tp, NULL);
245 if (rc) {
246 return;
247 }
248
249 ts.tv_sec = tp.tv_sec;
250 ts.tv_nsec = tp.tv_usec * 1000;
251 ts.tv_sec += milliSeconds / 1000;
252 ts.tv_nsec += (milliSeconds % 1000)*1000000;
253 ts.tv_sec += ts.tv_nsec / 1000000000L;
254 ts.tv_nsec = ts.tv_nsec % 1000000000L;
255
257 pthread_cond_timedwait(&monitorCondition, &monitorMutex, &ts);
259}
260
263 pthread_cond_signal(&monitorCondition);
265}
266
273void logCallbackDataAdd(int level, AVBPrint *data) {
274
275 // CREATE DATA STRUCT FIRST
276 struct CallbackData *newData = (struct CallbackData*)av_malloc(sizeof(struct CallbackData));
277 newData->type = LogType;
278 newData->sessionId = globalSessionId;
279 newData->logLevel = level;
280 av_bprint_init(&newData->logData, 0, AV_BPRINT_SIZE_UNLIMITED);
281 av_bprintf(&newData->logData, "%s", data->str);
282 newData->next = NULL;
283
284 mutexLock();
285
286 // INSERT IT TO THE END OF QUEUE
287 if (callbackDataTail == NULL) {
288 callbackDataTail = newData;
289
290 if (callbackDataHead != NULL) {
291 LOGE("Dangling callback data head detected. This can cause memory leak.");
292 } else {
293 callbackDataHead = newData;
294 }
295 } else {
296 struct CallbackData *oldTail = callbackDataTail;
297 oldTail->next = newData;
298
299 callbackDataTail = newData;
300 }
301
302 mutexUnlock();
303
305
307}
308
312void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed) {
313
314 // CREATE DATA STRUCT FIRST
315 struct CallbackData *newData = (struct CallbackData*)av_malloc(sizeof(struct CallbackData));
316 newData->type = StatisticsType;
317 newData->sessionId = globalSessionId;
318 newData->statisticsFrameNumber = frameNumber;
319 newData->statisticsFps = fps;
320 newData->statisticsQuality = quality;
321 newData->statisticsSize = size;
322 newData->statisticsTime = time;
323 newData->statisticsBitrate = bitrate;
324 newData->statisticsSpeed = speed;
325
326 newData->next = NULL;
327
328 mutexLock();
329
330 // INSERT IT TO THE END OF QUEUE
331 if (callbackDataTail == NULL) {
332 callbackDataTail = newData;
333
334 if (callbackDataHead != NULL) {
335 LOGE("Dangling callback data head detected. This can cause memory leak.");
336 } else {
337 callbackDataHead = newData;
338 }
339 } else {
340 struct CallbackData *oldTail = callbackDataTail;
341 oldTail->next = newData;
342
343 callbackDataTail = newData;
344 }
345
346 mutexUnlock();
347
349
351}
352
358void addSession(long id) {
359 atomic_store(&sessionMap[id % SESSION_MAP_SIZE], 1);
360}
361
366 struct CallbackData *currentData;
367
368 mutexLock();
369
370 if (callbackDataHead == NULL) {
371 currentData = NULL;
372 } else {
373 currentData = callbackDataHead;
374
375 struct CallbackData *nextHead = currentData->next;
376 if (nextHead == NULL) {
378 LOGE("Head and tail callback data pointers do not match for single callback data element. This can cause memory leak.");
379 } else {
380 callbackDataTail = NULL;
381 }
382 callbackDataHead = NULL;
383
384 } else {
385 callbackDataHead = nextHead;
386 }
387 }
388
389 mutexUnlock();
390
391 return currentData;
392}
393
399void removeSession(long id) {
400 atomic_store(&sessionMap[id % SESSION_MAP_SIZE], 0);
401}
402
408void cancelSession(long id) {
409 atomic_store(&sessionMap[id % SESSION_MAP_SIZE], 2);
410}
411
418int cancelRequested(long id) {
419 if (atomic_load(&sessionMap[id % SESSION_MAP_SIZE]) == 2) {
420 return 1;
421 } else {
422 return 0;
423 }
424}
425
433}
434
443void ffmpegkit_log_callback_function(void *ptr, int level, const char* format, va_list vargs) {
444 AVBPrint fullLine;
445 AVBPrint part[4];
446 int print_prefix = 1;
447
448 if (level >= 0) {
449 level &= 0xff;
450 }
451 int activeLogLevel = av_log_get_level();
452
453 // AV_LOG_STDERR logs are always redirected
454 if ((activeLogLevel == AV_LOG_QUIET && level != AV_LOG_STDERR) || (level > activeLogLevel)) {
455 return;
456 }
457
458 av_bprint_init(&fullLine, 0, AV_BPRINT_SIZE_UNLIMITED);
459
460 avutil_log_format_line(ptr, level, format, vargs, part, &print_prefix);
461 avutil_log_sanitize(part[0].str);
462 avutil_log_sanitize(part[1].str);
463 avutil_log_sanitize(part[2].str);
464 avutil_log_sanitize(part[3].str);
465
466 // COMBINE ALL 4 LOG PARTS
467 av_bprintf(&fullLine, "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
468
469 if (fullLine.len > 0) {
470 logCallbackDataAdd(level, &fullLine);
471 }
472
473 av_bprint_finalize(part, NULL);
474 av_bprint_finalize(part+1, NULL);
475 av_bprint_finalize(part+2, NULL);
476 av_bprint_finalize(part+3, NULL);
477 av_bprint_finalize(&fullLine, NULL);
478}
479
491void ffmpegkit_statistics_callback_function(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed) {
492 statisticsCallbackDataAdd(frameNumber, fps, quality, size, time, bitrate, speed);
493}
494
499 JNIEnv *env;
500 jint getEnvRc = (*globalVm)->GetEnv(globalVm, (void**) &env, JNI_VERSION_1_6);
501 if (getEnvRc != JNI_OK) {
502 if (getEnvRc != JNI_EDETACHED) {
503 LOGE("Callback thread failed to GetEnv for class %s with rc %d.\n", configClassName, getEnvRc);
504 return NULL;
505 }
506
507 if ((*globalVm)->AttachCurrentThread(globalVm, &env, NULL) != 0) {
508 LOGE("Callback thread failed to AttachCurrentThread for class %s.\n", configClassName);
509 return NULL;
510 }
511 }
512
513 LOGD("Async callback block started.\n");
514
515 while(redirectionEnabled) {
516
517 struct CallbackData *callbackData = callbackDataRemove();
518 if (callbackData != NULL) {
519 if (callbackData->type == LogType) {
520
521 // LOG CALLBACK
522
523 int size = callbackData->logData.len;
524
525 jbyteArray byteArray = (jbyteArray) (*env)->NewByteArray(env, size);
526 (*env)->SetByteArrayRegion(env, byteArray, 0, size, callbackData->logData.str);
527 (*env)->CallStaticVoidMethod(env, configClass, logMethod, (jlong) callbackData->sessionId, callbackData->logLevel, byteArray);
528 (*env)->DeleteLocalRef(env, byteArray);
529
530 // CLEAN LOG DATA
531 av_bprint_finalize(&callbackData->logData, NULL);
532
533 } else {
534
535 // STATISTICS CALLBACK
536
537 (*env)->CallStaticVoidMethod(env, configClass, statisticsMethod,
538 (jlong) callbackData->sessionId, callbackData->statisticsFrameNumber,
539 callbackData->statisticsFps, callbackData->statisticsQuality,
540 callbackData->statisticsSize, callbackData->statisticsTime,
541 callbackData->statisticsBitrate, callbackData->statisticsSpeed);
542
543 }
544
545 atomic_fetch_sub(&sessionInTransitMessageCountMap[callbackData->sessionId % SESSION_MAP_SIZE], 1);
546
547 // CLEAN STRUCT
548 callbackData->next = NULL;
549 av_free(callbackData);
550
551 } else {
552 monitorWait(100);
553 }
554 }
555
556 (*globalVm)->DetachCurrentThread(globalVm);
557
558 LOGD("Async callback block stopped.\n");
559
560 return NULL;
561}
562
567 JNIEnv *env = NULL;
568 (*globalVm)->GetEnv(globalVm, (void**) &env, JNI_VERSION_1_6);
569 (*env)->CallStaticVoidMethod(env, configClass, closeParcelFileDescriptorMethod, fd);
570 return 0;
571}
572
580jint JNI_OnLoad(JavaVM *vm, void *reserved) {
581 JNIEnv *env;
582 if ((*vm)->GetEnv(vm, (void**)(&env), JNI_VERSION_1_6) != JNI_OK) {
583 LOGE("OnLoad failed to GetEnv for class %s.\n", configClassName);
584 return JNI_FALSE;
585 }
586
587 jclass localConfigClass = (*env)->FindClass(env, configClassName);
588 if (localConfigClass == NULL) {
589 LOGE("OnLoad failed to FindClass %s.\n", configClassName);
590 return JNI_FALSE;
591 }
592
593 if ((*env)->RegisterNatives(env, localConfigClass, configMethods, 14) < 0) {
594 LOGE("OnLoad failed to RegisterNatives for class %s.\n", configClassName);
595 return JNI_FALSE;
596 }
597
598 jclass localStringClass = (*env)->FindClass(env, stringClassName);
599 if (localStringClass == NULL) {
600 LOGE("OnLoad failed to FindClass %s.\n", stringClassName);
601 return JNI_FALSE;
602 }
603
604 (*env)->GetJavaVM(env, &globalVm);
605
606 logMethod = (*env)->GetStaticMethodID(env, localConfigClass, "log", "(JI[B)V");
607 if (logMethod == NULL) {
608 LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "log");
609 return JNI_FALSE;
610 }
611
612 statisticsMethod = (*env)->GetStaticMethodID(env, localConfigClass, "statistics", "(JIFFJIDD)V");
613 if (logMethod == NULL) {
614 LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "statistics");
615 return JNI_FALSE;
616 }
617
618 closeParcelFileDescriptorMethod = (*env)->GetStaticMethodID(env, localConfigClass, "closeParcelFileDescriptor", "(I)V");
619 if (logMethod == NULL) {
620 LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "closeParcelFileDescriptor");
621 return JNI_FALSE;
622 }
623
624 stringConstructor = (*env)->GetMethodID(env, localStringClass, "<init>", "([BLjava/lang/String;)V");
625 if (stringConstructor == NULL) {
626 LOGE("OnLoad thread failed to GetMethodID for %s.\n", "<init>");
627 return JNI_FALSE;
628 }
629
630 av_jni_set_java_vm(vm, NULL);
631
632 configClass = (jclass) ((*env)->NewGlobalRef(env, localConfigClass));
633 stringClass = (jclass) ((*env)->NewGlobalRef(env, localStringClass));
634
635 callbackDataHead = NULL;
636 callbackDataTail = NULL;
637
638 for(int i = 0; i<SESSION_MAP_SIZE; i++) {
639 atomic_init(&sessionMap[i], 0);
640 atomic_init(&sessionInTransitMessageCountMap[i], 0);
641 }
642
643 mutexInit();
644 monitorInit();
645
647
648 av_set_fd_close(close_parcel_file_descriptor);
649
650 return JNI_VERSION_1_6;
651}
652
660JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeLogLevel(JNIEnv *env, jclass object, jint level) {
661 configuredLogLevel = level;
662}
663
670JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeLogLevel(JNIEnv *env, jclass object) {
671 return configuredLogLevel;
672}
673
680JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_enableNativeRedirection(JNIEnv *env, jclass object) {
681 mutexLock();
682
683 if (redirectionEnabled != 0) {
684 mutexUnlock();
685 return;
686 }
688
689 mutexUnlock();
690
691 int rc = pthread_create(&callbackThread, 0, callbackThreadFunction, 0);
692 if (rc != 0) {
693 LOGE("Failed to create callback thread (rc=%d).\n", rc);
694 return;
695 }
696
697 av_log_set_callback(ffmpegkit_log_callback_function);
699}
700
707JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_disableNativeRedirection(JNIEnv *env, jclass object) {
708
709 mutexLock();
710
711 if (redirectionEnabled != 1) {
712 mutexUnlock();
713 return;
714 }
716
717 mutexUnlock();
718
719 av_log_set_callback(av_log_default_callback);
721
723}
724
732JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeFFmpegVersion(JNIEnv *env, jclass object) {
733 return (*env)->NewStringUTF(env, FFMPEG_VERSION);
734}
735
743JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeVersion(JNIEnv *env, jclass object) {
744 return (*env)->NewStringUTF(env, FFMPEG_KIT_VERSION);
745}
746
756JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute(JNIEnv *env, jclass object, jlong id, jobjectArray stringArray) {
757 jstring *tempArray = NULL;
758 int argumentCount = 1;
759 char **argv = NULL;
760
761 // SETS DEFAULT LOG LEVEL BEFORE STARTING A NEW RUN
762 av_log_set_level(configuredLogLevel);
763
764 if (stringArray) {
765 int programArgumentCount = (*env)->GetArrayLength(env, stringArray);
766 argumentCount = programArgumentCount + 1;
767
768 tempArray = (jstring *) av_malloc(sizeof(jstring) * programArgumentCount);
769 }
770
771 /* PRESERVE USAGE FORMAT
772 *
773 * ffmpeg <arguments>
774 */
775 argv = (char **)av_malloc(sizeof(char*) * (argumentCount));
776 argv[0] = (char *)av_malloc(sizeof(char) * (strlen(LIB_NAME) + 1));
777 strcpy(argv[0], LIB_NAME);
778
779 // PREPARE ARRAY ELEMENTS
780 if (stringArray) {
781 for (int i = 0; i < (argumentCount - 1); i++) {
782 tempArray[i] = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i);
783 if (tempArray[i] != NULL) {
784 argv[i + 1] = (char *) (*env)->GetStringUTFChars(env, tempArray[i], 0);
785 }
786 }
787 }
788
789 // REGISTER THE ID BEFORE STARTING THE SESSION
790 globalSessionId = (long) id;
791 addSession((long) id);
792
794
795 // RUN
796 int returnCode = ffmpeg_execute(argumentCount, argv);
797
798 // ALWAYS REMOVE THE ID FROM THE MAP
799 removeSession((long) id);
800
801 // CLEANUP
802 if (tempArray) {
803 for (int i = 0; i < (argumentCount - 1); i++) {
804 (*env)->ReleaseStringUTFChars(env, tempArray[i], argv[i + 1]);
805 }
806
807 av_free(tempArray);
808 }
809 av_free(argv[0]);
810 av_free(argv);
811
812 return returnCode;
813}
814
822JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegCancel(JNIEnv *env, jclass object, jlong id) {
824}
825
834JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_registerNewNativeFFmpegPipe(JNIEnv *env, jclass object, jstring ffmpegPipePath) {
835 const char *ffmpegPipePathString = (*env)->GetStringUTFChars(env, ffmpegPipePath, 0);
836
837 return mkfifo(ffmpegPipePathString, S_IRWXU | S_IRWXG | S_IROTH);
838}
839
847JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeBuildDate(JNIEnv *env, jclass object) {
848 char buildDate[10];
849 sprintf(buildDate, "%d", FFMPEG_KIT_BUILD_DATE);
850 return (*env)->NewStringUTF(env, buildDate);
851}
852
862JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeEnvironmentVariable(JNIEnv *env, jclass object, jstring variableName, jstring variableValue) {
863 const char *variableNameString = (*env)->GetStringUTFChars(env, variableName, 0);
864 const char *variableValueString = (*env)->GetStringUTFChars(env, variableValue, 0);
865
866 int rc = setenv(variableNameString, variableValueString, 1);
867
868 (*env)->ReleaseStringUTFChars(env, variableName, variableNameString);
869 (*env)->ReleaseStringUTFChars(env, variableValue, variableValueString);
870 return rc;
871}
872
880JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal(JNIEnv *env, jclass object, jint signum) {
881 if (signum == SIGQUIT) {
882 handleSIGQUIT = 0;
883 } else if (signum == SIGINT) {
884 handleSIGINT = 0;
885 } else if (signum == SIGTERM) {
886 handleSIGTERM = 0;
887 } else if (signum == SIGXCPU) {
888 handleSIGXCPU = 0;
889 } else if (signum == SIGPIPE) {
890 handleSIGPIPE = 0;
891 }
892}
893
902JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_messagesInTransmit(JNIEnv *env, jclass object, jlong id) {
903 return atomic_load(&sessionInTransitMessageCountMap[id % SESSION_MAP_SIZE]);
904}
void monitorUnInit()
Definition: ffmpegkit.c:226
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeBuildDate(JNIEnv *env, jclass object)
Definition: ffmpegkit.c:847
void ffmpegkit_log_callback_function(void *ptr, int level, const char *format, va_list vargs)
Definition: ffmpegkit.c:443
static atomic_short sessionMap[SESSION_MAP_SIZE]
Definition: ffmpegkit.c:57
static jclass stringClass
Definition: ffmpegkit.c:87
static pthread_mutex_t lockMutex
Definition: ffmpegkit.c:61
struct CallbackData * callbackDataRemove()
Definition: ffmpegkit.c:365
#define SESSION_MAP_SIZE
Definition: ffmpegkit.c:56
struct CallbackData * callbackDataTail
Definition: ffmpegkit.c:69
void addSession(long id)
Definition: ffmpegkit.c:358
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute(JNIEnv *env, jclass object, jlong id, jobjectArray stringArray)
Definition: ffmpegkit.c:756
void monitorNotify()
Definition: ffmpegkit.c:261
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_enableNativeRedirection(JNIEnv *env, jclass object)
Definition: ffmpegkit.c:680
static void avutil_log_sanitize(uint8_t *line)
Definition: ffmpegkit.c:189
volatile int handleSIGINT
Definition: ffmpegkit.c:100
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeLogLevel(JNIEnv *env, jclass object, jint level)
Definition: ffmpegkit.c:660
volatile int handleSIGTERM
Definition: ffmpegkit.c:101
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegCancel(JNIEnv *env, jclass object, jlong id)
Definition: ffmpegkit.c:822
const char * configClassName
Definition: ffmpegkit.c:93
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeLogLevel(JNIEnv *env, jclass object)
Definition: ffmpegkit.c:670
static const char * avutil_log_get_level_str(int level)
Definition: ffmpegkit.c:132
void ffmpegkit_statistics_callback_function(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed)
Definition: ffmpegkit.c:491
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:157
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeFFmpegVersion(JNIEnv *env, jclass object)
Definition: ffmpegkit.c:732
void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed)
Definition: ffmpegkit.c:312
const char * stringClassName
Definition: ffmpegkit.c:96
JNINativeMethod configMethods[]
Definition: ffmpegkit.c:112
void monitorWait(int milliSeconds)
Definition: ffmpegkit.c:239
static JavaVM * globalVm
Definition: ffmpegkit.c:72
struct CallbackData * callbackDataHead
Definition: ffmpegkit.c:68
pthread_t callbackThread
Definition: ffmpegkit.c:65
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal(JNIEnv *env, jclass object, jint signum)
Definition: ffmpegkit.c:880
static pthread_cond_t monitorCondition
Definition: ffmpegkit.c:63
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeVersion(JNIEnv *env, jclass object)
Definition: ffmpegkit.c:743
void monitorInit()
Definition: ffmpegkit.c:206
void cancelSession(long id)
Definition: ffmpegkit.c:408
int redirectionEnabled
Definition: ffmpegkit.c:66
int cancelRequested(long id)
Definition: ffmpegkit.c:418
void mutexUnlock()
Definition: ffmpegkit.c:235
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_registerNewNativeFFmpegPipe(JNIEnv *env, jclass object, jstring ffmpegPipePath)
Definition: ffmpegkit.c:834
void mutexUnInit()
Definition: ffmpegkit.c:222
#define LogType
Definition: ffmpegkit.c:33
void * callbackThreadFunction()
Definition: ffmpegkit.c:498
volatile int handleSIGPIPE
Definition: ffmpegkit.c:103
static pthread_mutex_t monitorMutex
Definition: ffmpegkit.c:62
jint JNI_OnLoad(JavaVM *vm, void *reserved)
Definition: ffmpegkit.c:580
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_disableNativeRedirection(JNIEnv *env, jclass object)
Definition: ffmpegkit.c:707
static jmethodID logMethod
Definition: ffmpegkit.c:78
volatile int handleSIGXCPU
Definition: ffmpegkit.c:102
void resetMessagesInTransmit(long id)
Definition: ffmpegkit.c:431
static jclass configClass
Definition: ffmpegkit.c:75
static atomic_int sessionInTransitMessageCountMap[SESSION_MAP_SIZE]
Definition: ffmpegkit.c:58
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeEnvironmentVariable(JNIEnv *env, jclass object, jstring variableName, jstring variableValue)
Definition: ffmpegkit.c:862
void mutexLock()
Definition: ffmpegkit.c:231
void mutexInit()
Definition: ffmpegkit.c:197
int configuredLogLevel
Definition: ffmpegkit.c:109
int close_parcel_file_descriptor(int fd)
Definition: ffmpegkit.c:566
#define StatisticsType
Definition: ffmpegkit.c:34
int ffmpeg_execute(int argc, char **argv)
static jmethodID stringConstructor
Definition: ffmpegkit.c:90
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_messagesInTransmit(JNIEnv *env, jclass object, jlong id)
Definition: ffmpegkit.c:902
__thread volatile long globalSessionId
Definition: ffmpegkit.c:106
static jmethodID statisticsMethod
Definition: ffmpegkit.c:81
static jmethodID closeParcelFileDescriptorMethod
Definition: ffmpegkit.c:84
volatile int handleSIGQUIT
Definition: ffmpegkit.c:99
void logCallbackDataAdd(int level, AVBPrint *data)
Definition: ffmpegkit.c:273
void removeSession(long id)
Definition: ffmpegkit.c:399
#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)
fg outputs[0] format
#define pthread_mutex_lock(a)
#define pthread_mutex_unlock(a)
int logLevel
Definition: ffmpegkit.c:41
double statisticsBitrate
Definition: ffmpegkit.c:49
float statisticsQuality
Definition: ffmpegkit.c:46
struct CallbackData * next
Definition: ffmpegkit.c:52
double statisticsSpeed
Definition: ffmpegkit.c:50
int statisticsFrameNumber
Definition: ffmpegkit.c:44
int statisticsTime
Definition: ffmpegkit.c:48
float statisticsFps
Definition: ffmpegkit.c:45
long sessionId
Definition: ffmpegkit.c:39
AVBPrint logData
Definition: ffmpegkit.c:42
int64_t statisticsSize
Definition: ffmpegkit.c:47