23#import "libavutil/ffversion.h"
24#import "libavutil/bprint.h"
58#define SESSION_MAP_SIZE 1000
79static NSRecursiveLock *
lock;
109 id<Session> first = [sessionHistoryList firstObject];
111 [sessionHistoryList removeObjectAtIndex:0];
112 [sessionHistoryMap removeObjectForKey:[NSNumber numberWithLong:[first getSessionId]]];
118 NSNumber* sessionIdNumber = [NSNumber numberWithLong:[session getSessionId]];
120 [sessionHistoryLock lock];
127 [sessionHistoryMap setObject:session forKey:sessionIdNumber];
128 [sessionHistoryList addObject:session];
132 [sessionHistoryLock unlock];
158 - (instancetype)init:(
long)sessionId logLevel:(
int)logLevel data:(AVBPrint*)data {
164 av_bprint_init(&
_logData, 0, AV_BPRINT_SIZE_UNLIMITED);
165 av_bprintf(&
_logData,
"%s", data->str);
171 - (instancetype)init:(
long)sessionId
172 videoFrameNumber:(
int)videoFrameNumber
174 quality:(
float)videoQuality
177 bitrate:(
double)bitrate
178 speed:(
double)speed {
181 _type = StatisticsType;
195- (CallbackType)getType {
199- (long)getSessionId {
207- (AVBPrint*)getLogData {
211- (
int)getStatisticsFrameNumber {
215- (float)getStatisticsFps {
219- (float)getStatisticsQuality {
223- (int64_t)getStatisticsSize {
227- (
int)getStatisticsTime {
231- (double)getStatisticsBitrate {
235- (double)getStatisticsSpeed {
247 dispatch_semaphore_wait(
semaphore, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(milliSeconds * NSEC_PER_MSEC)));
282static void avutil_log_format_line(
void *avcl,
int level,
const char *fmt, va_list vl, AVBPrint part[4],
int *print_prefix) {
283 int flags = av_log_get_flags();
284 AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
285 av_bprint_init(part+0, 0, 1);
286 av_bprint_init(part+1, 0, 1);
287 av_bprint_init(part+2, 0, 1);
288 av_bprint_init(part+3, 0, 65536);
290 if (*print_prefix && avc) {
291 if (avc->parent_log_context_offset) {
292 AVClass** parent = *(AVClass ***) (((uint8_t *) avcl) +
293 avc->parent_log_context_offset);
294 if (parent && *parent) {
295 av_bprintf(part+0,
"[%s @ %p] ",
296 (*parent)->item_name(parent), parent);
299 av_bprintf(part+1,
"[%s @ %p] ",
300 avc->item_name(avcl), avcl);
303 if (*print_prefix && (level > AV_LOG_QUIET) && (flags & AV_LOG_PRINT_LEVEL))
306 av_vbprintf(part+3, fmt, vl);
308 if(*part[0].str || *part[1].str || *part[2].str || *part[3].str) {
309 char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0;
310 *print_prefix = lastc ==
'\n' || lastc ==
'\r';
316 if(*line < 0x08 || (*line > 0x0D && *line < 0x20))
332 [callbackDataArray addObject:callbackData];
344 CallbackData *callbackData = [[
CallbackData alloc] init:globalSessionId videoFrameNumber:frameNumber fps:fps quality:quality size:size time:time bitrate:bitrate speed:speed];
347 [callbackDataArray addObject:callbackData];
365 newData = [callbackDataArray objectAtIndex:0];
366 [callbackDataArray removeObjectAtIndex:0];
368 }
@catch(NSException *exception) {
438 int print_prefix = 1;
444 int activeLogLevel = av_log_get_level();
447 if ((activeLogLevel == LevelAVLogQuiet && level != LevelAVLogStdErr) || (level > activeLogLevel)) {
451 av_bprint_init(&fullLine, 0, AV_BPRINT_SIZE_UNLIMITED);
460 av_bprintf(&fullLine,
"%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
462 if (fullLine.len > 0) {
466 av_bprint_finalize(part, NULL);
467 av_bprint_finalize(part+1, NULL);
468 av_bprint_finalize(part+2, NULL);
469 av_bprint_finalize(part+3, NULL);
470 av_bprint_finalize(&fullLine, NULL);
488void process_log(
long sessionId,
int levelValue, AVBPrint* logMessage) {
489 int activeLogLevel = av_log_get_level();
490 Log* log = [[
Log alloc] init:sessionId:levelValue:[NSString stringWithCString:logMessage->str encoding:NSUTF8StringEncoding]];
491 BOOL globalCallbackDefined =
false;
492 BOOL sessionCallbackDefined =
false;
496 if ((activeLogLevel == LevelAVLogQuiet && levelValue != LevelAVLogStdErr) || (levelValue > activeLogLevel)) {
502 if (session != nil) {
503 activeLogRedirectionStrategy = [session getLogRedirectionStrategy];
504 [session addLog:log];
506 LogCallback sessionLogCallback = [session getLogCallback];
507 if (sessionLogCallback != nil) {
508 sessionCallbackDefined = TRUE;
512 sessionLogCallback(log);
514 @catch(NSException* exception) {
515 NSLog(
@"Exception thrown inside session log callback. %@", [exception callStackSymbols]);
521 if (globalLogCallback != nil) {
522 globalCallbackDefined = TRUE;
526 globalLogCallback(log);
528 @catch(NSException* exception) {
529 NSLog(
@"Exception thrown inside global log callback. %@", [exception callStackSymbols]);
534 switch (activeLogRedirectionStrategy) {
535 case LogRedirectionStrategyNeverPrintLogs: {
538 case LogRedirectionStrategyPrintLogsWhenGlobalCallbackNotDefined: {
539 if (globalCallbackDefined) {
544 case LogRedirectionStrategyPrintLogsWhenSessionCallbackNotDefined: {
545 if (sessionCallbackDefined) {
550 case LogRedirectionStrategyPrintLogsWhenNoCallbacksDefined: {
551 if (globalCallbackDefined || sessionCallbackDefined) {
556 case LogRedirectionStrategyAlwaysPrintLogs: {
562 switch (levelValue) {
563 case LevelAVLogQuiet:
568 NSLog(
@"%@: %@", [
FFmpegKitConfig logLevelToString:levelValue], [NSString stringWithCString:logMessage->str encoding:NSUTF8StringEncoding]);
573void process_statistics(
long sessionId,
int videoFrameNumber,
float videoFps,
float videoQuality,
long size,
int time,
double bitrate,
double speed) {
575 Statistics *statistics = [[
Statistics alloc] init:sessionId videoFrameNumber:videoFrameNumber videoFps:videoFps videoQuality:videoQuality size:size time:time bitrate:bitrate speed:speed];
578 if (session != nil && [session isFFmpeg]) {
583 if (sessionStatisticsCallback != nil) {
585 sessionStatisticsCallback(statistics);
587 @catch(NSException* exception) {
588 NSLog(
@"Exception thrown inside session statistics callback. %@", [exception callStackSymbols]);
594 if (globalStatisticsCallback != nil) {
596 globalStatisticsCallback(statistics);
598 @catch(NSException* exception) {
599 NSLog(
@"Exception thrown inside global statistics callback. %@", [exception callStackSymbols]);
608 int activeLogLevel = av_log_get_level();
609 if ((activeLogLevel != LevelAVLogQuiet) && (LevelAVLogDebug <= activeLogLevel)) {
610 NSLog(
@"Async callback block started.\n");
618 if (callbackData != nil) {
620 if ([callbackData getType] == LogType) {
621 process_log([callbackData getSessionId], [callbackData getLogLevel], [callbackData getLogData]);
622 av_bprint_finalize([callbackData getLogData], NULL);
625 [callbackData getStatisticsFrameNumber],
626 [callbackData getStatisticsFps],
627 [callbackData getStatisticsQuality],
628 [callbackData getStatisticsSize],
629 [callbackData getStatisticsTime],
630 [callbackData getStatisticsBitrate],
631 [callbackData getStatisticsSpeed]);
640 }
@catch(NSException *exception) {
641 activeLogLevel = av_log_get_level();
642 if ((activeLogLevel != LevelAVLogQuiet) && (LevelAVLogWarning <= activeLogLevel)) {
643 NSLog(
@"Async callback block received error: %@n\n", exception);
644 NSLog(
@"%@", [exception callStackSymbols]);
650 activeLogLevel = av_log_get_level();
651 if ((activeLogLevel != LevelAVLogQuiet) && (LevelAVLogDebug <= activeLogLevel)) {
652 NSLog(
@"Async callback block stopped.\n");
657 NSString*
const LIB_NAME =
@"ffmpeg";
662 char **commandCharPArray = (
char **)av_malloc(
sizeof(
char*) * ([arguments count] + 1));
668 commandCharPArray[0] = (
char *)av_malloc(
sizeof(
char) * ([LIB_NAME length] + 1));
669 strcpy(commandCharPArray[0], [LIB_NAME UTF8String]);
672 for (
int i=0; i < [arguments count]; i++) {
673 NSString *argument = [arguments objectAtIndex:i];
674 commandCharPArray[i + 1] = (
char *) [argument UTF8String];
684 int returnCode =
ffmpeg_execute(([arguments count] + 1), commandCharPArray);
690 av_free(commandCharPArray[0]);
691 av_free(commandCharPArray);
697 NSString*
const LIB_NAME =
@"ffprobe";
702 char **commandCharPArray = (
char **)av_malloc(
sizeof(
char*) * ([arguments count] + 1));
708 commandCharPArray[0] = (
char *)av_malloc(
sizeof(
char) * ([LIB_NAME length] + 1));
709 strcpy(commandCharPArray[0], [LIB_NAME UTF8String]);
712 for (
int i=0; i < [arguments count]; i++) {
713 NSString *argument = [arguments objectAtIndex:i];
714 commandCharPArray[i + 1] = (
char *) [argument UTF8String];
724 int returnCode =
ffprobe_execute(([arguments count] + 1), commandCharPArray);
730 av_free(commandCharPArray[0]);
731 av_free(commandCharPArray);
766 lock = [[NSRecursiveLock alloc] init];
767 semaphore = dispatch_semaphore_create(0);
784 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
803 av_log_set_callback(av_log_default_callback);
809+ (
int)setFontconfigConfigurationPath:(NSString*)path {
813+ (void)setFontDirectory:(NSString*)fontDirectoryPath with:(NSDictionary*)fontNameMapping {
817+ (void)setFontDirectoryList:(NSArray*)fontDirectoryArray with:(NSDictionary*)fontNameMapping {
818 NSError *error = nil;
819 BOOL isDirectory = YES;
821 int validFontNameMappingCount = 0;
822 NSString *tempConfigurationDirectory = [NSTemporaryDirectory() stringByAppendingPathComponent:@"fontconfig"];
823 NSString *fontConfigurationFile = [tempConfigurationDirectory stringByAppendingPathComponent:@"fonts.conf"];
825 if (![[NSFileManager defaultManager] fileExistsAtPath:tempConfigurationDirectory isDirectory:&isDirectory]) {
826 if (![[NSFileManager defaultManager] createDirectoryAtPath:tempConfigurationDirectory withIntermediateDirectories:YES attributes:nil error:&error]) {
827 NSLog(
@"Failed to set font directory. Error received while creating temp conf directory: %@.", error);
830 NSLog(
@"Created temporary font conf directory: TRUE.");
833 if ([[NSFileManager defaultManager] fileExistsAtPath:fontConfigurationFile isDirectory:&isFile]) {
834 BOOL fontConfigurationDeleted = [[NSFileManager defaultManager] removeItemAtPath:fontConfigurationFile error:nil];
835 NSLog(
@"Deleted old temporary font configuration: %s.", fontConfigurationDeleted?
"TRUE":
"FALSE");
839 NSString *fontNameMappingBlock =
@"";
840 for (NSString *fontName in [fontNameMapping allKeys]) {
841 NSString *mappedFontName = [fontNameMapping objectForKey:fontName];
843 if ((fontName != nil) && (mappedFontName != nil) && ([fontName length] > 0) && ([mappedFontName length] > 0)) {
845 fontNameMappingBlock = [NSString stringWithFormat:@"%@\n%@\n%@%@%@\n%@\n%@\n%@%@%@\n%@\n%@\n",
846 @" <match target=\"pattern\">",
847 @" <test qual=\"any\" name=\"family\">",
848 @" <string>", fontName, @"</string>",
850 @" <edit name=\"family\" mode=\"assign\" binding=\"same\">",
851 @" <string>", mappedFontName, @"</string>",
855 validFontNameMappingCount++;
859 NSMutableString *fontConfiguration = [NSMutableString stringWithFormat:@"%@\n%@\n%@\n%@\n",
860 @"<?xml version=\"1.0\"?>",
861 @"<!DOCTYPE fontconfig SYSTEM \"fonts.dtd\">",
863 @" <dir prefix=\"cwd\">.</dir>"];
864 for (
int i=0; i < [fontDirectoryArray count]; i++) {
865 NSString *fontDirectoryPath = [fontDirectoryArray objectAtIndex:i];
866 [fontConfiguration appendString: @" <dir>"];
867 [fontConfiguration appendString: fontDirectoryPath];
868 [fontConfiguration appendString: @"</dir>\n"];
870 [fontConfiguration appendString:fontNameMappingBlock];
871 [fontConfiguration appendString:@"</fontconfig>\n"];
873 if (![fontConfiguration writeToFile:fontConfigurationFile atomically:YES encoding:NSUTF8StringEncoding error:&error]) {
874 NSLog(
@"Failed to set font directory. Error received while saving font configuration: %@.", error);
878 NSLog(
@"Saved new temporary font configuration with %d font name mappings.", validFontNameMappingCount);
882 for (
int i=0; i < [fontDirectoryArray count]; i++) {
883 NSString *fontDirectoryPath = [fontDirectoryArray objectAtIndex:i];
884 NSLog(
@"Font directory %@ registered successfully.", fontDirectoryPath);
889 NSError *error = nil;
893 NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
894 NSString *pipesDir = [cacheDir stringByAppendingPathComponent:@"pipes"];
896 if (![[NSFileManager defaultManager] fileExistsAtPath:pipesDir isDirectory:&isDirectory]) {
897 if (![[NSFileManager defaultManager] createDirectoryAtPath:pipesDir withIntermediateDirectories:YES attributes:nil error:&error]) {
898 NSLog(
@"Failed to create pipes directory: %@. Operation failed with %@.", pipesDir, error);
903 NSString *newFFmpegPipePath = [NSString stringWithFormat:@"%@/%@%ld", pipesDir, FFmpegKitNamedPipePrefix, [pipeIndexGenerator
getAndIncrement]];
908 int rc = mkfifo([newFFmpegPipePath UTF8String], S_IRWXU | S_IRWXG | S_IROTH);
910 return newFFmpegPipePath;
912 NSLog(
@"Failed to register new FFmpeg pipe %@. Operation failed with rc=%d.", newFFmpegPipePath, rc);
917+ (void)closeFFmpegPipe:(NSString*)ffmpegPipePath {
918 NSFileManager *fileManager = [NSFileManager defaultManager];
920 if ([fileManager fileExistsAtPath:ffmpegPipePath]){
921 [fileManager removeItemAtPath:ffmpegPipePath error:nil];
926 return [NSString stringWithUTF8String:FFMPEG_VERSION];
931 return [NSString stringWithFormat:@"%@-lts", FFmpegKitVersion];
938 #if defined(FFMPEG_KIT_LTS)
947 sprintf(buildDate,
"%d", FFMPEG_KIT_BUILD_DATE);
948 return [NSString stringWithUTF8String:buildDate];
951+ (
int)setEnvironmentVariable:(NSString*)variableName value:(NSString*)variableValue {
952 return setenv([variableName UTF8String], [variableValue UTF8String],
true);
955+ (void)ignoreSignal:(Signal)signal {
956 if (signal == SignalQuit) {
958 }
else if (signal == SignalInt) {
960 }
else if (signal == SignalTerm) {
962 }
else if (signal == SignalXcpu) {
964 }
else if (signal == SignalPipe) {
973 int returnCode =
executeFFmpeg([ffmpegSession getSessionId], [ffmpegSession getArguments]);
975 }
@catch (NSException *exception) {
976 [ffmpegSession
fail:exception];
977 NSLog(
@"FFmpeg execute failed: %@.%@", [
FFmpegKitConfig argumentsToString:[ffmpegSession getArguments]], [NSString stringWithFormat:
@"%@", [exception callStackSymbols]]);
985 int returnCode =
executeFFprobe([ffprobeSession getSessionId], [ffprobeSession getArguments]);
987 }
@catch (NSException *exception) {
988 [ffprobeSession
fail:exception];
989 NSLog(
@"FFprobe execute failed: %@.%@", [
FFmpegKitConfig argumentsToString:[ffprobeSession getArguments]], [NSString stringWithFormat:
@"%@", [exception callStackSymbols]]);
993+ (void)getMediaInformationExecute:(
MediaInformationSession*)mediaInformationSession withTimeout:(
int)waitTimeout {
997 int returnCodeValue =
executeFFprobe([mediaInformationSession getSessionId], [mediaInformationSession getArguments]);
999 [mediaInformationSession
complete:returnCode];
1000 if ([returnCode isValueSuccess]) {
1002 NSMutableString* ffprobeJsonOutput = [[NSMutableString alloc] init];
1003 for (
int i=0; i < [allLogs count]; i++) {
1004 Log* log = [allLogs objectAtIndex:i];
1005 if ([log getLevel] == LevelAVLogStdErr) {
1006 [ffprobeJsonOutput appendString:[log
getMessage]];
1012 }
@catch (NSException *exception) {
1013 [mediaInformationSession
fail:exception];
1014 NSLog(
@"Get media information execute failed: %@.%@", [
FFmpegKitConfig argumentsToString:[mediaInformationSession getArguments]], [NSString stringWithFormat:
@"\n%@\n%@", [exception userInfo], [exception callStackSymbols]]);
1022+ (void)asyncFFmpegExecute:(
FFmpegSession*)ffmpegSession onDispatchQueue:(dispatch_queue_t)queue {
1023 dispatch_async(queue, ^{
1027 if (completeCallback != nil) {
1030 completeCallback(ffmpegSession);
1032 @catch(NSException* exception) {
1033 NSLog(
@"Exception thrown inside session complete callback. %@", [exception callStackSymbols]);
1038 if (globalFFmpegSessionCompleteCallback != nil) {
1041 globalFFmpegSessionCompleteCallback(ffmpegSession);
1043 @catch(NSException* exception) {
1044 NSLog(
@"Exception thrown inside global complete callback. %@", [exception callStackSymbols]);
1054+ (void)asyncFFprobeExecute:(
FFprobeSession*)ffprobeSession onDispatchQueue:(dispatch_queue_t)queue {
1055 dispatch_async(queue, ^{
1059 if (completeCallback != nil) {
1062 completeCallback(ffprobeSession);
1064 @catch(NSException* exception) {
1065 NSLog(
@"Exception thrown inside session complete callback. %@", [exception callStackSymbols]);
1070 if (globalFFprobeSessionCompleteCallback != nil) {
1073 globalFFprobeSessionCompleteCallback(ffprobeSession);
1075 @catch(NSException* exception) {
1076 NSLog(
@"Exception thrown inside global complete callback. %@", [exception callStackSymbols]);
1082+ (void)asyncGetMediaInformationExecute:(
MediaInformationSession*)mediaInformationSession withTimeout:(
int)waitTimeout {
1086+ (void)asyncGetMediaInformationExecute:(
MediaInformationSession*)mediaInformationSession onDispatchQueue:(dispatch_queue_t)queue withTimeout:(
int)waitTimeout {
1087 dispatch_async(queue, ^{
1091 if (completeCallback != nil) {
1094 completeCallback(mediaInformationSession);
1096 @catch(NSException* exception) {
1097 NSLog(
@"Exception thrown inside session complete callback. %@", [exception callStackSymbols]);
1102 if (globalMediaInformationSessionCompleteCallback != nil) {
1105 globalMediaInformationSessionCompleteCallback(mediaInformationSession);
1107 @catch(NSException* exception) {
1108 NSLog(
@"Exception thrown inside global complete callback. %@", [exception callStackSymbols]);
1150+ (void)setLogLevel:(
int)level {
1154+ (NSString*)logLevelToString:(
int)level {
1156 case LevelAVLogStdErr:
return @"STDERR";
1157 case LevelAVLogTrace:
return @"TRACE";
1158 case LevelAVLogDebug:
return @"DEBUG";
1159 case LevelAVLogVerbose:
return @"VERBOSE";
1160 case LevelAVLogInfo:
return @"INFO";
1161 case LevelAVLogWarning:
return @"WARNING";
1162 case LevelAVLogError:
return @"ERROR";
1163 case LevelAVLogFatal:
return @"FATAL";
1164 case LevelAVLogPanic:
return @"PANIC";
1165 case LevelAVLogQuiet:
return @"QUIET";
1166 default:
return @"";
1174+ (void)setSessionHistorySize:(
int)pSessionHistorySize {
1180 @throw([NSException exceptionWithName:NSInvalidArgumentException reason:@"Session history size must not exceed the hard limit!" userInfo:nil]);
1181 }
else if (pSessionHistorySize > 0) {
1187+ (id<
Session>)getSession:(
long)sessionId {
1188 [sessionHistoryLock lock];
1190 id<Session> session = [sessionHistoryMap objectForKey:[NSNumber numberWithLong:sessionId]];
1192 [sessionHistoryLock unlock];
1198 [sessionHistoryLock lock];
1200 id<Session> lastSession = [sessionHistoryList lastObject];
1202 [sessionHistoryLock unlock];
1208 id<Session> lastCompletedSession = nil;
1210 [sessionHistoryLock lock];
1213 id<Session> session = [sessionHistoryList objectAtIndex:i];
1214 if ([session getState] == SessionStateCompleted) {
1215 lastCompletedSession = session;
1220 [sessionHistoryLock unlock];
1222 return lastCompletedSession;
1226 [sessionHistoryLock lock];
1228 NSArray* sessionsCopy = [sessionHistoryList copy];
1230 [sessionHistoryLock unlock];
1232 return sessionsCopy;
1236 [sessionHistoryLock lock];
1238 [sessionHistoryList removeAllObjects];
1239 [sessionHistoryMap removeAllObjects];
1241 [sessionHistoryLock unlock];
1245 NSMutableArray* ffmpegSessions = [[NSMutableArray alloc] init];
1247 [sessionHistoryLock lock];
1249 for(
int i = 0; i < [sessionHistoryList count]; i++) {
1250 id<Session> session = [sessionHistoryList objectAtIndex:i];
1251 if ([session isFFmpeg]) {
1252 [ffmpegSessions addObject:session];
1256 [sessionHistoryLock unlock];
1258 return ffmpegSessions;
1262 NSMutableArray* ffprobeSessions = [[NSMutableArray alloc] init];
1264 [sessionHistoryLock lock];
1266 for(
int i = 0; i < [sessionHistoryList count]; i++) {
1267 id<Session> session = [sessionHistoryList objectAtIndex:i];
1268 if ([session isFFprobe]) {
1269 [ffprobeSessions addObject:session];
1273 [sessionHistoryLock unlock];
1275 return ffprobeSessions;
1279 NSMutableArray* mediaInformationSessions = [[NSMutableArray alloc] init];
1281 [sessionHistoryLock lock];
1283 for(
int i = 0; i < [sessionHistoryList count]; i++) {
1284 id<Session> session = [sessionHistoryList objectAtIndex:i];
1285 if ([session isMediaInformation]) {
1286 [mediaInformationSessions addObject:session];
1290 [sessionHistoryLock unlock];
1292 return mediaInformationSessions;
1295+ (NSArray*)getSessionsByState:(SessionState)state {
1296 NSMutableArray* sessions = [[NSMutableArray alloc] init];
1298 [sessionHistoryLock lock];
1300 for(
int i = 0; i < [sessionHistoryList count]; i++) {
1301 id<Session> session = [sessionHistoryList objectAtIndex:i];
1302 if ([session getState] == state) {
1303 [sessions addObject:session];
1307 [sessionHistoryLock unlock];
1316+ (void)setLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy {
1320+ (
int)messagesInTransmit:(
long)sessionId {
1324+ (NSString*)sessionStateToString:(SessionState)state {
1326 case SessionStateCreated:
return @"CREATED";
1327 case SessionStateRunning:
return @"RUNNING";
1328 case SessionStateFailed:
return @"FAILED";
1329 case SessionStateCompleted:
return @"COMPLETED";
1330 default:
return @"";
1334+ (NSArray*)parseArguments:(NSString*)command {
1335 NSMutableArray *argumentArray = [[NSMutableArray alloc] init];
1336 NSMutableString *currentArgument = [[NSMutableString alloc] init];
1338 bool singleQuoteStarted =
false;
1339 bool doubleQuoteStarted =
false;
1341 for (
int i = 0; i < command.length; i++) {
1342 unichar previousChar;
1344 previousChar = [command characterAtIndex:(i - 1)];
1348 unichar currentChar = [command characterAtIndex:i];
1350 if (currentChar ==
' ') {
1351 if (singleQuoteStarted || doubleQuoteStarted) {
1352 [currentArgument appendFormat: @"%C", currentChar];
1353 }
else if ([currentArgument length] > 0) {
1354 [argumentArray addObject: currentArgument];
1355 currentArgument = [[NSMutableString alloc] init];
1357 }
else if (currentChar ==
'\'' && (previousChar == 0 || previousChar !=
'\\')) {
1358 if (singleQuoteStarted) {
1359 singleQuoteStarted =
false;
1360 }
else if (doubleQuoteStarted) {
1361 [currentArgument appendFormat: @"%C", currentChar];
1363 singleQuoteStarted =
true;
1365 }
else if (currentChar ==
'\"' && (previousChar == 0 || previousChar !=
'\\')) {
1366 if (doubleQuoteStarted) {
1367 doubleQuoteStarted =
false;
1368 }
else if (singleQuoteStarted) {
1369 [currentArgument appendFormat: @"%C", currentChar];
1371 doubleQuoteStarted =
true;
1374 [currentArgument appendFormat: @"%C", currentChar];
1378 if ([currentArgument length] > 0) {
1379 [argumentArray addObject: currentArgument];
1382 return argumentArray;
1385+ (NSString*)argumentsToString:(NSArray*)arguments {
1386 if (arguments == nil) {
1390 NSMutableString *
string = [NSMutableString stringWithString:@""];
1391 for (
int i=0; i < [arguments count]; i++) {
1392 NSString *argument = [arguments objectAtIndex:i];
1394 [string appendString:@" "];
1396 [string appendString:argument];
int executeFFprobe(long sessionId, NSArray *arguments)
void callbackWait(int milliSeconds)
void ffmpegkit_log_callback_function(void *ptr, int level, const char *format, va_list vargs)
static atomic_short sessionMap[SESSION_MAP_SIZE]
void cancelSession(long sessionId)
static volatile NSMutableDictionary * sessionHistoryMap
static FFmpegSessionCompleteCallback ffmpegSessionCompleteCallback
static int sessionHistorySize
static void avutil_log_sanitize(uint8_t *line)
static NSRecursiveLock * lock
volatile int handleSIGINT
int ffprobe_execute(int argc, char **argv)
volatile int handleSIGTERM
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)
static dispatch_queue_t asyncDispatchQueue
void removeSession(long sessionId)
void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed)
static LogCallback logCallback
void callbackBlockFunction()
double _statisticsBitrate
static MediaInformationSessionCompleteCallback mediaInformationSessionCompleteCallback
void registerSessionId(long sessionId)
static NSRecursiveLock * sessionHistoryLock
void process_log(long sessionId, int levelValue, AVBPrint *logMessage)
static dispatch_semaphore_t semaphore
void deleteExpiredSessions()
__thread long globalSessionId
static int redirectionEnabled
void resetMessagesInTransmit(long sessionId)
static NSMutableArray * callbackDataArray
CallbackData * callbackDataRemove()
int _statisticsFrameNumber
void process_statistics(long sessionId, int videoFrameNumber, float videoFps, float videoQuality, long size, int time, double bitrate, double speed)
int cancelRequested(long sessionId)
volatile int handleSIGPIPE
NSString *const FFmpegKitVersion
volatile int handleSIGXCPU
static LogRedirectionStrategy globalLogRedirectionStrategy
static StatisticsCallback statisticsCallback
static atomic_int sessionInTransitMessageCountMap[SESSION_MAP_SIZE]
static FFprobeSessionCompleteCallback ffprobeSessionCompleteCallback
static AtomicLong * pipeIndexGenerator
static NSMutableArray * sessionHistoryList
typedef NS_ENUM(NSUInteger, CallbackType)
NSString *const FFmpegKitNamedPipePrefix
void addSessionToSessionHistory(id< Session > session)
int ffmpeg_execute(int argc, char **argv)
volatile int handleSIGQUIT
void logCallbackDataAdd(int level, AVBPrint *data)
int executeFFmpeg(long sessionId, NSArray *arguments)
void(^ FFmpegSessionCompleteCallback)(FFmpegSession *session)
void(^ FFprobeSessionCompleteCallback)(FFprobeSession *session)
void(^ LogCallback)(Log *log)
void(^ StatisticsCallback)(Statistics *statistics)
void fail:(NSException *exception)
NSArray * getAllLogsWithTimeout:(int waitTimeout)
void complete:(ReturnCode *returnCode)
void asyncFFmpegExecute:onDispatchQueue:(FFmpegSession *ffmpegSession,[onDispatchQueue] dispatch_queue_t queue)
NSArray * getFFmpegSessions()
FFmpegSessionCompleteCallback getFFmpegSessionCompleteCallback()
LogRedirectionStrategy getLogRedirectionStrategy()
void getMediaInformationExecute:withTimeout:(MediaInformationSession *mediaInformationSession,[withTimeout] int waitTimeout)
void disableRedirection()
NSString * registerNewFFmpegPipe()
FFprobeSessionCompleteCallback getFFprobeSessionCompleteCallback()
MediaInformationSessionCompleteCallback getMediaInformationSessionCompleteCallback()
int setFontconfigConfigurationPath:(NSString *path)
NSString * getBuildDate()
void ffprobeExecute:(FFprobeSession *ffprobeSession)
NSArray * getFFprobeSessions()
NSArray * getMediaInformationSessions()
void ffmpegExecute:(FFmpegSession *ffmpegSession)
int getSessionHistorySize()
id< Session > getSession:(long sessionId)
int setEnvironmentVariable:value:(NSString *variableName,[value] NSString *variableValue)
id< Session > getLastSession()
void asyncFFprobeExecute:onDispatchQueue:(FFprobeSession *ffprobeSession,[onDispatchQueue] dispatch_queue_t queue)
NSString * getFFmpegVersion()
void asyncGetMediaInformationExecute:onDispatchQueue:withTimeout:(MediaInformationSession *mediaInformationSession,[onDispatchQueue] dispatch_queue_t queue,[withTimeout] int waitTimeout)
void setFontDirectoryList:with:(NSArray *fontDirectoryList,[with] NSDictionary *fontNameMapping)
void closeFFmpegPipe:(NSString *ffmpegPipePath)
id< Session > getLastCompletedSession()
StatisticsCallback getStatisticsCallback()
void addStatistics:(Statistics *statistics)
FFmpegSessionCompleteCallback getCompleteCallback()
FFprobeSessionCompleteCallback getCompleteCallback()