FFmpegKit iOS / macOS / tvOS API 5.1
FFmpegKitConfig.m
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018-2022 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#import <stdatomic.h>
21#import <sys/types.h>
22#import <sys/stat.h>
23#import "libavutil/ffversion.h"
24#import "libavutil/bprint.h"
25#import "fftools_ffmpeg.h"
26#import "ArchDetect.h"
27#import "AtomicLong.h"
28#import "FFmpegKit.h"
29#import "FFmpegKitConfig.h"
30#import "FFmpegSession.h"
31#import "FFprobeKit.h"
32#import "FFprobeSession.h"
33#import "Level.h"
36#import "SessionState.h"
37
39NSString* const FFmpegKitVersion = @"5.1";
40
44NSString* const FFmpegKitNamedPipePrefix = @"fk_pipe_";
45
50
51/* Session history variables */
53static volatile NSMutableDictionary* sessionHistoryMap;
54static NSMutableArray* sessionHistoryList;
55static NSRecursiveLock* sessionHistoryLock;
56
58#define SESSION_MAP_SIZE 1000
59static atomic_short sessionMap[SESSION_MAP_SIZE];
60static atomic_int sessionInTransitMessageCountMap[SESSION_MAP_SIZE];
61
62static dispatch_queue_t asyncDispatchQueue;
63
66
69
74
75static LogRedirectionStrategy globalLogRedirectionStrategy;
76
79static NSRecursiveLock *lock;
80static dispatch_semaphore_t semaphore;
81static NSMutableArray *callbackDataArray;
82
84volatile int handleSIGQUIT = 1;
85volatile int handleSIGINT = 1;
86volatile int handleSIGTERM = 1;
87volatile int handleSIGXCPU = 1;
88volatile int handleSIGPIPE = 1;
89
91__thread long globalSessionId = 0;
92
94int configuredLogLevel = LevelAVLogInfo;
95
97int ffmpeg_execute(int argc, char **argv);
98
100int ffprobe_execute(int argc, char **argv);
101
102typedef NS_ENUM(NSUInteger, CallbackType) {
103 LogType,
104 StatisticsType
105};
106
108 while ([sessionHistoryList count] > sessionHistorySize) {
109 id<Session> first = [sessionHistoryList firstObject];
110 if (first != nil) {
111 [sessionHistoryList removeObjectAtIndex:0];
112 [sessionHistoryMap removeObjectForKey:[NSNumber numberWithLong:[first getSessionId]]];
113 }
114 }
115}
116
117void addSessionToSessionHistory(id<Session> session) {
118 NSNumber* sessionIdNumber = [NSNumber numberWithLong:[session getSessionId]];
119
120 [sessionHistoryLock lock];
121
122 /*
123 * ASYNC SESSIONS CALL THIS METHOD TWICE
124 * THIS CHECK PREVENTS ADDING THE SAME SESSION AGAIN
125 */
126 if ([sessionHistoryMap objectForKey:sessionIdNumber] == nil) {
127 [sessionHistoryMap setObject:session forKey:sessionIdNumber];
128 [sessionHistoryList addObject:session];
130 }
131
132 [sessionHistoryLock unlock];
133}
134
138@interface CallbackData : NSObject
139
140@end
141
142@implementation CallbackData {
143 CallbackType _type;
144 long _sessionId; // session id
145
146 int _logLevel; // log level
147 AVBPrint _logData; // log data
148
149 int _statisticsFrameNumber; // statistics frame number
150 float _statisticsFps; // statistics fps
151 float _statisticsQuality; // statistics quality
152 int64_t _statisticsSize; // statistics size
153 int _statisticsTime; // statistics time
154 double _statisticsBitrate; // statistics bitrate
155 double _statisticsSpeed; // statistics speed
156}
157
158 - (instancetype)init:(long)sessionId logLevel:(int)logLevel data:(AVBPrint*)data {
159 self = [super init];
160 if (self) {
161 _type = LogType;
162 _sessionId = sessionId;
163 _logLevel = logLevel;
164 av_bprint_init(&_logData, 0, AV_BPRINT_SIZE_UNLIMITED);
165 av_bprintf(&_logData, "%s", data->str);
166 }
167
168 return self;
169}
170
171 - (instancetype)init:(long)sessionId
172 videoFrameNumber:(int)videoFrameNumber
173 fps:(float)videoFps
174 quality:(float)videoQuality
175 size:(int64_t)size
176 time:(int)time
177 bitrate:(double)bitrate
178 speed:(double)speed {
179 self = [super init];
180 if (self) {
181 _type = StatisticsType;
182 _sessionId = sessionId;
183 _statisticsFrameNumber = videoFrameNumber;
184 _statisticsFps = videoFps;
185 _statisticsQuality = videoQuality;
186 _statisticsSize = size;
187 _statisticsTime = time;
188 _statisticsBitrate = bitrate;
189 _statisticsSpeed = speed;
190 }
191
192 return self;
193}
194
195- (CallbackType)getType {
196 return _type;
197}
198
199- (long)getSessionId {
200 return _sessionId;
201}
202
203- (int)getLogLevel {
204 return _logLevel;
205}
206
207- (AVBPrint*)getLogData {
208 return &_logData;
209}
210
211- (int)getStatisticsFrameNumber {
213}
214
215- (float)getStatisticsFps {
216 return _statisticsFps;
217}
218
219- (float)getStatisticsQuality {
220 return _statisticsQuality;
221}
222
223- (int64_t)getStatisticsSize {
224 return _statisticsSize;
225}
226
227- (int)getStatisticsTime {
228 return _statisticsTime;
229}
230
231- (double)getStatisticsBitrate {
232 return _statisticsBitrate;
233}
234
235- (double)getStatisticsSpeed {
236 return _statisticsSpeed;
237}
238
239@end
240
246void callbackWait(int milliSeconds) {
247 dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(milliSeconds * NSEC_PER_MSEC)));
248}
249
254 dispatch_semaphore_signal(semaphore);
255}
256
257static const char *avutil_log_get_level_str(int level) {
258 switch (level) {
259 case AV_LOG_STDERR:
260 return "stderr";
261 case AV_LOG_QUIET:
262 return "quiet";
263 case AV_LOG_DEBUG:
264 return "debug";
265 case AV_LOG_VERBOSE:
266 return "verbose";
267 case AV_LOG_INFO:
268 return "info";
269 case AV_LOG_WARNING:
270 return "warning";
271 case AV_LOG_ERROR:
272 return "error";
273 case AV_LOG_FATAL:
274 return "fatal";
275 case AV_LOG_PANIC:
276 return "panic";
277 default:
278 return "";
279 }
280}
281
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);
289
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);
297 }
298 }
299 av_bprintf(part+1, "[%s @ %p] ",
300 avc->item_name(avcl), avcl);
301 }
302
303 if (*print_prefix && (level > AV_LOG_QUIET) && (flags & AV_LOG_PRINT_LEVEL))
304 av_bprintf(part+2, "[%s] ", avutil_log_get_level_str(level));
305
306 av_vbprintf(part+3, fmt, vl);
307
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';
311 }
312}
313
314static void avutil_log_sanitize(uint8_t *line) {
315 while(*line){
316 if(*line < 0x08 || (*line > 0x0D && *line < 0x20))
317 *line='?';
318 line++;
319 }
320}
321
328void logCallbackDataAdd(int level, AVBPrint *data) {
329 CallbackData* callbackData = [[CallbackData alloc] init:globalSessionId logLevel:level data:data];
330
331 [lock lock];
332 [callbackDataArray addObject:callbackData];
333 [lock unlock];
334
336
338}
339
343void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed) {
344 CallbackData *callbackData = [[CallbackData alloc] init:globalSessionId videoFrameNumber:frameNumber fps:fps quality:quality size:size time:time bitrate:bitrate speed:speed];
345
346 [lock lock];
347 [callbackDataArray addObject:callbackData];
348 [lock unlock];
349
351
353}
354
359 CallbackData *newData = nil;
360
361 [lock lock];
362
363 @try {
364 if ([callbackDataArray count] > 0) {
365 newData = [callbackDataArray objectAtIndex:0];
366 [callbackDataArray removeObjectAtIndex:0];
367 }
368 } @catch(NSException *exception) {
369 // DO NOTHING
370 } @finally {
371 [lock unlock];
372 }
373
374 return newData;
375}
376
382void registerSessionId(long sessionId) {
383 atomic_store(&sessionMap[sessionId % SESSION_MAP_SIZE], 1);
384}
385
391void removeSession(long sessionId) {
392 atomic_store(&sessionMap[sessionId % SESSION_MAP_SIZE], 0);
393}
394
400void cancelSession(long sessionId) {
401 atomic_store(&sessionMap[sessionId % SESSION_MAP_SIZE], 2);
402}
403
410int cancelRequested(long sessionId) {
411 if (atomic_load(&sessionMap[sessionId % SESSION_MAP_SIZE]) == 2) {
412 return 1;
413 } else {
414 return 0;
415 }
416}
417
423void resetMessagesInTransmit(long sessionId) {
424 atomic_store(&sessionInTransitMessageCountMap[sessionId % SESSION_MAP_SIZE], 0);
425}
426
435void ffmpegkit_log_callback_function(void *ptr, int level, const char* format, va_list vargs) {
436 AVBPrint fullLine;
437 AVBPrint part[4];
438 int print_prefix = 1;
439
440 // DO NOT PROCESS UNWANTED LOGS
441 if (level >= 0) {
442 level &= 0xff;
443 }
444 int activeLogLevel = av_log_get_level();
445
446 // LevelAVLogStdErr logs are always redirected
447 if ((activeLogLevel == LevelAVLogQuiet && level != LevelAVLogStdErr) || (level > activeLogLevel)) {
448 return;
449 }
450
451 av_bprint_init(&fullLine, 0, AV_BPRINT_SIZE_UNLIMITED);
452
453 avutil_log_format_line(ptr, level, format, vargs, part, &print_prefix);
454 avutil_log_sanitize(part[0].str);
455 avutil_log_sanitize(part[1].str);
456 avutil_log_sanitize(part[2].str);
457 avutil_log_sanitize(part[3].str);
458
459 // COMBINE ALL 4 LOG PARTS
460 av_bprintf(&fullLine, "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
461
462 if (fullLine.len > 0) {
463 logCallbackDataAdd(level, &fullLine);
464 }
465
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);
471}
472
484void ffmpegkit_statistics_callback_function(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed) {
485 statisticsCallbackDataAdd(frameNumber, fps, quality, size, time, bitrate, speed);
486}
487
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;
493 LogRedirectionStrategy activeLogRedirectionStrategy = globalLogRedirectionStrategy;
494
495 // LevelAVLogStdErr logs are always redirected
496 if ((activeLogLevel == LevelAVLogQuiet && levelValue != LevelAVLogStdErr) || (levelValue > activeLogLevel)) {
497 // LOG NEITHER PRINTED NOR FORWARDED
498 return;
499 }
500
501 id<Session> session = [FFmpegKitConfig getSession:sessionId];
502 if (session != nil) {
503 activeLogRedirectionStrategy = [session getLogRedirectionStrategy];
504 [session addLog:log];
505
506 LogCallback sessionLogCallback = [session getLogCallback];
507 if (sessionLogCallback != nil) {
508 sessionCallbackDefined = TRUE;
509
510 @try {
511 // NOTIFY SESSION CALLBACK DEFINED
512 sessionLogCallback(log);
513 }
514 @catch(NSException* exception) {
515 NSLog(@"Exception thrown inside session log callback. %@", [exception callStackSymbols]);
516 }
517 }
518 }
519
520 LogCallback globalLogCallback = logCallback;
521 if (globalLogCallback != nil) {
522 globalCallbackDefined = TRUE;
523
524 @try {
525 // NOTIFY GLOBAL CALLBACK DEFINED
526 globalLogCallback(log);
527 }
528 @catch(NSException* exception) {
529 NSLog(@"Exception thrown inside global log callback. %@", [exception callStackSymbols]);
530 }
531 }
532
533 // EXECUTE THE LOG STRATEGY
534 switch (activeLogRedirectionStrategy) {
535 case LogRedirectionStrategyNeverPrintLogs: {
536 return;
537 }
538 case LogRedirectionStrategyPrintLogsWhenGlobalCallbackNotDefined: {
539 if (globalCallbackDefined) {
540 return;
541 }
542 }
543 break;
544 case LogRedirectionStrategyPrintLogsWhenSessionCallbackNotDefined: {
545 if (sessionCallbackDefined) {
546 return;
547 }
548 }
549 break;
550 case LogRedirectionStrategyPrintLogsWhenNoCallbacksDefined: {
551 if (globalCallbackDefined || sessionCallbackDefined) {
552 return;
553 }
554 }
555 break;
556 case LogRedirectionStrategyAlwaysPrintLogs: {
557 }
558 break;
559 }
560
561 // PRINT LOGS
562 switch (levelValue) {
563 case LevelAVLogQuiet:
564 // PRINT NO OUTPUT
565 break;
566 default:
567 // WRITE TO NSLOG
568 NSLog(@"%@: %@", [FFmpegKitConfig logLevelToString:levelValue], [NSString stringWithCString:logMessage->str encoding:NSUTF8StringEncoding]);
569 break;
570 }
571}
572
573void process_statistics(long sessionId, int videoFrameNumber, float videoFps, float videoQuality, long size, int time, double bitrate, double speed) {
574
575 Statistics *statistics = [[Statistics alloc] init:sessionId videoFrameNumber:videoFrameNumber videoFps:videoFps videoQuality:videoQuality size:size time:time bitrate:bitrate speed:speed];
576
577 id<Session> session = [FFmpegKitConfig getSession:sessionId];
578 if (session != nil && [session isFFmpeg]) {
579 FFmpegSession *ffmpegSession = (FFmpegSession*)session;
580 [ffmpegSession addStatistics:statistics];
581
582 StatisticsCallback sessionStatisticsCallback = [ffmpegSession getStatisticsCallback];
583 if (sessionStatisticsCallback != nil) {
584 @try {
585 sessionStatisticsCallback(statistics);
586 }
587 @catch(NSException* exception) {
588 NSLog(@"Exception thrown inside session statistics callback. %@", [exception callStackSymbols]);
589 }
590 }
591 }
592
593 StatisticsCallback globalStatisticsCallback = statisticsCallback;
594 if (globalStatisticsCallback != nil) {
595 @try {
596 globalStatisticsCallback(statistics);
597 }
598 @catch(NSException* exception) {
599 NSLog(@"Exception thrown inside global statistics callback. %@", [exception callStackSymbols]);
600 }
601 }
602}
603
608 int activeLogLevel = av_log_get_level();
609 if ((activeLogLevel != LevelAVLogQuiet) && (LevelAVLogDebug <= activeLogLevel)) {
610 NSLog(@"Async callback block started.\n");
611 }
612
613 while(redirectionEnabled) {
614 @autoreleasepool {
615 @try {
616
617 CallbackData *callbackData = callbackDataRemove();
618 if (callbackData != nil) {
619
620 if ([callbackData getType] == LogType) {
621 process_log([callbackData getSessionId], [callbackData getLogLevel], [callbackData getLogData]);
622 av_bprint_finalize([callbackData getLogData], NULL);
623 } else {
624 process_statistics([callbackData getSessionId],
625 [callbackData getStatisticsFrameNumber],
626 [callbackData getStatisticsFps],
627 [callbackData getStatisticsQuality],
628 [callbackData getStatisticsSize],
629 [callbackData getStatisticsTime],
630 [callbackData getStatisticsBitrate],
631 [callbackData getStatisticsSpeed]);
632 }
633
634 atomic_fetch_sub(&sessionInTransitMessageCountMap[[callbackData getSessionId] % SESSION_MAP_SIZE], 1);
635
636 } else {
637 callbackWait(100);
638 }
639
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]);
645 }
646 }
647 }
648 }
649
650 activeLogLevel = av_log_get_level();
651 if ((activeLogLevel != LevelAVLogQuiet) && (LevelAVLogDebug <= activeLogLevel)) {
652 NSLog(@"Async callback block stopped.\n");
653 }
654}
655
656int executeFFmpeg(long sessionId, NSArray* arguments) {
657 NSString* const LIB_NAME = @"ffmpeg";
658
659 // SETS DEFAULT LOG LEVEL BEFORE STARTING A NEW RUN
660 av_log_set_level(configuredLogLevel);
661
662 char **commandCharPArray = (char **)av_malloc(sizeof(char*) * ([arguments count] + 1));
663
664 /* PRESERVE USAGE FORMAT
665 *
666 * ffmpeg <arguments>
667 */
668 commandCharPArray[0] = (char *)av_malloc(sizeof(char) * ([LIB_NAME length] + 1));
669 strcpy(commandCharPArray[0], [LIB_NAME UTF8String]);
670
671 // PREPARE ARRAY ELEMENTS
672 for (int i=0; i < [arguments count]; i++) {
673 NSString *argument = [arguments objectAtIndex:i];
674 commandCharPArray[i + 1] = (char *) [argument UTF8String];
675 }
676
677 // REGISTER THE ID BEFORE STARTING THE SESSION
678 globalSessionId = sessionId;
679 registerSessionId(sessionId);
680
681 resetMessagesInTransmit(sessionId);
682
683 // RUN
684 int returnCode = ffmpeg_execute(([arguments count] + 1), commandCharPArray);
685
686 // ALWAYS REMOVE THE ID FROM THE MAP
687 removeSession(sessionId);
688
689 // CLEANUP
690 av_free(commandCharPArray[0]);
691 av_free(commandCharPArray);
692
693 return returnCode;
694}
695
696int executeFFprobe(long sessionId, NSArray* arguments) {
697 NSString* const LIB_NAME = @"ffprobe";
698
699 // SETS DEFAULT LOG LEVEL BEFORE STARTING A NEW RUN
700 av_log_set_level(configuredLogLevel);
701
702 char **commandCharPArray = (char **)av_malloc(sizeof(char*) * ([arguments count] + 1));
703
704 /* PRESERVE USAGE FORMAT
705 *
706 * ffprobe <arguments>
707 */
708 commandCharPArray[0] = (char *)av_malloc(sizeof(char) * ([LIB_NAME length] + 1));
709 strcpy(commandCharPArray[0], [LIB_NAME UTF8String]);
710
711 // PREPARE ARRAY ELEMENTS
712 for (int i=0; i < [arguments count]; i++) {
713 NSString *argument = [arguments objectAtIndex:i];
714 commandCharPArray[i + 1] = (char *) [argument UTF8String];
715 }
716
717 // REGISTER THE ID BEFORE STARTING THE SESSION
718 globalSessionId = sessionId;
719 registerSessionId(sessionId);
720
721 resetMessagesInTransmit(sessionId);
722
723 // RUN
724 int returnCode = ffprobe_execute(([arguments count] + 1), commandCharPArray);
725
726 // ALWAYS REMOVE THE ID FROM THE MAP
727 removeSession(sessionId);
728
729 // CLEANUP
730 av_free(commandCharPArray[0]);
731 av_free(commandCharPArray);
732
733 return returnCode;
734}
735
736@implementation FFmpegKitConfig
737
738+ (void)initialize {
739 [ArchDetect class];
740 [FFmpegKit class];
741 [FFprobeKit class];
742
743 pipeIndexGenerator = [[AtomicLong alloc] initWithValue:1];
744
746 sessionHistoryMap = [[NSMutableDictionary alloc] init];
747 sessionHistoryList = [[NSMutableArray alloc] init];
748 sessionHistoryLock = [[NSRecursiveLock alloc] init];
749
750 for(int i = 0; i<SESSION_MAP_SIZE; i++) {
751 atomic_init(&sessionMap[i], 0);
752 atomic_init(&sessionInTransitMessageCountMap[i], 0);
753 }
754
755 asyncDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
756
757 logCallback = nil;
758 statisticsCallback = nil;
762
763 globalLogRedirectionStrategy = LogRedirectionStrategyPrintLogsWhenNoCallbacksDefined;
764
766 lock = [[NSRecursiveLock alloc] init];
767 semaphore = dispatch_semaphore_create(0);
768 callbackDataArray = [[NSMutableArray alloc] init];
769
771}
772
773+ (void)enableRedirection {
774 [lock lock];
775
776 if (redirectionEnabled != 0) {
777 [lock unlock];
778 return;
779 }
781
782 [lock unlock];
783
784 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
786 });
787
788 av_log_set_callback(ffmpegkit_log_callback_function);
790}
791
792+ (void)disableRedirection {
793 [lock lock];
794
795 if (redirectionEnabled != 1) {
796 [lock unlock];
797 return;
798 }
800
801 [lock unlock];
802
803 av_log_set_callback(av_log_default_callback);
805
807}
808
809+ (int)setFontconfigConfigurationPath:(NSString*)path {
810 return [FFmpegKitConfig setEnvironmentVariable:@"FONTCONFIG_PATH" value:path];
811}
812
813+ (void)setFontDirectory:(NSString*)fontDirectoryPath with:(NSDictionary*)fontNameMapping {
814 [FFmpegKitConfig setFontDirectoryList:[NSArray arrayWithObject:fontDirectoryPath] with:fontNameMapping];
815}
816
817+ (void)setFontDirectoryList:(NSArray*)fontDirectoryArray with:(NSDictionary*)fontNameMapping {
818 NSError *error = nil;
819 BOOL isDirectory = YES;
820 BOOL isFile = NO;
821 int validFontNameMappingCount = 0;
822 NSString *tempConfigurationDirectory = [NSTemporaryDirectory() stringByAppendingPathComponent:@"fontconfig"];
823 NSString *fontConfigurationFile = [tempConfigurationDirectory stringByAppendingPathComponent:@"fonts.conf"];
824
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);
828 return;
829 }
830 NSLog(@"Created temporary font conf directory: TRUE.");
831 }
832
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");
836 }
837
838 /* PROCESS MAPPINGS FIRST */
839 NSString *fontNameMappingBlock = @"";
840 for (NSString *fontName in [fontNameMapping allKeys]) {
841 NSString *mappedFontName = [fontNameMapping objectForKey:fontName];
842
843 if ((fontName != nil) && (mappedFontName != nil) && ([fontName length] > 0) && ([mappedFontName length] > 0)) {
844
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>",
849 @" </test>",
850 @" <edit name=\"family\" mode=\"assign\" binding=\"same\">",
851 @" <string>", mappedFontName, @"</string>",
852 @" </edit>",
853 @" </match>"];
854
855 validFontNameMappingCount++;
856 }
857 }
858
859 NSMutableString *fontConfiguration = [NSMutableString stringWithFormat:@"%@\n%@\n%@\n%@\n",
860 @"<?xml version=\"1.0\"?>",
861 @"<!DOCTYPE fontconfig SYSTEM \"fonts.dtd\">",
862 @"<fontconfig>",
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"];
869 }
870 [fontConfiguration appendString:fontNameMappingBlock];
871 [fontConfiguration appendString:@"</fontconfig>\n"];
872
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);
875 return;
876 }
877
878 NSLog(@"Saved new temporary font configuration with %d font name mappings.", validFontNameMappingCount);
879
880 [FFmpegKitConfig setFontconfigConfigurationPath:tempConfigurationDirectory];
881
882 for (int i=0; i < [fontDirectoryArray count]; i++) {
883 NSString *fontDirectoryPath = [fontDirectoryArray objectAtIndex:i];
884 NSLog(@"Font directory %@ registered successfully.", fontDirectoryPath);
885 }
886}
887
888+ (NSString*)registerNewFFmpegPipe {
889 NSError *error = nil;
890 BOOL isDirectory;
891
892 // PIPES ARE CREATED UNDER THE PIPES DIRECTORY
893 NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
894 NSString *pipesDir = [cacheDir stringByAppendingPathComponent:@"pipes"];
895
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);
899 return nil;
900 }
901 }
902
903 NSString *newFFmpegPipePath = [NSString stringWithFormat:@"%@/%@%ld", pipesDir, FFmpegKitNamedPipePrefix, [pipeIndexGenerator getAndIncrement]];
904
905 // FIRST CLOSE OLD PIPES WITH THE SAME NAME
906 [FFmpegKitConfig closeFFmpegPipe:newFFmpegPipePath];
907
908 int rc = mkfifo([newFFmpegPipePath UTF8String], S_IRWXU | S_IRWXG | S_IROTH);
909 if (rc == 0) {
910 return newFFmpegPipePath;
911 } else {
912 NSLog(@"Failed to register new FFmpeg pipe %@. Operation failed with rc=%d.", newFFmpegPipePath, rc);
913 return nil;
914 }
915}
916
917+ (void)closeFFmpegPipe:(NSString*)ffmpegPipePath {
918 NSFileManager *fileManager = [NSFileManager defaultManager];
919
920 if ([fileManager fileExistsAtPath:ffmpegPipePath]){
921 [fileManager removeItemAtPath:ffmpegPipePath error:nil];
922 }
923}
924
925+ (NSString*)getFFmpegVersion {
926 return [NSString stringWithUTF8String:FFMPEG_VERSION];
927}
928
929+ (NSString*)getVersion {
930 if ([FFmpegKitConfig isLTSBuild] == 1) {
931 return [NSString stringWithFormat:@"%@-lts", FFmpegKitVersion];
932 } else {
933 return FFmpegKitVersion;
934 }
935}
936
937+ (int)isLTSBuild {
938 #if defined(FFMPEG_KIT_LTS)
939 return 1;
940 #else
941 return 0;
942 #endif
943}
944
945+ (NSString*)getBuildDate {
946 char buildDate[10];
947 sprintf(buildDate, "%d", FFMPEG_KIT_BUILD_DATE);
948 return [NSString stringWithUTF8String:buildDate];
949}
950
951+ (int)setEnvironmentVariable:(NSString*)variableName value:(NSString*)variableValue {
952 return setenv([variableName UTF8String], [variableValue UTF8String], true);
953}
954
955+ (void)ignoreSignal:(Signal)signal {
956 if (signal == SignalQuit) {
957 handleSIGQUIT = 0;
958 } else if (signal == SignalInt) {
959 handleSIGINT = 0;
960 } else if (signal == SignalTerm) {
961 handleSIGTERM = 0;
962 } else if (signal == SignalXcpu) {
963 handleSIGXCPU = 0;
964 } else if (signal == SignalPipe) {
965 handleSIGPIPE = 0;
966 }
967}
968
969+ (void)ffmpegExecute:(FFmpegSession*)ffmpegSession {
970 [ffmpegSession startRunning];
971
972 @try {
973 int returnCode = executeFFmpeg([ffmpegSession getSessionId], [ffmpegSession getArguments]);
974 [ffmpegSession complete:[[ReturnCode alloc] init:returnCode]];
975 } @catch (NSException *exception) {
976 [ffmpegSession fail:exception];
977 NSLog(@"FFmpeg execute failed: %@.%@", [FFmpegKitConfig argumentsToString:[ffmpegSession getArguments]], [NSString stringWithFormat:@"%@", [exception callStackSymbols]]);
978 }
979}
980
981+ (void)ffprobeExecute:(FFprobeSession*)ffprobeSession {
982 [ffprobeSession startRunning];
983
984 @try {
985 int returnCode = executeFFprobe([ffprobeSession getSessionId], [ffprobeSession getArguments]);
986 [ffprobeSession complete:[[ReturnCode alloc] init:returnCode]];
987 } @catch (NSException *exception) {
988 [ffprobeSession fail:exception];
989 NSLog(@"FFprobe execute failed: %@.%@", [FFmpegKitConfig argumentsToString:[ffprobeSession getArguments]], [NSString stringWithFormat:@"%@", [exception callStackSymbols]]);
990 }
991}
992
993+ (void)getMediaInformationExecute:(MediaInformationSession*)mediaInformationSession withTimeout:(int)waitTimeout {
994 [mediaInformationSession startRunning];
995
996 @try {
997 int returnCodeValue = executeFFprobe([mediaInformationSession getSessionId], [mediaInformationSession getArguments]);
998 ReturnCode* returnCode = [[ReturnCode alloc] init:returnCodeValue];
999 [mediaInformationSession complete:returnCode];
1000 if ([returnCode isValueSuccess]) {
1001 NSArray* allLogs = [mediaInformationSession getAllLogsWithTimeout:waitTimeout];
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]];
1007 }
1008 }
1009 MediaInformation* mediaInformation = [MediaInformationJsonParser fromWithError:ffprobeJsonOutput];
1010 [mediaInformationSession setMediaInformation:mediaInformation];
1011 }
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]]);
1015 }
1016}
1017
1018+ (void)asyncFFmpegExecute:(FFmpegSession*)ffmpegSession {
1019 [FFmpegKitConfig asyncFFmpegExecute:ffmpegSession onDispatchQueue:asyncDispatchQueue];
1020}
1021
1022+ (void)asyncFFmpegExecute:(FFmpegSession*)ffmpegSession onDispatchQueue:(dispatch_queue_t)queue {
1023 dispatch_async(queue, ^{
1024 [FFmpegKitConfig ffmpegExecute:ffmpegSession];
1025
1026 FFmpegSessionCompleteCallback completeCallback = [ffmpegSession getCompleteCallback];
1027 if (completeCallback != nil) {
1028 @try {
1029 // NOTIFY SESSION CALLBACK DEFINED
1030 completeCallback(ffmpegSession);
1031 }
1032 @catch(NSException* exception) {
1033 NSLog(@"Exception thrown inside session complete callback. %@", [exception callStackSymbols]);
1034 }
1035 }
1036
1038 if (globalFFmpegSessionCompleteCallback != nil) {
1039 @try {
1040 // NOTIFY SESSION CALLBACK DEFINED
1041 globalFFmpegSessionCompleteCallback(ffmpegSession);
1042 }
1043 @catch(NSException* exception) {
1044 NSLog(@"Exception thrown inside global complete callback. %@", [exception callStackSymbols]);
1045 }
1046 }
1047 });
1048}
1049
1050+ (void)asyncFFprobeExecute:(FFprobeSession*)ffprobeSession {
1051 [FFmpegKitConfig asyncFFprobeExecute:ffprobeSession onDispatchQueue:asyncDispatchQueue];
1052}
1053
1054+ (void)asyncFFprobeExecute:(FFprobeSession*)ffprobeSession onDispatchQueue:(dispatch_queue_t)queue {
1055 dispatch_async(queue, ^{
1056 [FFmpegKitConfig ffprobeExecute:ffprobeSession];
1057
1058 FFprobeSessionCompleteCallback completeCallback = [ffprobeSession getCompleteCallback];
1059 if (completeCallback != nil) {
1060 @try {
1061 // NOTIFY SESSION CALLBACK DEFINED
1062 completeCallback(ffprobeSession);
1063 }
1064 @catch(NSException* exception) {
1065 NSLog(@"Exception thrown inside session complete callback. %@", [exception callStackSymbols]);
1066 }
1067 }
1068
1070 if (globalFFprobeSessionCompleteCallback != nil) {
1071 @try {
1072 // NOTIFY SESSION CALLBACK DEFINED
1073 globalFFprobeSessionCompleteCallback(ffprobeSession);
1074 }
1075 @catch(NSException* exception) {
1076 NSLog(@"Exception thrown inside global complete callback. %@", [exception callStackSymbols]);
1077 }
1078 }
1079 });
1080}
1081
1082+ (void)asyncGetMediaInformationExecute:(MediaInformationSession*)mediaInformationSession withTimeout:(int)waitTimeout {
1083 [FFmpegKitConfig asyncGetMediaInformationExecute:mediaInformationSession onDispatchQueue:asyncDispatchQueue withTimeout:waitTimeout];
1084}
1085
1086+ (void)asyncGetMediaInformationExecute:(MediaInformationSession*)mediaInformationSession onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout {
1087 dispatch_async(queue, ^{
1088 [FFmpegKitConfig getMediaInformationExecute:mediaInformationSession withTimeout:waitTimeout];
1089
1090 MediaInformationSessionCompleteCallback completeCallback = [mediaInformationSession getCompleteCallback];
1091 if (completeCallback != nil) {
1092 @try {
1093 // NOTIFY SESSION CALLBACK DEFINED
1094 completeCallback(mediaInformationSession);
1095 }
1096 @catch(NSException* exception) {
1097 NSLog(@"Exception thrown inside session complete callback. %@", [exception callStackSymbols]);
1098 }
1099 }
1100
1102 if (globalMediaInformationSessionCompleteCallback != nil) {
1103 @try {
1104 // NOTIFY SESSION CALLBACK DEFINED
1105 globalMediaInformationSessionCompleteCallback(mediaInformationSession);
1106 }
1107 @catch(NSException* exception) {
1108 NSLog(@"Exception thrown inside global complete callback. %@", [exception callStackSymbols]);
1109 }
1110 }
1111 });
1112}
1113
1114+ (void)enableLogCallback:(LogCallback)callback {
1115 logCallback = callback;
1116}
1117
1118+ (void)enableStatisticsCallback:(StatisticsCallback)callback {
1119 statisticsCallback = callback;
1120}
1121
1122+ (void)enableFFmpegSessionCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback {
1123 ffmpegSessionCompleteCallback = completeCallback;
1124}
1125
1128}
1129
1130+ (void)enableFFprobeSessionCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback {
1131 ffprobeSessionCompleteCallback = completeCallback;
1132}
1133
1136}
1137
1138+ (void)enableMediaInformationSessionCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback {
1139 mediaInformationSessionCompleteCallback = completeCallback;
1140}
1141
1144}
1145
1146+ (int)getLogLevel {
1147 return configuredLogLevel;
1148}
1149
1150+ (void)setLogLevel:(int)level {
1151 configuredLogLevel = level;
1152}
1153
1154+ (NSString*)logLevelToString:(int)level {
1155 switch (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 @"";
1167 }
1168}
1169
1171 return sessionHistorySize;
1172}
1173
1174+ (void)setSessionHistorySize:(int)pSessionHistorySize {
1175 if (pSessionHistorySize >= SESSION_MAP_SIZE) {
1176
1177 /*
1178 * THERE IS A HARD LIMIT ON THE NATIVE SIDE. HISTORY SIZE MUST BE SMALLER THAN SESSION_MAP_SIZE
1179 */
1180 @throw([NSException exceptionWithName:NSInvalidArgumentException reason:@"Session history size must not exceed the hard limit!" userInfo:nil]);
1181 } else if (pSessionHistorySize > 0) {
1182 sessionHistorySize = pSessionHistorySize;
1184 }
1185}
1186
1187+ (id<Session>)getSession:(long)sessionId {
1188 [sessionHistoryLock lock];
1189
1190 id<Session> session = [sessionHistoryMap objectForKey:[NSNumber numberWithLong:sessionId]];
1191
1192 [sessionHistoryLock unlock];
1193
1194 return session;
1195}
1196
1197+ (id<Session>)getLastSession {
1198 [sessionHistoryLock lock];
1199
1200 id<Session> lastSession = [sessionHistoryList lastObject];
1201
1202 [sessionHistoryLock unlock];
1203
1204 return lastSession;
1205}
1206
1208 id<Session> lastCompletedSession = nil;
1209
1210 [sessionHistoryLock lock];
1211
1212 for(int i = [sessionHistoryList count] - 1; i >= 0; i--) {
1213 id<Session> session = [sessionHistoryList objectAtIndex:i];
1214 if ([session getState] == SessionStateCompleted) {
1215 lastCompletedSession = session;
1216 break;
1217 }
1218 }
1219
1220 [sessionHistoryLock unlock];
1221
1222 return lastCompletedSession;
1223}
1224
1225+ (NSArray*)getSessions {
1226 [sessionHistoryLock lock];
1227
1228 NSArray* sessionsCopy = [sessionHistoryList copy];
1229
1230 [sessionHistoryLock unlock];
1231
1232 return sessionsCopy;
1233}
1234
1235+ (void)clearSessions {
1236 [sessionHistoryLock lock];
1237
1238 [sessionHistoryList removeAllObjects];
1239 [sessionHistoryMap removeAllObjects];
1240
1241 [sessionHistoryLock unlock];
1242}
1243
1244+ (NSArray*)getFFmpegSessions {
1245 NSMutableArray* ffmpegSessions = [[NSMutableArray alloc] init];
1246
1247 [sessionHistoryLock lock];
1248
1249 for(int i = 0; i < [sessionHistoryList count]; i++) {
1250 id<Session> session = [sessionHistoryList objectAtIndex:i];
1251 if ([session isFFmpeg]) {
1252 [ffmpegSessions addObject:session];
1253 }
1254 }
1255
1256 [sessionHistoryLock unlock];
1257
1258 return ffmpegSessions;
1259}
1260
1261+ (NSArray*)getFFprobeSessions {
1262 NSMutableArray* ffprobeSessions = [[NSMutableArray alloc] init];
1263
1264 [sessionHistoryLock lock];
1265
1266 for(int i = 0; i < [sessionHistoryList count]; i++) {
1267 id<Session> session = [sessionHistoryList objectAtIndex:i];
1268 if ([session isFFprobe]) {
1269 [ffprobeSessions addObject:session];
1270 }
1271 }
1272
1273 [sessionHistoryLock unlock];
1274
1275 return ffprobeSessions;
1276}
1277
1278+ (NSArray*)getMediaInformationSessions {
1279 NSMutableArray* mediaInformationSessions = [[NSMutableArray alloc] init];
1280
1281 [sessionHistoryLock lock];
1282
1283 for(int i = 0; i < [sessionHistoryList count]; i++) {
1284 id<Session> session = [sessionHistoryList objectAtIndex:i];
1285 if ([session isMediaInformation]) {
1286 [mediaInformationSessions addObject:session];
1287 }
1288 }
1289
1290 [sessionHistoryLock unlock];
1291
1292 return mediaInformationSessions;
1293}
1294
1295+ (NSArray*)getSessionsByState:(SessionState)state {
1296 NSMutableArray* sessions = [[NSMutableArray alloc] init];
1297
1298 [sessionHistoryLock lock];
1299
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];
1304 }
1305 }
1306
1307 [sessionHistoryLock unlock];
1308
1309 return sessions;
1310}
1311
1312+ (LogRedirectionStrategy)getLogRedirectionStrategy {
1314}
1315
1316+ (void)setLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy {
1317 globalLogRedirectionStrategy = logRedirectionStrategy;
1318}
1319
1320+ (int)messagesInTransmit:(long)sessionId {
1321 return atomic_load(&sessionInTransitMessageCountMap[sessionId % SESSION_MAP_SIZE]);
1322}
1323
1324+ (NSString*)sessionStateToString:(SessionState)state {
1325 switch (state) {
1326 case SessionStateCreated: return @"CREATED";
1327 case SessionStateRunning: return @"RUNNING";
1328 case SessionStateFailed: return @"FAILED";
1329 case SessionStateCompleted: return @"COMPLETED";
1330 default: return @"";
1331 }
1332}
1333
1334+ (NSArray*)parseArguments:(NSString*)command {
1335 NSMutableArray *argumentArray = [[NSMutableArray alloc] init];
1336 NSMutableString *currentArgument = [[NSMutableString alloc] init];
1337
1338 bool singleQuoteStarted = false;
1339 bool doubleQuoteStarted = false;
1340
1341 for (int i = 0; i < command.length; i++) {
1342 unichar previousChar;
1343 if (i > 0) {
1344 previousChar = [command characterAtIndex:(i - 1)];
1345 } else {
1346 previousChar = 0;
1347 }
1348 unichar currentChar = [command characterAtIndex:i];
1349
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];
1356 }
1357 } else if (currentChar == '\'' && (previousChar == 0 || previousChar != '\\')) {
1358 if (singleQuoteStarted) {
1359 singleQuoteStarted = false;
1360 } else if (doubleQuoteStarted) {
1361 [currentArgument appendFormat: @"%C", currentChar];
1362 } else {
1363 singleQuoteStarted = true;
1364 }
1365 } else if (currentChar == '\"' && (previousChar == 0 || previousChar != '\\')) {
1366 if (doubleQuoteStarted) {
1367 doubleQuoteStarted = false;
1368 } else if (singleQuoteStarted) {
1369 [currentArgument appendFormat: @"%C", currentChar];
1370 } else {
1371 doubleQuoteStarted = true;
1372 }
1373 } else {
1374 [currentArgument appendFormat: @"%C", currentChar];
1375 }
1376 }
1377
1378 if ([currentArgument length] > 0) {
1379 [argumentArray addObject: currentArgument];
1380 }
1381
1382 return argumentArray;
1383}
1384
1385+ (NSString*)argumentsToString:(NSArray*)arguments {
1386 if (arguments == nil) {
1387 return @"nil";
1388 }
1389
1390 NSMutableString *string = [NSMutableString stringWithString:@""];
1391 for (int i=0; i < [arguments count]; i++) {
1392 NSString *argument = [arguments objectAtIndex:i];
1393 if (i > 0) {
1394 [string appendString:@" "];
1395 }
1396 [string appendString:argument];
1397 }
1398
1399 return string;
1400}
1401
1402@end
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]
float _statisticsQuality
void cancelSession(long sessionId)
static volatile NSMutableDictionary * sessionHistoryMap
#define SESSION_MAP_SIZE
int _logLevel
static FFmpegSessionCompleteCallback ffmpegSessionCompleteCallback
static int sessionHistorySize
static void avutil_log_sanitize(uint8_t *line)
static NSRecursiveLock * lock
int _statisticsTime
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 callbackNotify()
float _statisticsFps
long _sessionId
void callbackBlockFunction()
double _statisticsBitrate
static MediaInformationSessionCompleteCallback mediaInformationSessionCompleteCallback
void registerSessionId(long sessionId)
double _statisticsSpeed
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
int64_t _statisticsSize
AVBPrint _logData
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
int configuredLogLevel
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)
Definition: LogCallback.h:31
void(^ MediaInformationSessionCompleteCallback)(MediaInformationSession *session)
void(^ StatisticsCallback)(Statistics *statistics)
#define AV_LOG_STDERR
void set_report_callback(void(*callback)(int, float, float, int64_t, int, double, double))
void fail:(NSException *exception)
NSArray * getAllLogsWithTimeout:(int waitTimeout)
void complete:(ReturnCode *returnCode)
long getAndIncrement()
Definition: AtomicLong.m:40
void asyncFFmpegExecute:onDispatchQueue:(FFmpegSession *ffmpegSession,[onDispatchQueue] dispatch_queue_t queue)
NSArray * getFFmpegSessions()
FFmpegSessionCompleteCallback getFFmpegSessionCompleteCallback()
LogRedirectionStrategy getLogRedirectionStrategy()
void getMediaInformationExecute:withTimeout:(MediaInformationSession *mediaInformationSession,[withTimeout] int waitTimeout)
NSString * registerNewFFmpegPipe()
NSArray * getSessions()
FFprobeSessionCompleteCallback getFFprobeSessionCompleteCallback()
NSString * getVersion()
MediaInformationSessionCompleteCallback getMediaInformationSessionCompleteCallback()
int setFontconfigConfigurationPath:(NSString *path)
NSString * getBuildDate()
void ffprobeExecute:(FFprobeSession *ffprobeSession)
NSArray * getFFprobeSessions()
NSArray * getMediaInformationSessions()
void ffmpegExecute:(FFmpegSession *ffmpegSession)
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()
Definition: FFmpegSession.m:66
void addStatistics:(Statistics *statistics)
FFmpegSessionCompleteCallback getCompleteCallback()
Definition: FFmpegSession.m:70
FFprobeSessionCompleteCallback getCompleteCallback()
Definition: Log.h:29
NSString * getMessage()
Definition: Log.m:47
MediaInformation * fromWithError:(NSString *ffprobeJsonOutput)
void setMediaInformation:(MediaInformation *mediaInformation)
MediaInformationSessionCompleteCallback getCompleteCallback()