ตรวจสอบสถานะการเล่นของ AVPlayer


คำตอบ:


57

หากต้องการรับการแจ้งเตือนเมื่อไปถึงจุดสิ้นสุดของรายการ (ผ่านApple ):

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

และในการติดตามการเล่นคุณสามารถ:

"ติดตามการเปลี่ยนแปลงตำแหน่งของตัวชี้ตำแหน่งในออบเจ็กต์ AVPlayer" โดยใช้addPeriodicTimeObserverForInterval: que: usingBlock:หรือaddBoundaryTimeObserverForTimes: que: usingBlock:usingBlock:

ตัวอย่างมาจาก 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];
}];

คุณสามารถโยนธงบูลีนเพื่อตรวจสอบสถานะการเล่น
moonman239

การแจ้งเตือนอาจทำให้เกิดปัญหาหากคุณเปลี่ยนไอเท็มของผู้เล่นเช่นมี-replaceCurrentItemWithPlayerItem:และจัดการไม่ถูกต้อง วิธีที่น่าเชื่อถือกว่าสำหรับฉันคือการติดตามAVPlayerสถานะโดยใช้ KVO ดูคำตอบของฉันด้านล่างสำหรับรายละเอียดเพิ่มเติม: stackoverflow.com/a/34321993/3160561
maxkonovalov

2
ต้องการการแจ้งเตือนข้อผิดพลาดหรือไม่? AVPlayerItemFailedToPlayToEndTimeNotification
ToolmakerSteve

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
ไม่จำเป็นว่ามันไม่ได้จัดการกับสถานการณ์ที่ผู้เล่นหยุดชะงักเนื่องจากข้อผิดพลาดในไฟล์ มีบางอย่างที่ฉันพบวิธีที่ยากลำบาก ...
Dermot

7
ดังที่ Dermot กล่าวไว้หากคุณพยายามเล่นอะไรบางอย่างขณะอยู่ในโหมดเครื่องบินอัตรา AVPlayer จะยังคงตั้งเป็น 1.0 เนื่องจากแสดงถึงความตั้งใจที่จะเล่น
phi

4
AVPlayer มีคุณสมบัติข้อผิดพลาดเพียงตรวจสอบว่าไม่ใช่ศูนย์และการตรวจสอบอัตราไม่ใช่ 0 :)
James Campbell

23
โปรดทราบว่าคำตอบได้รับการอัปเดตเพื่อป้องกันสถานการณ์ @Dermot อันนี้ใช้งานได้จริง
jomafer

2
จะไม่ทำงานเมื่อเล่นภาพวิดีโอย้อนกลับ ( - [AVPlayer setRate:-1.0]) เนื่องจาก-1.0น้อยกว่า 0
Julian 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)
    }
}

สำหรับคำถามที่สองของคุณหากต้องการทราบว่า 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

2
@objc func didPlayToEnd () สำหรับ Swift 4.2
Sean Stayns

21

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หรือไม่


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

BTW คุณพบว่าอะไร "ไม่น่าเชื่อถือ" เกี่ยวกับการใช้ NSNotification ของAVPlayerItemDidPlayToEndTimeNotification?
ToolmakerSteve

ToolmakerSteve ขอบคุณสำหรับบันทึกของคุณเพิ่มการตรวจสอบข้อผิดพลาดในคำตอบของฉัน สำหรับการแจ้งเตือนที่ไม่น่าเชื่อถือ - ฉันพบปัญหาด้วยตัวเองในขณะที่ใช้มุมมองผู้เล่นที่ทำซ้ำและใช้ซ้ำได้ในมุมมองคอลเลกชันและ KVO ทำให้สิ่งต่างๆชัดเจนยิ่งขึ้นเนื่องจากอนุญาตให้เก็บข้อมูลทั้งหมดไว้ในเครื่องได้มากขึ้นโดยไม่มีการแจ้งเตือนของผู้เล่นที่แตกต่างกันรบกวนซึ่งกันและกัน
maxkonovalov

17

สำหรับSwift :

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' ให้ข้อผิดพลาดของคอมไพเลอร์ดังนั้นคุณต้องตรวจสอบข้อผิดพลาดโดยใช้ 'player.error == nil' ใน Swift (เนื่องจากคุณสมบัติข้อผิดพลาด ไม่ใช่ประเภท '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
   }
}

2
AVPlayer! = AVAudioPlayer
quemeful

2
คำเตือน: ทั้งหมดที่กล่าวมาข้างต้นในคำตอบที่ปรากฏขึ้นสองปีก่อนหน้านี้
Dan Rosenstark

1
@Yar ฉันรู้ว่ายังเพิ่มคะแนนให้กับคำตอบข้างต้น แต่นี่เป็นคำตอบที่รวดเร็วและใน Swift '! player.error' ไม่ได้ผลสำหรับฉันมันได้รับอนุญาตสำหรับประเภทบูลเท่านั้นดังนั้นฉันจึงเพิ่มคำตอบ oops โหวตความคิดเห็นของคุณโดยไม่ได้ตั้งใจเพื่อตอบกลับโดยใช้ นี้แตกล้นแอป :)
Aks

ข้อกังวลของฉันคือฉันไม่รู้ว่าผู้เล่นดีแค่ไหนข้อผิดพลาดที่ไม่มีการใช้งานจริง
Dan Rosenstark

1
จะไม่ทำงานเมื่อเล่นภาพวิดีโอย้อนกลับ ( player.rate = -1.0) เนื่องจาก -1.0 น้อยกว่า 0
Julian F. Weinert


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!


สวัสดีคุณ Stanev ขอบคุณสำหรับคำตอบของคุณ สิ่งนี้ไม่ได้ผลสำหรับฉัน (aka ไม่พิมพ์อะไรในคอนโซล?)
Cesare

ไม่เป็นไรมันใช้งานได้ - ผู้เล่นของฉันเป็นnil! แต่ฉันต้องรู้ว่าเมื่อใดที่มุมมองเริ่มต้น (ไม่สิ้นสุด) จะทำอย่างไรก็ได้
Cesare

3

ขณะนี้มี swift 5 วิธีที่ง่ายที่สุดในการตรวจสอบว่าผู้เล่นกำลังเล่นอยู่หรือหยุดชั่วคราวคือการตรวจสอบตัวแปร. timeControlStatus

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

1

คำตอบคือ Objective 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
}

0
player.timeControlStatus == AVPlayer.TimeControlStatus.playing

1
คำตอบที่ให้ไว้นี้อาจจะถูกต้อง แต่มันจะได้ประโยชน์จากคำอธิบาย คำตอบที่ใช้โค้ดเท่านั้นไม่ถือว่าเป็นคำตอบที่ "ดี" คำแนะนำบางประการสำหรับฉันจะเขียนคำตอบที่ดีได้อย่างไร . จากรีวิว .
MyNameIsCaleb
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.