AVPlayerの再生状態を確認する


回答:


57

アイテムの最後に到達したことを通知するには(Apple経由):

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

また、再生を追跡するには、次のことができます。

addPeriodicTimeObserverForInterval:queue:usingBlock:またはaddBoundaryTimeObserverForTimes:queue:usingBlock:を使用して、「AVPlayerオブジェクトの再生ヘッドの位置の変化を追跡する」。

例はアップルからです:

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

ブールフラグをスローして、再生ステータスを確認できます。
moonman239 2015年

たとえばを使用してプレーヤーのアイテムを変更し-replaceCurrentItemWithPlayerItem:、それを適切に処理しない場合、通知によって問題が発生する可能性があります。私にとってより信頼できる方法は、AVPlayerKVOを使用してのステータスを追跡することです。詳細については、以下の私の回答を参照してください:stackoverflow.com/a/34321993/3160561
maxkonovalov

2
エラーの通知も必要ですか? AVPlayerItemFailedToPlayToEndTimeNotification
ToolmakerSteve、2016

332

あなたはそれが遊んでいると言うことができます:

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

Swift 3拡張:

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

29
必ずしもそうとは限りませんが、ファイル内のエラーが原因でプレーヤーが停止した場合は処理されません。私が難しい方法を見つけた何か...
ダーモット2013年

7
ダーモットが言ったように、飛行機モードのときに何かをプレイしようとすると、AVPlayerのレートは1.0に設定されます。
phi 2013年

4
AVPlayerにはエラープロパティがあります。nilでないこと、およびレートが0でないことを確認するだけです。:)
James Campbell

23
回答が更新され、@ Dermotシナリオが回避されていることに注意してください。これは実際に機能します。
jomafer 2015年

2
逆ビデオ映像を再生しているとき(働くことはありません- [AVPlayer setRate:-1.0]ので、)-1.00未満である
ジュリアン・F. Weinert

49

iOS10には、このための組み込みプロパティがあります:timeControlStatus

たとえば、この関数は、そのステータスに基づいてavPlayerを再生または一時停止し、再生/一時停止ボタンを適切に更新します。

@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)
    }
}

2番目の質問については、avPlayerが最後に到達したかどうかを知るために、通知を設定するのが最も簡単です。

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

たとえば、最後まで来たら、ビデオの最初まで巻き戻して、一時停止ボタンを再生にリセットできます。

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

これらの例は、独自のコントロールを作成する場合に役立ちますが、AVPlayerViewControllerを使用する場合は、コントロールが組み込まれています。


iOS 10以降で使いやすい
technerd 2017年

2
@objc func didPlayToEnd()for Swift 4.2
Sean Stayns

21

rate動画が再生されているかどうかを確認する方法ではありません(停止する可能性があります)。のドキュメントから:rate

希望する再生速度を示します。0.0は「一時停止」を意味し、1.0は現在のアイテムの自然なレートでプレイする意欲を示します。

キーワード「再生したい」- の率は1.0、ビデオが再生されていることを意味しません。

iOS 10.0以降のソリューションはAVPlayerTimeControlStatusAVPlayer timeControlStatusプロパティで観察できるものを使用することです。

iOS 10.0より前のソリューション(9.0、8.0など)は、独自のソリューションをロールバックすることです。率は0.0、ビデオが一時停止されていることを意味します。rate != 0.0動画が再生中、停止していることを意味する場合。

次の方法でプレーヤーの時間を観察することで、違いを確認できます。 func addPeriodicTimeObserver(forInterval interval: CMTime, queue: DispatchQueue?, using block: @escaping (CMTime) -> Void) -> Any

ブロックは、現在のプレーヤーの時間をで返します。そのCMTimeため、lastTime(ブロックから最後に受信されcurrentTimeた時間)と(ブロックが報告されたばかりの時間)を比較すると、プレーヤーが再生中か停止中かがわかります。例えば、場合lastTime == currentTimerate != 0.0、そのプレイヤーが失速しています。

他の人が指摘したように、再生が終了したかどうかを判断することはで示されAVPlayerItemDidPlayToEndTimeNotificationます。


18

のより信頼できる代替手段NSNotificationは、自分をプレイヤーのrateプロパティのオブザーバーとして追加することです。

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

次に、観測されたレートの新しい値がゼロであるかどうかを確認します。つまり、最後に到達したり、バッファーが空のために停止したりするなど、何らかの理由で再生が停止したことを意味します。

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

rate == 0.0場合、正確に停止して再生を引き起こしたかを知るためには、次のチェックを行うことができます。

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
}

そして、プレーヤーが最後に達したときに停止することを忘れないでください:

self.player.actionAtItemEnd = AVPlayerActionAtItemEndPause;


最後まで到達できない場合の通知も必要だと思います- AVPlayerItemFailedToPlayToEndTimeNotification。このエラーが発生した場合、終了時間に達することはありません。または、mazの回答を読んで、コードにのチェックを追加します。player.error != nilこの場合、エラーが原因で再生が「終了」します。
ToolmakerSteve、2016

ところで、NSNotification ofの使用について「信頼できない」と感じたのは何AVPlayerItemDidPlayToEndTimeNotificationですか。
ToolmakerSteve 2016

ToolmakerSteve、ご連絡ありがとうございます。私の回答にエラーチェックを追加しました。信頼性の低い通知について-コレクションビューで繰り返し再利用可能なプレーヤービューを実装しているときに自分で問題に遭遇しました。KVOは、さまざまなプレーヤーの通知が互いに干渉することなく、よりローカルに保つことができるため、より明確になりました。
maxkonovalov 2016

17

スウィフト

AVPlayer

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

更新:ビデオが逆方向に再生
player.rate > 0されてplayer.rate != 0いる場合、指摘したJulianのおかげでマイナスになる可能性があるため、条件がに変更されました。
:これは上記の(Mazの)回答と同じように見えるかもしれませんが、Swiftでは '!player.error'でコンパイラエラーが発生したため、Swiftで 'player.error == nil'を使用してエラーを確認する必要があります。 「ブール」タイプではありません)

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
警告:この質問の2年前に出てきた回答で上記に述べたすべて。
Dan Rosenstark、2015

1
@Yar私も上記の回答に賛成票を投じていますが、これは迅速なものであり、Swiftでは '!player.error'が機能しなかったため、ブール型に対してのみ許可されているため、誤ってコメントを反対票に回答を追加して、このスタックオーバーフローアプリ:)
Aks

私の懸念は、nilでないことのplayer.errorが実際にどの程度うまく機能するのかわからないことです。
Dan Rosenstark、2015

1
ビデオフッテージをリバース(player.rate = -1.0)で再生するときは機能しません


6

maxkonovalovの答えのSwiftバージョンはこれです:

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

そして

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")
            }
        }
    }
}

maxkonovalovありがとうございます!


こんにちは、スタネフさん、回答ありがとうございます。これは私にはうまくいきません(コンソールに何も表示されませんか?)
Cesare

気にしないでください、それはうまくいきます-私のプレイヤーはそうでしたnil!しかし、ビューがいつ開始するか(終了しない)を知る必要があります。それを行う方法はありますか?
チェザーレ

3

現在、Swift 5では、プレーヤーが再生中か一時停止中かを確認する最も簡単な方法は、.timeControlStatus変数を確認することです。

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

1

答えは目的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
}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.