Sergey_Hot_UA
Sergey_Hot_UA

Reputation: 31

Extract thumbnail from video url in threads

I have a problem with my MPMoviePlayer in another thread, using (Grand Central Dispatch). I want to appeal to the video by url, cut 5-th frame and return the picture. In the emulator works fine, but on a real device - fall. What's the problem here? maybe it only works in the main thread?

NSURL* url = [NSURL URLWithString:filePath];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void)
{
  MPMoviePlayerController* moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:url];
  moviePlayer.shouldAutoplay = NO;
  UIImage* thumbnail = [moviePlayer thumbnailImageAtTime:5 timeOption:MPMovieTimeOptionNearestKeyFrame];

  dispatch_async(dispatch_get_main_queue(), ^(void)
  {
     [[Singleton sharedSingleton].imageCache setValue:thumbnail forKey:filePath];
     [cell.presentationViewOutlet setImage:thumbnail];;
  });
});

Now, I try to use another method but it also - works well on the simulator and on a real device is not displayed. Sometimes returns imageRef = (null), sometimes imageRef = <CGImage 0x1766dd20>.

EDIT:

NSURL* url = [NSURL URLWithString:filePath];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void)
{
    AVAsset *asset = [AVAsset assetWithURL:videoURL];
    AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc]initWithAsset:asset];
    imageGenerator.appliesPreferredTrackTransform = TRUE;
    CMTime time = CMTimeMakeWithSeconds(1, 1);
    NSError *err = NULL;
    CGImageRef imageRef = [imageGenerator copyCGImageAtTime:time actualTime:NULL error:&err];
    dispatch_async(dispatch_get_main_queue(), ^(void)
    {
        NSLog(@"imageRef = %@", imageRef);
        UIImage* image = [UIImage imageWithCGImage:imageRef];
        if (image != nil)
        {
            NSLog(@"image != nil");
            [view setImage:image];
            NSString* videoURLString = [videoURL absoluteString];
            [[Singleton sharedSingleton].imageCache setValue:image forKey:videoURLString];
            CGImageRelease(imageRef);
        }
        else
        {
            NSLog(@"err = %@", err);
        }
    });
});

Error:

If imageRef = (null) show err = Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo=0x156c1a50 {NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x155b29a0 "The operation couldn’t be completed. (OSStatus error -12792.)", NSLocalizedFailureReason=An unknown error occurred (-12792)}

Upvotes: 3

Views: 927

Answers (2)

box86rowh
box86rowh

Reputation: 3415

Does it work better if you move the imageref inside the async section? Like:

NSURL* url = [NSURL URLWithString:filePath];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void)
{
    AVAsset *asset = [AVAsset assetWithURL:videoURL];
    AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc]initWithAsset:asset];
    imageGenerator.appliesPreferredTrackTransform = TRUE;
    CMTime time = CMTimeMakeWithSeconds(1, 1);
    dispatch_async(dispatch_get_main_queue(), ^(void)
    {
        NSError *err = NULL;
        CGImageRef imageRef = [imageGenerator copyCGImageAtTime:time actualTime:NULL error:&err];
        NSLog(@"imageRef = %@", imageRef);
        UIImage* image = [UIImage imageWithCGImage:imageRef];
        if (image != nil)
        {
            NSLog(@"image != nil");
            [view setImage:image];
            NSString* videoURLString = [videoURL absoluteString];
            [[Singleton sharedSingleton].imageCache setValue:image forKey:videoURLString];
            CGImageRelease(imageRef);
        }
        else
        {
            NSLog(@"err = %@", err);
        }
    });
});

Upvotes: 0

Duncan C
Duncan C

Reputation: 131491

An MPMoviePlayerController is a user interface controller. As such it is almost certainly not thread-safe. The docs don't say specifically, but I would bet money that it's not.

Upvotes: 1

Related Questions