AVPlayer की प्ले स्थिति जांचें


106

क्या यह जानने का कोई तरीका है कि क्या एक AVPlayerप्लेबैक रुक गया है या अंत तक पहुंच गया है?

जवाबों:


57

किसी आइटम के अंत तक पहुंचने के लिए अधिसूचना प्राप्त करना ( Apple के माध्यम से ):

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

और खेलने के लिए ट्रैक कर सकते हैं:

"एवीप्लेयर ऑब्जेक्ट में प्लेहेड की स्थिति में परिवर्तन को ट्रैक करें" का उपयोग करके addPeriodicTimeObserverForInterval: कतार: usingBlock: या addBoundaryTimeObserverForTimesTimes AVPlayer

उदाहरण 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:, और इसे ठीक से हैंडल नहीं करने पर सूचनाएँ समस्याएँ पैदा कर सकती हैं । मेरे लिए एक अधिक विश्वसनीय तरीका AVPlayerकेवीओ का उपयोग करके स्थिति को ट्रैक करना है । अधिक जानकारी के लिए नीचे दिए गए मेरे जवाब देखें: stackoverflow.com/a/34321993/3160561
maxkonovalov

2
इसके अलावा त्रुटि की सूचना की आवश्यकता है? AVPlayerItemFailedToPlayToEndTimeNotification
टूलमेकरसेव

332

आप बता सकते हैं कि यह प्रयोग करके खेल रहा है:

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

स्विफ्ट 3 एक्सटेंशन:

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

29
जरूरी नहीं कि, यह उन परिस्थितियों को नहीं संभालता है जहां खिलाड़ी फाइल में त्रुटि के कारण स्टॉल करता है। मुझे कुछ कठिन तरीके से पता चला ...
Dermot

7
जैसा कि डरमोट ने कहा, यदि आप हवाई जहाज मोड में कुछ खेलने की कोशिश करते हैं, तो AVPlayer की दर अभी भी 1.0 पर सेट है, क्योंकि यह खेलने के इरादे का अर्थ है।
फि

4
AVPlayer के पास एक त्रुटि संपत्ति है, बस जांचें कि यह शून्य नहीं है और साथ ही दर की जाँच नहीं है 0 :)
जेम्स कैम्पबेल

23
ध्यान दें कि उत्तर @Dermot परिदृश्य को रोकने के लिए अद्यतन किया गया है। तो यह वास्तव में काम करता है।
जॉम्फर

2
वीडियो फुटेज को उल्टा चलाने पर काम नहीं किया जाएगा ( - [AVPlayer setRate:-1.0]), क्योंकि -1.00. से कम है
जूलियन एफ। वेनर्ट

49

IOS10 में, अब इसके लिए एक अंतर्निहित संपत्ति है: timeControlStatus

उदाहरण के लिए, यह फ़ंक्शन खेलता है या यह स्थिति के आधार पर एवीलेयर को रोक देता है और प्ले / पॉज़ बटन को उचित रूप से अपडेट करता है।

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

आपके दूसरे प्रश्न के रूप में, यह जानने के लिए कि क्या एवरप्ले अंत तक पहुँच गया है, सबसे आसान काम एक अधिसूचना स्थापित करना होगा।

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 का उपयोग करते हैं, तो नियंत्रण में निर्मित होते हैं।


आसान 10+ iOS के लिए उपयोग करने के लिए
technerd

2
@objc func didPlayToEnd () स्विफ्ट 4.2 के लिए
सीन

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, जिसमें त्रुटि के कारण प्लेबैक "समाप्त" हो गया है।
टूलमेकरसेव

BTW, NSNotification का उपयोग करने के बारे में आपको "विश्वसनीय नहीं" क्या मिला AVPlayerItemDidPlayToEndTimeNotification?
टूलमेकरसेव

ToolmakerSteve, आपके नोट के लिए धन्यवाद, मेरे उत्तर में त्रुटि की जाँच करें। विश्वसनीय सूचनाओं के लिए - मैं संग्रह के दृश्य में दोहराए जाने वाले और पुन: प्रयोज्य खिलाड़ियों के विचारों को लागू करते समय स्वयं इस मुद्दे पर आया, और केवीओ ने चीजों को और अधिक स्पष्ट किया, क्योंकि इसने सभी खिलाड़ियों को एक-दूसरे के साथ हस्तक्षेप किए बिना सभी अधिक स्थानीय रखने की अनुमति दी।
मैक्सकोनोवालोव

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क्योंकि अगर वीडियो रिवर्स में खेल रहा है तो यह जूलियन को इंगित करने के लिए नकारात्मक धन्यवाद हो सकता है।
नोट : यह ऊपर (Maz's) उत्तर के समान दिखाई दे सकता है, लेकिन 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
कैविट्स: सभी इस उत्तर में ऊपर वर्णित हैं जो इस एक से दो साल पहले दिखाई दिए थे।
दान रोसेनस्टार्क

1
@ यार मुझे पता है कि उत्तर के ऊपर भी उत्कीर्ण किया गया था, लेकिन यह स्विफ्ट और स्विफ्ट के लिए है '! खिलाड़ी' शेर 'मेरे लिए काम नहीं कर रहा था यह केवल बूल प्रकारों के लिए अनुमति है इसलिए मैंने उत्तर दिया है ऊप्स ने आपकी टिप्पणी को गलत तरीके से उत्तर दिया है। यह स्टैक ओवरफ्लो ऐप :)
अक्स

मेरी चिंता यह है कि मैं नहीं जानता कि खिलाड़ी.नियर वास्तव में काम नहीं करता है।
दान रोसेनस्टार्क

1
वीडियो फुटेज को उल्टा चलाने पर काम नहीं होगा ( player.rate = -1.0), क्योंकि -1.0 0. से कम है
जूलियन एफ। वेनर्ट

9

Maz द्वारा जवाब के आधार पर स्विफ्ट विस्तार

extension AVPlayer {

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

6

Maxkonovalov के उत्तर का स्विफ्ट संस्करण यह है:

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

धन्यवाद मैक्सकोनोवालोव!


हेलो मिस्टर स्टेनव, आपके उत्तर के लिए धन्यवाद। यह मेरे लिए काम नहीं करता है (उर्फ कंसोल में कुछ भी प्रिंट नहीं करता है?)
Cesare

कोई बात नहीं, यह काम करता है - मेरा खिलाड़ी था nil! लेकिन मुझे यह जानना चाहिए कि जब दृश्य शुरू होता है (समाप्त नहीं होता है)। ऐसा करने का कोई तरीका?
Cesare

3

वर्तमान में तेजी से 5 अगर खिलाड़ी खेल रहे हैं या रुका हुआ है की जाँच करने के लिए सबसे आसान तरीका के साथ जांच करने के लिए है .timeControlStatus चर।

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

1

उत्तर उद्देश्य सी है

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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.