AVPlayer
是iOS常见的播放器,使用时需导入
#import <AVKit/AVKit.h>
AVPlayer
能控制播放器的播放,暂停,播放速度
// 初始化
+ (instancetype)playerWithURL:(NSURL *)URL;
+ (instancetype)playerWithPlayerItem:(nullable AVPlayerItem *)item;
- (instancetype)initWithURL:(NSURL *)URL;
- (instancetype)initWithPlayerItem:(nullable AVPlayerItem *)item;
// 常用属性
@property (nonatomic, readonly) AVPlayerStatus status; // 播放媒体状态
@property (nonatomic) float rate; // 播放速度, 在视频开始播放之后才会生效
// 常用方法
- (void)play; // 播放
- (void)pause; // 暂停
// 添加周期时间观察者
- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(nullable dispatch_queue_t)queue
usingBlock:(void (^)(CMTime time))block;
单纯使用AVPlayer
类是无法显示视频的,要将视频层添加至AVPlayerLayer
中,这样才能将视频显示出来
// 初始化
+ (AVPlayerLayer *)playerLayerWithPlayer:(nullable AVPlayer *)player;
// 常用属性
@property (nonatomic, retain, nullable) AVPlayer *player;
// AVLayerVideoGravityResize, 非均匀模式。两个维度完全填充至整个视图区域
// AVLayerVideoGravityResizeAspect, 等比例填充,直到一个维度到达区域边界
// AVLayerVideoGravityResizeAspectFill, 等比例填充,直到填充满整个视图区域,其中一个维度的部分区域会被裁剪
@property(copy) AVLayerVideoGravity videoGravity;
播放视频
self.player = [[AVPlayer alloc] initWithURL:[NSURL URLWithString:@"http://xxx.mp4"]];
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
playerLayer.frame = self.playerView.bounds;
[self.playerView.layer addSublayer:playerLayer];
AVPlayerItem
管理资源对象,提供播放数据源
// 初始化
+ (instancetype)playerItemWithURL:(NSURL *)URL;
+ (instancetype)playerItemWithAsset:(AVAsset *)asset;
- (instancetype)initWithURL:(NSURL *)URL;
- (instancetype)initWithAsset:(AVAsset *)asset;
// 常见属性
@property (readonly) AVPlayerItemStatus status; // 播放状态
@property (nonatomic, readonly) AVAsset *asset;
@property (readonly) CMTime duration; // 总时间
@property (readonly) NSArray<NSValue *> *loadedTimeRanges; // 缓存时间
// 主要方法
- (CMTime)currentTime; // 当前时间
结构体CMTime
是以分数的形式表示时间,value
表示分子,timescale
表示分母,flags
是位掩码,表示时间的指定状态。
typedef struct
{
CMTimeValue value; // 帧数
CMTimeScale timescale; // 帧率(影片每秒有几帧)
CMTimeFlags flags;
CMTimeEpoch epoch;
} CMTime;
获取当前播放时间
float currentTime = self.playItem.currentTime.value/self.playItem.currentTime.timescale;
还有一种利用系统提供的方法,我们用它获取视频总时间:
float totalTime = CMTimeGetSeconds(self.playItem.duration);
使用KVO监测AVPlayerItem
,获取播放状态的变化
- (void)viewDidLoad {
__weak __typeof(self)weakSelf = self;
[self.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:nil usingBlock:^(CMTime time) {
NSLog(@"%lld/%.2f", weakSelf.playerItem.currentTime.value/weakSelf.playerItem.currentTime.timescale,
CMTimeGetSeconds(weakSelf.playerItem.duration));
}];
[self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
[self.playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)dealloc {
[self.playerItem removeObserver:self forKeyPath:@"status"];
[self.playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"status"]) {
switch (self.playerItem.status) {
case AVPlayerItemStatusReadyToPlay:
NSLog(@"AVPlayerItemStatusReadyToPlay");
break;
case AVPlayerItemStatusUnknown:
NSLog(@"AVPlayerItemStatusUnknown");
break;
case AVPlayerItemStatusFailed:
NSLog(@"AVPlayerItemStatusFailed");
break;
}
} else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
NSArray<NSValue *> *array = _playerItem.loadedTimeRanges;
//本次缓冲时间范围
CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];
float startSeconds = CMTimeGetSeconds(timeRange.start);
float durationSeconds = CMTimeGetSeconds(timeRange.duration);
NSTimeInterval totalBuffer = startSeconds + durationSeconds;//缓冲总长度
NSLog(@"当前缓冲时间:%f",totalBuffer);
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
AVPlayerViewController
整合了一个完整的播放器,可以作为控制器进行操作显示。
// 主要属性
@property (nonatomic, strong, nullable) AVPlayer *player;
@property (nonatomic) BOOL showsPlaybackControls; // 是否显示媒体播放组件
@property (nonatomic, copy) AVLayerVideoGravity videoGravity; // 拉伸模式
AVPlayerViewController
可以全屏播放,也可以在UIView
里播放
// 全屏播放
- (void)onFullScreenPlayClick:(UIButton *)sender {
AVPlayerViewController *playerViewController = [[AVPlayerViewController alloc] init];
playerViewController.player = self.player;
[self presentViewController:playerViewController animated:YES completion:nil];
[self.player play];
}
// 在UIView里播放
- (void)onViewPlayClick:(UIButton *)sender {
AVPlayerViewController *playerViewController = [[AVPlayerViewController alloc] init];
playerViewController.player = self.player;
playerViewController.view.frame = self.playerView.bounds;
[self.playerView addSubview:playerViewController.view];
[self.player play];
}