...
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
/Makefile
|
||||
/.deps/
|
||||
*.o
|
||||
*.lo
|
||||
/.libs/
|
||||
*.la
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_ABSTRACT_SESSION_H
|
||||
#define FFMPEG_KIT_ABSTRACT_SESSION_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Session.h"
|
||||
|
||||
/**
|
||||
* Defines how long default "getAll" methods wait, in milliseconds.
|
||||
*/
|
||||
extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
|
||||
|
||||
/**
|
||||
* Abstract session implementation which includes common features shared by <code>FFmpeg</code>,
|
||||
* <code>FFprobe</code> and <code>MediaInformation</code> sessions.
|
||||
*/
|
||||
@interface AbstractSession : NSObject<Session>
|
||||
|
||||
/**
|
||||
* Creates a new abstract session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param logCallback session specific log callback
|
||||
* @param logRedirectionStrategy session specific log redirection strategy
|
||||
*/
|
||||
- (instancetype)init:(NSArray*)arguments withLogCallback:(LogCallback)logCallback withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy;
|
||||
|
||||
/**
|
||||
* Waits for all asynchronous messages to be transmitted until the given timeout.
|
||||
*
|
||||
* @param timeout wait timeout in milliseconds
|
||||
*/
|
||||
- (void)waitForAsynchronousMessagesInTransmit:(int)timeout;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_ABSTRACT_SESSION_H
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#import "AbstractSession.h"
|
||||
#import "AtomicLong.h"
|
||||
#import "FFmpegKit.h"
|
||||
#import "FFmpegKitConfig.h"
|
||||
#import "LogCallback.h"
|
||||
#import "ReturnCode.h"
|
||||
|
||||
int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit = 5000;
|
||||
|
||||
static AtomicLong *sessionIdGenerator = nil;
|
||||
|
||||
extern void addSessionToSessionHistory(id<Session> session);
|
||||
|
||||
@implementation AbstractSession {
|
||||
long _sessionId;
|
||||
LogCallback _logCallback;
|
||||
NSDate* _createTime;
|
||||
NSDate* _startTime;
|
||||
NSDate* _endTime;
|
||||
NSArray* _arguments;
|
||||
NSMutableArray* _logs;
|
||||
NSRecursiveLock* _logsLock;
|
||||
SessionState _state;
|
||||
ReturnCode* _returnCode;
|
||||
NSString* _failStackTrace;
|
||||
LogRedirectionStrategy _logRedirectionStrategy;
|
||||
}
|
||||
|
||||
+ (void)initialize {
|
||||
sessionIdGenerator = [[AtomicLong alloc] initWithValue:1];
|
||||
}
|
||||
|
||||
- (instancetype)init:(NSArray*)arguments withLogCallback:(LogCallback)logCallback withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_sessionId = [sessionIdGenerator getAndIncrement];
|
||||
_logCallback = logCallback;
|
||||
_createTime = [NSDate date];
|
||||
_startTime = nil;
|
||||
_endTime = nil;
|
||||
_arguments = arguments;
|
||||
_logs = [[NSMutableArray alloc] init];
|
||||
_logsLock = [[NSRecursiveLock alloc] init];
|
||||
_state = SessionStateCreated;
|
||||
_returnCode = nil;
|
||||
_failStackTrace = nil;
|
||||
_logRedirectionStrategy = logRedirectionStrategy;
|
||||
|
||||
addSessionToSessionHistory(self);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (LogCallback)getLogCallback {
|
||||
return _logCallback;
|
||||
}
|
||||
|
||||
- (long)getSessionId {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
- (NSDate*)getCreateTime {
|
||||
return _createTime;
|
||||
}
|
||||
|
||||
- (NSDate*)getStartTime {
|
||||
return _startTime;
|
||||
}
|
||||
|
||||
- (NSDate*)getEndTime {
|
||||
return _endTime;
|
||||
}
|
||||
|
||||
- (long)getDuration {
|
||||
NSDate* startTime = _startTime;
|
||||
NSDate* endTime = _endTime;
|
||||
if (startTime != nil && endTime != nil) {
|
||||
return [[NSNumber numberWithDouble:([endTime timeIntervalSinceDate:startTime]*1000)] longValue];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (NSArray*)getArguments {
|
||||
return _arguments;
|
||||
}
|
||||
|
||||
- (NSString*)getCommand {
|
||||
return [FFmpegKitConfig argumentsToString:_arguments];
|
||||
}
|
||||
|
||||
- (void)waitForAsynchronousMessagesInTransmit:(int)timeout {
|
||||
NSDate* expireDate = [[NSDate date] dateByAddingTimeInterval:((double)timeout)/1000];
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
while ([self thereAreAsynchronousMessagesInTransmit] && ([[NSDate date] timeIntervalSinceDate:expireDate] < 0)) {
|
||||
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 100 * NSEC_PER_MSEC));
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray*)getAllLogsWithTimeout:(int)waitTimeout {
|
||||
[self waitForAsynchronousMessagesInTransmit:waitTimeout];
|
||||
|
||||
if ([self thereAreAsynchronousMessagesInTransmit]) {
|
||||
NSLog(@"getAllLogsWithTimeout was called to return all logs but there are still logs being transmitted for session id %ld.", _sessionId);
|
||||
}
|
||||
|
||||
return [self getLogs];
|
||||
}
|
||||
|
||||
- (NSArray*)getAllLogs {
|
||||
return [self getAllLogsWithTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit];
|
||||
}
|
||||
|
||||
- (NSArray*)getLogs {
|
||||
[_logsLock lock];
|
||||
NSArray* logsCopy = [_logs copy];
|
||||
[_logsLock unlock];
|
||||
|
||||
return logsCopy;
|
||||
}
|
||||
|
||||
- (NSString*)getAllLogsAsStringWithTimeout:(int)waitTimeout {
|
||||
[self waitForAsynchronousMessagesInTransmit:waitTimeout];
|
||||
|
||||
if ([self thereAreAsynchronousMessagesInTransmit]) {
|
||||
NSLog(@"getAllLogsAsStringWithTimeout was called to return all logs but there are still logs being transmitted for session id %ld.", _sessionId);
|
||||
}
|
||||
|
||||
return [self getLogsAsString];
|
||||
}
|
||||
|
||||
- (NSString*)getAllLogsAsString {
|
||||
return [self getAllLogsAsStringWithTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit];
|
||||
}
|
||||
|
||||
- (NSString*)getLogsAsString {
|
||||
NSMutableString* concatenatedString = [[NSMutableString alloc] init];
|
||||
|
||||
[_logsLock lock];
|
||||
for (int i=0; i < [_logs count]; i++) {
|
||||
[concatenatedString appendString:[[_logs objectAtIndex:i] getMessage]];
|
||||
}
|
||||
[_logsLock unlock];
|
||||
|
||||
return concatenatedString;
|
||||
}
|
||||
|
||||
- (NSString*)getOutput {
|
||||
return [self getAllLogsAsString];
|
||||
}
|
||||
|
||||
- (SessionState)getState {
|
||||
return _state;
|
||||
}
|
||||
|
||||
- (ReturnCode*)getReturnCode {
|
||||
return _returnCode;
|
||||
}
|
||||
|
||||
- (NSString*)getFailStackTrace {
|
||||
return _failStackTrace;
|
||||
}
|
||||
|
||||
- (LogRedirectionStrategy)getLogRedirectionStrategy {
|
||||
return _logRedirectionStrategy;
|
||||
}
|
||||
|
||||
- (BOOL)thereAreAsynchronousMessagesInTransmit {
|
||||
return ([FFmpegKitConfig messagesInTransmit:_sessionId] != 0);
|
||||
}
|
||||
|
||||
- (void)addLog:(Log*)log {
|
||||
[_logsLock lock];
|
||||
[_logs addObject:log];
|
||||
[_logsLock unlock];
|
||||
}
|
||||
|
||||
- (void)startRunning {
|
||||
_state = SessionStateRunning;
|
||||
_startTime = [NSDate date];
|
||||
}
|
||||
|
||||
- (void)complete:(ReturnCode*)returnCode {
|
||||
_returnCode = returnCode;
|
||||
_state = SessionStateCompleted;
|
||||
_endTime = [NSDate date];
|
||||
}
|
||||
|
||||
- (void)fail:(NSException*)exception {
|
||||
_failStackTrace = [NSString stringWithFormat:@"%@\n%@", [exception userInfo], [exception callStackSymbols]];
|
||||
_state = SessionStateFailed;
|
||||
_endTime = [NSDate date];
|
||||
}
|
||||
|
||||
- (BOOL)isFFmpeg {
|
||||
// IMPLEMENTED IN SUBCLASSES
|
||||
return false;
|
||||
}
|
||||
|
||||
- (BOOL)isFFprobe {
|
||||
// IMPLEMENTED IN SUBCLASSES
|
||||
return false;
|
||||
}
|
||||
|
||||
- (BOOL)isMediaInformation {
|
||||
// IMPLEMENTED IN SUBCLASSES
|
||||
return false;
|
||||
}
|
||||
|
||||
- (void)cancel {
|
||||
if (_state == SessionStateRunning) {
|
||||
[FFmpegKit cancel:_sessionId];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_ARCH_DETECT_H
|
||||
#define FFMPEG_KIT_ARCH_DETECT_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* Detects the running architecture.
|
||||
*/
|
||||
@interface ArchDetect : NSObject
|
||||
|
||||
/**
|
||||
* Returns architecture name of the cpu running.
|
||||
*
|
||||
* @return architecture name of the cpu running
|
||||
*/
|
||||
+ (NSString*)getCpuArch;
|
||||
|
||||
/**
|
||||
* Returns architecture name loaded.
|
||||
*
|
||||
* @return architecture name loaded
|
||||
*/
|
||||
+ (NSString*)getArch;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_ARCH_DETECT_H
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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 <sys/types.h>
|
||||
#import <sys/sysctl.h>
|
||||
#import <mach/machine.h>
|
||||
#import "ArchDetect.h"
|
||||
#import "FFmpegKitConfig.h"
|
||||
#import "FFmpegKit.h"
|
||||
#import "FFprobeKit.h"
|
||||
|
||||
@implementation ArchDetect
|
||||
|
||||
+ (void)initialize {
|
||||
[FFmpegKit class];
|
||||
[FFmpegKitConfig class];
|
||||
[FFprobeKit class];
|
||||
}
|
||||
|
||||
+ (NSString*)getCpuArch {
|
||||
NSMutableString* cpu = [[NSMutableString alloc] init];
|
||||
size_t size;
|
||||
cpu_type_t type;
|
||||
cpu_subtype_t subtype;
|
||||
size = sizeof(type);
|
||||
sysctlbyname("hw.cputype", &type, &size, nil, 0);
|
||||
|
||||
size = sizeof(subtype);
|
||||
sysctlbyname("hw.cpusubtype", &subtype, &size, nil, 0);
|
||||
|
||||
if (type == CPU_TYPE_X86_64) {
|
||||
[cpu appendString:@"x86_64"];
|
||||
|
||||
} else if (type == CPU_TYPE_X86) {
|
||||
[cpu appendString:@"x86"];
|
||||
|
||||
switch(subtype) {
|
||||
case CPU_SUBTYPE_X86_64_H:
|
||||
[cpu appendString:@"_64h"];
|
||||
break;
|
||||
case CPU_SUBTYPE_X86_64_ALL:
|
||||
[cpu appendString:@"_64all"];
|
||||
break;
|
||||
case CPU_SUBTYPE_X86_ARCH1:
|
||||
[cpu appendString:@"_arch1"];
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (type == CPU_TYPE_I386) {
|
||||
[cpu appendString:@"i386"];
|
||||
|
||||
} else if (type == CPU_TYPE_ARM64) {
|
||||
[cpu appendString:@"arm64"];
|
||||
|
||||
switch(subtype) {
|
||||
case CPU_SUBTYPE_ARM64_V8:
|
||||
[cpu appendString:@"v8"];
|
||||
break;
|
||||
|
||||
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 120100
|
||||
case CPU_SUBTYPE_ARM64E:
|
||||
[cpu appendString:@"e"];
|
||||
break;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
} else if (type == CPU_TYPE_ARM) {
|
||||
[cpu appendString:@"arm"];
|
||||
|
||||
switch(subtype) {
|
||||
case CPU_SUBTYPE_ARM_XSCALE:
|
||||
[cpu appendString:@"xscale"];
|
||||
break;
|
||||
case CPU_SUBTYPE_ARM_V4T:
|
||||
[cpu appendString:@"v4t"];
|
||||
break;
|
||||
case CPU_SUBTYPE_ARM_V5TEJ:
|
||||
[cpu appendString:@"v5tej"];
|
||||
break;
|
||||
case CPU_SUBTYPE_ARM_V6:
|
||||
[cpu appendString:@"v6"];
|
||||
break;
|
||||
case CPU_SUBTYPE_ARM_V6M:
|
||||
[cpu appendString:@"v6m"];
|
||||
break;
|
||||
case CPU_SUBTYPE_ARM_V7:
|
||||
[cpu appendString:@"v7"];
|
||||
break;
|
||||
case CPU_SUBTYPE_ARM_V7EM:
|
||||
[cpu appendString:@"v7em"];
|
||||
break;
|
||||
case CPU_SUBTYPE_ARM_V7F:
|
||||
[cpu appendString:@"v7f"];
|
||||
break;
|
||||
case CPU_SUBTYPE_ARM_V7K:
|
||||
[cpu appendString:@"v7k"];
|
||||
break;
|
||||
case CPU_SUBTYPE_ARM_V7M:
|
||||
[cpu appendString:@"v7m"];
|
||||
break;
|
||||
case CPU_SUBTYPE_ARM_V7S:
|
||||
[cpu appendString:@"v7s"];
|
||||
break;
|
||||
#ifndef FFMPEG_KIT_LTS
|
||||
case CPU_SUBTYPE_ARM_V8:
|
||||
[cpu appendString:@"v8"];
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 120100
|
||||
} else if (type == CPU_TYPE_ARM64_32) {
|
||||
[cpu appendString:@"arm64_32"];
|
||||
|
||||
switch(subtype) {
|
||||
case CPU_SUBTYPE_ARM64_32_V8:
|
||||
[cpu appendString:@"v8"];
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
[cpu appendString:[NSString stringWithFormat:@"%d", type]];
|
||||
}
|
||||
|
||||
return cpu;
|
||||
}
|
||||
|
||||
+ (NSString*)getArch {
|
||||
NSMutableString *arch = [[NSMutableString alloc] init];
|
||||
|
||||
#ifdef FFMPEG_KIT_ARMV7
|
||||
[arch appendString:@"armv7"];
|
||||
#elif FFMPEG_KIT_ARMV7S
|
||||
[arch appendString:@"armv7s"];
|
||||
#elif FFMPEG_KIT_ARM64
|
||||
[arch appendString:@"arm64"];
|
||||
#elif FFMPEG_KIT_ARM64_MAC_CATALYST
|
||||
[arch appendString:@"arm64_mac_catalyst"];
|
||||
#elif FFMPEG_KIT_ARM64_SIMULATOR
|
||||
[arch appendString:@"arm64_simulator"];
|
||||
#elif FFMPEG_KIT_ARM64E
|
||||
[arch appendString:@"arm64e"];
|
||||
#elif FFMPEG_KIT_I386
|
||||
[arch appendString:@"i386"];
|
||||
#elif FFMPEG_KIT_X86_64
|
||||
[arch appendString:@"x86_64"];
|
||||
#elif FFMPEG_KIT_X86_64_MAC_CATALYST
|
||||
[arch appendString:@"x86_64_mac_catalyst"];
|
||||
#endif
|
||||
|
||||
return arch;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2020-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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_ATOMIC_LONG_H
|
||||
#define FFMPEG_KIT_ATOMIC_LONG_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* Represents an atomic long data type.
|
||||
*/
|
||||
@interface AtomicLong : NSObject
|
||||
|
||||
- (instancetype)initWithValue:(long)value;
|
||||
|
||||
- (long)incrementAndGet;
|
||||
|
||||
- (long)getAndIncrement;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_ATOMIC_LONG_H
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2020-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 "AtomicLong.h"
|
||||
|
||||
@implementation AtomicLong {
|
||||
atomic_int _value;
|
||||
}
|
||||
|
||||
- (instancetype)initWithValue:(long)value {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
atomic_init(&_value, value);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (long)incrementAndGet {
|
||||
return (long)atomic_fetch_add(&_value, 1) + 1;
|
||||
}
|
||||
|
||||
- (long)getAndIncrement {
|
||||
return (long)atomic_fetch_add(&_value, 1);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_CHAPTER_H
|
||||
#define FFMPEG_KIT_CHAPTER_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern NSString* const ChapterKeyId;
|
||||
extern NSString* const ChapterKeyTimeBase;
|
||||
extern NSString* const ChapterKeyStart;
|
||||
extern NSString* const ChapterKeyStartTime;
|
||||
extern NSString* const ChapterKeyEnd;
|
||||
extern NSString* const ChapterKeyEndTime;
|
||||
extern NSString* const ChapterKeyTags;
|
||||
|
||||
/**
|
||||
* Chapter class.
|
||||
*/
|
||||
@interface Chapter : NSObject
|
||||
|
||||
- (instancetype)init:(NSDictionary*)chapterDictionary;
|
||||
|
||||
- (NSNumber*)getId;
|
||||
|
||||
- (NSString*)getTimeBase;
|
||||
|
||||
- (NSNumber*)getStart;
|
||||
|
||||
- (NSString*)getStartTime;
|
||||
|
||||
- (NSNumber*)getEnd;
|
||||
|
||||
- (NSString*)getEndTime;
|
||||
|
||||
- (NSDictionary*)getTags;
|
||||
|
||||
/**
|
||||
* Returns the chapter property associated with the key.
|
||||
*
|
||||
* @return chapter property as string or nil if the key is not found
|
||||
*/
|
||||
- (NSString*)getStringProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns the chapter property associated with the key.
|
||||
*
|
||||
* @return chapter property as number or nil if the key is not found
|
||||
*/
|
||||
- (NSNumber*)getNumberProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns the chapter property associated with the key.
|
||||
*
|
||||
* @return chapter property as id or nil if the key is not found
|
||||
*/
|
||||
- (id)getProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns all chapter properties defined.
|
||||
*
|
||||
* @return all chapter properties in a dictionary or nil if no properties are defined
|
||||
*/
|
||||
- (NSDictionary*)getAllProperties;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_CHAPTER_H
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 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 "Chapter.h"
|
||||
|
||||
NSString* const ChapterKeyId = @"id";
|
||||
NSString* const ChapterKeyTimeBase = @"time_base";
|
||||
NSString* const ChapterKeyStart = @"start";
|
||||
NSString* const ChapterKeyStartTime = @"start_time";
|
||||
NSString* const ChapterKeyEnd = @"end";
|
||||
NSString* const ChapterKeyEndTime = @"end_time";
|
||||
NSString* const ChapterKeyTags = @"tags";
|
||||
|
||||
@implementation Chapter {
|
||||
|
||||
/**
|
||||
* Stores all properties.
|
||||
*/
|
||||
NSDictionary *dictionary;
|
||||
|
||||
}
|
||||
|
||||
- (instancetype)init:(NSDictionary*)chapterDictionary {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
dictionary = chapterDictionary;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSNumber*)getId {
|
||||
return [self getNumberProperty:ChapterKeyId];
|
||||
}
|
||||
|
||||
- (NSString*)getTimeBase {
|
||||
return [self getStringProperty:ChapterKeyTimeBase];
|
||||
}
|
||||
|
||||
- (NSNumber*)getStart {
|
||||
return [self getNumberProperty:ChapterKeyStart];
|
||||
}
|
||||
|
||||
- (NSString*)getStartTime {
|
||||
return [self getStringProperty:ChapterKeyStartTime];
|
||||
}
|
||||
|
||||
- (NSNumber*)getEnd {
|
||||
return [self getNumberProperty:ChapterKeyEnd];
|
||||
}
|
||||
|
||||
- (NSString*)getEndTime {
|
||||
return [self getStringProperty:ChapterKeyEndTime];
|
||||
}
|
||||
|
||||
- (NSDictionary*)getTags {
|
||||
return [self getProperty:ChapterKeyTags];
|
||||
}
|
||||
|
||||
- (NSString*)getStringProperty:(NSString*)key {
|
||||
NSDictionary* allProperties = [self getAllProperties];
|
||||
if (allProperties == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return allProperties[key];
|
||||
}
|
||||
|
||||
- (NSNumber*)getNumberProperty:(NSString*)key {
|
||||
NSDictionary* allProperties = [self getAllProperties];
|
||||
if (allProperties == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return allProperties[key];
|
||||
}
|
||||
|
||||
- (id)getProperty:(NSString*)key {
|
||||
NSDictionary* allProperties = [self getAllProperties];
|
||||
if (allProperties == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return allProperties[key];
|
||||
}
|
||||
|
||||
- (NSDictionary*)getAllProperties {
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_H
|
||||
#define FFMPEG_KIT_H
|
||||
|
||||
#import <string.h>
|
||||
#import <stdlib.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "LogCallback.h"
|
||||
#import "FFmpegSession.h"
|
||||
#import "StatisticsCallback.h"
|
||||
|
||||
/**
|
||||
* <p>Main class to run <code>FFmpeg</code> commands. Supports executing commands both synchronously and
|
||||
* asynchronously.
|
||||
* <pre>
|
||||
* FFmpegSession *session = [FFmpegKit execute:@"-i file1.mp4 -c:v libxvid file1.avi"];
|
||||
*
|
||||
* FFmpegSession *asyncSession = [FFmpegKit executeAsync:@"-i file1.mp4 -c:v libxvid file1.avi" withCompleteCallback:completeCallback];
|
||||
* </pre>
|
||||
* <p>Provides overloaded <code>execute</code> methods to define session specific callbacks.
|
||||
* <pre>
|
||||
* FFmpegSession *asyncSession = [FFmpegKit executeAsync:@"-i file1.mp4 -c:v libxvid file1.avi" withCompleteCallback:completeCallback withLogCallback:logCallback withStatisticsCallback:statisticsCallback];
|
||||
* </pre>
|
||||
*/
|
||||
@interface FFmpegKit : NSObject
|
||||
|
||||
/**
|
||||
* <p>Synchronously executes FFmpeg with arguments provided.
|
||||
*
|
||||
* @param arguments FFmpeg command options/arguments as string array
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeWithArguments:(NSArray*)arguments;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFmpeg command options/arguments as string array
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFmpeg command options/arguments as string array
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param statisticsCallback callback that will receive statistics
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFmpeg command options/arguments as string array
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFmpeg command options/arguments as string array
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param statisticsCallback callback that will receive statistics
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Synchronously executes FFmpeg command provided. Space character is used to split command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside
|
||||
* your command.
|
||||
*
|
||||
* @param command FFmpeg command
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)execute:(NSString*)command;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFmpeg command
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeAsync:(NSString*)command withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFmpeg command
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param statisticsCallback callback that will receive statistics
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeAsync:(NSString*)command withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFmpeg command
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeAsync:(NSString*)command withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFmpeg command
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param statisticsCallback callback that will receive statistics
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeAsync:(NSString*)command withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Cancels all running sessions.
|
||||
*
|
||||
* <p>This method does not wait for termination to complete and returns immediately.
|
||||
*/
|
||||
+ (void)cancel;
|
||||
|
||||
/**
|
||||
* <p>Cancels the session specified with <code>sessionId</code>.
|
||||
*
|
||||
* <p>This method does not wait for termination to complete and returns immediately.
|
||||
*
|
||||
* @param sessionId id of the session that will be cancelled
|
||||
*/
|
||||
+ (void)cancel:(long)sessionId;
|
||||
|
||||
/**
|
||||
* <p>Lists all FFmpeg sessions in the session history.
|
||||
*
|
||||
* @return all FFmpeg sessions in the session history
|
||||
*/
|
||||
+ (NSArray*)listSessions;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_H
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2022 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 "fftools_ffmpeg.h"
|
||||
#import "ArchDetect.h"
|
||||
#import "AtomicLong.h"
|
||||
#import "FFmpegKit.h"
|
||||
#import "FFmpegKitConfig.h"
|
||||
#import "Packages.h"
|
||||
|
||||
@implementation FFmpegKit
|
||||
|
||||
+ (void)initialize {
|
||||
NSLog(@"Loading ffmpeg-kit.\n");
|
||||
|
||||
[FFmpegKitConfig class];
|
||||
|
||||
NSLog(@"Loaded ffmpeg-kit-%@-%@-%@-%@.\n", [Packages getPackageName], [ArchDetect getArch], [FFmpegKitConfig getVersion], [FFmpegKitConfig getBuildDate]);
|
||||
}
|
||||
|
||||
+ (FFmpegSession*)executeWithArguments:(NSArray*)arguments {
|
||||
FFmpegSession* session = [FFmpegSession create:arguments];
|
||||
[FFmpegKitConfig ffmpegExecute:session];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback {
|
||||
FFmpegSession* session = [FFmpegSession create:arguments withCompleteCallback:completeCallback];
|
||||
[FFmpegKitConfig asyncFFmpegExecute:session];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback {
|
||||
FFmpegSession* session = [FFmpegSession create:arguments withCompleteCallback:completeCallback withLogCallback:logCallback withStatisticsCallback:statisticsCallback];
|
||||
[FFmpegKitConfig asyncFFmpegExecute:session];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback onDispatchQueue:(dispatch_queue_t)queue {
|
||||
FFmpegSession* session = [FFmpegSession create:arguments withCompleteCallback:completeCallback];
|
||||
[FFmpegKitConfig asyncFFmpegExecute:session onDispatchQueue:queue];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback onDispatchQueue:(dispatch_queue_t)queue {
|
||||
FFmpegSession* session = [FFmpegSession create:arguments withCompleteCallback:completeCallback withLogCallback:logCallback withStatisticsCallback:statisticsCallback];
|
||||
[FFmpegKitConfig asyncFFmpegExecute:session onDispatchQueue:queue];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFmpegSession*)execute:(NSString*)command {
|
||||
FFmpegSession* session = [FFmpegSession create:[FFmpegKitConfig parseArguments:command]];
|
||||
[FFmpegKitConfig ffmpegExecute:session];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFmpegSession*)executeAsync:(NSString*)command withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback {
|
||||
FFmpegSession* session = [FFmpegSession create:[FFmpegKitConfig parseArguments:command] withCompleteCallback:completeCallback];
|
||||
[FFmpegKitConfig asyncFFmpegExecute:session];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFmpegSession*)executeAsync:(NSString*)command withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback {
|
||||
FFmpegSession* session = [FFmpegSession create:[FFmpegKitConfig parseArguments:command] withCompleteCallback:completeCallback withLogCallback:logCallback withStatisticsCallback:statisticsCallback];
|
||||
[FFmpegKitConfig asyncFFmpegExecute:session];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFmpegSession*)executeAsync:(NSString*)command withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback onDispatchQueue:(dispatch_queue_t)queue {
|
||||
FFmpegSession* session = [FFmpegSession create:[FFmpegKitConfig parseArguments:command] withCompleteCallback:completeCallback];
|
||||
[FFmpegKitConfig asyncFFmpegExecute:session onDispatchQueue:queue];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFmpegSession*)executeAsync:(NSString*)command withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback onDispatchQueue:(dispatch_queue_t)queue {
|
||||
FFmpegSession* session = [FFmpegSession create:[FFmpegKitConfig parseArguments:command] withCompleteCallback:completeCallback withLogCallback:logCallback withStatisticsCallback:statisticsCallback];
|
||||
[FFmpegKitConfig asyncFFmpegExecute:session onDispatchQueue:queue];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (void)cancel {
|
||||
|
||||
/*
|
||||
* ZERO (0) IS A SPECIAL SESSION ID
|
||||
* WHEN IT IS PASSED TO THIS METHOD, A SIGINT IS GENERATED WHICH CANCELS ALL ONGOING SESSIONS
|
||||
*/
|
||||
cancel_operation(0);
|
||||
}
|
||||
|
||||
+ (void)cancel:(long)sessionId {
|
||||
cancel_operation(sessionId);
|
||||
}
|
||||
|
||||
+ (NSArray*)listSessions {
|
||||
return [FFmpegKitConfig getFFmpegSessions];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,462 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_CONFIG_H
|
||||
#define FFMPEG_KIT_CONFIG_H
|
||||
|
||||
#import <stdio.h>
|
||||
#import <pthread.h>
|
||||
#import <unistd.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FFmpegSession.h"
|
||||
#import "FFprobeSession.h"
|
||||
#import "LogCallback.h"
|
||||
#import "MediaInformationSession.h"
|
||||
#import "StatisticsCallback.h"
|
||||
|
||||
/** Global library version */
|
||||
extern NSString* const FFmpegKitVersion;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, Signal) {
|
||||
SignalInt = 2,
|
||||
SignalQuit = 3,
|
||||
SignalPipe = 13,
|
||||
SignalTerm = 15,
|
||||
SignalXcpu = 24
|
||||
};
|
||||
|
||||
/**
|
||||
* <p>Configuration class of <code>FFmpegKit</code> library. Allows customizing the global library
|
||||
* options. Provides helper methods to support additional resources.
|
||||
*/
|
||||
@interface FFmpegKitConfig : NSObject
|
||||
|
||||
/**
|
||||
* <p>Enables log and statistics redirection.
|
||||
*
|
||||
* <p>When redirection is enabled FFmpeg/FFprobe logs are redirected to NSLog and sessions
|
||||
* collect log and statistics entries for the executions. It is possible to define global or
|
||||
* session specific log/statistics callbacks as well.
|
||||
*
|
||||
* <p>Note that redirection is enabled by default. If you do not want to use its functionality
|
||||
* please use disableRedirection method to disable it.
|
||||
*/
|
||||
+ (void)enableRedirection;
|
||||
|
||||
/**
|
||||
* <p>Disables log and statistics redirection.
|
||||
*
|
||||
* <p>When redirection is disabled logs are printed to stderr, all logs and statistics
|
||||
* callbacks are disabled and <code>FFprobe</code>'s <code>getMediaInformation</code> methods
|
||||
* do not work.
|
||||
*/
|
||||
+ (void)disableRedirection;
|
||||
|
||||
/**
|
||||
* <p>Sets and overrides <code>fontconfig</code> configuration directory.
|
||||
*
|
||||
* @param path directory that contains fontconfig configuration (fonts.conf)
|
||||
* @return zero on success, non-zero on error
|
||||
*/
|
||||
+ (int)setFontconfigConfigurationPath:(NSString*)path;
|
||||
|
||||
/**
|
||||
* <p>Registers the fonts inside the given path, so they become available to use in FFmpeg
|
||||
* filters.
|
||||
*
|
||||
* <p>Note that you need to build <code>FFmpegKit</code> with <code>fontconfig</code>
|
||||
* enabled or use a prebuilt package with <code>fontconfig</code> inside to be able to use
|
||||
* fonts in <code>FFmpeg</code>.
|
||||
*
|
||||
* @param fontDirectoryPath directory that contains fonts (.ttf and .otf files)
|
||||
* @param fontNameMapping custom font name mappings, useful to access your fonts with more
|
||||
* friendly names
|
||||
*/
|
||||
+ (void)setFontDirectory:(NSString*)fontDirectoryPath with:(NSDictionary*)fontNameMapping;
|
||||
|
||||
/**
|
||||
* <p>Registers the fonts inside the given array of font directories, so they become available
|
||||
* to use in FFmpeg filters.
|
||||
*
|
||||
* <p>Note that you need to build <code>FFmpegKit</code> with <code>fontconfig</code>
|
||||
* enabled or use a prebuilt package with <code>fontconfig</code> inside to be able to use
|
||||
* fonts in <code>FFmpeg</code>.
|
||||
*
|
||||
* @param fontDirectoryList array of directories that contain fonts (.ttf and .otf files)
|
||||
* @param fontNameMapping custom font name mappings, useful to access your fonts with more
|
||||
* friendly names
|
||||
*/
|
||||
+ (void)setFontDirectoryList:(NSArray*)fontDirectoryList with:(NSDictionary*)fontNameMapping;
|
||||
|
||||
/**
|
||||
* <p>Creates a new named pipe to use in <code>FFmpeg</code> operations.
|
||||
*
|
||||
* <p>Please note that creator is responsible of closing created pipes.
|
||||
*
|
||||
* @return the full path of the named pipe
|
||||
*/
|
||||
+ (NSString*)registerNewFFmpegPipe;
|
||||
|
||||
/**
|
||||
* <p>Closes a previously created <code>FFmpeg</code> pipe.
|
||||
*
|
||||
* @param ffmpegPipePath full path of the FFmpeg pipe
|
||||
*/
|
||||
+ (void)closeFFmpegPipe:(NSString*)ffmpegPipePath;
|
||||
|
||||
/**
|
||||
* <p>Returns the version of FFmpeg bundled within <code>FFmpegKit</code> library.
|
||||
*
|
||||
* @return the version of FFmpeg
|
||||
*/
|
||||
+ (NSString*)getFFmpegVersion;
|
||||
|
||||
/**
|
||||
* Returns FFmpegKit library version.
|
||||
*
|
||||
* @return FFmpegKit version
|
||||
*/
|
||||
+ (NSString*)getVersion;
|
||||
|
||||
/**
|
||||
* <p>Returns whether FFmpegKit release is a Long Term Release or not.
|
||||
*
|
||||
* @return true/yes or false/no
|
||||
*/
|
||||
+ (int)isLTSBuild;
|
||||
|
||||
/**
|
||||
* Returns FFmpegKit library build date.
|
||||
*
|
||||
* @return FFmpegKit library build date
|
||||
*/
|
||||
+ (NSString*)getBuildDate;
|
||||
|
||||
/**
|
||||
* <p>Sets an environment variable.
|
||||
*
|
||||
* @param variableName environment variable name
|
||||
* @param variableValue environment variable value
|
||||
* @return zero on success, non-zero on error
|
||||
*/
|
||||
+ (int)setEnvironmentVariable:(NSString*)variableName value:(NSString*)variableValue;
|
||||
|
||||
/**
|
||||
* <p>Registers a new ignored signal. Ignored signals are not handled by <code>FFmpegKit</code>
|
||||
* library.
|
||||
*
|
||||
* @param signal signal to be ignored
|
||||
*/
|
||||
+ (void)ignoreSignal:(Signal)signal;
|
||||
|
||||
/**
|
||||
* <p>Synchronously executes the FFmpeg session provided.
|
||||
*
|
||||
* @param ffmpegSession FFmpeg session which includes command options/arguments
|
||||
*/
|
||||
+ (void)ffmpegExecute:(FFmpegSession*)ffmpegSession;
|
||||
|
||||
/**
|
||||
* <p>Synchronously executes the FFprobe session provided.
|
||||
*
|
||||
* @param ffprobeSession FFprobe session which includes command options/arguments
|
||||
*/
|
||||
+ (void)ffprobeExecute:(FFprobeSession*)ffprobeSession;
|
||||
|
||||
/**
|
||||
* <p>Synchronously executes the media information session provided.
|
||||
*
|
||||
* @param mediaInformationSession media information session which includes command options/arguments
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
*/
|
||||
+ (void)getMediaInformationExecute:(MediaInformationSession*)mediaInformationSession withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution for the given session.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param ffmpegSession FFmpeg session which includes command options/arguments
|
||||
*/
|
||||
+ (void)asyncFFmpegExecute:(FFmpegSession*)ffmpegSession;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution for the given session.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param ffmpegSession FFmpeg session which includes command options/arguments
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
*/
|
||||
+ (void)asyncFFmpegExecute:(FFmpegSession*)ffmpegSession onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given session.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param ffprobeSession FFprobe session which includes command options/arguments
|
||||
*/
|
||||
+ (void)asyncFFprobeExecute:(FFprobeSession*)ffprobeSession;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given session.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param ffprobeSession FFprobe session which includes command options/arguments
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
*/
|
||||
+ (void)asyncFFprobeExecute:(FFprobeSession*)ffprobeSession onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given media information session.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param mediaInformationSession media information session which includes command options/arguments
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
*/
|
||||
+ (void)asyncGetMediaInformationExecute:(MediaInformationSession*)mediaInformationSession withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given media information session.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param mediaInformationSession media information session which includes command options/arguments
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
*/
|
||||
+ (void)asyncGetMediaInformationExecute:(MediaInformationSession*)mediaInformationSession onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Sets a global log callback to redirect FFmpeg/FFprobe logs.
|
||||
*
|
||||
* @param logCallback log callback or nil to disable a previously defined log callback
|
||||
*/
|
||||
+ (void)enableLogCallback:(LogCallback)logCallback;
|
||||
|
||||
/**
|
||||
* <p>Sets a global statistics callback to redirect FFmpeg statistics.
|
||||
*
|
||||
* @param statisticsCallback statistics callback or nil to disable a previously defined statistics callback
|
||||
*/
|
||||
+ (void)enableStatisticsCallback:(StatisticsCallback)statisticsCallback;
|
||||
|
||||
/**
|
||||
* <p>Sets a global FFmpegSessionCompleteCallback to receive execution results for FFmpeg sessions.
|
||||
*
|
||||
* @param ffmpegSessionCompleteCallback complete callback or nil to disable a previously defined callback
|
||||
*/
|
||||
+ (void)enableFFmpegSessionCompleteCallback:(FFmpegSessionCompleteCallback)ffmpegSessionCompleteCallback;
|
||||
|
||||
/**
|
||||
* <p>Returns the global FFmpegSessionCompleteCallback set.
|
||||
*
|
||||
* @return global FFmpegSessionCompleteCallback or nil if it is not set
|
||||
*/
|
||||
+ (FFmpegSessionCompleteCallback)getFFmpegSessionCompleteCallback;
|
||||
|
||||
/**
|
||||
* <p>Sets a global FFprobeSessionCompleteCallback to receive execution results for FFprobe sessions.
|
||||
*
|
||||
* @param ffprobeSessionCompleteCallback complete callback or nil to disable a previously defined callback
|
||||
*/
|
||||
+ (void)enableFFprobeSessionCompleteCallback:(FFprobeSessionCompleteCallback)ffprobeSessionCompleteCallback;
|
||||
|
||||
/**
|
||||
* <p>Returns the global FFprobeSessionCompleteCallback set.
|
||||
*
|
||||
* @return global FFprobeSessionCompleteCallback or nil if it is not set
|
||||
*/
|
||||
+ (FFprobeSessionCompleteCallback)getFFprobeSessionCompleteCallback;
|
||||
|
||||
/**
|
||||
* <p>Sets a global MediaInformationSessionCompleteCallback to receive execution results for MediaInformation sessions.
|
||||
*
|
||||
* @param mediaInformationSessionCompleteCallback complete callback or nil to disable a previously defined
|
||||
* callback
|
||||
*/
|
||||
+ (void)enableMediaInformationSessionCompleteCallback:(MediaInformationSessionCompleteCallback)mediaInformationSessionCompleteCallback;
|
||||
|
||||
/**
|
||||
* <p>Returns the global MediaInformationSessionCompleteCallback set.
|
||||
*
|
||||
* @return global MediaInformationSessionCompleteCallback or nil if it is not set
|
||||
*/
|
||||
+ (MediaInformationSessionCompleteCallback)getMediaInformationSessionCompleteCallback;
|
||||
|
||||
/**
|
||||
* Returns the current log level.
|
||||
*
|
||||
* @return current log level
|
||||
*/
|
||||
+ (int)getLogLevel;
|
||||
|
||||
/**
|
||||
* Sets the log level.
|
||||
*
|
||||
* @param level new log level
|
||||
*/
|
||||
+ (void)setLogLevel:(int)level;
|
||||
|
||||
/**
|
||||
* Converts int log level to string.
|
||||
*
|
||||
* @param level value
|
||||
* @return string value
|
||||
*/
|
||||
+ (NSString*)logLevelToString:(int)level;
|
||||
|
||||
/**
|
||||
* Returns the session history size.
|
||||
*
|
||||
* @return session history size
|
||||
*/
|
||||
+ (int)getSessionHistorySize;
|
||||
|
||||
/**
|
||||
* Sets the session history size.
|
||||
*
|
||||
* @param sessionHistorySize session history size, should be smaller than 1000
|
||||
*/
|
||||
+ (void)setSessionHistorySize:(int)sessionHistorySize;
|
||||
|
||||
/**
|
||||
* Returns the session specified with <code>sessionId</code> from the session history.
|
||||
*
|
||||
* @param sessionId session identifier
|
||||
* @return session specified with sessionId or nil if it is not found in the history
|
||||
*/
|
||||
+ (id<Session>)getSession:(long)sessionId;
|
||||
|
||||
/**
|
||||
* Returns the last session created from the session history.
|
||||
*
|
||||
* @return the last session created or nil if session history is empty
|
||||
*/
|
||||
+ (id<Session>)getLastSession;
|
||||
|
||||
/**
|
||||
* Returns the last session completed from the session history.
|
||||
*
|
||||
* @return the last session completed. If there are no completed sessions in the history this
|
||||
* method will return nil
|
||||
*/
|
||||
+ (id<Session>)getLastCompletedSession;
|
||||
|
||||
/**
|
||||
* <p>Returns all sessions in the session history.
|
||||
*
|
||||
* @return all sessions in the session history
|
||||
*/
|
||||
+ (NSArray*)getSessions;
|
||||
|
||||
/**
|
||||
* <p>Clears all, including ongoing, sessions in the session history.
|
||||
* <p>Note that callbacks cannot be triggered for deleted sessions.
|
||||
*/
|
||||
+ (void)clearSessions;
|
||||
|
||||
/**
|
||||
* <p>Returns all FFmpeg sessions in the session history.
|
||||
*
|
||||
* @return all FFmpeg sessions in the session history
|
||||
*/
|
||||
+ (NSArray*)getFFmpegSessions;
|
||||
|
||||
/**
|
||||
* <p>Returns all FFprobe sessions in the session history.
|
||||
*
|
||||
* @return all FFprobe sessions in the session history
|
||||
*/
|
||||
+ (NSArray*)getFFprobeSessions;
|
||||
|
||||
/**
|
||||
* <p>Returns all MediaInformation sessions in the session history.
|
||||
*
|
||||
* @return all MediaInformation sessions in the session history
|
||||
*/
|
||||
+ (NSArray*)getMediaInformationSessions;
|
||||
|
||||
/**
|
||||
* <p>Returns sessions that have the given state.
|
||||
*
|
||||
* @return sessions that have the given state from the session history
|
||||
*/
|
||||
+ (NSArray*)getSessionsByState:(SessionState)state;
|
||||
|
||||
/**
|
||||
* Returns the active log redirection strategy.
|
||||
*
|
||||
* @return log redirection strategy
|
||||
*/
|
||||
+ (LogRedirectionStrategy)getLogRedirectionStrategy;
|
||||
|
||||
/**
|
||||
* <p>Sets the log redirection strategy
|
||||
*
|
||||
* @param logRedirectionStrategy log redirection strategy
|
||||
*/
|
||||
+ (void)setLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy;
|
||||
|
||||
/**
|
||||
* <p>Returns the number of async messages that are not transmitted to the callbacks for
|
||||
* this session.
|
||||
*
|
||||
* @param sessionId id of the session
|
||||
* @return number of async messages that are not transmitted to the callbacks for this session
|
||||
*/
|
||||
+ (int)messagesInTransmit:(long)sessionId;
|
||||
|
||||
/**
|
||||
* Converts session state to string.
|
||||
*
|
||||
* @param state session state
|
||||
* @return string value
|
||||
*/
|
||||
+ (NSString*)sessionStateToString:(SessionState)state;
|
||||
|
||||
/**
|
||||
* <p>Parses the given command into arguments. Uses space character to split the arguments.
|
||||
* Supports single and double quote characters.
|
||||
*
|
||||
* @param command string command
|
||||
* @return array of arguments
|
||||
*/
|
||||
+ (NSArray*)parseArguments:(NSString*)command;
|
||||
|
||||
/**
|
||||
* <p>Concatenates arguments into a string adding a space character between two arguments.
|
||||
*
|
||||
* @param arguments arguments
|
||||
* @return concatenated string containing all arguments
|
||||
*/
|
||||
+ (NSString*)argumentsToString:(NSArray*)arguments;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_CONFIG_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_FFMPEG_SESSION_H
|
||||
#define FFMPEG_KIT_FFMPEG_SESSION_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "AbstractSession.h"
|
||||
#import "StatisticsCallback.h"
|
||||
#import "FFmpegSessionCompleteCallback.h"
|
||||
|
||||
/**
|
||||
* <p>An FFmpeg session.
|
||||
*/
|
||||
@interface FFmpegSession : AbstractSession
|
||||
|
||||
/**
|
||||
* Builds a new FFmpeg session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @return created session
|
||||
*/
|
||||
+ (instancetype)create:(NSArray*)arguments;
|
||||
|
||||
/**
|
||||
* Builds a new FFmpeg session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
* @return created session
|
||||
*/
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* Builds a new FFmpeg session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
* @param logCallback session specific log callback
|
||||
* @param statisticsCallback session specific statistics callback
|
||||
* @return created session
|
||||
*/
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback;
|
||||
|
||||
/**
|
||||
* Builds a new FFmpeg session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
* @param logCallback session specific log callback
|
||||
* @param statisticsCallback session specific statistics callback
|
||||
* @param logRedirectionStrategy session specific log redirection strategy
|
||||
* @return created session
|
||||
*/
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy;
|
||||
|
||||
/**
|
||||
* Returns the session specific statistics callback.
|
||||
*
|
||||
* @return session specific statistics callback
|
||||
*/
|
||||
- (StatisticsCallback)getStatisticsCallback;
|
||||
|
||||
/**
|
||||
* Returns the session specific complete callback.
|
||||
*
|
||||
* @return session specific complete callback
|
||||
*/
|
||||
- (FFmpegSessionCompleteCallback)getCompleteCallback;
|
||||
|
||||
/**
|
||||
* Returns all statistics entries generated for this session. If there are asynchronous
|
||||
* messages that are not delivered yet, this method waits for them until the given timeout.
|
||||
*
|
||||
* @param waitTimeout wait timeout for asynchronous messages in milliseconds
|
||||
* @return list of statistics entries generated for this session
|
||||
*/
|
||||
- (NSArray*)getAllStatisticsWithTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* Returns all statistics entries generated for this session. If there are asynchronous
|
||||
* messages that are not delivered yet, this method waits for them until
|
||||
* AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit expires.
|
||||
*
|
||||
* @return list of statistics entries generated for this session
|
||||
*/
|
||||
- (NSArray*)getAllStatistics;
|
||||
|
||||
/**
|
||||
* Returns all statistics entries delivered for this session. Note that if there are
|
||||
* asynchronous messages that are not delivered yet, this method will not wait for
|
||||
* them and will return immediately.
|
||||
*
|
||||
* @return list of statistics entries received for this session
|
||||
*/
|
||||
- (NSArray*)getStatistics;
|
||||
|
||||
/**
|
||||
* Returns the last received statistics entry.
|
||||
*
|
||||
* @return the last received statistics entry or nil if there are not any statistics entries
|
||||
* received
|
||||
*/
|
||||
- (Statistics*)getLastReceivedStatistics;
|
||||
|
||||
/**
|
||||
* Adds a new statistics entry for this session. It is invoked internally by <code>FFmpegKit</code> library methods.
|
||||
* Must not be used by user applications.
|
||||
*
|
||||
* @param statistics statistics entry
|
||||
*/
|
||||
- (void)addStatistics:(Statistics*)statistics;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_FFMPEG_SESSION_H
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#import "FFmpegSession.h"
|
||||
#import "FFmpegKitConfig.h"
|
||||
#import "LogCallback.h"
|
||||
#import "StatisticsCallback.h"
|
||||
|
||||
@implementation FFmpegSession {
|
||||
StatisticsCallback _statisticsCallback;
|
||||
FFmpegSessionCompleteCallback _completeCallback;
|
||||
NSMutableArray* _statistics;
|
||||
NSRecursiveLock* _statisticsLock;
|
||||
}
|
||||
|
||||
+ (void)initialize {
|
||||
// EMPTY INITIALIZE
|
||||
}
|
||||
|
||||
+ (instancetype)create:(NSArray*)arguments {
|
||||
return [[self alloc] init:arguments withCompleteCallback:nil withLogCallback:nil withStatisticsCallback:nil withLogRedirectionStrategy:[FFmpegKitConfig getLogRedirectionStrategy]];
|
||||
}
|
||||
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback {
|
||||
return [[self alloc] init:arguments withCompleteCallback:completeCallback withLogCallback:nil withStatisticsCallback:nil withLogRedirectionStrategy:[FFmpegKitConfig getLogRedirectionStrategy]];
|
||||
}
|
||||
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback {
|
||||
return [[self alloc] init:arguments withCompleteCallback:completeCallback withLogCallback:logCallback withStatisticsCallback:statisticsCallback withLogRedirectionStrategy:[FFmpegKitConfig getLogRedirectionStrategy]];
|
||||
}
|
||||
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy {
|
||||
return [[self alloc] init:arguments withCompleteCallback:completeCallback withLogCallback:logCallback withStatisticsCallback:statisticsCallback withLogRedirectionStrategy:logRedirectionStrategy];
|
||||
}
|
||||
|
||||
- (instancetype)init:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy {
|
||||
|
||||
self = [super init:arguments withLogCallback:logCallback withLogRedirectionStrategy:logRedirectionStrategy];
|
||||
|
||||
if (self) {
|
||||
_statisticsCallback = statisticsCallback;
|
||||
_completeCallback = completeCallback;
|
||||
_statistics = [[NSMutableArray alloc] init];
|
||||
_statisticsLock = [[NSRecursiveLock alloc] init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (StatisticsCallback)getStatisticsCallback {
|
||||
return _statisticsCallback;
|
||||
}
|
||||
|
||||
- (FFmpegSessionCompleteCallback)getCompleteCallback {
|
||||
return _completeCallback;
|
||||
}
|
||||
|
||||
- (NSArray*)getAllStatisticsWithTimeout:(int)waitTimeout {
|
||||
[self waitForAsynchronousMessagesInTransmit:waitTimeout];
|
||||
|
||||
if ([self thereAreAsynchronousMessagesInTransmit]) {
|
||||
NSLog(@"getAllStatisticsWithTimeout was called to return all statistics but there are still statistics being transmitted for session id %ld.", [self getSessionId]);
|
||||
}
|
||||
|
||||
return [self getStatistics];
|
||||
}
|
||||
|
||||
- (NSArray*)getAllStatistics {
|
||||
return [self getAllStatisticsWithTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit];
|
||||
}
|
||||
|
||||
- (NSArray*)getStatistics {
|
||||
[_statisticsLock lock];
|
||||
NSArray* statisticsCopy = [_statistics copy];
|
||||
[_statisticsLock unlock];
|
||||
|
||||
return statisticsCopy;
|
||||
}
|
||||
|
||||
- (Statistics*)getLastReceivedStatistics {
|
||||
Statistics* lastStatistics = nil;
|
||||
|
||||
[_statisticsLock lock];
|
||||
if ([_statistics count] > 0) {
|
||||
lastStatistics = [_statistics objectAtIndex:[_statistics count] - 1];
|
||||
}
|
||||
[_statisticsLock unlock];
|
||||
|
||||
return lastStatistics;
|
||||
}
|
||||
|
||||
- (void)addStatistics:(Statistics*)statistics {
|
||||
[_statisticsLock lock];
|
||||
[_statistics addObject:statistics];
|
||||
[_statisticsLock unlock];
|
||||
}
|
||||
|
||||
- (BOOL)isFFmpeg {
|
||||
return true;
|
||||
}
|
||||
|
||||
- (BOOL)isFFprobe {
|
||||
return false;
|
||||
}
|
||||
|
||||
- (BOOL)isMediaInformation {
|
||||
return false;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2020-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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_FFMPEG_SESSION_COMPLETE_CALLBACK_H
|
||||
#define FFMPEG_KIT_FFMPEG_SESSION_COMPLETE_CALLBACK_H
|
||||
|
||||
@class FFmpegSession;
|
||||
|
||||
/**
|
||||
* <p>Callback function that is invoked when an asynchronous <code>FFmpeg</code> session has ended.
|
||||
* <p>Session has either SessionStateCompleted or SessionStateFailed state when
|
||||
* the callback is invoked.
|
||||
* <p>If it has SessionStateCompleted state, <code>ReturnCode</code> should be checked to
|
||||
* see the execution result.
|
||||
* <p>If <code>getState</code> returns SessionStateFailed then
|
||||
* <code>getFailStackTrace</code> should be used to get the failure reason.
|
||||
* <pre>
|
||||
* switch ([session getState]) {
|
||||
* case SessionStateCompleted:
|
||||
* ReturnCode *returnCode = [session getReturnCode];
|
||||
* break;
|
||||
* case SessionStateFailed:
|
||||
* NSString *failStackTrace = [session getFailStackTrace];
|
||||
* break;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param session session of the completed execution
|
||||
*/
|
||||
typedef void (^FFmpegSessionCompleteCallback)(FFmpegSession* session);
|
||||
|
||||
#import "FFmpegSession.h"
|
||||
|
||||
#endif // FFMPEG_KIT_FFMPEG_SESSION_COMPLETE_CALLBACK_H
|
||||
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Copyright (c) 2020-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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFPROBE_KIT_H
|
||||
#define FFPROBE_KIT_H
|
||||
|
||||
#import <string.h>
|
||||
#import <stdlib.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FFprobeSession.h"
|
||||
#import "MediaInformationJsonParser.h"
|
||||
|
||||
/**
|
||||
* <p>Main class to run <code>FFprobe</code> commands. Supports executing commands both synchronously and
|
||||
* asynchronously.
|
||||
* <pre>
|
||||
* FFprobeSession *session = [FFprobeKit execute:@"-hide_banner -v error -show_entries format=size -of default=noprint_wrappers=1 file1.mp4"];
|
||||
*
|
||||
* FFprobeSession *asyncSession = [FFprobeKit executeAsync:@"-hide_banner -v error -show_entries format=size -of default=noprint_wrappers=1 file1.mp4" withCompleteCallback:completeCallback];
|
||||
* </pre>
|
||||
* <p>Provides overloaded <code>execute</code> methods to define session specific callbacks.
|
||||
* <pre>
|
||||
* FFprobeSession *session = [FFprobeKit executeAsync:@"-hide_banner -v error -show_entries format=size -of default=noprint_wrappers=1 file1.mp4" withCompleteCallback:completeCallback withLogCallback:logCallback];
|
||||
* </pre>
|
||||
* <p>It can extract media information for a file or a url, using getMediaInformation method.
|
||||
* <pre>
|
||||
* MediaInformationSession *session = [FFprobeKit getMediaInformation:@"file1.mp4"];
|
||||
* </pre>
|
||||
*/
|
||||
@interface FFprobeKit : NSObject
|
||||
|
||||
/**
|
||||
* <p>Synchronously executes FFprobe with arguments provided.
|
||||
*
|
||||
* @param arguments FFprobe command options/arguments as string array
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeWithArguments:(NSArray*)arguments;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFprobe command options/arguments as string array
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFprobe command options/arguments as string array
|
||||
* @param completeCallback callback that will be notified when execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFprobe command options/arguments as string array
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFprobe command options/arguments as string array
|
||||
* @param completeCallback callback that will be notified when execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Synchronously executes FFprobe command provided. Space character is used to split command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside
|
||||
* your command.
|
||||
*
|
||||
* @param command FFprobe command
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)execute:(NSString*)command;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFprobe command
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeAsync:(NSString*)command withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFprobe command
|
||||
* @param completeCallback callback that will be notified when execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeAsync:(NSString*)command withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFprobe command
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeAsync:(NSString*)command withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFprobe command
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeAsync:(NSString*)command withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Extracts media information for the file specified with path.
|
||||
*
|
||||
* @param path path or uri of a media file
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformation:(NSString*)path;
|
||||
|
||||
/**
|
||||
* <p>Extracts media information for the file specified with path.
|
||||
*
|
||||
* @param path path or uri of a media file
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformation:(NSString*)path withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution to extract the media information for the specified file.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param path path or uri of a media file
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution to extract the media information for the specified file.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param path path or uri of a media file
|
||||
* @param completeCallback callback that will be notified when execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution to extract the media information for the specified file.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param path path or uri of a media file
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution to extract the media information for the specified file.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param path path or uri of a media file
|
||||
* @param completeCallback callback that will be notified when execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Extracts media information using the command provided asynchronously.
|
||||
*
|
||||
* @param command FFprobe command that prints media information for a file in JSON format
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformationFromCommand:(NSString*)command;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution to extract media information using a command. The command passed to
|
||||
* this method must generate the output in JSON format in order to successfully extract media information from it.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFprobe command that prints media information for a file in JSON format
|
||||
* @param completeCallback callback that will be notified when execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformationFromCommandAsync:(NSString*)command withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution to extract media information using command arguments. The command
|
||||
* passed to this method must generate the output in JSON format in order to successfully extract media information
|
||||
* from it.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFprobe command that prints media information for a file in JSON format
|
||||
* @param completeCallback callback that will be notified when execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformationFromCommandArgumentsAsync:(NSArray*)arguments withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Lists all FFprobe sessions in the session history.
|
||||
*
|
||||
* @return all FFprobe sessions in the session history
|
||||
*/
|
||||
+ (NSArray*)listFFprobeSessions;
|
||||
|
||||
/**
|
||||
* <p>Lists all MediaInformation sessions in the session history.
|
||||
*
|
||||
* @return all MediaInformation sessions in the session history
|
||||
*/
|
||||
+ (NSArray*)listMediaInformationSessions;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFPROBE_KIT_H
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2022 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 "fftools_ffmpeg.h"
|
||||
#import "FFmpegKit.h"
|
||||
#import "FFmpegKitConfig.h"
|
||||
#import "FFprobeKit.h"
|
||||
|
||||
@implementation FFprobeKit
|
||||
|
||||
+ (void)initialize {
|
||||
[FFmpegKitConfig class];
|
||||
}
|
||||
|
||||
+ (NSArray*)defaultGetMediaInformationCommandArguments:(NSString*)path {
|
||||
return [[NSArray alloc] initWithObjects:@"-v", @"error", @"-hide_banner", @"-print_format", @"json", @"-show_format", @"-show_streams", @"-show_chapters", @"-i", path, nil];
|
||||
}
|
||||
|
||||
+ (FFprobeSession*)executeWithArguments:(NSArray*)arguments {
|
||||
FFprobeSession* session = [FFprobeSession create:arguments];
|
||||
[FFmpegKitConfig ffprobeExecute:session];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback {
|
||||
FFprobeSession* session = [FFprobeSession create:arguments withCompleteCallback:completeCallback];
|
||||
[FFmpegKitConfig asyncFFprobeExecute:session];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback {
|
||||
FFprobeSession* session = [FFprobeSession create:arguments withCompleteCallback:completeCallback withLogCallback:logCallback];
|
||||
[FFmpegKitConfig asyncFFprobeExecute:session];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback onDispatchQueue:(dispatch_queue_t)queue {
|
||||
FFprobeSession* session = [FFprobeSession create:arguments withCompleteCallback:completeCallback];
|
||||
[FFmpegKitConfig asyncFFprobeExecute:session onDispatchQueue:queue];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue {
|
||||
FFprobeSession* session = [FFprobeSession create:arguments withCompleteCallback:completeCallback withLogCallback:logCallback];
|
||||
[FFmpegKitConfig asyncFFprobeExecute:session onDispatchQueue:queue];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFprobeSession*)execute:(NSString*)command {
|
||||
FFprobeSession* session = [FFprobeSession create:[FFmpegKitConfig parseArguments:command]];
|
||||
[FFmpegKitConfig ffprobeExecute:session];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFprobeSession*)executeAsync:(NSString*)command withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback {
|
||||
FFprobeSession* session = [FFprobeSession create:[FFmpegKitConfig parseArguments:command] withCompleteCallback:completeCallback];
|
||||
[FFmpegKitConfig asyncFFprobeExecute:session];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFprobeSession*)executeAsync:(NSString*)command withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback {
|
||||
FFprobeSession* session = [FFprobeSession create:[FFmpegKitConfig parseArguments:command] withCompleteCallback:completeCallback withLogCallback:logCallback];
|
||||
[FFmpegKitConfig asyncFFprobeExecute:session];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFprobeSession*)executeAsync:(NSString*)command withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback onDispatchQueue:(dispatch_queue_t)queue {
|
||||
FFprobeSession* session = [FFprobeSession create:[FFmpegKitConfig parseArguments:command] withCompleteCallback:completeCallback];
|
||||
[FFmpegKitConfig asyncFFprobeExecute:session onDispatchQueue:queue];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (FFprobeSession*)executeAsync:(NSString*)command withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue {
|
||||
FFprobeSession* session = [FFprobeSession create:[FFmpegKitConfig parseArguments:command] withCompleteCallback:completeCallback withLogCallback:logCallback];
|
||||
[FFmpegKitConfig asyncFFprobeExecute:session onDispatchQueue:queue];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (MediaInformationSession*)getMediaInformation:(NSString*)path {
|
||||
NSArray* arguments = [FFprobeKit defaultGetMediaInformationCommandArguments:path];
|
||||
MediaInformationSession* session = [MediaInformationSession create:arguments];
|
||||
[FFmpegKitConfig getMediaInformationExecute:session withTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (MediaInformationSession*)getMediaInformation:(NSString*)path withTimeout:(int)waitTimeout {
|
||||
NSArray* arguments = [FFprobeKit defaultGetMediaInformationCommandArguments:path];
|
||||
MediaInformationSession* session = [MediaInformationSession create:arguments];
|
||||
[FFmpegKitConfig getMediaInformationExecute:session withTimeout:waitTimeout];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback {
|
||||
NSArray* arguments = [FFprobeKit defaultGetMediaInformationCommandArguments:path];
|
||||
MediaInformationSession* session = [MediaInformationSession create:arguments withCompleteCallback:completeCallback];
|
||||
[FFmpegKitConfig asyncGetMediaInformationExecute:session withTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withTimeout:(int)waitTimeout {
|
||||
NSArray* arguments = [FFprobeKit defaultGetMediaInformationCommandArguments:path];
|
||||
MediaInformationSession* session = [MediaInformationSession create:arguments withCompleteCallback:completeCallback withLogCallback:logCallback];
|
||||
[FFmpegKitConfig asyncGetMediaInformationExecute:session withTimeout:waitTimeout];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback onDispatchQueue:(dispatch_queue_t)queue {
|
||||
NSArray* arguments = [FFprobeKit defaultGetMediaInformationCommandArguments:path];
|
||||
MediaInformationSession* session = [MediaInformationSession create:arguments withCompleteCallback:completeCallback];
|
||||
[FFmpegKitConfig asyncGetMediaInformationExecute:session onDispatchQueue:queue withTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout {
|
||||
NSArray* arguments = [FFprobeKit defaultGetMediaInformationCommandArguments:path];
|
||||
MediaInformationSession* session = [MediaInformationSession create:arguments withCompleteCallback:completeCallback];
|
||||
[FFmpegKitConfig asyncGetMediaInformationExecute:session onDispatchQueue:queue withTimeout:waitTimeout];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (MediaInformationSession*)getMediaInformationFromCommand:(NSString*)command {
|
||||
MediaInformationSession* session = [MediaInformationSession create:[FFmpegKitConfig parseArguments:command]];
|
||||
[FFmpegKitConfig getMediaInformationExecute:session withTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (MediaInformationSession*)getMediaInformationFromCommandAsync:(NSString*)command withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout {
|
||||
MediaInformationSession* session = [MediaInformationSession create:[FFmpegKitConfig parseArguments:command] withCompleteCallback:completeCallback withLogCallback:logCallback];
|
||||
[FFmpegKitConfig asyncGetMediaInformationExecute:session onDispatchQueue:queue withTimeout:waitTimeout];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (MediaInformationSession*)getMediaInformationFromCommandArgumentsAsync:(NSArray*)arguments withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout {
|
||||
MediaInformationSession* session = [MediaInformationSession create:arguments withCompleteCallback:completeCallback withLogCallback:logCallback];
|
||||
[FFmpegKitConfig asyncGetMediaInformationExecute:session onDispatchQueue:queue withTimeout:waitTimeout];
|
||||
return session;
|
||||
}
|
||||
|
||||
+ (NSArray*)listFFprobeSessions {
|
||||
return [FFmpegKitConfig getFFprobeSessions];
|
||||
}
|
||||
|
||||
+ (NSArray*)listMediaInformationSessions {
|
||||
return [FFmpegKitConfig getMediaInformationSessions];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_FFPROBE_SESSION_H
|
||||
#define FFMPEG_KIT_FFPROBE_SESSION_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "AbstractSession.h"
|
||||
#import "FFprobeSessionCompleteCallback.h"
|
||||
|
||||
/**
|
||||
* <p>An FFprobe session.
|
||||
*/
|
||||
@interface FFprobeSession : AbstractSession
|
||||
|
||||
/**
|
||||
* Builds a new FFprobe session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @return created session
|
||||
*/
|
||||
+ (instancetype)create:(NSArray*)arguments;
|
||||
|
||||
/**
|
||||
* Builds a new FFprobe session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
* @return created session
|
||||
*/
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* Builds a new FFprobe session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
* @param logCallback session specific log callback
|
||||
* @return created session
|
||||
*/
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback;
|
||||
|
||||
/**
|
||||
* Builds a new FFprobe session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
* @param logCallback session specific log callback
|
||||
* @param logRedirectionStrategy session specific log redirection strategy
|
||||
* @return created session
|
||||
*/
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy;
|
||||
|
||||
/**
|
||||
* Returns the session specific complete callback.
|
||||
*
|
||||
* @return session specific complete callback
|
||||
*/
|
||||
- (FFprobeSessionCompleteCallback)getCompleteCallback;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_FFPROBE_SESSION_H
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#import "FFprobeSession.h"
|
||||
#import "FFmpegKitConfig.h"
|
||||
#import "LogCallback.h"
|
||||
|
||||
@implementation FFprobeSession {
|
||||
FFprobeSessionCompleteCallback _completeCallback;
|
||||
}
|
||||
|
||||
+ (void)initialize {
|
||||
// EMPTY INITIALIZE
|
||||
}
|
||||
|
||||
+ (instancetype)create:(NSArray*)arguments {
|
||||
return [[self alloc] init:arguments withCompleteCallback:nil withLogCallback:nil withLogRedirectionStrategy:[FFmpegKitConfig getLogRedirectionStrategy]];
|
||||
}
|
||||
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback {
|
||||
return [[self alloc] init:arguments withCompleteCallback:completeCallback withLogCallback:nil withLogRedirectionStrategy:[FFmpegKitConfig getLogRedirectionStrategy]];
|
||||
}
|
||||
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback {
|
||||
return [[self alloc] init:arguments withCompleteCallback:completeCallback withLogCallback:logCallback withLogRedirectionStrategy:[FFmpegKitConfig getLogRedirectionStrategy]];
|
||||
}
|
||||
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy {
|
||||
return [[self alloc] init:arguments withCompleteCallback:completeCallback withLogCallback:logCallback withLogRedirectionStrategy:logRedirectionStrategy];
|
||||
}
|
||||
|
||||
- (instancetype)init:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy {
|
||||
|
||||
self = [super init:arguments withLogCallback:logCallback withLogRedirectionStrategy:logRedirectionStrategy];
|
||||
|
||||
if (self) {
|
||||
_completeCallback = completeCallback;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (FFprobeSessionCompleteCallback)getCompleteCallback {
|
||||
return _completeCallback;
|
||||
}
|
||||
|
||||
- (BOOL)isFFmpeg {
|
||||
return false;
|
||||
}
|
||||
|
||||
- (BOOL)isFFprobe {
|
||||
return true;
|
||||
}
|
||||
|
||||
- (BOOL)isMediaInformation {
|
||||
return false;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2020-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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_FFPROBE_SESSION_COMPLETE_CALLBACK_H
|
||||
#define FFMPEG_KIT_FFPROBE_SESSION_COMPLETE_CALLBACK_H
|
||||
|
||||
@class FFprobeSession;
|
||||
|
||||
/**
|
||||
* <p>Callback function that is invoked when an asynchronous <code>FFprobe</code> session has ended.
|
||||
* <p>Session has either SessionStateCompleted or SessionStateFailed state when
|
||||
* the callback is invoked.
|
||||
* <p>If it has SessionStateCompleted state, <code>ReturnCode</code> should be checked to
|
||||
* see the execution result.
|
||||
* <p>If <code>getState</code> returns SessionStateFailed then
|
||||
* <code>getFailStackTrace</code> should be used to get the failure reason.
|
||||
* <pre>
|
||||
* switch ([session getState]) {
|
||||
* case SessionStateCompleted:
|
||||
* ReturnCode *returnCode = [session getReturnCode];
|
||||
* break;
|
||||
* case SessionStateFailed:
|
||||
* NSString *failStackTrace = [session getFailStackTrace];
|
||||
* break;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param session session of the completed execution
|
||||
*/
|
||||
typedef void (^FFprobeSessionCompleteCallback)(FFprobeSession* session);
|
||||
|
||||
#import "FFprobeSession.h"
|
||||
|
||||
#endif // FFMPEG_KIT_FFPROBE_SESSION_COMPLETE_CALLBACK_H
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_LEVEL_H
|
||||
#define FFMPEG_KIT_LEVEL_H
|
||||
|
||||
/**
|
||||
* <p>Enumeration type for log levels.
|
||||
*/
|
||||
typedef NS_ENUM(NSUInteger, Level) {
|
||||
|
||||
/**
|
||||
* This log level is defined by FFmpegKit. It is used to specify logs printed to stderr by
|
||||
* FFmpeg. Logs that has this level are not filtered and always redirected.
|
||||
*/
|
||||
LevelAVLogStdErr = -16,
|
||||
|
||||
/**
|
||||
* Print no output.
|
||||
*/
|
||||
LevelAVLogQuiet = -8,
|
||||
|
||||
/**
|
||||
* Something went really wrong and we will crash now.
|
||||
*/
|
||||
LevelAVLogPanic = 0,
|
||||
|
||||
/**
|
||||
* Something went wrong and recovery is not possible.
|
||||
* For example, no header was found for a format which depends
|
||||
* on headers or an illegal combination of parameters is used.
|
||||
*/
|
||||
LevelAVLogFatal = 8,
|
||||
|
||||
/**
|
||||
* Something went wrong and cannot losslessly be recovered.
|
||||
* However, not all future data is affected.
|
||||
*/
|
||||
LevelAVLogError = 16,
|
||||
|
||||
/**
|
||||
* Something somehow does not look correct. This may or may not
|
||||
* lead to problems. An example would be the use of '-vstrict -2'.
|
||||
*/
|
||||
LevelAVLogWarning = 24,
|
||||
|
||||
/**
|
||||
* Standard information.
|
||||
*/
|
||||
LevelAVLogInfo = 32,
|
||||
|
||||
/**
|
||||
* Detailed information.
|
||||
*/
|
||||
LevelAVLogVerbose = 40,
|
||||
|
||||
/**
|
||||
* Stuff which is only useful for libav* developers.
|
||||
*/
|
||||
LevelAVLogDebug = 48,
|
||||
|
||||
/**
|
||||
* Extremely verbose debugging, useful for libav* development.
|
||||
*/
|
||||
LevelAVLogTrace = 56
|
||||
|
||||
};
|
||||
|
||||
#endif // FFMPEG_KIT_LEVEL_H
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_LOG_H
|
||||
#define FFMPEG_KIT_LOG_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* <p>Log entry for an <code>FFmpegKit</code> session.
|
||||
*/
|
||||
@interface Log : NSObject
|
||||
|
||||
- (instancetype)init:(long)sessionId :(int)level :(NSString*)message;
|
||||
|
||||
- (long)getSessionId;
|
||||
|
||||
- (int)getLevel;
|
||||
|
||||
- (NSString*)getMessage;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_LOG_H
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#import "Log.h"
|
||||
|
||||
@implementation Log {
|
||||
long _sessionId;
|
||||
int _level;
|
||||
NSString *_message;
|
||||
}
|
||||
|
||||
- (instancetype)init:(long)sessionId :(int)level :(NSString*)message {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_sessionId = sessionId;
|
||||
_level = level;
|
||||
_message = message;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (long)getSessionId {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
- (int)getLevel {
|
||||
return _level;
|
||||
}
|
||||
|
||||
- (NSString*)getMessage {
|
||||
return _message;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_LOG_CALLBACK_H
|
||||
#define FFMPEG_KIT_LOG_CALLBACK_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Log.h"
|
||||
|
||||
/**
|
||||
* <p>Callback that receives logs generated for <code>FFmpegKit</code> sessions.
|
||||
*
|
||||
* @param log log entry
|
||||
*/
|
||||
typedef void (^LogCallback)(Log* log);
|
||||
|
||||
#endif // FFMPEG_KIT_LOG_CALLBACK_H
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_LOG_REDIRECTION_STRATEGY_H
|
||||
#define FFMPEG_KIT_LOG_REDIRECTION_STRATEGY_H
|
||||
|
||||
typedef NS_ENUM(NSUInteger, LogRedirectionStrategy) {
|
||||
LogRedirectionStrategyAlwaysPrintLogs,
|
||||
LogRedirectionStrategyPrintLogsWhenNoCallbacksDefined,
|
||||
LogRedirectionStrategyPrintLogsWhenGlobalCallbackNotDefined,
|
||||
LogRedirectionStrategyPrintLogsWhenSessionCallbackNotDefined,
|
||||
LogRedirectionStrategyNeverPrintLogs
|
||||
};
|
||||
|
||||
#endif // FFMPEG_KIT_LOG_REDIRECTION_STRATEGY_H
|
||||
@@ -0,0 +1,78 @@
|
||||
lib_LTLIBRARIES = libffmpegkit.la
|
||||
|
||||
libffmpegkit_la_LIBADD = @FFMPEG_FRAMEWORKS@
|
||||
|
||||
libffmpegkit_la_SOURCES = \
|
||||
AbstractSession.m \
|
||||
ArchDetect.m \
|
||||
AtomicLong.m \
|
||||
Chapter.m \
|
||||
FFmpegKit.m \
|
||||
FFmpegKitConfig.m \
|
||||
FFmpegSession.m \
|
||||
FFprobeKit.m \
|
||||
FFprobeSession.m \
|
||||
Log.m \
|
||||
MediaInformation.m \
|
||||
MediaInformationJsonParser.m \
|
||||
MediaInformationSession.m \
|
||||
Packages.m \
|
||||
ReturnCode.m \
|
||||
Statistics.m \
|
||||
StreamInformation.m \
|
||||
ffmpegkit_exception.m \
|
||||
fftools_cmdutils.c \
|
||||
fftools_ffmpeg.c \
|
||||
fftools_ffmpeg_demux.c \
|
||||
fftools_ffmpeg_filter.c \
|
||||
fftools_ffmpeg_hw.c \
|
||||
fftools_ffmpeg_mux.c \
|
||||
fftools_ffmpeg_mux_init.c \
|
||||
fftools_ffmpeg_opt.c \
|
||||
fftools_ffprobe.c \
|
||||
fftools_objpool.c \
|
||||
fftools_opt_common.c \
|
||||
fftools_sync_queue.c \
|
||||
fftools_thread_queue.c
|
||||
|
||||
include_HEADERS = \
|
||||
AbstractSession.h \
|
||||
ArchDetect.h \
|
||||
AtomicLong.h \
|
||||
Chapter.h \
|
||||
FFmpegKit.h \
|
||||
FFmpegKitConfig.h \
|
||||
FFmpegSession.h \
|
||||
FFmpegSessionCompleteCallback.h \
|
||||
FFprobeKit.h \
|
||||
FFprobeSession.h \
|
||||
FFprobeSessionCompleteCallback.h \
|
||||
Level.h \
|
||||
Log.h \
|
||||
LogCallback.h \
|
||||
LogRedirectionStrategy.h \
|
||||
MediaInformation.h \
|
||||
MediaInformationJsonParser.h \
|
||||
MediaInformationSession.h \
|
||||
MediaInformationSessionCompleteCallback.h \
|
||||
Packages.h \
|
||||
ReturnCode.h \
|
||||
Session.h \
|
||||
SessionState.h \
|
||||
Statistics.h \
|
||||
StatisticsCallback.h \
|
||||
StreamInformation.h \
|
||||
ffmpegkit_exception.h \
|
||||
fftools_cmdutils.h \
|
||||
fftools_ffmpeg.h \
|
||||
fftools_ffmpeg_mux.h \
|
||||
fftools_fopen_utf8.h \
|
||||
fftools_objpool.h \
|
||||
fftools_opt_common.h \
|
||||
fftools_sync_queue.h \
|
||||
fftools_thread_queue.h
|
||||
|
||||
libffmpegkit_la_CFLAGS = $(CFLAGS)
|
||||
libffmpegkit_la_OBJCFLAGS = $(CFLAGS)
|
||||
libffmpegkit_la_CXXFLAGS = $(CXXFLAGS)
|
||||
libffmpegkit_la_LDFLAGS = $(LDFLAGS)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2022 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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_MEDIA_INFORMATION_H
|
||||
#define FFMPEG_KIT_MEDIA_INFORMATION_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Chapter.h"
|
||||
#import "StreamInformation.h"
|
||||
|
||||
extern NSString* const MediaKeyMediaProperties;
|
||||
extern NSString* const MediaKeyFilename;
|
||||
extern NSString* const MediaKeyFormat;
|
||||
extern NSString* const MediaKeyFormatLong;
|
||||
extern NSString* const MediaKeyStartTime;
|
||||
extern NSString* const MediaKeyDuration;
|
||||
extern NSString* const MediaKeySize;
|
||||
extern NSString* const MediaKeyBitRate;
|
||||
extern NSString* const MediaKeyTags;
|
||||
|
||||
/**
|
||||
* Media information class.
|
||||
*/
|
||||
@interface MediaInformation : NSObject
|
||||
|
||||
- (instancetype)init:(NSDictionary*)mediaDictionary withStreams:(NSArray*)streams withChapters:(NSArray*)chapters;
|
||||
|
||||
/**
|
||||
* Returns file name.
|
||||
*
|
||||
* @return media file name
|
||||
*/
|
||||
- (NSString*)getFilename;
|
||||
|
||||
/**
|
||||
* Returns format.
|
||||
*
|
||||
* @return media format
|
||||
*/
|
||||
- (NSString*)getFormat;
|
||||
|
||||
/**
|
||||
* Returns long format.
|
||||
*
|
||||
* @return media long format
|
||||
*/
|
||||
- (NSString*)getLongFormat;
|
||||
|
||||
/**
|
||||
* Returns duration.
|
||||
*
|
||||
* @return media duration in "seconds.microseconds" format
|
||||
*/
|
||||
- (NSString*)getDuration;
|
||||
|
||||
/**
|
||||
* Returns start time.
|
||||
*
|
||||
* @return media start time in milliseconds
|
||||
*/
|
||||
- (NSString*)getStartTime;
|
||||
|
||||
/**
|
||||
* Returns size.
|
||||
*
|
||||
* @return media size in bytes
|
||||
*/
|
||||
- (NSString*)getSize;
|
||||
|
||||
/**
|
||||
* Returns bitrate.
|
||||
*
|
||||
* @return media bitrate in kb/s
|
||||
*/
|
||||
- (NSString*)getBitrate;
|
||||
|
||||
/**
|
||||
* Returns all tags.
|
||||
*
|
||||
* @return tags dictionary
|
||||
*/
|
||||
- (NSDictionary*)getTags;
|
||||
|
||||
/**
|
||||
* Returns all streams.
|
||||
*
|
||||
* @return streams array
|
||||
*/
|
||||
- (NSArray*)getStreams;
|
||||
|
||||
/**
|
||||
* Returns all chapters.
|
||||
*
|
||||
* @return chapters array
|
||||
*/
|
||||
- (NSArray*)getChapters;
|
||||
|
||||
/**
|
||||
* Returns the property associated with the key.
|
||||
*
|
||||
* @return property as string or nil if the key is not found
|
||||
*/
|
||||
- (NSString*)getStringProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns the property associated with the key.
|
||||
*
|
||||
* @return property as number or nil if the key is not found
|
||||
*/
|
||||
- (NSNumber*)getNumberProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns the property associated with the key.
|
||||
*
|
||||
* @return property as id or nil if the key is not found
|
||||
*/
|
||||
- (id)getProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns the format property associated with the key.
|
||||
*
|
||||
* @return format property as string or nil if the key is not found
|
||||
*/
|
||||
- (NSString*)getStringFormatProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns the format property associated with the key.
|
||||
*
|
||||
* @return format property as number or nil if the key is not found
|
||||
*/
|
||||
- (NSNumber*)getNumberFormatProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns the format property associated with the key.
|
||||
*
|
||||
* @return format property as id or nil if the key is not found
|
||||
*/
|
||||
- (id)getFormatProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns all format properties defined.
|
||||
*
|
||||
* @return all format properties in a dictionary or nil if no format properties are defined
|
||||
*/
|
||||
- (NSDictionary*)getFormatProperties;
|
||||
|
||||
/**
|
||||
* Returns all properties defined.
|
||||
*
|
||||
* @return all properties in a dictionary or nil if no properties are defined
|
||||
*/
|
||||
- (NSDictionary*)getAllProperties;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_MEDIA_INFORMATION_H
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* 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 "MediaInformation.h"
|
||||
|
||||
NSString* const MediaKeyFormatProperties = @"format";
|
||||
NSString* const MediaKeyFilename = @"filename";
|
||||
NSString* const MediaKeyFormat = @"format_name";
|
||||
NSString* const MediaKeyFormatLong = @"format_long_name";
|
||||
NSString* const MediaKeyStartTime = @"start_time";
|
||||
NSString* const MediaKeyDuration = @"duration";
|
||||
NSString* const MediaKeySize = @"size";
|
||||
NSString* const MediaKeyBitRate = @"bit_rate";
|
||||
NSString* const MediaKeyTags = @"tags";
|
||||
|
||||
@implementation MediaInformation {
|
||||
|
||||
/**
|
||||
* Stores all properties.
|
||||
*/
|
||||
NSDictionary *dictionary;
|
||||
|
||||
/**
|
||||
* Stores streams.
|
||||
*/
|
||||
NSArray *streamArray;
|
||||
|
||||
/**
|
||||
* Stores chapters.
|
||||
*/
|
||||
NSArray *chapterArray;
|
||||
|
||||
}
|
||||
|
||||
- (instancetype)init:(NSDictionary*)mediaDictionary withStreams:(NSArray*)streams withChapters:(NSArray*)chapters{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
dictionary = mediaDictionary;
|
||||
streamArray = streams;
|
||||
chapterArray = chapters;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString*)getFilename {
|
||||
return [self getStringFormatProperty:MediaKeyFilename];
|
||||
}
|
||||
|
||||
- (NSString*)getFormat {
|
||||
return [self getStringFormatProperty:MediaKeyFormat];
|
||||
}
|
||||
|
||||
- (NSString*)getLongFormat {
|
||||
return [self getStringFormatProperty:MediaKeyFormatLong];
|
||||
}
|
||||
|
||||
- (NSString*)getStartTime {
|
||||
return [self getStringFormatProperty:MediaKeyStartTime];
|
||||
}
|
||||
|
||||
- (NSString*)getDuration {
|
||||
return [self getStringFormatProperty:MediaKeyDuration];
|
||||
}
|
||||
|
||||
- (NSString*)getSize {
|
||||
return [self getStringFormatProperty:MediaKeySize];
|
||||
}
|
||||
|
||||
- (NSString*)getBitrate {
|
||||
return [self getStringFormatProperty:MediaKeyBitRate];
|
||||
}
|
||||
|
||||
- (NSDictionary*)getTags {
|
||||
return [self getFormatProperty:MediaKeyTags];
|
||||
}
|
||||
|
||||
- (NSArray*)getStreams {
|
||||
return streamArray;
|
||||
}
|
||||
|
||||
- (NSArray*)getChapters {
|
||||
return chapterArray;
|
||||
}
|
||||
|
||||
- (NSString*)getStringProperty:(NSString*)key {
|
||||
NSDictionary* allProperties = [self getAllProperties];
|
||||
if (allProperties == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return allProperties[key];
|
||||
}
|
||||
|
||||
- (NSNumber*)getNumberProperty:(NSString*)key {
|
||||
NSDictionary* allProperties = [self getAllProperties];
|
||||
if (allProperties == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return allProperties[key];
|
||||
}
|
||||
|
||||
- (id)getProperty:(NSString*)key {
|
||||
NSDictionary* allProperties = [self getAllProperties];
|
||||
if (allProperties == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return allProperties[key];
|
||||
}
|
||||
|
||||
- (NSString*)getStringFormatProperty:(NSString*)key {
|
||||
NSDictionary* formatProperties = [self getFormatProperties];
|
||||
if (formatProperties == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return formatProperties[key];
|
||||
}
|
||||
|
||||
- (NSNumber*)getNumberFormatProperty:(NSString*)key {
|
||||
NSDictionary* formatProperties = [self getFormatProperties];
|
||||
if (formatProperties == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return formatProperties[key];
|
||||
}
|
||||
|
||||
- (id)getFormatProperty:(NSString*)key {
|
||||
NSDictionary* formatProperties = [self getFormatProperties];
|
||||
if (formatProperties == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return formatProperties[key];
|
||||
}
|
||||
|
||||
- (NSDictionary*)getFormatProperties {
|
||||
return dictionary[MediaKeyFormatProperties];
|
||||
}
|
||||
|
||||
- (NSDictionary*)getAllProperties {
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2022 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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_MEDIA_INFORMATION_PARSER_H
|
||||
#define FFMPEG_KIT_MEDIA_INFORMATION_PARSER_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MediaInformation.h"
|
||||
|
||||
/**
|
||||
* A parser that constructs MediaInformation from FFprobe's json output.
|
||||
*/
|
||||
@interface MediaInformationJsonParser : NSObject
|
||||
|
||||
/**
|
||||
* Extracts <code>MediaInformation</code> from the given FFprobe json output.
|
||||
*
|
||||
* @param ffprobeJsonOutput FFprobe json output
|
||||
* @return created MediaInformation instance of nil if a parsing error occurs
|
||||
*/
|
||||
+ (MediaInformation*)from:(NSString*)ffprobeJsonOutput;
|
||||
|
||||
/**
|
||||
* Extracts <code>MediaInformation</code> from the given FFprobe json output. If a parsing error occurs an NSException
|
||||
* is thrown.
|
||||
*
|
||||
* @param ffprobeJsonOutput FFprobe json output
|
||||
* @return created MediaInformation instance
|
||||
*/
|
||||
+ (MediaInformation*)fromWithError:(NSString*)ffprobeJsonOutput;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_MEDIA_INFORMATION_PARSER_H
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2022 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 "MediaInformationJsonParser.h"
|
||||
|
||||
NSString* const MediaInformationJsonParserKeyStreams = @"streams";
|
||||
NSString* const MediaInformationJsonParserKeyChapters = @"chapters";
|
||||
|
||||
@implementation MediaInformationJsonParser
|
||||
|
||||
+ (MediaInformation*)from:(NSString*)ffprobeJsonOutput {
|
||||
@try {
|
||||
return [self fromWithError:ffprobeJsonOutput];
|
||||
} @catch (NSException *exception) {
|
||||
NSLog(@"MediaInformation parsing failed: %@.\n", [NSString stringWithFormat:@"%@\n%@", [exception userInfo], [exception callStackSymbols]]);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
+ (MediaInformation*)fromWithError:(NSString*)ffprobeJsonOutput {
|
||||
NSError* error = nil;
|
||||
NSData *jsonData = [ffprobeJsonOutput dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
|
||||
if (error != nil) {
|
||||
@throw [NSException exceptionWithName:@"ParsingException" reason:[NSString stringWithFormat:@"%ld",(long)[error code]] userInfo:[error userInfo]];
|
||||
}
|
||||
if (jsonDictionary == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSArray* jsonStreamArray = [jsonDictionary objectForKey:MediaInformationJsonParserKeyStreams];
|
||||
NSMutableArray *streamArray = [[NSMutableArray alloc] init];
|
||||
for(int i = 0; i<jsonStreamArray.count; i++) {
|
||||
NSDictionary *streamDictionary = [jsonStreamArray objectAtIndex:i];
|
||||
[streamArray addObject:[[StreamInformation alloc] init:streamDictionary]];
|
||||
}
|
||||
|
||||
NSArray* jsonChapterArray = [jsonDictionary objectForKey:MediaInformationJsonParserKeyChapters];
|
||||
NSMutableArray *chapterArray = [[NSMutableArray alloc] init];
|
||||
for(int i = 0; i<jsonChapterArray.count; i++) {
|
||||
NSDictionary *chapterDictionary = [jsonChapterArray objectAtIndex:i];
|
||||
[chapterArray addObject:[[Chapter alloc] init:chapterDictionary]];
|
||||
}
|
||||
|
||||
return [[MediaInformation alloc] init:jsonDictionary withStreams:streamArray withChapters:chapterArray];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_MEDIA_INFORMATION_SESSION_H
|
||||
#define FFMPEG_KIT_MEDIA_INFORMATION_SESSION_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "AbstractSession.h"
|
||||
#import "MediaInformation.h"
|
||||
#import "MediaInformationSessionCompleteCallback.h"
|
||||
|
||||
/**
|
||||
* <p>A custom FFprobe session, which produces a <code>MediaInformation</code> object using the
|
||||
* FFprobe output.
|
||||
*/
|
||||
@interface MediaInformationSession : AbstractSession
|
||||
|
||||
/**
|
||||
* Creates a new media information session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @return created session
|
||||
*/
|
||||
+ (instancetype)create:(NSArray*)arguments;
|
||||
|
||||
/**
|
||||
* Creates a new media information session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
* @return created session
|
||||
*/
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* Creates a new media information session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
* @param logCallback session specific log callback
|
||||
* @return created session
|
||||
*/
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback;
|
||||
|
||||
/**
|
||||
* Returns the media information extracted in this session.
|
||||
*
|
||||
* @return media information extracted or nil if the command failed or the output can not be
|
||||
* parsed
|
||||
*/
|
||||
- (MediaInformation*)getMediaInformation;
|
||||
|
||||
/**
|
||||
* Sets the media information extracted in this session.
|
||||
*
|
||||
* @param mediaInformation media information extracted
|
||||
*/
|
||||
- (void)setMediaInformation:(MediaInformation*)mediaInformation;
|
||||
|
||||
/**
|
||||
* Returns the session specific complete callback.
|
||||
*
|
||||
* @return session specific complete callback
|
||||
*/
|
||||
- (MediaInformationSessionCompleteCallback)getCompleteCallback;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_MEDIA_INFORMATION_SESSION_H
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#import "MediaInformationSession.h"
|
||||
#import "LogCallback.h"
|
||||
#import "MediaInformation.h"
|
||||
|
||||
@implementation MediaInformationSession {
|
||||
MediaInformation* _mediaInformation;
|
||||
MediaInformationSessionCompleteCallback _completeCallback;
|
||||
}
|
||||
|
||||
+ (void)initialize {
|
||||
// EMPTY INITIALIZE
|
||||
}
|
||||
|
||||
+ (instancetype)create:(NSArray*)arguments {
|
||||
return [[self alloc] init:arguments withCompleteCallback:nil withLogCallback:nil];
|
||||
}
|
||||
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback {
|
||||
return [[self alloc] init:arguments withCompleteCallback:completeCallback withLogCallback:nil];
|
||||
}
|
||||
|
||||
+ (instancetype)create:(NSArray*)arguments withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback {
|
||||
return [[self alloc] init:arguments withCompleteCallback:completeCallback withLogCallback:logCallback];
|
||||
}
|
||||
|
||||
- (instancetype)init:(NSArray*)arguments withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback {
|
||||
|
||||
self = [super init:arguments withLogCallback:logCallback withLogRedirectionStrategy:LogRedirectionStrategyNeverPrintLogs];
|
||||
|
||||
if (self) {
|
||||
_completeCallback = completeCallback;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (MediaInformation*)getMediaInformation {
|
||||
return _mediaInformation;
|
||||
}
|
||||
|
||||
- (void)setMediaInformation:(MediaInformation*)mediaInformation {
|
||||
_mediaInformation = mediaInformation;
|
||||
}
|
||||
|
||||
- (MediaInformationSessionCompleteCallback)getCompleteCallback {
|
||||
return _completeCallback;
|
||||
}
|
||||
|
||||
- (BOOL)isFFmpeg {
|
||||
return false;
|
||||
}
|
||||
|
||||
- (BOOL)isFFprobe {
|
||||
return false;
|
||||
}
|
||||
|
||||
- (BOOL)isMediaInformation {
|
||||
return true;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2020-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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_MEDIA_INFORMATION_SESSION_COMPLETE_CALLBACK_H
|
||||
#define FFMPEG_KIT_MEDIA_INFORMATION_SESSION_COMPLETE_CALLBACK_H
|
||||
|
||||
@class MediaInformationSession;
|
||||
|
||||
/**
|
||||
* <p>Callback function that is invoked when an asynchronous <code>MediaInformation</code> session
|
||||
* has ended.
|
||||
* <p>Session has either SessionStateCompleted or SessionStateFailed state when
|
||||
* the callback is invoked.
|
||||
* <p>If it has SessionStateCompleted state, <code>ReturnCode</code> should be checked to
|
||||
* see the execution result.
|
||||
* <p>If <code>getState</code> returns SessionStateFailed then
|
||||
* <code>getFailStackTrace</code> should be used to get the failure reason.
|
||||
* <pre>
|
||||
* switch ([session getState]) {
|
||||
* case SessionStateCompleted:
|
||||
* ReturnCode *returnCode = [session getReturnCode];
|
||||
* break;
|
||||
* case SessionStateFailed:
|
||||
* NSString *failStackTrace = [session getFailStackTrace];
|
||||
* break;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param session session of the completed execution
|
||||
*/
|
||||
typedef void (^MediaInformationSessionCompleteCallback)(MediaInformationSession* session);
|
||||
|
||||
#import "MediaInformationSession.h"
|
||||
|
||||
#endif // FFMPEG_KIT_MEDIA_INFORMATION_SESSION_COMPLETE_CALLBACK_H
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_PACKAGES_H
|
||||
#define FFMPEG_KIT_PACKAGES_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* <p>Helper class to extract binary package information.
|
||||
*/
|
||||
@interface Packages : NSObject
|
||||
|
||||
/**
|
||||
* Returns the FFmpegKit binary package name.
|
||||
*
|
||||
* @return predicted FFmpegKit binary package name
|
||||
*/
|
||||
+ (NSString*)getPackageName;
|
||||
|
||||
/**
|
||||
* Returns enabled external libraries by FFmpeg.
|
||||
*
|
||||
* @return enabled external libraries
|
||||
*/
|
||||
+ (NSArray*)getExternalLibraries;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_PACKAGES_H
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright (c) 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#import "config.h"
|
||||
#import "libavutil/ffversion.h"
|
||||
#import "FFmpegKitConfig.h"
|
||||
#import "Packages.h"
|
||||
|
||||
static NSMutableArray *supportedExternalLibraries;
|
||||
|
||||
@implementation Packages
|
||||
|
||||
+ (void)initialize {
|
||||
supportedExternalLibraries = [[NSMutableArray alloc] init];
|
||||
[supportedExternalLibraries addObject:@"dav1d"];
|
||||
[supportedExternalLibraries addObject:@"fontconfig"];
|
||||
[supportedExternalLibraries addObject:@"freetype"];
|
||||
[supportedExternalLibraries addObject:@"fribidi"];
|
||||
[supportedExternalLibraries addObject:@"gmp"];
|
||||
[supportedExternalLibraries addObject:@"gnutls"];
|
||||
[supportedExternalLibraries addObject:@"kvazaar"];
|
||||
[supportedExternalLibraries addObject:@"mp3lame"];
|
||||
[supportedExternalLibraries addObject:@"libaom"];
|
||||
[supportedExternalLibraries addObject:@"libass"];
|
||||
[supportedExternalLibraries addObject:@"iconv"];
|
||||
[supportedExternalLibraries addObject:@"libilbc"];
|
||||
[supportedExternalLibraries addObject:@"libtheora"];
|
||||
[supportedExternalLibraries addObject:@"libvidstab"];
|
||||
[supportedExternalLibraries addObject:@"libvorbis"];
|
||||
[supportedExternalLibraries addObject:@"libvpx"];
|
||||
[supportedExternalLibraries addObject:@"libwebp"];
|
||||
[supportedExternalLibraries addObject:@"libxml2"];
|
||||
[supportedExternalLibraries addObject:@"opencore-amr"];
|
||||
[supportedExternalLibraries addObject:@"openh264"];
|
||||
[supportedExternalLibraries addObject:@"opus"];
|
||||
[supportedExternalLibraries addObject:@"rubberband"];
|
||||
[supportedExternalLibraries addObject:@"sdl2"];
|
||||
[supportedExternalLibraries addObject:@"shine"];
|
||||
[supportedExternalLibraries addObject:@"snappy"];
|
||||
[supportedExternalLibraries addObject:@"soxr"];
|
||||
[supportedExternalLibraries addObject:@"speex"];
|
||||
[supportedExternalLibraries addObject:@"tesseract"];
|
||||
[supportedExternalLibraries addObject:@"twolame"];
|
||||
[supportedExternalLibraries addObject:@"x264"];
|
||||
[supportedExternalLibraries addObject:@"x265"];
|
||||
[supportedExternalLibraries addObject:@"xvid"];
|
||||
}
|
||||
|
||||
+ (NSString*)getBuildConf {
|
||||
return [NSString stringWithUTF8String:FFMPEG_CONFIGURATION];
|
||||
}
|
||||
|
||||
+ (NSString*)getPackageName {
|
||||
NSArray *enabledLibraryArray = [Packages getExternalLibraries];
|
||||
Boolean speex = [enabledLibraryArray containsObject:@"speex"];
|
||||
Boolean fribidi = [enabledLibraryArray containsObject:@"fribidi"];
|
||||
Boolean gnutls = [enabledLibraryArray containsObject:@"gnutls"];
|
||||
Boolean xvid = [enabledLibraryArray containsObject:@"xvid"];
|
||||
|
||||
Boolean minGpl = false;
|
||||
Boolean https = false;
|
||||
Boolean httpsGpl = false;
|
||||
Boolean audio = false;
|
||||
Boolean video = false;
|
||||
Boolean full = false;
|
||||
Boolean fullGpl = false;
|
||||
|
||||
if (speex && fribidi) {
|
||||
if (xvid) {
|
||||
fullGpl = true;
|
||||
} else {
|
||||
full = true;
|
||||
}
|
||||
} else if (speex) {
|
||||
audio = true;
|
||||
} else if (fribidi) {
|
||||
video = true;
|
||||
} else if (xvid) {
|
||||
if (gnutls) {
|
||||
httpsGpl = true;
|
||||
} else {
|
||||
minGpl = true;
|
||||
}
|
||||
} else {
|
||||
if (gnutls) {
|
||||
https = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (fullGpl) {
|
||||
if ([enabledLibraryArray containsObject:@"dav1d"] &&
|
||||
[enabledLibraryArray containsObject:@"fontconfig"] &&
|
||||
[enabledLibraryArray containsObject:@"freetype"] &&
|
||||
[enabledLibraryArray containsObject:@"fribidi"] &&
|
||||
[enabledLibraryArray containsObject:@"gmp"] &&
|
||||
[enabledLibraryArray containsObject:@"gnutls"] &&
|
||||
[enabledLibraryArray containsObject:@"kvazaar"] &&
|
||||
[enabledLibraryArray containsObject:@"mp3lame"] &&
|
||||
[enabledLibraryArray containsObject:@"libass"] &&
|
||||
[enabledLibraryArray containsObject:@"iconv"] &&
|
||||
[enabledLibraryArray containsObject:@"libilbc"] &&
|
||||
[enabledLibraryArray containsObject:@"libtheora"] &&
|
||||
[enabledLibraryArray containsObject:@"libvidstab"] &&
|
||||
[enabledLibraryArray containsObject:@"libvorbis"] &&
|
||||
[enabledLibraryArray containsObject:@"libvpx"] &&
|
||||
[enabledLibraryArray containsObject:@"libwebp"] &&
|
||||
[enabledLibraryArray containsObject:@"libxml2"] &&
|
||||
[enabledLibraryArray containsObject:@"opencore-amr"] &&
|
||||
[enabledLibraryArray containsObject:@"opus"] &&
|
||||
[enabledLibraryArray containsObject:@"shine"] &&
|
||||
[enabledLibraryArray containsObject:@"snappy"] &&
|
||||
[enabledLibraryArray containsObject:@"soxr"] &&
|
||||
[enabledLibraryArray containsObject:@"speex"] &&
|
||||
[enabledLibraryArray containsObject:@"twolame"] &&
|
||||
[enabledLibraryArray containsObject:@"x264"] &&
|
||||
[enabledLibraryArray containsObject:@"x265"] &&
|
||||
[enabledLibraryArray containsObject:@"xvid"]) {
|
||||
return @"full-gpl";
|
||||
} else {
|
||||
return @"custom";
|
||||
}
|
||||
}
|
||||
|
||||
if (full) {
|
||||
if ([enabledLibraryArray containsObject:@"dav1d"] &&
|
||||
[enabledLibraryArray containsObject:@"fontconfig"] &&
|
||||
[enabledLibraryArray containsObject:@"freetype"] &&
|
||||
[enabledLibraryArray containsObject:@"fribidi"] &&
|
||||
[enabledLibraryArray containsObject:@"gmp"] &&
|
||||
[enabledLibraryArray containsObject:@"gnutls"] &&
|
||||
[enabledLibraryArray containsObject:@"kvazaar"] &&
|
||||
[enabledLibraryArray containsObject:@"mp3lame"] &&
|
||||
[enabledLibraryArray containsObject:@"libass"] &&
|
||||
[enabledLibraryArray containsObject:@"iconv"] &&
|
||||
[enabledLibraryArray containsObject:@"libilbc"] &&
|
||||
[enabledLibraryArray containsObject:@"libtheora"] &&
|
||||
[enabledLibraryArray containsObject:@"libvorbis"] &&
|
||||
[enabledLibraryArray containsObject:@"libvpx"] &&
|
||||
[enabledLibraryArray containsObject:@"libwebp"] &&
|
||||
[enabledLibraryArray containsObject:@"libxml2"] &&
|
||||
[enabledLibraryArray containsObject:@"opencore-amr"] &&
|
||||
[enabledLibraryArray containsObject:@"opus"] &&
|
||||
[enabledLibraryArray containsObject:@"shine"] &&
|
||||
[enabledLibraryArray containsObject:@"snappy"] &&
|
||||
[enabledLibraryArray containsObject:@"soxr"] &&
|
||||
[enabledLibraryArray containsObject:@"speex"] &&
|
||||
[enabledLibraryArray containsObject:@"twolame"]) {
|
||||
return @"full";
|
||||
} else {
|
||||
return @"custom";
|
||||
}
|
||||
}
|
||||
|
||||
if (video) {
|
||||
if ([enabledLibraryArray containsObject:@"dav1d"] &&
|
||||
[enabledLibraryArray containsObject:@"fontconfig"] &&
|
||||
[enabledLibraryArray containsObject:@"freetype"] &&
|
||||
[enabledLibraryArray containsObject:@"fribidi"] &&
|
||||
[enabledLibraryArray containsObject:@"kvazaar"] &&
|
||||
[enabledLibraryArray containsObject:@"libass"] &&
|
||||
[enabledLibraryArray containsObject:@"iconv"] &&
|
||||
[enabledLibraryArray containsObject:@"libtheora"] &&
|
||||
[enabledLibraryArray containsObject:@"libvpx"] &&
|
||||
[enabledLibraryArray containsObject:@"libwebp"] &&
|
||||
[enabledLibraryArray containsObject:@"snappy"]) {
|
||||
return @"video";
|
||||
} else {
|
||||
return @"custom";
|
||||
}
|
||||
}
|
||||
|
||||
if (audio) {
|
||||
if ([enabledLibraryArray containsObject:@"mp3lame"] &&
|
||||
[enabledLibraryArray containsObject:@"libilbc"] &&
|
||||
[enabledLibraryArray containsObject:@"libvorbis"] &&
|
||||
[enabledLibraryArray containsObject:@"opencore-amr"] &&
|
||||
[enabledLibraryArray containsObject:@"opus"] &&
|
||||
[enabledLibraryArray containsObject:@"shine"] &&
|
||||
[enabledLibraryArray containsObject:@"soxr"] &&
|
||||
[enabledLibraryArray containsObject:@"speex"] &&
|
||||
[enabledLibraryArray containsObject:@"twolame"]) {
|
||||
return @"audio";
|
||||
} else {
|
||||
return @"custom";
|
||||
}
|
||||
}
|
||||
|
||||
if (httpsGpl) {
|
||||
if ([enabledLibraryArray containsObject:@"gmp"] &&
|
||||
[enabledLibraryArray containsObject:@"gnutls"] &&
|
||||
[enabledLibraryArray containsObject:@"libvidstab"] &&
|
||||
[enabledLibraryArray containsObject:@"x264"] &&
|
||||
[enabledLibraryArray containsObject:@"x265"] &&
|
||||
[enabledLibraryArray containsObject:@"xvid"]) {
|
||||
return @"https-gpl";
|
||||
} else {
|
||||
return @"custom";
|
||||
}
|
||||
}
|
||||
|
||||
if (https) {
|
||||
if ([enabledLibraryArray containsObject:@"gmp"] &&
|
||||
[enabledLibraryArray containsObject:@"gnutls"]) {
|
||||
return @"https";
|
||||
} else {
|
||||
return @"custom";
|
||||
}
|
||||
}
|
||||
|
||||
if (minGpl) {
|
||||
if ([enabledLibraryArray containsObject:@"libvidstab"] &&
|
||||
[enabledLibraryArray containsObject:@"x264"] &&
|
||||
[enabledLibraryArray containsObject:@"x265"] &&
|
||||
[enabledLibraryArray containsObject:@"xvid"]) {
|
||||
return @"min-gpl";
|
||||
} else {
|
||||
return @"custom";
|
||||
}
|
||||
}
|
||||
|
||||
return @"min";
|
||||
}
|
||||
|
||||
+ (NSArray*)getExternalLibraries {
|
||||
NSString *buildConfiguration = [Packages getBuildConf];
|
||||
NSMutableArray *enabledLibraryArray = [[NSMutableArray alloc] init];
|
||||
|
||||
for (int i=0; i < [supportedExternalLibraries count]; i++) {
|
||||
NSString *supportedExternalLibrary = [supportedExternalLibraries objectAtIndex:i];
|
||||
|
||||
NSString *libraryName1 = [NSString stringWithFormat:@"enable-%@", supportedExternalLibrary];
|
||||
NSString *libraryName2 = [NSString stringWithFormat:@"enable-lib%@", supportedExternalLibrary];
|
||||
|
||||
if ([buildConfiguration rangeOfString:libraryName1].location != NSNotFound || [buildConfiguration rangeOfString:libraryName2].location != NSNotFound) {
|
||||
[enabledLibraryArray addObject:supportedExternalLibrary];
|
||||
}
|
||||
}
|
||||
|
||||
[enabledLibraryArray sortUsingSelector:@selector(compare:)];
|
||||
|
||||
return enabledLibraryArray;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_RETURN_CODE_H
|
||||
#define FFMPEG_KIT_RETURN_CODE_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM(NSUInteger, ReturnCodeEnum) {
|
||||
ReturnCodeSuccess = 0,
|
||||
ReturnCodeCancel = 255
|
||||
};
|
||||
|
||||
@interface ReturnCode : NSObject
|
||||
|
||||
- (instancetype)init:(int)value;
|
||||
|
||||
+ (BOOL)isSuccess:(ReturnCode*)value;
|
||||
|
||||
+ (BOOL)isCancel:(ReturnCode*)value;
|
||||
|
||||
- (int)getValue;
|
||||
|
||||
- (BOOL)isValueSuccess;
|
||||
|
||||
- (BOOL)isValueError;
|
||||
|
||||
- (BOOL)isValueCancel;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_RETURN_CODE_H
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#import "ReturnCode.h"
|
||||
|
||||
@implementation ReturnCode {
|
||||
int _value;
|
||||
}
|
||||
|
||||
- (instancetype)init:(int)value {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_value = value;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)isSuccess:(ReturnCode*)value {
|
||||
return (value != nil) && ([value getValue] == ReturnCodeSuccess);
|
||||
}
|
||||
|
||||
+ (BOOL)isCancel:(ReturnCode*)value {
|
||||
return (value != nil) && ([value getValue] == ReturnCodeCancel);
|
||||
}
|
||||
|
||||
- (int)getValue {
|
||||
return _value;
|
||||
}
|
||||
|
||||
- (BOOL)isValueSuccess {
|
||||
return (_value == ReturnCodeSuccess);
|
||||
}
|
||||
|
||||
- (BOOL)isValueError {
|
||||
return ((_value != ReturnCodeSuccess) && (_value != ReturnCodeCancel));
|
||||
}
|
||||
|
||||
- (BOOL)isValueCancel {
|
||||
return (_value == ReturnCodeCancel);
|
||||
}
|
||||
|
||||
- (NSString*)description {
|
||||
return [NSString stringWithFormat:@"%d", _value];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (c) 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_SESSION_H
|
||||
#define FFMPEG_KIT_SESSION_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Log.h"
|
||||
#import "LogCallback.h"
|
||||
#import "LogRedirectionStrategy.h"
|
||||
#import "ReturnCode.h"
|
||||
#import "SessionState.h"
|
||||
|
||||
/**
|
||||
* <p>Common interface for all <code>FFmpegKit</code> sessions.
|
||||
*/
|
||||
@protocol Session
|
||||
|
||||
@required
|
||||
|
||||
/**
|
||||
* Returns the session specific log callback.
|
||||
*
|
||||
* @return session specific log callback
|
||||
*/
|
||||
- (LogCallback)getLogCallback;
|
||||
|
||||
/**
|
||||
* Returns the session identifier.
|
||||
*
|
||||
* @return session identifier
|
||||
*/
|
||||
- (long)getSessionId;
|
||||
|
||||
/**
|
||||
* Returns session create time.
|
||||
*
|
||||
* @return session create time
|
||||
*/
|
||||
- (NSDate*)getCreateTime;
|
||||
|
||||
/**
|
||||
* Returns session start time.
|
||||
*
|
||||
* @return session start time
|
||||
*/
|
||||
- (NSDate*)getStartTime;
|
||||
|
||||
/**
|
||||
* Returns session end time.
|
||||
*
|
||||
* @return session end time
|
||||
*/
|
||||
- (NSDate*)getEndTime;
|
||||
|
||||
/**
|
||||
* Returns the time taken to execute this session.
|
||||
*
|
||||
* @return time taken to execute this session in milliseconds or zero (0) if the session is
|
||||
* not over yet
|
||||
*/
|
||||
- (long)getDuration;
|
||||
|
||||
/**
|
||||
* Returns command arguments as an array.
|
||||
*
|
||||
* @return command arguments as an array
|
||||
*/
|
||||
- (NSArray*)getArguments;
|
||||
|
||||
/**
|
||||
* Returns command arguments as a concatenated string.
|
||||
*
|
||||
* @return command arguments as a concatenated string
|
||||
*/
|
||||
- (NSString*)getCommand;
|
||||
|
||||
/**
|
||||
* Returns all log entries generated for this session. If there are asynchronous
|
||||
* messages that are not delivered yet, this method waits for them until the given timeout.
|
||||
*
|
||||
* @param waitTimeout wait timeout for asynchronous messages in milliseconds
|
||||
* @return list of log entries generated for this session
|
||||
*/
|
||||
- (NSArray*)getAllLogsWithTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* Returns all log entries generated for this session. If there are asynchronous
|
||||
* messages that are not delivered yet, this method waits for them.
|
||||
*
|
||||
* @return list of log entries generated for this session
|
||||
*/
|
||||
- (NSArray*)getAllLogs;
|
||||
|
||||
/**
|
||||
* Returns all log entries delivered for this session. Note that if there are asynchronous
|
||||
* messages that are not delivered yet, this method will not wait for them and will return
|
||||
* immediately.
|
||||
*
|
||||
* @return list of log entries received for this session
|
||||
*/
|
||||
- (NSArray*)getLogs;
|
||||
|
||||
/**
|
||||
* Returns all log entries generated for this session as a concatenated string. If there are
|
||||
* asynchronous messages that are not delivered yet, this method waits for them until
|
||||
* the given timeout.
|
||||
*
|
||||
* @param waitTimeout wait timeout for asynchronous messages in milliseconds
|
||||
* @return all log entries generated for this session as a concatenated string
|
||||
*/
|
||||
- (NSString*)getAllLogsAsStringWithTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* Returns all log entries generated for this session as a concatenated string. If there are
|
||||
* asynchronous messages that are not delivered yet, this method waits for them.
|
||||
*
|
||||
* @return all log entries generated for this session as a concatenated string
|
||||
*/
|
||||
- (NSString*)getAllLogsAsString;
|
||||
|
||||
/**
|
||||
* Returns all log entries delivered for this session as a concatenated string. Note that if
|
||||
* there are asynchronous messages that are not delivered yet, this method will not wait
|
||||
* for them and will return immediately.
|
||||
*
|
||||
* @return list of log entries received for this session
|
||||
*/
|
||||
- (NSString*)getLogsAsString;
|
||||
|
||||
/**
|
||||
* Returns the log output generated while running the session.
|
||||
*
|
||||
* @return log output generated
|
||||
*/
|
||||
- (NSString*)getOutput;
|
||||
|
||||
/**
|
||||
* Returns the state of the session.
|
||||
*
|
||||
* @return state of the session
|
||||
*/
|
||||
- (SessionState)getState;
|
||||
|
||||
/**
|
||||
* Returns the return code for this session. Note that return code is only set for sessions
|
||||
* that end with SessionStateCompleted state. If a session is not started, still running or failed then
|
||||
* this method returns nil.
|
||||
*
|
||||
* @return the return code for this session if the session has completed, nil if session is
|
||||
* not started, still running or failed
|
||||
*/
|
||||
- (ReturnCode*)getReturnCode;
|
||||
|
||||
/**
|
||||
* Returns the stack trace of the exception received while executing this session.
|
||||
* <p>
|
||||
* The stack trace is only set for sessions that end with SessionStateFailed state. For sessions that has
|
||||
* SessionStateCompleted state this method returns nil.
|
||||
*
|
||||
* @return stack trace of the exception received while executing this session, nil if session
|
||||
* is not started, still running or completed
|
||||
*/
|
||||
- (NSString*)getFailStackTrace;
|
||||
|
||||
/**
|
||||
* Returns session specific log redirection strategy.
|
||||
*
|
||||
* @return session specific log redirection strategy
|
||||
*/
|
||||
- (LogRedirectionStrategy)getLogRedirectionStrategy;
|
||||
|
||||
/**
|
||||
* Returns whether there are still asynchronous messages being transmitted for this
|
||||
* session or not.
|
||||
*
|
||||
* @return true if there are still asynchronous messages being transmitted, false
|
||||
* otherwise
|
||||
*/
|
||||
- (BOOL)thereAreAsynchronousMessagesInTransmit;
|
||||
|
||||
/**
|
||||
* Adds a new log entry for this session.
|
||||
*
|
||||
* It is invoked internally by <code>FFmpegKit</code> library methods. Must not be used by user
|
||||
* applications.
|
||||
*
|
||||
* @param log log entry
|
||||
*/
|
||||
- (void)addLog:(Log*)log;
|
||||
|
||||
/**
|
||||
* Starts running the session.
|
||||
*/
|
||||
- (void)startRunning;
|
||||
|
||||
/**
|
||||
* Completes running the session with the provided return code.
|
||||
*
|
||||
* @param returnCode return code of the execution
|
||||
*/
|
||||
- (void)complete:(ReturnCode*)returnCode;
|
||||
|
||||
/**
|
||||
* Ends running the session with a failure.
|
||||
*
|
||||
* @param exception execution received
|
||||
*/
|
||||
- (void)fail:(NSException*)exception;
|
||||
|
||||
/**
|
||||
* Returns whether it is an <code>FFmpeg</code> session or not.
|
||||
*
|
||||
* @return true if it is an <code>FFmpeg</code> session, false otherwise
|
||||
*/
|
||||
- (BOOL)isFFmpeg;
|
||||
|
||||
/**
|
||||
* Returns whether it is an <code>FFprobe</code> session or not.
|
||||
*
|
||||
* @return true if it is an <code>FFprobe</code> session, false otherwise
|
||||
*/
|
||||
- (BOOL)isFFprobe;
|
||||
|
||||
/**
|
||||
* Returns whether it is a <code>MediaInformation</code> session or not.
|
||||
*
|
||||
* @return true if it is a <code>MediaInformation</code> session, false otherwise
|
||||
*/
|
||||
- (BOOL)isMediaInformation;
|
||||
|
||||
/**
|
||||
* Cancels running the session.
|
||||
*/
|
||||
- (void)cancel;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_SESSION_H
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 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 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 License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_SESSION_STATE_H
|
||||
#define FFMPEG_KIT_SESSION_STATE_H
|
||||
|
||||
typedef NS_ENUM(NSUInteger, SessionState) {
|
||||
SessionStateCreated,
|
||||
SessionStateRunning,
|
||||
SessionStateFailed,
|
||||
SessionStateCompleted
|
||||
};
|
||||
|
||||
#endif // FFMPEG_KIT_SESSION_STATE_H
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_STATISTICS_H
|
||||
#define FFMPEG_KIT_STATISTICS_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* Statistics entry for an FFmpeg execute session.
|
||||
*/
|
||||
@interface Statistics : NSObject
|
||||
|
||||
- (instancetype)init:(long)sessionId videoFrameNumber:(int)videoFrameNumber videoFps:(float)videoFps videoQuality:(float)videoQuality size:(int64_t)size time:(double)time bitrate:(double)bitrate speed:(double)speed;
|
||||
|
||||
- (long)getSessionId;
|
||||
|
||||
- (int)getVideoFrameNumber;
|
||||
|
||||
- (float)getVideoFps;
|
||||
|
||||
- (float)getVideoQuality;
|
||||
|
||||
- (long)getSize;
|
||||
|
||||
- (double)getTime;
|
||||
|
||||
- (double)getBitrate;
|
||||
|
||||
- (double)getSpeed;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_STATISTICS_H
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 "Statistics.h"
|
||||
|
||||
@implementation Statistics {
|
||||
long _sessionId;
|
||||
int _videoFrameNumber;
|
||||
float _videoFps;
|
||||
float _videoQuality;
|
||||
long _size;
|
||||
double _time;
|
||||
double _bitrate;
|
||||
double _speed;
|
||||
}
|
||||
|
||||
- (instancetype)init:(long)sessionId videoFrameNumber:(int)videoFrameNumber videoFps:(float)videoFps videoQuality:(float)videoQuality size:(int64_t)size time:(double)time bitrate:(double)bitrate speed:(double)speed {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_sessionId = sessionId;
|
||||
_videoFrameNumber = videoFrameNumber;
|
||||
_videoFps = videoFps;
|
||||
_videoQuality = videoQuality;
|
||||
_size = size;
|
||||
_time = time;
|
||||
_bitrate = bitrate;
|
||||
_speed = speed;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (long)getSessionId {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
- (int)getVideoFrameNumber {
|
||||
return _videoFrameNumber;
|
||||
}
|
||||
|
||||
- (float)getVideoFps {
|
||||
return _videoFps;
|
||||
}
|
||||
|
||||
- (float)getVideoQuality {
|
||||
return _videoQuality;
|
||||
}
|
||||
|
||||
- (long)getSize {
|
||||
return _size;
|
||||
}
|
||||
|
||||
- (double)getTime {
|
||||
return _time;
|
||||
}
|
||||
|
||||
- (double)getBitrate {
|
||||
return _bitrate;
|
||||
}
|
||||
|
||||
- (double)getSpeed {
|
||||
return _speed;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_STATISTICS_CALLBACK_H
|
||||
#define FFMPEG_KIT_STATISTICS_CALLBACK_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Statistics.h"
|
||||
|
||||
/**
|
||||
* <p>Callback that receives statistics generated for <code>FFmpegKit</code> sessions.
|
||||
*
|
||||
* @param statistics statistics entry
|
||||
*/
|
||||
typedef void (^StatisticsCallback)(Statistics* statistics);
|
||||
|
||||
#endif // FFMPEG_KIT_STATISTICS_CALLBACK_H
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2022 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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_STREAM_INFORMATION_H
|
||||
#define FFMPEG_KIT_STREAM_INFORMATION_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern NSString* const StreamKeyIndex;
|
||||
extern NSString* const StreamKeyType;
|
||||
extern NSString* const StreamKeyCodec;
|
||||
extern NSString* const StreamKeyCodecLong;
|
||||
extern NSString* const StreamKeyFormat;
|
||||
extern NSString* const StreamKeyWidth;
|
||||
extern NSString* const StreamKeyHeight;
|
||||
extern NSString* const StreamKeyBitRate;
|
||||
extern NSString* const StreamKeySampleRate;
|
||||
extern NSString* const StreamKeySampleFormat;
|
||||
extern NSString* const StreamKeyChannelLayout;
|
||||
extern NSString* const StreamKeySampleAspectRatio;
|
||||
extern NSString* const StreamKeyDisplayAspectRatio;
|
||||
extern NSString* const StreamKeyAverageFrameRate;
|
||||
extern NSString* const StreamKeyRealFrameRate;
|
||||
extern NSString* const StreamKeyTimeBase;
|
||||
extern NSString* const StreamKeyCodecTimeBase;
|
||||
extern NSString* const StreamKeyTags;
|
||||
|
||||
/**
|
||||
* Stream information class.
|
||||
*/
|
||||
@interface StreamInformation : NSObject
|
||||
|
||||
- (instancetype)init:(NSDictionary*)streamDictionary;
|
||||
|
||||
/**
|
||||
* Returns stream index.
|
||||
*
|
||||
* @return stream index, starting from zero
|
||||
*/
|
||||
- (NSNumber*)getIndex;
|
||||
|
||||
/**
|
||||
* Returns stream type.
|
||||
*
|
||||
* @return stream type; audio or video
|
||||
*/
|
||||
- (NSString*)getType;
|
||||
|
||||
/**
|
||||
* Returns stream codec.
|
||||
*
|
||||
* @return stream codec
|
||||
*/
|
||||
- (NSString*)getCodec;
|
||||
|
||||
/**
|
||||
* Returns stream codec in long format.
|
||||
*
|
||||
* @return stream codec with additional profile and mode information
|
||||
*/
|
||||
- (NSString*)getCodecLong;
|
||||
|
||||
/**
|
||||
* Returns stream format.
|
||||
*
|
||||
* @return stream format
|
||||
*/
|
||||
- (NSString*)getFormat;
|
||||
|
||||
/**
|
||||
* Returns width.
|
||||
*
|
||||
* @return width in pixels
|
||||
*/
|
||||
- (NSNumber*)getWidth;
|
||||
|
||||
/**
|
||||
* Returns height.
|
||||
*
|
||||
* @return height in pixels
|
||||
*/
|
||||
- (NSNumber*)getHeight;
|
||||
|
||||
/**
|
||||
* Returns bitrate.
|
||||
*
|
||||
* @return bitrate in kb/s
|
||||
*/
|
||||
- (NSString*)getBitrate;
|
||||
|
||||
/**
|
||||
* Returns sample rate.
|
||||
*
|
||||
* @return sample rate in hz
|
||||
*/
|
||||
- (NSString*)getSampleRate;
|
||||
|
||||
/**
|
||||
* Returns sample format.
|
||||
*
|
||||
* @return sample format
|
||||
*/
|
||||
- (NSString*)getSampleFormat;
|
||||
|
||||
/**
|
||||
* Returns channel layout.
|
||||
*
|
||||
* @return channel layout
|
||||
*/
|
||||
- (NSString*)getChannelLayout;
|
||||
|
||||
/**
|
||||
* Returns sample aspect ratio.
|
||||
*
|
||||
* @return sample aspect ratio
|
||||
*/
|
||||
- (NSString*)getSampleAspectRatio;
|
||||
|
||||
/**
|
||||
* Returns display aspect ratio.
|
||||
*
|
||||
* @return display aspect ratio
|
||||
*/
|
||||
- (NSString*)getDisplayAspectRatio;
|
||||
|
||||
/**
|
||||
* Returns average frame rate.
|
||||
*
|
||||
* @return average frame rate in fps
|
||||
*/
|
||||
- (NSString*)getAverageFrameRate;
|
||||
|
||||
/**
|
||||
* Returns real frame rate.
|
||||
*
|
||||
* @return real frame rate in tbr
|
||||
*/
|
||||
- (NSString*)getRealFrameRate;
|
||||
|
||||
/**
|
||||
* Returns time base.
|
||||
*
|
||||
* @return time base in tbn
|
||||
*/
|
||||
- (NSString*)getTimeBase;
|
||||
|
||||
/**
|
||||
* Returns codec time base.
|
||||
*
|
||||
* @return codec time base in tbc
|
||||
*/
|
||||
- (NSString*)getCodecTimeBase;
|
||||
|
||||
/**
|
||||
* Returns all tags.
|
||||
*
|
||||
* @return tags dictionary
|
||||
*/
|
||||
- (NSDictionary*)getTags;
|
||||
|
||||
/**
|
||||
* Returns the stream property associated with the key.
|
||||
*
|
||||
* @return stream property as string or nil if the key is not found
|
||||
*/
|
||||
- (NSString*)getStringProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns the stream property associated with the key.
|
||||
*
|
||||
* @return stream property as number or nil if the key is not found
|
||||
*/
|
||||
- (NSNumber*)getNumberProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns the stream property associated with the key.
|
||||
*
|
||||
* @return stream property as id or nil if the key is not found
|
||||
*/
|
||||
- (id)getProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns all stream properties defined.
|
||||
*
|
||||
* @return all stream properties in a dictionary or nil if no properties are defined
|
||||
*/
|
||||
- (NSDictionary*)getAllProperties;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_STREAM_INFORMATION_H
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2022 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 "StreamInformation.h"
|
||||
|
||||
NSString* const StreamKeyIndex = @"index";
|
||||
NSString* const StreamKeyType = @"codec_type";
|
||||
NSString* const StreamKeyCodec = @"codec_name";
|
||||
NSString* const StreamKeyCodecLong = @"codec_long_name";
|
||||
NSString* const StreamKeyFormat = @"pix_fmt";
|
||||
NSString* const StreamKeyWidth = @"width";
|
||||
NSString* const StreamKeyHeight = @"height";
|
||||
NSString* const StreamKeyBitRate = @"bit_rate";
|
||||
NSString* const StreamKeySampleRate = @"sample_rate";
|
||||
NSString* const StreamKeySampleFormat = @"sample_fmt";
|
||||
NSString* const StreamKeyChannelLayout = @"channel_layout";
|
||||
NSString* const StreamKeySampleAspectRatio = @"sample_aspect_ratio";
|
||||
NSString* const StreamKeyDisplayAspectRatio = @"display_aspect_ratio";
|
||||
NSString* const StreamKeyAverageFrameRate = @"avg_frame_rate";
|
||||
NSString* const StreamKeyRealFrameRate = @"r_frame_rate";
|
||||
NSString* const StreamKeyTimeBase = @"time_base";
|
||||
NSString* const StreamKeyCodecTimeBase = @"codec_time_base";
|
||||
NSString* const StreamKeyTags = @"tags";
|
||||
|
||||
@implementation StreamInformation {
|
||||
|
||||
/**
|
||||
* Stores all properties.
|
||||
*/
|
||||
NSDictionary *dictionary;
|
||||
|
||||
}
|
||||
|
||||
- (instancetype)init:(NSDictionary*)streamDictionary {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
dictionary = streamDictionary;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSNumber*)getIndex {
|
||||
return [self getNumberProperty:StreamKeyIndex];
|
||||
}
|
||||
|
||||
- (NSString*)getType {
|
||||
return [self getStringProperty:StreamKeyType];
|
||||
}
|
||||
|
||||
- (NSString*)getCodec {
|
||||
return [self getStringProperty:StreamKeyCodec];
|
||||
}
|
||||
|
||||
- (NSString*)getCodecLong {
|
||||
return [self getStringProperty:StreamKeyCodecLong];
|
||||
}
|
||||
|
||||
- (NSString*)getFormat {
|
||||
return [self getStringProperty:StreamKeyFormat];
|
||||
}
|
||||
|
||||
- (NSNumber*)getWidth {
|
||||
return [self getNumberProperty:StreamKeyWidth];
|
||||
}
|
||||
|
||||
- (NSNumber*)getHeight {
|
||||
return [self getNumberProperty:StreamKeyHeight];
|
||||
}
|
||||
|
||||
- (NSString*)getBitrate {
|
||||
return [self getStringProperty:StreamKeyBitRate];
|
||||
}
|
||||
|
||||
- (NSString*)getSampleRate {
|
||||
return [self getStringProperty:StreamKeySampleRate];
|
||||
}
|
||||
|
||||
- (NSString*)getSampleFormat {
|
||||
return [self getStringProperty:StreamKeySampleFormat];
|
||||
}
|
||||
|
||||
- (NSString*)getChannelLayout {
|
||||
return [self getStringProperty:StreamKeyChannelLayout];
|
||||
}
|
||||
|
||||
- (NSString*)getSampleAspectRatio {
|
||||
return [self getStringProperty:StreamKeySampleAspectRatio];
|
||||
}
|
||||
|
||||
- (NSString*)getDisplayAspectRatio {
|
||||
return [self getStringProperty:StreamKeyDisplayAspectRatio];
|
||||
}
|
||||
|
||||
- (NSString*)getAverageFrameRate {
|
||||
return [self getStringProperty:StreamKeyAverageFrameRate];
|
||||
}
|
||||
|
||||
- (NSString*)getRealFrameRate {
|
||||
return [self getStringProperty:StreamKeyRealFrameRate];
|
||||
}
|
||||
|
||||
- (NSString*)getTimeBase {
|
||||
return [self getStringProperty:StreamKeyTimeBase];
|
||||
}
|
||||
|
||||
- (NSString*)getCodecTimeBase {
|
||||
return [self getStringProperty:StreamKeyCodecTimeBase];
|
||||
}
|
||||
|
||||
- (NSDictionary*)getTags {
|
||||
return [self getProperty:StreamKeyTags];
|
||||
}
|
||||
|
||||
- (NSString*)getStringProperty:(NSString*)key {
|
||||
NSDictionary* allProperties = [self getAllProperties];
|
||||
if (allProperties == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return allProperties[key];
|
||||
}
|
||||
|
||||
- (NSNumber*)getNumberProperty:(NSString*)key {
|
||||
NSDictionary* allProperties = [self getAllProperties];
|
||||
if (allProperties == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return allProperties[key];
|
||||
}
|
||||
|
||||
- (id)getProperty:(NSString*)key {
|
||||
NSDictionary* allProperties = [self getAllProperties];
|
||||
if (allProperties == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return allProperties[key];
|
||||
}
|
||||
|
||||
- (NSDictionary*)getAllProperties {
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_EXCEPTION_H
|
||||
#define FFMPEG_KIT_EXCEPTION_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
/** Holds information to implement exception handling. */
|
||||
extern __thread jmp_buf ex_buf__;
|
||||
|
||||
#endif // FFMPEG_KIT_EXCEPTION_H
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "ffmpegkit_exception.h"
|
||||
|
||||
/** Holds information to implement exception handling. */
|
||||
__thread jmp_buf ex_buf__;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
* Various utilities for command line tools
|
||||
* copyright (c) 2003 Fabrice Bellard
|
||||
* copyright (c) 2018-2022 Taner Sener
|
||||
* copyright (c) 2023 ARTHENICA LTD
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg 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 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is the modified version of cmdutils.h file living in ffmpeg source code under the fftools folder. We
|
||||
* manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied
|
||||
* by us to develop mobile-ffmpeg and later ffmpeg-kit libraries.
|
||||
*
|
||||
* ffmpeg-kit changes by ARTHENICA LTD
|
||||
*
|
||||
* 07.2023
|
||||
* --------------------------------------------------------
|
||||
* - FFmpeg 6.0 changes migrated
|
||||
*
|
||||
* mobile-ffmpeg / ffmpeg-kit changes by Taner Sener
|
||||
*
|
||||
* 09.2022
|
||||
* --------------------------------------------------------
|
||||
* - config.h include added back
|
||||
*
|
||||
* 01.2020
|
||||
* --------------------------------------------------------
|
||||
* - ffprobe support added (variables used by ffprobe marked with "__thread" specifier)
|
||||
* - AV_LOG_STDERR log level added
|
||||
*
|
||||
* 12.2019
|
||||
* --------------------------------------------------------
|
||||
* - concurrent execution support ("__thread" specifier added to variables used by multiple threads)
|
||||
*
|
||||
* 03.2019
|
||||
* --------------------------------------------------------
|
||||
* - config.h include removed
|
||||
*
|
||||
* 08.2018
|
||||
* --------------------------------------------------------
|
||||
* - fftools_ prefix added to file name and include guards
|
||||
*
|
||||
* 07.2018
|
||||
* --------------------------------------------------------
|
||||
* - include guards renamed
|
||||
* - unused headers removed
|
||||
*/
|
||||
|
||||
#ifndef FFTOOLS_CMDUTILS_H
|
||||
#define FFTOOLS_CMDUTILS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "libavcodec/avcodec.h"
|
||||
#include "libavfilter/avfilter.h"
|
||||
#include "libavformat/avformat.h"
|
||||
#include "libswscale/swscale.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef main /* We don't want SDL to override our main() */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Defines logs printed to stderr by ffmpeg. They are not filtered and always redirected.
|
||||
*/
|
||||
#define AV_LOG_STDERR -16
|
||||
|
||||
/**
|
||||
* program name, defined by the program for show_version().
|
||||
*/
|
||||
extern __thread char *program_name;
|
||||
|
||||
/**
|
||||
* program birth year, defined by the program for show_banner()
|
||||
*/
|
||||
extern __thread int program_birth_year;
|
||||
|
||||
extern __thread AVDictionary *sws_dict;
|
||||
extern __thread AVDictionary *swr_opts;
|
||||
extern __thread AVDictionary *format_opts, *codec_opts;
|
||||
extern __thread int hide_banner;
|
||||
extern __thread int find_stream_info;
|
||||
|
||||
/**
|
||||
* Register a program-specific cleanup routine.
|
||||
*/
|
||||
void register_exit(void (*cb)(int ret));
|
||||
|
||||
/**
|
||||
* Reports an error corresponding to the provided
|
||||
* AVERROR code and calls exit_program() with the
|
||||
* corresponding POSIX error code.
|
||||
* @note ret must be an AVERROR-value of a POSIX error code
|
||||
* (i.e. AVERROR(EFOO) and not AVERROR_FOO).
|
||||
* library functions can return both, so call this only
|
||||
* with AVERROR(EFOO) of your own.
|
||||
*/
|
||||
void report_and_exit(int ret) av_noreturn;
|
||||
|
||||
/**
|
||||
* Wraps exit with a program-specific cleanup routine.
|
||||
*/
|
||||
void exit_program(int ret) av_noreturn;
|
||||
|
||||
/**
|
||||
* Initialize dynamic library loading
|
||||
*/
|
||||
void init_dynload(void);
|
||||
|
||||
/**
|
||||
* Uninitialize the cmdutils option system, in particular
|
||||
* free the *_opts contexts and their contents.
|
||||
*/
|
||||
void uninit_opts(void);
|
||||
|
||||
/**
|
||||
* Trivial log callback.
|
||||
* Only suitable for opt_help and similar since it lacks prefix handling.
|
||||
*/
|
||||
void log_callback_help(void* ptr, int level, const char* fmt, va_list vl);
|
||||
|
||||
/**
|
||||
* Fallback for options that are not explicitly handled, these will be
|
||||
* parsed through AVOptions.
|
||||
*/
|
||||
int opt_default(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Limit the execution time.
|
||||
*/
|
||||
int opt_timelimit(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Parse a string and return its corresponding value as a double.
|
||||
* Exit from the application if the string cannot be correctly
|
||||
* parsed or the corresponding value is invalid.
|
||||
*
|
||||
* @param context the context of the value to be set (e.g. the
|
||||
* corresponding command line option name)
|
||||
* @param numstr the string to be parsed
|
||||
* @param type the type (OPT_INT64 or OPT_FLOAT) as which the
|
||||
* string should be parsed
|
||||
* @param min the minimum valid accepted value
|
||||
* @param max the maximum valid accepted value
|
||||
*/
|
||||
double parse_number_or_die(const char *context, const char *numstr, int type,
|
||||
double min, double max);
|
||||
|
||||
/**
|
||||
* Parse a string specifying a time and return its corresponding
|
||||
* value as a number of microseconds. Exit from the application if
|
||||
* the string cannot be correctly parsed.
|
||||
*
|
||||
* @param context the context of the value to be set (e.g. the
|
||||
* corresponding command line option name)
|
||||
* @param timestr the string to be parsed
|
||||
* @param is_duration a flag which tells how to interpret timestr, if
|
||||
* not zero timestr is interpreted as a duration, otherwise as a
|
||||
* date
|
||||
*
|
||||
* @see av_parse_time()
|
||||
*/
|
||||
int64_t parse_time_or_die(const char *context, const char *timestr,
|
||||
int is_duration);
|
||||
|
||||
typedef struct SpecifierOpt {
|
||||
char *specifier; /**< stream/chapter/program/... specifier */
|
||||
union {
|
||||
uint8_t *str;
|
||||
int i;
|
||||
int64_t i64;
|
||||
uint64_t ui64;
|
||||
float f;
|
||||
double dbl;
|
||||
} u;
|
||||
} SpecifierOpt;
|
||||
|
||||
typedef struct OptionDef {
|
||||
const char *name;
|
||||
int flags;
|
||||
#define HAS_ARG 0x0001
|
||||
#define OPT_BOOL 0x0002
|
||||
#define OPT_EXPERT 0x0004
|
||||
#define OPT_STRING 0x0008
|
||||
#define OPT_VIDEO 0x0010
|
||||
#define OPT_AUDIO 0x0020
|
||||
#define OPT_INT 0x0080
|
||||
#define OPT_FLOAT 0x0100
|
||||
#define OPT_SUBTITLE 0x0200
|
||||
#define OPT_INT64 0x0400
|
||||
#define OPT_EXIT 0x0800
|
||||
#define OPT_DATA 0x1000
|
||||
#define OPT_PERFILE 0x2000 /* the option is per-file (currently ffmpeg-only).
|
||||
implied by OPT_OFFSET or OPT_SPEC */
|
||||
#define OPT_OFFSET 0x4000 /* option is specified as an offset in a passed optctx */
|
||||
#define OPT_SPEC 0x8000 /* option is to be stored in an array of SpecifierOpt.
|
||||
Implies OPT_OFFSET. Next element after the offset is
|
||||
an int containing element count in the array. */
|
||||
#define OPT_TIME 0x10000
|
||||
#define OPT_DOUBLE 0x20000
|
||||
#define OPT_INPUT 0x40000
|
||||
#define OPT_OUTPUT 0x80000
|
||||
union {
|
||||
void *dst_ptr;
|
||||
int (*func_arg)(void *, const char *, const char *);
|
||||
size_t off;
|
||||
} u;
|
||||
const char *help;
|
||||
const char *argname;
|
||||
} OptionDef;
|
||||
|
||||
/**
|
||||
* Print help for all options matching specified flags.
|
||||
*
|
||||
* @param options a list of options
|
||||
* @param msg title of this group. Only printed if at least one option matches.
|
||||
* @param req_flags print only options which have all those flags set.
|
||||
* @param rej_flags don't print options which have any of those flags set.
|
||||
* @param alt_flags print only options that have at least one of those flags set
|
||||
*/
|
||||
void show_help_options(const OptionDef *options, const char *msg, int req_flags,
|
||||
int rej_flags, int alt_flags);
|
||||
|
||||
/**
|
||||
* Show help for all options with given flags in class and all its
|
||||
* children.
|
||||
*/
|
||||
void show_help_children(const AVClass *clazz, int flags);
|
||||
|
||||
/**
|
||||
* Per-fftool specific help handler. Implemented in each
|
||||
* fftool, called by show_help().
|
||||
*/
|
||||
void show_help_default_ffmpeg(const char *opt, const char *arg);
|
||||
void show_help_default_ffprobe(const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Parse the command line arguments.
|
||||
*
|
||||
* @param optctx an opaque options context
|
||||
* @param argc number of command line arguments
|
||||
* @param argv values of command line arguments
|
||||
* @param options Array with the definitions required to interpret every
|
||||
* option of the form: -option_name [argument]
|
||||
* @param parse_arg_function Name of the function called to process every
|
||||
* argument without a leading option name flag. NULL if such arguments do
|
||||
* not have to be processed.
|
||||
*/
|
||||
void parse_options(void *optctx, int argc, char **argv, const OptionDef *options,
|
||||
void (* parse_arg_function)(void *optctx, const char*));
|
||||
|
||||
/**
|
||||
* Parse one given option.
|
||||
*
|
||||
* @return on success 1 if arg was consumed, 0 otherwise; negative number on error
|
||||
*/
|
||||
int parse_option(void *optctx, const char *opt, const char *arg,
|
||||
const OptionDef *options);
|
||||
|
||||
/**
|
||||
* An option extracted from the commandline.
|
||||
* Cannot use AVDictionary because of options like -map which can be
|
||||
* used multiple times.
|
||||
*/
|
||||
typedef struct Option {
|
||||
const OptionDef *opt;
|
||||
const char *key;
|
||||
const char *val;
|
||||
} Option;
|
||||
|
||||
typedef struct OptionGroupDef {
|
||||
/**< group name */
|
||||
const char *name;
|
||||
/**
|
||||
* Option to be used as group separator. Can be NULL for groups which
|
||||
* are terminated by a non-option argument (e.g. ffmpeg output files)
|
||||
*/
|
||||
const char *sep;
|
||||
/**
|
||||
* Option flags that must be set on each option that is
|
||||
* applied to this group
|
||||
*/
|
||||
int flags;
|
||||
} OptionGroupDef;
|
||||
|
||||
typedef struct OptionGroup {
|
||||
const OptionGroupDef *group_def;
|
||||
const char *arg;
|
||||
|
||||
Option *opts;
|
||||
int nb_opts;
|
||||
|
||||
AVDictionary *codec_opts;
|
||||
AVDictionary *format_opts;
|
||||
AVDictionary *sws_dict;
|
||||
AVDictionary *swr_opts;
|
||||
} OptionGroup;
|
||||
|
||||
/**
|
||||
* A list of option groups that all have the same group type
|
||||
* (e.g. input files or output files)
|
||||
*/
|
||||
typedef struct OptionGroupList {
|
||||
const OptionGroupDef *group_def;
|
||||
|
||||
OptionGroup *groups;
|
||||
int nb_groups;
|
||||
} OptionGroupList;
|
||||
|
||||
typedef struct OptionParseContext {
|
||||
OptionGroup global_opts;
|
||||
|
||||
OptionGroupList *groups;
|
||||
int nb_groups;
|
||||
|
||||
/* parsing state */
|
||||
OptionGroup cur_group;
|
||||
} OptionParseContext;
|
||||
|
||||
/**
|
||||
* Parse an options group and write results into optctx.
|
||||
*
|
||||
* @param optctx an app-specific options context. NULL for global options group
|
||||
* @param g option group
|
||||
*/
|
||||
int parse_optgroup(void *optctx, OptionGroup *g);
|
||||
|
||||
/**
|
||||
* Split the commandline into an intermediate form convenient for further
|
||||
* processing.
|
||||
*
|
||||
* The commandline is assumed to be composed of options which either belong to a
|
||||
* group (those with OPT_SPEC, OPT_OFFSET or OPT_PERFILE) or are global
|
||||
* (everything else).
|
||||
*
|
||||
* A group (defined by an OptionGroupDef struct) is a sequence of options
|
||||
* terminated by either a group separator option (e.g. -i) or a parameter that
|
||||
* is not an option (doesn't start with -). A group without a separator option
|
||||
* must always be first in the supplied groups list.
|
||||
*
|
||||
* All options within the same group are stored in one OptionGroup struct in an
|
||||
* OptionGroupList, all groups with the same group definition are stored in one
|
||||
* OptionGroupList in OptionParseContext.groups. The order of group lists is the
|
||||
* same as the order of group definitions.
|
||||
*/
|
||||
int split_commandline(OptionParseContext *octx, int argc, char *argv[],
|
||||
const OptionDef *options,
|
||||
const OptionGroupDef *groups, int nb_groups);
|
||||
|
||||
/**
|
||||
* Free all allocated memory in an OptionParseContext.
|
||||
*/
|
||||
void uninit_parse_context(OptionParseContext *octx);
|
||||
|
||||
/**
|
||||
* Find the '-loglevel' option in the command line args and apply it.
|
||||
*/
|
||||
void parse_loglevel(int argc, char **argv, const OptionDef *options);
|
||||
|
||||
/**
|
||||
* Return index of option opt in argv or 0 if not found.
|
||||
*/
|
||||
int locate_option(int argc, char **argv, const OptionDef *options,
|
||||
const char *optname);
|
||||
|
||||
/**
|
||||
* Check if the given stream matches a stream specifier.
|
||||
*
|
||||
* @param s Corresponding format context.
|
||||
* @param st Stream from s to be checked.
|
||||
* @param spec A stream specifier of the [v|a|s|d]:[\<stream index\>] form.
|
||||
*
|
||||
* @return 1 if the stream matches, 0 if it doesn't, <0 on error
|
||||
*/
|
||||
int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec);
|
||||
|
||||
/**
|
||||
* Filter out options for given codec.
|
||||
*
|
||||
* Create a new options dictionary containing only the options from
|
||||
* opts which apply to the codec with ID codec_id.
|
||||
*
|
||||
* @param opts dictionary to place options in
|
||||
* @param codec_id ID of the codec that should be filtered for
|
||||
* @param s Corresponding format context.
|
||||
* @param st A stream from s for which the options should be filtered.
|
||||
* @param codec The particular codec for which the options should be filtered.
|
||||
* If null, the default one is looked up according to the codec id.
|
||||
* @return a pointer to the created dictionary
|
||||
*/
|
||||
AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
|
||||
AVFormatContext *s, AVStream *st, const AVCodec *codec);
|
||||
|
||||
/**
|
||||
* Setup AVCodecContext options for avformat_find_stream_info().
|
||||
*
|
||||
* Create an array of dictionaries, one dictionary for each stream
|
||||
* contained in s.
|
||||
* Each dictionary will contain the options from codec_opts which can
|
||||
* be applied to the corresponding stream codec context.
|
||||
*
|
||||
* @return pointer to the created array of dictionaries.
|
||||
* Calls exit() on failure.
|
||||
*/
|
||||
AVDictionary **setup_find_stream_info_opts(AVFormatContext *s,
|
||||
AVDictionary *codec_opts);
|
||||
|
||||
/**
|
||||
* Print an error message to stderr, indicating filename and a human
|
||||
* readable description of the error code err.
|
||||
*
|
||||
* If strerror_r() is not available the use of this function in a
|
||||
* multithreaded application may be unsafe.
|
||||
*
|
||||
* @see av_strerror()
|
||||
*/
|
||||
void print_error(const char *filename, int err);
|
||||
|
||||
/**
|
||||
* Print the program banner to stderr. The banner contents depend on the
|
||||
* current version of the repository and of the libav* libraries used by
|
||||
* the program.
|
||||
*/
|
||||
void show_banner(int argc, char **argv, const OptionDef *options);
|
||||
|
||||
/**
|
||||
* Return a positive value if a line read from standard input
|
||||
* starts with [yY], otherwise return 0.
|
||||
*/
|
||||
int read_yesno(void);
|
||||
|
||||
/**
|
||||
* Get a file corresponding to a preset file.
|
||||
*
|
||||
* If is_path is non-zero, look for the file in the path preset_name.
|
||||
* Otherwise search for a file named arg.ffpreset in the directories
|
||||
* $FFMPEG_DATADIR (if set), $HOME/.ffmpeg, and in the datadir defined
|
||||
* at configuration time or in a "ffpresets" folder along the executable
|
||||
* on win32, in that order. If no such file is found and
|
||||
* codec_name is defined, then search for a file named
|
||||
* codec_name-preset_name.avpreset in the above-mentioned directories.
|
||||
*
|
||||
* @param filename buffer where the name of the found filename is written
|
||||
* @param filename_size size in bytes of the filename buffer
|
||||
* @param preset_name name of the preset to search
|
||||
* @param is_path tell if preset_name is a filename path
|
||||
* @param codec_name name of the codec for which to look for the
|
||||
* preset, may be NULL
|
||||
*/
|
||||
FILE *get_preset_file(char *filename, size_t filename_size,
|
||||
const char *preset_name, int is_path, const char *codec_name);
|
||||
|
||||
/**
|
||||
* Realloc array to hold new_size elements of elem_size.
|
||||
* Calls exit() on failure.
|
||||
*
|
||||
* @param array array to reallocate
|
||||
* @param elem_size size in bytes of each element
|
||||
* @param size new element count will be written here
|
||||
* @param new_size number of elements to place in reallocated array
|
||||
* @return reallocated array
|
||||
*/
|
||||
void *grow_array(void *array, int elem_size, int *size, int new_size);
|
||||
|
||||
/**
|
||||
* Atomically add a new element to an array of pointers, i.e. allocate
|
||||
* a new entry, reallocate the array of pointers and make the new last
|
||||
* member of this array point to the newly allocated buffer.
|
||||
* Calls exit() on failure.
|
||||
*
|
||||
* @param array array of pointers to reallocate
|
||||
* @param elem_size size of the new element to allocate
|
||||
* @param nb_elems pointer to the number of elements of the array array;
|
||||
* *nb_elems will be incremented by one by this function.
|
||||
* @return pointer to the newly allocated entry
|
||||
*/
|
||||
void *allocate_array_elem(void *array, size_t elem_size, int *nb_elems);
|
||||
|
||||
#define GROW_ARRAY(array, nb_elems)\
|
||||
array = grow_array(array, sizeof(*array), &nb_elems, nb_elems + 1)
|
||||
|
||||
#define ALLOC_ARRAY_ELEM(array, nb_elems)\
|
||||
allocate_array_elem(&array, sizeof(*array[0]), &nb_elems)
|
||||
|
||||
#define GET_PIX_FMT_NAME(pix_fmt)\
|
||||
const char *name = av_get_pix_fmt_name(pix_fmt);
|
||||
|
||||
#define GET_CODEC_NAME(id)\
|
||||
const char *name = avcodec_descriptor_get(id)->name;
|
||||
|
||||
#define GET_SAMPLE_FMT_NAME(sample_fmt)\
|
||||
const char *name = av_get_sample_fmt_name(sample_fmt)
|
||||
|
||||
#define GET_SAMPLE_RATE_NAME(rate)\
|
||||
char name[16];\
|
||||
snprintf(name, sizeof(name), "%d", rate);
|
||||
|
||||
double get_rotation(int32_t *displaymatrix);
|
||||
|
||||
#endif /* FFTOOLS_CMDUTILS_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,912 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
* Copyright (c) 2018-2022 Taner Sener
|
||||
* Copyright (c) 2023 ARTHENICA LTD
|
||||
*
|
||||
* FFmpeg 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 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is the modified version of ffmpeg.h file living in ffmpeg source code under the fftools folder. We
|
||||
* manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied
|
||||
* by us to develop mobile-ffmpeg and later ffmpeg-kit libraries.
|
||||
*
|
||||
* ffmpeg-kit changes by ARTHENICA LTD
|
||||
*
|
||||
* 07.2023
|
||||
* --------------------------------------------------------
|
||||
* - FFmpeg 6.0 changes migrated
|
||||
* - WARN_MULTIPLE_OPT_USAGE, MATCH_PER_STREAM_OPT, MATCH_PER_TYPE_OPT, SPECIFIER_OPT_FMT declarations migrated to
|
||||
* ffmpeg_mux.h
|
||||
* - "class" member field renamed as clazz
|
||||
* - time field in set_report_callback updated as double
|
||||
*
|
||||
* mobile-ffmpeg / ffmpeg-kit changes by Taner Sener
|
||||
*
|
||||
* 09.2022
|
||||
* --------------------------------------------------------
|
||||
* - config.h include added back
|
||||
* - volatile dropped from thread local variables
|
||||
* - dropped signatures of ffmpeg_opt.c methods called by both ffmpeg and ffprobe
|
||||
*
|
||||
* 06.2020
|
||||
* --------------------------------------------------------
|
||||
* - cancel_operation() method signature updated with id
|
||||
*
|
||||
* 12.2019
|
||||
* --------------------------------------------------------
|
||||
* - concurrent execution support ("__thread" specifier added to variables used by multiple threads,
|
||||
* signatures of ffmpeg_opt.c methods called by both ffmpeg and ffprobe added)
|
||||
*
|
||||
* 03.2019
|
||||
* --------------------------------------------------------
|
||||
* - config.h include removed
|
||||
*
|
||||
* 08.2018
|
||||
* --------------------------------------------------------
|
||||
* - fftools_ prefix added to file name and include guards
|
||||
* - set_report_callback() method declared
|
||||
* - cancel_operation() method declared
|
||||
*
|
||||
* 07.2018
|
||||
* --------------------------------------------------------
|
||||
* - include guards renamed
|
||||
*/
|
||||
|
||||
#ifndef FFTOOLS_FFMPEG_H
|
||||
#define FFTOOLS_FFMPEG_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "fftools_cmdutils.h"
|
||||
#include "fftools_sync_queue.h"
|
||||
|
||||
#include "libavformat/avformat.h"
|
||||
#include "libavformat/avio.h"
|
||||
|
||||
#include "libavcodec/avcodec.h"
|
||||
#include "libavcodec/bsf.h"
|
||||
|
||||
#include "libavfilter/avfilter.h"
|
||||
|
||||
#include "libavutil/avutil.h"
|
||||
#include "libavutil/dict.h"
|
||||
#include "libavutil/eval.h"
|
||||
#include "libavutil/fifo.h"
|
||||
#include "libavutil/hwcontext.h"
|
||||
#include "libavutil/pixfmt.h"
|
||||
#include "libavutil/rational.h"
|
||||
#include "libavutil/thread.h"
|
||||
#include "libavutil/threadmessage.h"
|
||||
|
||||
#include "libswresample/swresample.h"
|
||||
|
||||
// deprecated features
|
||||
#define FFMPEG_OPT_PSNR 1
|
||||
#define FFMPEG_OPT_MAP_CHANNEL 1
|
||||
#define FFMPEG_OPT_MAP_SYNC 1
|
||||
#define FFMPEG_ROTATION_METADATA 1
|
||||
|
||||
enum VideoSyncMethod {
|
||||
VSYNC_AUTO = -1,
|
||||
VSYNC_PASSTHROUGH,
|
||||
VSYNC_CFR,
|
||||
VSYNC_VFR,
|
||||
VSYNC_VSCFR,
|
||||
VSYNC_DROP,
|
||||
};
|
||||
|
||||
#define MAX_STREAMS 1024 /* arbitrary sanity check value */
|
||||
|
||||
enum HWAccelID {
|
||||
HWACCEL_NONE = 0,
|
||||
HWACCEL_AUTO,
|
||||
HWACCEL_GENERIC,
|
||||
};
|
||||
|
||||
typedef struct HWDevice {
|
||||
const char *name;
|
||||
enum AVHWDeviceType type;
|
||||
AVBufferRef *device_ref;
|
||||
} HWDevice;
|
||||
|
||||
/* select an input stream for an output stream */
|
||||
typedef struct StreamMap {
|
||||
int disabled; /* 1 is this mapping is disabled by a negative map */
|
||||
int file_index;
|
||||
int stream_index;
|
||||
char *linklabel; /* name of an output link, for mapping lavfi outputs */
|
||||
} StreamMap;
|
||||
|
||||
#if FFMPEG_OPT_MAP_CHANNEL
|
||||
typedef struct {
|
||||
int file_idx, stream_idx, channel_idx; // input
|
||||
int ofile_idx, ostream_idx; // output
|
||||
} AudioChannelMap;
|
||||
#endif
|
||||
|
||||
typedef struct OptionsContext {
|
||||
OptionGroup *g;
|
||||
|
||||
/* input/output options */
|
||||
int64_t start_time;
|
||||
int64_t start_time_eof;
|
||||
int seek_timestamp;
|
||||
const char *format;
|
||||
|
||||
SpecifierOpt *codec_names;
|
||||
int nb_codec_names;
|
||||
SpecifierOpt *audio_ch_layouts;
|
||||
int nb_audio_ch_layouts;
|
||||
SpecifierOpt *audio_channels;
|
||||
int nb_audio_channels;
|
||||
SpecifierOpt *audio_sample_rate;
|
||||
int nb_audio_sample_rate;
|
||||
SpecifierOpt *frame_rates;
|
||||
int nb_frame_rates;
|
||||
SpecifierOpt *max_frame_rates;
|
||||
int nb_max_frame_rates;
|
||||
SpecifierOpt *frame_sizes;
|
||||
int nb_frame_sizes;
|
||||
SpecifierOpt *frame_pix_fmts;
|
||||
int nb_frame_pix_fmts;
|
||||
|
||||
/* input options */
|
||||
int64_t input_ts_offset;
|
||||
int loop;
|
||||
int rate_emu;
|
||||
float readrate;
|
||||
int accurate_seek;
|
||||
int thread_queue_size;
|
||||
int input_sync_ref;
|
||||
int find_stream_info;
|
||||
|
||||
SpecifierOpt *ts_scale;
|
||||
int nb_ts_scale;
|
||||
SpecifierOpt *dump_attachment;
|
||||
int nb_dump_attachment;
|
||||
SpecifierOpt *hwaccels;
|
||||
int nb_hwaccels;
|
||||
SpecifierOpt *hwaccel_devices;
|
||||
int nb_hwaccel_devices;
|
||||
SpecifierOpt *hwaccel_output_formats;
|
||||
int nb_hwaccel_output_formats;
|
||||
SpecifierOpt *autorotate;
|
||||
int nb_autorotate;
|
||||
|
||||
/* output options */
|
||||
StreamMap *stream_maps;
|
||||
int nb_stream_maps;
|
||||
#if FFMPEG_OPT_MAP_CHANNEL
|
||||
AudioChannelMap *audio_channel_maps; /* one info entry per -map_channel */
|
||||
int nb_audio_channel_maps; /* number of (valid) -map_channel settings */
|
||||
#endif
|
||||
const char **attachments;
|
||||
int nb_attachments;
|
||||
|
||||
int chapters_input_file;
|
||||
|
||||
int64_t recording_time;
|
||||
int64_t stop_time;
|
||||
int64_t limit_filesize;
|
||||
float mux_preload;
|
||||
float mux_max_delay;
|
||||
float shortest_buf_duration;
|
||||
int shortest;
|
||||
int bitexact;
|
||||
|
||||
int video_disable;
|
||||
int audio_disable;
|
||||
int subtitle_disable;
|
||||
int data_disable;
|
||||
|
||||
/* indexed by output file stream index */
|
||||
int *streamid_map;
|
||||
int nb_streamid_map;
|
||||
|
||||
SpecifierOpt *metadata;
|
||||
int nb_metadata;
|
||||
SpecifierOpt *max_frames;
|
||||
int nb_max_frames;
|
||||
SpecifierOpt *bitstream_filters;
|
||||
int nb_bitstream_filters;
|
||||
SpecifierOpt *codec_tags;
|
||||
int nb_codec_tags;
|
||||
SpecifierOpt *sample_fmts;
|
||||
int nb_sample_fmts;
|
||||
SpecifierOpt *qscale;
|
||||
int nb_qscale;
|
||||
SpecifierOpt *forced_key_frames;
|
||||
int nb_forced_key_frames;
|
||||
SpecifierOpt *fps_mode;
|
||||
int nb_fps_mode;
|
||||
SpecifierOpt *force_fps;
|
||||
int nb_force_fps;
|
||||
SpecifierOpt *frame_aspect_ratios;
|
||||
int nb_frame_aspect_ratios;
|
||||
SpecifierOpt *display_rotations;
|
||||
int nb_display_rotations;
|
||||
SpecifierOpt *display_hflips;
|
||||
int nb_display_hflips;
|
||||
SpecifierOpt *display_vflips;
|
||||
int nb_display_vflips;
|
||||
SpecifierOpt *rc_overrides;
|
||||
int nb_rc_overrides;
|
||||
SpecifierOpt *intra_matrices;
|
||||
int nb_intra_matrices;
|
||||
SpecifierOpt *inter_matrices;
|
||||
int nb_inter_matrices;
|
||||
SpecifierOpt *chroma_intra_matrices;
|
||||
int nb_chroma_intra_matrices;
|
||||
SpecifierOpt *top_field_first;
|
||||
int nb_top_field_first;
|
||||
SpecifierOpt *metadata_map;
|
||||
int nb_metadata_map;
|
||||
SpecifierOpt *presets;
|
||||
int nb_presets;
|
||||
SpecifierOpt *copy_initial_nonkeyframes;
|
||||
int nb_copy_initial_nonkeyframes;
|
||||
SpecifierOpt *copy_prior_start;
|
||||
int nb_copy_prior_start;
|
||||
SpecifierOpt *filters;
|
||||
int nb_filters;
|
||||
SpecifierOpt *filter_scripts;
|
||||
int nb_filter_scripts;
|
||||
SpecifierOpt *reinit_filters;
|
||||
int nb_reinit_filters;
|
||||
SpecifierOpt *fix_sub_duration;
|
||||
int nb_fix_sub_duration;
|
||||
SpecifierOpt *fix_sub_duration_heartbeat;
|
||||
int nb_fix_sub_duration_heartbeat;
|
||||
SpecifierOpt *canvas_sizes;
|
||||
int nb_canvas_sizes;
|
||||
SpecifierOpt *pass;
|
||||
int nb_pass;
|
||||
SpecifierOpt *passlogfiles;
|
||||
int nb_passlogfiles;
|
||||
SpecifierOpt *max_muxing_queue_size;
|
||||
int nb_max_muxing_queue_size;
|
||||
SpecifierOpt *muxing_queue_data_threshold;
|
||||
int nb_muxing_queue_data_threshold;
|
||||
SpecifierOpt *guess_layout_max;
|
||||
int nb_guess_layout_max;
|
||||
SpecifierOpt *apad;
|
||||
int nb_apad;
|
||||
SpecifierOpt *discard;
|
||||
int nb_discard;
|
||||
SpecifierOpt *disposition;
|
||||
int nb_disposition;
|
||||
SpecifierOpt *program;
|
||||
int nb_program;
|
||||
SpecifierOpt *time_bases;
|
||||
int nb_time_bases;
|
||||
SpecifierOpt *enc_time_bases;
|
||||
int nb_enc_time_bases;
|
||||
SpecifierOpt *autoscale;
|
||||
int nb_autoscale;
|
||||
SpecifierOpt *bits_per_raw_sample;
|
||||
int nb_bits_per_raw_sample;
|
||||
SpecifierOpt *enc_stats_pre;
|
||||
int nb_enc_stats_pre;
|
||||
SpecifierOpt *enc_stats_post;
|
||||
int nb_enc_stats_post;
|
||||
SpecifierOpt *mux_stats;
|
||||
int nb_mux_stats;
|
||||
SpecifierOpt *enc_stats_pre_fmt;
|
||||
int nb_enc_stats_pre_fmt;
|
||||
SpecifierOpt *enc_stats_post_fmt;
|
||||
int nb_enc_stats_post_fmt;
|
||||
SpecifierOpt *mux_stats_fmt;
|
||||
int nb_mux_stats_fmt;
|
||||
} OptionsContext;
|
||||
|
||||
typedef struct InputFilter {
|
||||
AVFilterContext *filter;
|
||||
struct InputStream *ist;
|
||||
struct FilterGraph *graph;
|
||||
uint8_t *name;
|
||||
enum AVMediaType type; // AVMEDIA_TYPE_SUBTITLE for sub2video
|
||||
|
||||
AVFifo *frame_queue;
|
||||
|
||||
// parameters configured for this input
|
||||
int format;
|
||||
|
||||
int width, height;
|
||||
AVRational sample_aspect_ratio;
|
||||
|
||||
int sample_rate;
|
||||
AVChannelLayout ch_layout;
|
||||
|
||||
AVBufferRef *hw_frames_ctx;
|
||||
int32_t *displaymatrix;
|
||||
|
||||
int eof;
|
||||
} InputFilter;
|
||||
|
||||
typedef struct OutputFilter {
|
||||
AVFilterContext *filter;
|
||||
struct OutputStream *ost;
|
||||
struct FilterGraph *graph;
|
||||
uint8_t *name;
|
||||
|
||||
/* temporary storage until stream maps are processed */
|
||||
AVFilterInOut *out_tmp;
|
||||
enum AVMediaType type;
|
||||
|
||||
/* desired output stream properties */
|
||||
int width, height;
|
||||
AVRational frame_rate;
|
||||
int format;
|
||||
int sample_rate;
|
||||
AVChannelLayout ch_layout;
|
||||
|
||||
// those are only set if no format is specified and the encoder gives us multiple options
|
||||
// They point directly to the relevant lists of the encoder.
|
||||
const int *formats;
|
||||
const AVChannelLayout *ch_layouts;
|
||||
const int *sample_rates;
|
||||
} OutputFilter;
|
||||
|
||||
typedef struct FilterGraph {
|
||||
int index;
|
||||
const char *graph_desc;
|
||||
|
||||
AVFilterGraph *graph;
|
||||
int reconfiguration;
|
||||
// true when the filtergraph contains only meta filters
|
||||
// that do not modify the frame data
|
||||
int is_meta;
|
||||
|
||||
InputFilter **inputs;
|
||||
int nb_inputs;
|
||||
OutputFilter **outputs;
|
||||
int nb_outputs;
|
||||
} FilterGraph;
|
||||
|
||||
typedef struct InputStream {
|
||||
int file_index;
|
||||
AVStream *st;
|
||||
int discard; /* true if stream data should be discarded */
|
||||
int user_set_discard;
|
||||
int decoding_needed; /* non zero if the packets must be decoded in 'raw_fifo', see DECODING_FOR_* */
|
||||
#define DECODING_FOR_OST 1
|
||||
#define DECODING_FOR_FILTER 2
|
||||
int processing_needed; /* non zero if the packets must be processed */
|
||||
// should attach FrameData as opaque_ref after decoding
|
||||
int want_frame_data;
|
||||
|
||||
/**
|
||||
* Codec parameters - to be used by the decoding/streamcopy code.
|
||||
* st->codecpar should not be accessed, because it may be modified
|
||||
* concurrently by the demuxing thread.
|
||||
*/
|
||||
AVCodecParameters *par;
|
||||
AVCodecContext *dec_ctx;
|
||||
const AVCodec *dec;
|
||||
AVFrame *decoded_frame;
|
||||
AVPacket *pkt;
|
||||
|
||||
AVRational framerate_guessed;
|
||||
|
||||
int64_t prev_pkt_pts;
|
||||
int64_t start; /* time when read started */
|
||||
/* predicted dts of the next packet read for this stream or (when there are
|
||||
* several frames in a packet) of the next frame in current packet (in AV_TIME_BASE units) */
|
||||
int64_t next_dts;
|
||||
int64_t first_dts; ///< dts of the first packet read for this stream (in AV_TIME_BASE units)
|
||||
int64_t dts; ///< dts of the last packet read for this stream (in AV_TIME_BASE units)
|
||||
|
||||
int64_t next_pts; ///< synthetic pts for the next decode frame (in AV_TIME_BASE units)
|
||||
int64_t pts; ///< current pts of the decoded frame (in AV_TIME_BASE units)
|
||||
int wrap_correction_done;
|
||||
|
||||
// the value of AVCodecParserContext.repeat_pict from the AVStream parser
|
||||
// for the last packet returned from ifile_get_packet()
|
||||
// -1 if unknown
|
||||
// FIXME: this is a hack, the avstream parser should not be used
|
||||
int last_pkt_repeat_pict;
|
||||
|
||||
int64_t filter_in_rescale_delta_last;
|
||||
|
||||
int64_t min_pts; /* pts with the smallest value in a current stream */
|
||||
int64_t max_pts; /* pts with the higher value in a current stream */
|
||||
|
||||
// when forcing constant input framerate through -r,
|
||||
// this contains the pts that will be given to the next decoded frame
|
||||
int64_t cfr_next_pts;
|
||||
|
||||
int64_t nb_samples; /* number of samples in the last decoded audio frame before looping */
|
||||
|
||||
double ts_scale;
|
||||
int saw_first_ts;
|
||||
AVDictionary *decoder_opts;
|
||||
AVRational framerate; /* framerate forced with -r */
|
||||
int top_field_first;
|
||||
int guess_layout_max;
|
||||
|
||||
int autorotate;
|
||||
|
||||
int fix_sub_duration;
|
||||
struct { /* previous decoded subtitle and related variables */
|
||||
int got_output;
|
||||
int ret;
|
||||
AVSubtitle subtitle;
|
||||
} prev_sub;
|
||||
|
||||
struct sub2video {
|
||||
int64_t last_pts;
|
||||
int64_t end_pts;
|
||||
AVFifo *sub_queue; ///< queue of AVSubtitle* before filter init
|
||||
AVFrame *frame;
|
||||
int w, h;
|
||||
unsigned int initialize; ///< marks if sub2video_update should force an initialization
|
||||
} sub2video;
|
||||
|
||||
/* decoded data from this stream goes into all those filters
|
||||
* currently video and audio only */
|
||||
InputFilter **filters;
|
||||
int nb_filters;
|
||||
|
||||
int reinit_filters;
|
||||
|
||||
/* hwaccel options */
|
||||
enum HWAccelID hwaccel_id;
|
||||
enum AVHWDeviceType hwaccel_device_type;
|
||||
char *hwaccel_device;
|
||||
enum AVPixelFormat hwaccel_output_format;
|
||||
|
||||
int (*hwaccel_retrieve_data)(AVCodecContext *s, AVFrame *frame);
|
||||
enum AVPixelFormat hwaccel_pix_fmt;
|
||||
|
||||
/* stats */
|
||||
// combined size of all the packets read
|
||||
uint64_t data_size;
|
||||
/* number of packets successfully read for this stream */
|
||||
uint64_t nb_packets;
|
||||
// number of frames/samples retrieved from the decoder
|
||||
uint64_t frames_decoded;
|
||||
uint64_t samples_decoded;
|
||||
|
||||
int64_t *dts_buffer;
|
||||
int nb_dts_buffer;
|
||||
|
||||
int got_output;
|
||||
} InputStream;
|
||||
|
||||
typedef struct LastFrameDuration {
|
||||
int stream_idx;
|
||||
int64_t duration;
|
||||
} LastFrameDuration;
|
||||
|
||||
typedef struct InputFile {
|
||||
int index;
|
||||
|
||||
AVFormatContext *ctx;
|
||||
int eof_reached; /* true if eof reached */
|
||||
int eagain; /* true if last read attempt returned EAGAIN */
|
||||
int64_t input_ts_offset;
|
||||
int input_sync_ref;
|
||||
/**
|
||||
* Effective format start time based on enabled streams.
|
||||
*/
|
||||
int64_t start_time_effective;
|
||||
int64_t ts_offset;
|
||||
/**
|
||||
* Extra timestamp offset added by discontinuity handling.
|
||||
*/
|
||||
int64_t ts_offset_discont;
|
||||
int64_t last_ts;
|
||||
int64_t start_time; /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */
|
||||
int64_t recording_time;
|
||||
|
||||
/* streams that ffmpeg is aware of;
|
||||
* there may be extra streams in ctx that are not mapped to an InputStream
|
||||
* if new streams appear dynamically during demuxing */
|
||||
InputStream **streams;
|
||||
int nb_streams;
|
||||
|
||||
int rate_emu;
|
||||
float readrate;
|
||||
int accurate_seek;
|
||||
|
||||
/* when looping the input file, this queue is used by decoders to report
|
||||
* the last frame duration back to the demuxer thread */
|
||||
AVThreadMessageQueue *audio_duration_queue;
|
||||
int audio_duration_queue_size;
|
||||
} InputFile;
|
||||
|
||||
enum forced_keyframes_const {
|
||||
FKF_N,
|
||||
FKF_N_FORCED,
|
||||
FKF_PREV_FORCED_N,
|
||||
FKF_PREV_FORCED_T,
|
||||
FKF_T,
|
||||
FKF_NB
|
||||
};
|
||||
|
||||
#define ABORT_ON_FLAG_EMPTY_OUTPUT (1 << 0)
|
||||
#define ABORT_ON_FLAG_EMPTY_OUTPUT_STREAM (1 << 1)
|
||||
|
||||
enum EncStatsType {
|
||||
ENC_STATS_LITERAL = 0,
|
||||
ENC_STATS_FILE_IDX,
|
||||
ENC_STATS_STREAM_IDX,
|
||||
ENC_STATS_FRAME_NUM,
|
||||
ENC_STATS_FRAME_NUM_IN,
|
||||
ENC_STATS_TIMEBASE,
|
||||
ENC_STATS_TIMEBASE_IN,
|
||||
ENC_STATS_PTS,
|
||||
ENC_STATS_PTS_TIME,
|
||||
ENC_STATS_PTS_IN,
|
||||
ENC_STATS_PTS_TIME_IN,
|
||||
ENC_STATS_DTS,
|
||||
ENC_STATS_DTS_TIME,
|
||||
ENC_STATS_SAMPLE_NUM,
|
||||
ENC_STATS_NB_SAMPLES,
|
||||
ENC_STATS_PKT_SIZE,
|
||||
ENC_STATS_BITRATE,
|
||||
ENC_STATS_AVG_BITRATE,
|
||||
};
|
||||
|
||||
typedef struct EncStatsComponent {
|
||||
enum EncStatsType type;
|
||||
|
||||
uint8_t *str;
|
||||
size_t str_len;
|
||||
} EncStatsComponent;
|
||||
|
||||
typedef struct EncStats {
|
||||
EncStatsComponent *components;
|
||||
int nb_components;
|
||||
|
||||
AVIOContext *io;
|
||||
} EncStats;
|
||||
|
||||
extern const char *const forced_keyframes_const_names[];
|
||||
|
||||
typedef enum {
|
||||
ENCODER_FINISHED = 1,
|
||||
MUXER_FINISHED = 2,
|
||||
} OSTFinished ;
|
||||
|
||||
enum {
|
||||
KF_FORCE_SOURCE = 1,
|
||||
KF_FORCE_SOURCE_NO_DROP = 2,
|
||||
};
|
||||
|
||||
typedef struct KeyframeForceCtx {
|
||||
int type;
|
||||
|
||||
int64_t ref_pts;
|
||||
|
||||
// timestamps of the forced keyframes, in AV_TIME_BASE_Q
|
||||
int64_t *pts;
|
||||
int nb_pts;
|
||||
int index;
|
||||
|
||||
AVExpr *pexpr;
|
||||
double expr_const_values[FKF_NB];
|
||||
|
||||
int dropped_keyframe;
|
||||
} KeyframeForceCtx;
|
||||
|
||||
typedef struct OutputStream {
|
||||
const AVClass *clazz;
|
||||
|
||||
int file_index; /* file index */
|
||||
int index; /* stream index in the output file */
|
||||
|
||||
/* input stream that is the source for this output stream;
|
||||
* may be NULL for streams with no well-defined source, e.g.
|
||||
* attachments or outputs from complex filtergraphs */
|
||||
InputStream *ist;
|
||||
|
||||
AVStream *st; /* stream in the output file */
|
||||
/* number of frames emitted by the video-encoding sync code */
|
||||
int64_t vsync_frame_number;
|
||||
/* predicted pts of the next frame to be encoded
|
||||
* audio/video encoding only */
|
||||
int64_t next_pts;
|
||||
/* dts of the last packet sent to the muxing queue, in AV_TIME_BASE_Q */
|
||||
int64_t last_mux_dts;
|
||||
/* pts of the last frame received from the filters, in AV_TIME_BASE_Q */
|
||||
int64_t last_filter_pts;
|
||||
|
||||
// timestamp from which the streamcopied streams should start,
|
||||
// in AV_TIME_BASE_Q;
|
||||
// everything before it should be discarded
|
||||
int64_t ts_copy_start;
|
||||
|
||||
// the timebase of the packets sent to the muxer
|
||||
AVRational mux_timebase;
|
||||
AVRational enc_timebase;
|
||||
|
||||
AVCodecContext *enc_ctx;
|
||||
AVFrame *filtered_frame;
|
||||
AVFrame *last_frame;
|
||||
AVFrame *sq_frame;
|
||||
AVPacket *pkt;
|
||||
int64_t last_dropped;
|
||||
int64_t last_nb0_frames[3];
|
||||
|
||||
/* video only */
|
||||
AVRational frame_rate;
|
||||
AVRational max_frame_rate;
|
||||
enum VideoSyncMethod vsync_method;
|
||||
int is_cfr;
|
||||
int force_fps;
|
||||
int top_field_first;
|
||||
#if FFMPEG_ROTATION_METADATA
|
||||
int rotate_overridden;
|
||||
#endif
|
||||
int autoscale;
|
||||
int bitexact;
|
||||
int bits_per_raw_sample;
|
||||
#if FFMPEG_ROTATION_METADATA
|
||||
double rotate_override_value;
|
||||
#endif
|
||||
|
||||
AVRational frame_aspect_ratio;
|
||||
|
||||
KeyframeForceCtx kf;
|
||||
|
||||
/* audio only */
|
||||
#if FFMPEG_OPT_MAP_CHANNEL
|
||||
int *audio_channels_map; /* list of the channels id to pick from the source stream */
|
||||
int audio_channels_mapped; /* number of channels in audio_channels_map */
|
||||
#endif
|
||||
|
||||
char *logfile_prefix;
|
||||
FILE *logfile;
|
||||
|
||||
OutputFilter *filter;
|
||||
char *avfilter;
|
||||
char *filters; ///< filtergraph associated to the -filter option
|
||||
char *filters_script; ///< filtergraph script associated to the -filter_script option
|
||||
|
||||
AVDictionary *encoder_opts;
|
||||
AVDictionary *sws_dict;
|
||||
AVDictionary *swr_opts;
|
||||
char *apad;
|
||||
OSTFinished finished; /* no more packets should be written for this stream */
|
||||
int unavailable; /* true if the steram is unavailable (possibly temporarily) */
|
||||
|
||||
// init_output_stream() has been called for this stream
|
||||
// The encoder and the bitstream filters have been initialized and the stream
|
||||
// parameters are set in the AVStream.
|
||||
int initialized;
|
||||
|
||||
int inputs_done;
|
||||
|
||||
const char *attachment_filename;
|
||||
int streamcopy_started;
|
||||
int copy_initial_nonkeyframes;
|
||||
int copy_prior_start;
|
||||
|
||||
int keep_pix_fmt;
|
||||
|
||||
/* stats */
|
||||
// combined size of all the packets sent to the muxer
|
||||
uint64_t data_size_mux;
|
||||
// combined size of all the packets received from the encoder
|
||||
uint64_t data_size_enc;
|
||||
// number of packets send to the muxer
|
||||
atomic_uint_least64_t packets_written;
|
||||
// number of frames/samples sent to the encoder
|
||||
uint64_t frames_encoded;
|
||||
uint64_t samples_encoded;
|
||||
// number of packets received from the encoder
|
||||
uint64_t packets_encoded;
|
||||
|
||||
/* packet quality factor */
|
||||
int quality;
|
||||
|
||||
/* packet picture type */
|
||||
int pict_type;
|
||||
|
||||
/* frame encode sum of squared error values */
|
||||
int64_t error[4];
|
||||
|
||||
int sq_idx_encode;
|
||||
int sq_idx_mux;
|
||||
|
||||
EncStats enc_stats_pre;
|
||||
EncStats enc_stats_post;
|
||||
|
||||
/*
|
||||
* bool on whether this stream should be utilized for splitting
|
||||
* subtitles utilizing fix_sub_duration at random access points.
|
||||
*/
|
||||
unsigned int fix_sub_duration_heartbeat;
|
||||
} OutputStream;
|
||||
|
||||
typedef struct OutputFile {
|
||||
const AVClass *clazz;
|
||||
|
||||
int index;
|
||||
|
||||
const AVOutputFormat *format;
|
||||
const char *url;
|
||||
|
||||
OutputStream **streams;
|
||||
int nb_streams;
|
||||
|
||||
SyncQueue *sq_encode;
|
||||
|
||||
int64_t recording_time; ///< desired length of the resulting file in microseconds == AV_TIME_BASE units
|
||||
int64_t start_time; ///< start time in microseconds == AV_TIME_BASE units
|
||||
|
||||
int shortest;
|
||||
int bitexact;
|
||||
} OutputFile;
|
||||
|
||||
extern __thread InputFile **input_files;
|
||||
extern __thread int nb_input_files;
|
||||
|
||||
extern __thread OutputFile **output_files;
|
||||
extern __thread int nb_output_files;
|
||||
|
||||
extern __thread FilterGraph **filtergraphs;
|
||||
extern __thread int nb_filtergraphs;
|
||||
|
||||
extern __thread char *vstats_filename;
|
||||
extern __thread char *sdp_filename;
|
||||
|
||||
extern __thread float audio_drift_threshold;
|
||||
extern __thread float dts_delta_threshold;
|
||||
extern __thread float dts_error_threshold;
|
||||
|
||||
extern __thread enum VideoSyncMethod video_sync_method;
|
||||
extern __thread float frame_drop_threshold;
|
||||
extern __thread int do_benchmark;
|
||||
extern __thread int do_benchmark_all;
|
||||
extern __thread int do_hex_dump;
|
||||
extern __thread int do_pkt_dump;
|
||||
extern __thread int copy_ts;
|
||||
extern __thread int start_at_zero;
|
||||
extern __thread int copy_tb;
|
||||
extern __thread int debug_ts;
|
||||
extern __thread int exit_on_error;
|
||||
extern __thread int abort_on_flags;
|
||||
extern __thread int print_stats;
|
||||
extern __thread int64_t stats_period;
|
||||
extern __thread int qp_hist;
|
||||
extern __thread int stdin_interaction;
|
||||
extern __thread AVIOContext *progress_avio;
|
||||
extern __thread float max_error_rate;
|
||||
|
||||
extern __thread char *filter_nbthreads;
|
||||
extern __thread int filter_complex_nbthreads;
|
||||
extern __thread int vstats_version;
|
||||
extern __thread int auto_conversion_filters;
|
||||
|
||||
extern __thread const AVIOInterruptCB int_cb;
|
||||
|
||||
extern __thread HWDevice *filter_hw_device;
|
||||
|
||||
extern __thread unsigned nb_output_dumped;
|
||||
extern __thread int main_ffmpeg_return_code;
|
||||
|
||||
extern __thread int ignore_unknown_streams;
|
||||
extern __thread int copy_unknown_streams;
|
||||
|
||||
extern __thread int recast_media;
|
||||
|
||||
#if FFMPEG_OPT_PSNR
|
||||
extern __thread int do_psnr;
|
||||
#endif
|
||||
|
||||
void term_init(void);
|
||||
void term_exit(void);
|
||||
|
||||
void show_usage(void);
|
||||
|
||||
void remove_avoptions(AVDictionary **a, AVDictionary *b);
|
||||
void assert_avoptions(AVDictionary *m);
|
||||
|
||||
void assert_file_overwrite(const char *filename);
|
||||
char *file_read(const char *filename);
|
||||
AVDictionary *strip_specifiers(const AVDictionary *dict);
|
||||
const AVCodec *find_codec_or_die(void *logctx, const char *name,
|
||||
enum AVMediaType type, int encoder);
|
||||
int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global);
|
||||
|
||||
int configure_filtergraph(FilterGraph *fg);
|
||||
void check_filter_outputs(void);
|
||||
int filtergraph_is_simple(FilterGraph *fg);
|
||||
int init_simple_filtergraph(InputStream *ist, OutputStream *ost);
|
||||
int init_complex_filtergraph(FilterGraph *fg);
|
||||
|
||||
void sub2video_update(InputStream *ist, int64_t heartbeat_pts, AVSubtitle *sub);
|
||||
|
||||
int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame);
|
||||
|
||||
int ffmpeg_parse_options(int argc, char **argv);
|
||||
|
||||
void enc_stats_write(OutputStream *ost, EncStats *es,
|
||||
const AVFrame *frame, const AVPacket *pkt,
|
||||
uint64_t frame_num);
|
||||
|
||||
HWDevice *hw_device_get_by_name(const char *name);
|
||||
int hw_device_init_from_string(const char *arg, HWDevice **dev);
|
||||
void hw_device_free_all(void);
|
||||
|
||||
int hw_device_setup_for_decode(InputStream *ist);
|
||||
int hw_device_setup_for_encode(OutputStream *ost);
|
||||
int hw_device_setup_for_filter(FilterGraph *fg);
|
||||
|
||||
int hwaccel_decode_init(AVCodecContext *avctx);
|
||||
|
||||
/*
|
||||
* Initialize muxing state for the given stream, should be called
|
||||
* after the codec/streamcopy setup has been done.
|
||||
*
|
||||
* Open the muxer once all the streams have been initialized.
|
||||
*/
|
||||
int of_stream_init(OutputFile *of, OutputStream *ost);
|
||||
int of_write_trailer(OutputFile *of);
|
||||
int of_open(const OptionsContext *o, const char *filename);
|
||||
void of_close(OutputFile **pof);
|
||||
|
||||
void of_enc_stats_close(void);
|
||||
|
||||
/*
|
||||
* Send a single packet to the output, applying any bitstream filters
|
||||
* associated with the output stream. This may result in any number
|
||||
* of packets actually being written, depending on what bitstream
|
||||
* filters are applied. The supplied packet is consumed and will be
|
||||
* blank (as if newly-allocated) when this function returns.
|
||||
*
|
||||
* If eof is set, instead indicate EOF to all bitstream filters and
|
||||
* therefore flush any delayed packets to the output. A blank packet
|
||||
* must be supplied in this case.
|
||||
*/
|
||||
void of_output_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof);
|
||||
int64_t of_filesize(OutputFile *of);
|
||||
|
||||
int ifile_open(const OptionsContext *o, const char *filename);
|
||||
void ifile_close(InputFile **f);
|
||||
|
||||
/**
|
||||
* Get next input packet from the demuxer.
|
||||
*
|
||||
* @param pkt the packet is written here when this function returns 0
|
||||
* @return
|
||||
* - 0 when a packet has been read successfully
|
||||
* - 1 when stream end was reached, but the stream is looped;
|
||||
* caller should flush decoders and read from this demuxer again
|
||||
* - a negative error code on failure
|
||||
*/
|
||||
int ifile_get_packet(InputFile *f, AVPacket **pkt);
|
||||
|
||||
/* iterate over all input streams in all input files;
|
||||
* pass NULL to start iteration */
|
||||
InputStream *ist_iter(InputStream *prev);
|
||||
|
||||
extern const char * const opt_name_codec_names[];
|
||||
extern const char * const opt_name_codec_tags[];
|
||||
extern const char * const opt_name_frame_rates[];
|
||||
extern const char * const opt_name_top_field_first[];
|
||||
|
||||
void set_report_callback(void (*callback)(int, float, float, int64_t, double, double, double));
|
||||
void cancel_operation(long id);
|
||||
|
||||
#endif /* FFTOOLS_FFMPEG_H */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,608 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Taner Sener
|
||||
* Copyright (c) 2023 ARTHENICA LTD
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg 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 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is the modified version of ffmpeg_hw.c file living in ffmpeg source code under the fftools folder. We
|
||||
* manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied
|
||||
* by us to develop mobile-ffmpeg and later ffmpeg-kit libraries.
|
||||
*
|
||||
* ffmpeg-kit changes by ARTHENICA LTD
|
||||
*
|
||||
* 07.2023
|
||||
* --------------------------------------------------------
|
||||
* - FFmpeg 6.0 changes migrated
|
||||
*
|
||||
* mobile-ffmpeg / ffmpeg-kit changes by Taner Sener
|
||||
*
|
||||
* 12.2019
|
||||
* --------------------------------------------------------
|
||||
* - concurrent execution support ("__thread" specifier added to variables used by multiple threads)
|
||||
*
|
||||
* 08.2018
|
||||
* --------------------------------------------------------
|
||||
* - fftools_ prefix added to file name and parent header
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "libavutil/avstring.h"
|
||||
#include "libavutil/pixdesc.h"
|
||||
#include "libavfilter/buffersink.h"
|
||||
|
||||
#include "fftools_ffmpeg.h"
|
||||
|
||||
__thread int nb_hw_devices;
|
||||
__thread HWDevice **hw_devices;
|
||||
|
||||
static HWDevice *hw_device_get_by_type(enum AVHWDeviceType type)
|
||||
{
|
||||
HWDevice *found = NULL;
|
||||
int i;
|
||||
for (i = 0; i < nb_hw_devices; i++) {
|
||||
if (hw_devices[i]->type == type) {
|
||||
if (found)
|
||||
return NULL;
|
||||
found = hw_devices[i];
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
HWDevice *hw_device_get_by_name(const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < nb_hw_devices; i++) {
|
||||
if (!strcmp(hw_devices[i]->name, name))
|
||||
return hw_devices[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static HWDevice *hw_device_add(void)
|
||||
{
|
||||
int err;
|
||||
err = av_reallocp_array(&hw_devices, nb_hw_devices + 1,
|
||||
sizeof(*hw_devices));
|
||||
if (err) {
|
||||
nb_hw_devices = 0;
|
||||
return NULL;
|
||||
}
|
||||
hw_devices[nb_hw_devices] = av_mallocz(sizeof(HWDevice));
|
||||
if (!hw_devices[nb_hw_devices])
|
||||
return NULL;
|
||||
return hw_devices[nb_hw_devices++];
|
||||
}
|
||||
|
||||
static char *hw_device_default_name(enum AVHWDeviceType type)
|
||||
{
|
||||
// Make an automatic name of the form "type%d". We arbitrarily
|
||||
// limit at 1000 anonymous devices of the same type - there is
|
||||
// probably something else very wrong if you get to this limit.
|
||||
const char *type_name = av_hwdevice_get_type_name(type);
|
||||
char *name;
|
||||
size_t index_pos;
|
||||
int index, index_limit = 1000;
|
||||
index_pos = strlen(type_name);
|
||||
name = av_malloc(index_pos + 4);
|
||||
if (!name)
|
||||
return NULL;
|
||||
for (index = 0; index < index_limit; index++) {
|
||||
snprintf(name, index_pos + 4, "%s%d", type_name, index);
|
||||
if (!hw_device_get_by_name(name))
|
||||
break;
|
||||
}
|
||||
if (index >= index_limit) {
|
||||
av_freep(&name);
|
||||
return NULL;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
int hw_device_init_from_string(const char *arg, HWDevice **dev_out)
|
||||
{
|
||||
// "type=name"
|
||||
// "type=name,key=value,key2=value2"
|
||||
// "type=name:device,key=value,key2=value2"
|
||||
// "type:device,key=value,key2=value2"
|
||||
// -> av_hwdevice_ctx_create()
|
||||
// "type=name@name"
|
||||
// "type@name"
|
||||
// -> av_hwdevice_ctx_create_derived()
|
||||
|
||||
AVDictionary *options = NULL;
|
||||
const char *type_name = NULL, *name = NULL, *device = NULL;
|
||||
enum AVHWDeviceType type;
|
||||
HWDevice *dev, *src;
|
||||
AVBufferRef *device_ref = NULL;
|
||||
int err;
|
||||
const char *errmsg, *p, *q;
|
||||
size_t k;
|
||||
|
||||
k = strcspn(arg, ":=@");
|
||||
p = arg + k;
|
||||
|
||||
type_name = av_strndup(arg, k);
|
||||
if (!type_name) {
|
||||
err = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
type = av_hwdevice_find_type_by_name(type_name);
|
||||
if (type == AV_HWDEVICE_TYPE_NONE) {
|
||||
errmsg = "unknown device type";
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (*p == '=') {
|
||||
k = strcspn(p + 1, ":@,");
|
||||
|
||||
name = av_strndup(p + 1, k);
|
||||
if (!name) {
|
||||
err = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
if (hw_device_get_by_name(name)) {
|
||||
errmsg = "named device already exists";
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
p += 1 + k;
|
||||
} else {
|
||||
name = hw_device_default_name(type);
|
||||
if (!name) {
|
||||
err = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*p) {
|
||||
// New device with no parameters.
|
||||
err = av_hwdevice_ctx_create(&device_ref, type,
|
||||
NULL, NULL, 0);
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
|
||||
} else if (*p == ':') {
|
||||
// New device with some parameters.
|
||||
++p;
|
||||
q = strchr(p, ',');
|
||||
if (q) {
|
||||
if (q - p > 0) {
|
||||
device = av_strndup(p, q - p);
|
||||
if (!device) {
|
||||
err = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
err = av_dict_parse_string(&options, q + 1, "=", ",", 0);
|
||||
if (err < 0) {
|
||||
errmsg = "failed to parse options";
|
||||
goto invalid;
|
||||
}
|
||||
}
|
||||
|
||||
err = av_hwdevice_ctx_create(&device_ref, type,
|
||||
q ? device : p[0] ? p : NULL,
|
||||
options, 0);
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
|
||||
} else if (*p == '@') {
|
||||
// Derive from existing device.
|
||||
|
||||
src = hw_device_get_by_name(p + 1);
|
||||
if (!src) {
|
||||
errmsg = "invalid source device name";
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
err = av_hwdevice_ctx_create_derived(&device_ref, type,
|
||||
src->device_ref, 0);
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
} else if (*p == ',') {
|
||||
err = av_dict_parse_string(&options, p + 1, "=", ",", 0);
|
||||
|
||||
if (err < 0) {
|
||||
errmsg = "failed to parse options";
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
err = av_hwdevice_ctx_create(&device_ref, type,
|
||||
NULL, options, 0);
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
} else {
|
||||
errmsg = "parse error";
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
dev = hw_device_add();
|
||||
if (!dev) {
|
||||
err = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dev->name = name;
|
||||
dev->type = type;
|
||||
dev->device_ref = device_ref;
|
||||
|
||||
if (dev_out)
|
||||
*dev_out = dev;
|
||||
|
||||
name = NULL;
|
||||
err = 0;
|
||||
done:
|
||||
av_freep(&type_name);
|
||||
av_freep(&name);
|
||||
av_freep(&device);
|
||||
av_dict_free(&options);
|
||||
return err;
|
||||
invalid:
|
||||
av_log(NULL, AV_LOG_ERROR,
|
||||
"Invalid device specification \"%s\": %s\n", arg, errmsg);
|
||||
err = AVERROR(EINVAL);
|
||||
goto done;
|
||||
fail:
|
||||
av_log(NULL, AV_LOG_ERROR,
|
||||
"Device creation failed: %d.\n", err);
|
||||
av_buffer_unref(&device_ref);
|
||||
goto done;
|
||||
}
|
||||
|
||||
static int hw_device_init_from_type(enum AVHWDeviceType type,
|
||||
const char *device,
|
||||
HWDevice **dev_out)
|
||||
{
|
||||
AVBufferRef *device_ref = NULL;
|
||||
HWDevice *dev;
|
||||
char *name;
|
||||
int err;
|
||||
|
||||
name = hw_device_default_name(type);
|
||||
if (!name) {
|
||||
err = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = av_hwdevice_ctx_create(&device_ref, type, device, NULL, 0);
|
||||
if (err < 0) {
|
||||
av_log(NULL, AV_LOG_ERROR,
|
||||
"Device creation failed: %d.\n", err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dev = hw_device_add();
|
||||
if (!dev) {
|
||||
err = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dev->name = name;
|
||||
dev->type = type;
|
||||
dev->device_ref = device_ref;
|
||||
|
||||
if (dev_out)
|
||||
*dev_out = dev;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
av_freep(&name);
|
||||
av_buffer_unref(&device_ref);
|
||||
return err;
|
||||
}
|
||||
|
||||
void hw_device_free_all(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < nb_hw_devices; i++) {
|
||||
av_freep(&hw_devices[i]->name);
|
||||
av_buffer_unref(&hw_devices[i]->device_ref);
|
||||
av_freep(&hw_devices[i]);
|
||||
}
|
||||
av_freep(&hw_devices);
|
||||
nb_hw_devices = 0;
|
||||
}
|
||||
|
||||
static HWDevice *hw_device_match_by_codec(const AVCodec *codec)
|
||||
{
|
||||
const AVCodecHWConfig *config;
|
||||
HWDevice *dev;
|
||||
int i;
|
||||
for (i = 0;; i++) {
|
||||
config = avcodec_get_hw_config(codec, i);
|
||||
if (!config)
|
||||
return NULL;
|
||||
if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
|
||||
continue;
|
||||
dev = hw_device_get_by_type(config->device_type);
|
||||
if (dev)
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
|
||||
int hw_device_setup_for_decode(InputStream *ist)
|
||||
{
|
||||
const AVCodecHWConfig *config;
|
||||
enum AVHWDeviceType type;
|
||||
HWDevice *dev = NULL;
|
||||
int err, auto_device = 0;
|
||||
|
||||
if (ist->hwaccel_device) {
|
||||
dev = hw_device_get_by_name(ist->hwaccel_device);
|
||||
if (!dev) {
|
||||
if (ist->hwaccel_id == HWACCEL_AUTO) {
|
||||
auto_device = 1;
|
||||
} else if (ist->hwaccel_id == HWACCEL_GENERIC) {
|
||||
type = ist->hwaccel_device_type;
|
||||
err = hw_device_init_from_type(type, ist->hwaccel_device,
|
||||
&dev);
|
||||
} else {
|
||||
// This will be dealt with by API-specific initialisation
|
||||
// (using hwaccel_device), so nothing further needed here.
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (ist->hwaccel_id == HWACCEL_AUTO) {
|
||||
ist->hwaccel_device_type = dev->type;
|
||||
} else if (ist->hwaccel_device_type != dev->type) {
|
||||
av_log(NULL, AV_LOG_ERROR, "Invalid hwaccel device "
|
||||
"specified for decoder: device %s of type %s is not "
|
||||
"usable with hwaccel %s.\n", dev->name,
|
||||
av_hwdevice_get_type_name(dev->type),
|
||||
av_hwdevice_get_type_name(ist->hwaccel_device_type));
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ist->hwaccel_id == HWACCEL_AUTO) {
|
||||
auto_device = 1;
|
||||
} else if (ist->hwaccel_id == HWACCEL_GENERIC) {
|
||||
type = ist->hwaccel_device_type;
|
||||
dev = hw_device_get_by_type(type);
|
||||
|
||||
// When "-qsv_device device" is used, an internal QSV device named
|
||||
// as "__qsv_device" is created. Another QSV device is created too
|
||||
// if "-init_hw_device qsv=name:device" is used. There are 2 QSV devices
|
||||
// if both "-qsv_device device" and "-init_hw_device qsv=name:device"
|
||||
// are used, hw_device_get_by_type(AV_HWDEVICE_TYPE_QSV) returns NULL.
|
||||
// To keep back-compatibility with the removed ad-hoc libmfx setup code,
|
||||
// call hw_device_get_by_name("__qsv_device") to select the internal QSV
|
||||
// device.
|
||||
if (!dev && type == AV_HWDEVICE_TYPE_QSV)
|
||||
dev = hw_device_get_by_name("__qsv_device");
|
||||
|
||||
if (!dev)
|
||||
err = hw_device_init_from_type(type, NULL, &dev);
|
||||
} else {
|
||||
dev = hw_device_match_by_codec(ist->dec);
|
||||
if (!dev) {
|
||||
// No device for this codec, but not using generic hwaccel
|
||||
// and therefore may well not need one - ignore.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (auto_device) {
|
||||
int i;
|
||||
if (!avcodec_get_hw_config(ist->dec, 0)) {
|
||||
// Decoder does not support any hardware devices.
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; !dev; i++) {
|
||||
config = avcodec_get_hw_config(ist->dec, i);
|
||||
if (!config)
|
||||
break;
|
||||
type = config->device_type;
|
||||
dev = hw_device_get_by_type(type);
|
||||
if (dev) {
|
||||
av_log(NULL, AV_LOG_INFO, "Using auto "
|
||||
"hwaccel type %s with existing device %s.\n",
|
||||
av_hwdevice_get_type_name(type), dev->name);
|
||||
}
|
||||
}
|
||||
for (i = 0; !dev; i++) {
|
||||
config = avcodec_get_hw_config(ist->dec, i);
|
||||
if (!config)
|
||||
break;
|
||||
type = config->device_type;
|
||||
// Try to make a new device of this type.
|
||||
err = hw_device_init_from_type(type, ist->hwaccel_device,
|
||||
&dev);
|
||||
if (err < 0) {
|
||||
// Can't make a device of this type.
|
||||
continue;
|
||||
}
|
||||
if (ist->hwaccel_device) {
|
||||
av_log(NULL, AV_LOG_INFO, "Using auto "
|
||||
"hwaccel type %s with new device created "
|
||||
"from %s.\n", av_hwdevice_get_type_name(type),
|
||||
ist->hwaccel_device);
|
||||
} else {
|
||||
av_log(NULL, AV_LOG_INFO, "Using auto "
|
||||
"hwaccel type %s with new default device.\n",
|
||||
av_hwdevice_get_type_name(type));
|
||||
}
|
||||
}
|
||||
if (dev) {
|
||||
ist->hwaccel_device_type = type;
|
||||
} else {
|
||||
av_log(NULL, AV_LOG_INFO, "Auto hwaccel "
|
||||
"disabled: no device found.\n");
|
||||
ist->hwaccel_id = HWACCEL_NONE;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev) {
|
||||
av_log(NULL, AV_LOG_ERROR, "No device available "
|
||||
"for decoder: device type %s needed for codec %s.\n",
|
||||
av_hwdevice_get_type_name(type), ist->dec->name);
|
||||
return err;
|
||||
}
|
||||
|
||||
ist->dec_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
|
||||
if (!ist->dec_ctx->hw_device_ctx)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hw_device_setup_for_encode(OutputStream *ost)
|
||||
{
|
||||
const AVCodecHWConfig *config;
|
||||
HWDevice *dev = NULL;
|
||||
AVBufferRef *frames_ref = NULL;
|
||||
int i;
|
||||
|
||||
if (ost->filter) {
|
||||
frames_ref = av_buffersink_get_hw_frames_ctx(ost->filter->filter);
|
||||
if (frames_ref &&
|
||||
((AVHWFramesContext*)frames_ref->data)->format ==
|
||||
ost->enc_ctx->pix_fmt) {
|
||||
// Matching format, will try to use hw_frames_ctx.
|
||||
} else {
|
||||
frames_ref = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0;; i++) {
|
||||
config = avcodec_get_hw_config(ost->enc_ctx->codec, i);
|
||||
if (!config)
|
||||
break;
|
||||
|
||||
if (frames_ref &&
|
||||
config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX &&
|
||||
(config->pix_fmt == AV_PIX_FMT_NONE ||
|
||||
config->pix_fmt == ost->enc_ctx->pix_fmt)) {
|
||||
av_log(ost->enc_ctx, AV_LOG_VERBOSE, "Using input "
|
||||
"frames context (format %s) with %s encoder.\n",
|
||||
av_get_pix_fmt_name(ost->enc_ctx->pix_fmt),
|
||||
ost->enc_ctx->codec->name);
|
||||
ost->enc_ctx->hw_frames_ctx = av_buffer_ref(frames_ref);
|
||||
if (!ost->enc_ctx->hw_frames_ctx)
|
||||
return AVERROR(ENOMEM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dev &&
|
||||
config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)
|
||||
dev = hw_device_get_by_type(config->device_type);
|
||||
}
|
||||
|
||||
if (dev) {
|
||||
av_log(ost->enc_ctx, AV_LOG_VERBOSE, "Using device %s "
|
||||
"(type %s) with %s encoder.\n", dev->name,
|
||||
av_hwdevice_get_type_name(dev->type), ost->enc_ctx->codec->name);
|
||||
ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
|
||||
if (!ost->enc_ctx->hw_device_ctx)
|
||||
return AVERROR(ENOMEM);
|
||||
} else {
|
||||
// No device required, or no device available.
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input)
|
||||
{
|
||||
InputStream *ist = avctx->opaque;
|
||||
AVFrame *output = NULL;
|
||||
enum AVPixelFormat output_format = ist->hwaccel_output_format;
|
||||
int err;
|
||||
|
||||
if (input->format == output_format) {
|
||||
// Nothing to do.
|
||||
return 0;
|
||||
}
|
||||
|
||||
output = av_frame_alloc();
|
||||
if (!output)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
output->format = output_format;
|
||||
|
||||
err = av_hwframe_transfer_data(output, input, 0);
|
||||
if (err < 0) {
|
||||
av_log(avctx, AV_LOG_ERROR, "Failed to transfer data to "
|
||||
"output frame: %d.\n", err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = av_frame_copy_props(output, input);
|
||||
if (err < 0) {
|
||||
av_frame_unref(output);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
av_frame_unref(input);
|
||||
av_frame_move_ref(input, output);
|
||||
av_frame_free(&output);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
av_frame_free(&output);
|
||||
return err;
|
||||
}
|
||||
|
||||
int hwaccel_decode_init(AVCodecContext *avctx)
|
||||
{
|
||||
InputStream *ist = avctx->opaque;
|
||||
|
||||
ist->hwaccel_retrieve_data = &hwaccel_retrieve_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hw_device_setup_for_filter(FilterGraph *fg)
|
||||
{
|
||||
HWDevice *dev;
|
||||
int i;
|
||||
|
||||
// Pick the last hardware device if the user doesn't pick the device for
|
||||
// filters explicitly with the filter_hw_device option.
|
||||
if (filter_hw_device)
|
||||
dev = filter_hw_device;
|
||||
else if (nb_hw_devices > 0) {
|
||||
dev = hw_devices[nb_hw_devices - 1];
|
||||
|
||||
if (nb_hw_devices > 1)
|
||||
av_log(NULL, AV_LOG_WARNING, "There are %d hardware devices. device "
|
||||
"%s of type %s is picked for filters by default. Set hardware "
|
||||
"device explicitly with the filter_hw_device option if device "
|
||||
"%s is not usable for filters.\n",
|
||||
nb_hw_devices, dev->name,
|
||||
av_hwdevice_get_type_name(dev->type), dev->name);
|
||||
} else
|
||||
dev = NULL;
|
||||
|
||||
if (dev) {
|
||||
for (i = 0; i < fg->graph->nb_filters; i++) {
|
||||
fg->graph->filters[i]->hw_device_ctx =
|
||||
av_buffer_ref(dev->device_ref);
|
||||
if (!fg->graph->filters[i]->hw_device_ctx)
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,781 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
* Copyright (c) 2022 Taner Sener
|
||||
* Copyright (c) 2023 ARTHENICA LTD
|
||||
*
|
||||
* FFmpeg 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 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is the modified version of ffmpeg_mux.c file living in ffmpeg source code under the fftools folder. We
|
||||
* manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied
|
||||
* by us to develop the ffmpeg-kit library.
|
||||
*
|
||||
* ffmpeg-kit changes by ARTHENICA LTD
|
||||
*
|
||||
* 07.2023
|
||||
* --------------------------------------------------------
|
||||
* - FFmpeg 6.0 changes migrated
|
||||
* - fftools header names updated
|
||||
* - want_sdp marked as thread-local
|
||||
* - ms_from_ost migrated from ffmpeg_mux.c and marked as non-static
|
||||
*
|
||||
* ffmpeg-kit changes by Taner Sener
|
||||
*
|
||||
* 09.2022
|
||||
* --------------------------------------------------------
|
||||
* - fftools_ prefix added to fftools headers
|
||||
* - using main_ffmpeg_return_code instead of main_return_code
|
||||
* - printf replaced with av_log statements
|
||||
*/
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fftools_ffmpeg.h"
|
||||
#include "fftools_ffmpeg_mux.h"
|
||||
#include "fftools_objpool.h"
|
||||
#include "fftools_sync_queue.h"
|
||||
#include "fftools_thread_queue.h"
|
||||
|
||||
#include "libavutil/fifo.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "libavutil/log.h"
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavutil/timestamp.h"
|
||||
#include "libavutil/thread.h"
|
||||
|
||||
#include "libavcodec/packet.h"
|
||||
|
||||
#include "libavformat/avformat.h"
|
||||
#include "libavformat/avio.h"
|
||||
|
||||
__thread int want_sdp = 1;
|
||||
|
||||
MuxStream *ms_from_ost(OutputStream *ost)
|
||||
{
|
||||
return (MuxStream*)ost;
|
||||
}
|
||||
|
||||
static Muxer *mux_from_of(OutputFile *of)
|
||||
{
|
||||
return (Muxer*)of;
|
||||
}
|
||||
|
||||
static int64_t filesize(AVIOContext *pb)
|
||||
{
|
||||
int64_t ret = -1;
|
||||
|
||||
if (pb) {
|
||||
ret = avio_size(pb);
|
||||
if (ret <= 0) // FIXME improve avio_size() so it works with non seekable output too
|
||||
ret = avio_tell(pb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int write_packet(Muxer *mux, OutputStream *ost, AVPacket *pkt)
|
||||
{
|
||||
MuxStream *ms = ms_from_ost(ost);
|
||||
AVFormatContext *s = mux->fc;
|
||||
AVStream *st = ost->st;
|
||||
int64_t fs;
|
||||
uint64_t frame_num;
|
||||
int ret;
|
||||
|
||||
fs = filesize(s->pb);
|
||||
atomic_store(&mux->last_filesize, fs);
|
||||
if (fs >= mux->limit_filesize) {
|
||||
ret = AVERROR_EOF;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->vsync_method == VSYNC_DROP)
|
||||
pkt->pts = pkt->dts = AV_NOPTS_VALUE;
|
||||
|
||||
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
if (ost->frame_rate.num && ost->is_cfr) {
|
||||
if (pkt->duration > 0)
|
||||
av_log(ost, AV_LOG_WARNING, "Overriding packet duration by frame rate, this should not happen\n");
|
||||
pkt->duration = av_rescale_q(1, av_inv_q(ost->frame_rate),
|
||||
pkt->time_base);
|
||||
}
|
||||
}
|
||||
|
||||
av_packet_rescale_ts(pkt, pkt->time_base, ost->st->time_base);
|
||||
pkt->time_base = ost->st->time_base;
|
||||
|
||||
if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS)) {
|
||||
if (pkt->dts != AV_NOPTS_VALUE &&
|
||||
pkt->pts != AV_NOPTS_VALUE &&
|
||||
pkt->dts > pkt->pts) {
|
||||
av_log(s, AV_LOG_WARNING, "Invalid DTS: %"PRId64" PTS: %"PRId64" in output stream %d:%d, replacing by guess\n",
|
||||
pkt->dts, pkt->pts,
|
||||
ost->file_index, ost->st->index);
|
||||
pkt->pts =
|
||||
pkt->dts = pkt->pts + pkt->dts + ms->last_mux_dts + 1
|
||||
- FFMIN3(pkt->pts, pkt->dts, ms->last_mux_dts + 1)
|
||||
- FFMAX3(pkt->pts, pkt->dts, ms->last_mux_dts + 1);
|
||||
}
|
||||
if ((st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) &&
|
||||
pkt->dts != AV_NOPTS_VALUE &&
|
||||
ms->last_mux_dts != AV_NOPTS_VALUE) {
|
||||
int64_t max = ms->last_mux_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT);
|
||||
if (pkt->dts < max) {
|
||||
int loglevel = max - pkt->dts > 2 || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ? AV_LOG_WARNING : AV_LOG_DEBUG;
|
||||
if (exit_on_error)
|
||||
loglevel = AV_LOG_ERROR;
|
||||
av_log(s, loglevel, "Non-monotonous DTS in output stream "
|
||||
"%d:%d; previous: %"PRId64", current: %"PRId64"; ",
|
||||
ost->file_index, ost->st->index, ms->last_mux_dts, pkt->dts);
|
||||
if (exit_on_error) {
|
||||
ret = AVERROR(EINVAL);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
av_log(s, loglevel, "changing to %"PRId64". This may result "
|
||||
"in incorrect timestamps in the output file.\n",
|
||||
max);
|
||||
if (pkt->pts >= pkt->dts)
|
||||
pkt->pts = FFMAX(pkt->pts, max);
|
||||
pkt->dts = max;
|
||||
}
|
||||
}
|
||||
}
|
||||
ms->last_mux_dts = pkt->dts;
|
||||
|
||||
ost->data_size_mux += pkt->size;
|
||||
frame_num = atomic_fetch_add(&ost->packets_written, 1);
|
||||
|
||||
pkt->stream_index = ost->index;
|
||||
|
||||
if (debug_ts) {
|
||||
av_log(ost, AV_LOG_INFO, "muxer <- type:%s "
|
||||
"pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s duration:%s duration_time:%s size:%d\n",
|
||||
av_get_media_type_string(st->codecpar->codec_type),
|
||||
av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &ost->st->time_base),
|
||||
av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &ost->st->time_base),
|
||||
av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &ost->st->time_base),
|
||||
pkt->size
|
||||
);
|
||||
}
|
||||
|
||||
if (ms->stats.io)
|
||||
enc_stats_write(ost, &ms->stats, NULL, pkt, frame_num);
|
||||
|
||||
ret = av_interleaved_write_frame(s, pkt);
|
||||
if (ret < 0) {
|
||||
print_error("av_interleaved_write_frame()", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
av_packet_unref(pkt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sync_queue_process(Muxer *mux, OutputStream *ost, AVPacket *pkt, int *stream_eof)
|
||||
{
|
||||
OutputFile *of = &mux->of;
|
||||
|
||||
if (ost->sq_idx_mux >= 0) {
|
||||
int ret = sq_send(mux->sq_mux, ost->sq_idx_mux, SQPKT(pkt));
|
||||
if (ret < 0) {
|
||||
if (ret == AVERROR_EOF)
|
||||
*stream_eof = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
ret = sq_receive(mux->sq_mux, -1, SQPKT(mux->sq_pkt));
|
||||
if (ret < 0)
|
||||
return (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) ? 0 : ret;
|
||||
|
||||
ret = write_packet(mux, of->streams[ret],
|
||||
mux->sq_pkt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
} else if (pkt)
|
||||
return write_packet(mux, ost, pkt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void thread_set_name(OutputFile *of)
|
||||
{
|
||||
char name[16];
|
||||
snprintf(name, sizeof(name), "mux%d:%s", of->index, of->format->name);
|
||||
ff_thread_setname(name);
|
||||
}
|
||||
|
||||
static void *muxer_thread(void *arg)
|
||||
{
|
||||
Muxer *mux = arg;
|
||||
OutputFile *of = &mux->of;
|
||||
AVPacket *pkt = NULL;
|
||||
int ret = 0;
|
||||
|
||||
pkt = av_packet_alloc();
|
||||
if (!pkt) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
thread_set_name(of);
|
||||
|
||||
while (1) {
|
||||
OutputStream *ost;
|
||||
int stream_idx, stream_eof = 0;
|
||||
|
||||
ret = tq_receive(mux->tq, &stream_idx, pkt);
|
||||
if (stream_idx < 0) {
|
||||
av_log(mux, AV_LOG_VERBOSE, "All streams finished\n");
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ost = of->streams[stream_idx];
|
||||
ret = sync_queue_process(mux, ost, ret < 0 ? NULL : pkt, &stream_eof);
|
||||
av_packet_unref(pkt);
|
||||
if (ret == AVERROR_EOF && stream_eof)
|
||||
tq_receive_finish(mux->tq, stream_idx);
|
||||
else if (ret < 0) {
|
||||
av_log(mux, AV_LOG_ERROR, "Error muxing a packet\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
av_packet_free(&pkt);
|
||||
|
||||
for (unsigned int i = 0; i < mux->fc->nb_streams; i++)
|
||||
tq_receive_finish(mux->tq, i);
|
||||
|
||||
av_log(mux, AV_LOG_VERBOSE, "Terminating muxer thread\n");
|
||||
|
||||
return (void*)(intptr_t)ret;
|
||||
}
|
||||
|
||||
static int thread_submit_packet(Muxer *mux, OutputStream *ost, AVPacket *pkt)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!pkt || ost->finished & MUXER_FINISHED)
|
||||
goto finish;
|
||||
|
||||
ret = tq_send(mux->tq, ost->index, pkt);
|
||||
if (ret < 0)
|
||||
goto finish;
|
||||
|
||||
return 0;
|
||||
|
||||
finish:
|
||||
if (pkt)
|
||||
av_packet_unref(pkt);
|
||||
|
||||
ost->finished |= MUXER_FINISHED;
|
||||
tq_send_finish(mux->tq, ost->index);
|
||||
return ret == AVERROR_EOF ? 0 : ret;
|
||||
}
|
||||
|
||||
static int queue_packet(Muxer *mux, OutputStream *ost, AVPacket *pkt)
|
||||
{
|
||||
MuxStream *ms = ms_from_ost(ost);
|
||||
AVPacket *tmp_pkt = NULL;
|
||||
int ret;
|
||||
|
||||
if (!av_fifo_can_write(ms->muxing_queue)) {
|
||||
size_t cur_size = av_fifo_can_read(ms->muxing_queue);
|
||||
size_t pkt_size = pkt ? pkt->size : 0;
|
||||
unsigned int are_we_over_size =
|
||||
(ms->muxing_queue_data_size + pkt_size) > ms->muxing_queue_data_threshold;
|
||||
size_t limit = are_we_over_size ? ms->max_muxing_queue_size : SIZE_MAX;
|
||||
size_t new_size = FFMIN(2 * cur_size, limit);
|
||||
|
||||
if (new_size <= cur_size) {
|
||||
av_log(ost, AV_LOG_ERROR,
|
||||
"Too many packets buffered for output stream %d:%d.\n",
|
||||
ost->file_index, ost->st->index);
|
||||
return AVERROR(ENOSPC);
|
||||
}
|
||||
ret = av_fifo_grow2(ms->muxing_queue, new_size - cur_size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pkt) {
|
||||
ret = av_packet_make_refcounted(pkt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tmp_pkt = av_packet_alloc();
|
||||
if (!tmp_pkt)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
av_packet_move_ref(tmp_pkt, pkt);
|
||||
ms->muxing_queue_data_size += tmp_pkt->size;
|
||||
}
|
||||
av_fifo_write(ms->muxing_queue, &tmp_pkt, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int submit_packet(Muxer *mux, AVPacket *pkt, OutputStream *ost)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (mux->tq) {
|
||||
return thread_submit_packet(mux, ost, pkt);
|
||||
} else {
|
||||
/* the muxer is not initialized yet, buffer the packet */
|
||||
ret = queue_packet(mux, ost, pkt);
|
||||
if (ret < 0) {
|
||||
if (pkt)
|
||||
av_packet_unref(pkt);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void of_output_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof)
|
||||
{
|
||||
Muxer *mux = mux_from_of(of);
|
||||
MuxStream *ms = ms_from_ost(ost);
|
||||
const char *err_msg;
|
||||
int ret = 0;
|
||||
|
||||
if (!eof && pkt->dts != AV_NOPTS_VALUE)
|
||||
ost->last_mux_dts = av_rescale_q(pkt->dts, pkt->time_base, AV_TIME_BASE_Q);
|
||||
|
||||
/* apply the output bitstream filters */
|
||||
if (ms->bsf_ctx) {
|
||||
int bsf_eof = 0;
|
||||
|
||||
ret = av_bsf_send_packet(ms->bsf_ctx, eof ? NULL : pkt);
|
||||
if (ret < 0) {
|
||||
err_msg = "submitting a packet for bitstream filtering";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
while (!bsf_eof) {
|
||||
ret = av_bsf_receive_packet(ms->bsf_ctx, pkt);
|
||||
if (ret == AVERROR(EAGAIN))
|
||||
return;
|
||||
else if (ret == AVERROR_EOF)
|
||||
bsf_eof = 1;
|
||||
else if (ret < 0) {
|
||||
err_msg = "applying bitstream filters to a packet";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = submit_packet(mux, bsf_eof ? NULL : pkt, ost);
|
||||
if (ret < 0)
|
||||
goto mux_fail;
|
||||
}
|
||||
} else {
|
||||
ret = submit_packet(mux, eof ? NULL : pkt, ost);
|
||||
if (ret < 0)
|
||||
goto mux_fail;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
mux_fail:
|
||||
err_msg = "submitting a packet to the muxer";
|
||||
|
||||
fail:
|
||||
av_log(ost, AV_LOG_ERROR, "Error %s\n", err_msg);
|
||||
if (exit_on_error)
|
||||
exit_program(1);
|
||||
|
||||
}
|
||||
|
||||
static int thread_stop(Muxer *mux)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if (!mux || !mux->tq)
|
||||
return 0;
|
||||
|
||||
for (unsigned int i = 0; i < mux->fc->nb_streams; i++)
|
||||
tq_send_finish(mux->tq, i);
|
||||
|
||||
pthread_join(mux->thread, &ret);
|
||||
|
||||
tq_free(&mux->tq);
|
||||
|
||||
return (int)(intptr_t)ret;
|
||||
}
|
||||
|
||||
static void pkt_move(void *dst, void *src)
|
||||
{
|
||||
av_packet_move_ref(dst, src);
|
||||
}
|
||||
|
||||
static int thread_start(Muxer *mux)
|
||||
{
|
||||
AVFormatContext *fc = mux->fc;
|
||||
ObjPool *op;
|
||||
int ret;
|
||||
|
||||
op = objpool_alloc_packets();
|
||||
if (!op)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
mux->tq = tq_alloc(fc->nb_streams, mux->thread_queue_size, op, pkt_move);
|
||||
if (!mux->tq) {
|
||||
objpool_free(&op);
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
ret = pthread_create(&mux->thread, NULL, muxer_thread, (void*)mux);
|
||||
if (ret) {
|
||||
tq_free(&mux->tq);
|
||||
return AVERROR(ret);
|
||||
}
|
||||
|
||||
/* flush the muxing queues */
|
||||
for (int i = 0; i < fc->nb_streams; i++) {
|
||||
OutputStream *ost = mux->of.streams[i];
|
||||
MuxStream *ms = ms_from_ost(ost);
|
||||
AVPacket *pkt;
|
||||
|
||||
/* try to improve muxing time_base (only possible if nothing has been written yet) */
|
||||
if (!av_fifo_can_read(ms->muxing_queue))
|
||||
ost->mux_timebase = ost->st->time_base;
|
||||
|
||||
while (av_fifo_read(ms->muxing_queue, &pkt, 1) >= 0) {
|
||||
ret = thread_submit_packet(mux, ost, pkt);
|
||||
if (pkt) {
|
||||
ms->muxing_queue_data_size -= pkt->size;
|
||||
av_packet_free(&pkt);
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_sdp(void)
|
||||
{
|
||||
char sdp[16384];
|
||||
int i;
|
||||
int j, ret;
|
||||
AVIOContext *sdp_pb;
|
||||
AVFormatContext **avc;
|
||||
|
||||
for (i = 0; i < nb_output_files; i++) {
|
||||
if (!mux_from_of(output_files[i])->header_written)
|
||||
return 0;
|
||||
}
|
||||
|
||||
avc = av_malloc_array(nb_output_files, sizeof(*avc));
|
||||
if (!avc)
|
||||
return AVERROR(ENOMEM);
|
||||
for (i = 0, j = 0; i < nb_output_files; i++) {
|
||||
if (!strcmp(output_files[i]->format->name, "rtp")) {
|
||||
avc[j] = mux_from_of(output_files[i])->fc;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!j) {
|
||||
av_log(NULL, AV_LOG_ERROR, "No output streams in the SDP.\n");
|
||||
ret = AVERROR(EINVAL);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = av_sdp_create(avc, j, sdp, sizeof(sdp));
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
if (!sdp_filename) {
|
||||
av_log(NULL, AV_LOG_ERROR, "SDP:\n%s\n", sdp);
|
||||
fflush(stdout);
|
||||
} else {
|
||||
ret = avio_open2(&sdp_pb, sdp_filename, AVIO_FLAG_WRITE, &int_cb, NULL);
|
||||
if (ret < 0) {
|
||||
av_log(NULL, AV_LOG_ERROR, "Failed to open sdp file '%s'\n", sdp_filename);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
avio_print(sdp_pb, sdp);
|
||||
avio_closep(&sdp_pb);
|
||||
av_freep(&sdp_filename);
|
||||
}
|
||||
|
||||
// SDP successfully written, allow muxer threads to start
|
||||
ret = 1;
|
||||
|
||||
fail:
|
||||
av_freep(&avc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mux_check_init(Muxer *mux)
|
||||
{
|
||||
OutputFile *of = &mux->of;
|
||||
AVFormatContext *fc = mux->fc;
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < fc->nb_streams; i++) {
|
||||
OutputStream *ost = of->streams[i];
|
||||
if (!ost->initialized)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = avformat_write_header(fc, &mux->opts);
|
||||
if (ret < 0) {
|
||||
av_log(mux, AV_LOG_ERROR, "Could not write header (incorrect codec "
|
||||
"parameters ?): %s\n", av_err2str(ret));
|
||||
return ret;
|
||||
}
|
||||
//assert_avoptions(of->opts);
|
||||
mux->header_written = 1;
|
||||
|
||||
av_dump_format(fc, of->index, fc->url, 1);
|
||||
nb_output_dumped++;
|
||||
|
||||
if (sdp_filename || want_sdp) {
|
||||
ret = print_sdp();
|
||||
if (ret < 0) {
|
||||
av_log(NULL, AV_LOG_ERROR, "Error writing the SDP.\n");
|
||||
return ret;
|
||||
} else if (ret == 1) {
|
||||
/* SDP is written only after all the muxers are ready, so now we
|
||||
* start ALL the threads */
|
||||
for (i = 0; i < nb_output_files; i++) {
|
||||
ret = thread_start(mux_from_of(output_files[i]));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = thread_start(mux_from_of(of));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bsf_init(MuxStream *ms)
|
||||
{
|
||||
OutputStream *ost = &ms->ost;
|
||||
AVBSFContext *ctx = ms->bsf_ctx;
|
||||
int ret;
|
||||
|
||||
if (!ctx)
|
||||
return 0;
|
||||
|
||||
ret = avcodec_parameters_copy(ctx->par_in, ost->st->codecpar);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ctx->time_base_in = ost->st->time_base;
|
||||
|
||||
ret = av_bsf_init(ctx);
|
||||
if (ret < 0) {
|
||||
av_log(ms, AV_LOG_ERROR, "Error initializing bitstream filter: %s\n",
|
||||
ctx->filter->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = avcodec_parameters_copy(ost->st->codecpar, ctx->par_out);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ost->st->time_base = ctx->time_base_out;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int of_stream_init(OutputFile *of, OutputStream *ost)
|
||||
{
|
||||
Muxer *mux = mux_from_of(of);
|
||||
MuxStream *ms = ms_from_ost(ost);
|
||||
int ret;
|
||||
|
||||
if (ost->sq_idx_mux >= 0)
|
||||
sq_set_tb(mux->sq_mux, ost->sq_idx_mux, ost->mux_timebase);
|
||||
|
||||
/* initialize bitstream filters for the output stream
|
||||
* needs to be done here, because the codec id for streamcopy is not
|
||||
* known until now */
|
||||
ret = bsf_init(ms);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ost->initialized = 1;
|
||||
|
||||
return mux_check_init(mux);
|
||||
}
|
||||
|
||||
int of_write_trailer(OutputFile *of)
|
||||
{
|
||||
Muxer *mux = mux_from_of(of);
|
||||
AVFormatContext *fc = mux->fc;
|
||||
int ret;
|
||||
|
||||
if (!mux->tq) {
|
||||
av_log(mux, AV_LOG_ERROR,
|
||||
"Nothing was written into output file, because "
|
||||
"at least one of its streams received no packets.\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
ret = thread_stop(mux);
|
||||
if (ret < 0)
|
||||
main_ffmpeg_return_code = ret;
|
||||
|
||||
ret = av_write_trailer(fc);
|
||||
if (ret < 0) {
|
||||
av_log(mux, AV_LOG_ERROR, "Error writing trailer: %s\n", av_err2str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
mux->last_filesize = filesize(fc->pb);
|
||||
|
||||
if (!(of->format->flags & AVFMT_NOFILE)) {
|
||||
ret = avio_closep(&fc->pb);
|
||||
if (ret < 0) {
|
||||
av_log(mux, AV_LOG_ERROR, "Error closing file: %s\n", av_err2str(ret));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ost_free(OutputStream **post)
|
||||
{
|
||||
OutputStream *ost = *post;
|
||||
MuxStream *ms;
|
||||
|
||||
if (!ost)
|
||||
return;
|
||||
ms = ms_from_ost(ost);
|
||||
|
||||
if (ost->logfile) {
|
||||
if (fclose(ost->logfile))
|
||||
av_log(ms, AV_LOG_ERROR,
|
||||
"Error closing logfile, loss of information possible: %s\n",
|
||||
av_err2str(AVERROR(errno)));
|
||||
ost->logfile = NULL;
|
||||
}
|
||||
|
||||
if (ms->muxing_queue) {
|
||||
AVPacket *pkt;
|
||||
while (av_fifo_read(ms->muxing_queue, &pkt, 1) >= 0)
|
||||
av_packet_free(&pkt);
|
||||
av_fifo_freep2(&ms->muxing_queue);
|
||||
}
|
||||
|
||||
av_bsf_free(&ms->bsf_ctx);
|
||||
|
||||
av_frame_free(&ost->filtered_frame);
|
||||
av_frame_free(&ost->sq_frame);
|
||||
av_frame_free(&ost->last_frame);
|
||||
av_packet_free(&ost->pkt);
|
||||
av_dict_free(&ost->encoder_opts);
|
||||
|
||||
av_freep(&ost->kf.pts);
|
||||
av_expr_free(ost->kf.pexpr);
|
||||
|
||||
av_freep(&ost->avfilter);
|
||||
av_freep(&ost->logfile_prefix);
|
||||
av_freep(&ost->apad);
|
||||
|
||||
#if FFMPEG_OPT_MAP_CHANNEL
|
||||
av_freep(&ost->audio_channels_map);
|
||||
ost->audio_channels_mapped = 0;
|
||||
#endif
|
||||
|
||||
av_dict_free(&ost->sws_dict);
|
||||
av_dict_free(&ost->swr_opts);
|
||||
|
||||
if (ost->enc_ctx)
|
||||
av_freep(&ost->enc_ctx->stats_in);
|
||||
avcodec_free_context(&ost->enc_ctx);
|
||||
|
||||
for (int i = 0; i < ost->enc_stats_pre.nb_components; i++)
|
||||
av_freep(&ost->enc_stats_pre.components[i].str);
|
||||
av_freep(&ost->enc_stats_pre.components);
|
||||
|
||||
for (int i = 0; i < ost->enc_stats_post.nb_components; i++)
|
||||
av_freep(&ost->enc_stats_post.components[i].str);
|
||||
av_freep(&ost->enc_stats_post.components);
|
||||
|
||||
for (int i = 0; i < ms->stats.nb_components; i++)
|
||||
av_freep(&ms->stats.components[i].str);
|
||||
av_freep(&ms->stats.components);
|
||||
|
||||
av_freep(post);
|
||||
}
|
||||
|
||||
static void fc_close(AVFormatContext **pfc)
|
||||
{
|
||||
AVFormatContext *fc = *pfc;
|
||||
|
||||
if (!fc)
|
||||
return;
|
||||
|
||||
if (!(fc->oformat->flags & AVFMT_NOFILE))
|
||||
avio_closep(&fc->pb);
|
||||
avformat_free_context(fc);
|
||||
|
||||
*pfc = NULL;
|
||||
}
|
||||
|
||||
void of_close(OutputFile **pof)
|
||||
{
|
||||
OutputFile *of = *pof;
|
||||
Muxer *mux;
|
||||
|
||||
if (!of)
|
||||
return;
|
||||
mux = mux_from_of(of);
|
||||
|
||||
thread_stop(mux);
|
||||
|
||||
sq_free(&of->sq_encode);
|
||||
sq_free(&mux->sq_mux);
|
||||
|
||||
for (int i = 0; i < of->nb_streams; i++)
|
||||
ost_free(&of->streams[i]);
|
||||
av_freep(&of->streams);
|
||||
|
||||
av_dict_free(&mux->opts);
|
||||
|
||||
av_packet_free(&mux->sq_pkt);
|
||||
|
||||
fc_close(&mux->fc);
|
||||
|
||||
av_freep(pof);
|
||||
}
|
||||
|
||||
int64_t of_filesize(OutputFile *of)
|
||||
{
|
||||
Muxer *mux = mux_from_of(of);
|
||||
return atomic_load(&mux->last_filesize);
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Muxer internal APIs - should not be included outside of ffmpeg_mux*
|
||||
* Copyright (c) 2023 ARTHENICA LTD
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg 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 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is the modified version of ffmpeg_mux.h file living in ffmpeg source code under the fftools folder. We
|
||||
* manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied
|
||||
* by us to develop ffmpeg-kit library.
|
||||
*
|
||||
* ffmpeg-kit changes by ARTHENICA LTD
|
||||
*
|
||||
* 07.2023
|
||||
* --------------------------------------------------------
|
||||
* - FFmpeg 6.0 changes migrated
|
||||
* - fftools header names updated
|
||||
* - want_sdp made thread-local
|
||||
* - EncStatsFile declaration migrated from ffmpeg_mux_init.c
|
||||
* - WARN_MULTIPLE_OPT_USAGE, MATCH_PER_STREAM_OPT, MATCH_PER_TYPE_OPT, SPECIFIER_OPT_FMT declarations migrated from
|
||||
* ffmpeg.h
|
||||
* - ms_from_ost migrated to ffmpeg_mux.c
|
||||
*/
|
||||
|
||||
#ifndef FFTOOLS_FFMPEG_MUX_H
|
||||
#define FFTOOLS_FFMPEG_MUX_H
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "fftools_thread_queue.h"
|
||||
|
||||
#include "libavformat/avformat.h"
|
||||
|
||||
#include "libavcodec/packet.h"
|
||||
|
||||
#include "libavutil/dict.h"
|
||||
#include "libavutil/fifo.h"
|
||||
#include "libavutil/thread.h"
|
||||
|
||||
#define SPECIFIER_OPT_FMT_str "%s"
|
||||
#define SPECIFIER_OPT_FMT_i "%i"
|
||||
#define SPECIFIER_OPT_FMT_i64 "%"PRId64
|
||||
#define SPECIFIER_OPT_FMT_ui64 "%"PRIu64
|
||||
#define SPECIFIER_OPT_FMT_f "%f"
|
||||
#define SPECIFIER_OPT_FMT_dbl "%lf"
|
||||
|
||||
#define WARN_MULTIPLE_OPT_USAGE(name, type, so, st)\
|
||||
{\
|
||||
char namestr[128] = "";\
|
||||
const char *spec = so->specifier && so->specifier[0] ? so->specifier : "";\
|
||||
for (int _i = 0; opt_name_##name[_i]; _i++)\
|
||||
av_strlcatf(namestr, sizeof(namestr), "-%s%s", opt_name_##name[_i], opt_name_##name[_i+1] ? (opt_name_##name[_i+2] ? ", " : " or ") : "");\
|
||||
av_log(NULL, AV_LOG_WARNING, "Multiple %s options specified for stream %d, only the last option '-%s%s%s "SPECIFIER_OPT_FMT_##type"' will be used.\n",\
|
||||
namestr, st->index, opt_name_##name[0], spec[0] ? ":" : "", spec, so->u.type);\
|
||||
}
|
||||
|
||||
#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\
|
||||
{\
|
||||
int _ret, _matches = 0;\
|
||||
SpecifierOpt *so;\
|
||||
for (int _i = 0; _i < o->nb_ ## name; _i++) {\
|
||||
char *spec = o->name[_i].specifier;\
|
||||
if ((_ret = check_stream_specifier(fmtctx, st, spec)) > 0) {\
|
||||
outvar = o->name[_i].u.type;\
|
||||
so = &o->name[_i];\
|
||||
_matches++;\
|
||||
} else if (_ret < 0)\
|
||||
exit_program(1);\
|
||||
}\
|
||||
if (_matches > 1)\
|
||||
WARN_MULTIPLE_OPT_USAGE(name, type, so, st);\
|
||||
}
|
||||
|
||||
#define MATCH_PER_TYPE_OPT(name, type, outvar, fmtctx, mediatype)\
|
||||
{\
|
||||
int i;\
|
||||
for (i = 0; i < o->nb_ ## name; i++) {\
|
||||
char *spec = o->name[i].specifier;\
|
||||
if (!strcmp(spec, mediatype))\
|
||||
outvar = o->name[i].u.type;\
|
||||
}\
|
||||
}
|
||||
|
||||
typedef struct MuxStream {
|
||||
OutputStream ost;
|
||||
|
||||
// name used for logging
|
||||
char log_name[32];
|
||||
|
||||
/* the packets are buffered here until the muxer is ready to be initialized */
|
||||
AVFifo *muxing_queue;
|
||||
|
||||
AVBSFContext *bsf_ctx;
|
||||
|
||||
EncStats stats;
|
||||
|
||||
int64_t max_frames;
|
||||
|
||||
/*
|
||||
* The size of the AVPackets' buffers in queue.
|
||||
* Updated when a packet is either pushed or pulled from the queue.
|
||||
*/
|
||||
size_t muxing_queue_data_size;
|
||||
|
||||
int max_muxing_queue_size;
|
||||
|
||||
/* Threshold after which max_muxing_queue_size will be in effect */
|
||||
size_t muxing_queue_data_threshold;
|
||||
|
||||
/* dts of the last packet sent to the muxer, in the stream timebase
|
||||
* used for making up missing dts values */
|
||||
int64_t last_mux_dts;
|
||||
} MuxStream;
|
||||
|
||||
typedef struct Muxer {
|
||||
OutputFile of;
|
||||
|
||||
// name used for logging
|
||||
char log_name[32];
|
||||
|
||||
AVFormatContext *fc;
|
||||
|
||||
pthread_t thread;
|
||||
ThreadQueue *tq;
|
||||
|
||||
AVDictionary *opts;
|
||||
|
||||
int thread_queue_size;
|
||||
|
||||
/* filesize limit expressed in bytes */
|
||||
int64_t limit_filesize;
|
||||
atomic_int_least64_t last_filesize;
|
||||
int header_written;
|
||||
|
||||
SyncQueue *sq_mux;
|
||||
AVPacket *sq_pkt;
|
||||
} Muxer;
|
||||
|
||||
typedef struct EncStatsFile {
|
||||
char *path;
|
||||
AVIOContext *io;
|
||||
} EncStatsFile;
|
||||
|
||||
/* whether we want to print an SDP, set in of_open() */
|
||||
extern __thread int want_sdp;
|
||||
|
||||
int mux_check_init(Muxer *mux);
|
||||
|
||||
#endif /* FFTOOLS_FFMPEG_MUX_H */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg 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 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is the modified version of fopen_utf8.h file living in ffmpeg source code under the fftools folder. We
|
||||
* manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied
|
||||
* by us to develop the ffmpeg-kit library.
|
||||
*
|
||||
* ffmpeg-kit changes by Taner Sener
|
||||
*/
|
||||
|
||||
#ifndef FFTOOLS_FOPEN_UTF8_H
|
||||
#define FFTOOLS_FOPEN_UTF8_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* The fopen_utf8 function here is essentially equivalent to avpriv_fopen_utf8,
|
||||
* except that it doesn't set O_CLOEXEC, and that it isn't exported
|
||||
* from a different library. (On Windows, each DLL might use a different
|
||||
* CRT, and FILE* handles can't be shared across them.) */
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "libavutil/wchar_filename.h"
|
||||
|
||||
static inline FILE *fopen_utf8(const char *path_utf8, const char *mode)
|
||||
{
|
||||
wchar_t *path_w, *mode_w;
|
||||
FILE *f;
|
||||
|
||||
/* convert UTF-8 to wide chars */
|
||||
if (get_extended_win32_path(path_utf8, &path_w)) /* This sets errno on error. */
|
||||
return NULL;
|
||||
if (!path_w)
|
||||
goto fallback;
|
||||
|
||||
if (utf8towchar(mode, &mode_w))
|
||||
return NULL;
|
||||
if (!mode_w) {
|
||||
/* If failing to interpret the mode string as utf8, it is an invalid
|
||||
* parameter. */
|
||||
av_freep(&path_w);
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f = _wfopen(path_w, mode_w);
|
||||
av_freep(&path_w);
|
||||
av_freep(&mode_w);
|
||||
|
||||
return f;
|
||||
fallback:
|
||||
/* path may be in CP_ACP */
|
||||
return fopen(path_utf8, mode);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline FILE *fopen_utf8(const char *path, const char *mode)
|
||||
{
|
||||
return fopen(path, mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FFTOOLS_FOPEN_UTF8_H */
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
* Copyright (c) 2023 ARTHENICA LTD
|
||||
*
|
||||
* FFmpeg 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 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is the modified version of objpool.c file living in ffmpeg source code under the fftools folder. We
|
||||
* manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied
|
||||
* by us to develop ffmpeg-kit library.
|
||||
*
|
||||
* ffmpeg-kit changes by ARTHENICA LTD
|
||||
*
|
||||
* 07.2023
|
||||
* --------------------------------------------------------
|
||||
* - FFmpeg 6.0 changes migrated
|
||||
* - fftools header names updated
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libavcodec/packet.h"
|
||||
|
||||
#include "libavutil/common.h"
|
||||
#include "libavutil/error.h"
|
||||
#include "libavutil/frame.h"
|
||||
#include "libavutil/mem.h"
|
||||
|
||||
#include "fftools_objpool.h"
|
||||
|
||||
struct ObjPool {
|
||||
void *pool[32];
|
||||
unsigned int pool_count;
|
||||
|
||||
ObjPoolCBAlloc alloc;
|
||||
ObjPoolCBReset reset;
|
||||
ObjPoolCBFree free;
|
||||
};
|
||||
|
||||
ObjPool *objpool_alloc(ObjPoolCBAlloc cb_alloc, ObjPoolCBReset cb_reset,
|
||||
ObjPoolCBFree cb_free)
|
||||
{
|
||||
ObjPool *op = av_mallocz(sizeof(*op));
|
||||
|
||||
if (!op)
|
||||
return NULL;
|
||||
|
||||
op->alloc = cb_alloc;
|
||||
op->reset = cb_reset;
|
||||
op->free = cb_free;
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
void objpool_free(ObjPool **pop)
|
||||
{
|
||||
ObjPool *op = *pop;
|
||||
|
||||
if (!op)
|
||||
return;
|
||||
|
||||
for (unsigned int i = 0; i < op->pool_count; i++)
|
||||
op->free(&op->pool[i]);
|
||||
|
||||
av_freep(pop);
|
||||
}
|
||||
|
||||
int objpool_get(ObjPool *op, void **obj)
|
||||
{
|
||||
if (op->pool_count) {
|
||||
*obj = op->pool[--op->pool_count];
|
||||
op->pool[op->pool_count] = NULL;
|
||||
} else
|
||||
*obj = op->alloc();
|
||||
|
||||
return *obj ? 0 : AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
void objpool_release(ObjPool *op, void **obj)
|
||||
{
|
||||
if (!*obj)
|
||||
return;
|
||||
|
||||
op->reset(*obj);
|
||||
|
||||
if (op->pool_count < FF_ARRAY_ELEMS(op->pool))
|
||||
op->pool[op->pool_count++] = *obj;
|
||||
else
|
||||
op->free(obj);
|
||||
|
||||
*obj = NULL;
|
||||
}
|
||||
|
||||
static void *alloc_packet(void)
|
||||
{
|
||||
return av_packet_alloc();
|
||||
}
|
||||
static void *alloc_frame(void)
|
||||
{
|
||||
return av_frame_alloc();
|
||||
}
|
||||
|
||||
static void reset_packet(void *obj)
|
||||
{
|
||||
av_packet_unref(obj);
|
||||
}
|
||||
static void reset_frame(void *obj)
|
||||
{
|
||||
av_frame_unref(obj);
|
||||
}
|
||||
|
||||
static void free_packet(void **obj)
|
||||
{
|
||||
AVPacket *pkt = *obj;
|
||||
av_packet_free(&pkt);
|
||||
*obj = NULL;
|
||||
}
|
||||
static void free_frame(void **obj)
|
||||
{
|
||||
AVFrame *frame = *obj;
|
||||
av_frame_free(&frame);
|
||||
*obj = NULL;
|
||||
}
|
||||
|
||||
ObjPool *objpool_alloc_packets(void)
|
||||
{
|
||||
return objpool_alloc(alloc_packet, reset_packet, free_packet);
|
||||
}
|
||||
ObjPool *objpool_alloc_frames(void)
|
||||
{
|
||||
return objpool_alloc(alloc_frame, reset_frame, free_frame);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
* Copyright (c) 2023 ARTHENICA LTD
|
||||
*
|
||||
* FFmpeg 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 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is the modified version of objpool.h file living in ffmpeg source code under the fftools folder. We
|
||||
* manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied
|
||||
* by us to develop ffmpeg-kit library.
|
||||
*
|
||||
* ffmpeg-kit changes by ARTHENICA LTD
|
||||
*
|
||||
* 07.2023
|
||||
* --------------------------------------------------------
|
||||
* - FFmpeg 6.0 changes migrated
|
||||
*/
|
||||
|
||||
#ifndef FFTOOLS_OBJPOOL_H
|
||||
#define FFTOOLS_OBJPOOL_H
|
||||
|
||||
typedef struct ObjPool ObjPool;
|
||||
|
||||
typedef void* (*ObjPoolCBAlloc)(void);
|
||||
typedef void (*ObjPoolCBReset)(void *);
|
||||
typedef void (*ObjPoolCBFree)(void **);
|
||||
|
||||
void objpool_free(ObjPool **op);
|
||||
ObjPool *objpool_alloc(ObjPoolCBAlloc cb_alloc, ObjPoolCBReset cb_reset,
|
||||
ObjPoolCBFree cb_free);
|
||||
ObjPool *objpool_alloc_packets(void);
|
||||
ObjPool *objpool_alloc_frames(void);
|
||||
|
||||
int objpool_get(ObjPool *op, void **obj);
|
||||
void objpool_release(ObjPool *op, void **obj);
|
||||
|
||||
#endif // FFTOOLS_OBJPOOL_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Option handlers shared between the tools.
|
||||
* Copyright (c) 2022 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg 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 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is the modified version of opt_common.h file living in ffmpeg source code under the fftools folder. We
|
||||
* manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied
|
||||
* by us to develop the ffmpeg-kit library.
|
||||
*
|
||||
* ffmpeg-kit changes by Taner Sener
|
||||
*
|
||||
* 09.2022
|
||||
* --------------------------------------------------------
|
||||
* - CMDUTILS_COMMON_OPTIONS and CMDUTILS_COMMON_OPTIONS_AVDEVICE defines dropped
|
||||
* - fftools_ prefix added to fftools headers
|
||||
*/
|
||||
|
||||
#ifndef FFTOOLS_OPT_COMMON_H
|
||||
#define FFTOOLS_OPT_COMMON_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "fftools_cmdutils.h"
|
||||
|
||||
#if CONFIG_AVDEVICE
|
||||
/**
|
||||
* Print a listing containing autodetected sinks of the output device.
|
||||
* Device name with options may be passed as an argument to limit results.
|
||||
*/
|
||||
int show_sinks(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing autodetected sources of the input device.
|
||||
* Device name with options may be passed as an argument to limit results.
|
||||
*/
|
||||
int show_sources(void *optctx, const char *opt, const char *arg);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Print the license of the program to stdout. The license depends on
|
||||
* the license of the libraries compiled into the program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_license(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Generic -h handler common to all fftools.
|
||||
*/
|
||||
int show_help(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print the version of the program to stdout. The version message
|
||||
* depends on the current versions of the repository and of the libav*
|
||||
* libraries.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_version(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print the build configuration of the program to stdout. The contents
|
||||
* depend on the definition of FFMPEG_CONFIGURATION.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_buildconf(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the formats supported by the
|
||||
* program (including devices).
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_formats(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the muxers supported by the
|
||||
* program (including devices).
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_muxers(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the demuxer supported by the
|
||||
* program (including devices).
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_demuxers(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the devices supported by the
|
||||
* program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_devices(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the codecs supported by the
|
||||
* program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_codecs(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the decoders supported by the
|
||||
* program.
|
||||
*/
|
||||
int show_decoders(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the encoders supported by the
|
||||
* program.
|
||||
*/
|
||||
int show_encoders(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the bit stream filters supported by the
|
||||
* program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_bsfs(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the protocols supported by the
|
||||
* program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_protocols(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the filters supported by the
|
||||
* program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_filters(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the pixel formats supported by the
|
||||
* program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_pix_fmts(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the standard channel layouts supported by
|
||||
* the program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_layouts(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the sample formats supported by the
|
||||
* program.
|
||||
*/
|
||||
int show_sample_fmts(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all supported stream dispositions.
|
||||
*/
|
||||
int show_dispositions(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the color names and values recognized
|
||||
* by the program.
|
||||
*/
|
||||
int show_colors(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Set the libav* libraries log level.
|
||||
*/
|
||||
int opt_loglevel(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
int opt_report(void *optctx, const char *opt, const char *arg);
|
||||
int init_report(const char *env, FILE **file);
|
||||
|
||||
int opt_max_alloc(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Override the cpuflags.
|
||||
*/
|
||||
int opt_cpuflags(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Override the cpucount.
|
||||
*/
|
||||
int opt_cpucount(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
#endif /* FFTOOLS_OPT_COMMON_H */
|
||||
@@ -0,0 +1,462 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
* Copyright (c) 2023 ARTHENICA LTD
|
||||
*
|
||||
* FFmpeg 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 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is the modified version of sync_queue.c file living in ffmpeg source code under the fftools folder. We
|
||||
* manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied
|
||||
* by us to develop ffmpeg-kit library.
|
||||
*
|
||||
* ffmpeg-kit changes by ARTHENICA LTD
|
||||
*
|
||||
* 07.2023
|
||||
* --------------------------------------------------------
|
||||
* - FFmpeg 6.0 changes migrated
|
||||
* - fftools header names updated
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/error.h"
|
||||
#include "libavutil/fifo.h"
|
||||
#include "libavutil/mathematics.h"
|
||||
#include "libavutil/mem.h"
|
||||
|
||||
#include "fftools_objpool.h"
|
||||
#include "fftools_sync_queue.h"
|
||||
|
||||
typedef struct SyncQueueStream {
|
||||
AVFifo *fifo;
|
||||
AVRational tb;
|
||||
|
||||
/* stream head: largest timestamp seen */
|
||||
int64_t head_ts;
|
||||
int limiting;
|
||||
/* no more frames will be sent for this stream */
|
||||
int finished;
|
||||
|
||||
uint64_t frames_sent;
|
||||
uint64_t frames_max;
|
||||
} SyncQueueStream;
|
||||
|
||||
struct SyncQueue {
|
||||
enum SyncQueueType type;
|
||||
|
||||
/* no more frames will be sent for any stream */
|
||||
int finished;
|
||||
/* sync head: the stream with the _smallest_ head timestamp
|
||||
* this stream determines which frames can be output */
|
||||
int head_stream;
|
||||
/* the finished stream with the smallest finish timestamp or -1 */
|
||||
int head_finished_stream;
|
||||
|
||||
// maximum buffering duration in microseconds
|
||||
int64_t buf_size_us;
|
||||
|
||||
SyncQueueStream *streams;
|
||||
unsigned int nb_streams;
|
||||
|
||||
// pool of preallocated frames to avoid constant allocations
|
||||
ObjPool *pool;
|
||||
};
|
||||
|
||||
static void frame_move(const SyncQueue *sq, SyncQueueFrame dst,
|
||||
SyncQueueFrame src)
|
||||
{
|
||||
if (sq->type == SYNC_QUEUE_PACKETS)
|
||||
av_packet_move_ref(dst.p, src.p);
|
||||
else
|
||||
av_frame_move_ref(dst.f, src.f);
|
||||
}
|
||||
|
||||
static int64_t frame_ts(const SyncQueue *sq, SyncQueueFrame frame)
|
||||
{
|
||||
return (sq->type == SYNC_QUEUE_PACKETS) ?
|
||||
frame.p->pts + frame.p->duration :
|
||||
frame.f->pts + frame.f->duration;
|
||||
}
|
||||
|
||||
static int frame_null(const SyncQueue *sq, SyncQueueFrame frame)
|
||||
{
|
||||
return (sq->type == SYNC_QUEUE_PACKETS) ? (frame.p == NULL) : (frame.f == NULL);
|
||||
}
|
||||
|
||||
static void finish_stream(SyncQueue *sq, unsigned int stream_idx)
|
||||
{
|
||||
SyncQueueStream *st = &sq->streams[stream_idx];
|
||||
|
||||
st->finished = 1;
|
||||
|
||||
if (st->limiting && st->head_ts != AV_NOPTS_VALUE) {
|
||||
/* check if this stream is the new finished head */
|
||||
if (sq->head_finished_stream < 0 ||
|
||||
av_compare_ts(st->head_ts, st->tb,
|
||||
sq->streams[sq->head_finished_stream].head_ts,
|
||||
sq->streams[sq->head_finished_stream].tb) < 0) {
|
||||
sq->head_finished_stream = stream_idx;
|
||||
}
|
||||
|
||||
/* mark as finished all streams that should no longer receive new frames,
|
||||
* due to them being ahead of some finished stream */
|
||||
st = &sq->streams[sq->head_finished_stream];
|
||||
for (unsigned int i = 0; i < sq->nb_streams; i++) {
|
||||
SyncQueueStream *st1 = &sq->streams[i];
|
||||
if (st != st1 && st1->head_ts != AV_NOPTS_VALUE &&
|
||||
av_compare_ts(st->head_ts, st->tb, st1->head_ts, st1->tb) <= 0)
|
||||
st1->finished = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* mark the whole queue as finished if all streams are finished */
|
||||
for (unsigned int i = 0; i < sq->nb_streams; i++) {
|
||||
if (!sq->streams[i].finished)
|
||||
return;
|
||||
}
|
||||
sq->finished = 1;
|
||||
}
|
||||
|
||||
static void queue_head_update(SyncQueue *sq)
|
||||
{
|
||||
if (sq->head_stream < 0) {
|
||||
/* wait for one timestamp in each stream before determining
|
||||
* the queue head */
|
||||
for (unsigned int i = 0; i < sq->nb_streams; i++) {
|
||||
SyncQueueStream *st = &sq->streams[i];
|
||||
if (st->limiting && st->head_ts == AV_NOPTS_VALUE)
|
||||
return;
|
||||
}
|
||||
|
||||
// placeholder value, correct one will be found below
|
||||
sq->head_stream = 0;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < sq->nb_streams; i++) {
|
||||
SyncQueueStream *st_head = &sq->streams[sq->head_stream];
|
||||
SyncQueueStream *st_other = &sq->streams[i];
|
||||
if (st_other->limiting && st_other->head_ts != AV_NOPTS_VALUE &&
|
||||
av_compare_ts(st_other->head_ts, st_other->tb,
|
||||
st_head->head_ts, st_head->tb) < 0)
|
||||
sq->head_stream = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* update this stream's head timestamp */
|
||||
static void stream_update_ts(SyncQueue *sq, unsigned int stream_idx, int64_t ts)
|
||||
{
|
||||
SyncQueueStream *st = &sq->streams[stream_idx];
|
||||
|
||||
if (ts == AV_NOPTS_VALUE ||
|
||||
(st->head_ts != AV_NOPTS_VALUE && st->head_ts >= ts))
|
||||
return;
|
||||
|
||||
st->head_ts = ts;
|
||||
|
||||
/* if this stream is now ahead of some finished stream, then
|
||||
* this stream is also finished */
|
||||
if (sq->head_finished_stream >= 0 &&
|
||||
av_compare_ts(sq->streams[sq->head_finished_stream].head_ts,
|
||||
sq->streams[sq->head_finished_stream].tb,
|
||||
ts, st->tb) <= 0)
|
||||
finish_stream(sq, stream_idx);
|
||||
|
||||
/* update the overall head timestamp if it could have changed */
|
||||
if (st->limiting &&
|
||||
(sq->head_stream < 0 || sq->head_stream == stream_idx))
|
||||
queue_head_update(sq);
|
||||
}
|
||||
|
||||
/* If the queue for the given stream (or all streams when stream_idx=-1)
|
||||
* is overflowing, trigger a fake heartbeat on lagging streams.
|
||||
*
|
||||
* @return 1 if heartbeat triggered, 0 otherwise
|
||||
*/
|
||||
static int overflow_heartbeat(SyncQueue *sq, int stream_idx)
|
||||
{
|
||||
SyncQueueStream *st;
|
||||
SyncQueueFrame frame;
|
||||
int64_t tail_ts = AV_NOPTS_VALUE;
|
||||
|
||||
/* if no stream specified, pick the one that is most ahead */
|
||||
if (stream_idx < 0) {
|
||||
int64_t ts = AV_NOPTS_VALUE;
|
||||
|
||||
for (int i = 0; i < sq->nb_streams; i++) {
|
||||
st = &sq->streams[i];
|
||||
if (st->head_ts != AV_NOPTS_VALUE &&
|
||||
(ts == AV_NOPTS_VALUE ||
|
||||
av_compare_ts(ts, sq->streams[stream_idx].tb,
|
||||
st->head_ts, st->tb) < 0)) {
|
||||
ts = st->head_ts;
|
||||
stream_idx = i;
|
||||
}
|
||||
}
|
||||
/* no stream has a timestamp yet -> nothing to do */
|
||||
if (stream_idx < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
st = &sq->streams[stream_idx];
|
||||
|
||||
/* get the chosen stream's tail timestamp */
|
||||
for (size_t i = 0; tail_ts == AV_NOPTS_VALUE &&
|
||||
av_fifo_peek(st->fifo, &frame, 1, i) >= 0; i++)
|
||||
tail_ts = frame_ts(sq, frame);
|
||||
|
||||
/* overflow triggers when the tail is over specified duration behind the head */
|
||||
if (tail_ts == AV_NOPTS_VALUE || tail_ts >= st->head_ts ||
|
||||
av_rescale_q(st->head_ts - tail_ts, st->tb, AV_TIME_BASE_Q) < sq->buf_size_us)
|
||||
return 0;
|
||||
|
||||
/* signal a fake timestamp for all streams that prevent tail_ts from being output */
|
||||
tail_ts++;
|
||||
for (unsigned int i = 0; i < sq->nb_streams; i++) {
|
||||
SyncQueueStream *st1 = &sq->streams[i];
|
||||
int64_t ts;
|
||||
|
||||
if (st == st1 || st1->finished ||
|
||||
(st1->head_ts != AV_NOPTS_VALUE &&
|
||||
av_compare_ts(tail_ts, st->tb, st1->head_ts, st1->tb) <= 0))
|
||||
continue;
|
||||
|
||||
ts = av_rescale_q(tail_ts, st->tb, st1->tb);
|
||||
if (st1->head_ts != AV_NOPTS_VALUE)
|
||||
ts = FFMAX(st1->head_ts + 1, ts);
|
||||
|
||||
stream_update_ts(sq, i, ts);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sq_send(SyncQueue *sq, unsigned int stream_idx, SyncQueueFrame frame)
|
||||
{
|
||||
SyncQueueStream *st;
|
||||
SyncQueueFrame dst;
|
||||
int64_t ts;
|
||||
int ret;
|
||||
|
||||
av_assert0(stream_idx < sq->nb_streams);
|
||||
st = &sq->streams[stream_idx];
|
||||
|
||||
av_assert0(st->tb.num > 0 && st->tb.den > 0);
|
||||
|
||||
if (frame_null(sq, frame)) {
|
||||
finish_stream(sq, stream_idx);
|
||||
return 0;
|
||||
}
|
||||
if (st->finished)
|
||||
return AVERROR_EOF;
|
||||
|
||||
ret = objpool_get(sq->pool, (void**)&dst);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
frame_move(sq, dst, frame);
|
||||
|
||||
ts = frame_ts(sq, dst);
|
||||
|
||||
ret = av_fifo_write(st->fifo, &dst, 1);
|
||||
if (ret < 0) {
|
||||
frame_move(sq, frame, dst);
|
||||
objpool_release(sq->pool, (void**)&dst);
|
||||
return ret;
|
||||
}
|
||||
|
||||
stream_update_ts(sq, stream_idx, ts);
|
||||
|
||||
st->frames_sent++;
|
||||
if (st->frames_sent >= st->frames_max)
|
||||
finish_stream(sq, stream_idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int receive_for_stream(SyncQueue *sq, unsigned int stream_idx,
|
||||
SyncQueueFrame frame)
|
||||
{
|
||||
SyncQueueStream *st_head = sq->head_stream >= 0 ?
|
||||
&sq->streams[sq->head_stream] : NULL;
|
||||
SyncQueueStream *st;
|
||||
|
||||
av_assert0(stream_idx < sq->nb_streams);
|
||||
st = &sq->streams[stream_idx];
|
||||
|
||||
if (av_fifo_can_read(st->fifo)) {
|
||||
SyncQueueFrame peek;
|
||||
int64_t ts;
|
||||
int cmp = 1;
|
||||
|
||||
av_fifo_peek(st->fifo, &peek, 1, 0);
|
||||
ts = frame_ts(sq, peek);
|
||||
|
||||
/* check if this stream's tail timestamp does not overtake
|
||||
* the overall queue head */
|
||||
if (ts != AV_NOPTS_VALUE && st_head)
|
||||
cmp = av_compare_ts(ts, st->tb, st_head->head_ts, st_head->tb);
|
||||
|
||||
/* We can release frames that do not end after the queue head.
|
||||
* Frames with no timestamps are just passed through with no conditions.
|
||||
*/
|
||||
if (cmp <= 0 || ts == AV_NOPTS_VALUE) {
|
||||
frame_move(sq, frame, peek);
|
||||
objpool_release(sq->pool, (void**)&peek);
|
||||
av_fifo_drain2(st->fifo, 1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (sq->finished || (st->finished && !av_fifo_can_read(st->fifo))) ?
|
||||
AVERROR_EOF : AVERROR(EAGAIN);
|
||||
}
|
||||
|
||||
static int receive_internal(SyncQueue *sq, int stream_idx, SyncQueueFrame frame)
|
||||
{
|
||||
int nb_eof = 0;
|
||||
int ret;
|
||||
|
||||
/* read a frame for a specific stream */
|
||||
if (stream_idx >= 0) {
|
||||
ret = receive_for_stream(sq, stream_idx, frame);
|
||||
return (ret < 0) ? ret : stream_idx;
|
||||
}
|
||||
|
||||
/* read a frame for any stream with available output */
|
||||
for (unsigned int i = 0; i < sq->nb_streams; i++) {
|
||||
ret = receive_for_stream(sq, i, frame);
|
||||
if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) {
|
||||
nb_eof += (ret == AVERROR_EOF);
|
||||
continue;
|
||||
}
|
||||
return (ret < 0) ? ret : i;
|
||||
}
|
||||
|
||||
return (nb_eof == sq->nb_streams) ? AVERROR_EOF : AVERROR(EAGAIN);
|
||||
}
|
||||
|
||||
int sq_receive(SyncQueue *sq, int stream_idx, SyncQueueFrame frame)
|
||||
{
|
||||
int ret = receive_internal(sq, stream_idx, frame);
|
||||
|
||||
/* try again if the queue overflowed and triggered a fake heartbeat
|
||||
* for lagging streams */
|
||||
if (ret == AVERROR(EAGAIN) && overflow_heartbeat(sq, stream_idx))
|
||||
ret = receive_internal(sq, stream_idx, frame);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sq_add_stream(SyncQueue *sq, int limiting)
|
||||
{
|
||||
SyncQueueStream *tmp, *st;
|
||||
|
||||
tmp = av_realloc_array(sq->streams, sq->nb_streams + 1, sizeof(*sq->streams));
|
||||
if (!tmp)
|
||||
return AVERROR(ENOMEM);
|
||||
sq->streams = tmp;
|
||||
|
||||
st = &sq->streams[sq->nb_streams];
|
||||
memset(st, 0, sizeof(*st));
|
||||
|
||||
st->fifo = av_fifo_alloc2(1, sizeof(SyncQueueFrame), AV_FIFO_FLAG_AUTO_GROW);
|
||||
if (!st->fifo)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
/* we set a valid default, so that a pathological stream that never
|
||||
* receives even a real timebase (and no frames) won't stall all other
|
||||
* streams forever; cf. overflow_heartbeat() */
|
||||
st->tb = (AVRational){ 1, 1 };
|
||||
st->head_ts = AV_NOPTS_VALUE;
|
||||
st->frames_max = UINT64_MAX;
|
||||
st->limiting = limiting;
|
||||
|
||||
return sq->nb_streams++;
|
||||
}
|
||||
|
||||
void sq_set_tb(SyncQueue *sq, unsigned int stream_idx, AVRational tb)
|
||||
{
|
||||
SyncQueueStream *st;
|
||||
|
||||
av_assert0(stream_idx < sq->nb_streams);
|
||||
st = &sq->streams[stream_idx];
|
||||
|
||||
av_assert0(!av_fifo_can_read(st->fifo));
|
||||
|
||||
if (st->head_ts != AV_NOPTS_VALUE)
|
||||
st->head_ts = av_rescale_q(st->head_ts, st->tb, tb);
|
||||
|
||||
st->tb = tb;
|
||||
}
|
||||
|
||||
void sq_limit_frames(SyncQueue *sq, unsigned int stream_idx, uint64_t frames)
|
||||
{
|
||||
SyncQueueStream *st;
|
||||
|
||||
av_assert0(stream_idx < sq->nb_streams);
|
||||
st = &sq->streams[stream_idx];
|
||||
|
||||
st->frames_max = frames;
|
||||
if (st->frames_sent >= st->frames_max)
|
||||
finish_stream(sq, stream_idx);
|
||||
}
|
||||
|
||||
SyncQueue *sq_alloc(enum SyncQueueType type, int64_t buf_size_us)
|
||||
{
|
||||
SyncQueue *sq = av_mallocz(sizeof(*sq));
|
||||
|
||||
if (!sq)
|
||||
return NULL;
|
||||
|
||||
sq->type = type;
|
||||
sq->buf_size_us = buf_size_us;
|
||||
|
||||
sq->head_stream = -1;
|
||||
sq->head_finished_stream = -1;
|
||||
|
||||
sq->pool = (type == SYNC_QUEUE_PACKETS) ? objpool_alloc_packets() :
|
||||
objpool_alloc_frames();
|
||||
if (!sq->pool) {
|
||||
av_freep(&sq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sq;
|
||||
}
|
||||
|
||||
void sq_free(SyncQueue **psq)
|
||||
{
|
||||
SyncQueue *sq = *psq;
|
||||
|
||||
if (!sq)
|
||||
return;
|
||||
|
||||
for (unsigned int i = 0; i < sq->nb_streams; i++) {
|
||||
SyncQueueFrame frame;
|
||||
while (av_fifo_read(sq->streams[i].fifo, &frame, 1) >= 0)
|
||||
objpool_release(sq->pool, (void**)&frame);
|
||||
|
||||
av_fifo_freep2(&sq->streams[i].fifo);
|
||||
}
|
||||
|
||||
av_freep(&sq->streams);
|
||||
|
||||
objpool_free(&sq->pool);
|
||||
|
||||
av_freep(psq);
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
* Copyright (c) 2023 ARTHENICA LTD
|
||||
*
|
||||
* FFmpeg 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 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is the modified version of sync_queue.h file living in ffmpeg source code under the fftools folder. We
|
||||
* manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied
|
||||
* by us to develop ffmpeg-kit library.
|
||||
*
|
||||
* ffmpeg-kit changes by ARTHENICA LTD
|
||||
*
|
||||
* 07.2023
|
||||
* --------------------------------------------------------
|
||||
* - FFmpeg 6.0 changes migrated
|
||||
*/
|
||||
|
||||
#ifndef FFTOOLS_SYNC_QUEUE_H
|
||||
#define FFTOOLS_SYNC_QUEUE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libavcodec/packet.h"
|
||||
|
||||
#include "libavutil/frame.h"
|
||||
|
||||
enum SyncQueueType {
|
||||
SYNC_QUEUE_PACKETS,
|
||||
SYNC_QUEUE_FRAMES,
|
||||
};
|
||||
|
||||
typedef union SyncQueueFrame {
|
||||
AVFrame *f;
|
||||
AVPacket *p;
|
||||
} SyncQueueFrame;
|
||||
|
||||
#define SQFRAME(frame) ((SyncQueueFrame){ .f = (frame) })
|
||||
#define SQPKT(pkt) ((SyncQueueFrame){ .p = (pkt) })
|
||||
|
||||
typedef struct SyncQueue SyncQueue;
|
||||
|
||||
/**
|
||||
* Allocate a sync queue of the given type.
|
||||
*
|
||||
* @param buf_size_us maximum duration that will be buffered in microseconds
|
||||
*/
|
||||
SyncQueue *sq_alloc(enum SyncQueueType type, int64_t buf_size_us);
|
||||
void sq_free(SyncQueue **sq);
|
||||
|
||||
/**
|
||||
* Add a new stream to the sync queue.
|
||||
*
|
||||
* @param limiting whether the stream is limiting, i.e. no other stream can be
|
||||
* longer than this one
|
||||
* @return
|
||||
* - a non-negative stream index on success
|
||||
* - a negative error code on error
|
||||
*/
|
||||
int sq_add_stream(SyncQueue *sq, int limiting);
|
||||
|
||||
/**
|
||||
* Set the timebase for the stream with index stream_idx. Should be called
|
||||
* before sending any frames for this stream.
|
||||
*/
|
||||
void sq_set_tb(SyncQueue *sq, unsigned int stream_idx, AVRational tb);
|
||||
|
||||
/**
|
||||
* Limit the number of output frames for stream with index stream_idx
|
||||
* to max_frames.
|
||||
*/
|
||||
void sq_limit_frames(SyncQueue *sq, unsigned int stream_idx,
|
||||
uint64_t max_frames);
|
||||
|
||||
/**
|
||||
* Submit a frame for the stream with index stream_idx.
|
||||
*
|
||||
* On success, the sync queue takes ownership of the frame and will reset the
|
||||
* contents of the supplied frame. On failure, the frame remains owned by the
|
||||
* caller.
|
||||
*
|
||||
* Sending a frame with NULL contents marks the stream as finished.
|
||||
*
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - AVERROR_EOF when no more frames should be submitted for this stream
|
||||
* - another a negative error code on failure
|
||||
*/
|
||||
int sq_send(SyncQueue *sq, unsigned int stream_idx, SyncQueueFrame frame);
|
||||
|
||||
/**
|
||||
* Read a frame from the queue.
|
||||
*
|
||||
* @param stream_idx index of the stream to read a frame for. May be -1, then
|
||||
* try to read a frame from any stream that is ready for
|
||||
* output.
|
||||
* @param frame output frame will be written here on success. The frame is owned
|
||||
* by the caller.
|
||||
*
|
||||
* @return
|
||||
* - a non-negative index of the stream to which the returned frame belongs
|
||||
* - AVERROR(EAGAIN) when more frames need to be submitted to the queue
|
||||
* - AVERROR_EOF when no more frames will be available for this stream (for any
|
||||
* stream if stream_idx is -1)
|
||||
* - another negative error code on failure
|
||||
*/
|
||||
int sq_receive(SyncQueue *sq, int stream_idx, SyncQueueFrame frame);
|
||||
|
||||
#endif // FFTOOLS_SYNC_QUEUE_H
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
* Copyright (c) 2023 ARTHENICA LTD
|
||||
*
|
||||
* FFmpeg 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 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is the modified version of thread_queue.c file living in ffmpeg source code under the fftools folder. We
|
||||
* manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied
|
||||
* by us to develop ffmpeg-kit library.
|
||||
*
|
||||
* ffmpeg-kit changes by ARTHENICA LTD
|
||||
*
|
||||
* 07.2023
|
||||
* --------------------------------------------------------
|
||||
* - FFmpeg 6.0 changes migrated
|
||||
* - fftools header names updated
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/error.h"
|
||||
#include "libavutil/fifo.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavutil/thread.h"
|
||||
|
||||
#include "fftools_objpool.h"
|
||||
#include "fftools_thread_queue.h"
|
||||
|
||||
enum {
|
||||
FINISHED_SEND = (1 << 0),
|
||||
FINISHED_RECV = (1 << 1),
|
||||
};
|
||||
|
||||
typedef struct FifoElem {
|
||||
void *obj;
|
||||
unsigned int stream_idx;
|
||||
} FifoElem;
|
||||
|
||||
struct ThreadQueue {
|
||||
int *finished;
|
||||
unsigned int nb_streams;
|
||||
|
||||
AVFifo *fifo;
|
||||
|
||||
ObjPool *obj_pool;
|
||||
void (*obj_move)(void *dst, void *src);
|
||||
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t cond;
|
||||
};
|
||||
|
||||
void tq_free(ThreadQueue **ptq)
|
||||
{
|
||||
ThreadQueue *tq = *ptq;
|
||||
|
||||
if (!tq)
|
||||
return;
|
||||
|
||||
if (tq->fifo) {
|
||||
FifoElem elem;
|
||||
while (av_fifo_read(tq->fifo, &elem, 1) >= 0)
|
||||
objpool_release(tq->obj_pool, &elem.obj);
|
||||
}
|
||||
av_fifo_freep2(&tq->fifo);
|
||||
|
||||
objpool_free(&tq->obj_pool);
|
||||
|
||||
av_freep(&tq->finished);
|
||||
|
||||
pthread_cond_destroy(&tq->cond);
|
||||
pthread_mutex_destroy(&tq->lock);
|
||||
|
||||
av_freep(ptq);
|
||||
}
|
||||
|
||||
ThreadQueue *tq_alloc(unsigned int nb_streams, size_t queue_size,
|
||||
ObjPool *obj_pool, void (*obj_move)(void *dst, void *src))
|
||||
{
|
||||
ThreadQueue *tq;
|
||||
int ret;
|
||||
|
||||
tq = av_mallocz(sizeof(*tq));
|
||||
if (!tq)
|
||||
return NULL;
|
||||
|
||||
ret = pthread_cond_init(&tq->cond, NULL);
|
||||
if (ret) {
|
||||
av_freep(&tq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = pthread_mutex_init(&tq->lock, NULL);
|
||||
if (ret) {
|
||||
pthread_cond_destroy(&tq->cond);
|
||||
av_freep(&tq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tq->finished = av_calloc(nb_streams, sizeof(*tq->finished));
|
||||
if (!tq->finished)
|
||||
goto fail;
|
||||
tq->nb_streams = nb_streams;
|
||||
|
||||
tq->fifo = av_fifo_alloc2(queue_size, sizeof(FifoElem), 0);
|
||||
if (!tq->fifo)
|
||||
goto fail;
|
||||
|
||||
tq->obj_pool = obj_pool;
|
||||
tq->obj_move = obj_move;
|
||||
|
||||
return tq;
|
||||
fail:
|
||||
tq_free(&tq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int tq_send(ThreadQueue *tq, unsigned int stream_idx, void *data)
|
||||
{
|
||||
int *finished;
|
||||
int ret;
|
||||
|
||||
av_assert0(stream_idx < tq->nb_streams);
|
||||
finished = &tq->finished[stream_idx];
|
||||
|
||||
pthread_mutex_lock(&tq->lock);
|
||||
|
||||
if (*finished & FINISHED_SEND) {
|
||||
ret = AVERROR(EINVAL);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
while (!(*finished & FINISHED_RECV) && !av_fifo_can_write(tq->fifo))
|
||||
pthread_cond_wait(&tq->cond, &tq->lock);
|
||||
|
||||
if (*finished & FINISHED_RECV) {
|
||||
ret = AVERROR_EOF;
|
||||
*finished |= FINISHED_SEND;
|
||||
} else {
|
||||
FifoElem elem = { .stream_idx = stream_idx };
|
||||
|
||||
ret = objpool_get(tq->obj_pool, &elem.obj);
|
||||
if (ret < 0)
|
||||
goto finish;
|
||||
|
||||
tq->obj_move(elem.obj, data);
|
||||
|
||||
ret = av_fifo_write(tq->fifo, &elem, 1);
|
||||
av_assert0(ret >= 0);
|
||||
pthread_cond_broadcast(&tq->cond);
|
||||
}
|
||||
|
||||
finish:
|
||||
pthread_mutex_unlock(&tq->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int receive_locked(ThreadQueue *tq, int *stream_idx,
|
||||
void *data)
|
||||
{
|
||||
FifoElem elem;
|
||||
unsigned int nb_finished = 0;
|
||||
|
||||
if (av_fifo_read(tq->fifo, &elem, 1) >= 0) {
|
||||
tq->obj_move(data, elem.obj);
|
||||
objpool_release(tq->obj_pool, &elem.obj);
|
||||
*stream_idx = elem.stream_idx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < tq->nb_streams; i++) {
|
||||
if (!(tq->finished[i] & FINISHED_SEND))
|
||||
continue;
|
||||
|
||||
/* return EOF to the consumer at most once for each stream */
|
||||
if (!(tq->finished[i] & FINISHED_RECV)) {
|
||||
tq->finished[i] |= FINISHED_RECV;
|
||||
*stream_idx = i;
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
|
||||
nb_finished++;
|
||||
}
|
||||
|
||||
return nb_finished == tq->nb_streams ? AVERROR_EOF : AVERROR(EAGAIN);
|
||||
}
|
||||
|
||||
int tq_receive(ThreadQueue *tq, int *stream_idx, void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
*stream_idx = -1;
|
||||
|
||||
pthread_mutex_lock(&tq->lock);
|
||||
|
||||
while (1) {
|
||||
ret = receive_locked(tq, stream_idx, data);
|
||||
if (ret == AVERROR(EAGAIN)) {
|
||||
pthread_cond_wait(&tq->cond, &tq->lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
pthread_cond_broadcast(&tq->cond);
|
||||
|
||||
pthread_mutex_unlock(&tq->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void tq_send_finish(ThreadQueue *tq, unsigned int stream_idx)
|
||||
{
|
||||
av_assert0(stream_idx < tq->nb_streams);
|
||||
|
||||
pthread_mutex_lock(&tq->lock);
|
||||
|
||||
/* mark the stream as send-finished;
|
||||
* next time the consumer thread tries to read this stream it will get
|
||||
* an EOF and recv-finished flag will be set */
|
||||
tq->finished[stream_idx] |= FINISHED_SEND;
|
||||
pthread_cond_broadcast(&tq->cond);
|
||||
|
||||
pthread_mutex_unlock(&tq->lock);
|
||||
}
|
||||
|
||||
void tq_receive_finish(ThreadQueue *tq, unsigned int stream_idx)
|
||||
{
|
||||
av_assert0(stream_idx < tq->nb_streams);
|
||||
|
||||
pthread_mutex_lock(&tq->lock);
|
||||
|
||||
/* mark the stream as recv-finished;
|
||||
* next time the producer thread tries to send for this stream, it will
|
||||
* get an EOF and send-finished flag will be set */
|
||||
tq->finished[stream_idx] |= FINISHED_RECV;
|
||||
pthread_cond_broadcast(&tq->cond);
|
||||
|
||||
pthread_mutex_unlock(&tq->lock);
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
* Copyright (c) 2023 ARTHENICA LTD
|
||||
*
|
||||
* FFmpeg 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 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is the modified version of thread_queue.h file living in ffmpeg source code under the fftools folder. We
|
||||
* manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied
|
||||
* by us to develop ffmpeg-kit library.
|
||||
*
|
||||
* ffmpeg-kit changes by ARTHENICA LTD
|
||||
*
|
||||
* 07.2023
|
||||
* --------------------------------------------------------
|
||||
* - FFmpeg 6.0 changes migrated
|
||||
*/
|
||||
|
||||
#ifndef FFTOOLS_THREAD_QUEUE_H
|
||||
#define FFTOOLS_THREAD_QUEUE_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "fftools_objpool.h"
|
||||
|
||||
typedef struct ThreadQueue ThreadQueue;
|
||||
|
||||
/**
|
||||
* Allocate a queue for sending data between threads.
|
||||
*
|
||||
* @param nb_streams number of streams for which a distinct EOF state is
|
||||
* maintained
|
||||
* @param queue_size number of items that can be stored in the queue without
|
||||
* blocking
|
||||
* @param obj_pool object pool that will be used to allocate items stored in the
|
||||
* queue; the pool becomes owned by the queue
|
||||
* @param callback that moves the contents between two data pointers
|
||||
*/
|
||||
ThreadQueue *tq_alloc(unsigned int nb_streams, size_t queue_size,
|
||||
ObjPool *obj_pool, void (*obj_move)(void *dst, void *src));
|
||||
void tq_free(ThreadQueue **tq);
|
||||
|
||||
/**
|
||||
* Send an item for the given stream to the queue.
|
||||
*
|
||||
* @param data the item to send, its contents will be moved using the callback
|
||||
* provided to tq_alloc(); on failure the item will be left
|
||||
* untouched
|
||||
* @return
|
||||
* - 0 the item was successfully sent
|
||||
* - AVERROR(ENOMEM) could not allocate an item for writing to the FIFO
|
||||
* - AVERROR(EINVAL) the sending side has previously been marked as finished
|
||||
* - AVERROR_EOF the receiving side has marked the given stream as finished
|
||||
*/
|
||||
int tq_send(ThreadQueue *tq, unsigned int stream_idx, void *data);
|
||||
/**
|
||||
* Mark the given stream finished from the sending side.
|
||||
*/
|
||||
void tq_send_finish(ThreadQueue *tq, unsigned int stream_idx);
|
||||
|
||||
/**
|
||||
* Read the next item from the queue.
|
||||
*
|
||||
* @param stream_idx the index of the stream that was processed or -1 will be
|
||||
* written here
|
||||
* @param data the data item will be written here on success using the
|
||||
* callback provided to tq_alloc()
|
||||
* @return
|
||||
* - 0 a data item was successfully read; *stream_idx contains a non-negative
|
||||
* stream index
|
||||
* - AVERROR_EOF When *stream_idx is non-negative, this signals that the sending
|
||||
* side has marked the given stream as finished. This will happen at most once
|
||||
* for each stream. When *stream_idx is -1, all streams are done.
|
||||
*/
|
||||
int tq_receive(ThreadQueue *tq, int *stream_idx, void *data);
|
||||
/**
|
||||
* Mark the given stream finished from the receiving side.
|
||||
*/
|
||||
void tq_receive_finish(ThreadQueue *tq, unsigned int stream_idx);
|
||||
|
||||
#endif // FFTOOLS_THREAD_QUEUE_H
|
||||
Reference in New Issue
Block a user