Search code examples
iosobjective-cuitextfieldavplayerlayer

Magnifying glass appearing in a wrong way when I'm using AVPlayerLayer


I am using an AVPlayerLayer to play video in the background of my UIViewController instance. When I launched my app on the iPhone I noticed that magnifying glass appearing in a wrong way. Video specifications: H.264, AAC, 640x360, MOV.

enter image description here

The background inside magnifying glass drawing without my video sublayer. Only subviews (buttons, text fields, etc.) are drawing inside my magnifying glass.

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor yellowColor];

    NSURL *videoURL = [[NSBundle mainBundle] URLForResource:@"bf4" withExtension:@"mov"];
    AVAsset *asset = [AVAsset assetWithURL:videoURL];
    AVPlayerItem *item = [AVPlayerItem playerItemWithAsset:asset];
    AVPlayer *player = [AVPlayer playerWithPlayerItem:item];
    player.actionAtItemEnd = AVPlayerActionAtItemEndNone;

    UIView *container = [[UIView alloc] initWithFrame:self.view.bounds];
    container.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    [self.view addSubview:container];

    AVPlayerLayer *layer = [AVPlayerLayer playerLayerWithPlayer:player];
    [container.layer addSublayer:layer];
    layer.frame = container.bounds;
    layer.videoGravity = AVLayerVideoGravityResizeAspectFill;

    [self.view bringSubviewToFront:self.textField];        
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [player play];
    });
}

Does anyone know how to prevent this?


Solution

  • The only one solution I figured out is to:

    1. Put UIImageView below container view:

      self.containerThumbnail = [[UIImageView alloc] initWithFrame:self.view.bounds];
      self.containerThumbnail.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
      self.containerThumbnail.backgroundColor = [UIColor clearColor];
      [self.view insertSubview:self.containerThumbnail belowSubview:container];
      
    2. Become a time observer to the media player:

       CMTime bgInterval = CMTimeMake(1, 10);
      __weak __typeof(self)weakSelf = self;
      [player addPeriodicTimeObserverForInterval:bgInterval 
                                           queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)
                                      usingBlock:^(CMTime time)
      {
          [weakSelf locateThumbnail:time];
      }];
      
    3. Put snapshots inside your UIImageView:

      - (void)locateThumbnail:(CMTime)time
      {
          __weak __typeof(self)weakSelf = self;
          dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {
              CGImageRef imageRef = [weakSelf.imageGenerator copyCGImageAtTime:time actualTime:NULL error:NULL];
              UIImage *image = [UIImage imageWithCGImage:imageRef];
              CGImageRelease(imageRef);
              __strong __typeof(weakSelf)strongSelf = weakSelf;
              dispatch_async(dispatch_get_main_queue(), ^(void) {
                  strongSelf.containerThumbnail.image = image;
              });
          });
      }
      

    The property imageGenerator is of type AVAssetImageGenerator:

    imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    imageGenerator.appliesPreferredTrackTransform = YES;
    

    N.B. Snapshots updates in the background and because of this frames lag behind the video. But this is better than nothing.