Ошибка памяти AVQueuePlayer при зацикливании списка воспроизведения в iOS

В моем iOS-приложении я пытаюсь воспроизвести список видео, загруженных в каталог документов приложения. Для достижения этой цели я использовал 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. Но это не решило проблему.

Затем я попытался установить проигрыватель, связанные массивы и слои на ноль и создал заново для новой сессии цикла.

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

Но это также не помогло.

Затем я использовал Инструмент, чтобы выяснить использование памяти и утечки. Приложение не превышает 18 МБ в случае сбоя, а также более 200 МБ осталось свободным. Инструменты немного сложнее, но все же я не обнаружил утечек памяти, связанных с этим кодом.

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 в изменяемом массиве. Это решило проблему.

Заголовок вопроса и теги могут не соответствовать ответу, но я подумал, что это стоит использовать как вопрос и ответ, а не удалять сообщение.

Другие вопросы по тегам