回答:
アイテムの最後に到達したことを通知するには(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];
}];
-replaceCurrentItemWithPlayerItem:
、それを適切に処理しない場合、通知によって問題が発生する可能性があります。私にとってより信頼できる方法は、AVPlayer
KVOを使用してのステータスを追跡することです。詳細については、以下の私の回答を参照してください:stackoverflow.com/a/34321993/3160561
AVPlayerItemFailedToPlayToEndTimeNotification
あなたはそれが遊んでいると言うことができます:
AVPlayer *player = ...
if ((player.rate != 0) && (player.error == nil)) {
// player is playing
}
Swift 3拡張:
extension AVPlayer {
var isPlaying: Bool {
return rate != 0 && error == nil
}
}
- [AVPlayer setRate:-1.0]
ので、)-1.0
0未満である
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を使用する場合は、コントロールが組み込まれています。
rate
動画が再生されているかどうかを確認する方法ではありません(停止する可能性があります)。のドキュメントから:rate
希望する再生速度を示します。0.0は「一時停止」を意味し、1.0は現在のアイテムの自然なレートでプレイする意欲を示します。
キーワード「再生したい」- の率は1.0
、ビデオが再生されていることを意味しません。
iOS 10.0以降のソリューションはAVPlayerTimeControlStatus
、AVPlayer
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 == currentTime
やrate != 0.0
、そのプレイヤーが失速しています。
他の人が指摘したように、再生が終了したかどうかを判断することはで示されAVPlayerItemDidPlayToEndTimeNotification
ます。
のより信頼できる代替手段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
この場合、エラーが原因で再生が「終了」します。
AVPlayerItemDidPlayToEndTimeNotification
ですか。
用スウィフト:
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
}
}
player.rate = -1.0
)で再生するときは機能しません
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ありがとうございます!
nil
!しかし、ビューがいつ開始するか(終了しない)を知る必要があります。それを行う方法はありますか?
答えは目的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
}
player.timeControlStatus == AVPlayer.TimeControlStatus.playing