AVPlayer'ın oynatma durumunu kontrol edin


Yanıtlar:


57

Bir öğenin sonuna ulaşıldığına dair bildirim almak için ( Apple aracılığıyla ):

[[NSNotificationCenter defaultCenter] 
      addObserver:<self>
      selector:@selector(<#The selector name#>)
      name:AVPlayerItemDidPlayToEndTimeNotification 
      object:<#A player item#>];

Çalmayı izlemek için şunları yapabilirsiniz:

addPeriodicTimeObserverForInterval: queue: usingBlock: veya addBoundaryTimeObserverForTimes: queue: usingBlock: kullanarak "bir AVPlayer nesnesinde oynatma kafasının konumundaki değişiklikleri izleyin" .

Örnek Apple'dan:

// Assume a property: @property (retain) id playerObserver;

Float64 durationSeconds = CMTimeGetSeconds([<#An asset#> duration]);
CMTime firstThird = CMTimeMakeWithSeconds(durationSeconds/3.0, 1);
CMTime secondThird = CMTimeMakeWithSeconds(durationSeconds*2.0/3.0, 1);
NSArray *times = [NSArray arrayWithObjects:[NSValue valueWithCMTime:firstThird], [NSValue valueWithCMTime:secondThird], nil];

self.playerObserver = [<#A player#> addBoundaryTimeObserverForTimes:times queue:NULL usingBlock:^{
    // Passing NULL for the queue specifies the main queue.

    NSString *timeDescription = (NSString *)CMTimeCopyDescription(NULL, [self.player currentTime]);
    NSLog(@"Passed a boundary at %@", timeDescription);
    [timeDescription release];
}];

Oyun durumunu kontrol etmek için bir Boole bayrağı atabilirsiniz.
moonman239

Oyuncunun öğesini, örneğin ile değiştirirseniz -replaceCurrentItemWithPlayerItem:ve düzgün şekilde kullanmazsanız, bildirimler sorunlara neden olabilir . Benim için daha güvenilir bir yol, AVPlayerKVO kullanarak 'ın durumunu izlemektir. Daha fazla ayrıntı için aşağıdaki
cevabıma

2
Ayrıca hata bildirimine mi ihtiyacınız var? AVPlayerItemFailedToPlayToEndTimeNotification
ToolmakerSteve

332

Oynadığını şunu kullanarak anlayabilirsiniz:

AVPlayer *player = ...
if ((player.rate != 0) && (player.error == nil)) {
    // player is playing
}

Swift 3 uzantısı:

extension AVPlayer {
    var isPlaying: Bool {
        return rate != 0 && error == nil
    }
}

29
Mutlaka değil, oynatıcının dosyadaki bir hata nedeniyle durduğu durumları işlemez. Zor yoldan öğrendiğim bir şey ...
Dermot

7
Dermot'un dediği gibi, uçak modundayken bir şey çalmaya çalışırsanız, AVPlayer oranı, oynama niyetini ifade ettiği için hala 1.0 olarak ayarlanmıştır.
phi

4
AVPlayer'da bir hata özelliği var, sadece sıfır olmadığını kontrol edin ve oranın 0 olmadığını kontrol edin :)
James Campbell

23
@Dermot senaryosunu önlemek için cevabın güncellendiğini unutmayın. Yani bu gerçekten işe yarıyor.
jomafer

2
0'dan küçük olduğu için reverse ( - [AVPlayer setRate:-1.0]) video görüntüsü oynatırken çalışmayacak.-1.0
Julian F. Weinert

49

İOS10'da bunun için yerleşik bir özellik var: timeControlStatus

Örneğin bu işlev, durumuna göre avPlayer'ı oynatır veya duraklatır ve oynat / duraklat düğmesini uygun şekilde günceller.

@IBAction func btnPlayPauseTap(_ sender: Any) {
    if aPlayer.timeControlStatus == .playing {
        aPlayer.pause()
        btnPlay.setImage(UIImage(named: "control-play"), for: .normal)
    } else if aPlayer.timeControlStatus == .paused {
        aPlayer.play()
        btnPlay.setImage(UIImage(named: "control-pause"), for: .normal)
    }
}

İkinci sorunuza gelince, avPlayer'ın sona ulaşıp ulaşmadığını bilmek için yapılacak en kolay şey bir bildirim ayarlamak olacaktır.

NotificationCenter.default.addObserver(self, selector: #selector(self.didPlayToEnd), name: .AVPlayerItemDidPlayToEndTime, object: nil)

Örneğin, sona geldiğinde videonun başlangıcına geri sarabilir ve Duraklat düğmesini Oynat olarak sıfırlayabilirsiniz.

@objc func didPlayToEnd() {
    aPlayer.seek(to: CMTimeMakeWithSeconds(0, 1))
    btnPlay.setImage(UIImage(named: "control-play"), for: .normal)
}

Bu örnekler, kendi kontrollerinizi oluşturuyorsanız kullanışlıdır, ancak bir AVPlayerViewController kullanıyorsanız, o zaman kontroller yerleşik olarak gelir.


İOS

2
Swift 4.2 için @objc func didPlayToEnd ()
Sean Stayns

21

rateolduğu DEĞİL video olup olmadığını kontrol etmek yolu oynarken (araba durdu olabilir). Belgelerden rate:

İstenen oynatma oranını gösterir; 0.0 "duraklatıldı" anlamına gelir, 1.0 ise mevcut öğenin doğal hızında oynatma isteğini gösterir.

Anahtar kelimeler "oynatma isteği" - oranı 1.0videonun oynatıldığı anlamına gelmez.

İOS 10.0'dan beri çözüm AVPlayerTimeControlStatus, AVPlayer timeControlStatusmülk üzerinde gözlemlenebilen kullanmaktır .

İOS 10.0'dan önceki çözüm (9.0, 8.0 vb.) Kendi çözümünüzü kullanmaktır. Oran 0.0, videonun duraklatıldığı anlamına gelir. Ne zaman rate != 0.0o video ya oynama olduğu anlamına gelir veya takıldı.

Oyuncu zamanını aşağıdaki yollarla gözlemleyerek farkı öğrenebilirsiniz: func addPeriodicTimeObserver(forInterval interval: CMTime, queue: DispatchQueue?, using block: @escaping (CMTime) -> Void) -> Any

Blok, içinde geçerli oyuncu zamanını döndürür CMTime, bu nedenle lastTime(bloktan en son alınan currentTimezaman ) ve (bloğun henüz bildirildiği zaman) bir karşılaştırması, oyuncunun oynayıp oynamadığını gösterir. Örneğin, eğer lastTime == currentTimeve rate != 0.0, sonra oyuncu durdu.

Başkaları tarafından da belirtildiği gibi, oynatmanın bitip bitmediğini anlamak ile belirtilir AVPlayerItemDidPlayToEndTimeNotification.


18

Daha güvenilir bir alternatif, NSNotificationkendinizi oyuncunun ratemülküne gözlemci olarak eklemektir .

[self.player addObserver:self
              forKeyPath:@"rate"
                 options:NSKeyValueObservingOptionNew
                 context:NULL];

Ardından, gözlemlenen hız için yeni değerin sıfır olup olmadığını kontrol edin; bu, sona ulaşma veya boş arabellek nedeniyle durma gibi bir nedenle oynatmanın durduğu anlamına gelir.

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary<NSString *,id> *)change
                       context:(void *)context {
    if ([keyPath isEqualToString:@"rate"]) {
        float rate = [change[NSKeyValueChangeNewKey] floatValue];
        if (rate == 0.0) {
            // Playback stopped
        } else if (rate == 1.0) {
            // Normal playback
        } else if (rate == -1.0) {
            // Reverse playback
        }
    }
}

İçin rate == 0.0durumunda, tam durağına oynatmayı neyin neden olduğunu bilmek, aşağıdaki kontrolleri yapabilirsiniz:

if (self.player.error != nil) {
    // Playback failed
}
if (CMTimeGetSeconds(self.player.currentTime) >=
    CMTimeGetSeconds(self.player.currentItem.duration)) {
    // Playback reached end
} else if (!self.player.currentItem.playbackLikelyToKeepUp) {
    // Not ready to play, wait until enough data is loaded
}

Ve sona ulaştığında oynatıcınızı durdurmayı unutmayın:

self.player.actionAtItemEnd = AVPlayerActionAtItemEndPause;


Sonuna ulaşmak için başarısızlık bildirimine de ihtiyacım olduğunu düşünüyorum - AVPlayerItemFailedToPlayToEndTimeNotification. Bu hata olursa, hiçbir zaman bitiş zamanına ulaşmaz. Veya maz'ın cevabını okuyarak, kodunuza bir kontrol ekleyin player.error != nil, bu durumda oynatma, hata nedeniyle "sona erdi".
ToolmakerSteve

BTW, NSNotification'ı kullanma konusunda neyi "güvenilir değil" buldunuz AVPlayerItemDidPlayToEndTimeNotification?
ToolmakerSteve

ToolmakerSteve, notunuz için teşekkürler, cevabıma hata kontrolü ekledi. Güvenilir olmayan bildirimler için - Koleksiyon görünümünde tekrarlanan ve yeniden kullanılabilir oyuncu görünümlerini uygularken sorunla kendim karşılaştım ve KVO, farklı oyuncuların bildirimleri birbirine müdahale etmeden her şeyi daha yerel tutmaya izin verdiği için işleri daha net hale getirdi.
maxkonovalov

17

İçin Swift :

AVPlayer :

let player = AVPlayer(URL: NSURL(string: "http://www.sample.com/movie.mov"))
if (player.rate != 0 && player.error == nil) {
   println("playing")
}

Güncelleme :
player.rate > 0durum olarak değiştirildi, player.rate != 0çünkü video ters yönde oynatılıyorsa, Julian sayesinde işaret ettiği için olumsuz olabilir .
Not : Bu, yukarıdaki (Maz'in) cevabı ile aynı görünebilir ancak Swift'de '! Player.error' bana bir derleyici hatası veriyordu, bu nedenle Swift'de 'player.error == nil' kullanırken hata olup olmadığını kontrol etmelisiniz. (Çünkü hata özelliği 'Bool' türünde değil)

AVAudioPlayer:

if let theAudioPlayer =  appDelegate.audioPlayer {
   if (theAudioPlayer.playing) {
       // playing
   }
}

AVQueuePlayer:

if let theAudioQueuePlayer =  appDelegate.audioPlayerQueue {
   if (theAudioQueuePlayer.rate != 0 && theAudioQueuePlayer.error == nil) {
       // playing
   }
}

2
AVPlayer! = AVAudioPlayer
quemeful

2
Uyarılar: Yukarıda, bundan iki yıl önce ortaya çıkan cevapta bahsedildi.
Dan Rosenstark

1
@Yar da yukarıdaki cevaba olumlu oy verildiğini biliyorum ama bu hızlı ve Swift için '! Player.error' benim için çalışmıyordu, sadece bool türleri için izin veriliyor, bu yüzden yanıtı ekledim oops yorumunuzu yanlışlıkla yanıt vermek için this stack overflow app :)
Aks

Endişem şu ki player.error'un ne kadar iyi çalıştığını bilmiyorum.
Dan Rosenstark

1
Ters video görüntüsü oynatılırken çalışmayacak player.rate = -1.0, çünkü -1.0 0'dan küçük.
Julian F. Weinert

9

Maz tarafından verilen cevaba dayalı hızlı uzantı

extension AVPlayer {

    var isPlaying: Bool {
        return ((rate != 0) && (error == nil))
    }
}

6

Maxkonovalov'un cevabının Swift versiyonu şudur:

player.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions.New, context: nil)

ve

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if keyPath == "rate" {
        if let rate = change?[NSKeyValueChangeNewKey] as? Float {
            if rate == 0.0 {
                print("playback stopped")
            }
            if rate == 1.0 {
                print("normal playback")
            }
            if rate == -1.0 {
                print("reverse playback")
            }
        }
    }
}

Teşekkürler maxkonovalov!


Merhaba Bay Stanev, cevabınız için teşekkürler. Bu benim için çalışmıyor (aka konsolda hiçbir şey yazdırmıyor mu?)
Cesare

Boşver, işe yarıyor - oyuncum öyleydi nil! Ancak görünümün ne zaman başladığını (bitmediğini) bilmem gerekiyor. Bunu yapmanın bir yolu var mı?
Cesare

3

Şu anda swift 5 ile oyuncunun oynayıp oynamadığını veya duraklatıldığını kontrol etmenin en kolay yolu .timeControlStatus değişkenini kontrol etmektir .

player.timeControlStatus == .paused
player.timeControlStatus == .playing

1

Cevap Hedef C

if (player.timeControlStatus == AVPlayerTimeControlStatusPlaying) {
    //player is playing
}
else if (player.timeControlStatus == AVPlayerTimeControlStatusPaused) {
    //player is pause
}
else if (player.timeControlStatus == AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate) {
    //player is waiting to play
}

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.