Implemented support for multiple decoders per file name extension, with a floating point priority control per interface. In the event that more than one input is registered to a given extension, and we match that extension, it will be passed off to an instance of the multi-decoder wrapper, which will try opening the file with all of the decoders in order of priority, until either one of them accepts it, or all of them have failed. This paves the way for adding a VGMSTREAM input, so I can give it a very low priority, since it has several formats that are verified by file name extension only. All current inputs have been given a priority of 1.0, except for CoreAudio, which was given a priority of 0.5, because it contains an MP3 and AC3 decoders that I'd rather not use if I don't have to.
2013-10-21 17:54:11 +00:00
|
|
|
//
|
2015-04-13 07:39:24 +00:00
|
|
|
// CogPluginMulti.m
|
Implemented support for multiple decoders per file name extension, with a floating point priority control per interface. In the event that more than one input is registered to a given extension, and we match that extension, it will be passed off to an instance of the multi-decoder wrapper, which will try opening the file with all of the decoders in order of priority, until either one of them accepts it, or all of them have failed. This paves the way for adding a VGMSTREAM input, so I can give it a very low priority, since it has several formats that are verified by file name extension only. All current inputs have been given a priority of 1.0, except for CoreAudio, which was given a priority of 0.5, because it contains an MP3 and AC3 decoders that I'd rather not use if I don't have to.
2013-10-21 17:54:11 +00:00
|
|
|
// CogAudio
|
|
|
|
//
|
|
|
|
// Created by Christopher Snowhill on 10/21/13.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
2015-04-13 07:39:24 +00:00
|
|
|
#import "CogPluginMulti.h"
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
NSArray *sortClassesByPriority(NSArray *theClasses) {
|
|
|
|
NSMutableArray *sortedClasses = [NSMutableArray arrayWithArray:theClasses];
|
|
|
|
[sortedClasses sortUsingComparator:
|
|
|
|
^NSComparisonResult(id obj1, id obj2) {
|
|
|
|
NSString *classString1 = (NSString *)obj1;
|
|
|
|
NSString *classString2 = (NSString *)obj2;
|
|
|
|
|
|
|
|
Class class1 = NSClassFromString(classString1);
|
|
|
|
Class class2 = NSClassFromString(classString2);
|
|
|
|
|
|
|
|
float priority1 = [class1 priority];
|
|
|
|
float priority2 = [class2 priority];
|
|
|
|
|
|
|
|
if(priority1 == priority2)
|
|
|
|
return NSOrderedSame;
|
|
|
|
else if(priority1 > priority2)
|
|
|
|
return NSOrderedAscending;
|
|
|
|
else
|
|
|
|
return NSOrderedDescending;
|
|
|
|
}];
|
|
|
|
return sortedClasses;
|
2015-04-13 07:39:24 +00:00
|
|
|
}
|
Implemented support for multiple decoders per file name extension, with a floating point priority control per interface. In the event that more than one input is registered to a given extension, and we match that extension, it will be passed off to an instance of the multi-decoder wrapper, which will try opening the file with all of the decoders in order of priority, until either one of them accepts it, or all of them have failed. This paves the way for adding a VGMSTREAM input, so I can give it a very low priority, since it has several formats that are verified by file name extension only. All current inputs have been given a priority of 1.0, except for CoreAudio, which was given a priority of 0.5, because it contains an MP3 and AC3 decoders that I'd rather not use if I don't have to.
2013-10-21 17:54:11 +00:00
|
|
|
|
2022-02-08 03:18:45 +00:00
|
|
|
@interface CogDecoderMulti (Private)
|
|
|
|
- (void)registerObservers;
|
|
|
|
- (void)removeObservers;
|
|
|
|
- (void)observeValueForKeyPath:(NSString *)keyPath
|
|
|
|
ofObject:(id)object
|
|
|
|
change:(NSDictionary *)change
|
|
|
|
context:(void *)context;
|
|
|
|
@end
|
|
|
|
|
Implemented support for multiple decoders per file name extension, with a floating point priority control per interface. In the event that more than one input is registered to a given extension, and we match that extension, it will be passed off to an instance of the multi-decoder wrapper, which will try opening the file with all of the decoders in order of priority, until either one of them accepts it, or all of them have failed. This paves the way for adding a VGMSTREAM input, so I can give it a very low priority, since it has several formats that are verified by file name extension only. All current inputs have been given a priority of 1.0, except for CoreAudio, which was given a priority of 0.5, because it contains an MP3 and AC3 decoders that I'd rather not use if I don't have to.
2013-10-21 17:54:11 +00:00
|
|
|
@implementation CogDecoderMulti
|
|
|
|
|
2022-06-15 23:47:43 +00:00
|
|
|
static void *kCogDecoderMultiContext = &kCogDecoderMultiContext;
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
+ (NSArray *)mimeTypes {
|
|
|
|
return nil;
|
Implemented support for multiple decoders per file name extension, with a floating point priority control per interface. In the event that more than one input is registered to a given extension, and we match that extension, it will be passed off to an instance of the multi-decoder wrapper, which will try opening the file with all of the decoders in order of priority, until either one of them accepts it, or all of them have failed. This paves the way for adding a VGMSTREAM input, so I can give it a very low priority, since it has several formats that are verified by file name extension only. All current inputs have been given a priority of 1.0, except for CoreAudio, which was given a priority of 0.5, because it contains an MP3 and AC3 decoders that I'd rather not use if I don't have to.
2013-10-21 17:54:11 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
+ (NSArray *)fileTypes {
|
|
|
|
return nil;
|
Implemented support for multiple decoders per file name extension, with a floating point priority control per interface. In the event that more than one input is registered to a given extension, and we match that extension, it will be passed off to an instance of the multi-decoder wrapper, which will try opening the file with all of the decoders in order of priority, until either one of them accepts it, or all of them have failed. This paves the way for adding a VGMSTREAM input, so I can give it a very low priority, since it has several formats that are verified by file name extension only. All current inputs have been given a priority of 1.0, except for CoreAudio, which was given a priority of 0.5, because it contains an MP3 and AC3 decoders that I'd rather not use if I don't have to.
2013-10-21 17:54:11 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
+ (float)priority {
|
|
|
|
return -1.0;
|
Implemented support for multiple decoders per file name extension, with a floating point priority control per interface. In the event that more than one input is registered to a given extension, and we match that extension, it will be passed off to an instance of the multi-decoder wrapper, which will try opening the file with all of the decoders in order of priority, until either one of them accepts it, or all of them have failed. This paves the way for adding a VGMSTREAM input, so I can give it a very low priority, since it has several formats that are verified by file name extension only. All current inputs have been given a priority of 1.0, except for CoreAudio, which was given a priority of 0.5, because it contains an MP3 and AC3 decoders that I'd rather not use if I don't have to.
2013-10-21 17:54:11 +00:00
|
|
|
}
|
|
|
|
|
2022-01-19 02:12:57 +00:00
|
|
|
+ (NSArray *)fileTypeAssociations {
|
2022-02-07 05:49:27 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)initWithDecoders:(NSArray *)decoders {
|
|
|
|
self = [super init];
|
|
|
|
if(self) {
|
|
|
|
theDecoders = sortClassesByPriority(decoders);
|
|
|
|
theDecoder = nil;
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDictionary *)properties {
|
|
|
|
if(theDecoder != nil) return [theDecoder properties];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2022-02-09 03:56:39 +00:00
|
|
|
- (NSDictionary *)metadata {
|
|
|
|
if(theDecoder != nil) return [theDecoder metadata];
|
|
|
|
return @{};
|
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (int)readAudio:(void *)buffer frames:(UInt32)frames {
|
|
|
|
if(theDecoder != nil) return [theDecoder readAudio:buffer frames:frames];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)open:(id<CogSource>)source {
|
|
|
|
for(NSString *classString in theDecoders) {
|
|
|
|
Class decoder = NSClassFromString(classString);
|
|
|
|
theDecoder = [[decoder alloc] init];
|
2022-02-08 03:18:45 +00:00
|
|
|
[self registerObservers];
|
2022-02-07 05:49:27 +00:00
|
|
|
if([theDecoder open:source])
|
|
|
|
return YES;
|
2022-02-08 03:18:45 +00:00
|
|
|
[self removeObservers];
|
2022-02-09 21:44:04 +00:00
|
|
|
// HTTP reader supports limited rewinding
|
|
|
|
[source seek:0 whence:SEEK_SET];
|
2022-02-07 05:49:27 +00:00
|
|
|
}
|
|
|
|
theDecoder = nil;
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (long)seek:(long)frame {
|
|
|
|
if(theDecoder != nil) return [theDecoder seek:frame];
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)close {
|
|
|
|
if(theDecoder != nil) {
|
2022-02-08 03:18:45 +00:00
|
|
|
[self removeObservers];
|
2022-02-07 05:49:27 +00:00
|
|
|
[theDecoder close];
|
|
|
|
theDecoder = nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-21 05:31:03 +00:00
|
|
|
- (void)dealloc {
|
|
|
|
[self close];
|
|
|
|
}
|
|
|
|
|
2022-02-08 03:18:45 +00:00
|
|
|
- (void)registerObservers {
|
2022-06-17 01:16:09 +00:00
|
|
|
if(!observersAdded) {
|
|
|
|
[theDecoder addObserver:self
|
|
|
|
forKeyPath:@"properties"
|
|
|
|
options:(NSKeyValueObservingOptionNew)
|
|
|
|
context:kCogDecoderMultiContext];
|
|
|
|
|
|
|
|
[theDecoder addObserver:self
|
|
|
|
forKeyPath:@"metadata"
|
|
|
|
options:(NSKeyValueObservingOptionNew)
|
|
|
|
context:kCogDecoderMultiContext];
|
|
|
|
observersAdded = YES;
|
|
|
|
}
|
2022-02-08 03:18:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)removeObservers {
|
2022-06-17 01:16:09 +00:00
|
|
|
if(observersAdded) {
|
|
|
|
observersAdded = NO;
|
|
|
|
[theDecoder removeObserver:self forKeyPath:@"properties" context:kCogDecoderMultiContext];
|
|
|
|
[theDecoder removeObserver:self forKeyPath:@"metadata" context:kCogDecoderMultiContext];
|
|
|
|
}
|
2022-02-08 03:18:45 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (BOOL)setTrack:(NSURL *)track {
|
|
|
|
if(theDecoder != nil && [theDecoder respondsToSelector:@selector(setTrack:)]) return [theDecoder setTrack:track];
|
|
|
|
return NO;
|
Implemented support for multiple decoders per file name extension, with a floating point priority control per interface. In the event that more than one input is registered to a given extension, and we match that extension, it will be passed off to an instance of the multi-decoder wrapper, which will try opening the file with all of the decoders in order of priority, until either one of them accepts it, or all of them have failed. This paves the way for adding a VGMSTREAM input, so I can give it a very low priority, since it has several formats that are verified by file name extension only. All current inputs have been given a priority of 1.0, except for CoreAudio, which was given a priority of 0.5, because it contains an MP3 and AC3 decoders that I'd rather not use if I don't have to.
2013-10-21 17:54:11 +00:00
|
|
|
}
|
|
|
|
|
2022-02-08 03:18:45 +00:00
|
|
|
- (void)observeValueForKeyPath:(NSString *)keyPath
|
|
|
|
ofObject:(id)object
|
|
|
|
change:(NSDictionary *)change
|
|
|
|
context:(void *)context {
|
2022-06-15 23:47:43 +00:00
|
|
|
if(context == kCogDecoderMultiContext) {
|
|
|
|
[self willChangeValueForKey:keyPath];
|
|
|
|
[self didChangeValueForKey:keyPath];
|
|
|
|
} else {
|
|
|
|
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
|
|
|
}
|
Implemented support for multiple decoders per file name extension, with a floating point priority control per interface. In the event that more than one input is registered to a given extension, and we match that extension, it will be passed off to an instance of the multi-decoder wrapper, which will try opening the file with all of the decoders in order of priority, until either one of them accepts it, or all of them have failed. This paves the way for adding a VGMSTREAM input, so I can give it a very low priority, since it has several formats that are verified by file name extension only. All current inputs have been given a priority of 1.0, except for CoreAudio, which was given a priority of 0.5, because it contains an MP3 and AC3 decoders that I'd rather not use if I don't have to.
2013-10-21 17:54:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
2015-04-13 07:39:24 +00:00
|
|
|
|
|
|
|
@implementation CogContainerMulti
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
+ (NSArray *)urlsForContainerURL:(NSURL *)url containers:(NSArray *)containers {
|
|
|
|
NSArray *sortedContainers = sortClassesByPriority(containers);
|
|
|
|
for(NSString *classString in sortedContainers) {
|
|
|
|
Class container = NSClassFromString(classString);
|
|
|
|
NSArray *urls = [container urlsForContainerURL:url];
|
|
|
|
if([urls count])
|
|
|
|
return urls;
|
|
|
|
}
|
|
|
|
return nil;
|
2015-04-13 07:39:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation CogMetadataReaderMulti
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
+ (NSDictionary *)metadataForURL:(NSURL *)url readers:(NSArray *)readers {
|
|
|
|
NSArray *sortedReaders = sortClassesByPriority(readers);
|
|
|
|
for(NSString *classString in sortedReaders) {
|
|
|
|
Class reader = NSClassFromString(classString);
|
|
|
|
NSDictionary *data = [reader metadataForURL:url];
|
|
|
|
if([data count])
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
return nil;
|
2015-04-13 07:39:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation CogPropertiesReaderMulti
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
+ (NSDictionary *)propertiesForSource:(id<CogSource>)source readers:(NSArray *)readers {
|
|
|
|
NSArray *sortedReaders = sortClassesByPriority(readers);
|
|
|
|
for(NSString *classString in sortedReaders) {
|
|
|
|
Class reader = NSClassFromString(classString);
|
|
|
|
NSDictionary *data = [reader propertiesForSource:source];
|
|
|
|
if([data count])
|
|
|
|
return data;
|
|
|
|
if([source seekable])
|
|
|
|
[source seek:0 whence:SEEK_SET];
|
|
|
|
}
|
|
|
|
return nil;
|
2015-04-13 07:39:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|