2012-01-04 21 views
14

AVPlayer के लिए टाइमलाइन प्रगति पट्टी पूरी तरह से अनुकूलन योग्य है, दुर्भाग्य से समय रेखा प्रगति पट्टी दिखाने के लिए AVPlayer में सुविधाजनक तरीके हैं।AVPlayer

AVPlayer *player = [AVPlayer playerWithURL:URL]; 
AVPlayerLayer *playerLayer = [[AVPlayerLayer playerLayerWithPlayer:avPlayer] retain];[self.view.layer addSubLayer:playerLayer]; 

मैं एक प्रगति बार इंगित करता है कि कैसे वीडियो खेला गया है, और कितना अभी MPMoviePlayer की तरह के रूप में बने रहे।

तो प्रगति बार

मुझे सुझाएँ अद्यतन करने के लिए AVPlayer और कैसे से वीडियो के समय मिलता है।

+1

AVPlayerViewController उपयोग करने पर विचार करें। प्लेबैक करना बहुत आसान है (लेकिन आपकी ज़रूरतों को पूरा नहीं कर सकता है।)। बस अगर आप इसके बारे में पता नहीं हैं तो कह रहे हैं। (संपादित करें) - ओह यह तीन साल पहले है: पी। –

उत्तर

21

नीचे कोड जहाँ से सेब उदाहरण कोड "AVPlayerDemo" है का उपयोग करें है।

double interval = .1f; 

    CMTime playerDuration = [self playerItemDuration]; // return player duration. 
    if (CMTIME_IS_INVALID(playerDuration)) 
    { 
     return; 
    } 
    double duration = CMTimeGetSeconds(playerDuration); 
    if (isfinite(duration)) 
    { 
     CGFloat width = CGRectGetWidth([yourSlider bounds]); 
     interval = 0.5f * duration/width; 
    } 

    /* Update the scrubber during normal playback. */ 
    timeObserver = [[player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(interval, NSEC_PER_SEC) 
                  queue:NULL 
                usingBlock: 
                 ^(CMTime time) 
                 { 
                  [self syncScrubber]; 
                 }] retain]; 


- (CMTime)playerItemDuration 
{ 
    AVPlayerItem *thePlayerItem = [player currentItem]; 
    if (thePlayerItem.status == AVPlayerItemStatusReadyToPlay) 
    {   

     return([playerItem duration]); 
    } 

    return(kCMTimeInvalid); 
} 

और सिंक में स्क्रूबर विधि UISlider या UIProgressBar मान को अद्यतन करती है।

- (void)syncScrubber 
{ 
    CMTime playerDuration = [self playerItemDuration]; 
    if (CMTIME_IS_INVALID(playerDuration)) 
    { 
     yourSlider.minimumValue = 0.0; 
     return; 
    } 

    double duration = CMTimeGetSeconds(playerDuration); 
    if (isfinite(duration) && (duration > 0)) 
    { 
     float minValue = [ yourSlider minimumValue]; 
     float maxValue = [ yourSlider maximumValue]; 
     double time = CMTimeGetSeconds([player currentTime]); 
     [yourSlider setValue:(maxValue - minValue) * time/duration + minValue]; 
    } 
} 
+0

परिवर्तनीय समय ऑब्सर्वर क्या है? –

+0

आपको वास्तव में 'पर्यवेक्षण' रद्द करने के लिए ऑब्सर्वर की आवश्यकता है और जब तक आप देखना चाहते हैं, तब भी आपको इसे बनाए रखने की आवश्यकता है ..आप ऐप्पल डॉकू को addPeriodicTimeObserverForInterval के बारे में पढ़ सकते हैं: कतार: उपयोगब्लॉक: –

1

समय के लिए मैं इस

-(void)changeSliderValue { 

double duration = CMTimeGetSeconds(self.player.currentItem.duration); 

[lengthSlider setMaximumValue:(float)duration]; 

lengthSlider.value = CMTimeGetSeconds([self.player currentTime]); 

int seconds = lengthSlider.value,minutes = seconds/60,hours = minutes/60; 

int secondsRemain = lengthSlider.maximumValue - seconds,minutesRemain = secondsRemain/60,hoursRemain = minutesRemain/60; 

seconds = seconds-minutes*60; 

minutes = minutes-hours*60; 

secondsRemain = secondsRemain - minutesRemain*60; 

minutesRemain = minutesRemain - hoursRemain*60; 

NSString *hourStr,*minuteStr,*secondStr,*hourStrRemain,*minuteStrRemain,*secondStrRemain; 

hourStr = hours > 9 ? [NSString stringWithFormat:@"%d",hours] : [NSString stringWithFormat:@"0%d",hours]; 

minuteStr = minutes > 9 ? [NSString stringWithFormat:@"%d",minutes] : [NSString stringWithFormat:@"0%d",minutes]; 

secondStr = seconds > 9 ? [NSString stringWithFormat:@"%d",seconds] : [NSString stringWithFormat:@"0%d",seconds]; 

hourStrRemain = hoursRemain > 9 ? [NSString stringWithFormat:@"%d",hoursRemain] : [NSString stringWithFormat:@"0%d",hoursRemain]; 

minuteStrRemain = minutesRemain > 9 ? [NSString stringWithFormat:@"%d",minutesRemain] : [NSString stringWithFormat:@"0%d",minutesRemain]; 

secondStrRemain = secondsRemain > 9 ? [NSString stringWithFormat:@"%d",secondsRemain] : [NSString stringWithFormat:@"0%d",secondsRemain]; 

timePlayed.text = [NSString stringWithFormat:@"%@:%@:%@",hourStr,minuteStr,secondStr]; 

timeRemain.text = [NSString stringWithFormat:@"-%@:%@:%@",hourStrRemain,minuteStrRemain,secondStrRemain]; 

और आयात CoreMedia ढांचे

lengthSlider UISlider

+0

मैं यूआरएल से गाना बज रहा हूं। लेकिन सीएमटाइम अवधि और सीएमटाइम चालू समय पर मुझे 0 मिल रहा है। 0 मूल्य के लिए यहां समस्या क्या है? क्या आप समाधान जानते हैं? – Moxarth

+0

यहां इस बारे में प्रलेखन है: https://developer.apple.com/documentation/avfoundation/avplayeritem/1389386- अवधि –

+0

कि अवधि कोड ने मेरी सहायता नहीं की है। – Moxarth

16

कोड के लिए iOSPawan धन्यवाद! मैंने जरूरी लाइनों को कोड सरलीकृत किया। यह अवधारणा को समझने के लिए और अधिक स्पष्ट हो सकता है। असल में मैंने इसे इस तरह कार्यान्वित किया है और यह ठीक काम करता है।

__weak NSObject *weakSelf = self;  
[_player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(1.0/60.0, NSEC_PER_SEC) 
             queue:NULL 
           usingBlock:^(CMTime time){ 
               [weakSelf updateProgressBar]; 
              }]; 

[_player play]; 

तो फिर आप अपने प्रगति बार अद्यतन करने के लिए एक विधि की आवश्यकता है:

वीडियो शुरू करने से पहले

- (void)updateProgressBar 
{ 
    double duration = CMTimeGetSeconds(_playerItem.duration); 
    double time = CMTimeGetSeconds(_player.currentTime); 
    _progressView.progress = (CGFloat) (time/duration); 
} 
+0

आप यहां __block का दुरुपयोग कर रहे हैं। ब्लॉक में चर के लिए असाइनमेंट का उपयोग करने की आवश्यकता होने पर __block का उपयोग किया जाता है। आप शायद __weak – kball

+0

का उपयोग करने के लिए मतलब है अपना कोड अपडेट किया है। लेकिन इसके अतिरिक्त - आपको addPeriodicTimeObserverForInterval द्वारा दिए गए ऑब्जेक्ट का संदर्भ रखना होगा: इसके लिए संदेश भेजने जारी रखने के लिए और ताकि आप इसे बाद में हटा सकें। https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVPlayer_Class/#//apple_ref/occ/instm/AVPlayer/addPeriodicTimeObserverForInterval:queue:usingBlock: – kball

+0

टाइम ओब्सर्वर को '@result खेलना बंद करने के बाद हटा दिया जाना चाहिए \t एनएसओब्जेक्ट प्रोटोकॉल के अनुरूप एक वस्तु। जब तक आप खिलाड़ी द्वारा समय पर्यवेक्षक को बुलाया जाना चाहते हैं, तब तक आपको यह लौटाया मूल्य बनाए रखना होगा। \t इस ऑब्जेक्ट को -removeTimeObserver पर पास करें: समय अवलोकन को रद्द करने के लिए। – Leo

4
let progressView = UIProgressView(progressViewStyle: UIProgressViewStyle.Bar) 
    self.view.addSubview(progressView) 
    progressView.constrainHeight("\(1.0/UIScreen.mainScreen().scale)") 
    progressView.alignLeading("", trailing: "", toView: self.view) 
    progressView.alignBottomEdgeWithView(self.view, predicate: "") 
    player.addPeriodicTimeObserverForInterval(CMTimeMakeWithSeconds(1/30.0, Int32(NSEC_PER_SEC)), queue: nil) { time in 
     let duration = CMTimeGetSeconds(playerItem.duration) 
     progressView.progress = Float((CMTimeGetSeconds(time)/duration)) 
    } 
1

मेरे मामले में, निम्न कोड काम करता है स्विफ्ट 3:

var timeObserver: Any? 
override func viewDidLoad() { 
    ........ 
    let interval = CMTime(seconds: 0.05, preferredTimescale: CMTimeScale(NSEC_PER_SEC)) 
    timeObserver = avPlayer.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using: { elapsedTime in 
      self.updateSlider(elapsedTime: elapsedTime)  
     }) 
} 

func updateSlider(elapsedTime: CMTime) { 
    let playerDuration = playerItemDuration() 
    if CMTIME_IS_INVALID(playerDuration) { 
     seekSlider.minimumValue = 0.0 
     return 
    } 
    let duration = Float(CMTimeGetSeconds(playerDuration)) 
    if duration.isFinite && duration > 0 { 
     seekSlider.minimumValue = 0.0 
     seekSlider.maximumValue = duration 
     let time = Float(CMTimeGetSeconds(elapsedTime)) 
     seekSlider.setValue(time, animated: true) 
    } 
} 

private func playerItemDuration() -> CMTime { 
    let thePlayerItem = avPlayer.currentItem 
    if thePlayerItem?.status == .readyToPlay { 
     return thePlayerItem!.duration 
    } 
    return kCMTimeInvalid 
} 

override func viewDidDisappear(_ animated: Bool) { 
    super.viewDidDisappear(animated) 
    avPlayer.removeTimeObserver(timeObserver!) 
} 
0

मैंने जवाब एफ रोम IOSSPawan और राफेल और फिर मेरी जरूरतों के अनुरूप। तो मेरे पास संगीत और UIProgressView है जो हमेशा लूप में होता है और जब आप अगली स्क्रीन पर जाते हैं और गीत वापस आते हैं और बार जारी रहता है जहां वे छोड़े गए थे।

कोड:

@interface YourClassViewController(){ 

    NSObject * periodicPlayerTimeObserverHandle; 
} 
@property (nonatomic, strong) AVPlayer *player; 
@property (nonatomic, strong) UIProgressView *progressView; 

-(void)viewWillAppear:(BOOL)animated{ 
    [super viewWillAppear:animated]; 

    if(_player != nil && ![self isPlaying]) 
    { 
     [self musicPlay]; 
    } 
} 


-(void)viewWillDisappear:(BOOL)animated 
{ 
    [super viewWillDisappear:animated]; 

    if (_player != nil) { 

     [self stopPlaying]; 
    } 
} 

// ---------- 
//  PLAYER 
// ---------- 

-(BOOL) isPlaying 
{ 
    return ([_player rate] > 0); 
} 

-(void) musicPlay 
{ 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(playerItemDidReachEnd:) 
               name:AVPlayerItemDidPlayToEndTimeNotification 
               object:[_player currentItem]]; 

    __weak typeof(self) weakSelf = self; 
    periodicPlayerTimeObserverHandle = [_player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(1.0/60.0, NSEC_PER_SEC) 
                      queue:NULL 
                     usingBlock:^(CMTime time){ 
                      [weakSelf updateProgressBar]; 
                     }]; 
    [_player play]; 
} 


-(void) stopPlaying 
{ 
    @try { 

     if(periodicPlayerTimeObserverHandle != nil) 
     { 
      [_player removeTimeObserver:periodicPlayerTimeObserverHandle]; 
      periodicPlayerTimeObserverHandle = nil; 
     } 

     [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil]; 
     [_player pause]; 
    } 
    @catch (NSException * __unused exception) {} 
} 


-(void) playPreviewSong:(NSURL *) previewSongURL 
{ 
    [self configureAVPlayerAndPlay:previewSongURL]; 
} 


-(void) configureAVPlayerAndPlay: (NSURL*) url { 

    if(_player) 
     [self stopPlaying]; 

    AVAsset *audioFileAsset = [AVURLAsset URLAssetWithURL:url options:nil]; 
    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:audioFileAsset]; 
    _player = [AVPlayer playerWithPlayerItem:playerItem]; 
    [_player addObserver:self forKeyPath:@"status" options:0 context:nil]; 

    CRLPerformBlockOnMainThreadAfterDelay(^{ 
     NSError *loadErr; 
     if([audioFileAsset statusOfValueForKey:@"playable" error:&loadErr] == AVKeyValueStatusLoading) 
     { 
      [audioFileAsset cancelLoading]; 
      [self stopPlaying]; 
      [self showNetworkError:NSLocalizedString(@"Could not play file",nil)]; 
     } 
    }, NETWORK_REQUEST_TIMEOUT); 
} 


- (void)updateProgressBar 
{ 

    double currentTime = CMTimeGetSeconds(_player.currentTime); 
    if(currentTime <= 0.05){ 
     [_progressView setProgress:(float)(0.0) animated:NO]; 
     return; 
    } 

    if (isfinite(currentTime) && (currentTime > 0)) 
    { 
     float maxValue = CMTimeGetSeconds(_player.currentItem.asset.duration); 
     [_progressView setProgress:(float)(currentTime/maxValue) animated:YES]; 
    } 
} 


-(void) showNetworkError:(NSString*)errorMessage 
{ 
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"No connection", nil) message:errorMessage preferredStyle:UIAlertControllerStyleAlert]; 
    [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { 
     // do nothing 
    }]]; 

    [self presentViewController:alert animated:YES completion:nil]; 
} 


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 

    if (object == _player && [keyPath isEqualToString:@"status"]) { 
     if (_player.status == AVPlayerStatusFailed) { 
      [self showNetworkError:NSLocalizedString(@"Could not play file", nil)]; 
     } else if (_player.status == AVPlayerStatusReadyToPlay) { 
      NSLog(@"AVPlayerStatusReadyToPlay"); 
      [TLAppAudioAccess setAudioAccess:TLAppAudioAccessType_Playback]; 
      [self musicPlay]; 

     } else if (_player.status == AVPlayerItemStatusUnknown) { 
      NSLog(@"AVPlayerItemStatusUnknown"); 
     } 
    } 
} 


- (void)playerItemDidReachEnd:(NSNotification *)notification { 

    if ([notification.object isEqual:self.player.currentItem]) 
    { 
     [self.player seekToTime:kCMTimeZero]; 
     [self.player play]; 
    } 
} 


-(void) dealloc{ 

    @try { 
     [_player removeObserver:self forKeyPath:@"status"]; 
    } 
    @catch (NSException * __unused exception) {} 
    [self stopPlaying]; 
    _player = nil; 
} 
संबंधित मुद्दे