简体   繁体   English

在iOS中循环播放列表时出现AVQueuePlayer内存问题

[英]AVQueuePlayer memory issue while looping a playlist in iOS

In my iOS application, I'm trying to play list of videos downloaded to applications' Documents directory. 在我的iOS应用程序中,我试图播放下载到应用程序“文档”目录中的视频列表。 To achieve that target, I used AVQueuePlayer. 为了实现该目标,我使用了AVQueuePlayer。 Following is my code which leads to app crash after 6/7 times looping. 以下是我的代码,导致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];
    }
}

After getting memory issue, I tried to make some changes to above code. 遇到内存问题后,我尝试对上述代码进行一些更改。

I tried to set avQueuePlayer variable public and set it as strong variable 我试图将avQueuePlayer变量设置为public并将其设置为强变量

 @property (strong, nonatomic) AVQueuePlayer *avQueuePlayer;

By doing that I expected avQueuePlayer variable remain in the memory till we manually set to nil. 通过这样做,我希望avQueuePlayer变量保留在内存中,直到我们手动将其设置为nil为止。 But that didn't solve the problem. 但这并不能解决问题。

Then I tried to set player, related arrays and layers to nil and created again for new loop session. 然后,我尝试将播放器,相关的数组和图层设置为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];

But that also didn't help to solve the issue. 但这也无助于解决问题。

Next I try to remove the observer before it re-initialized in a new loop 接下来,我尝试在新循环中将观察者重新初始化之前将其移除

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

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

But that also didn't help. 但这也无济于事。

Next I used Instrument to find out memory usages and leaks. 接下来,我使用Instrument查找内存使用情况和泄漏。 Application is not exceeding 18 MB when it is crashing and also there were more than 200 MB remaining as free. 当应用崩溃时,应用程序大小不超过18 MB,并且还有200 MB以上的可用空间。 Instruments is little more complicated but still I didn't find any memory leaks related to this code. 仪器稍微复杂一点,但是我仍然没有发现与此代码相关的任何内存泄漏。

Actually the error was not with the AVQueuePlayer. 实际上,该错误并非与AVQueuePlayer有关。 In my application I'm listing all the videos inside a table below the video playing view. 在我的应用程序中,我在视频播放视图下方的表格内列出了所有视频。 In that table, each row consists with video thumbnail that I taken from below code. 在该表中,每一行都包含我从以下代码中提取的视频缩略图。

+ (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;
}

Every time a video clip ends playing and also playlist begins a new loop, I update the table view. 每当视频剪辑结束播放并且播放列表开始新的循环时,我都会更新表格视图。 So each time I call above method and that's the reason for memory issue. 因此,每次我调用上述方法时,这就是内存问题的原因。

As the solution I call this method only once for a single video clip and store the returning UIImage in a mutable array. 作为解决方案,我仅对单个视频剪辑调用此方法一次,并将返回的UIImage存储在可变数组中。 That solved the issue. 那解决了问题。

Heading of the question and the tags may not adequate with the answer, but I thought this is worth existing as a Q & A rather than deleting the post. 问题的标题和标签可能不足以回答问题,但我认为值得将其作为问答,而不是删除帖子。

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

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