26#include "libavcodec/jni.h"
27#include "libavutil/bprint.h"
28#include "libavutil/file.h"
34# define StatisticsType 2
56#define SESSION_MAP_SIZE 1000
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);
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);
174 av_bprintf(part+1,
"[%s @ %p] ",
175 avc->item_name(avcl), avcl);
178 if (*print_prefix && (level > AV_LOG_QUIET) && (flags & AV_LOG_PRINT_LEVEL))
181 av_vbprintf(part+3, fmt, vl);
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';
191 if(*line < 0x08 || (*line > 0x0D && *line < 0x20))
198 pthread_mutexattr_t attributes;
199 pthread_mutexattr_init(&attributes);
200 pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
202 pthread_mutex_init(&
lockMutex, &attributes);
203 pthread_mutexattr_destroy(&attributes);
207 pthread_mutexattr_t attributes;
208 pthread_mutexattr_init(&attributes);
209 pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
211 pthread_condattr_t cattributes;
212 pthread_condattr_init(&cattributes);
213 pthread_condattr_setpshared(&cattributes, PTHREAD_PROCESS_PRIVATE);
216 pthread_mutexattr_destroy(&attributes);
219 pthread_condattr_destroy(&cattributes);
244 rc = gettimeofday(&tp, NULL);
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;
280 av_bprint_init(&newData->
logData, 0, AV_BPRINT_SIZE_UNLIMITED);
281 av_bprintf(&newData->
logData,
"%s", data->str);
282 newData->
next = NULL;
291 LOGE(
"Dangling callback data head detected. This can cause memory leak.");
297 oldTail->
next = newData;
326 newData->
next = NULL;
335 LOGE(
"Dangling callback data head detected. This can cause memory leak.");
341 oldTail->
next = newData;
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.");
446 int print_prefix = 1;
451 int activeLogLevel = av_log_get_level();
454 if ((activeLogLevel == AV_LOG_QUIET && level !=
AV_LOG_STDERR) || (level > activeLogLevel)) {
458 av_bprint_init(&fullLine, 0, AV_BPRINT_SIZE_UNLIMITED);
467 av_bprintf(&fullLine,
"%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
469 if (fullLine.len > 0) {
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);
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);
507 if ((*globalVm)->AttachCurrentThread(
globalVm, &env, NULL) != 0) {
513 LOGD(
"Async callback block started.\n");
518 if (callbackData != NULL) {
523 int size = callbackData->
logData.len;
525 jbyteArray byteArray = (jbyteArray) (*env)->NewByteArray(env, size);
526 (*env)->SetByteArrayRegion(env, byteArray, 0, size, callbackData->
logData.str);
528 (*env)->DeleteLocalRef(env, byteArray);
531 av_bprint_finalize(&callbackData->
logData, NULL);
548 callbackData->
next = NULL;
549 av_free(callbackData);
556 (*globalVm)->DetachCurrentThread(
globalVm);
558 LOGD(
"Async callback block stopped.\n");
568 (*globalVm)->GetEnv(
globalVm, (
void**) &env, JNI_VERSION_1_6);
582 if ((*vm)->GetEnv(vm, (
void**)(&env), JNI_VERSION_1_6) != JNI_OK) {
588 if (localConfigClass == NULL) {
593 if ((*env)->RegisterNatives(env, localConfigClass,
configMethods, 14) < 0) {
599 if (localStringClass == NULL) {
606 logMethod = (*env)->GetStaticMethodID(env, localConfigClass,
"log",
"(JI[B)V");
608 LOGE(
"OnLoad thread failed to GetStaticMethodID for %s.\n",
"log");
612 statisticsMethod = (*env)->GetStaticMethodID(env, localConfigClass,
"statistics",
"(JIFFJIDD)V");
614 LOGE(
"OnLoad thread failed to GetStaticMethodID for %s.\n",
"statistics");
620 LOGE(
"OnLoad thread failed to GetStaticMethodID for %s.\n",
"closeParcelFileDescriptor");
624 stringConstructor = (*env)->GetMethodID(env, localStringClass,
"<init>",
"([BLjava/lang/String;)V");
626 LOGE(
"OnLoad thread failed to GetMethodID for %s.\n",
"<init>");
630 av_jni_set_java_vm(vm, NULL);
632 configClass = (jclass) ((*env)->NewGlobalRef(env, localConfigClass));
633 stringClass = (jclass) ((*env)->NewGlobalRef(env, localStringClass));
650 return JNI_VERSION_1_6;
693 LOGE(
"Failed to create callback thread (rc=%d).\n", rc);
719 av_log_set_callback(av_log_default_callback);
733 return (*env)->NewStringUTF(env, FFMPEG_VERSION);
757 jstring *tempArray = NULL;
758 int argumentCount = 1;
765 int programArgumentCount = (*env)->GetArrayLength(env, stringArray);
766 argumentCount = programArgumentCount + 1;
768 tempArray = (jstring *) av_malloc(
sizeof(jstring) * programArgumentCount);
775 argv = (
char **)av_malloc(
sizeof(
char*) * (argumentCount));
776 argv[0] = (
char *)av_malloc(
sizeof(
char) * (strlen(
LIB_NAME) + 1));
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);
803 for (
int i = 0; i < (argumentCount - 1); i++) {
804 (*env)->ReleaseStringUTFChars(env, tempArray[i], argv[i + 1]);
835 const char *ffmpegPipePathString = (*env)->GetStringUTFChars(env, ffmpegPipePath, 0);
837 return mkfifo(ffmpegPipePathString, S_IRWXU | S_IRWXG | S_IROTH);
849 sprintf(buildDate,
"%d", FFMPEG_KIT_BUILD_DATE);
850 return (*env)->NewStringUTF(env, buildDate);
863 const char *variableNameString = (*env)->GetStringUTFChars(env, variableName, 0);
864 const char *variableValueString = (*env)->GetStringUTFChars(env, variableValue, 0);
866 int rc = setenv(variableNameString, variableValueString, 1);
868 (*env)->ReleaseStringUTFChars(env, variableName, variableNameString);
869 (*env)->ReleaseStringUTFChars(env, variableValue, variableValueString);
881 if (signum == SIGQUIT) {
883 }
else if (signum == SIGINT) {
885 }
else if (signum == SIGTERM) {
887 }
else if (signum == SIGXCPU) {
889 }
else if (signum == SIGPIPE) {
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeBuildDate(JNIEnv *env, jclass object)
void ffmpegkit_log_callback_function(void *ptr, int level, const char *format, va_list vargs)
static atomic_short sessionMap[SESSION_MAP_SIZE]
static jclass stringClass
static pthread_mutex_t lockMutex
struct CallbackData * callbackDataRemove()
struct CallbackData * callbackDataTail
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegExecute(JNIEnv *env, jclass object, jlong id, jobjectArray stringArray)
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_enableNativeRedirection(JNIEnv *env, jclass object)
static void avutil_log_sanitize(uint8_t *line)
volatile int handleSIGINT
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_setNativeLogLevel(JNIEnv *env, jclass object, jint level)
volatile int handleSIGTERM
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFmpegCancel(JNIEnv *env, jclass object, jlong id)
const char * configClassName
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeLogLevel(JNIEnv *env, jclass object)
static const char * avutil_log_get_level_str(int level)
void ffmpegkit_statistics_callback_function(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed)
static void avutil_log_format_line(void *avcl, int level, const char *fmt, va_list vl, AVBPrint part[4], int *print_prefix)
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeFFmpegVersion(JNIEnv *env, jclass object)
void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed)
const char * stringClassName
JNINativeMethod configMethods[]
void monitorWait(int milliSeconds)
struct CallbackData * callbackDataHead
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_ignoreNativeSignal(JNIEnv *env, jclass object, jint signum)
static pthread_cond_t monitorCondition
JNIEXPORT jstring JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_getNativeVersion(JNIEnv *env, jclass object)
void cancelSession(long id)
int cancelRequested(long id)
JNIEXPORT int JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_registerNewNativeFFmpegPipe(JNIEnv *env, jclass object, jstring ffmpegPipePath)
void * callbackThreadFunction()
volatile int handleSIGPIPE
static pthread_mutex_t monitorMutex
jint JNI_OnLoad(JavaVM *vm, void *reserved)
JNIEXPORT void JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_disableNativeRedirection(JNIEnv *env, jclass object)
static jmethodID logMethod
volatile int handleSIGXCPU
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 close_parcel_file_descriptor(int fd)
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)
__thread volatile long globalSessionId
static jmethodID statisticsMethod
static jmethodID closeParcelFileDescriptorMethod
volatile int handleSIGQUIT
void logCallbackDataAdd(int level, AVBPrint *data)
void removeSession(long id)
#define FFMPEG_KIT_VERSION
JNIEXPORT jint JNICALL Java_com_arthenica_ffmpegkit_FFmpegKitConfig_nativeFFprobeExecute(JNIEnv *env, jclass object, jlong id, jobjectArray stringArray)
struct CallbackData * next
int statisticsFrameNumber