【问题标题】:AVQueuePlayer memory issue while looping a playlist in iOS在 iOS 中循环播放列表时出现 AVQueuePlayer 内存问题
【发布时间】:2015-08-20 16:41:28
【问题描述】:

在我的 iOS 应用程序中,我正在尝试播放下载到应用程序的 Documents 目录的视频列表。为了实现这个目标,我使用了 AVQueuePlayer。以下是我的代码,它在 6/7 次循环后导致应用程序崩溃。

@interface PlayYTVideoViewController () <NSURLConnectionDataDelegate, UITableViewDataSource, UITableViewDelegate> 
{

AVQueuePlayer *avQueuePlayer;

}


- (void)playlistLoop
{
    NSLog(@"%s - %d", __PRETTY_FUNCTION__, __LINE__);

    lastPlayedVideoNumber = 0;

    _loadingVideoLabel.hidden = YES;

    avPlayerItemsMutArray = [[NSMutableArray alloc] init];

    for (NSString *videoPath in clipUrlsMutArr)
    {
        NSURL *vidPathUrl = [NSURL fileURLWithPath:videoPath];

        AVPlayerItem *avpItem = [AVPlayerItem playerItemWithURL:vidPathUrl];

        [avPlayerItemsMutArray addObject:avpItem];
    }

    avPlayerItemsArray = [avPlayerItemsMutArray copy];

    for(AVPlayerItem *item in avPlayerItemsArray)
    {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemDidPlayToEndTime:) name:AVPlayerItemDidPlayToEndTimeNotification object:item];
    }

    avQueuePlayer = [AVQueuePlayer queuePlayerWithItems:avPlayerItemsArray];

    avQueuePlayer.actionAtItemEnd = AVPlayerActionAtItemEndAdvance;

    introVideoLayer = [AVPlayerLayer playerLayerWithPlayer:avQueuePlayer];

    introVideoLayer.frame = _mpIntroVideoView.bounds;

    [_mpContainerView.layer addSublayer:introVideoLayer];

    [avQueuePlayer play];
}


- (void)itemDidPlayToEndTime:(NSNotification *)notification
{
    NSLog(@"%s - %d", __PRETTY_FUNCTION__, __LINE__);

    AVPlayerItem *endedAVPlayerItem = [notification object];

    [endedAVPlayerItem seekToTime:kCMTimeZero];

    for (AVPlayerItem *item in avPlayerItemsArray)
    {
        if (item == endedAVPlayerItem)
        {
            lastPlayedVideoNumber++;
            break;
        }
    }

    [self reloadVideoClipsTable];

    if ([endedAVPlayerItem isEqual:[avPlayerItemsArray lastObject]])
    {
        [self playlistLoop];
    }
}

在遇到内存问题后,我尝试对上述代码进行一些更改。

我尝试将 avQueuePlayer 变量设置为 public 并将其设置为强变量

 @property (strong, nonatomic) AVQueuePlayer *avQueuePlayer;

通过这样做,我希望 avQueuePlayer 变量保留在内存中,直到我们手动设置为 nil。但这并没有解决问题。

然后我尝试将播放器、相关数组和层设置为 nil,并为新的循环会话再次创建。

if (avPlayerItemsMutArray != nil)
    {
        avPlayerItemsMutArray = nil;
    }

avPlayerItemsMutArray = [[NSMutableArray alloc] init];

if (avPlayerItemsArray != nil)
    {
        avPlayerItemsArray = nil;
    }

avPlayerItemsArray = [avPlayerItemsMutArray copy];

if (avQueuePlayer != nil)
    {
        avQueuePlayer = nil;
    }

avQueuePlayer = [AVQueuePlayer queuePlayerWithItems:avPlayerItemsArray];

if(introVideoLayer != nil)
    {
        [introVideoLayer removeFromSuperlayer];
        introVideoLayer = nil;
    }

introVideoLayer = [AVPlayerLayer playerLayerWithPlayer:avQueuePlayer];

但这也无助于解决问题。

接下来我尝试在新循环中重新初始化之前删除观察者

if (avPlayerItemsArray != nil)
{
    avPlayerItemsArray = nil;

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:AVPlayerItemDidPlayToEndTimeNotification
                                                  object:nil];
}

但这也无济于事。

接下来我使用 Instrument 来找出内存使用情况和泄漏情况。应用程序崩溃时不超过 18 MB,并且还有超过 200 MB 的可用空间。 Instruments 稍微复杂一些,但我仍然没有发现任何与此代码相关的内存泄漏。

【问题讨论】:

    标签: ios objective-c memory-leaks avqueueplayer


    【解决方案1】:

    实际上错误不在于 AVQueuePlayer。在我的应用程序中,我在视频播放视图下方的表格中列出了所有视频。在该表中,每一行都包含我从下面的代码中获取的视频缩略图。

    + (UIImage *)createThumbForVideo:(NSString *)vidFileName
    {
        NSString *videoFolder = [Video getVideoFolder];
        NSString *videoFilePath = [videoFolder stringByAppendingFormat:@"/trickbook/videos/edited/%@",vidFileName];
    
        NSURL *url = [NSURL fileURLWithPath:videoFilePath];
    
        AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:url options:nil];
        AVAssetImageGenerator *generateImg = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    
        generateImg.appliesPreferredTrackTransform = YES;
    
        NSError *error = NULL;
        CMTime time = CMTimeMake(1, 65);
        CGImageRef refImg = [generateImg copyCGImageAtTime:time actualTime:NULL error:&error];
    
        UIImage *frameImage = [[UIImage alloc] initWithCGImage:refImg];
    
        return frameImage;
    }
    

    每次视频剪辑结束播放并且播放列表开始一个新循环时,我都会更新表格视图。所以每次我调用上述方法时,这就是内存问题的原因。

    作为解决方案,我只为单个视频剪辑调用此方法一次,并将返回的 UIImage 存储在可变数组中。这样就解决了问题。

    问题的标题和标签可能不足以回答问题,但我认为这值得作为问答存在而不是删除帖子。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多