FFmpegKitConfig.m
Go to the documentation of this file.
/*
* Copyright (c) 2018-2021 Taner Sener
*
* This file is part of FFmpegKit.
*
* FFmpegKit is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FFmpegKit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
*/
#import <stdatomic.h>
#import <sys/types.h>
#import <sys/stat.h>
#import "libavutil/ffversion.h"
#import "fftools_ffmpeg.h"
#import "ArchDetect.h"
#import "AtomicLong.h"
#import "FFmpegKit.h"
#import "FFmpegKitConfig.h"
#import "FFmpegSession.h"
#import "FFprobeKit.h"
#import "FFprobeSession.h"
#import "Level.h"
#import "LogRedirectionStrategy.h"
#import "MediaInformationSession.h"
#import "SessionState.h"
NSString* const FFmpegKitVersion = @"4.4";
NSString* const FFmpegKitNamedPipePrefix = @"fk_pipe_";
static AtomicLong* pipeIndexGenerator;
/* Session history variables */
static int sessionHistorySize;
static volatile NSMutableDictionary* sessionHistoryMap;
static NSMutableArray* sessionHistoryList;
static NSRecursiveLock* sessionHistoryLock;
const int SESSION_MAP_SIZE = 1000;
static atomic_short sessionMap[SESSION_MAP_SIZE];
static atomic_int sessionInTransitMessageCountMap[SESSION_MAP_SIZE];
static dispatch_queue_t asyncDispatchQueue;
static LogCallback logCallback;
static StatisticsCallback statisticsCallback;
static ExecuteCallback executeCallback;
static LogRedirectionStrategy globalLogRedirectionStrategy;
static int redirectionEnabled;
static NSRecursiveLock *lock;
static dispatch_semaphore_t semaphore;
static NSMutableArray *callbackDataArray;
volatile int handleSIGQUIT = 1;
volatile int handleSIGINT = 1;
volatile int handleSIGTERM = 1;
volatile int handleSIGXCPU = 1;
volatile int handleSIGPIPE = 1;
__thread volatile long _sessionId = 0;
int configuredLogLevel = LevelAVLogInfo;
int ffmpeg_execute(int argc, char **argv);
int ffprobe_execute(int argc, char **argv);
typedef NS_ENUM(NSUInteger, CallbackType) {
LogType,
StatisticsType
};
@interface CallbackData : NSObject
@end
@implementation CallbackData {
CallbackType _type;
long _sessionId; // session id
int _logLevel; // log level
NSString* _logData; // log data
int _statisticsFrameNumber; // statistics frame number
float _statisticsFps; // statistics fps
float _statisticsQuality; // statistics quality
int64_t _statisticsSize; // statistics size
int _statisticsTime; // statistics time
double _statisticsBitrate; // statistics bitrate
double _statisticsSpeed; // statistics speed
}
- (instancetype)init:(long)sessionId logLevel:(int)logLevel data:(NSString*)logData {
self = [super init];
if (self) {
_type = LogType;
_sessionId = sessionId;
_logLevel = logLevel;
_logData = logData;
}
return self;
}
- (instancetype)init:(long)sessionId
videoFrameNumber:(int)videoFrameNumber
fps:(float)videoFps
quality:(float)videoQuality
size:(int64_t)size
time:(int)time
bitrate:(double)bitrate
speed:(double)speed {
self = [super init];
if (self) {
_type = StatisticsType;
_sessionId = sessionId;
_statisticsFrameNumber = videoFrameNumber;
_statisticsFps = videoFps;
_statisticsQuality = videoQuality;
_statisticsSize = size;
_statisticsTime = time;
_statisticsBitrate = bitrate;
_statisticsSpeed = speed;
}
return self;
}
- (CallbackType)getType {
return _type;
}
- (long)getSessionId {
return _sessionId;
}
- (int)getLogLevel {
return _logLevel;
}
- (NSString*)getLogData {
return _logData;
}
- (int)getStatisticsFrameNumber {
return _statisticsFrameNumber;
}
- (float)getStatisticsFps {
return _statisticsFps;
}
- (float)getStatisticsQuality {
return _statisticsQuality;
}
- (int64_t)getStatisticsSize {
return _statisticsSize;
}
- (int)getStatisticsTime {
return _statisticsTime;
}
- (double)getStatisticsBitrate {
return _statisticsBitrate;
}
- (double)getStatisticsSpeed {
return _statisticsSpeed;
}
@end
void callbackWait(int milliSeconds) {
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(milliSeconds * NSEC_PER_MSEC)));
}
void callbackNotify() {
dispatch_semaphore_signal(semaphore);
}
void logCallbackDataAdd(int level, NSString *logData) {
CallbackData* callbackData = [[CallbackData alloc] init:_sessionId logLevel:level data:logData];
[lock lock];
[callbackDataArray addObject:callbackData];
[lock unlock];
callbackNotify();
atomic_fetch_add(&sessionInTransitMessageCountMap[_sessionId % SESSION_MAP_SIZE], 1);
}
void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed) {
CallbackData *callbackData = [[CallbackData alloc] init:_sessionId videoFrameNumber:frameNumber fps:fps quality:quality size:size time:time bitrate:bitrate speed:speed];
[lock lock];
[callbackDataArray addObject:callbackData];
[lock unlock];
callbackNotify();
atomic_fetch_add(&sessionInTransitMessageCountMap[_sessionId % SESSION_MAP_SIZE], 1);
}
CallbackData *callbackDataRemove() {
CallbackData *newData = nil;
[lock lock];
@try {
if ([callbackDataArray count] > 0) {
newData = [callbackDataArray objectAtIndex:0];
[callbackDataArray removeObjectAtIndex:0];
}
} @catch(NSException *exception) {
// DO NOTHING
} @finally {
[lock unlock];
}
return newData;
}
void addSession(long sessionId) {
atomic_store(&sessionMap[sessionId % SESSION_MAP_SIZE], 1);
}
void removeSession(long sessionId) {
atomic_store(&sessionMap[sessionId % SESSION_MAP_SIZE], 0);
}
void cancelSession(long sessionId) {
atomic_store(&sessionMap[sessionId % SESSION_MAP_SIZE], 2);
}
int cancelRequested(long sessionId) {
if (atomic_load(&sessionMap[sessionId % SESSION_MAP_SIZE]) == 2) {
return 1;
} else {
return 0;
}
}
void resetMessagesInTransmit(long sessionId) {
atomic_store(&sessionInTransitMessageCountMap[sessionId % SESSION_MAP_SIZE], 0);
}
void ffmpegkit_log_callback_function(void *ptr, int level, const char* format, va_list vargs) {
// DO NOT PROCESS UNWANTED LOGS
if (level >= 0) {
level &= 0xff;
}
int activeLogLevel = av_log_get_level();
// LevelAVLogStdErr logs are always redirected
if ((activeLogLevel == LevelAVLogQuiet && level != LevelAVLogStdErr) || (level > activeLogLevel)) {
return;
}
NSString *logData = [[NSString alloc] initWithFormat:[NSString stringWithCString:format encoding:NSUTF8StringEncoding] arguments:vargs];
if (logData.length > 0) {
logCallbackDataAdd(level, logData);
}
}
void ffmpegkit_statistics_callback_function(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed) {
statisticsCallbackDataAdd(frameNumber, fps, quality, size, time, bitrate, speed);
}
void process_log(long sessionId, int levelValue, NSString* logMessage) {
int activeLogLevel = av_log_get_level();
Log* log = [[Log alloc] init:sessionId:levelValue:logMessage];
BOOL globalCallbackDefined = false;
BOOL sessionCallbackDefined = false;
LogRedirectionStrategy activeLogRedirectionStrategy = globalLogRedirectionStrategy;
// LevelAVLogStdErr logs are always redirected
if ((activeLogLevel == LevelAVLogQuiet && levelValue != LevelAVLogStdErr) || (levelValue > activeLogLevel)) {
// LOG NEITHER PRINTED NOR FORWARDED
return;
}
id<Session> session = [FFmpegKitConfig getSession:sessionId];
if (session != nil) {
activeLogRedirectionStrategy = [session getLogRedirectionStrategy];
[session addLog:log];
LogCallback sessionLogCallback = [session getLogCallback];
if (sessionLogCallback != nil) {
sessionCallbackDefined = TRUE;
@try {
// NOTIFY SESSION CALLBACK DEFINED
sessionLogCallback(log);
}
@catch(NSException* exception) {
NSLog(@"Exception thrown inside session LogCallback block. %@", [exception callStackSymbols]);
}
}
}
LogCallback globalLogCallback = logCallback;
if (globalLogCallback != nil) {
globalCallbackDefined = TRUE;
@try {
// NOTIFY GLOBAL CALLBACK DEFINED
globalLogCallback(log);
}
@catch(NSException* exception) {
NSLog(@"Exception thrown inside global LogCallback block. %@", [exception callStackSymbols]);
}
}
// EXECUTE THE LOG STRATEGY
switch (activeLogRedirectionStrategy) {
case LogRedirectionStrategyNeverPrintLogs: {
return;
}
case LogRedirectionStrategyPrintLogsWhenGlobalCallbackNotDefined: {
if (globalCallbackDefined) {
return;
}
}
break;
case LogRedirectionStrategyPrintLogsWhenSessionCallbackNotDefined: {
if (sessionCallbackDefined) {
return;
}
}
case LogRedirectionStrategyPrintLogsWhenNoCallbacksDefined: {
if (globalCallbackDefined || sessionCallbackDefined) {
return;
}
}
case LogRedirectionStrategyAlwaysPrintLogs: {
}
}
// PRINT LOGS
switch (levelValue) {
case LevelAVLogQuiet:
// PRINT NO OUTPUT
break;
default:
// WRITE TO NSLOG
NSLog(@"%@: %@", [FFmpegKitConfig logLevelToString:levelValue], logMessage);
break;
}
}
void process_statistics(long sessionId, int videoFrameNumber, float videoFps, float videoQuality, long size, int time, double bitrate, double speed) {
Statistics *statistics = [[Statistics alloc] init:sessionId videoFrameNumber:videoFrameNumber videoFps:videoFps videoQuality:videoQuality size:size time:time bitrate:bitrate speed:speed];
id<Session> session = [FFmpegKitConfig getSession:sessionId];
if (session != nil && [session isFFmpeg]) {
FFmpegSession *ffmpegSession = (FFmpegSession*)session;
[ffmpegSession addStatistics:statistics];
StatisticsCallback sessionStatisticsCallback = [ffmpegSession getStatisticsCallback];
if (sessionStatisticsCallback != nil) {
@try {
sessionStatisticsCallback(statistics);
}
@catch(NSException* exception) {
NSLog(@"Exception thrown inside session StatisticsCallback block. %@", [exception callStackSymbols]);
}
}
}
StatisticsCallback globalStatisticsCallback = statisticsCallback;
if (globalStatisticsCallback != nil) {
@try {
globalStatisticsCallback(statistics);
}
@catch(NSException* exception) {
NSLog(@"Exception thrown inside global StatisticsCallback block. %@", [exception callStackSymbols]);
}
}
}
void callbackBlockFunction() {
int activeLogLevel = av_log_get_level();
if ((activeLogLevel != LevelAVLogQuiet) && (LevelAVLogDebug <= activeLogLevel)) {
NSLog(@"Async callback block started.\n");
}
while(redirectionEnabled) {
@autoreleasepool {
@try {
CallbackData *callbackData = callbackDataRemove();
if (callbackData != nil) {
if ([callbackData getType] == LogType) {
process_log([callbackData getSessionId], [callbackData getLogLevel], [callbackData getLogData]);
} else {
process_statistics([callbackData getSessionId],
[callbackData getStatisticsFrameNumber],
[callbackData getStatisticsFps],
[callbackData getStatisticsQuality],
[callbackData getStatisticsSize],
[callbackData getStatisticsTime],
[callbackData getStatisticsBitrate],
[callbackData getStatisticsSpeed]);
}
atomic_fetch_sub(&sessionInTransitMessageCountMap[[callbackData getSessionId] % SESSION_MAP_SIZE], 1);
} else {
callbackWait(100);
}
} @catch(NSException *exception) {
activeLogLevel = av_log_get_level();
if ((activeLogLevel != LevelAVLogQuiet) && (LevelAVLogWarning <= activeLogLevel)) {
NSLog(@"Async callback block received error: %@n\n", exception);
NSLog(@"%@", [exception callStackSymbols]);
}
}
}
}
activeLogLevel = av_log_get_level();
if ((activeLogLevel != LevelAVLogQuiet) && (LevelAVLogDebug <= activeLogLevel)) {
NSLog(@"Async callback block stopped.\n");
}
}
int executeFFmpeg(long sessionId, NSArray* arguments) {
NSString* const LIB_NAME = @"ffmpeg";
// SETS DEFAULT LOG LEVEL BEFORE STARTING A NEW RUN
av_log_set_level(configuredLogLevel);
char **commandCharPArray = (char **)av_malloc(sizeof(char*) * ([arguments count] + 1));
/* PRESERVE USAGE FORMAT
*
* ffmpeg <arguments>
*/
commandCharPArray[0] = (char *)av_malloc(sizeof(char) * ([LIB_NAME length] + 1));
strcpy(commandCharPArray[0], [LIB_NAME UTF8String]);
// PREPARE ARRAY ELEMENTS
for (int i=0; i < [arguments count]; i++) {
NSString *argument = [arguments objectAtIndex:i];
commandCharPArray[i + 1] = (char *) [argument UTF8String];
}
// REGISTER THE ID BEFORE STARTING THE SESSION
_sessionId = sessionId;
addSession(sessionId);
resetMessagesInTransmit(sessionId);
// RUN
int returnCode = ffmpeg_execute(([arguments count] + 1), commandCharPArray);
// ALWAYS REMOVE THE ID FROM THE MAP
removeSession(sessionId);
// CLEANUP
av_free(commandCharPArray[0]);
av_free(commandCharPArray);
return returnCode;
}
int executeFFprobe(long sessionId, NSArray* arguments) {
NSString* const LIB_NAME = @"ffprobe";
// SETS DEFAULT LOG LEVEL BEFORE STARTING A NEW RUN
av_log_set_level(configuredLogLevel);
char **commandCharPArray = (char **)av_malloc(sizeof(char*) * ([arguments count] + 1));
/* PRESERVE USAGE FORMAT
*
* ffprobe <arguments>
*/
commandCharPArray[0] = (char *)av_malloc(sizeof(char) * ([LIB_NAME length] + 1));
strcpy(commandCharPArray[0], [LIB_NAME UTF8String]);
// PREPARE ARRAY ELEMENTS
for (int i=0; i < [arguments count]; i++) {
NSString *argument = [arguments objectAtIndex:i];
commandCharPArray[i + 1] = (char *) [argument UTF8String];
}
// REGISTER THE ID BEFORE STARTING THE SESSION
_sessionId = sessionId;
addSession(sessionId);
resetMessagesInTransmit(sessionId);
// RUN
int returnCode = ffprobe_execute(([arguments count] + 1), commandCharPArray);
// ALWAYS REMOVE THE ID FROM THE MAP
removeSession(sessionId);
// CLEANUP
av_free(commandCharPArray[0]);
av_free(commandCharPArray);
return returnCode;
}
@implementation FFmpegKitConfig
+ (void)initialize {
[ArchDetect class];
[FFmpegKit class];
[FFprobeKit class];
pipeIndexGenerator = [[AtomicLong alloc] initWithValue:1];
sessionHistorySize = 10;
sessionHistoryMap = [[NSMutableDictionary alloc] init];
sessionHistoryList = [[NSMutableArray alloc] init];
sessionHistoryLock = [[NSRecursiveLock alloc] init];
for(int i = 0; i<SESSION_MAP_SIZE; i++) {
atomic_init(&sessionMap[i], 0);
atomic_init(&sessionInTransitMessageCountMap[i], 0);
}
asyncDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
logCallback = nil;
statisticsCallback = nil;
executeCallback = nil;
globalLogRedirectionStrategy = LogRedirectionStrategyPrintLogsWhenNoCallbacksDefined;
redirectionEnabled = 0;
lock = [[NSRecursiveLock alloc] init];
semaphore = dispatch_semaphore_create(0);
callbackDataArray = [[NSMutableArray alloc] init];
[FFmpegKitConfig enableRedirection];
}
+ (void)enableRedirection {
[lock lock];
if (redirectionEnabled != 0) {
[lock unlock];
return;
}
redirectionEnabled = 1;
[lock unlock];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
callbackBlockFunction();
});
av_log_set_callback(ffmpegkit_log_callback_function);
set_report_callback(ffmpegkit_statistics_callback_function);
}
+ (void)disableRedirection {
[lock lock];
if (redirectionEnabled != 1) {
[lock unlock];
return;
}
redirectionEnabled = 0;
[lock unlock];
av_log_set_callback(av_log_default_callback);
set_report_callback(nil);
callbackNotify();
}
+ (int)setFontconfigConfigurationPath:(NSString*)path {
return [FFmpegKitConfig setEnvironmentVariable:@"FONTCONFIG_PATH" value:path];
}
+ (void)setFontDirectory:(NSString*)fontDirectoryPath with:(NSDictionary*)fontNameMapping {
[FFmpegKitConfig setFontDirectoryList:[NSArray arrayWithObject:fontDirectoryPath] with:fontNameMapping];
}
+ (void)setFontDirectoryList:(NSArray*)fontDirectoryArray with:(NSDictionary*)fontNameMapping {
NSError *error = nil;
BOOL isDirectory = YES;
BOOL isFile = NO;
int validFontNameMappingCount = 0;
NSString *tempConfigurationDirectory = [NSTemporaryDirectory() stringByAppendingPathComponent:@"fontconfig"];
NSString *fontConfigurationFile = [tempConfigurationDirectory stringByAppendingPathComponent:@"fonts.conf"];
if (![[NSFileManager defaultManager] fileExistsAtPath:tempConfigurationDirectory isDirectory:&isDirectory]) {
if (![[NSFileManager defaultManager] createDirectoryAtPath:tempConfigurationDirectory withIntermediateDirectories:YES attributes:nil error:&error]) {
NSLog(@"Failed to set font directory. Error received while creating temp conf directory: %@.", error);
return;
}
NSLog(@"Created temporary font conf directory: TRUE.");
}
if ([[NSFileManager defaultManager] fileExistsAtPath:fontConfigurationFile isDirectory:&isFile]) {
BOOL fontConfigurationDeleted = [[NSFileManager defaultManager] removeItemAtPath:fontConfigurationFile error:nil];
NSLog(@"Deleted old temporary font configuration: %s.", fontConfigurationDeleted?"TRUE":"FALSE");
}
/* PROCESS MAPPINGS FIRST */
NSString *fontNameMappingBlock = @"";
for (NSString *fontName in [fontNameMapping allKeys]) {
NSString *mappedFontName = [fontNameMapping objectForKey:fontName];
if ((fontName != nil) && (mappedFontName != nil) && ([fontName length] > 0) && ([mappedFontName length] > 0)) {
fontNameMappingBlock = [NSString stringWithFormat:@"%@\n%@\n%@%@%@\n%@\n%@\n%@%@%@\n%@\n%@\n",
@" <match target=\"pattern\">",
@" <test qual=\"any\" name=\"family\">",
@" <string>", fontName, @"</string>",
@" </test>",
@" <edit name=\"family\" mode=\"assign\" binding=\"same\">",
@" <string>", mappedFontName, @"</string>",
@" </edit>",
@" </match>"];
validFontNameMappingCount++;
}
}
NSMutableString *fontConfiguration = [NSMutableString stringWithFormat:@"%@\n%@\n%@\n%@\n",
@"<?xml version=\"1.0\"?>",
@"<!DOCTYPE fontconfig SYSTEM \"fonts.dtd\">",
@"<fontconfig>",
@" <dir prefix=\"cwd\">.</dir>"];
for (int i=0; i < [fontDirectoryArray count]; i++) {
NSString *fontDirectoryPath = [fontDirectoryArray objectAtIndex:i];
[fontConfiguration appendString: @" <dir>"];
[fontConfiguration appendString: fontDirectoryPath];
[fontConfiguration appendString: @"</dir>"];
}
[fontConfiguration appendString:fontNameMappingBlock];
[fontConfiguration appendString:@"</fontconfig>"];
if (![fontConfiguration writeToFile:fontConfigurationFile atomically:YES encoding:NSUTF8StringEncoding error:&error]) {
NSLog(@"Failed to set font directory. Error received while saving font configuration: %@.", error);
return;
}
NSLog(@"Saved new temporary font configuration with %d font name mappings.", validFontNameMappingCount);
[FFmpegKitConfig setFontconfigConfigurationPath:tempConfigurationDirectory];
for (int i=0; i < [fontDirectoryArray count]; i++) {
NSString *fontDirectoryPath = [fontDirectoryArray objectAtIndex:i];
NSLog(@"Font directory %@ registered successfully.", fontDirectoryPath);
}
}
+ (NSString*)registerNewFFmpegPipe {
NSError *error = nil;
BOOL isDirectory;
// PIPES ARE CREATED UNDER THE PIPES DIRECTORY
NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *pipesDir = [cacheDir stringByAppendingPathComponent:@"pipes"];
if (![[NSFileManager defaultManager] fileExistsAtPath:pipesDir isDirectory:&isDirectory]) {
if (![[NSFileManager defaultManager] createDirectoryAtPath:pipesDir withIntermediateDirectories:YES attributes:nil error:&error]) {
NSLog(@"Failed to create pipes directory: %@. Operation failed with %@.", pipesDir, error);
return nil;
}
}
NSString *newFFmpegPipePath = [NSString stringWithFormat:@"%@/%@%ld", pipesDir, FFmpegKitNamedPipePrefix, [pipeIndexGenerator getAndIncrement]];
// FIRST CLOSE OLD PIPES WITH THE SAME NAME
[FFmpegKitConfig closeFFmpegPipe:newFFmpegPipePath];
int rc = mkfifo([newFFmpegPipePath UTF8String], S_IRWXU | S_IRWXG | S_IROTH);
if (rc == 0) {
return newFFmpegPipePath;
} else {
NSLog(@"Failed to register new FFmpeg pipe %@. Operation failed with rc=%d.", newFFmpegPipePath, rc);
return nil;
}
}
+ (void)closeFFmpegPipe:(NSString*)ffmpegPipePath {
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:ffmpegPipePath]){
[fileManager removeItemAtPath:ffmpegPipePath error:nil];
}
}
+ (NSString*)getFFmpegVersion {
return [NSString stringWithUTF8String:FFMPEG_VERSION];
}
+ (NSString*)getVersion {
if ([FFmpegKitConfig isLTSBuild] == 1) {
return [NSString stringWithFormat:@"%@-lts", FFmpegKitVersion];
} else {
return FFmpegKitVersion;
}
}
+ (int)isLTSBuild {
#if defined(FFMPEG_KIT_LTS)
return 1;
#else
return 0;
#endif
}
+ (NSString*)getBuildDate {
char buildDate[10];
sprintf(buildDate, "%d", FFMPEG_KIT_BUILD_DATE);
return [NSString stringWithUTF8String:buildDate];
}
+ (int)setEnvironmentVariable:(NSString*)variableName value:(NSString*)variableValue {
return setenv([variableName UTF8String], [variableValue UTF8String], true);
}
+ (void)ignoreSignal:(Signal)signal {
if (signal == SignalQuit) {
handleSIGQUIT = 0;
} else if (signal == SignalInt) {
handleSIGINT = 0;
} else if (signal == SignalTerm) {
handleSIGTERM = 0;
} else if (signal == SignalXcpu) {
handleSIGXCPU = 0;
} else if (signal == SignalPipe) {
handleSIGPIPE = 0;
}
}
+ (void)ffmpegExecute:(FFmpegSession*)ffmpegSession {
[FFmpegKitConfig addSession:ffmpegSession];
[ffmpegSession startRunning];
@try {
int returnCode = executeFFmpeg([ffmpegSession getSessionId], [ffmpegSession getArguments]);
[ffmpegSession complete:[[ReturnCode alloc] init:returnCode]];
} @catch (NSException *exception) {
[ffmpegSession fail:exception];
NSLog(@"FFmpeg execute failed: %@.%@", [FFmpegKit argumentsToString:[ffmpegSession getArguments]], [NSString stringWithFormat:@"%@", [exception callStackSymbols]]);
}
}
+ (void)ffprobeExecute:(FFprobeSession*)ffprobeSession {
[FFmpegKitConfig addSession:ffprobeSession];
[ffprobeSession startRunning];
@try {
int returnCode = executeFFprobe([ffprobeSession getSessionId], [ffprobeSession getArguments]);
[ffprobeSession complete:[[ReturnCode alloc] init:returnCode]];
} @catch (NSException *exception) {
[ffprobeSession fail:exception];
NSLog(@"FFprobe execute failed: %@.%@", [FFmpegKit argumentsToString:[ffprobeSession getArguments]], [NSString stringWithFormat:@"%@", [exception callStackSymbols]]);
}
}
+ (void)getMediaInformationExecute:(MediaInformationSession*)mediaInformationSession withTimeout:(int)waitTimeout {
[FFmpegKitConfig addSession:mediaInformationSession];
[mediaInformationSession startRunning];
@try {
int returnCodeValue = executeFFprobe([mediaInformationSession getSessionId], [mediaInformationSession getArguments]);
ReturnCode* returnCode = [[ReturnCode alloc] init:returnCodeValue];
[mediaInformationSession complete:returnCode];
if ([returnCode isSuccess]) {
MediaInformation* mediaInformation = [MediaInformationJsonParser from:[mediaInformationSession getAllLogsAsStringWithTimeout:waitTimeout]];
[mediaInformationSession setMediaInformation:mediaInformation];
}
} @catch (NSException *exception) {
[mediaInformationSession fail:exception];
NSLog(@"Get media information execute failed: %@.%@", [FFmpegKit argumentsToString:[mediaInformationSession getArguments]], [NSString stringWithFormat:@"%@", [exception callStackSymbols]]);
}
}
+ (void)asyncFFmpegExecute:(FFmpegSession*)ffmpegSession {
[FFmpegKitConfig asyncFFmpegExecute:ffmpegSession onDispatchQueue:asyncDispatchQueue];
}
+ (void)asyncFFmpegExecute:(FFmpegSession*)ffmpegSession onDispatchQueue:(dispatch_queue_t)queue {
[FFmpegKitConfig addSession:ffmpegSession];
dispatch_async(queue, ^{
[FFmpegKitConfig ffmpegExecute:ffmpegSession];
ExecuteCallback globalExecuteCallback = [FFmpegKitConfig getExecuteCallback];
if (globalExecuteCallback != nil) {
globalExecuteCallback(ffmpegSession);
}
ExecuteCallback sessionExecuteCallback = [ffmpegSession getExecuteCallback];
if (sessionExecuteCallback != nil) {
sessionExecuteCallback(ffmpegSession);
}
});
}
+ (void)asyncFFprobeExecute:(FFprobeSession*)ffprobeSession {
[FFmpegKitConfig asyncFFprobeExecute:ffprobeSession onDispatchQueue:asyncDispatchQueue];
}
+ (void)asyncFFprobeExecute:(FFprobeSession*)ffprobeSession onDispatchQueue:(dispatch_queue_t)queue {
[FFmpegKitConfig addSession:ffprobeSession];
dispatch_async(queue, ^{
[FFmpegKitConfig ffprobeExecute:ffprobeSession];
ExecuteCallback globalExecuteCallback = [FFmpegKitConfig getExecuteCallback];
if (globalExecuteCallback != nil) {
globalExecuteCallback(ffprobeSession);
}
ExecuteCallback sessionExecuteCallback = [ffprobeSession getExecuteCallback];
if (sessionExecuteCallback != nil) {
sessionExecuteCallback(ffprobeSession);
}
});
}
+ (void)asyncGetMediaInformationExecute:(MediaInformationSession*)mediaInformationSession withTimeout:(int)waitTimeout {
[FFmpegKitConfig asyncGetMediaInformationExecute:mediaInformationSession onDispatchQueue:asyncDispatchQueue withTimeout:waitTimeout];
}
+ (void)asyncGetMediaInformationExecute:(MediaInformationSession*)mediaInformationSession onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout {
[FFmpegKitConfig addSession:mediaInformationSession];
dispatch_async(queue, ^{
[FFmpegKitConfig getMediaInformationExecute:mediaInformationSession withTimeout:waitTimeout];
ExecuteCallback globalExecuteCallback = [FFmpegKitConfig getExecuteCallback];
if (globalExecuteCallback != nil) {
globalExecuteCallback(mediaInformationSession);
}
ExecuteCallback sessionExecuteCallback = [mediaInformationSession getExecuteCallback];
if (sessionExecuteCallback != nil) {
sessionExecuteCallback(mediaInformationSession);
}
});
}
+ (void)enableLogCallback:(LogCallback)callback {
logCallback = callback;
}
+ (void)enableStatisticsCallback:(StatisticsCallback)callback {
statisticsCallback = callback;
}
+ (void)enableExecuteCallback:(ExecuteCallback)callback {
executeCallback = callback;
}
+ (ExecuteCallback)getExecuteCallback {
return executeCallback;
}
+ (int)getLogLevel {
return configuredLogLevel;
}
+ (void)setLogLevel:(int)level {
configuredLogLevel = level;
}
+ (NSString*)logLevelToString:(int)level {
switch (level) {
case LevelAVLogStdErr: return @"STDERR";
case LevelAVLogTrace: return @"TRACE";
case LevelAVLogDebug: return @"DEBUG";
case LevelAVLogVerbose: return @"VERBOSE";
case LevelAVLogInfo: return @"INFO";
case LevelAVLogWarning: return @"WARNING";
case LevelAVLogError: return @"ERROR";
case LevelAVLogFatal: return @"FATAL";
case LevelAVLogPanic: return @"PANIC";
case LevelAVLogQuiet: return @"QUIET";
default: return @"";
}
}
+ (int)getSessionHistorySize {
return sessionHistorySize;
}
+ (void)setSessionHistorySize:(int)pSessionHistorySize {
if (pSessionHistorySize >= SESSION_MAP_SIZE) {
/*
* THERE IS A HARD LIMIT ON THE NATIVE SIDE. HISTORY SIZE MUST BE SMALLER THAN SESSION_MAP_SIZE
*/
@throw([NSException exceptionWithName:NSInvalidArgumentException reason:@"Session history size must not exceed the hard limit!" userInfo:nil]);
} else if (pSessionHistorySize > 0) {
sessionHistorySize = pSessionHistorySize;
}
}
+ (void)addSession:(id<Session>)session {
NSNumber* sessionIdNumber = [NSNumber numberWithLong:[session getSessionId]];
[sessionHistoryLock lock];
/*
* ASYNC SESSIONS CALL THIS METHOD TWICE
* THIS CHECK PREVENTS ADDING THE SAME SESSION TWICE
*/
if ([sessionHistoryMap objectForKey:sessionIdNumber] == nil) {
[sessionHistoryMap setObject:session forKey:sessionIdNumber];
[sessionHistoryList addObject:session];
if ([sessionHistoryList count] > sessionHistorySize) {
id<Session> first = [sessionHistoryList firstObject];
if (first != nil) {
NSNumber* key = [NSNumber numberWithLong:[first getSessionId]];
[sessionHistoryList removeObject:key];
[sessionHistoryMap removeObjectForKey:key];
}
}
}
[sessionHistoryLock unlock];
}
+ (id<Session>)getSession:(long)sessionId {
[sessionHistoryLock lock];
id<Session> session = [sessionHistoryMap objectForKey:[NSNumber numberWithLong:sessionId]];
[sessionHistoryLock unlock];
return session;
}
+ (id<Session>)getLastSession {
[sessionHistoryLock lock];
id<Session> lastSession = [sessionHistoryList lastObject];
[sessionHistoryLock unlock];
return lastSession;
}
+ (id<Session>)getLastCompletedSession {
id<Session> lastCompletedSession = nil;
[sessionHistoryLock lock];
for(int i = [sessionHistoryList count] - 1; i >= 0; i--) {
id<Session> session = [sessionHistoryList objectAtIndex:i];
if ([session getState] == SessionStateCompleted) {
lastCompletedSession = session;
break;
}
}
[sessionHistoryLock unlock];
return lastCompletedSession;
}
+ (NSArray*)getSessions {
[sessionHistoryLock lock];
NSArray* sessionsCopy = [sessionHistoryList copy];
[sessionHistoryLock unlock];
return sessionsCopy;
}
+ (NSArray*)getFFmpegSessions {
NSMutableArray* ffmpegSessions = [[NSMutableArray alloc] init];
[sessionHistoryLock lock];
for(int i = 0; i < [sessionHistoryList count]; i++) {
id<Session> session = [sessionHistoryList objectAtIndex:i];
if ([session isFFmpeg]) {
[ffmpegSessions addObject:session];
}
}
[sessionHistoryLock unlock];
return ffmpegSessions;
}
+ (NSArray*)getFFprobeSessions {
NSMutableArray* ffprobeSessions = [[NSMutableArray alloc] init];
[sessionHistoryLock lock];
for(int i = 0; i < [sessionHistoryList count]; i++) {
id<Session> session = [sessionHistoryList objectAtIndex:i];
if ([session isFFprobe]) {
[ffprobeSessions addObject:session];
}
}
[sessionHistoryLock unlock];
return ffprobeSessions;
}
+ (NSArray*)getSessionsByState:(SessionState)state {
NSMutableArray* sessions = [[NSMutableArray alloc] init];
[sessionHistoryLock lock];
for(int i = 0; i < [sessionHistoryList count]; i++) {
id<Session> session = [sessionHistoryList objectAtIndex:i];
if ([session getState] == state) {
[sessions addObject:session];
}
}
[sessionHistoryLock unlock];
return sessions;
}
+ (LogRedirectionStrategy)getLogRedirectionStrategy {
return globalLogRedirectionStrategy;
}
+ (void)setLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy {
globalLogRedirectionStrategy = logRedirectionStrategy;
}
+ (int)messagesInTransmit:(long)sessionId {
return atomic_load(&sessionInTransitMessageCountMap[sessionId % SESSION_MAP_SIZE]);
}
+ (NSString*)sessionStateToString:(SessionState)state {
switch (state) {
case SessionStateCreated: return @"CREATED";
case SessionStateRunning: return @"RUNNING";
case SessionStateFailed: return @"FAILED";
case SessionStateCompleted: return @"COMPLETED";
default: return @"";
}
}
@end
ArchDetect.h
AtomicLong.h
ExecuteCallback
void(^ ExecuteCallback)(id< Session > session)
Definition: ExecuteCallback.h:46
FFmpegKit.h
FFmpegKitConfig.h
executeFFprobe
int executeFFprobe(long sessionId, NSArray *arguments)
Definition: FFmpegKitConfig.m:577
callbackWait
void callbackWait(int milliSeconds)
Definition: FFmpegKitConfig.m:214
ffmpegkit_log_callback_function
void ffmpegkit_log_callback_function(void *ptr, int level, const char *format, va_list vargs)
Definition: FFmpegKitConfig.m:338
sessionMap
static atomic_short sessionMap[SESSION_MAP_SIZE]
Definition: FFmpegKitConfig.m:58
_statisticsQuality
float _statisticsQuality
Definition: FFmpegKitConfig.m:120
cancelSession
void cancelSession(long sessionId)
Definition: FFmpegKitConfig.m:303
sessionHistoryMap
static volatile NSMutableDictionary * sessionHistoryMap
Definition: FFmpegKitConfig.m:52
_logLevel
int _logLevel
Definition: FFmpegKitConfig.m:115
sessionHistorySize
static int sessionHistorySize
Definition: FFmpegKitConfig.m:51
lock
static NSRecursiveLock * lock
Definition: FFmpegKitConfig.m:76
_statisticsTime
int _statisticsTime
Definition: FFmpegKitConfig.m:122
handleSIGINT
volatile int handleSIGINT
Definition: FFmpegKitConfig.m:82
ffprobe_execute
int ffprobe_execute(int argc, char **argv)
Definition: fftools_ffprobe.c:3713
handleSIGTERM
volatile int handleSIGTERM
Definition: FFmpegKitConfig.m:83
process_log
void process_log(long sessionId, int levelValue, NSString *logMessage)
Definition: FFmpegKitConfig.m:373
ffmpegkit_statistics_callback_function
void ffmpegkit_statistics_callback_function(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed)
Definition: FFmpegKitConfig.m:369
asyncDispatchQueue
static dispatch_queue_t asyncDispatchQueue
Definition: FFmpegKitConfig.m:61
removeSession
void removeSession(long sessionId)
Definition: FFmpegKitConfig.m:294
statisticsCallbackDataAdd
void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed)
Definition: FFmpegKitConfig.m:246
logCallback
static LogCallback logCallback
Definition: FFmpegKitConfig.m:64
addSession
void addSession(long sessionId)
Definition: FFmpegKitConfig.m:285
callbackNotify
void callbackNotify()
Definition: FFmpegKitConfig.m:221
_statisticsFps
float _statisticsFps
Definition: FFmpegKitConfig.m:119
callbackDataRemove
CallbackData * callbackDataRemove()
Definition: FFmpegKitConfig.m:261
_sessionId
__thread volatile long _sessionId
Definition: FFmpegKitConfig.m:88
callbackBlockFunction
void callbackBlockFunction()
Definition: FFmpegKitConfig.m:489
_statisticsBitrate
double _statisticsBitrate
Definition: FFmpegKitConfig.m:123
_statisticsSpeed
double _statisticsSpeed
Definition: FFmpegKitConfig.m:124
sessionHistoryLock
static NSRecursiveLock * sessionHistoryLock
Definition: FFmpegKitConfig.m:54
executeCallback
static ExecuteCallback executeCallback
Definition: FFmpegKitConfig.m:70
semaphore
static dispatch_semaphore_t semaphore
Definition: FFmpegKitConfig.m:77
_logData
NSString * _logData
Definition: FFmpegKitConfig.m:116
redirectionEnabled
static int redirectionEnabled
Definition: FFmpegKitConfig.m:75
resetMessagesInTransmit
void resetMessagesInTransmit(long sessionId)
Definition: FFmpegKitConfig.m:326
callbackDataArray
static NSMutableArray * callbackDataArray
Definition: FFmpegKitConfig.m:78
_statisticsSize
int64_t _statisticsSize
Definition: FFmpegKitConfig.m:121
_statisticsFrameNumber
int _statisticsFrameNumber
Definition: FFmpegKitConfig.m:118
process_statistics
void process_statistics(long sessionId, int videoFrameNumber, float videoFps, float videoQuality, long size, int time, double bitrate, double speed)
Definition: FFmpegKitConfig.m:455
cancelRequested
int cancelRequested(long sessionId)
Definition: FFmpegKitConfig.m:313
handleSIGPIPE
volatile int handleSIGPIPE
Definition: FFmpegKitConfig.m:85
SESSION_MAP_SIZE
const int SESSION_MAP_SIZE
Definition: FFmpegKitConfig.m:57
FFmpegKitVersion
NSString *const FFmpegKitVersion
Definition: FFmpegKitConfig.m:38
logCallbackDataAdd
void logCallbackDataAdd(int level, NSString *logData)
Definition: FFmpegKitConfig.m:231
handleSIGXCPU
volatile int handleSIGXCPU
Definition: FFmpegKitConfig.m:84
globalLogRedirectionStrategy
static LogRedirectionStrategy globalLogRedirectionStrategy
Definition: FFmpegKitConfig.m:72
statisticsCallback
static StatisticsCallback statisticsCallback
Definition: FFmpegKitConfig.m:67
sessionInTransitMessageCountMap
static atomic_int sessionInTransitMessageCountMap[SESSION_MAP_SIZE]
Definition: FFmpegKitConfig.m:59
pipeIndexGenerator
static AtomicLong * pipeIndexGenerator
Definition: FFmpegKitConfig.m:48
sessionHistoryList
static NSMutableArray * sessionHistoryList
Definition: FFmpegKitConfig.m:53
NS_ENUM
typedef NS_ENUM(NSUInteger, CallbackType)
Definition: FFmpegKitConfig.m:99
FFmpegKitNamedPipePrefix
NSString *const FFmpegKitNamedPipePrefix
Definition: FFmpegKitConfig.m:43
configuredLogLevel
int configuredLogLevel
Definition: FFmpegKitConfig.m:91
ffmpeg_execute
int ffmpeg_execute(int argc, char **argv)
Definition: fftools_ffmpeg.c:5162
handleSIGQUIT
volatile int handleSIGQUIT
Definition: FFmpegKitConfig.m:81
executeFFmpeg
int executeFFmpeg(long sessionId, NSArray *arguments)
Definition: FFmpegKitConfig.m:537
FFmpegSession.h
FFprobeKit.h
FFprobeSession.h
Level.h
LogCallback
void(^ LogCallback)(Log *log)
Definition: LogCallback.h:31
LogRedirectionStrategy.h
MediaInformationSession.h
SessionState.h
StatisticsCallback
void(^ StatisticsCallback)(Statistics *statistics)
Definition: StatisticsCallback.h:31
set_report_callback
void set_report_callback(void(*callback)(int, float, float, int64_t, int, double, double))
Definition: fftools_ffmpeg.c:5146
fftools_ffmpeg.h
int
int
Definition: fftools_ffmpeg_filter.c:200
-[AbstractSession fail:]
void fail:(NSException *exception)
Definition: AbstractSession.m:213
-[AbstractSession complete:]
void complete:(ReturnCode *returnCode)
Definition: AbstractSession.m:207
-[AbstractSession startRunning]
void startRunning()
Definition: AbstractSession.m:202
-[AbstractSession getExecuteCallback]
ExecuteCallback getExecuteCallback()
Definition: AbstractSession.m:73
-[AbstractSession getAllLogsAsStringWithTimeout:]
NSString * getAllLogsAsStringWithTimeout:(int waitTimeout)
Definition: AbstractSession.m:146
ArchDetect
Definition: ArchDetect.h:29
AtomicLong
Definition: AtomicLong.h:29
-[AtomicLong getAndIncrement]
long getAndIncrement()
Definition: AtomicLong.m:40
CallbackData
Definition: FFmpegKitConfig.m:108
-[CallbackData _sessionId]
long _sessionId
Definition: FFmpegKitConfig.m:111
FFmpegKitConfig
Definition: FFmpegKitConfig.h:50
+[FFmpegKitConfig addSession:]
void addSession:(id< Session > session)
Definition: FFmpegKitConfig.m:1011
+[FFmpegKitConfig asyncFFmpegExecute:onDispatchQueue:]
void asyncFFmpegExecute:onDispatchQueue:(FFmpegSession *ffmpegSession,[onDispatchQueue] dispatch_queue_t queue)
Definition: FFmpegKitConfig.m:896
+[FFmpegKitConfig initialize]
void initialize()
Definition: FFmpegKitConfig.m:619
+[FFmpegKitConfig getFFmpegSessions]
NSArray * getFFmpegSessions()
Definition: FFmpegKitConfig.m:1084
+[FFmpegKitConfig getLogRedirectionStrategy]
LogRedirectionStrategy getLogRedirectionStrategy()
Definition: FFmpegKitConfig.m:1135
+[FFmpegKitConfig getMediaInformationExecute:withTimeout:]
void getMediaInformationExecute:withTimeout:(MediaInformationSession *mediaInformationSession,[withTimeout] int waitTimeout)
Definition: FFmpegKitConfig.m:874
+[FFmpegKitConfig getLogLevel]
int getLogLevel()
Definition: FFmpegKitConfig.m:971
+[FFmpegKitConfig disableRedirection]
void disableRedirection()
Definition: FFmpegKitConfig.m:671
+[FFmpegKitConfig registerNewFFmpegPipe]
NSString * registerNewFFmpegPipe()
Definition: FFmpegKitConfig.m:767
+[FFmpegKitConfig getSessions]
NSArray * getSessions()
Definition: FFmpegKitConfig.m:1074
+[FFmpegKitConfig getVersion]
NSString * getVersion()
Definition: FFmpegKitConfig.m:808
+[FFmpegKitConfig setFontconfigConfigurationPath:]
int setFontconfigConfigurationPath:(NSString *path)
Definition: FFmpegKitConfig.m:688
+[FFmpegKitConfig getExecuteCallback]
ExecuteCallback getExecuteCallback()
Definition: FFmpegKitConfig.m:967
+[FFmpegKitConfig getBuildDate]
NSString * getBuildDate()
Definition: FFmpegKitConfig.m:824
+[FFmpegKitConfig ffprobeExecute:]
void ffprobeExecute:(FFprobeSession *ffprobeSession)
Definition: FFmpegKitConfig.m:861
+[FFmpegKitConfig getFFprobeSessions]
NSArray * getFFprobeSessions()
Definition: FFmpegKitConfig.m:1101
+[FFmpegKitConfig ffmpegExecute:]
void ffmpegExecute:(FFmpegSession *ffmpegSession)
Definition: FFmpegKitConfig.m:848
+[FFmpegKitConfig getSessionHistorySize]
int getSessionHistorySize()
Definition: FFmpegKitConfig.m:995
+[FFmpegKitConfig getSession:]
id< Session > getSession:(long sessionId)
Definition: FFmpegKitConfig.m:1036
+[FFmpegKitConfig setEnvironmentVariable:value:]
int setEnvironmentVariable:value:(NSString *variableName,[value] NSString *variableValue)
Definition: FFmpegKitConfig.m:830
+[FFmpegKitConfig getLastSession]
id< Session > getLastSession()
Definition: FFmpegKitConfig.m:1046
+[FFmpegKitConfig asyncFFprobeExecute:onDispatchQueue:]
void asyncFFprobeExecute:onDispatchQueue:(FFprobeSession *ffprobeSession,[onDispatchQueue] dispatch_queue_t queue)
Definition: FFmpegKitConfig.m:917
+[FFmpegKitConfig getFFmpegVersion]
NSString * getFFmpegVersion()
Definition: FFmpegKitConfig.m:804
+[FFmpegKitConfig asyncGetMediaInformationExecute:onDispatchQueue:withTimeout:]
void asyncGetMediaInformationExecute:onDispatchQueue:withTimeout:(MediaInformationSession *mediaInformationSession,[onDispatchQueue] dispatch_queue_t queue,[withTimeout] int waitTimeout)
Definition: FFmpegKitConfig.m:938
+[FFmpegKitConfig enableRedirection]
void enableRedirection()
Definition: FFmpegKitConfig.m:652
+[FFmpegKitConfig setFontDirectoryList:with:]
void setFontDirectoryList:with:(NSArray *fontDirectoryList,[with] NSDictionary *fontNameMapping)
Definition: FFmpegKitConfig.m:696
+[FFmpegKitConfig isLTSBuild]
int isLTSBuild()
Definition: FFmpegKitConfig.m:816
+[FFmpegKitConfig closeFFmpegPipe:]
void closeFFmpegPipe:(NSString *ffmpegPipePath)
Definition: FFmpegKitConfig.m:796
+[FFmpegKitConfig getLastCompletedSession]
id< Session > getLastCompletedSession()
Definition: FFmpegKitConfig.m:1056
FFmpegKit
Definition: FFmpegKit.h:45
FFmpegSession
Definition: FFmpegSession.h:31
-[FFmpegSession getStatisticsCallback]
StatisticsCallback getStatisticsCallback()
Definition: FFmpegSession.m:88
-[FFmpegSession addStatistics:]
void addStatistics:(Statistics *statistics)
Definition: FFmpegSession.m:126
FFprobeKit
Definition: FFprobeKit.h:47
FFprobeSession
Definition: FFprobeSession.h:30
Log
Definition: Log.h:29
MediaInformation
Definition: MediaInformation.h:40
MediaInformationJsonParser
Definition: MediaInformationJsonParser.h:30
+[MediaInformationJsonParser from:]
MediaInformation * from:(NSString *ffprobeJsonOutput)
Definition: MediaInformationJsonParser.m:24
MediaInformationSession
Definition: MediaInformationSession.h:32
-[MediaInformationSession setMediaInformation:]
void setMediaInformation:(MediaInformation *mediaInformation)
Definition: MediaInformationSession.m:58
ReturnCode
Definition: ReturnCode.h:31
Statistics
Definition: Statistics.h:29
Session-p
Definition: Session.h:34
-[Session-p getSessionId]
long getSessionId()