2015-08-14 3 views
0

В моем приложении iOS я пытаюсь воспроизвести список видеороликов, загруженных в каталог документов «Документы». Для достижения этой цели я использовал AVQueuePlayer. Ниже приведен мой код, который приводит к сбою приложения после 6/7 раз цикла.Проблема с памятью AVQueuePlayer во время цикла воспроизведения плейлиста в iOS

@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 переменных общественности и установить его в качестве сильной переменной

@property (strong, nonatomic) AVQueuePlayer *avQueuePlayer; 

Поступая, что я ожидал, переменная avQueuePlayer останется в памяти, пока мы вручную установить на ноль. Но это не решило проблему.

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

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 МБ, оставшихся свободными. Инструменты немного сложнее, но до сих пор я не обнаружил утечек памяти, связанных с этим кодом.

ответ

0

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

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