简体   繁体   English

内存泄漏:AVplayerViewController

[英]Memory Leak: AVplayerViewController

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. 请参阅下面的分配工具读数截图。 在此输入图像描述 Every time, when I pop the view controller (showing video) there are some objects related to AVFoundation holding the memory. 每当我弹出视图控制器(显示视频)时,都会有一些与AVFoundation相关的对象保持内存。 Interestingly the responsible library of all these objects is AVFoundation. 有趣的是,所有这些对象的负责库都是AVFoundation。 None of the increase in memory is due to objects created in the APP. 内存增加都不是由于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. 我在网上看到了一些AVPlayerViewController的例子,但它们似乎有同样的问题。

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. 如果有人想要复制这个,那么他可以下载上面给出的任何2个项目。 You have to make minor changes in the storyboard for creating root view controller with the navigation controller. 您必须在故事板中进行细微更改,以便使用导航控制器创建根视图控制器。

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];

    }


}

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. 我尝试使用AVPlayer,并使用(参考Apple AVPlayer演示应用程序。 )创建我自己的UI,我找不到任何泄漏。 It just worked. 它刚刚起作用。 If someone gets stuck with similar problem just give a try to reference code from AVPlayer Demo app. 如果有人遇到类似问题,请尝试从AVPlayer演示应用程序中引用代码。 And if someone knows the answer for the issue I on this thread. 如果有人知道我在这个问题上的问题的答案。 Please let me know. 请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM