2
  1. I am trying to get an array of images from video. It is working well but I have a doubt that In which thread the completion handler get called.

  2. I called this method(generateCGImagesAsynchronouslyForTimes:) in new operation and I updated the UI in the completion handler. The UI get updated.

  3. But typically the UI updation doesn't happen in secondary thread?. My doubt is the completion handler called in current calling thread or main thread?

My Code is:

__block unsigned int i = 0;
AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime, CGImageRef im, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error){

    i++;
    if(result == AVAssetImageGeneratorSucceeded){

        //Create a block to save the image in disk
        NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
            NSFileManager *fileMgr = [NSFileManager defaultManager];
            NSString *documentsDirectory = [NSHomeDirectory()
                                            stringByAppendingPathComponent:@"Documents"];
            NSError *error = nil;

            //Create file path for storing the image
            NSString *videoOutputPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"VideoFrames%i.png", i]];

            //Delete if already any image exist 
            if ([fileMgr fileExistsAtPath:videoOutputPath]){
                if ([fileMgr removeItemAtPath:videoOutputPath error:&error] != YES)
                    NSLog(@"Unable to delete file: %@", [error localizedDescription]);
            }

            //Convert the CGImageRef to UIImage
            UIImage *image = [UIImage imageWithCGImage:im];//**This line gives error: EXE_BAD_ACCESS**

            //Save the image
            if(![UIImagePNGRepresentation(image) writeToFile:videoOutputPath options:NSDataWritingFileProtectionNone error:&error])
                NSLog(@"Failed to save image at path %@", videoOutputPath);
        }];

        //Add the operation to the queue
        [self.imageWritingQueue addOperation:operation];
    }
   }
};
4

2 回答 2

4

The documentation states it clearly:

Concurrent Programming with AV Foundation

Callouts from AV Foundation—invocations of blocks, key-value observers, and notification handlers—are not guaranteed to be made on any particular thread or queue. Instead, AV Foundation invokes these handlers on threads or queues on which it performs its internal tasks. You are responsible for testing whether the thread or queue on which a handler is invoked is appropriate for the tasks you want to perform. If it’s not (for example, if you want to update the user interface and the callout is not on the main thread), you must redirect the execution of your tasks to a safe thread or queue that you recognize, or that you create for the purpose.

See also: AV Foundation Programming Guide

Edit:

The problem is, that you don't retain/release the CGImageRef image provided in parameter im since you use it in a NSBlockOperation later. You need to retain it outside the block (from the NSBlockOperation) before you invoke the block, and release it before the block returns (within the block).

于 2014-02-01T09:57:24.477 回答
2

IIRC,是的。但是您可以对其进行测试,并且为了安全起见,您可以将代码包装在一个将其分派到主线程的块中。

一般来说,回调必须返回到主线程,因为如果它不是主线程,则不能保证它启动的线程正在运行一个运行循环。

除非您安排与其他操作(依赖项)相关的创建块,否则我不确定该块给您带来什么优势,因为图像加载是异步的,因此您可以从主线程触发它而不会阻塞任何东西。


根据您的评论,在这种情况下,您应该切换代码。在为您提供图像的完成块内创建块操作。将每个块操作添加到您的队列中。块操作只是获取图像并将其保存到磁盘。

于 2014-02-01T09:05:18.457 回答