ymotov
ymotov

Reputation: 1489

When app is in the background AVAssetReader would fail to initialize properly so can't start reading

While initializing AVAssetReader I noticed that about 20% of the time it fails to start reading. Below is the code snippet which ends where the code stops 20% of time. The 'startReading' call returns NO.

Anybody know why that may be happening? Am I missing anything here? I should also note that this code gets executed quite often. It could be about 10 videos that are being processed sequentially one after another. So about 2 or 3 videos would fail to process because of the 'startReading' call would return NO.


Update: with more testing I found out that it fails all the time when the app goes into the background. So the AVAssetReader is not able to 'startReading' while the app is in the background. Is there any way to make it work while the app is in the background??

NSError *error = nil;
NSURL *srcVideo = [NSURL fileURLWithPath:[video getVideoLocation]];

NSDictionary *opts =
    [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:yes]
                                forKey:@"AVURLAssetPreferPreciseDurationAndTimingKey"];

AVAsset *avAsset = [[AVURLAsset alloc] initWithURL:srcVideo options:opts];

// Get the video track but first check for existence of track
if( [[avAsset tracksWithMediaType:AVMediaTypeVideo] count] == 0 ) {
    DLog(@"Error - no video tracks in asset");
    return;
}

AVAssetTrack *videoTrack = [[avAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];

// Set up the reading of the video track
AVAssetReader *reader = [[AVAssetReader alloc] initWithAsset:avAsset
                                                       error:&error];
NSDictionary *videoOptions =
    [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA]
                                forKey:(id)kCVPixelBufferPixelFormatTypeKey];

AVAssetReaderTrackOutput *assetReaderVideoOutput =
    [[AVAssetReaderTrackOutput alloc] initWithTrack:videoTrack
                                     outputSettings:videoOptions];

[reader addOutput:assetReaderVideoOutput];

if( ![reader startReading] ) {
    DLog(@"Error - failed to start reading video");

    DLog(@"Happens about 20% of time...");

    return;
}

Upvotes: 3

Views: 1316

Answers (1)

jlw
jlw

Reputation: 3216

You can request time to run in the background. (confirmed on iOS8, and might work on earlier iOS as well.)

Add a property for a UIBackgroundTaskIdentifier.

@property (nonatomic) UIBackgroundTaskIdentifier bgIdentifier;

When your app will enter the background, begin a background task.

self.bgIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^ {
      NSLog(@"background task expired.");
      [[UIApplication sharedApplication] endBackgroundTask:self.bgIdentifier];
      self.bgIdentifier = UIBackgroundTaskInvalid;
}];

Do some work. (Your asset reader should now be reading in the background).

End the task when you've finished, so that the system can suspend your app.

[[UIApplication sharedApplication] endBackgroundTask:self.bgIdentifier];
self.bgIdentifier = UIBackgroundTaskInvalid;

Keep in mind you will only get a few minutes' time using this method.

Upvotes: 1

Related Questions