Significantly improve memory usage of loading tags
This especially helps with bad or brutal files. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
parent
34edc003db
commit
a1bd2e0d44
11 changed files with 343 additions and 290 deletions
|
@ -746,6 +746,7 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path);
|
|||
NSURL *url = urlForPath(key);
|
||||
|
||||
[op addExecutionBlock:^{
|
||||
@autoreleasepool {
|
||||
DLog(@"Loading metadata for %@", url);
|
||||
[[FIRCrashlytics crashlytics] logWithFormat:@"Loading metadata for %@", url];
|
||||
|
||||
|
@ -758,13 +759,16 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path);
|
|||
NSDictionary *entryInfo = [NSDictionary dictionaryByMerging:entryProperties with:entryMetadata];
|
||||
|
||||
[weakLock lock];
|
||||
@autoreleasepool {
|
||||
entryInfo = [weakDataStore coalesceEntryInfo:entryInfo];
|
||||
}
|
||||
[weakArray addObject:key];
|
||||
[weakArray addObject:entryInfo];
|
||||
[uniquePathsEntries setObject:[[NSMutableArray alloc] init] forKey:key];
|
||||
progress += progressstep;
|
||||
[self setProgressJobStatus:progress];
|
||||
[weakLock unlock];
|
||||
}
|
||||
}];
|
||||
|
||||
[queue addOperation:op];
|
||||
|
|
|
@ -562,6 +562,7 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va
|
|||
}
|
||||
tag = NULL;
|
||||
while((tag = av_dict_get(metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
|
||||
@autoreleasepool {
|
||||
if(!strcasecmp(tag->key, "streamtitle")) {
|
||||
NSString *artistTitle = guess_encoding_of_string(tag->value);
|
||||
NSArray *splitValues = [artistTitle componentsSeparatedByString:@" - "];
|
||||
|
@ -634,11 +635,13 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class sourceClass = [source class];
|
||||
if([sourceClass isEqual:NSClassFromString(@"HTTPSource")]) {
|
||||
HTTPSource *httpSource = (HTTPSource *)source;
|
||||
if([httpSource hasMetadata]) {
|
||||
@autoreleasepool {
|
||||
NSDictionary *metadata = [httpSource metadata];
|
||||
NSString *_genre = [metadata valueForKey:@"genre"];
|
||||
NSString *_album = [metadata valueForKey:@"album"];
|
||||
|
@ -659,9 +662,12 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(![_metaDict isEqualToDictionary:metaDict]) {
|
||||
@autoreleasepool {
|
||||
metaDict = _metaDict;
|
||||
}
|
||||
if(![source seekable]) {
|
||||
[self willChangeValueForKey:@"metadata"];
|
||||
[self didChangeValueForKey:@"metadata"];
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
83747C4A2862DCF40021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = "<group>"; };
|
||||
8384912D180816C900E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
|
||||
83AA660A27B7DAE40098D4B8 /* cuesheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = cuesheet.m; sourceTree = "<group>"; };
|
||||
83C70A392ACC32FB004B60E4 /* RedundantPlaylistDataStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RedundantPlaylistDataStore.h; path = ../../Utils/RedundantPlaylistDataStore.h; sourceTree = "<group>"; };
|
||||
8D5B49B6048680CD000E48DA /* Flac.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Flac.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
|
||||
|
@ -93,6 +94,7 @@
|
|||
08FB77AFFE84173DC02AAC07 /* Classes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
83C70A392ACC32FB004B60E4 /* RedundantPlaylistDataStore.h */,
|
||||
834A42B4287AF7AA00EB9D9B /* AudioChunk.h */,
|
||||
8301C145287805F500651A6E /* NSDictionary+Merge.h */,
|
||||
8301C146287805F500651A6E /* NSDictionary+Merge.m */,
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#import "Plugin.h"
|
||||
|
||||
#import "RedundantPlaylistDataStore.h"
|
||||
|
||||
@interface FlacDecoder : NSObject <CogDecoder> {
|
||||
FLAC__StreamDecoder *decoder;
|
||||
void *blockBuffer;
|
||||
|
@ -42,6 +44,8 @@
|
|||
|
||||
BOOL cuesheetFound;
|
||||
NSString *cuesheet;
|
||||
|
||||
RedundantPlaylistDataStore *dataStore;
|
||||
}
|
||||
|
||||
- (void)setSource:(id<CogSource>)s;
|
||||
|
|
|
@ -210,6 +210,7 @@ void MetadataCallback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMeta
|
|||
if(metadata->type == FLAC__METADATA_TYPE_CUESHEET && !flacDecoder->cuesheetFound) {
|
||||
flacDecoder->cuesheetFound = YES;
|
||||
|
||||
@autoreleasepool {
|
||||
NSString *_cuesheet;
|
||||
grabbag__cuesheet_emit(&_cuesheet, metadata, [[NSString stringWithFormat:@"\"%@\"", [[[flacDecoder->source url] path] lastPathComponent]] UTF8String]);
|
||||
|
||||
|
@ -221,6 +222,7 @@ void MetadataCallback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMeta
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(metadata->type == FLAC__METADATA_TYPE_PICTURE) {
|
||||
NSData *_albumArt = [NSData dataWithBytes:metadata->data.picture.data length:metadata->data.picture.data_length];
|
||||
|
@ -241,11 +243,14 @@ void MetadataCallback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMeta
|
|||
char *_name;
|
||||
char *_value;
|
||||
if(FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(vorbis_comment->comments[i], &_name, &_value)) {
|
||||
@autoreleasepool {
|
||||
NSString *name = guess_encoding_of_string(_name);
|
||||
NSString *value = guess_encoding_of_string(_value);
|
||||
free(_name);
|
||||
free(_value);
|
||||
name = [name lowercaseString];
|
||||
name = [flacDecoder->dataStore coalesceString:name];
|
||||
value = [flacDecoder->dataStore coalesceString:value];
|
||||
if([name isEqualToString:@"cuesheet"]) {
|
||||
_cuesheet = value;
|
||||
flacDecoder->cuesheetFound = YES;
|
||||
|
@ -263,6 +268,7 @@ void MetadataCallback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMeta
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(![_metaDict isEqualToDictionary:flacDecoder->metaDict] ||
|
||||
![_cuesheet isEqualToString:flacDecoder->cuesheet]) {
|
||||
|
@ -308,6 +314,9 @@ void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorS
|
|||
cuesheetFound = NO;
|
||||
cuesheet = @"";
|
||||
|
||||
id dataStoreClass = NSClassFromString(@"RedundantPlaylistDataStore");
|
||||
dataStore = [[dataStoreClass alloc] init];
|
||||
|
||||
decoder = FLAC__stream_decoder_new();
|
||||
if(decoder == NULL)
|
||||
return NO;
|
||||
|
|
|
@ -61,6 +61,7 @@ static size_t http_curl_write_wrapper(HTTPSource *fp, void *ptr, size_t size) {
|
|||
|
||||
static int http_parse_shoutcast_meta(HTTPSource *fp, const char *meta, size_t size) {
|
||||
// DLog (@"reading %d bytes of metadata\n", size);
|
||||
@autoreleasepool {
|
||||
DLog(@"%s", meta);
|
||||
const char *e = meta + size;
|
||||
const char strtitle[] = "StreamTitle='";
|
||||
|
@ -126,6 +127,7 @@ static int http_parse_shoutcast_meta(HTTPSource *fp, const char *meta, size_t si
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static const uint8_t *parse_header(const uint8_t *p, const uint8_t *e, uint8_t *key, int keysize, uint8_t *value, int valuesize) {
|
||||
size_t sz; // will hold length of extracted string
|
||||
|
@ -205,6 +207,7 @@ static size_t http_content_header_handler_int(void *ptr, size_t size, void *stre
|
|||
while(p < end && (*p == 0x0d || *p == 0x0a)) {
|
||||
p++;
|
||||
}
|
||||
@autoreleasepool {
|
||||
p = parse_header(p, end, key, sizeof(key), value, sizeof(value));
|
||||
DLog(@"%skey=%s value=%s\n", fp->icyheader ? "[icy] " : "", key, value);
|
||||
if(!strcasecmp((char *)key, "Content-Type")) {
|
||||
|
@ -227,6 +230,7 @@ static size_t http_content_header_handler_int(void *ptr, size_t size, void *stre
|
|||
fp->album = guess_encoding_of_string((const char *)value);
|
||||
fp->gotmetadata = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// for icy streams, reset length
|
||||
if(!strncasecmp((char *)key, "icy-", 4)) {
|
||||
|
|
|
@ -74,6 +74,7 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va
|
|||
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
||||
|
||||
for(size_t i = 0; i < metadata.get_count(); ++i) {
|
||||
@autoreleasepool {
|
||||
const midi_meta_data_item &item = metadata[i];
|
||||
NSString *name = [guess_encoding_of_string(item.m_name.c_str()) lowercaseString];
|
||||
if(![name isEqualToString:@"type"]) {
|
||||
|
@ -82,12 +83,15 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va
|
|||
setDictionary(dict, name, guess_encoding_of_string(item.m_value.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> albumArt;
|
||||
|
||||
if(metadata.get_bitmap(albumArt)) {
|
||||
@autoreleasepool {
|
||||
[dict setObject:[NSData dataWithBytes:&albumArt[0] length:albumArt.size()] forKey:@"albumArt"];
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va
|
|||
std::vector<std::string> keys = mod->get_metadata_keys();
|
||||
|
||||
for(std::vector<std::string>::iterator key = keys.begin(); key != keys.end(); ++key) {
|
||||
@autoreleasepool {
|
||||
NSString *tag = guess_encoding_of_string((*key).c_str());
|
||||
NSString *value = guess_encoding_of_string(mod->get_metadata(*key).c_str());
|
||||
if(*key == "type")
|
||||
|
@ -79,6 +80,7 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va
|
|||
setDictionary(dict, tag, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete mod;
|
||||
|
||||
|
|
|
@ -154,6 +154,7 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va
|
|||
FLAC__StreamMetadata_VorbisComment_Entry entry = { .entry = (FLAC__byte *)tags->user_comments[i], .length = tags->comment_lengths[i] };
|
||||
char *name, *value;
|
||||
if(FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(entry, &name, &value)) {
|
||||
@autoreleasepool {
|
||||
NSString *tagName = guess_encoding_of_string(name);
|
||||
free(name);
|
||||
|
||||
|
@ -180,11 +181,14 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va
|
|||
free(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(![_albumArt isEqualToData:albumArt] ||
|
||||
![_metaDict isEqualToDictionary:metaDict]) {
|
||||
@autoreleasepool {
|
||||
metaDict = _metaDict;
|
||||
albumArt = _albumArt;
|
||||
}
|
||||
|
||||
if(![source seekable]) {
|
||||
[self willChangeValueForKey:@"metadata"];
|
||||
|
@ -203,6 +207,7 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va
|
|||
if([sourceClass isEqual:NSClassFromString(@"HTTPSource")]) {
|
||||
HTTPSource *httpSource = (HTTPSource *)source;
|
||||
if([httpSource hasMetadata]) {
|
||||
@autoreleasepool {
|
||||
NSDictionary *metadata = [httpSource metadata];
|
||||
NSString *_genre = [metadata valueForKey:@"genre"];
|
||||
NSString *_album = [metadata valueForKey:@"album"];
|
||||
|
@ -223,9 +228,12 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(![_icyMetaDict isEqualToDictionary:icyMetaDict]) {
|
||||
@autoreleasepool {
|
||||
icyMetaDict = _icyMetaDict;
|
||||
}
|
||||
[self willChangeValueForKey:@"metadata"];
|
||||
[self didChangeValueForKey:@"metadata"];
|
||||
}
|
||||
|
|
|
@ -134,6 +134,7 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va
|
|||
FLAC__StreamMetadata_VorbisComment_Entry entry = { .entry = (FLAC__byte *)tags->user_comments[i], .length = tags->comment_lengths[i] };
|
||||
char *name, *value;
|
||||
if(FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(entry, &name, &value)) {
|
||||
@autoreleasepool {
|
||||
NSString *tagName = guess_encoding_of_string(name);
|
||||
free(name);
|
||||
|
||||
|
@ -157,11 +158,14 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va
|
|||
free(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(![_albumArt isEqualToData:albumArt] ||
|
||||
![_metaDict isEqualToDictionary:metaDict]) {
|
||||
@autoreleasepool {
|
||||
metaDict = _metaDict;
|
||||
albumArt = _albumArt;
|
||||
}
|
||||
|
||||
if(![source seekable]) {
|
||||
[self willChangeValueForKey:@"metadata"];
|
||||
|
@ -180,6 +184,7 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va
|
|||
if([sourceClass isEqual:NSClassFromString(@"HTTPSource")]) {
|
||||
HTTPSource *httpSource = (HTTPSource *)source;
|
||||
if([httpSource hasMetadata]) {
|
||||
@autoreleasepool {
|
||||
NSDictionary *metadata = [httpSource metadata];
|
||||
NSString *_genre = [metadata valueForKey:@"genre"];
|
||||
NSString *_album = [metadata valueForKey:@"album"];
|
||||
|
@ -200,9 +205,12 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(![_icyMetaDict isEqualToDictionary:icyMetaDict]) {
|
||||
@autoreleasepool {
|
||||
icyMetaDict = _icyMetaDict;
|
||||
}
|
||||
[self willChangeValueForKey:@"metadata"];
|
||||
[self didChangeValueForKey:@"metadata"];
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
- (NSDictionary *)coalesceEntryInfo:(NSDictionary *)pe;
|
||||
- (void)reset;
|
||||
|
||||
- (NSString *)coalesceString:(NSString *)in;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
Loading…
Reference in a new issue