Last active
August 29, 2015 14:09
-
-
Save 0xced/dee6775974863270fbcf to your computer and use it in GitHub Desktop.
Fix for Lookback (0.6.5) crash when recording is stopped while playing a movie with a MPMoviePlayerController
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Add these options to `OTHER_LDFLAGS` if Lookback is not linked to the app. | |
| * -Wl,-U,_GFGetVersion | |
| * -Wl,-U,_OBJC_CLASS_$_GFThumbnailer2 | |
| * -Wl,-U,_OBJC_IVAR_$_GFThumbnailer2._jobs | |
| * -Wl,-U,_OBJC_IVAR_$_GFThumbnailer2._currentJob | |
| */ | |
| #import <AVFoundation/AVFoundation.h> | |
| #import <MediaPlayer/MediaPlayer.h> | |
| #import <dlfcn.h> | |
| #import <objc/runtime.h> | |
| #pragma clang diagnostic ignored "-Wdirect-ivar-access" | |
| #pragma clang diagnostic ignored "-Wobjc-interface-ivars" | |
| #pragma clang diagnostic ignored "-Wmissing-prototypes" | |
| #pragma mark - Private Lookback Interfaces | |
| __attribute__((weak_import)) extern NSString *(GFGetVersion)(void); | |
| @interface GFThumbnailerJob : NSObject | |
| - (NSURL *) url; | |
| @end | |
| __asm(".weak_reference _OBJC_IVAR_$_GFThumbnailer2._jobs"); | |
| __asm(".weak_reference _OBJC_IVAR_$_GFThumbnailer2._currentJob"); | |
| __attribute__((weak_import)) @interface GFThumbnailer2 : NSObject | |
| { | |
| @public | |
| NSMutableDictionary *_jobs; | |
| GFThumbnailerJob *_currentJob; | |
| MPMoviePlayerController *_controller; | |
| } | |
| - (void) jobFinished:(NSNotification *)notification; | |
| - (void) _performNextJob; | |
| - (void) _stopOutstandingThumbnailing; | |
| @end | |
| #pragma mark - _performNextJob Replacement | |
| /** | |
| * The original -[GFThumbnailer2 _performNextJob] method uses -[MPMoviePlayerController requestThumbnailImagesAtTimes:timeOption:] | |
| * to generate a thumbnail. For some reason, this causes a crash when another MPMoviePlayerController is already playing a movie. | |
| * | |
| * *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'movie player <MPMoviePlayerControllerNew: 0x1741f7b00> has wrong activation state (1)' | |
| * | |
| * In order to avoid this crash, the `_performNextJob` method is rewritten to use `AVAssetImageGenerator` instead. | |
| */ | |
| static void PerformNextJob(GFThumbnailer2 *self, SEL _cmd) | |
| { | |
| [self _stopOutstandingThumbnailing]; | |
| self->_currentJob = [[self->_jobs allValues] firstObject]; | |
| if (!self->_currentJob) | |
| return; | |
| NSURL *url = self->_currentJob.url; | |
| [self->_jobs removeObjectForKey:url]; | |
| AVAsset *asset = [AVAsset assetWithURL:url]; | |
| AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset]; | |
| [imageGenerator generateCGImagesAsynchronouslyForTimes:@[ @3.0 ] completionHandler:^(CMTime requestedTime, CGImageRef imageRef, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error) { | |
| NSMutableDictionary *userInfo = [NSMutableDictionary new]; | |
| UIImage *image = [UIImage imageWithCGImage:imageRef]; | |
| if (image) | |
| userInfo[MPMoviePlayerThumbnailImageKey] = image; | |
| if (error) | |
| userInfo[MPMoviePlayerThumbnailErrorKey] = error; | |
| NSNotification *notification = [[NSNotification alloc] initWithName:MPMoviePlayerThumbnailImageRequestDidFinishNotification object:nil userInfo:[userInfo copy]]; | |
| [self performSelectorOnMainThread:@selector(jobFinished:) withObject:notification waitUntilDone:NO]; | |
| }]; | |
| } | |
| @implementation GFThumbnailer2 (FixLookbackMPMoviePlayerControllerCrash) | |
| + (void) load | |
| { | |
| @autoreleasepool | |
| { | |
| if (!GFGetVersion) | |
| { | |
| NSLog(@"Could not fix Lookback/MPMoviePlayerController crash because the GFGetVersion function was not found."); | |
| return; | |
| } | |
| NSSet *supportedVersions = [NSSet setWithArray:@[ @"0.6.5" ]]; | |
| NSString *lookbackVersion = GFGetVersion(); | |
| if (![supportedVersions containsObject:lookbackVersion]) | |
| { | |
| NSLog(@"Could not fix Lookback/MPMoviePlayerController crash because version %@ is not supported.", lookbackVersion); | |
| return; | |
| } | |
| Method _performNextJob = class_getInstanceMethod(self, @selector(_performNextJob)); | |
| method_setImplementation(_performNextJob, (IMP)PerformNextJob); | |
| } | |
| } | |
| @end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment