AVPlayer缓存相关学习

AVAssetResourceLoader

AVAssetResourceLoader使用一个你提供的delegate来传达来自AVURLAsset的request。当一个request到达,resource loader将询问delegate,它是否能处理,然后将结果返回给asset。

Overview

不用自己创建resource loader对象,而是从AVURLAsset的resourceLoader属性来取得一个resource loader,然后使用它分配自定义的delegate对象。
delegate对象必须实现AVAssetResourceLoaderDelegate协议

AVURLAsset

AVURLAsset是AVAsset的一个具体的子类,用来通过一个本地或者远程的URL来初始化一个asset。

AVAsset

AVAsset是一个抽象的、不可变的类,用来表示一个视频或者音频。一个asset可能包含一个或者多个想一起呈现的track,每一个media类型,包括但不限于音频、视频、文本、闭合字幕、副标题。

Overview

AVAsset定义了一个构成asset的track的属性全集。(你可以access表示track集合的AVAssetTrack实例,然后有需要的话,你可以独立的检查他们)
一般,你会用AVURLAsset来实例化一个asset,AVURLAsset是一个AVAsset的具体的子类,它包含一个指向音视频资源的URL,资源包括:streams(包含了http live stream),QuickTime movie文件,MP3文件以及其他类型的文件。也可以用其他具体的子类实例化一个asset,比如用于时间编辑的AVComposition。

AVAsset定义了全部的asset的属性,另外表示track的AVAssetTrack可以被获取到,可以用户独立去检查每个Track。

由于音视频媒体的时间相关的特性,在成功初始化的时候,asset的一些或者全部属性可能你不会立刻可用。对于任何key的value,可以在任何时刻请求,然后asset会以同步的方式返回value,所以会阻塞当前调用的线程。为了避免阻塞,可以注册感兴趣的key,然后当value可用时会有通知,具体可以查看AVAsynchronousKeyValueLoading。

播放一个AVAsset,可以用asset创建一个AVPlayerItem实例,使用playerItem来创建它的展示状态(比如是否只有一段有效时间可以被播放),然后将player item提供给AVPlayer。

你可以在AVMutableComposition中插入一个AVAsset,将一个或者多个asset资源进行整合。

AVPlayerItem

AVPlayerItem模拟了AVPlayer播放一个asset的时间和展示状态。它提供了seek、展示大小、确定当前时间等功能。

Overview

AVPlayerItem存储了一个AVAsset的引用,AVAsset表示一个待播放的媒体。将这个媒体入播放队列之前,如果你需要获得这个asset的一些信息的话,可以使用AVAsynchronousKeyValueLoading来获取你需要的value。或者AVPlayerItem可以自动读取需要的asset数据,只要把希望获取的key的集合传递给它的init(asset:automaticallyLoadedAssetKeys:) 方法。当一个player item准备好播放的时候,这些asset属性就会被加载好并且可用。

AVPlayerItem是一个动态的对象。除了它的属性值都可以被修改之外,很多read-only属性值可以在准备阶段和播放阶段,被关联的AVPlayer修改。还可以使用KVO来观测状态的改变。状态表明了item是否已经准备好要播放,是否已经可用。第一次创建palyer item,它的状态值是unknown,表明媒体资源还没有被加载以及还没有被放到播放队列里。当AVPlayer和player item关联的时候,item立刻被放入了播放队列,并且准备播放,但是你需要等待状态变为“readyToPlay”才可以使用。下面这段代码表明了如何注册和检测状态改变。

- (void)prepareToPlay {
    NSURL *url = <#Asset URL#>
    // Create asset to be played
    asset = [AVAsset assetWithURL:url];
    NSArray *assetKeys = @[@"playable", @"hasProtectedContent"];

    // Create a new AVPlayerItem with the asset and an
    // array of asset keys to be automatically loaded
    playerItem = [AVPlayerItem playerItemWithAsset:asset
                      automaticallyLoadedAssetKeys:assetKeys];

    NSKeyValueObservingOptions options =
        NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;

    // Register as an observer of the player item's status property
    [playerItem addObserver:self
                 forKeyPath:@"status"
                    options:options
                    context:&PlayerItemContext];

    // Associate the player item with the player
    player = [AVPlayer playerWithPlayerItem:playerItem];
}

prepareToPlay方法使用了addObserver:forKeyPath:options:context:来观察player item的状态变化。这个方法应该在关联player之前调用,以确保你可以抓取到所有的状态改变。

为了接受到状态改变的通知,需要实现observeValueForKeyPath:ofObject:change:context:方法。这个方法在每次状态改变的时候都会被调用,然后可以采取相应的动作。
代码如下:

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary<NSString *,id> *)change
                       context:(void *)context {
    // Only handle observations for the PlayerItemContext
    if (context != &PlayerItemContext) {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        return;
    }

    if ([keyPath isEqualToString:@"status"]) {
        AVPlayerItemStatus status = AVPlayerItemStatusUnknown;
        // Get the status change from the change dictionary
        NSNumber *statusNumber = change[NSKeyValueChangeNewKey];
        if ([statusNumber isKindOfClass:[NSNumber class]]) {
            status = statusNumber.integerValue;
        }
        // Switch over the status
        switch (status) {
            case AVPlayerItemStatusReadyToPlay:
                // Ready to Play
                break;
            case AVPlayerItemStatusFailed:
                // Failed. Examine AVPlayerItem.error
                break;
            case AVPlayerItemStatusUnknown:
                // Not ready
                break;
        }
    }
}

这个例子,取到了变化字典中的新状态,如果player item的状态是AVPlayerItemStatusReadyToPlay,那么它就已经可以使用。如果加载资源出错,状态将会变成AVPlayerItemStatusFailed。如果你查询错误的属性,会得到一个提供详细错误信息的NSError对象。

AVPlayer

AVPlayer是一个用来管理媒体资源播放和时间的控制器对象。它提供了一些控制播放器行为的接口:play、pause、改变播放速率、seek。可以使用AVPlayer播放本地和远程的资源文件,比如QuickTIme movies和MP3音频文件,还有HTTP live流的媒体。

Overview

Note
AVPlayer用来在一个时间点播放一个单独的媒体资源。通过replaceCurrentItem(with:) 方法,player实例可以复用,播放另一个media asset。框架中还提供了一个AVPlayer的子类,叫做>AVQueuePlayer,你可以使用它来创建和管理一个用于播放一系列媒体资源的队列。

你可以使用AVPlayer来播放media assets(AVAsset),AVAsset只是media的一些静态部分的model,比如视频长度、创建时间。就其本身而言,不适合直接使用AVPlayer播放。为了播放一个asset,需要先创建一个asset的动态配对AVPlayerItem。这个对象模拟了一个asse在AVPlayer播放的时候的时间和展示状态。

AVPlayer是一个状态不停改变的动态的对象,有两种方法来监测player的状态改变

  • 通用的状态观察:使用KVO来监测player的许多动态属性的改变,比如当前播放item(currentItem)或者它的播放速率。你需要在主线程注册和解除绑定KVO。这样可以避免当改变来自其他thread时,只接收到部分通知。AV Foundation 在主线程调用observeValue(forKeyPath:of:change:context:),即使改变操作发生在其他线程。

  • 时间状态观察:在通常的状态观察中,KVO效果不错,但是对于持续改变的状态,比如player的时间,就不是很好用了。AVPlayer提供了两个方法来观察时间的改变:

      addPeriodicTimeObserver(forInterval:queue:using:)
      addBoundaryTimeObserver(forTimes:queue:using:)
      这些方法使得你可以周期性的或者边界性的,观察时间的改变。当改变发生时,你提供的callback block会被调用,你可以再里面做一些响应操作,比如更新用户界面的状态。
    

AVPlayer和AVPlayerItem是不可见的对象,意味着只靠他们自己无法再屏幕上传呈现视频。你有两种主要的方法来呈现视频:

AVKit:呈现视频最好的方法就是在iOS和tvOS上使用AVKit框架的AVPlayerViewController或者在macOS上使用AVPlayerView。这些类提供了视频内容,以及播放控件和其他的媒体特性,给你一个功能全面的播放体验。

AVPlayerLayer:如果你想自己实现播放界面,你可以使用AVFoundation提供的一个CALayer的子类:AVPlayerLayer。player layer可以放在view的layer上或者可以直接加入到layer的层级当中。不像AVPlayerView和AVPlayerViewController,player layer并没有提供播放控件,但是再屏幕上呈现了视频内容,控制play、pause、seek的播放控件全部都取决于你自己。

使用AVKit和AVPlayerLayer的同时,你可以使用AVSynchronizedLayer来展现和player的时间同步的animated content(不明白指什么)。它是一个特殊的CoreAnimation CALayer的子类,that is used to confer the current player timing onto its layer subtree(不明白这句)。你可以使用AVSynchronizedLayer来创建一些自定义的core animation的效果,比如下三分之一动画或者视频转场,并且在player播放当前AVPlayerItem的同时,异步播放。

外部播放模式

Apple TV 相关,用不到先不翻译了。

posted @ 2017-08-25 21:12  张驰小方块  阅读(2317)  评论(0编辑  收藏  举报