I have a function to read H264 video files. I want to use it to sequentially read many video files. It seems to work for a files (random time), fails partially for a few files (reads some and not all the frames) and then completely fails (reading 0 frames). I tested this by looping over the same video file and so this uncertainty is strange.
The error message I get is:
Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo=0x105d07480 {NSLocalizedFailureReason=An unknown error occurred (-6662), NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x100159350 "The operation couldn’t be completed. (OSStatus error -6662.)"}
I use ARC and OSX Lion. Any help is much appreciated:
void uncompressMovie(NSString *moviePath) {
AVAsset *asset = [AVAsset assetWithURL:[NSURL fileURLWithPath:moviePath]];
NSArray* video_tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
AVAssetTrack *video_track = [video_tracks objectAtIndex:0];
// Decompress to ARGB with the asset reader
NSDictionary *decompressionVideoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32ARGB], (id)kCVPixelBufferPixelFormatTypeKey,
[NSDictionary dictionary], (id)kCVPixelBufferIOSurfacePropertiesKey,
nil];
AVAssetReaderTrackOutput *asset_reader_output = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:video_track outputSettings:decompressionVideoSettings];
NSError *error = [[NSError alloc] init];
AVAssetReader *asset_reader = [[AVAssetReader alloc] initWithAsset:asset error:&error];
if ([asset_reader canAddOutput:asset_reader_output]) {
[asset_reader addOutput:asset_reader_output];
if ([asset_reader startReading] == YES) {
int count = 0;
while ( [asset_reader status]==AVAssetReaderStatusReading ) {
sampleBuffer = [asset_reader_output copyNextSampleBuffer];
if (sampleBuffer == NULL) {
if ([asset_reader status] == AVAssetReaderStatusFailed)
break;
else
continue;
}
count++;
// Will do some work here
CFRelease(sampleBuffer);
}
if (count == 0) {
NSLog(@"I am doomed %@", [asset_reader error]);
exit(1);
}
NSLog(@"Processed %d frames from %@", count, moviePath);
} else
NSLog(@"Couldn't start");
}
if ([asset_reader status] != AVAssetReaderStatusCompleted)
[asset_reader cancelReading];
// unlink([moviePath UTF8String]);
}
It might be interesting to try to add CMSampleBufferMakeDataReady() after the call to copyNextSampleBuffer. This is typically called when you are going to use the data but I am wondering of some of the decoders need this to be called to properly handle subsequent blocks.
You should also try profiling this in Instruments and see if memory is growing while in this loop. It looks like you are properly calling CFRelease on the sample buffer but there might be some large autoreleased objects in the AVAssetReaderOutput that are building up. If it does look like memory is building up then you might try to put an NSAutoreleasePool inside the loop to clean this up.