AVFoundation-02资源

作者: 秦明Qinmin | 来源:发表于2017-06-22 22:07 被阅读438次

    概述

    AVFoundation 是一个可以用来使用和创建基于时间的视听媒体数据的框架。AVFoundation 的构建考虑到了目前的硬件环境和应用程序,其设计过程高度依赖多线程机制。充分利用了多核硬件的优势并大量使用block和GCD机制,将复杂的计算机进程放到了后台线程运行。会自动提供硬件加速操作,确保在大部分设备上应用程序能以最佳性能运行。该框架就是针对64位处理器设计的,可以发挥64位处理器的所有优势。

    iOS 媒体环境.png

    AVAsset

    AVFondation 是一个非常强大且可扩展的框架,包括对媒体的捕捉、组合、播放和处理等广泛功能,同时它还有别于传统面向文件的音频类,框架把所有的代码设计围绕着 “资源” 进行。资源最重要的类是 AVAsset,它是 AVFoundation 设计的核心,在几乎所有特性和功能的开发中扮演着至关重要的角色。AVAsset 是一个抽象类,定义了媒体资源混合呈现的方式,将媒体的静态属性模块化成一个整体,比它们的标题、时长、元数据。
    AVAsset 不需要考虑媒体资源所具有的两个重要范畴。第一是它提供了对基本媒体格式的层抽象。也就是说无论是处理影片、音频,对开发者和框架而言面对的只有资源这个概念,让开发者面对不同格式的内容的时候有统一的处理方法,不用考虑许多编解码的细节。第二是它隐藏了资源的位置信息。当我们处理资源的时候,可以通过URL来创建资源,这个地址可能在本地、也可能在远程服务器上。

    AVAssetTrack

    AVAsset 本身不是媒体资源,但是它可以作为时基媒体的容器。它由一个或多个带有描述自身元数据的媒体组成。我们使用 AVAssetTrack 类代表保存在资源中统一类型媒体,并对每个资源建立相应的模型。AVAssetTrack 常见的形态是音频和视频流,但是它还可以表示文本、副标题、隐藏字幕等媒体类型。

    AVAsset 的组成.png

    在 AVAsset 中,可以通过 TrackID,获得特定的 AVAssetTrack。

    - (nullable AVAssetTrack *)trackWithTrackID:(CMPersistentTrackID)trackID;
    

    除了通过trackID获得track之外,AVAsset中还提供了其他3中方式获得track

    @property (nonatomic, readonly) NSArray<AVAssetTrack *> *tracks;
    - (NSArray<AVAssetTrack *> *)tracksWithMediaType:(NSString *)mediaType;
    - (NSArray<AVAssetTrack *> *)tracksWithMediaCharacteristic:(NSString *)mediaCharacteristic;
    

    tracks中包含了当前 AVAsset 中的所有track,通过遍历我们可以获得想要的track。- (NSArray<AVAssetTrack *> *)tracksWithMediaType:(NSString *)mediaType; 方法会根据指定的媒体类型返回一个track数组,数组中包含着Asset中所有指定媒体类型的track。如果Asset中没有这个媒体类型的track,返回一个空数组。AVMediaFormat 中有以下几种媒体类型:

    AVF_EXPORT NSString *const AVMediaTypeVideo                 NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMediaTypeAudio                 NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMediaTypeText                  NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMediaTypeClosedCaption         NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMediaTypeSubtitle              NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMediaTypeTimecode              NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMediaTypeMetadata              NS_AVAILABLE(10_8, 6_0);
    AVF_EXPORT NSString *const AVMediaTypeMuxed                 NS_AVAILABLE(10_7, 4_0);
    

    - (NSArray<AVAssetTrack *> *)tracksWithMediaCharacteristic:(NSString *)mediaCharacteristic; 方法会根据指定的媒体特征返回track数组。如果 AVAsset 中没有这个媒体特征的track,返回空数组。AVMediaFormat中一共有以下几种媒体特征:

     NSString *const AVMediaTypeMetadataObject;
     NSString *const AVMediaCharacteristicVisual;
     NSString *const AVMediaCharacteristicAudible;
     NSString *const AVMediaCharacteristicLegible;
     NSString *const AVMediaCharacteristicFrameBased;
     NSString *const AVMediaCharacteristicIsMainProgramContent;
     NSString *const AVMediaCharacteristicIsAuxiliaryContent;
     NSString *const AVMediaCharacteristicContainsOnlyForcedSubtitles;
     NSString *const AVMediaCharacteristicTranscribesSpokenDialogForAccessibility;
     NSString *const AVMediaCharacteristicDescribesMusicAndSoundForAccessibility;
     NSString *const AVMediaCharacteristicEasyToRead;
     NSString *const AVMediaCharacteristicDescribesVideoForAccessibility;
     NSString *const AVMediaCharacteristicLanguageTranslation;
     NSString *const AVMediaCharacteristicDubbedTranslation;
     NSString *const AVMediaCharacteristicVoiceOverTranslation;
    

    创建资源

    AVAsset 是一个抽象类,不能直接实例化。当使用 assetWithURL: 方法创建实例的时候,实际上创建的是它的子类,子类为AVURLAsset 。

    NSURL *mp3URL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"test" ofType:@"mp3"]];
    AVAsset *asset = [AVAsset assetWithURL:mp3URL];
    

    我们也可以直接创建 AVURLAsset 实例,我们可以传递更多的参数,来更精确地获取计时相关的信息。当然这样做可能需要加载更长的时间,以便获取更准确的时长及时间信息。

     NSDictionary *dict = @{
                               AVURLAssetPreferPreciseDurationAndTimingKey : @(YES)
                               };
     NSURL *mp3URL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"test" ofType:@"mp3"]];
     AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:mp3URL options:dict];
    

    照片库

    用户使用相机或者第三方视频捕捉程序捕捉的视频,它们通常被保存在用户的照片库中。我们可以通过 AssetsLibrary 来访问照片,并创建 AVAsset 对象。

    ALAssetsLibrary *assetLib = [[ALAssetsLibrary alloc] init];
    [assetLib enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
                            usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
                                [group setAssetsFilter:[ALAssetsFilter allVideos]];
                                
                                [group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:0]
                                                        options:0
                                                     usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
                                                         if (result) {
                                                             NSURL *url = [[result defaultRepresentation] url];
                                                             AVAsset *asset = [AVAsset assetWithURL:url];
                                                             
                                                         }
                                }];
                                
                            } failureBlock:^(NSError *error) {
                              NSLog(@"%@", [error localizedDescription]);
                          }];
    

    异步载入

    AVAsset 具有多种有用的方法和属性,可以提供有关的资源信息,比如时长、创建日期和元数据。当创建资源的时候,是对媒体文件的处理。为了高效加载资源,AVAsset 使用了延迟加载资源属性的方案。不过属性的访问总是同步发生,如果正在请求的属性没有预先加载,程序就会阻塞。不过 AVAsset 和 AVAssetTrack 提供了异步加载资源属性的方案。AVAsset 和 AVAssetTrack 都实现了 AVAsynchronousKeyValueLoading 协议,可以通过相关的接口进行异步查询资源的属性。

    // 查询给定属性的状态
    - (AVKeyValueStatus)statusOfValueForKey:(NSString *)key error:(NSError * _Nullable * _Nullable)outError;
    // 异步载入一个给定的属性 
    - (void)loadValuesAsynchronouslyForKeys:(NSArray<NSString *> *)keys completionHandler:(nullable void (^)(void))handler;
    
    NSURL *mp3URL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"test" ofType:@"mp3"]];
    AVURLAsset *asset = [AVURLAsset assetWithURL:mp3URL];
    
    [asset loadValuesAsynchronouslyForKeys:@[@"tracks"] completionHandler:^{
        
        NSError *error;
        AVKeyValueStatus status = [asset statusOfValueForKey:@"tracks" error:&error];
        
        switch (status) {
            case AVKeyValueStatusLoaded:
                
                break;
            case AVKeyValueStatusLoading:
                
                break;
            case AVKeyValueStatusUnknown:
                
                break;
            case AVKeyValueStatusFailed:
                
                break;
            case AVKeyValueStatusCancelled:
                
                break;
            default:
                break;
        }
    }];
    
    • 每次调用 - (void)loadValuesAsynchronouslyForKeys:(NSArray<NSString *> *)keys completionHandler:(nullable void (^)(void))handler; 只调用一次 completionHandler 块,调用该方法的次数并不是根据传递给这个方法的键的个数而定的。
    • 需要为每个请求的属性调用 - (AVKeyValueStatus)statusOfValueForKey:(NSString *)key error:(NSError * _Nullable * _Nullable)outError; 方法。不能假设所有的属性都返回相同的状态值。

    元数据

    AVAsset 和 AVAssetTrack 都可以实现相关元数据的查询功能。大部分情况下我们会使用 AVAsset 提供的元数据,不过涉及获取曲目一级元数据等情况时也会使用 AVAssetTrack。读取具体资源元数据的接口名为 AVMetadataItem 的类提供。

    // 属性中包含着当前视频常见格式类型的元数据
    @property (nonatomic, readonly) NSArray<AVMetadataItem *> *commonMetadata;
    
    // 属性中包含当前视频所有格式类型的元数据
    @property (nonatomic, readonly) NSArray<AVMetadataItem *> *metadata NS_AVAILABLE(10_10, 8_0);
    
    // 属性中包含当前视频所有可用元数据的格式类型
    元数据的格式类型在AVMetadataFormat中定义了很多种,常见的有title、creator、subject、publisher等
    @property (nonatomic, readonly) NSArray<NSString *> *availableMetadataFormats;
    
    // 通过format获取特定格式类型元数据
    - (NSArray<AVMetadataItem *> *)metadataForFormat:(NSString *)format;
    

    AVMetadata 的相关 Key 值。

    AVF_EXPORT NSString *const AVMetadataCommonKeyTitle                                      NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyCreator                                    NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeySubject                                    NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyDescription                                NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyPublisher                                  NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyContributor                                NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyCreationDate                               NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyLastModifiedDate                           NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyType                                       NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyFormat                                     NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyIdentifier                                 NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeySource                                     NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyLanguage                                   NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyRelation                                   NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyLocation                                   NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyCopyrights                                 NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyAlbumName                                  NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyAuthor                                     NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyArtist                                     NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyArtwork                                    NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyMake                                       NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeyModel                                      NS_AVAILABLE(10_7, 4_0);
    AVF_EXPORT NSString *const AVMetadataCommonKeySoftware
    

    章节元数据

    Asset中有一种特殊的元数据:章节。它是AVTimedMetadataGroup类型,这种类型表示一个只在特定时间段有效的元数据集合,也就是说章节中所包含的元数据只在当前章节的时间段有效。

    // 表示当前Asset中可用的章节Locale
    @property (readonly) NSArray<NSLocale *> *availableChapterLocales ;
    
    // 方法通过locale和元数据的commonkey筛选出特定的元数据,这些元数据只在当前章节的时间段有效
    - (NSArray<AVTimedMetadataGroup *> *)chapterMetadataGroupsWithTitleLocale:(NSLocale *)locale containingItemsWithCommonKeys:(nullable NSArray<NSString *> *)commonKeys NS_AVAILABLE(10_7, 4_3);
    
    // 方法通过指定一种语言,返回一个章节元数据数组。数组中越匹配指定语言的元数据,位置越靠前。
    - (NSArray<AVTimedMetadataGroup *> *)chapterMetadataGroupsBestMatchingPreferredLanguages:(NSArray<NSString *> *)preferredLanguages NS_AVAILABLE(10_8, 6_0);
    

    媒体选择

    一个多媒体文件中相同的媒体特征的东西可能会有很多,比如一个视频中可能会有2种字幕。对于类似选择哪个字幕的问题,有以下几个API:

    // 当前asset中有效的媒体特征选项。数组类型,里面包含着代表相应媒体特征的string.
    @property (nonatomic, readonly) NSArray<NSString *> *availableMediaCharacteristicsWithMediaSelectionOptions NS_AVAILABLE(10_8, 5_0);
    
    // 通过传入一个媒体特征类型,返回可供选择的媒体选项集合。例如传入字幕的媒体特征类型,返回当前Asset的可供选择的字幕选项集合。
    - (nullable AVMediaSelectionGroup *)mediaSelectionGroupForMediaCharacteristic:(NSString *)mediaCharacteristic NS_AVAILABLE(10_8, 5_0);
    
    // 主要是为各个媒体选项集合提供默认选项。
    @property (nonatomic, readonly) AVMediaSelection *preferredMediaSelection NS_AVAILABLE(10_11, 9_0);
    

    参考

    AVFoundation开发秘籍:实践掌握iOS & OSX应用的视听处理技术

    源码地址:AVFoundation开发 https://github.com/QinminiOS/AVFoundation

    相关文章

      网友评论

        本文标题:AVFoundation-02资源

        本文链接:https://www.haomeiwen.com/subject/cxvxcxtx.html