iOS AVPlayer視頻播放器

代碼地址以下:
http://www.demodashi.com/demo/11168.htmlhtml

1、運行效果

總效果.gif

2、實現過程

①、建立播放器avPlayer

//建立播放器
        url = [url stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
        AVPlayer *player = [AVPlayer playerWithURL:[NSURL URLWithString:url]];
        self.avPlayer = player;

②、建立顯示屏_videoLayer

- (void)createDisplay{

    // 顯示圖像的
    _videoLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
    //錨點的座標
    _videoLayer.position = CGPointMake(KPLAYVIEWWIDTH/2, KPLAYVIEWHEIGHT/2);
    _videoLayer.bounds = CGRectMake(0, 0, KPLAYVIEWWIDTH, KPLAYVIEWHEIGHT);
    // 錨點,值只能是0,1之間
    _videoLayer.anchorPoint = CGPointMake(0.5, 0.5);
    
    //     AVLayerVideoGravityResizeAspect 按比例壓縮,視頻不會超出Layer的範圍(默認)
    //     AVLayerVideoGravityResizeAspectFill 按比例填充Layer,不會有黑邊
    //     AVLayerVideoGravityResize 填充整個Layer,視頻會變形
    //     視頻內容拉伸的選項
    _videoLayer.videoGravity = AVLayerVideoGravityResizeAspect;
    //    //播放時,視頻實際佔的區域
    //    NSLog(@"%@", NSStringFromCGRect(videoLayer.videoRect));
    
    //Layer只能添加到Layer上面
    [self.displayView.layer addSublayer:_videoLayer];
}

③、添加觀察者和通知,用於監測更新視頻播放的狀態、進度、屏幕方向、狀態欄屬性、音量等等。

主要代碼以下:網絡

//監測屏幕旋轉
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
    
    //添加AVPlayerItem播放結束通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.avPlayer.currentItem];
    
    //添加AVPlayerItem開始緩衝通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(bufferStart:) name:AVPlayerItemPlaybackStalledNotification object:self.avPlayer.currentItem];

//KOV監控 播放器進度更新
- (void)addObserverForAVPlayer
{
    AVPlayerItem *playerItem = self.avPlayer.currentItem;
    
    // 給AVPlayer添加觀察者 必須實現 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
    
    //監控播放速率
    [self.avPlayer addObserver:self forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:nil];
    //監控狀態屬性(AVPlayer也有一個status屬性,經過監控它的status也能夠得到播放狀態)
    [playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    //監控網絡加載緩衝狀況屬性
    [playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    //監控是否可播放
    [playerItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
    
    
    //播放進度觀察者  //設置每0.1秒執行一次
    __weak GOVVideoView *weakSelf = self;
    _playerTimeObserver =  [self.avPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 10.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
        
        if (weakSelf.dragSlider) {
            return ;
        }
        
        CGFloat current = CMTimeGetSeconds(time);
        weakSelf.current = current;
        CMTime totalTime = weakSelf.avPlayer.currentItem.duration;
        CGFloat total = CMTimeGetSeconds(totalTime);
        weakSelf.total = total;
        weakSelf.slider.value = current/total;
        weakSelf.currentTimeLabel.text = [weakSelf timeFormatted:current];
        weakSelf.totalTimeLabel.text = [NSString stringWithFormat:@"/%@",[weakSelf timeFormatted:total]] ;
        
    }];
}

//經過KVO監控回調
//keyPath 監控屬性 object 監視器 change 狀態改變 context 上下文
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    
    if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
        
        //監控網絡加載狀況屬性
        NSArray *array = self.avPlayer.currentItem.loadedTimeRanges;
        //本次緩衝時間範圍
        CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];
        CGFloat startSeconds = CMTimeGetSeconds(timeRange.start);
        CGFloat durationSeconds = CMTimeGetSeconds(timeRange.duration);
        //現有緩衝總長度
        CGFloat totalBuffer = startSeconds + durationSeconds;
        //視頻總時長
        CMTime totalTime = self.avPlayer.currentItem.duration;
        CGFloat total = CMTimeGetSeconds(totalTime);
        if (totalBuffer/total <= 1.0 ) {
            [self.progressView setProgress:totalBuffer/total animated:YES];
        }
        
    }else if([keyPath isEqualToString:@"playbackLikelyToKeepUp"]){
        
        if (self.avPlayer.currentItem.playbackLikelyToKeepUp == YES) {
            
            if (_activityView != nil) {
                [self.activityView startAnimating];
                [self.activityView removeFromSuperview];
                _activityView = nil;
            }
        }
    }else if ([keyPath isEqualToString:@"status"]){
        
        //監控狀態屬性
        AVPlayerStatus status = [[change objectForKey:@"new"] intValue];
        
        switch ((status)) {
            case AVPlayerStatusReadyToPlay:
                
                break;
            case AVPlayerStatusUnknown:
                
                break;
            case AVPlayerStatusFailed:
                
                break;
                
        }
    }else if ([keyPath isEqualToString:@"rate"]){
        if (self.avPlayer.rate == 1) {
        }
    }
    
}

隱藏/顯示狀態欄的方法:

[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];這個方法在iOS9以後棄用了,而且須要
將View controller-based status bar appearance設置爲NO;而下面的重寫方法須要將View controller-based status bar appearance設置爲YES,這個方法在iOS7以後就有了;
//刷新狀態欄狀態
[self setNeedsStatusBarAppearanceUpdate];app

#pragma mark -- 隱藏/顯示狀態欄的方法
/*[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];這個方法在iOS9以後棄用了,而且須要
 將View controller-based status bar appearance設置爲NO;而下面的重寫方法須要將View controller-based status bar appearance設置爲YES,這個方法在iOS7以後就有了;
//刷新狀態欄狀態
 [self setNeedsStatusBarAppearanceUpdate];
 */
//設置樣式
- (UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}
//設置是否隱藏
- (BOOL)prefersStatusBarHidden {
    return self.isHiddenStatusBar;
}
//設置隱藏動畫
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
    return UIStatusBarAnimationNone;
}

④、建立用於處理播放結束、關閉播放器、全屏/退出全屏、隱藏/展現footBar和topBar的Block回調方法和代理方法,方便用戶作些自定義的操做。

//Block回調方法
typedef void(^FullScreenBlock)(BOOL isFull);

typedef void(^ClosePLayerBlock)();

typedef void(^ShowBarBlock)(BOOL isShow);

typedef void(^PlayFinishedBlock)();

@class GOVVideoPlayer;
//代理方法
@protocol GOVVideoPlayerDelegate  <NSObject>

//播放結束
- (void)videoPlayerPlayFinished:(GOVVideoPlayer *)videoPlayer;

//關閉播放器
- (void)videoPlayerClosePlayer:(GOVVideoPlayer *)videoPlayer;

//全屏按鈕
- (void)videoPlayerFullScreen:(GOVVideoPlayer *)videoPlayer withIsFull:(BOOL)isFull;

//隱藏/展現footBar和topBar
- (void)videoPlayerShowBar:(GOVVideoPlayer *)videoPlayer withIsShow:(BOOL)isShow;

3、項目結構圖

項目結構圖

4、補充

GOVVideoPlayer是在繼承於UIView的基礎上封裝的視頻View;
GOVVideoController是在繼承於UIViewController的基礎上封裝的視頻視圖控制器。
二者最大的不一樣是在全屏和取消全屏的處理上面:前者是一個視圖View,能夠直接加在父視圖上面,全屏時是加在 [UIApplication sharedApplication].keyWindow上的,然後者,小屏時是取GOVVideoController的View加在父視圖上,全屏和取消全屏時是採用present和dismiss模態化轉場的方法 。ide

iOS AVPlayer視頻播放器動畫

代碼地址以下:
http://www.demodashi.com/demo/11168.htmlurl

注:本文著做權歸做者,由demo大師代發,拒絕轉載,轉載須要做者受權spa

相關文章
相關標籤/搜索