OC AVPlayerItem,AVPlayer,AVPlayerLayer的使用


音量調節以及跳轉到指定的秒數,停止和暫停,只是學習,沒有封裝

#import <Masonry.h>
#import <AVFoundation/AVFoundation.h>
@interface RecordVideoplayVC ()
@property(nonatomic,strong)AVPlayerItem *avPlayerItem;
@property(nonatomic,strong)AVPlayer *avPlayer;
@property (nonatomic ,strong) id playbackTimeObserver;
@end

@implementation RecordVideoplayVC

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
//    AVPlayerItem:提供視頻信息,一個AVPlayerItem對應着你提供的一個視頻Url資源,這個理解它的時候可以把它比作一個Model, 你初始化了AVPlayerItem之后,並不是馬上就可以使用它了,因為凡是和Url網絡扯上關系的,都需要時間,等AVPlayerItem加載好之后就可以使用它了,那這一步我們怎么處理呢?
//    答案是利用KVO觀察statues屬性為 AVPlayerStatusReadyToPlay,看看這個屬性的定義:
    
//    @property (nonatomic, readonly) AVPlayerStatus status  它是一個只讀屬性,這點也需要注意,其實也就理解利用KVO的原因。
//
//    2>: 順便總結要是你要顯示當前視屏的緩存進度,你需要監測它的loadedTimeRanges屬性。
//
//    2、AVPlayerLayer
//
//    它主要負責的就是視頻的顯示,繼承自CALayer,其實你可以把它理解成我們的View。我們自定義的那些播放時候的控件就是添加在它上面的,比如我們能看到的播放按鈕,停止按鈕,或者播放進度條等等。
  
//    3、 AVPlayer
//
//    它主要負責的是管理視頻播放,暫停等等,相當於一個視頻管理器,要是類比的話他就是一個ViewController(當然不是真正的ViewController),這三者就基本含括了一個基本的視頻播,基於着三者我們總結一下播放一個視頻的基本的過程:
    
//    首先,得到視頻的URL
//    根據URL創建AVPlayerItem
//    把AVPlayerItem 提供給 AVPlayer
//    AVPlayerLayer 顯示視頻。
//    AVPlayer 控制視頻, 播放, 暫停, 跳轉 等等。
//    播放過程中獲取緩沖進度,獲取播放進度。
//    視頻播放完成后做些什么,是暫停還是循環播放,還是獲取最后一幀圖像。

//    4、AVPlayerViewController
//
//    它是Apple 幫我們封裝好的可以一個視頻播放控制器,它就有一個  @property (nonatomic, strong, nullable) AVPlayer *player 的屬性,前面的AVPlayer也就像相應的需要賦值給它,它里面還有一些我們需要理解一下的屬性,我們也把它寫出來,具體代碼我們下面再看:
//
//    player:                                    設置播放器
//    showsPlaybackControls:           設置是否顯示媒體播放組件,默認YES
//    videoGravity:                           設置視頻拉伸模式
//    allowsPictureInPicturePlayback: 設置是否允許畫中畫回放,默認YES
//    delegate:                                設置代理
//    5、AVPlayerViewControllerDelegate
//
//    這個代理就是前面說的AVPlayerViewController的協議,它主要的是為畫中畫的設置的代理,前面介紹 AVPlayerViewController 的時候有看到過一個是否允許畫中畫的屬性,具體什么是畫中畫相信大家都了解,看過直接的朋友應該都看到了這個技術點的具體應用。我們看看它里面的飯法規主要都干了些什么?
//    // 1、即將開始畫中畫
//    - (void)playerViewControllerWillStartPictureInPicture:(AVPlayerViewController *)playerViewController;
//    // 2、開始畫中畫
//    - (void)playerViewControllerDidStartPictureInPicture:(AVPlayerViewController *)playerViewController;
//    // 3、畫中畫失敗
//    - (void)playerViewController:(AVPlayerViewController *)playerViewController failedToStartPictureInPictureWithError:(NSError *)error;
//    // 4、即將結束畫中畫
//    - (void)playerViewControllerWillStopPictureInPicture:(AVPlayerViewController *)playerViewController;
//    // 5、結束畫中畫
//    - (void)playerViewControllerDidStopPictureInPicture:(AVPlayerViewController *)playerViewController;
    
    
    
    // Do any additional setup after loading the view.
    
    
    self.avPlayerItem   = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:MovieURL]];
    self.avPlayer       = [[AVPlayer alloc]initWithPlayerItem:self.avPlayerItem];
    AVPlayerLayer *avPlayerLayer  = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
    avPlayerLayer.frame = CGRectMake(10, 100, 355, 200);
    [self.view.layer addSublayer:avPlayerLayer];

    //狀態添加觀察者
    [self.avPlayerItem  addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil];
    // 緩存進度添加觀察者
    [self.avPlayerItem  addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    // 添加視頻播放結束通知
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(moviePlayDidEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.avPlayerItem];
    
    
    
    self.avPlayer.volume = 0.5;//調節音量 0-1
    
}

- (void)moviePlayDidEnd:(NSNotification *)notification {
    NSLog(@"Play end");
    
    __weak typeof(self) weakSelf = self;
    [self.avPlayer seekToTime:kCMTimeZero completionHandler:^(BOOL finished) {
        //把進度跳轉到0,
    }];
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    
    AVPlayerItem * avplayeritem = (AVPlayerItem *)object;
    if ([keyPath isEqualToString:@"status"]) {
        
        AVPlayerStatus status = [[change objectForKey:@"new"] intValue];
        if (status == AVPlayerStatusReadyToPlay) {
            NSLog(@"准備好播放");
            CMTime duration = avplayeritem.duration;
            NSLog(@"視頻總時長:%.2f",CMTimeGetSeconds(duration));//總時長
            // 播放
            [self.avPlayer play];
            [self monitoringPlayback];// 監聽播放狀態
           
        }else if (status == AVPlayerStatusFailed){
            NSLog(@"視頻准備發生錯誤");
        }else{
            NSLog(@"位置錯誤");
        }
    }else if ([keyPath isEqualToString:@"loadedTimeRanges"]){
        
        // 可以自定義緩存進度
        NSTimeInterval timeInterval = [self alreadyCacheVideoProgress];
        NSLog(@"視頻已經緩存的時長:%.2f",timeInterval);
    }
}

#pragma mark --
#pragma mark -- alreadyCacheVideoProgress
-(NSTimeInterval)alreadyCacheVideoProgress{
    // 先獲取到它的緩存的進度
    NSArray * cacheVideoTime = [self.avPlayerItem loadedTimeRanges];
    // CMTimeRange 結構體 start duration 表示起始位置 和 持續時間
    // 獲取緩沖區域
    CMTimeRange timeRange = [cacheVideoTime.firstObject CMTimeRangeValue];//NSValue
    float startSeconds    = CMTimeGetSeconds(timeRange.start);
    float durationSeconds = CMTimeGetSeconds(timeRange.duration);
   
    // 計算總緩沖時間 = start + duration
    NSTimeInterval result = startSeconds + durationSeconds;
    return result;
}



-(void)dealloc{
    [self.avPlayerItem removeObserver:self forKeyPath:@"status"];
    [self.avPlayerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:self.avPlayerItem];
    [self.avPlayer removeTimeObserver:self.playbackTimeObserver];
}

//監聽播放狀態
- (void)monitoringPlayback {
    /*
    CMTime CMTimeMake(
    int64_t value, //秒
    int32_t timescale)//次數
    */
 self.playbackTimeObserver = [self.avPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 5) queue:NULL usingBlock:^(CMTime time) {
        CGFloat currentSecond = self.avPlayerItem.currentTime.value/self.avPlayerItem.currentTime.timescale;// 計算當前在第幾秒
        //如果需要進度條的話,這里可以更新進度條
    }];
}
//跳轉到指定的秒數
-(void)jumptoValue:(float)seconds{
     CMTime changedTime = CMTimeMakeWithSeconds(seconds, 1);
    [self.avPlayer seekToTime:changedTime completionHandler:^(BOOL finished) {
        [self.avPlayer play];
    }];

}


//

@end

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM