AVFoundation – AVPlayer 播放视频

零基础 Object-C 学习路线推荐 : Object-C 学习目录 >> Object-C 基础

零基础 Object-C 学习路线推荐 : Object-C 学习目录 >> Object-C 线程

零基础 Object-C 学习路线推荐 : Object-C 学习目录 >> OpenGL ES

零基础 Object-C 学习路线推荐 : Object-C 学习目录 >> GPUImage

零基础 Object-C 学习路线推荐 : Object-C 学习目录 >> AVFoundation

零基础 Object-C 学习路线推荐 : Object-C 学习目录 >> CocoaPods


一.前言

1.AVAsset

Assets 可以来自一个文件或用户的相册,可以理解为多媒体资源,通过 URL 作为一个 asset 对象的标识. 这个 URL 可以是本地文件路径或网络流;


2.AVAssetTrack

AVAsset 包含很多轨道 AVAssetTrack 的结合,如 audio, video, text, closed captions, subtitles…


3.AVComposition / AVMutableComposition

使用 AVMutableComposition 类可以增删 AVAsset 来将单个或者多个 AVAsset 集合到一起,用来合成新视频。除此之外,若想将集合到一起的视听资源以自定义的方式进行播放,需要使用 AVMutableAudioMix 和 AVMutableVideoComposition 类对其中的资源进行协调管理;


4.AVMutableVideoComposition

AVFoundation 类 API 中最核心的类是 AVVideoComposition / AVMutableVideoComposition 。

AVVideoComposition / AVMutableVideoComposition 对两个或多个视频轨道组合在一起的方法给出了一个总体描述。它由一组时间范围和描述组合行为的介绍内容组成。这些信息出现在组合资源内的任意时间点。

AVVideoComposition / AVMutableVideoComposition 管理所有视频轨道,可以决定最终视频的尺寸,裁剪需要在这里进行;


5.AVMutableCompositionTrack

多个 AVAsset 集合到一起合成新视频中轨道信息,有音频轨、视频轨等,里面可以插入各种对应的素材(画中画,水印等);


6.AVMutableVideoCompositionLayerInstruction

AVMutableVideoCompositionLayerInstruction 主要用于对视频轨道中的一个视频处理缩放、模糊、裁剪、旋转等;


7.AVMutableVideoCompositionInstruction

表示一个指令,决定一个 timeRange 内每个轨道的状态,每一个指令包含多个 AVMutableVideoCompositionLayerInstruction ;而 AVVideoComposition 由多个 AVVideoCompositionInstruction 构成;

AVVideoCompositionInstruction 所提供的最关键的一段数据是组合对象时间轴内的时间范围信息。这一时间范围是在某一组合形式出现时的时间范围。要执行的组全特质是通过其 AVMutableVideoCompositionLayerInstruction 集合定义的。


8.AVAssetExportSession

AVAssetExportSession 主要用于导出视频;


二.AVPlayer 简介

首先在 iOS 平台使用播放视频,可用的选项一般有这四个,他们各自的作用和功能如下: 

AVFoundation – AVPlayer 播放视频 

由此可以看出,如果我们不做直播功能 AVPlayer 就是一个最优的选择。在创建一个播放器之前我们需要先了解一些播放器相关的类


1.AVPlayer

AVPlayer 控制播放器的播放,暂停,播放速度;

/*创建AVPlayer播放器*/
+ (instancetype)playerWithURL:(NSURL *)URL;
+ (instancetype)playerWithPlayerItem:(nullable AVPlayerItem *)item;
- (instancetype)initWithURL:(NSURL *)URL;
- (instancetype)initWithPlayerItem:(nullable AVPlayerItem *)item;

/*当前播放器播放的时间*/
- (CMTime)currentTime;

/*播放速度
    rate = 0.5;   // 慢放
    rate = 1.0;   // 正常播放
    rate = 0.0;   // 暂停
    rate = -0.5;  // 倒放
 */
@property (nonatomic) float rate;

/*播放 默认 rate = 1.0*/
- (void)play;

/*暂停播放 rate = 0.0*/
- (void)pause;

注意更改播放速度要在视频开始播放之后才会生效;


2.AVURLAsset

前面文章有对 AVAsset 介绍,AVURLAsset 是 AVAsset 的一个子类,使用 URL 进行实例化,实例化对象包换 URL 对应视频资源的所有信息;

NSURL *url = <#A URL that identifies an audiovisual asset such as a movie file#>;
AVURLAsset *anAsset = [[AVURLAsset alloc] initWithURL:url options:nil];

注意 NSURL 的使用:

[NSURL URLWithString:@"网络路径"]
[NSURL fileURLWithPath:@"本地路径"]
如果读取的是本地文件,那么请用第二个方法,第一个会出错,读取不到URL.

3.AVPlayerItem

AVPlayerItem 管理资源对象,提供播放数据源;


4.AVPlayerLayer

AVPlayerLayer 负责显示视频,如果没有添加该类,只有声音没有画面;


三.AVPlayer播放视频

- (BOOL)playVideoFile
{
    //创建一个资源实例
    NSURL* url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"123.mp4" ofType:nil]];
    AVURLAsset* asset = [[AVURLAsset alloc] initWithURL:url options:nil];
    
    //AVPlayerItem关联播放资源
    AVPlayerItem* item = [[AVPlayerItem alloc] initWithAsset:asset];
    
    //创建AVPlayer
    AVPlayer* player = [AVPlayer playerWithPlayerItem:item];
    
    //创建AVPlayerLayer用来显示资源内容
    AVPlayerLayer* playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
    //设置frame
    playerLayer.frame = self.view.frame;
    //添加到当前的view,否则无法显示
    [self.view.layer addSublayer:playerLayer];
    
    //播放
    [player play];
    
    return YES;
}
AVFoundation – AVPlayer 播放视频

四.AVPlayer seek

关于这个 seektotime,拖动进度条跳转的时候,比如跳到 10 秒,结果跳到了 6 秒或者 8 秒,很奇怪!seektotime 跳转不准确 ?

解决办法: 使用这个方法 seekToTime:toleranceBefore:toleranceAfter: 通过设置偏差tolerance,来精确设定跳转的误差。

/*!
 @method            seekToTime:toleranceBefore:toleranceAfter:
 @abstract          Moves the playback cursor within a specified time bound.
 @param             time
 @param             toleranceBefore
 @param             toleranceAfter
 @discussion        Use this method to seek to a specified time for the current player item.
                    The time seeked to will be within the range [time-toleranceBefore, time+toleranceAfter] and may differ from the specified time for efficiency.
                    Pass kCMTimeZero for both toleranceBefore and toleranceAfter to request sample accurate seeking which may incur additional decoding delay. 
                    Messaging this method with beforeTolerance:kCMTimePositiveInfinity and afterTolerance:kCMTimePositiveInfinity is the same as messaging seekToTime: directly.
 */
- (void)seekToTime:(CMTime)time toleranceBefore:(CMTime)toleranceBefore toleranceAfter:(CMTime)toleranceAfter;


示例代码

    [_player seekToTime:playTime toleranceBefore:CMTimeMake(1, 1000) toleranceAfter:CMTimeMake(1, 1000)];

完整代码如下:


#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>



@interface ViewController ()
{
    AVPlayerItem* _item ;         //用于加载媒体
    AVPlayer* _player;            //控制播放器的播放,暂停,播放速度
    AVPlayerLayer* _playerLayer;  //用于显示画面
    float _duration;              //媒体的时间
}


@end

@implementation ViewController

#pragma mark - create slider
- (UISlider*)createSlider {
    
    /// 创建Slider 设置Frame
    UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(0, 100, 247, 50)];
    
    /// 属性配置
    // minimumValue  : 当值可以改变时,滑块可以滑动到最小位置的值,默认为0.0
    slider.minimumValue = 0.0;
    // maximumValue : 当值可以改变时,滑块可以滑动到最大位置的值,默认为1.0
    slider.maximumValue = 1.0;
    // 当前值,这个值是介于滑块的最大值和最小值之间的,如果没有设置边界值,默认为0-1;
    slider.value = 0;
    
    // continuous : 如果设置YES,在拖动滑块的任何时候,滑块的值都会改变。默认设置为YES
    [slider setContinuous:YES];
    
    // minimumTrackTintColor : 小于滑块当前值滑块条的颜色,默认为蓝色
    slider.minimumTrackTintColor = [UIColor redColor];
    // maximumTrackTintColor: 大于滑块当前值滑块条的颜色,默认为白色
    slider.maximumTrackTintColor = [UIColor blueColor];
    // thumbTintColor : 当前滑块的颜色,默认为白色
    slider.thumbTintColor = [UIColor yellowColor];
    
    // minimumTrackTintColor : 小于滑块当前值滑块条的颜色,默认为蓝色
    slider.minimumTrackTintColor = [UIColor redColor];
    // maximumTrackTintColor: 大于滑块当前值滑块条的颜色,默认为白色
    slider.maximumTrackTintColor = [UIColor blueColor];
    // thumbTintColor : 当前滑块的颜色,默认为白色
    slider.thumbTintColor = [UIColor yellowColor];
    
    return slider;
}
#pragma mark - seek
- (void)_sliderValueDidChanged:(id)sender {
    
    UISlider *slider = (UISlider*)sender;
    NSLog(@"slider:%f _player.currentTime:%f",slider.value,CMTimeGetSeconds(_player.currentTime));
    //seek
    [_player seekToTime:CMTimeMake(slider.value*_duration*60, 60) toleranceBefore:CMTimeMake(1, 1000) toleranceAfter:CMTimeMake(1, 1000)];
    //play
    [_player play];
    ;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
        
    //创建一个资源实例
    NSURL* url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"123.mp4" ofType:nil]];
    AVURLAsset* asset = [[AVURLAsset alloc] initWithURL:url options:nil];
    
    //获取总时间
    _duration = CMTimeGetSeconds(asset.duration);
    
    //AVPlayerItem关联播放资源
    _item = [[AVPlayerItem alloc] initWithAsset:asset];
    

    //添加观察者,对该状态进行监控,以决定何时可以进行播放
    [_item addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    
    //创建AVPlayer
    _player = [AVPlayer playerWithPlayerItem:_item];
   
    
    //创建AVPlayerLayer用来显示资源内容
    _playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
    //设置frame
    _playerLayer.frame = self.view.frame;
    //添加到当前的view,否则无法显示
    [self.view.layer addSublayer:_playerLayer];
    
    //创建滑块
    UISlider *slider = [self createSlider];
    // 事件监听
    [slider addTarget:self action:@selector(_sliderValueDidChanged:) forControlEvents:UIControlEventValueChanged];
    [self.view addSubview:slider];
    
}

#pragma mark - 监听播放器状态
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([object isKindOfClass:[AVPlayerItem class]]) {
        if([keyPath isEqualToString:@"status"])
        {
            switch(_item.status)
            {
                case AVPlayerItemStatusReadyToPlay:
                    [_player play];
                    NSLog(@"AVPlayerItemStatusReadyToPlay");
                    break;
                case AVPlayerItemStatusUnknown:
                    NSLog(@"AVPlayerItemStatusUnknown");
                    break;
                case AVPlayerItemStatusFailed:
                    NSLog(@"AVPlayerItemStatusFailed");
                    break;

                default:break;
            }
        }
    }
}

- (void)dealloc
{
    //删除观察者
    [self removeObserver:self forKeyPath:@"status"];
}

@end

AVFoundation – AVPlayer 播放视频

五.AVPlayer注意问题

AVPlayer 创建后,播放并不是可以直接使用,还要对它的状态进行检查,只有 AVPlayerItem.status 的值为 AVPlayerStatusReadyToPlay 时,才能进行播放,所以这里需要使用 KVO 模式对该状态进行监控,以决定何时可以进行播放,详细操作,我们在 AVPlayerItem 中再详细讲解;


六.猜你喜欢


未经允许不得转载:猿说编程 » AVFoundation – AVPlayer 播放视频
喜欢(3) 打赏

评论抢沙发

评论前必须登录!

文章付费之后,如果下载源码失败,请直接留言,博主看到消息会及时处理的,感谢配合!!!共勉!!

开始学习

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏