Fix runaway NSData (#205)

* Fix runaway NSData

Previously we were generating all the frames of the GIF and dispatching
to write the data to the disk. This presents a problem if the disk backs
up though and it can end up with theoretically every frame in memory. Instead,
generate a frame and write it one frame at a time. Slower, but prevents
this runaway memory situation.

* Early return on error, thans @rahul-malik & @timonus!
This commit is contained in:
Garrett Moon
2016-06-07 15:40:43 -07:00
parent 3f0659a6dc
commit 097e01cf15

View File

@@ -380,34 +380,41 @@ ERROR;}) \
});
}
CGImageRef frameImage = CGImageSourceCreateImageAtIndex(imageSource, frameIdx, (CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceShouldCache : (__bridge NSNumber *)kCFBooleanFalse});
if (frameImage == nil) {
NSError *frameImageError = [NSError errorWithDomain:kPINAnimatedImageErrorDomain code:PINAnimatedImageErrorImageFrameError userInfo:nil];
HANDLE_PROCESSING_ERROR(frameImageError);
break;
}
Float32 duration = durations[frameIdx];
fileDuration += duration;
NSData *frameData = (__bridge_transfer NSData *)CGDataProviderCopyData(CGImageGetDataProvider(frameImage));
NSAssert(frameData.length == width * height * kPINAnimatedImageComponentsPerPixel, @"data should be width * height * 4 bytes");
dispatch_group_async(diskGroup, diskWriteQueue, ^{
if (PROCESSING_ERROR) {
return;
}
CGImageRef frameImage = CGImageSourceCreateImageAtIndex(imageSource, frameIdx, (CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceShouldCache : (__bridge NSNumber *)kCFBooleanFalse});
if (frameImage == nil) {
NSError *frameImageError = [NSError errorWithDomain:kPINAnimatedImageErrorDomain code:PINAnimatedImageErrorImageFrameError userInfo:nil];
HANDLE_PROCESSING_ERROR(frameImageError);
return;
}
NSData *frameData = (__bridge_transfer NSData *)CGDataProviderCopyData(CGImageGetDataProvider(frameImage));
NSAssert(frameData.length == width * height * kPINAnimatedImageComponentsPerPixel, @"data should be width * height * 4 bytes");
NSError *frameWriteError = [self writeFrameToFile:fileHandle duration:duration frameData:frameData];
HANDLE_PROCESSING_ERROR(frameWriteError);
CGImageRelease(frameImage);
});
CGImageRelease(frameImage);
frameCountForFile++;
}
}
} else {
completion(NO, nil, PROCESSING_ERROR);
}
CFRelease(imageSource);
}
dispatch_group_wait(diskGroup, DISPATCH_TIME_FOREVER);
if (imageSource) {
CFRelease(imageSource);
}
//close the file handle
PINLog(@"closing last file: %@", fileHandle);