2015-03-03 60 views
0

我到處搜索,仍無法找到解決此問題的解決方案。我有一個AVQueuePlayer我正在製作一個廣播應用程序。它一次排隊約20 AVPlayerItems。我將AVPlayerItemDidPlayToEndTimeNotification觀察員添加到這些項目中的每一個。通知被觸發並執行代碼以刪除關鍵觀察者的元數據和狀態,以便它不會崩潰並前進到隊列中的下一個項目。但它不想玩。沒有錯誤,狀態已準備就緒,AVPlayer網址加載完美。如果我點擊按鈕來調用advancenextitem,它可以完美運行,並且可以完美播放。 現在最奇怪的是:如果我手動發佈通知,通知代碼完美工作。我會很感激任何幫助或意見,因爲我一直在努力做到這一點。AVPlayerItemDidPlayToEndTimeNotification僅在強制使用時才起作用

if (playlist != nil) { 
    playlistInterval = [playlist count]/4.0; 
    NSMutableArray *playerItems = [[NSMutableArray alloc] initWithCapacity:playlistInterval]; 

     for(int i = 0; i < playlistInterval; i++) { 
      NSString *tempString = [playlist objectAtIndex:i]; 
      //NSLog(@"%@", tempString); 
      NSURL *temp = [[NSURL alloc] initWithString:tempString]; 
      AVPlayerItem *itemTemp = [AVPlayerItem playerItemWithURL:temp]; 
      [itemTemp addObserver:self forKeyPath:@"timedMetadata" options:NSKeyValueObservingOptionNew context:nil]; 
      [itemTemp addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil]; 
      [[NSNotificationCenter defaultCenter] addObserver: self 
                selector: @selector(playerItemDidReachEnd:) 
                 name: AVPlayerItemDidPlayToEndTimeNotification 
                 object: itemTemp]; 
      [playerItems addObject:itemTemp]; 
      playlistCounter++; 
     } 
     qPlayer = [AVQueuePlayer queuePlayerWithItems:playerItems]; 

     qPlayer.actionAtItemEnd = AVPlayerActionAtItemEndAdvance; 
     [ qPlayer addObserver:self 
        forKeyPath:@"rate" 
         options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew 
         context:rateDidChangeKVO]; 

     [qPlayer addObserver:self forKeyPath:@"currentItem.duration" 
        options:0 
        context:durationDidChangeKVO]; 
    return YES; 
} 
return NO; 

}

- (IBAction)advancePlayer:(id)sender { 
    unsigned long size = [[qPlayer items] count]; 
    NSLog(@"%tu",size); 
    if (size <= 0) { 
     [self initializePlayerWithItems:currentKey]; 
     [qPlayer play]; 
    } else { 
     //NSLog(@"%@",[qPlayer currentItem]); 
     [[qPlayer currentItem] removeObserver:self forKeyPath:@"status"]; 
     [[qPlayer currentItem] removeObserver:self forKeyPath:@"timedMetadata"]; 
     [qPlayer advanceToNextItem]; 
     [qPlayer play]; 
    } 

}

- (void)playerItemDidReachEnd:(NSNotification *)notification { 
[self advancePlayer:nil]; 
NSLog(@"IT REACHED THE END"); 

}

現在,如果我把這一切從一個按鈕或什麼完美的作品:

[[NSNotificationCenter defaultCenter] 
postNotificationName:@"AVPlayerItemDidPlayToEndTimeNotification" 
object:[qPlayer currentItem]]; 

回答

2

我沒有一個測試項目來測試這個理論,但是我猜測通知會丟失,因爲它們不是玩家的當前項目,並且在添加觀察者時只是局部變量。

我建議添加觀察者「之後」你初始化像這樣的球員。

... 
qPlayer = [AVQueuePlayer queuePlayerWithItems:playerItems]; 

qPlayer.actionAtItemEnd = AVPlayerActionAtItemEndAdvance; 

[[NSNotificationCenter defaultCenter] addObserver: self 
             selector: @selector(playerItemDidReachEnd:) 
              name: AVPlayerItemDidPlayToEndTimeNotification 
              object: [qPlayer currentItem]]; 

然後,在您推進播放器之後,您可以再次爲下一個當前項目添加觀察者。

- (IBAction)advancePlayer:(id)sender { 
    unsigned long size = [[qPlayer items] count]; 
    NSLog(@"%tu",size); 
    if (size <= 0) { 
     [self initializePlayerWithItems:currentKey]; 
     [qPlayer play]; 
    } else { 
     //NSLog(@"%@",[qPlayer currentItem]); 
     [[qPlayer currentItem] removeObserver:self forKeyPath:@"status"]; 
     [[qPlayer currentItem] removeObserver:self forKeyPath:@"timedMetadata"]; 
     [qPlayer advanceToNextItem]; 

     [[NSNotificationCenter defaultCenter] addObserver: self 
             selector: @selector(playerItemDidReachEnd:) 
              name: AVPlayerItemDidPlayToEndTimeNotification 
              object: [qPlayer currentItem]]; 
     [qPlayer play]; 
} 

希望能幫助並解決問題。

+0

感謝您的回覆。我嘗試了兩種方法。事情是在兩種情況下發送通知。在手動發佈通知的情況下,一切都按照原樣進行。在項目實際結束時發送通知的情況下,它會執行代碼,但音頻不會播放。但是我可以在球員和球員資料中找到任何錯誤。讓所有事情順利進行的唯一方法是按下按鈕以前進播放器。 – 2015-03-03 02:04:07

+0

「此通知可能發佈在與觀察者註冊的其他線程不同的線程上」我想知道在後臺線程中是否存在所有這些問題。 – 2015-03-03 02:18:51

+0

我會嘗試在主線程上註冊觀察者。我應該只在主線程或所有代碼(advancePlayer,initializeplayeritems等)上註冊觀察者嗎? – 2015-03-03 02:37:53

0

經過幾天不同的代碼和研究組合,我發現了這些: 問題:有一個AVQueuePlayer,每次有約20件以上的項目與註冊的觀察者。當AVPlayerItemDidPlayToEndTimeNotification被調用時,代碼將前進到下一個項目,但該項目不會播放。 由於我有觀察者附加到我的avplayeritems,我不能只使用AVPlayer的advanctonextitem屬性。我需要使用AVPlayerItemDidPlayToEndTimeNotification。現在,當這個方法被調用時它可以很好地工作,但是當AVPlayerItem發佈通知時,它會在[templayer advanceToNextItem](隊列中的下一個AVPlayerItem)被調用,其數據將會丟失。否則,如果我通過自己的代碼發佈通知,它會完美地推進到下一個項目。爲了解決這個問題,我嘗試了一切,但這是我最終完成的,它完美的工作,它只是想我需要,所以也許如果別人卡住它會幫助他們。我使用了一個可變數組來存儲「隊列」,並一次只加載一個AVPlayerItem。

if (playlist != nil) { 
    playlistInterval = [playlist count]/4.0; 
    //Array to hold AVPlayerItems 
    _playerItems = [[NSMutableArray alloc] initWithCapacity:playlistInterval]; 
    for(int i = 0; i < playlistInterval; i++) { 
     AVPlayerItem *itemTemp = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:[playlist objectAtIndex:playlistCounter]]]; 
     [itemTemp addObserver:self forKeyPath:@"timedMetadata" options:NSKeyValueObservingOptionNew context:nil]; 
     [itemTemp addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil]; 
     [[NSNotificationCenter defaultCenter] addObserver: self 
               selector: @selector(playerItemDidReachEnd:) 
                name: AVPlayerItemDidPlayToEndTimeNotification 
                object: itemTemp]; 
     [_playerItems addObject:itemTemp]; 
     playlistCounter++; 
    } 
    //Init player to only one item 
    self.player = [[AVPlayer alloc] initWithPlayerItem:[_playerItems objectAtIndex:0]]; 
    //Don't do anything since will be handling advancing 
    self.player.actionAtItemEnd = AVPlayerActionAtItemEndNone; 
    [ self.player addObserver:self 
         forKeyPath:@"rate" 
         options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew 
         context:rateDidChangeKVO]; 

    [self.player addObserver:self forKeyPath:@"currentItem.duration" 
         options:0 
         context:durationDidChangeKVO]; 
    return YES; 
} 

    - (void)playerItemDidReachEnd:(NSNotification *)notification { 
//NSLog(@"notifiacation thread: %d", [NSThread isMainThread]); 
if ([currentKey isEqualToString:@"morning slokha"] || selection != 0) 
    return; 
dispatch_async(dispatch_get_main_queue(), ^{ 
    unsigned long size = [_playerItems count]; 
    NSLog(@"%tu",size); 
    [self resetSlider]; 
    if (_playerItems.count <= 1) { 
     [self initializePlayerWithItems:currentKey]; 
     [self.player play]; 
    } else { 
     //NSLog(@"%@",[qPlayer currentItem]); 
     @try{ 
      [[_playerItems objectAtIndex:0] removeObserver:self forKeyPath:@"status"]; 
      [[_playerItems objectAtIndex:0] removeObserver:self forKeyPath:@"timedMetadata"]; 
      [[self.player currentItem] removeObserver:self forKeyPath:@"status"]; 
      [[self.player currentItem] removeObserver:self forKeyPath:@"timedMetadata"]; 
     }@catch(id anException){ 
      //do nothing, obviously it wasn't attached because an exception was thrown 
     } 
     [[NSNotificationCenter defaultCenter] addObserver: self 
               selector: @selector(playerItemDidReachEnd:) 
                name: AVPlayerItemDidPlayToEndTimeNotification 
                object: [_playerItems objectAtIndex:0]]; 
     [[NSNotificationCenter defaultCenter] addObserver: self 
               selector: @selector(playerItemDidReachEnd:) 
                name: AVPlayerItemDidPlayToEndTimeNotification 
                object: [self.player currentItem]]; 
     [_playerItems removeObjectAtIndex:0]; 
     //Replace AVPlayerItem manually 
     [self.player replaceCurrentItemWithPlayerItem:[_playerItems objectAtIndex:0]]; 
     [self.player seekToTime:kCMTimeZero]; 
     [self.player play]; 
    } 
}); 
} 
+0

請格式化答案。 – Opal 2015-04-08 12:00:35

1

確保您正在主線程上註冊您的通知。

dispatch_async(dispatch_get_main_queue(), ^{ 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(itemDidFinishPlaying:) 
               name:AVPlayerItemDidPlayToEndTimeNotification 
               object:self.playerItem]; 

}); 
+0

謝謝。你節省了我的時間 – 2016-08-05 07:10:48

0

1 - 我會非常驚訝的是PlayerItems迷路了。他們保留在某個地方,由玩家排列,...

2 - Appledoc明確指出您可以在任何線程上發送通知。

在這種情況下,一切都應該工作,但它沒有,我建議檢查上下文。我經歷過的一個簡單的例子(我已經失去了幾個小時!!)是持有玩家的視圖被處理掉了。在這種情況下,視頻仍在播放。所以很難調試。

我終於放棄了使用通知系統,切換到KVO。 ([player addObserver:self keypath:@「status」...)

我在處理視圖時得到了一個異常,因爲視圖仍然被註冊爲玩家觀察者。

我已經解決了視圖錯誤,然後我的視圖按預期接收到playerItem的通知。

它通常是這樣的。蘋果告訴我們這很簡單。 如果它不起作用,我們做了很多解決方法和個人補丁,而不是試圖瞭解我們已經做了什麼,可以有副作用...

相關問題