AVPlayer 音视频播放

前言

  • Objective-C

    1
    2
    3
    NS_CLASS_AVAILABLE(10_7, 4_0) @interface AVPlayer : NSObject 

    NS_CLASS_AVAILABLE_IOS(8_0) @interface AVPlayerViewController : UIViewController
  • Swift

    1
    2
    3
    @available(iOS 4.0, *) public class AVPlayer : NSObject

    @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 设备中不能。

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

    • 使用 AVPlayer 播放:

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

      1
      2
      3
      4
      5
      添加库文件:AVKit.framework
      AVFoundation.framework

      包含头文件:#import <AVKit/AVKit.h>
      #import <AVFoundation/AVFoundation.h>

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

1.1 使用 AVPlayer 播放

  • Objective-C

    • 添加头文件

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

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      // 加载本地音乐
      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 创建

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      // 加载本地音乐
      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

    • 添加头文件

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

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      // 加载本地音乐
      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 创建

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      // 加载本地音乐
      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

    • 添加头文件

      1
      2
      3
      4
      5
      添加库文件:AVKit.framework
      AVFoundation.framework

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

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      // 加载本地音乐
      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];
      }];
    • 手动播放

      1
      2
      3
      4
      5
      6
      7
      8
      9
      // 加载本地视频	
      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

    • 添加头文件

      1
      2
      3
      4
      5
      6
      添加库文件:AVKit.framework
      import AVFoundation


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

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      // 加载本地音乐
      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()
      }
    • 手动播放

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      // 加载本地视频
      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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    // 在视图上添加播放器
    /*
    必须添加到 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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    // 在视图上添加播放器
    /*
    必须添加到 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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    // 显示播放页面
    [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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    // 显示播放页面
    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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    // 将要开始画中画播放
    - (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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    // 将要开始画中画播放
    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 内嵌模式时调用的方法
    }
文章目录
  1. 1. 前言
  2. 2. 1、本地/网络音视频播放
    1. 2.1. 1.1 使用 AVPlayer 播放
    2. 2.2. 1.2 使用 AVPlayerViewController 播放
  3. 3. 2、本地/网络音视频播放设置
    1. 3.1. 2.1 使用 AVPlayer 播放
    2. 3.2. 2.2 使用 AVPlayerViewController 播放
  4. 4. 3、AVPlayerViewControllerDelegate 画中画协议方法
隐藏目录