How to manage GPUImage movieFile Processing in background? - ios

I have implemented GPUImage library to apply filters in existing videos, Now issue is that the application is crash when I lock device, I Have also set BOOL variable to get application current state, Bun unfortunately resignActive call after application crash. The crash happen in this line of code.
[self.context presentRenderbuffer:GL_RENDERBUFFER];
Can you please suggest me what is best way to deal with this.

-(void)viewWillAppear:(BOOL)animated{
[[NSNotificationCenter defaultCenter]addObserver:self
selector:#selector(EnterBackground:)
name:UIApplicationWillResignActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self
selector:#selector(DidBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
}
- (void)EnterBackground:(NSNotification*)notification{
NSLog(#"Enter in background");
[self.movieFile endProcessing];
[self.filter removeAllTargets];
[self.movieFile removeAllTargets];
}
- (void)DidBecomeActive:(NSNotification*)notification{
[_movieFile startProcessing];
}
Don't forget to remove observer in viewWillDisappear

Related

AVCaptureSession didFinishRecordingToOutputFileAtURL: not called when interruption (e.g. control center) occurs

I sunk a ton of time into this so I thought I'd repost.
I am using AVCaptureSession with AVCaptureMovieFileOutput to allow users to record video while providing a pause recording button.
This works great until the app is backgrounded, the control center is lifted, or an interruption such as alarm/call occurs. Depending on the device hardware, we see a different kind of bug.
On older devices, the capture session will fail to start recording after such an event, even if we re-initialize the captureSession.
On newer devices, the existing video, if it exists, will be fine, but any subsequent attempts to resume recording will either fail outright, or fail to record audio.
In the first situation, didStartRecordingToOutputFileAtURL: will never get called. In the second situation, didStartRecordingToOutputFileAtURL: will be called, but didFinishRecordingToOutputFileAtURL: will not.
Currently, we are doing this:
- (void)viewDidLoad {
[self initializeCaptureSessionAndOutputData]; //based on your requirements
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.captureSession startRunning];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(interruptionDidOccur)
name:UIApplicationWillResignActiveNotification
object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.captureSession stopRunning];
[[NSNotificationCenter] defaultCenter] removeObserver:self];
}
- (void)interruptionDidOccur {
[self.movieFileOutput stopRecording]; //expect didFinishRecordingToOutputFileAtURL to be called
}
The problem is undocumented, but solvable. In addition to calling
[self.captureSession stopRunning]
in viewWillDisappear: it must be called whenever a UIApplicationWillResignActiveNotification notification is fired too. Here is the sample code:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self handleAppReturn];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(becameActive)
name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(resignActive)
name:UIApplicationWillResignActiveNotification
object:nil];
}
- (void)resignActive {
[self.videoCameraManager.captureSession stopRunning];
if (!self.isPaused) {
[self pauseVideo];
}
}
- (void)becameActive {
[self.videoCameraManager.captureSession startRunning];
}

MPMoviePlayerController not playing video on iOS7

I have a basic MPMoviePlayerController code that plays videos. It works flawlessly on iOS8, however it freezes the app on iOS7.
Here's the code:
- (void)playURL:(NSURL *)URL fromView:(UIView *)view
{
NSParameterAssert(URL);
NSParameterAssert(view);
NSParameterAssert(view.superview);
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:URL];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayBackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:self.moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(movieControllerDidCollapse:) name:MPMoviePlayerDidExitFullscreenNotification object:self.moviePlayer];
self.moviePlayer.shouldAutoplay = YES;
self.moviePlayer.view.frame = view.frame;
[view.superview addSubview:self.moviePlayer.view];
[self.moviePlayer setFullscreen:YES animated:YES];
}
- (void)moviePlayBackDidFinish:(NSNotification *)notification
{
[self.moviePlayer setFullscreen:NO animated:YES];
}
- (void)movieControllerDidCollapse:(NSNotification *)note
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:self.moviePlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerDidExitFullscreenNotification object:self.moviePlayer];
[self.moviePlayer.view removeFromSuperview];
self.moviePlayer = nil;
}
I have the same code running in my other apps, and it works well, but in this particular app it gets iOS7 frozen. When launched, it starts spitting numerous CGContext errors in a loop, saying that the context is 0x0. I tried to create a dummy CGContext and got rid of errors, but in this case it spins up the CPU to 100%, presumably because it is trying to draw things in the context that has a wrong scope or smth.
I also tried to use MPMoviePlayerViewController instead of MPMoviePlayerController, but it does the same thing. Modal presentation animation does not even appear.
I also searched my project for some UIAppearance setters and method swizzlings, but found nothing that could potentially cause this behavior.
I ran Time Profiler on this app, and the problem has something to do with drawing Progress Sliders. I have no progress view subclasses or categories in my project. The Instruments profiling looks like this: Instruments output. (Sorry, can't include direct image due to reputation lack).
I also tried running a clean project with the whole set of my cocoapods and it works perfectly in a different project.
OK, there problem was with one of my categories. I defined a method [UIImage imageNamed:inBundle:] which apparently conflicted with one of the private APIs. But I got no warnings what so ever. Renaming the method solved the problem.

How to calculate the time in background and make SKAction jump to the time after

I am working on an app based on sprite kit. I know that all actions will be paused while the app is in background. However, I am doing the fading color thing so I want to calculate the time while the app is in background and make the SKAction which is the fading action jump the time after so that it doesn't look like the color is not changing while the app is in background. So can someone give me some detailed walkthrough about how to do so? Thanks so much!!
EDITED after rmaddy's suggestion.
In the View Controller that gets opened when the app becomes active, you can directly subscribe to UIApplicationDidBecomeActiveNotification and UIApplicationWillResignActiveNotification to get notified when the app enters or exits foreground.
#property(nonatomic) NSDate *enterBackground;
#property (nonatomic) NSTimeInterval enterForeground;
-(void)viewDidLoad{
[super viewDidLoad];
[self subscribeToNotifications];
}
-(void)viewWillDisappear:(BOOL)animated{
[self unsubscribeFromNotifications];
}
-(void)subscribeToNotifications{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appEntersBackground) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appEntersForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
}
-(void)unsubscribeFromNotifications{
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];
}
Now that your ViewController knows when the app is entering and exiting foreground, add the methods to start and stop the timer.
-(void)appEntersBackground{
self. enterBackground = [NSDate date];
}
-(void)appEntersForeground{
self.enterForeground = [[NSDate date]timeIntervalSinceDate:self.enterBackground];
NSLog(#"%f",self.enterForeground);
}
The time spent in background can be accessed by self.enterForeground

iOS NSNotificationCenter Observer not being removed

I have the following code within AppDelegate. The purpose being to create a couple of observers, and then call some code. Once that code completes it then posts a notification, and the observer should then remove both observers and call the completion handler.
My issue is that it appears that the observers are not being removed as I expected. The notification is posted, and the NSLog entry is written to console, so I know that the observer is working. However, on the second time of calling, the NSLog is called twice, third time three times etc.
My thoughts are that this is to do with the removal being within the block of code that is running from the observer, however, I am unsure how I can resolve this (if indeed this is what the issue is).
Could someone be so kind as to explain how I can achieve this?
Thanks.
-(void) application:(UIApplication *)application performFetchWithCompletionHandler:
(void (^)(UIBackgroundFetchResult))completionHandler {
[[NSNotificationCenter defaultCenter] addObserverForName:#"fetchDidCompleteNewData" object:nil
queue:nil usingBlock:^(NSNotification *completed) {
//Remove Observers
[[NSNotificationCenter defaultCenter] removeObserver:self
name:#"fetchDidCompleteNewData"
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:#"fetchDidCompleteNoData"
object:nil];
// Post completion
completionHandler(UIBackgroundFetchResultNewData);
NSLog(#"Background fetch completed... New Data");
}];
[[NSNotificationCenter defaultCenter] addObserverForName:#"fetchDidCompleteNoData" object:nil
queue:nil usingBlock:^(NSNotification *completed) {
//Remove Observers
[[NSNotificationCenter defaultCenter] removeObserver:self
name:#"fetchDidCompleteNoData"
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:#"fetchDidCompleteNewData"
object:nil];
//post completion
completionHandler(UIBackgroundFetchResultNoData);
NSLog(#"Background fetch completed... No New Data");
}];
GetDetails *getDetails = [[GetDetails alloc] init];
[getDetails backgroundRefresh];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
return YES;
}
You are not registering self as an object. Moreover, when the block is pushed onto the stack by addObserverForName: the method has not yet returned so the notification is nil.
Make a global object using block, eg
__block __weak id notification;
then,
notification = [[NSNotificationCenter defaultCenter] addObserverForName:#"fetchDidCompleteNewData" object:nil queue:nil usingBlock:^(NSNotification *completed) {
//Remove Observers
[[NSNotificationCenter defaultCenter] removeObserver:notification];
}];
My thoughts are that this is to do with the removal being within the
block of code that is running from the observer, however, I am unsure
how I can resolve this (if indeed this is what the issue is).
Could someone be so kind as to explain how I can achieve this?
Certainly.
You can easily test your theory by not using the addObserverForName:object:queue:usingBlock: method and instead using the addObserver:selector:name:object: method, where the selector is the name of a function you call instead of using a block.
Simply use the API guide for NSNotificationCenter for details about these methods, or in general, since you question was about what other method you could use that does not require a block statement, consulting the API is the first place to check for alternative tools within the class.

I need to send a message to a method every time my app comes back from background

I'm developing an iOS app with latest SDK.
It's a fullscreen app.
I have a method on viewWillAppear method that has to be called every time the apps comes from background.
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self setUpVideo];
}
On setUpVideo I set up AVCaptureVideoPreviewLayer because I lose the video when the apps come back from background.
As I have read, viewWillAppear isn't called when the apps come back from background and now, I don't know where to put that code.
On this question, occulus suggest to use [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(doMyLayoutStuff:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil]; but it doesn't work for me.
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(setUpVideo:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
}
Any advice?
Observe UIApplicationWillEnterForegroundNotification instead.
- (void)viewDidAppear {
[super viewDidAppear];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(enterForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
// ...
}
- (void)enterForeground:(NSNotification *)notification {
// do stuff
}
Don't call viewWillAppear: directly from the enterForeground: method. Instead move all required code to a separate method and call that from both viewWillAppear: and enterForeground:.
applicationWillEnterForeground will trigger when app comes from background
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
Additionally, you can use UIApplicationDidBecomeActiveNotification for firing some method
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(handleMethod:)
name: UIApplicationDidBecomeActiveNotification
object: [UIApplication sharedApplication]];
Try posting this notification from
- (void)applicationDidBecomeActive:(UIApplication *)application of AppDelegate(or observe corresponding notification which is better)

Resources