4

I am facing memory leaks when we play a video and return back to the parent window. See the screenshot below of readings from allocations tool.enter image description here Every time, when I pop the view controller (showing video) there are some objects related to AVFoundation holding the memory. Interestingly the responsible library of all these objects is AVFoundation. None of the increase in memory is due to objects created in the APP. It is very highly unlikely that there is some problem with such a popular framework. I saw a few examples of AVPlayerViewController over the web but they seem to have the same problem.

Does anyone have any idea what/where is the problem? If anyone wants to replicate this then he can download any of the 2 projects given above. You have to make minor changes in the storyboard for creating root view controller with the navigation controller.

  • http://www.modejong.com/blog/post13_iOS8_SunSpot/index.html
  • https://github.com/coolioxlr/PageView-AVPlayer

    This is how I am clearing the memory:

           -(void) dealloc{
    
               [self clearCurrentVideo];
    
            }
    
       -(void)clearCurrentVideo {
           [_playerItem removeObserver:self forKeyPath:@"status"];        
           [_currentVideoPlayerViewController.player removeObserver:self forKeyPath:@"rate"];
           [_currentVideoPlayerViewController.player pause];
           _currentVideoPlayerViewController.delegate=nil;
           _currentVideoPlayerViewController.player=nil;
          _playerItem=nil;
          _currentVideoPlayerViewController = nil;
       }
    

This is how I load the asset for videos:

 -(void)playtheAsset:(AVAsset *)asset{
[asset loadValuesAsynchronouslyForKeys:@[@"playable"] completionHandler:
                 ^{
                     dispatch_async( dispatch_get_main_queue(),
                                    ^{

                                        [self loadTheAsset:asset withKeys:@[@"playable"]];
                                    });
                 }];
}


- (void)loadTheAsset:(AVAsset *)asset withKeys:(NSArray *)requestedKeys{

    /* Make sure that the value of each key has loaded successfully. */
    for (NSString *thisKey in requestedKeys)
    {
        NSError *error = nil;
        AVKeyValueStatus keyStatus = [asset statusOfValueForKey:thisKey error:&error];
        if (keyStatus == AVKeyValueStatusFailed)
        {

            //[self assetFailedToPrepareForPlayback:error];
            if([thisKey isEqualToString:@"playable"]){

                 [self showNetworkErrorLabel];

            }

            return;
        } else if ((keyStatus == AVKeyValueStatusLoaded) || ( keyStatus == AVKeyValueStatusLoading )){

            [self removeNetworkLabel ];

        }
       }

    /* Use the AVAsset playable property to detect whether the asset can be played. */
    if (!asset.playable)
    {
        /* Generate an error describing the failure. */
        NSString *localizedDescription = NSLocalizedString(@"Item cannot be played", @"Item cannot be played description");
        NSString *localizedFailureReason = NSLocalizedString(@"The assets tracks were loaded, but could not be made playable.", @"Item cannot be played failure reason");
        NSDictionary *errorDict = [NSDictionary dictionaryWithObjectsAndKeys:
                                   localizedDescription, NSLocalizedDescriptionKey,
                                   localizedFailureReason, NSLocalizedFailureReasonErrorKey,
                                   nil];
        NSError *assetCannotBePlayedError = [NSError errorWithDomain:@"StitchedStreamPlayer" code:0 userInfo:errorDict];

        NSLog(@"%@",assetCannotBePlayedError);
        [self showNetworkErrorLabel];
        /* Display the error to the user. */
        [self assetFailedToPrepareForPlayback:assetCannotBePlayedError];

        return;
    }

    /* At this point we're ready to set up for playback of the asset. */

    /* Stop observing our prior AVPlayerItem, if we have one. */
    if (_playerItem)
    {
        /* Remove existing player item key value observers and notifications. */

        [_playerItem removeObserver:self forKeyPath:@"status"];

        [[NSNotificationCenter defaultCenter] removeObserver:self
                                                        name:AVPlayerItemDidPlayToEndTimeNotification
                                                      object:_playerItem];

        [[NSNotificationCenter defaultCenter] removeObserver:self
                                                        name:AVPlayerItemPlaybackStalledNotification
                                                      object:_playerItem];


    }


    /* Create a new instance of AVPlayerItem from the now successfully loaded AVAsset. */
    _playerItem = [AVPlayerItem playerItemWithAsset:asset];

    /* Observe the player item "status" key to determine when it is ready to play. */
    [_playerItem addObserver:self
                  forKeyPath:@"status"
                     options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                     context:AVPlayerDemoPlaybackViewControllerStatusObservationContext];

    /* When the player item has played to its end time we'll toggle
     the movie controller Pause button to be the Play button */
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(playerItemDidReachEnd:)
                                                 name:AVPlayerItemDidPlayToEndTimeNotification
                                               object:_playerItem];



       [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemFailedToPlayToEndTime:) name:AVPlayerItemPlaybackStalledNotification object:_playerItem];



    // Remove the movie player view controller from the "playback did finish" notification observers
    // Observe ourselves so we can get it to use the crossfade transition
    [[NSNotificationCenter defaultCenter] removeObserver:_currentVideoPlayerViewController
                                                    name:kPlayerViewDismissedNotification
                                                  object:_currentVideoPlayerViewController.player];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(videoFinishedCallback:)
                                                 name:kPlayerViewDismissedNotification
                                               object:_currentVideoPlayerViewController.player];



    /* Create new player, if we don't already have one. */
    if (!_currentVideoPlayerViewController.player)
    {
        /* Get a new AVPlayer initialized to play the specified player item. */
        _currentVideoPlayerViewController.player=[AVPlayer playerWithPlayerItem:self->_playerItem];


         [_currentVideoPlayerViewController.player addObserver:self
         forKeyPath:@"rate"
         options:NSKeyValueObservingOptionNew
         context:AVPlayerDemoPlaybackViewControllerRateObservationContext];

    }


}
Utsav Dusad
  • 2,139
  • 4
  • 31
  • 52
  • What about you have created a memory leak yourself? You don't show the critical code snippets that you found caused the issue, so what can we say: Nothing. You can't expect people to download a whole Xcode project and sort it out! Instead you should delete as much as code/files/... you can from your project until the problem disappears and you know where to zoom in. If you then still haven't got a clue, come back and post the few lines of code you have left. – meaning-matters Jun 11 '16 at 11:13
  • AVFoundation is very popular framework. I am sure the memory leak is due to some bad coding practice. But how do I resolve this problem. As these objects points to assembly level code. I am not able to figure out how and where these objects are created. Stack frame also points towards AVFoundation and assembly level code. – Utsav Dusad Jun 11 '16 at 11:35

1 Answers1

1

I couldn't figure out the reason behind this. I tried using AVPlayer instead and created my own UI using (reference Apple AVPlayer Demo app.) and I couldn't find any leak there. It just worked. If someone gets stuck with similar problem just give a try to reference code from AVPlayer Demo app. And if someone knows the answer for the issue I on this thread. Please let me know.

Utsav Dusad
  • 2,139
  • 4
  • 31
  • 52