1

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]);
}
  • The question states that you are having trouble reading multiple video files but the description and sample code do not seem to deal with multiple files. Unless I missed something it seems like you should improve the language of the question. – Jon Steinmetz Jan 23 '12 at 03:46
  • I've changes it to show that I meant reading files back to back rather than many files at the same time – Surendar Chandra Jan 23 '12 at 18:45

1 Answers1

0

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.

Jon Steinmetz
  • 4,104
  • 1
  • 23
  • 21
  • CMSampleBufferMakeDataReady() doesn't make any difference. Also, the memory does not grow while in this loop. OTOH, VTDecoderXPCService does seem to momentarily become huge (> 2 GB for virtual memory) and then its gone. – Surendar Chandra Jan 23 '12 at 09:25
  • OK, then you might try looking at the avexport sample at https://developer.apple.com/library/mac/#samplecode/avexporter/Introduction/Intro.html#//apple_ref/doc/uid/DTS40011051 and see what differences there are in your code. You could also try running the same movie through that sample code and see if it has the same issue. There are also other AVFoundation samples on the Mac developer sample code page. – Jon Steinmetz Jan 23 '12 at 16:29
  • Forget that example, try AVReaderWriter sample at https://developer.apple.com/library/mac/#samplecode/ReaderWriter/Introduction/Intro.html#//apple_ref/doc/uid/DTS40011124 instead. – Jon Steinmetz Jan 23 '12 at 16:41
  • My code looks quite similar to AVReaderWriter. I've tried different things and none seem to matter. For example, I inserted a delay in the while loop, opened 'n' different files (where each file is a copy of the same movie), opened longer movies and they all seem to fail completely after about 40 invocations. Before the end, some frames are lost but then it recovered for the remaining frames in the movie. For the outputSettings of AVAssetReaderTrackOutput, if I set it to nil, then it runs lot longer (over 1000 invocations). This gives me the compressed frames and so is not that useful. – Surendar Chandra Jan 23 '12 at 23:25
  • BTW, when I run this same code on a iPhone 4S running iOS 5.0, it again fails completely after a few invocations!! – Surendar Chandra Jan 23 '12 at 23:26
  • I "fixed" it by turning off ARC, throwing a NSAutoReleasePool around the code. Either way, my code doesn't seem to leak any memory (according to the profiler). But, turning off ARC keeps the VTDecoderXPCService process from ballooning up to 2 GB (now it only goes to about 256 MB) or so. The funny part is that, if I used 'AVAssetReader *asset_reader = [AVAssetReader assetReaderWithAsset:asset error:&error]; ', I don't have to explicitly call release anywhere in my code either. – Surendar Chandra Jan 26 '12 at 19:28
  • Interesting. So it was the case that some process was leaking memory. There are auto release pools in ARC, see http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSAutoreleasePool_Class/Reference/Reference.html.It would be interesting to see if turning off ARC was really necessary to solve this problem. Glad you were able to solve it. – Jon Steinmetz Jan 27 '12 at 03:23