1. 程式人生 > >AVPlayer自定義視訊播放器

AVPlayer自定義視訊播放器

我的avplayer播放器,能橫屏,豎屏,適應螢幕,上程式碼

1.我把我的那個最主要的類的.m的主要的程式碼附上

@implementation LDZMoviePlayerController


- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor blackColor];
    self.topProgressSlider.value = 0.0;
    [self addGestureRecognizer];
    //  新增觀察者
    [self addNotificationCenters];
    [self addAVPlayer];
}

- (void)addAVPlayer{
    playItem = [AVPlayerItem playerItemWithURL: self.movieURL];
    self.playerHelper = [[LDZAVPlayerHelper alloc] init];
    [_playerHelper initAVPlayerWithAVPlayerItem:playItem];
    //  建立顯示層
    self.playerLayer = [AVPlayerLayer playerLayerWithPlayer: _playerHelper.getAVPlayer];
    _playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
    //  豎屏的時候frame
    [self setVerticalFrame];
    //  這是視訊的填充模式, 預設為AVLayerVideoGravityResizeAspect
    _playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    //  插入到view層上面, 沒有用addSubLayer
    [self.view.layer insertSublayer:_playerLayer atIndex:0];
    //  新增進度觀察
    [self addProgressObserver];
    [self addObserverToPlayerItem: playItem];
}
//  播放頁面新增輕拍手勢
- (void)addGestureRecognizer {
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissAllSubViews:)];
    tap.delegate = self;
    [self.view addGestureRecognizer:tap];
}
#pragma mark - 觀察者 觀察播放完畢 觀察螢幕旋轉
- (void)addNotificationCenters {
    //  註冊觀察者用來觀察,是否播放完畢
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(moviePlayDidEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
    //  註冊觀察者來觀察螢幕的旋轉
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarOrientationChange:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
}
#pragma mark - 橫屏 豎屏的時候frame的設定
- (void)statusBarOrientationChange:(NSNotification *)notification {
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    if (orientation == UIInterfaceOrientationLandscapeRight) {
        [self setPlayerLayerFrame];
        self.isFirstRotatorTap = YES;
        [self setTopRightBottomFrame];
    }
    if (orientation == UIInterfaceOrientationLandscapeLeft) {
        [self setPlayerLayerFrame];
        self.isFirstRotatorTap = YES;
        [self setTopRightBottomFrame];
    }
    if (orientation == UIInterfaceOrientationPortrait) {
        //  豎屏的時候
        [self setVerticalFrame];
        self.isFirstRotatorTap = YES;
        [self setTopRightBottomFrame];
    }
}
//  橫屏的時候frame
- (void)setPlayerLayerFrame {
    CGRect frame = self.view.bounds;
    frame.origin.x = 20;
    frame.origin.y = (SCREEN_HEIGHT - SCREEN_HEIGHT * (SCREEN_WIDTH - 40) / SCREEN_WIDTH) / 2;
    frame.size.width = SCREEN_WIDTH - 40;
    frame.size.height = SCREEN_HEIGHT * (SCREEN_WIDTH - 40) / SCREEN_WIDTH;
    _playerLayer.frame = frame;
}
//  豎屏的時候frame
- (void)setVerticalFrame {
    CGRect frame = self.view.bounds;
    frame.origin.x = ZERO;
    frame.origin.y = (SCREEN_HEIGHT - SCREEN_WIDTH * (SCREEN_WIDTH / SCREEN_HEIGHT)) / 2;
    frame.size.width = SCREEN_WIDTH;
    frame.size.height = SCREEN_WIDTH * (SCREEN_WIDTH / SCREEN_HEIGHT);
    _playerLayer.frame = frame;
}

//  動畫(出現或隱藏top - right - bottom)
- (void)dismissAllSubViews:(UITapGestureRecognizer *)tap {
    [self setTopRightBottomFrame];
}
//  設定TopRightBottomFrame
- (void)setTopRightBottomFrame {
    __weak typeof (self) myself = self;
    if (!self.isFirstRotatorTap) {
        [UIView animateWithDuration:.2f animations:^{
            myself.topView.frame = CGRectMake(myself.topView.frame.origin.x, -TOPVIEW_HEIGHT, myself.topView.frame.size.width, myself.topView.frame.size.height);
            myself.rightView.frame = CGRectMake(SCREEN_WIDTH, myself.rightView.frame.origin.y, myself.rightView.frame.size.width, myself.rightView.frame.size.height);
            myself.verticalBottomView.frame = CGRectMake(myself.verticalBottomView.frame.origin.x, SCREEN_HEIGHT, myself.verticalBottomView.frame.size.width, myself.verticalBottomView.frame.size.height);
            myself.ratotarBottomView.frame = CGRectMake(myself.ratotarBottomView.frame.origin.x, SCREEN_HEIGHT, myself.ratotarBottomView.frame.size.width, myself.ratotarBottomView.frame.size.height);
        }];
        self.isFirstRotatorTap = YES;
    } else {
        [UIView animateWithDuration:.2f animations:^{
            myself.topView.frame = CGRectMake(myself.topView.frame.origin.x, ZERO, myself.topView.frame.size.width, myself.topView.frame.size.height);
            myself.rightView.frame = CGRectMake(SCREEN_WIDTH - RIGHT_WIDTH, myself.rightView.frame.origin.y, myself.rightView.frame.size.width, myself.rightView.frame.size.height);
            myself.verticalBottomView.frame = CGRectMake(myself.verticalBottomView.frame.origin.x, SCREEN_HEIGHT - VERTICAL_BOTTOM_HEIGHT, myself.verticalBottomView.frame.size.width, myself.verticalBottomView.frame.size.height);
            myself.ratotarBottomView.frame = CGRectMake(myself.ratotarBottomView.frame.origin.x, SCREEN_HEIGHT - ROTATOR_BOTTOM_HEIGHT, myself.ratotarBottomView.frame.size.width, myself.ratotarBottomView.frame.size.height);
        }];
        self.isFirstRotatorTap = NO;
    }
}
//  顯示top,right,bottom的View
- (void)setTopRightBottomViewHiddenToShow {
    _topView.hidden = NO;
    _rightView.hidden = NO;
    _ratotarBottomView.hidden = NO;
    _verticalBottomView.hidden = NO;
    _isFirstRotatorTap = NO;
}
//  隱藏top,right,bottom的View
- (void)setTopRightBottomViewShowToHidden {
    _topView.hidden = YES;
    _rightView.hidden = YES;
    _ratotarBottomView.hidden = YES;
    _verticalBottomView.hidden = YES;
    _isFirstRotatorTap = YES;
}
#pragma mark - 暫停
- (void)setMovieParse {
    [_playerHelper.getAVPlayer pause];
    isPlay = NO;
    //  因為用的是xib,不設定的話圖片會重合
    _verticalPlayButton.imageView.image = nil;
    _rotatorPlayButton.imageView.image = nil;
    [_verticalPlayButton setImage:[UIImage imageNamed:@"播放器_播放"] forState: UIControlStateNormal];
    [_rotatorPlayButton setImage:[UIImage imageNamed:@"播放器_播放"] forState:UIControlStateNormal];
}
#pragma mark - 播放
- (void)setMoviePlay {
    [_playerHelper.getAVPlayer play];
    isPlay = YES;
    //  因為用的是xib,不設定的話圖片會重合
    _verticalPlayButton.imageView.image = nil;
    _rotatorPlayButton.imageView.image = nil;
    [_verticalPlayButton setImage:[UIImage imageNamed:@"播放器_暫停"] forState: UIControlStateNormal];
    [_rotatorPlayButton setImage:[UIImage imageNamed:@"播放器_暫停"] forState:UIControlStateNormal];
}

#pragma mark -  新增進度觀察 - addProgressObserver
- (void)addProgressObserver {
    //  設定每秒執行一次
    [_playerHelper.getAVPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue: NULL usingBlock:^(CMTime time) {
NSLog(@"進度觀察 + %f", _topProgressSlider.value);
        //  獲取當前時間
        CMTime currentTime = _playerHelper.getAVPlayer.currentItem.currentTime;
        //  轉化成秒數
        CGFloat currentPlayTime = (CGFloat)currentTime.value / currentTime.timescale;
        //  總時間
        CMTime totalTime = playItem.duration;
        //  轉化成秒
        _totalMovieDuration = (CGFloat)totalTime.value / totalTime.timescale;
        //  相減後
        _topProgressSlider.value = CMTimeGetSeconds(currentTime) / _totalMovieDuration;
        progressSlider = CMTimeGetSeconds(currentTime) / _totalMovieDuration;
NSLog(@"%f", _topProgressSlider.value);
        NSDate *pastDate = [NSDate dateWithTimeIntervalSince1970: currentPlayTime];
         _topPastTimeLabel.text = [self getTimeByDate:pastDate byProgress: currentPlayTime];
        CGFloat remainderTime = _totalMovieDuration - currentPlayTime;
        NSDate *remainderDate = [NSDate dateWithTimeIntervalSince1970: remainderTime];
        _topRemainderLabel.text = [self getTimeByDate:remainderDate byProgress: remainderTime];
        if (_isFirstRotatorTap) {
            [self setTopRightBottomViewShowToHidden];
        } else {
            [self setTopRightBottomViewHiddenToShow];
        }
    }];
    //  設定topProgressSlider圖片
    UIImage *thumbImage = [UIImage imageNamed:@"slider-metal-handle.png"];
    [self.topProgressSlider setThumbImage:thumbImage forState:UIControlStateHighlighted];
    [self.topProgressSlider setThumbImage:thumbImage forState:UIControlStateNormal];
}

- (NSString *)getTimeByDate:(NSDate *)date byProgress:(float)current {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    if (current / 3600 >= 1) {
        [formatter setDateFormat:@"HH:mm:ss"];
    } else {
        [formatter setDateFormat:@"mm:ss"];
    }
    return [formatter stringFromDate:date];
}

- (void)addObserverToPlayerItem:(AVPlayerItem *)playerItem {
    [playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    [playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)removeObserverFromPlayerItem:(AVPlayerItem *)playerItem {
    [playerItem removeObserver:self forKeyPath:@"status"];
    [playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
}

//  觀察者的方法, 會在載入好後觸發, 可以在這個方法中, 儲存總檔案的大小, 用於後面的進度的實現
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    AVPlayerItem *playerItem = (AVPlayerItem *)object;
    if ([keyPath isEqualToString:@"status"]) {
        AVPlayerStatus status = [[change objectForKey:@"new"] intValue];
        if (status == AVPlayerStatusReadyToPlay) {
            NSLog(@"正在播放...,視訊總長度: %.2f",CMTimeGetSeconds(playerItem.duration));
            CMTime totalTime = playerItem.duration;
            self.totalMovieDuration = (CGFloat)totalTime.value / totalTime.timescale;
        }
    }
    if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
        NSArray *array = playerItem.loadedTimeRanges;
        //  本次緩衝時間範圍
        CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];
        float startSeconds = CMTimeGetSeconds(timeRange.start);
        float durationSeconds = CMTimeGetSeconds(timeRange.duration);
        //  緩衝總長度
        NSTimeInterval totalBuffer = startSeconds + durationSeconds;
//        NSLog(@"共緩衝%.2f", totalBuffer);
        NSLog(@"進度 + %f", progressSlider);
        self.topProgressSlider.value = progressSlider;
    }
}

#pragma mark - UIGestureRecognizerDelegate Method 方法
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    //  不讓子檢視響應點選事件
    if( CGRectContainsPoint(self.topView.frame, [gestureRecognizer locationInView:self.view]) || CGRectContainsPoint(self.rightView.frame, [gestureRecognizer locationInView:self.view]) || CGRectContainsPoint(self.ratotarBottomView.frame, [gestureRecognizer locationInView:self.view]) || CGRectContainsPoint(self.verticalBottomView.frame, [gestureRecognizer locationInView:self.view])) {
        return NO;
    } else{
        return YES;
    };
}

#pragma mark - 播放進度
- (IBAction)topSliderValueChangedAction:(id)sender {
    UISlider *test = (UISlider *)sender;
    NSLog(@"進度條進度 + %f", test.value);
    UISlider *senderSlider = sender;
    double currentTime = floor(_totalMovieDuration * senderSlider.value);
    //轉換成CMTime才能給player來控制播放進度
    CMTime dragedCMTime = CMTimeMake(currentTime, 1);
    [_playerHelper.getAVPlayer seekToTime:dragedCMTime completionHandler:^(BOOL finished) {
        if (_isPlayOrParse) {
            [_playerHelper.getAVPlayer play];
        }
    }];
}

- (IBAction)topSliderTouchDownAction:(id)sender {
}

- (IBAction)topSliderTouchUpInsideAction:(id)sender {
}

#pragma mark - 播放上一個
- (IBAction)rotatorUpAction:(id)sender {
    NSLog(@"上一個~~~");
}

#pragma mark - 播放...
- (IBAction)rotatorPlayAction:(UIButton *)sender {
    if (isPlay) {
        [self setMovieParse];
    } else {
        [self setMoviePlay];
    }
}

#pragma mark - 播放下一個...
- (IBAction)rotatorNextAction:(UIButton *)sender {
    NSLog(@"下一個~~~");
}

#pragma mark - 返回按鈕...
- (IBAction)finishAction:(UIButton *)sender {
    NSLog(@"完成~~~");
}

#pragma mark 播放結束後的代理回撥
- (void)moviePlayDidEnd:(NSNotification *)notify
{
    //  LettopRightBottomViewShow
    [self setTopRightBottomViewHiddenToShow];
    [self setMovieParse];
    //  讓這個視訊迴圈播放...
}

#pragma mark - 音量slider
- (IBAction)bottomSoundSliderAction:(UISlider *)sender {
    //  0 - 1
    [_playerHelper setAVPlayerVolume:sender.value];
    
    self.rotatorBottomSlider.value = sender.value;
    self.verticalBottomSlider.value = sender.value;
    if (sender.value == 0) {
        self.rotatorSoundImageView.image = [UIImage imageNamed:@"播放器_靜音"];
        self.verticalSoundImageView.image = [UIImage imageNamed:@"播放器_靜音"];
    } else {
        self.rotatorSoundImageView.image = [UIImage imageNamed:@"播放器_音量"];
        self.verticalSoundImageView.image = [UIImage imageNamed:@"播放器_音量"];
    }
}

#pragma mark -  分享 - 收藏 - 快取
- (IBAction)rightShareButton:(UIButton *)sender {
    NSLog(@"分享~~~");
}

- (IBAction)rightCollectButton:(UIButton *)sender {
    NSLog(@"收藏~~~");
}

- (IBAction)rightCacheButton:(UIButton *)sender {
    NSLog(@"快取~~~");
}

- (void)dealloc {
    //  移除觀察者,使用觀察者模式的時候,記得在不使用的時候,進行移除
    [self removeObserverFromPlayerItem: _playerHelper.getAVPlayer.currentItem];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
    //  返回前一個頁面的時候釋放記憶體
    [self.playerHelper.getAVPlayer replaceCurrentItemWithPlayerItem:nil];
}

2.到此說完啦,為了寫這個玩意,我寫了一週啊.

3.實現了橫屏,豎屏,快進,快退,暫停等功能

原始碼地址:http://download.csdn.net/detail/fengchenlangzi_/9354939