Câu trả lời:
Để nhận thông báo về việc hết mặt hàng (thông qua Apple ):
[[NSNotificationCenter defaultCenter]
addObserver:<self>
selector:@selector(<#The selector name#>)
name:AVPlayerItemDidPlayToEndTimeNotification
object:<#A player item#>];
Và để theo dõi quá trình chơi, bạn có thể:
"theo dõi các thay đổi về vị trí của đầu phát trong đối tượng AVPlayer" bằng cách sử dụng addPeriodicTimeObserverForInterval: queue: usingBlock: hoặc addBoundaryTimeObserverForTimes: queue: usingBlock : .
Ví dụ là của Apple:
// 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:
và không xử lý đúng cách. Một cách đáng tin cậy hơn đối với tôi là theo dõi AVPlayer
trạng thái của bằng KVO. Xem câu trả lời của tôi bên dưới để biết thêm chi tiết: stackoverflow.com/a/34321993/3160561
AVPlayerItemFailedToPlayToEndTimeNotification
Bạn có thể biết nó đang phát bằng cách sử dụng:
AVPlayer *player = ...
if ((player.rate != 0) && (player.error == nil)) {
// player is playing
}
Phần mở rộng Swift 3:
extension AVPlayer {
var isPlaying: Bool {
return rate != 0 && error == nil
}
}
- [AVPlayer setRate:-1.0]
), vì -1.0
nhỏ hơn 0.
Trong iOS10, có một thuộc tính tích hợp sẵn cho điều này ngay bây giờ: timeControlStatus
Ví dụ: chức năng này phát hoặc tạm dừng avPlayer dựa trên trạng thái của nó và cập nhật nút phát / tạm dừng một cách thích hợp.
@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)
}
}
Đối với câu hỏi thứ hai của bạn, để biết avPlayer đã đến cuối hay chưa, việc đơn giản nhất bạn có thể làm là thiết lập thông báo.
NotificationCenter.default.addObserver(self, selector: #selector(self.didPlayToEnd), name: .AVPlayerItemDidPlayToEndTime, object: nil)
Ví dụ: khi nó đi đến cuối, bạn có thể tua lại đến đầu video và đặt lại nút Tạm dừng để Phát.
@objc func didPlayToEnd() {
aPlayer.seek(to: CMTimeMakeWithSeconds(0, 1))
btnPlay.setImage(UIImage(named: "control-play"), for: .normal)
}
Những ví dụ này hữu ích nếu bạn đang tạo các điều khiển của riêng mình, nhưng nếu bạn sử dụng AVPlayerViewController, thì các điều khiển được tích hợp sẵn.
rate
là KHÔNG cách để kiểm tra xem một đoạn video được chơi (nó có thể bị đình trệ). Từ tài liệu của rate
:
Cho biết tốc độ phát lại mong muốn; 0,0 có nghĩa là "tạm dừng", 1,0 cho biết mong muốn chơi với tỷ lệ tự nhiên của mục hiện tại.
Từ khóa "mong muốn phát" - tỷ lệ 1.0
không có nghĩa là video đang phát.
Giải pháp kể từ iOS 10.0 là sử dụng AVPlayerTimeControlStatus
có thể được quan sát trên AVPlayer
timeControlStatus
tài sản.
Giải pháp trước iOS 10.0 (9.0, 8.0, v.v.) là triển khai giải pháp của riêng bạn. Tỷ lệ 0.0
có nghĩa là video bị tạm dừng. Khi rate != 0.0
điều đó có nghĩa là video đang phát hoặc bị dừng.
Bạn có thể tìm ra sự khác biệt bằng cách quan sát thời gian của người chơi qua: func addPeriodicTimeObserver(forInterval interval: CMTime, queue: DispatchQueue?, using block: @escaping (CMTime) -> Void) -> Any
Khối trả về thời gian của người chơi hiện tại CMTime
, do đó, so sánh giữa lastTime
(thời gian nhận được lần cuối từ khối) và currentTime
(thời gian mà khối vừa báo cáo) sẽ cho biết liệu người chơi đang chơi hay bị dừng. Ví dụ, nếu lastTime == currentTime
và rate != 0.0
, thì trình phát đã bị dừng.
Như những người khác đã lưu ý, việc tìm hiểu xem quá trình phát lại đã kết thúc hay chưa được chỉ ra bởi AVPlayerItemDidPlayToEndTimeNotification
.
Một giải pháp thay thế đáng tin cậy hơn NSNotification
là thêm bạn làm người quan sát rate
tài sản của người chơi .
[self.player addObserver:self
forKeyPath:@"rate"
options:NSKeyValueObservingOptionNew
context:NULL];
Sau đó, kiểm tra xem giá trị mới cho tỷ lệ quan sát có bằng 0 hay không, có nghĩa là quá trình phát lại đã dừng vì một lý do nào đó, như kết thúc hoặc bị đình trệ do bộ đệm trống.
- (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
}
}
}
Đối với rate == 0.0
trường hợp, để biết chính xác nguyên nhân nào khiến quá trình phát lại bị dừng, bạn có thể thực hiện các bước kiểm tra sau:
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
}
Và đừng quên yêu cầu trình phát của bạn dừng lại khi đến cuối:
self.player.actionAtItemEnd = AVPlayerActionAtItemEndPause;
AVPlayerItemFailedToPlayToEndTimeNotification
. Nếu lỗi này xảy ra, sẽ không bao giờ đến thời điểm kết thúc. Hoặc đọc câu trả lời của maz, thêm vào mã của bạn một kiểm tra player.error != nil
, trong trường hợp phát lại đã "kết thúc" do lỗi.
AVPlayerItemDidPlayToEndTimeNotification
?
Đối với Swift :
AVPlayer :
let player = AVPlayer(URL: NSURL(string: "http://www.sample.com/movie.mov"))
if (player.rate != 0 && player.error == nil) {
println("playing")
}
Cập nhật :
player.rate > 0
điều kiện được thay đổi thành player.rate != 0
vì nếu video đang phát ngược lại, nó có thể là tiêu cực, cảm ơn Julian đã chỉ ra.
Lưu ý : Câu trả lời này có thể giống như câu trả lời ở trên (của Maz) nhưng trong Swift '! Player.error' đã cho tôi lỗi trình biên dịch, vì vậy bạn phải kiểm tra lỗi khi sử dụng 'player.error == nil' trong Swift. (Vì thuộc tính lỗi không thuộc loại 'Bool')
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
), vì -1.0 nhỏ hơn 0.
Tiện ích mở rộng Swift dựa trên câu trả lời của maz
extension AVPlayer {
var isPlaying: Bool {
return ((rate != 0) && (error == nil))
}
}
Câu trả lời của maxkonovalov trong phiên bản Swift là:
player.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions.New, context: nil)
và
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")
}
}
}
}
Cảm ơn bạn maxkonovalov!
nil
! Nhưng tôi cần biết khi nào chế độ xem bắt đầu (không kết thúc). Bất kỳ cách nào để làm điều đó?
Câu trả lời là Mục tiêu 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