当前位置: 首页 > 工具软件 > PVS.AVPlayer > 使用案例 >

iOS AVPlayer和AVPlayerViewController

彭令秋
2023-12-01

1. AVPlayer

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];

2. AVPlayerItem

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];
    }
}

3. AVPlayerViewController

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];
}
 类似资料: