iOS - AVPlayer 音视频播放

简介: 前言 NS_CLASS_AVAILABLE(10_7, 4_0) @interface AVPlayer : NSObject @available(iOS 4.0, *) public class AVPlayer : NSObject NS_C...

前言

    NS_CLASS_AVAILABLE(10_7, 4_0) @interface AVPlayer : NSObject 
    @available(iOS 4.0, *)         public class AVPlayer : NSObject
    
    NS_CLASS_AVAILABLE_IOS(8_0) @interface AVPlayerViewController : UIViewController
    @available(iOS 8.0, *)       public class AVPlayerViewController : UIViewController 
  • AVPlayer 既可以播放音乐又可以播放视频;使用 AVPlayer 不能直接显示视频,必须要加入 AVPlayerLayer 中,并添加到其他能显示的 layer 中,AVPlayer 播放界面中不带播放控件。

    • MediaPlayer 的影片是放在 UIView 里面,而 AVPlayer 是放在 AVPlayerLayer 里面,AVPlayerLayer 是 CALayer 的子类別。
    • 使用 MediaPlayer 前,要记得加入 MediaPlayer.framework 及 #import <MediaPlayer/MediaPlayer.h>
    • 使用 AVPlayer 前,要记得加入 AVFoundation.framework 及 #import <AVFoundation/AVFoundation.h>
  • MeidaPlayer 框架中的 MPMoviePlayerController 类和 MPMoviePlayerViewController 类是 iOS 中视频播放的开发相关类和方法。在 iOS8 中,iOS 开发框架中引入了一个新的视频框架 AVKit,其中提供了视频开发类 AVPlayerViewController 用于在应用中嵌入播放视频的控件。AVPlayerViewcontroller 继承自 UIViewController,一般适用于点击一个视频缩略图,modal 出一个新的界面来进行播 放的情况,AVPlayerViewcontroller 既可以播放音乐又可以播放视频,播放界面中自带播放控件。在 iOS8 中,这两个框架中的视频播放功能并无太大差异,基本都可以满足开发者的需求。iOS9 系统后,iPad Air 正式开始支持多任务与画中画的分屏功能,所谓画中画,即是用户可以将当前播放的视频缩小放在屏幕上同时进行其他应用程序的使用。这个革命性的功能将极大的方便用户的使用。于此同时,在 iOS9 中,MPMoviePlayerController 与 MPMoviePlayerViewController 类也被完全弃用,开发者使用 AVPlayerViewController 可以十分方便的实现视频播放的功能并在一些型号的 iPad 上集成画中画的功能。

  • 实现画中画要实现以下三步:
    • 1、确保当前调试版本在 9.0 以上。
    • 2、在项目 TARGETS 中的 Capabilities -> Gapabilities -> Background Mode(选项开关打开)-> 勾选 Audio, AirPlay and Picture in Picture
    • 3、设置 AVAudioSession,这两行必须设置,不然画中画不能用,如果不写模拟器中可以画中画,但是在 iPad 设备中不能。

          AVAudioSession *audioSession = [AVAudioSession sharedInstance];
          [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
  • 播放设置:

    • 使用 AVPlayer 播放:

          添加库文件:AVFoundation.framework
          包含头文件:#import <AVFoundation/AVFoundation.h>
    • 使用 AVPlayerViewController 播放:

          添加库文件:AVKit.framework
                     AVFoundation.framework
      
          包含头文件:#import <AVKit/AVKit.h>
                     #import <AVFoundation/AVFoundation.h>

1、本地/网络音视频播放

1.1 使用 AVPlayer 播放

  • Objective-C

        添加库文件:AVFoundation.framework
        包含头文件:#import <AVFoundation/AVFoundation.h>
    • 直接由 URL 创建

          // 加载本地音乐
          NSURL *movieUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"蓝莲花" ofType:@"mp3"]];
      
          // 加载本地视频
          NSURL *movieUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"步步高手机" ofType:@"mp4"]];
      
          // 加载网络视频
          NSURL *movieUrl = [NSURL URLWithString:@"http://w2.dwstatic.com/1/5/1525/127352-100-1434554639.mp4"];
      
          // 创建 AVPlayer 播放器
          AVPlayer *player = [AVPlayer playerWithURL:movieUrl];
      
          // 将 AVPlayer 添加到 AVPlayerLayer 上
          AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
      
          // 设置播放页面大小
          playerLayer.frame = CGRectMake(10, 30, self.view.bounds.size.width - 20, 200);
      
          // 设置画面缩放模式
          playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
      
          // 在视图上添加播放器
          [self.view.layer addSublayer:playerLayer];
      
          // 开始播放
          [player play];
    • 由 AVPlayerItem 创建

          // 加载本地音乐
          NSURL *movieUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"蓝莲花" ofType:@"mp3"]];
      
          // 加载本地视频
          NSURL *movieUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"步步高手机" ofType:@"mp4"]];
      
          // 加载网络视频
          NSURL *movieUrl = [NSURL URLWithString:@"http://w2.dwstatic.com/1/5/1525/127352-100-1434554639.mp4"];
      
          AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:movieUrl];
      
          // 创建 AVPlayer 播放器
          AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
      
          // 将 AVPlayer 添加到 AVPlayerLayer 上
          AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
      
          // 设置播放页面大小
          playerLayer.frame = CGRectMake(10, 30, self.view.bounds.size.width - 20, 200);
      
          // 设置画面缩放模式
          playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
      
          // 在视图上添加播放器
          [self.view.layer addSublayer:playerLayer];
      
          // 开始播放
          [player play];
  • Swift

        添加库文件:AVFoundation.framework
        包含头文件:import AVFoundation
    • 直接由 URL 创建

          // 加载本地音乐
          let movieUrl:NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("蓝莲花", ofType: "mp3")!)
      
          // 加载本地视频
          let movieUrl:NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("步步高手机", ofType: "mp4")!)
      
          // 加载网络视频
          let movieUrl:NSURL = NSURL(string: "http://w2.dwstatic.com/1/5/1525/127352-100-1434554639.mp4")!
      
          // 创建 AVPlayer 播放器
          let player:AVPlayer = AVPlayer(URL: movieUrl)
      
          // 将 AVPlayer 添加到 AVPlayerLayer 上
          let playerLayer:AVPlayerLayer = AVPlayerLayer(player: player)
      
          // 设置播放页面大小
          playerLayer.frame = CGRectMake(10, 30, self.view.bounds.size.width - 20, 200)
      
          // 设置画面缩放模式                                      
          playerLayer.videoGravity = AVLayerVideoGravityResizeAspect
      
          // 在视图上添加播放器
          self.view.layer.addSublayer(playerLayer)
      
          // 开始播放
          player.play()
    • 由 AVPlayerItem 创建

          // 加载本地音乐
          let movieUrl:NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("蓝莲花", ofType: "mp3")!)
      
          // 加载本地视频
          let movieUrl:NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("步步高手机", ofType: "mp4")!)
      
          // 加载网络视频
          let movieUrl:NSURL = NSURL(string: "http://w2.dwstatic.com/1/5/1525/127352-100-1434554639.mp4")!
      
          let playerItem:AVPlayerItem = AVPlayerItem(URL: movieUrl)
      
          // 创建 AVPlayer 播放器
          let player:AVPlayer = AVPlayer(playerItem: playerItem)
      
          // 将 AVPlayer 添加到 AVPlayerLayer 上
          let playerLayer:AVPlayerLayer = AVPlayerLayer(player: player)
      
          // 设置播放页面大小
          playerLayer.frame = CGRectMake(10, 30, self.view.bounds.size.width - 20, 200)
      
          // 设置画面缩放模式                                     
          playerLayer.videoGravity = AVLayerVideoGravityResizeAspect
      
          // 在视图上添加播放器
          self.view.layer.addSublayer(playerLayer)
      
          // 开始播放
          player.play()

1.2 使用 AVPlayerViewController 播放

  • Objective-C

        添加库文件:AVKit.framework
                   AVFoundation.framework
    
        包含头文件:#import <AVKit/AVKit.h>
                   #import <AVFoundation/AVFoundation.h>
    • 弹出显示页面直接开始播放

          // 加载本地音乐
          NSURL *movieUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"蓝莲花" ofType:@"mp3"]];
      
          // 加载本地视频
          NSURL *movieUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"步步高手机" ofType:@"mp4"]];
      
          // 加载网络视频       
          NSURL *movieUrl = [NSURL URLWithString:@"http://w2.dwstatic.com/1/5/1525/127352-100-1434554639.mp4"];
      
          // 创建播放控制器
          AVPlayerViewController *playerViewController = [[AVPlayerViewController alloc] init];
      
          playerViewController.player = [AVPlayer playerWithURL:movieUrl];
      
          // 弹出播放页面
          [self presentViewController:playerViewController animated:YES completion:^{
      
              // 开始播放
              [playerViewController.player play];
          }];
    • 手动播放

          // 加载本地视频   
          NSURL *movieUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"步步高手机" ofType:@"mp4"]];  
      
          // 创建播放控制器      
          AVPlayerViewController *playerViewController = [[AVPlayerViewController alloc] init];                               
          playerViewController.player = [AVPlayer playerWithURL:movieUrl];
      
          // 弹出播放页面,需要点击播放按钮开始播放
          [self presentViewController:playerViewController animated:YES completion:nil];
  • Swift

        添加库文件:AVKit.framework
                   import AVFoundation
    
    
        包含头文件:import AVKit
                   AVFoundation.framework
    • 弹出显示页面直接开始播放

          // 加载本地音乐
          let movieUrl:NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("蓝莲花", ofType: "mp3")!)
      
          // 加载本地视频 
          let movieUrl:NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("步步高手机", ofType: "mp4")!)
      
          // 加载网络视频   
          let movieUrl:NSURL = NSURL(string: "http://w2.dwstatic.com/1/5/1525/127352-100-1434554639.mp4")!
      
          // 创建播放控制器
          let playerViewController:AVPlayerViewController = AVPlayerViewController()
      
          playerViewController.player = AVPlayer(URL: movieUrl)
      
          // 弹出播放页面
          self.presentViewController(playerViewController, animated: true) {
      
              // 开始播放
              playerViewController.player?.play()
          }
    • 手动播放

          // 加载本地视频
          let movieUrl:NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("步步高手机", ofType: "mp4")!)
      
          // 创建播放控制器  
          let playerViewController:AVPlayerViewController = AVPlayerViewController()
      
          playerViewController.player = AVPlayer(URL: movieUrl)
      
          // 弹出播放页面,需要点击播放按钮开始播放
          self.presentViewController(playerViewController, animated: true, completion:nil)

2、本地/网络音视频播放设置

2.1 使用 AVPlayer 播放

  • Objective-C

        // 在视图上添加播放器
        /*
            必须添加到 layer 上
        */
        avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:avPlayer];
        [self.view.layer addSublayer:avPlayerLayer];
    
        // 设置播放页面大小
        avPlayerLayer.frame = CGRectMake(10, 30, self.view.bounds.size.width - 20, 200);
    
        // 设置画面缩放模式
        /*
            AVLayerVideoGravityResizeAspect       适应屏幕大小,保持宽高比,默认
            AVLayerVideoGravityResizeAspectFill   充满屏幕,保持宽高比
            AVLayerVideoGravityResize             充满屏幕,不保持宽高比
        */
        avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    
        // 获取显示在接收视图范围内的视频图像的位置和大小
        CGRect videoRect = avPlayerLayer.videoRect;
    
        // 判断是否准备好显示
        BOOL readyForDisplay = avPlayerLayer.isReadyForDisplay;
    
        // 获取视频准备播放状态
        /*
            AVPlayerItemStatusUnknown,      状态未知
            AVPlayerItemStatusReadyToPlay,  准备好播放
            AVPlayerItemStatusFailed        准备失败
        */
        AVPlayerItemStatus status = avPlayerItem.status;
    
        // 监听准备播放状态属性
        [avPlayerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    
        // 系统自带监听方法
        - (void)observeValueForKeyPath:(NSString *)keyPath 
                              ofObject:(id)object 
                                change:(NSDictionary<NSString *,id> *)change 
                               context:(void *)context {   
    
            if ([keyPath isEqualToString:@"status"]) {
    
            }
        }
    
        // 获取视频缓冲进度
        NSArray<NSValue *> *loadedTimeRanges = avPlayerItem.loadedTimeRanges;
    
        CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];  // 获取缓冲区域                
        float startSeconds = CMTimeGetSeconds(timeRange.start);
        float durationSeconds = CMTimeGetSeconds(timeRange.duration);
    
        float loadedSecond = startSeconds + durationSeconds;                      // 计算缓冲总进度
    
        // 监听缓冲进度属性
        [avPlayerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    
        // 系统自带监听方法
        - (void)observeValueForKeyPath:(NSString *)keyPath 
                              ofObject:(id)object 
                                change:(NSDictionary<NSString *,id> *)change 
                               context:(void *)context {   
    
            if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
    
            }
        }
    
        // 获取当前播放进度
        /*
            或用 avPlayerItem.currentTime.value/avPlayerItem.currentTime.timescale;
        */
        CMTime currentTime = avPlayerItem.currentTime;
        float currentSecond = CMTimeGetSeconds(currentTime);
    
        // 监听播放进度
        /*
            NULL 在主线程中执行,每个一秒执行一次该 Block
        */
        [avPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:NULL usingBlock:^(CMTime time) {
    
        }];
    
        // 添加播放完成通知
        [[NSNotificationCenter defaultCenter] addObserver:self 
                                                 selector:@selector(playDidEnd:) 
                                                     name:AVPlayerItemDidPlayToEndTimeNotification 
                                                   object:avPlayerItem];
    
        // 获取视频总长度
        /*
            转换成秒,或用 duration.value / duration.timescale; 计算
        */
        CMTime duration = avPlayerItem.duration;
        float totalSecond = CMTimeGetSeconds(duration);
    
        // 跳转到指定位置
        /*
            10 / 1 = 10,跳转到第 10 秒的位置处  
        */
        [avPlayerItem seekToTime:CMTimeMake(10, 1)];    
    
        // 设置播放速率
        /*
            默认为 1.0 (normal speed),设为 0.0 时暂停播放。设置后立即开始播放,可放在开始播放后设置
        */
        avPlayer.rate = 1.0;
    
        // 获取当前播放速率
        float rate = avPlayer.rate;
    
        // 开始播放
        [avPlayer play];
    
        // 暂停播放
        [avPlayer pause];
    
        // 设置音量
        /*
            范围 0 - 1,默认为 1
        */
        avPlayer.volume = 0;
  • Swift

        // 在视图上添加播放器
        /*
            必须添加到 layer 上
        */
        avPlayerLayer = AVPlayerLayer(player: avPlayer)
        self.view.layer.addSublayer(avPlayerLayer)
    
        // 设置播放页面大小
        avPlayerLayer.frame = CGRectMake(10, 30, self.view.bounds.size.width - 20, 200)
    
        // 设置画面缩放模式
        /*
            AVLayerVideoGravityResizeAspect       适应屏幕大小,保持宽高比,默认
            AVLayerVideoGravityResizeAspectFill   充满屏幕,保持宽高比
            AVLayerVideoGravityResize             充满屏幕,不保持宽高比
        */
        avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
    
        // 获取显示在接收视图范围内的视频图像的位置和大小
        let videoRect:CGRect = avPlayerLayer.videoRect
    
        // 判断是否准备好显示
        let readyForDisplay:Bool = avPlayerLayer.readyForDisplay
    
        // 获取视频准备播放状态
        /*
            case Unknown       状态未知
            case ReadyToPlay   准备好播放
            case Failed        准备失败
        */
        let status:AVPlayerItemStatus = avPlayerItem.status
    
        // 监听准备播放状态属性
        avPlayerItem.addObserver(self, forKeyPath: "status", options: .New, context: nil)
    
        // 系统自带监听方法
        override func observeValueForKeyPath(keyPath: String?, 
                                     ofObject object: AnyObject?, 
                                              change: [String : AnyObject]?, 
                                             context: UnsafeMutablePointer<Void>) {
    
            if keyPath == "status" {
    
            }
        }
    
        // 获取视频缓冲进度
        let loadedTimeRanges:[NSValue] = avPlayerItem.loadedTimeRanges
    
        let timeRange:CMTimeRange = loadedTimeRanges.first!.CMTimeRangeValue  // 获取缓冲区域
        let startSeconds = CMTimeGetSeconds(timeRange.start)
        let durationSeconds = CMTimeGetSeconds(timeRange.duration)
    
        let loadedSecond:Double = startSeconds + durationSeconds              // 计算缓冲总进度
    
        // 监听缓冲进度属性 
        avPlayerItem.addObserver(self, forKeyPath: "loadedTimeRanges", options: .New, context: nil)
    
        // 系统自带监听方法
        override func observeValueForKeyPath(keyPath: String?, 
                                     ofObject object: AnyObject?, 
                                              change: [String : AnyObject]?, 
                                             context: UnsafeMutablePointer<Void>) {
    
            if keyPath == "loadedTimeRanges" {
    
            }
        }
    
        // 获取当前播放进度
        /*
            或用 avPlayerItem.currentTime.value/avPlayerItem.currentTime.timescale;
        */
        let currentTime:CMTime = self.avPlayerItem.currentTime()
        let currentSecond = CMTimeGetSeconds(currentTime)
    
        // 监听播放进度   
        /*
            nil 在主线程中执行,每个一秒执行一次该 Block
        */  
        avPlayer.addPeriodicTimeObserverForInterval(CMTimeMake(1, 1), queue: nil) { (time:CMTime) in
    
        }
    
        // 添加播放完成通知
        NSNotificationCenter.defaultCenter().addObserver(self, 
                                                selector: #selector(AvPlayer.playDidEnd(_:)), 
                                                    name: AVPlayerItemDidPlayToEndTimeNotification, 
                                                  object: avPlayerItem)
    
        // 获取视频总长度
        /*
            转换成秒,或用 duration.value / duration.timescale; 计算
        */
        let duration:CMTime = avPlayerItem.duration
        let totalSecond:Double = CMTimeGetSeconds(duration)
    
        // 跳转到指定位置
        /*
            10 / 1 = 10,跳转到第 10 秒的位置处 
        */
        avPlayerItem.seekToTime(CMTimeMake(10, 1))
    
        // 设置播放速率
        /*
            默认为 1.0 (normal speed),设为 0.0 时暂停播放。设置后立即开始播放,可放在开始播放后设置
        */
        avPlayer.rate = 1.0
    
        // 获取当前播放速率
        let rate:Float = avPlayer.rate
    
        // 开始播放
        avPlayer.play()
    
        // 暂停播放
        avPlayer.pause()
    
        // 设置音量
        /*
            范围 0 - 1,默认为 1
        */
        avPlayer.volume = 0

2.2 使用 AVPlayerViewController 播放

  • Objective-C

        // 显示播放页面
        [self presentViewController:avPlayerVC animated:YES completion:nil];
    
        // 设置画面缩放模式
        /*
            AVLayerVideoGravityResizeAspect       适应屏幕大小,保持宽高比,默认
            AVLayerVideoGravityResizeAspectFill   充满屏幕,保持宽高比
            AVLayerVideoGravityResize             充满屏幕,不保持宽高比
        */
        avPlayerVC.videoGravity = AVLayerVideoGravityResizeAspect;
    
        // 获取显示在接收视图范围内的视频图像的位置和大小
        CGRect videoBounds = avPlayerVC.videoBounds;
    
        // 获取播放控件所在的视图
        /*
            播放控件与播放内容界面之间的叠加视图
        */
        UIView *contentOverlayView = avPlayerVC.contentOverlayView;
    
        // 设置是否显示播放控件
        /*
            Default is YES
        */
        avPlayerVC.showsPlaybackControls = YES;
    
        // 设置是否允许画中画播放
        /*
            Default is YES
        */
        avPlayerVC.allowsPictureInPicturePlayback = YES;
    
        // 判断是否准备好显示
        BOOL readyForDisplay = avPlayerVC.isReadyForDisplay;
    
        // 设置画中画播放代理,需遵守协议 <AVPlayerViewControllerDelegate>
        avPlayerVC.delegate = self;
    
        // 实现画中画播放
        /*
            这两行必须设置,不然画中画不能用,如果不写模拟器中可以画中画,但是在设备中不能
        */
        AVAudioSession *audioSession = [AVAudioSession sharedInstance];
        [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
    
        // 获取视频准备播放状态
        /*
            AVPlayerItemStatusUnknown,      状态未知
            AVPlayerItemStatusReadyToPlay,  准备好播放
            AVPlayerItemStatusFailed        准备失败
        */
        AVPlayerItemStatus status = avPlayerVC.player.currentItem.status;
    
        // 监听准备播放状态属性
        [avPlayerVC.player.currentItem addObserver:self 
                                        forKeyPath:@"status" 
                                           options:NSKeyValueObservingOptionNew 
                                           context:nil];
    
        // 系统自带监听方法
        - (void)observeValueForKeyPath:(NSString *)keyPath 
                              ofObject:(id)object 
                                change:(NSDictionary<NSString *,id> *)change 
                               context:(void *)context {   
    
            if ([keyPath isEqualToString:@"status"]) {
    
            }
        }
    
        // 获取视频缓冲进度
        NSArray<NSValue *> *loadedTimeRanges = avPlayerVC.player.currentItem.loadedTimeRanges;
    
        CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];  // 获取缓冲区域
        float startSeconds = CMTimeGetSeconds(timeRange.start);
        float durationSeconds = CMTimeGetSeconds(timeRange.duration);
    
        float loadedSecond = startSeconds + durationSeconds;                      // 计算缓冲总进度
    
        // 监听缓冲进度属性 
        [avPlayerVC.player.currentItem addObserver:self 
                                        forKeyPath:@"loadedTimeRanges" 
                                           options:NSKeyValueObservingOptionNew 
                                           context:nil];
    
        // 系统自带监听方法
        - (void)observeValueForKeyPath:(NSString *)keyPath 
                              ofObject:(id)object 
                                change:(NSDictionary<NSString *,id> *)change 
                               context:(void *)context {   
    
            if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
    
            }
        }
    
        // 获取当前播放进度
        /*
            或用 avPlayerItem.currentTime.value/avPlayerItem.currentTime.timescale;
        */
        CMTime currentTime = avPlayerVC.player.currentItem.currentTime;
        float currentSecond = CMTimeGetSeconds(currentTime);
    
        // 监听播放进度
        /*
            NULL 在主线程中执行,每个一秒执行一次该 Block
        */
        [avPlayerVC.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:NULL usingBlock:^(CMTime time) {
    
        }];
    
        // 添加播放完成通知
        [[NSNotificationCenter defaultCenter] addObserver:self 
                                                 selector:@selector(playDidEnd:) 
                                                     name:AVPlayerItemDidPlayToEndTimeNotification 
                                                   object:avPlayerVC.player.currentItem];
    
        // 获取视频总长度
        /*
            转换成秒,或用 duration.value / duration.timescale; 计算
        */
        CMTime duration = avPlayerVC.player.currentItem.duration;
        float totalSecond = CMTimeGetSeconds(duration);
    
        // 跳转到指定位置
        /*
            10 / 1 = 10,跳转到第 10 秒的位置处 
        */
        [avPlayerVC.player.currentItem seekToTime:CMTimeMake(10, 1)];
    
        // 设置播放速率
        /*
            默认为 1.0 (normal speed),设为 0.0 时暂停播放。设置后立即开始播放,可放在开始播放后设置
        */
        avPlayerVC.player.rate = 1.0;
    
        // 获取当前播放速率
        float rate = avPlayerVC.player.rate;
    
        // 开始播放
        [avPlayerVC.player play];
    
        // 暂停播放
        [avPlayerVC.player pause];
    
        // 设置音量
        /*
            范围 0 - 1,默认为 1
        */
        avPlayerVC.player.volume = 0;
  • Swift

        // 显示播放页面
        self.presentViewController(avPlayerVC, animated: true, completion:nil)
    
        // 设置画面缩放模式
        /*
            AVLayerVideoGravityResizeAspect      适应屏幕大小,保持宽高比,默认
            AVLayerVideoGravityResizeAspectFill  充满屏幕,保持宽高比
            AVLayerVideoGravityResize            充满屏幕,不保持宽高比
        */
        avPlayerVC.videoGravity = AVLayerVideoGravityResizeAspect
    
        // 获取显示在接收视图范围内的视频图像的位置和大小
        let videoBounds:CGRect = avPlayerVC.videoBounds
    
        // 获取播放控件所在的视图
        /*
            播放控件与播放内容界面之间的叠加视图
        */
        let contentOverlayView:UIView = avPlayerVC.contentOverlayView!
    
        // 设置是否显示播放控件
        /*
            Default is YES
        */
        avPlayerVC.showsPlaybackControls = true
    
        // 设置是否允许画中画播放
        /*
            Default is YES
        */
        avPlayerVC.allowsPictureInPicturePlayback = true
    
        // 判断是否准备好显示
        let readyForDisplay:Bool = avPlayerVC.readyForDisplay
    
        // 设置画中画播放代理,需遵守协议 <AVPlayerViewControllerDelegate>
        avPlayerVC.delegate = self
    
        // 实现画中画播放
        /*
            这两行必须设置,不然画中画不能用,如果不写模拟器中可以画中画,但是在设备中不能
        */
        let audioSession:AVAudioSession = AVAudioSession.sharedInstance()
        try! audioSession.setCategory(AVAudioSessionCategoryPlayback)
    
        // 获取视频准备播放状态
        /*
            AVPlayerItemStatusUnknown,      状态未知
            AVPlayerItemStatusReadyToPlay,  准备好播放
            AVPlayerItemStatusFailed        准备失败
        */
        let status:AVPlayerItemStatus = avPlayerVC.player!.currentItem!.status
    
        // 监听准备播放状态属性
        avPlayerVC.player!.currentItem!.addObserver(self, forKeyPath: "status", options: .New, context: nil)
    
        // 系统自带监听方法
        override func observeValueForKeyPath(keyPath: String?, 
                                     ofObject object: AnyObject?, 
                                              change: [String : AnyObject]?, 
                                             context: UnsafeMutablePointer<Void>) {
    
            if keyPath == "status" {
    
            }
        }
    
        // 获取视频缓冲进度
        let loadedTimeRanges:[NSValue] = avPlayerVC.player!.currentItem!.loadedTimeRanges
    
        let timeRange:CMTimeRange = loadedTimeRanges.first!.CMTimeRangeValue   // 获取缓冲区域
        let startSeconds = CMTimeGetSeconds(timeRange.start)
        let durationSeconds = CMTimeGetSeconds(timeRange.duration)
    
        let loadedSecond:Double = startSeconds + durationSeconds               // 计算缓冲总进度
    
        // 监听缓冲进度属性 
        avPlayerVC.player!.currentItem!.addObserver(self, forKeyPath: "loadedTimeRanges", options: .New, context: nil)
    
        // 系统自带监听方法
        override func observeValueForKeyPath(keyPath: String?, 
                                     ofObject object: AnyObject?, 
                                              change: [String : AnyObject]?, 
                                             context: UnsafeMutablePointer<Void>) {
    
            if keyPath == "loadedTimeRanges" {
    
            }
        }
    
        // 获取当前播放进度
        let currentTime:CMTime = self.avPlayerVC.player!.currentItem!.currentTime()
        let currentSecond = CMTimeGetSeconds(currentTime)
    
        // 监听播放进度
        avPlayerVC.player?.addPeriodicTimeObserverForInterval(CMTimeMake(1, 1), queue: nil, usingBlock: { (time:CMTime) in
    
        })
    
        // 添加播放完成通知
        NSNotificationCenter.defaultCenter().addObserver(self, 
                                                selector: #selector(AvPlayer.playDidEnd(_:)), 
                                                    name: AVPlayerItemDidPlayToEndTimeNotification, 
                                                  object: avPlayerVC.player!.currentItem!)
    
        // 获取视频总长度
        /*
            转换成秒,或用 duration.value / duration.timescale; 计算
        */
        let duration:CMTime = avPlayerVC.player!.currentItem!.duration
        let totalSecond = CMTimeGetSeconds(duration)
    
        // 跳转到指定位置
        /*
            10 / 1 = 10,跳转到第 10 秒的位置处 
        */
        avPlayerVC.player!.currentItem!.seekToTime(CMTimeMake(10, 1))
    
        // 设置播放速率
        /*
            默认为 1.0 (normal speed),设为 0.0 时暂停播放。设置后立即开始播放,可放在开始播放后设置
        */
        avPlayerVC.player!.rate = 1.0
    
        // 获取当前播放速率
        let rate = avPlayerVC.player!.rate
    
        // 开始播放
        avPlayerVC.player!.play()
    
        // 暂停播放
        avPlayerVC.player!.pause()
    
        // 设置音量
        /*
            范围 0 - 1,默认为 1
        */
        avPlayerVC.player!.volume = 0

3、AVPlayerViewControllerDelegate 画中画协议方法

  • Objective-C

        // 将要开始画中画播放
        - (void)playerViewControllerWillStartPictureInPicture:(AVPlayerViewController *)playerViewController {
    
        }
    
        // 已经开始画中画播放
        - (void)playerViewControllerDidStartPictureInPicture:(AVPlayerViewController *)playerViewController {
    
        }
    
        // 画中画播放失败
        - (void)playerViewController:(AVPlayerViewController *)playerViewController failedToStartPictureInPictureWithError:(NSError *)error {
    
        }
    
        // 将要结束画中画播放
        - (void)playerViewControllerWillStopPictureInPicture:(AVPlayerViewController *)playerViewController {
    
        }
    
        // 已经结束画中画播放
        - (void)playerViewControllerDidStopPictureInPicture:(AVPlayerViewController *)playerViewController {
    
        }
    
        // 画中画播放开始时播放控制器界面是否自动退出
        - (BOOL)playerViewControllerShouldAutomaticallyDismissAtPictureInPictureStart:(AVPlayerViewController *)playerViewController {
    
            // 是否在开始画中画时自动将当前的播放界面 dismiss 掉,返回 YES 则自动 dismiss,返回 NO 则不会自动 dismiss
            return NO;
        }
    
        // 画中画停止之前恢复用户界面
        - (void)playerViewController:(AVPlayerViewController *)playerViewController restoreUserInterfaceForPictureInPictureStopWithCompletionHandler:(void (^)(BOOL             restored))completionHandler {
    
            // 用户点击还原按钮,从画中画模式还原回 App 内嵌模式时调用的方法
        }
  • Swift

        // 将要开始画中画播放
        func playerViewControllerWillStartPictureInPicture(playerViewController: AVPlayerViewController) {
    
        }
    
        // 已经开始画中画播放
        func playerViewControllerDidStartPictureInPicture(playerViewController: AVPlayerViewController) {
    
        }
    
        // 画中画播放失败
        func playerViewController(playerViewController: AVPlayerViewController, failedToStartPictureInPictureWithError error: NSError) {
    
        }
    
        // 将要结束画中画播放
        func playerViewControllerWillStopPictureInPicture(playerViewController: AVPlayerViewController) {
    
        }
    
        // 已经结束画中画播放
        func playerViewControllerDidStopPictureInPicture(playerViewController: AVPlayerViewController) {
    
        }
    
        // 画中画播放开始时播放控制器界面是否自动退出
        func playerViewControllerShouldAutomaticallyDismissAtPictureInPictureStart(playerViewController: AVPlayerViewController) -> Bool {
    
            // 是否在开始画中画时自动将当前的播放界面 dismiss 掉,返回 YES 则自动 dismiss,返回 NO 则不会自动 dismiss
            return false
        }
    
        // 画中画停止之前恢复用户界面
        func playerViewController(playerViewController: AVPlayerViewController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: (Bool)      -> Void) {
    
            // 用户点击还原按钮,从画中画模式还原回 App 内嵌模式时调用的方法
        }
目录
相关文章
|
4月前
|
编解码 Linux 开发工具
iOS平台如何实现RTSP|RTMP播放端录像?
我们在做RTSP、RTMP直播播放器的时候,有个比较重要的功能,就是拉流端实时录像,包括设置单个录像文件大小、文件前缀、audio转AAC、只录制视频或只录制音频、开始录像、停止录像事件状态回调等。
|
6月前
|
iOS开发
技术好文:xcode动态图,ios实现动态图,iosgif,暂停和继续播放
技术好文:xcode动态图,ios实现动态图,iosgif,暂停和继续播放
67 1
|
7月前
|
Android开发 iOS开发
ios后台播放声音的三种实现方式
ios后台播放声音的三种实现方式
583 1
|
编解码 开发工具 Android开发
安卓端/iOS端如何播放4K分辨率的RTMP/RTSP流
4K分辨率即4096×2160的像素分辨率,它是2K投影机和高清电视分辨率的4倍,属于超高清分辨率。在此分辨率下,观众将可以看清画面中的每一个细节,每一个特写。影院如果采用惊人的4096×2160像素,无论在影院的哪个位置,观众都可以清楚的看到画面的每一个细节,影片色彩鲜艳、文字清晰锐丽,再配合超真实音效,这种感觉真的是一种难以言传的享受。
330 0
安卓端/iOS端如何播放4K分辨率的RTMP/RTSP流
|
iOS开发
在iOS中调用leaveRoom方法并使用mPaaS音视频通话
在iOS中调用leaveRoom方法并使用mPaaS音视频通话
122 1
|
开发工具 图形学 Android开发
Windows/Android/IOS平台如何在Unity3d播放RTSP/RTMP流
如果基于Unity3d完全重新开发一个播放器,代价大,周期长,不适合快速出产品,最好的方式就是集成现有Native平台上成熟稳定播放器.
157 1
|
编解码 算法 iOS开发
iOS音视频开发 - IPB帧
做视频开发,特别是视频压缩、直播流优化,一个最基本的需要了解的概念就是IPB帧
|
编解码 Shell iOS开发
iOS音视频开发 - LAME编译
MP3编码引擎,目前在业界,转码成MP3格式的音频文件时,最常用的编码器就是LAME库。当达到320Kbit/s以上时,LAME编码出来的音频质量几乎可以和CD的音质相媲美,并且还能保证整个音频文件的体积非常小
|
iOS开发
iOS 多条音频拼接为一条音频进行播放
把多条mp3音频合并为一条保存并进行播放
345 0
|
缓存 iOS开发
iOS开发 - 用AVPlayer封装一个播放器
iOS开发 - 用AVPlayer封装一个播放器
441 0