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- (double)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 NSString* message = [NSString stringWithCString:logMessage->str encoding:NSUTF8StringEncoding];
491 if (message == nil) {
495 Log* log = [[
Log alloc] init:sessionId:levelValue:message];
496 BOOL globalCallbackDefined =
false;
497 BOOL sessionCallbackDefined =
false;
501 if ((activeLogLevel == LevelAVLogQuiet && levelValue != LevelAVLogStdErr) || (levelValue > activeLogLevel)) {
507 if (session != nil) {
508 activeLogRedirectionStrategy = [session getLogRedirectionStrategy];
509 [session addLog:log];
511 LogCallback sessionLogCallback = [session getLogCallback];
512 if (sessionLogCallback != nil) {
513 sessionCallbackDefined = TRUE;
517 sessionLogCallback(log);
519 @catch(NSException* exception) {
520 NSLog(
@"Exception thrown inside session log callback. %@", [exception callStackSymbols]);
526 if (globalLogCallback != nil) {
527 globalCallbackDefined = TRUE;
531 globalLogCallback(log);
533 @catch(NSException* exception) {
534 NSLog(
@"Exception thrown inside global log callback. %@", [exception callStackSymbols]);
539 switch (activeLogRedirectionStrategy) {
540 case LogRedirectionStrategyNeverPrintLogs: {
543 case LogRedirectionStrategyPrintLogsWhenGlobalCallbackNotDefined: {
544 if (globalCallbackDefined) {
549 case LogRedirectionStrategyPrintLogsWhenSessionCallbackNotDefined: {
550 if (sessionCallbackDefined) {
555 case LogRedirectionStrategyPrintLogsWhenNoCallbacksDefined: {
556 if (globalCallbackDefined || sessionCallbackDefined) {
561 case LogRedirectionStrategyAlwaysPrintLogs: {
567 switch (levelValue) {
568 case LevelAVLogQuiet:
573 NSLog(
@"%@: %@", [
FFmpegKitConfig logLevelToString:levelValue], [NSString stringWithCString:logMessage->str encoding:NSUTF8StringEncoding]);
578void process_statistics(
long sessionId,
int videoFrameNumber,
float videoFps,
float videoQuality,
long size,
double time,
double bitrate,
double speed) {
580 Statistics *statistics = [[
Statistics alloc] init:sessionId videoFrameNumber:videoFrameNumber videoFps:videoFps videoQuality:videoQuality size:size time:time bitrate:bitrate speed:speed];
583 if (session != nil && [session isFFmpeg]) {
588 if (sessionStatisticsCallback != nil) {
590 sessionStatisticsCallback(statistics);
592 @catch(NSException* exception) {
593 NSLog(
@"Exception thrown inside session statistics callback. %@", [exception callStackSymbols]);
599 if (globalStatisticsCallback != nil) {
601 globalStatisticsCallback(statistics);
603 @catch(NSException* exception) {
604 NSLog(
@"Exception thrown inside global statistics callback. %@", [exception callStackSymbols]);
613 int activeLogLevel = av_log_get_level();
614 if ((activeLogLevel != LevelAVLogQuiet) && (LevelAVLogDebug <= activeLogLevel)) {
615 NSLog(
@"Async callback block started.\n");
623 if (callbackData != nil) {
625 if ([callbackData getType] == LogType) {
626 process_log([callbackData getSessionId], [callbackData getLogLevel], [callbackData getLogData]);
627 av_bprint_finalize([callbackData getLogData], NULL);
630 [callbackData getStatisticsFrameNumber],
631 [callbackData getStatisticsFps],
632 [callbackData getStatisticsQuality],
633 [callbackData getStatisticsSize],
634 [callbackData getStatisticsTime],
635 [callbackData getStatisticsBitrate],
636 [callbackData getStatisticsSpeed]);
645 }
@catch(NSException *exception) {
646 activeLogLevel = av_log_get_level();
647 if ((activeLogLevel != LevelAVLogQuiet) && (LevelAVLogWarning <= activeLogLevel)) {
648 NSLog(
@"Async callback block received error: %@n\n", exception);
649 NSLog(
@"%@", [exception callStackSymbols]);
655 activeLogLevel = av_log_get_level();
656 if ((activeLogLevel != LevelAVLogQuiet) && (LevelAVLogDebug <= activeLogLevel)) {
657 NSLog(
@"Async callback block stopped.\n");
662 NSString*
const LIB_NAME =
@"ffmpeg";
667 char **commandCharPArray = (
char **)av_malloc(
sizeof(
char*) * ([arguments count] + 1));
673 commandCharPArray[0] = (
char *)av_malloc(
sizeof(
char) * ([LIB_NAME length] + 1));
674 strcpy(commandCharPArray[0], [LIB_NAME UTF8String]);
677 for (
int i=0; i < [arguments count]; i++) {
678 NSString *argument = [arguments objectAtIndex:i];
679 commandCharPArray[i + 1] = (
char *) [argument UTF8String];
689 int returnCode =
ffmpeg_execute(([arguments count] + 1), commandCharPArray);
695 av_free(commandCharPArray[0]);
696 av_free(commandCharPArray);
702 NSString*
const LIB_NAME =
@"ffprobe";
707 char **commandCharPArray = (
char **)av_malloc(
sizeof(
char*) * ([arguments count] + 1));
713 commandCharPArray[0] = (
char *)av_malloc(
sizeof(
char) * ([LIB_NAME length] + 1));
714 strcpy(commandCharPArray[0], [LIB_NAME UTF8String]);
717 for (
int i=0; i < [arguments count]; i++) {
718 NSString *argument = [arguments objectAtIndex:i];
719 commandCharPArray[i + 1] = (
char *) [argument UTF8String];
729 int returnCode =
ffprobe_execute(([arguments count] + 1), commandCharPArray);
735 av_free(commandCharPArray[0]);
736 av_free(commandCharPArray);
771 lock = [[NSRecursiveLock alloc] init];
772 semaphore = dispatch_semaphore_create(0);
789 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
808 av_log_set_callback(av_log_default_callback);
814+ (
int)setFontconfigConfigurationPath:(NSString*)path {
818+ (void)setFontDirectory:(NSString*)fontDirectoryPath with:(NSDictionary*)fontNameMapping {
822+ (void)setFontDirectoryList:(NSArray*)fontDirectoryArray with:(NSDictionary*)fontNameMapping {
823 NSError *error = nil;
824 BOOL isDirectory = YES;
826 int validFontNameMappingCount = 0;
827 NSString *tempConfigurationDirectory = [NSTemporaryDirectory() stringByAppendingPathComponent:@"fontconfig"];
828 NSString *fontConfigurationFile = [tempConfigurationDirectory stringByAppendingPathComponent:@"fonts.conf"];
830 if (![[NSFileManager defaultManager] fileExistsAtPath:tempConfigurationDirectory isDirectory:&isDirectory]) {
831 if (![[NSFileManager defaultManager] createDirectoryAtPath:tempConfigurationDirectory withIntermediateDirectories:YES attributes:nil error:&error]) {
832 NSLog(
@"Failed to set font directory. Error received while creating temp conf directory: %@.", error);
835 NSLog(
@"Created temporary font conf directory: TRUE.");
838 if ([[NSFileManager defaultManager] fileExistsAtPath:fontConfigurationFile isDirectory:&isFile]) {
839 BOOL fontConfigurationDeleted = [[NSFileManager defaultManager] removeItemAtPath:fontConfigurationFile error:nil];
840 NSLog(
@"Deleted old temporary font configuration: %s.", fontConfigurationDeleted?
"TRUE":
"FALSE");
844 NSString *fontNameMappingBlock =
@"";
845 for (NSString *fontName in [fontNameMapping allKeys]) {
846 NSString *mappedFontName = [fontNameMapping objectForKey:fontName];
848 if ((fontName != nil) && (mappedFontName != nil) && ([fontName length] > 0) && ([mappedFontName length] > 0)) {
850 fontNameMappingBlock = [NSString stringWithFormat:@"%@\n%@\n%@%@%@\n%@\n%@\n%@%@%@\n%@\n%@\n",
851 @" <match target=\"pattern\">",
852 @" <test qual=\"any\" name=\"family\">",
853 @" <string>", fontName, @"</string>",
855 @" <edit name=\"family\" mode=\"assign\" binding=\"same\">",
856 @" <string>", mappedFontName, @"</string>",
860 validFontNameMappingCount++;
864 NSMutableString *fontConfiguration = [NSMutableString stringWithFormat:@"%@\n%@\n%@\n%@\n",
865 @"<?xml version=\"1.0\"?>",
866 @"<!DOCTYPE fontconfig SYSTEM \"fonts.dtd\">",
868 @" <dir prefix=\"cwd\">.</dir>"];
869 for (
int i=0; i < [fontDirectoryArray count]; i++) {
870 NSString *fontDirectoryPath = [fontDirectoryArray objectAtIndex:i];
871 [fontConfiguration appendString: @" <dir>"];
872 [fontConfiguration appendString: fontDirectoryPath];
873 [fontConfiguration appendString: @"</dir>\n"];
875 [fontConfiguration appendString:fontNameMappingBlock];
876 [fontConfiguration appendString:@"</fontconfig>\n"];
878 if (![fontConfiguration writeToFile:fontConfigurationFile atomically:YES encoding:NSUTF8StringEncoding error:&error]) {
879 NSLog(
@"Failed to set font directory. Error received while saving font configuration: %@.", error);
883 NSLog(
@"Saved new temporary font configuration with %d font name mappings.", validFontNameMappingCount);
887 for (
int i=0; i < [fontDirectoryArray count]; i++) {
888 NSString *fontDirectoryPath = [fontDirectoryArray objectAtIndex:i];
889 NSLog(
@"Font directory %@ registered successfully.", fontDirectoryPath);
894 NSError *error = nil;
898 NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
899 NSString *pipesDir = [cacheDir stringByAppendingPathComponent:@"pipes"];
901 if (![[NSFileManager defaultManager] fileExistsAtPath:pipesDir isDirectory:&isDirectory]) {
902 if (![[NSFileManager defaultManager] createDirectoryAtPath:pipesDir withIntermediateDirectories:YES attributes:nil error:&error]) {
903 NSLog(
@"Failed to create pipes directory: %@. Operation failed with %@.", pipesDir, error);
908 NSString *newFFmpegPipePath = [NSString stringWithFormat:@"%@/%@%ld", pipesDir, FFmpegKitNamedPipePrefix, [pipeIndexGenerator
getAndIncrement]];
913 int rc = mkfifo([newFFmpegPipePath UTF8String], S_IRWXU | S_IRWXG | S_IROTH);
915 return newFFmpegPipePath;
917 NSLog(
@"Failed to register new FFmpeg pipe %@. Operation failed with rc=%d.", newFFmpegPipePath, rc);
922+ (void)closeFFmpegPipe:(NSString*)ffmpegPipePath {
923 NSFileManager *fileManager = [NSFileManager defaultManager];
925 if ([fileManager fileExistsAtPath:ffmpegPipePath]){
926 [fileManager removeItemAtPath:ffmpegPipePath error:nil];
931 return [NSString stringWithUTF8String:FFMPEG_VERSION];
936 return [NSString stringWithFormat:@"%@-lts", FFmpegKitVersion];
943 #if defined(FFMPEG_KIT_LTS)
952 sprintf(buildDate,
"%d", FFMPEG_KIT_BUILD_DATE);
953 return [NSString stringWithUTF8String:buildDate];
956+ (
int)setEnvironmentVariable:(NSString*)variableName value:(NSString*)variableValue {
957 return setenv([variableName UTF8String], [variableValue UTF8String],
true);
960+ (void)ignoreSignal:(Signal)signal {
961 if (signal == SignalQuit) {
963 }
else if (signal == SignalInt) {
965 }
else if (signal == SignalTerm) {
967 }
else if (signal == SignalXcpu) {
969 }
else if (signal == SignalPipe) {
978 int returnCode =
executeFFmpeg([ffmpegSession getSessionId], [ffmpegSession getArguments]);
980 }
@catch (NSException *exception) {
981 [ffmpegSession
fail:exception];
982 NSLog(
@"FFmpeg execute failed: %@.%@", [
FFmpegKitConfig argumentsToString:[ffmpegSession getArguments]], [NSString stringWithFormat:
@"%@", [exception callStackSymbols]]);
990 int returnCode =
executeFFprobe([ffprobeSession getSessionId], [ffprobeSession getArguments]);
992 }
@catch (NSException *exception) {
993 [ffprobeSession
fail:exception];
994 NSLog(
@"FFprobe execute failed: %@.%@", [
FFmpegKitConfig argumentsToString:[ffprobeSession getArguments]], [NSString stringWithFormat:
@"%@", [exception callStackSymbols]]);
998+ (void)getMediaInformationExecute:(
MediaInformationSession*)mediaInformationSession withTimeout:(
int)waitTimeout {
1002 int returnCodeValue =
executeFFprobe([mediaInformationSession getSessionId], [mediaInformationSession getArguments]);
1004 [mediaInformationSession
complete:returnCode];
1005 if ([returnCode isValueSuccess]) {
1007 NSMutableString* ffprobeJsonOutput = [[NSMutableString alloc] init];
1008 for (
int i=0; i < [allLogs count]; i++) {
1009 Log* log = [allLogs objectAtIndex:i];
1010 if ([log getLevel] == LevelAVLogStdErr) {
1011 [ffprobeJsonOutput appendString:[log
getMessage]];
1017 }
@catch (NSException *exception) {
1018 [mediaInformationSession
fail:exception];
1019 NSLog(
@"Get media information execute failed: %@.%@", [
FFmpegKitConfig argumentsToString:[mediaInformationSession getArguments]], [NSString stringWithFormat:
@"\n%@\n%@", [exception userInfo], [exception callStackSymbols]]);
1027+ (void)asyncFFmpegExecute:(
FFmpegSession*)ffmpegSession onDispatchQueue:(dispatch_queue_t)queue {
1028 dispatch_async(queue, ^{
1032 if (completeCallback != nil) {
1035 completeCallback(ffmpegSession);
1037 @catch(NSException* exception) {
1038 NSLog(
@"Exception thrown inside session complete callback. %@", [exception callStackSymbols]);
1043 if (globalFFmpegSessionCompleteCallback != nil) {
1046 globalFFmpegSessionCompleteCallback(ffmpegSession);
1048 @catch(NSException* exception) {
1049 NSLog(
@"Exception thrown inside global complete callback. %@", [exception callStackSymbols]);
1059+ (void)asyncFFprobeExecute:(
FFprobeSession*)ffprobeSession onDispatchQueue:(dispatch_queue_t)queue {
1060 dispatch_async(queue, ^{
1064 if (completeCallback != nil) {
1067 completeCallback(ffprobeSession);
1069 @catch(NSException* exception) {
1070 NSLog(
@"Exception thrown inside session complete callback. %@", [exception callStackSymbols]);
1075 if (globalFFprobeSessionCompleteCallback != nil) {
1078 globalFFprobeSessionCompleteCallback(ffprobeSession);
1080 @catch(NSException* exception) {
1081 NSLog(
@"Exception thrown inside global complete callback. %@", [exception callStackSymbols]);
1087+ (void)asyncGetMediaInformationExecute:(
MediaInformationSession*)mediaInformationSession withTimeout:(
int)waitTimeout {
1091+ (void)asyncGetMediaInformationExecute:(
MediaInformationSession*)mediaInformationSession onDispatchQueue:(dispatch_queue_t)queue withTimeout:(
int)waitTimeout {
1092 dispatch_async(queue, ^{
1096 if (completeCallback != nil) {
1099 completeCallback(mediaInformationSession);
1101 @catch(NSException* exception) {
1102 NSLog(
@"Exception thrown inside session complete callback. %@", [exception callStackSymbols]);
1107 if (globalMediaInformationSessionCompleteCallback != nil) {
1110 globalMediaInformationSessionCompleteCallback(mediaInformationSession);
1112 @catch(NSException* exception) {
1113 NSLog(
@"Exception thrown inside global complete callback. %@", [exception callStackSymbols]);
1155+ (void)setLogLevel:(
int)level {
1159+ (NSString*)logLevelToString:(
int)level {
1161 case LevelAVLogStdErr:
return @"STDERR";
1162 case LevelAVLogTrace:
return @"TRACE";
1163 case LevelAVLogDebug:
return @"DEBUG";
1164 case LevelAVLogVerbose:
return @"VERBOSE";
1165 case LevelAVLogInfo:
return @"INFO";
1166 case LevelAVLogWarning:
return @"WARNING";
1167 case LevelAVLogError:
return @"ERROR";
1168 case LevelAVLogFatal:
return @"FATAL";
1169 case LevelAVLogPanic:
return @"PANIC";
1170 case LevelAVLogQuiet:
return @"QUIET";
1171 default:
return @"";
1179+ (void)setSessionHistorySize:(
int)pSessionHistorySize {
1185 @throw([NSException exceptionWithName:NSInvalidArgumentException reason:@"Session history size must not exceed the hard limit!" userInfo:nil]);
1186 }
else if (pSessionHistorySize > 0) {
1192+ (id<Session>)getSession:(
long)sessionId {
1193 [sessionHistoryLock lock];
1195 id<Session> session = [sessionHistoryMap objectForKey:[NSNumber numberWithLong:sessionId]];
1197 [sessionHistoryLock unlock];
1203 [sessionHistoryLock lock];
1205 id<Session> lastSession = [sessionHistoryList lastObject];
1207 [sessionHistoryLock unlock];
1213 id<Session> lastCompletedSession = nil;
1215 [sessionHistoryLock lock];
1218 id<Session> session = [sessionHistoryList objectAtIndex:i];
1219 if ([session getState] == SessionStateCompleted) {
1220 lastCompletedSession = session;
1225 [sessionHistoryLock unlock];
1227 return lastCompletedSession;
1231 [sessionHistoryLock lock];
1233 NSArray* sessionsCopy = [sessionHistoryList copy];
1235 [sessionHistoryLock unlock];
1237 return sessionsCopy;
1241 [sessionHistoryLock lock];
1243 [sessionHistoryList removeAllObjects];
1244 [sessionHistoryMap removeAllObjects];
1246 [sessionHistoryLock unlock];
1250 NSMutableArray* ffmpegSessions = [[NSMutableArray alloc] init];
1252 [sessionHistoryLock lock];
1254 for(
int i = 0; i < [sessionHistoryList count]; i++) {
1255 id<Session> session = [sessionHistoryList objectAtIndex:i];
1256 if ([session isFFmpeg]) {
1257 [ffmpegSessions addObject:session];
1261 [sessionHistoryLock unlock];
1263 return ffmpegSessions;
1267 NSMutableArray* ffprobeSessions = [[NSMutableArray alloc] init];
1269 [sessionHistoryLock lock];
1271 for(
int i = 0; i < [sessionHistoryList count]; i++) {
1272 id<Session> session = [sessionHistoryList objectAtIndex:i];
1273 if ([session isFFprobe]) {
1274 [ffprobeSessions addObject:session];
1278 [sessionHistoryLock unlock];
1280 return ffprobeSessions;
1284 NSMutableArray* mediaInformationSessions = [[NSMutableArray alloc] init];
1286 [sessionHistoryLock lock];
1288 for(
int i = 0; i < [sessionHistoryList count]; i++) {
1289 id<Session> session = [sessionHistoryList objectAtIndex:i];
1290 if ([session isMediaInformation]) {
1291 [mediaInformationSessions addObject:session];
1295 [sessionHistoryLock unlock];
1297 return mediaInformationSessions;
1300+ (NSArray*)getSessionsByState:(SessionState)state {
1301 NSMutableArray* sessions = [[NSMutableArray alloc] init];
1303 [sessionHistoryLock lock];
1305 for(
int i = 0; i < [sessionHistoryList count]; i++) {
1306 id<Session> session = [sessionHistoryList objectAtIndex:i];
1307 if ([session getState] == state) {
1308 [sessions addObject:session];
1312 [sessionHistoryLock unlock];
1321+ (void)setLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy {
1325+ (
int)messagesInTransmit:(
long)sessionId {
1329+ (NSString*)sessionStateToString:(SessionState)state {
1331 case SessionStateCreated:
return @"CREATED";
1332 case SessionStateRunning:
return @"RUNNING";
1333 case SessionStateFailed:
return @"FAILED";
1334 case SessionStateCompleted:
return @"COMPLETED";
1335 default:
return @"";
1339+ (NSArray*)parseArguments:(NSString*)command {
1340 NSMutableArray *argumentArray = [[NSMutableArray alloc] init];
1341 NSMutableString *currentArgument = [[NSMutableString alloc] init];
1343 bool singleQuoteStarted =
false;
1344 bool doubleQuoteStarted =
false;
1346 for (
int i = 0; i < command.length; i++) {
1347 unichar previousChar;
1349 previousChar = [command characterAtIndex:(i - 1)];
1353 unichar currentChar = [command characterAtIndex:i];
1355 if (currentChar ==
' ') {
1356 if (singleQuoteStarted || doubleQuoteStarted) {
1357 [currentArgument appendFormat: @"%C", currentChar];
1358 }
else if ([currentArgument length] > 0) {
1359 [argumentArray addObject: currentArgument];
1360 currentArgument = [[NSMutableString alloc] init];
1362 }
else if (currentChar ==
'\'' && (previousChar == 0 || previousChar !=
'\\')) {
1363 if (singleQuoteStarted) {
1364 singleQuoteStarted =
false;
1365 }
else if (doubleQuoteStarted) {
1366 [currentArgument appendFormat: @"%C", currentChar];
1368 singleQuoteStarted =
true;
1370 }
else if (currentChar ==
'\"' && (previousChar == 0 || previousChar !=
'\\')) {
1371 if (doubleQuoteStarted) {
1372 doubleQuoteStarted =
false;
1373 }
else if (singleQuoteStarted) {
1374 [currentArgument appendFormat: @"%C", currentChar];
1376 doubleQuoteStarted =
true;
1379 [currentArgument appendFormat: @"%C", currentChar];
1383 if ([currentArgument length] > 0) {
1384 [argumentArray addObject: currentArgument];
1387 return argumentArray;
1390+ (NSString*)argumentsToString:(NSArray*)arguments {
1391 if (arguments == nil) {
1395 NSMutableString *
string = [NSMutableString stringWithString:@""];
1396 for (
int i=0; i < [arguments count]; i++) {
1397 NSString *argument = [arguments objectAtIndex:i];
1399 [string appendString:@" "];
1401 [string appendString:argument];
NSString *const FFmpegKitVersion
int executeFFprobe(long sessionId, NSArray *arguments)
void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, double time, double bitrate, double speed)
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
void ffmpegkit_statistics_callback_function(int frameNumber, float fps, float quality, int64_t size, double time, double bitrate, double speed)
static const char * avutil_log_get_level_str(int level)
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)
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
int cancelRequested(long sessionId)
volatile int handleSIGPIPE
void process_statistics(long sessionId, int videoFrameNumber, float videoFps, float videoQuality, long size, double time, double bitrate, double speed)
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()