iOS AVFoundation之AVMetadataItem

AVMetadataItem其实就是一个模型类, 主要是用来保存音视频等多媒体资料的各种附加信息。称之为元数据。
例如:作者, 标题, 创建时间, 封面等描述关于这个多媒体的一些常见描述信息。
在分析这个之前,大家可以下载一个元数据分析工具,对一个多媒体文件进行详细的分析, 有助于我们学习AVFoundation, 大家可以去苹果工具下载中心 搜索Atom Inspector 进行下载
大家也可以到AVFoundation(二):核心AVAsset先去了解一下AVFoundation核心类,详细介绍了Atom Inspector的用法 这里主要介绍AVMetadataItem

  1. AVMetadataItem获取

AVMetadataItem还有一个子类AVMutableMetadataItem, 他们两主要的区别就是一个不可变, 一个可变的, AVMetadataItem的属性基本都是只读(readonly)的, 而AVMutableMetadataItem的属性是可读可写(readwrite)。
AVMutableMetadataItem 除了常规的init的方法创建还可以通过+ (AVMutableMetadataItem *)metadataItem; 这个类方法创建。
AVMetadataItem: 这个一般不自己创建而是从AVAssetTrack 和 AVAsset获取到AVMetadataItem数组, 一个AVMetadataItem对象存放着一个信息。

  NSURL *assetUrl = [[NSBundle mainBundle] URLForResource:@"Hubblecast" withExtension:@"mov"];
    AVAsset *videoAsset = [AVAsset assetWithURL:assetUrl];
    NSArray *keys = @[@"tracks", @"availableMetadataFormats"];
    [self obtainAVMetadataItem:videoAsset];
    [videoAsset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
        NSError *error = nil;
        //获取加载tracks的状态, 作出相应的操作
       AVKeyValueStatus status =  [videoAsset statusOfValueForKey:@"tracks" error:&error];
        switch (status) {
            case AVKeyValueStatusUnknown:
                NSLog(@"AVKeyValueStatusUnknown");
                //加载tracks未知错误
                break;
            case AVKeyValueStatusFailed:
                NSLog(@"AVKeyValueStatusFailed");
                //加载tracks失败
                break;
            case AVKeyValueStatusLoading:
                NSLog(@"AVKeyValueStatusLoading");
                //加载tracks中
                break;
            case AVKeyValueStatusLoaded:
                NSLog(@"AVKeyValueStatusLoaded");
                //加载tracks完毕
                break;
            case AVKeyValueStatusCancelled:
                NSLog(@"AVKeyValueStatusCancelled");
                //取消加载tracks
                break;
                
        }
        
         status =  [videoAsset statusOfValueForKey:@"availableMetadataFormats" error:&error];
        switch (status) {
            case AVKeyValueStatusUnknown:
                NSLog(@"AVKeyValueStatusUnknown");
                //加载AVKeyValueStatusUnknown未知错误
                break;
            case AVKeyValueStatusFailed:
                NSLog(@"AVKeyValueStatusFailed");
                //加载AVKeyValueStatusUnknown失败
                break;
            case AVKeyValueStatusLoading:
                NSLog(@"AVKeyValueStatusLoading");
                //加载AVKeyValueStatusUnknown中
                break;
            case AVKeyValueStatusLoaded:
            {
                NSLog(@"AVKeyValueStatusLoaded");
                //加载AVKeyValueStatusUnknown完毕
               //获取videoAsset里面的元数据
                NSMutableArray *metadata = [NSMutableArray array];
                for (NSString *format in videoAsset.availableMetadataFormats) {
                    NSLog(@"%@", format);
                    NSLog(@"%@", [videoAsset metadataForFormat:format]);
                    [metadata addObject:[videoAsset metadataForFormat:format]];
                    
                    
                }
                for (AVMetadataItem *item in metadata.firstObject) {
                    NSLog(@"%@--%@\n",item.key, item.value);
                }
                [self keySpac:metadata];
                
                break;
            }
            case AVKeyValueStatusCancelled:
                NSLog(@"AVKeyValueStatusCancelled");
                //取消加载AVKeyValueStatusUnknown
                break;
                
        }
    }];
    

这里要注意的是AVFoundation里面很多类的属性都是用到时才加载,对于一些加载过程中比较耗时的属性,遵守了AVAsynchronousKeyValueLoading这个协议,使用异步加载的方式,防止界面卡顿
loadValuesAsynchronouslyForKeys 和 statusOfValueForKey
使用注意点
loadValuesAsynchronouslyForKeys 中的不管在keys中设置了多少个属性值, completionHandler只会调用一次,
所以在 completionHandler中获取 AVKeyValueStatus状态在keys有多个是不准确的, 得每个属性分开, 一个key对应一个statusOfValueForKey中获取加载状态

  1. AVMetadataItem分析

我们打印这个视频的创建时间AVMetadataItem出来看看:

 "<AVMetadataItem: 0x6100000139f0, identifier=mdta/com.apple.quicktime.year, keySpace=mdta, key class = __NSCFString, key=com.apple.quicktime.year, commonKey=(null), extendedLanguageTag=en-US, dataType=com.apple.metadata.datatype.UTF-8, time={INVALID}, duration={INVALID}, startDate=(null), extras={\n    dataType = 1;\n    dataTypeNamespace = \"com.apple.quicktime.mdta\";\n}, value=2013>"

再结合他的属性:


/* Indicates the identifier of the metadata item. Publicly defined identifiers are declared in AVMetadataIdentifiers.h. */
@property (nonatomic, readonly, copy, nullable) NSString *identifier NS_AVAILABLE(10_10, 8_0);

/* indicates the IETF BCP 47 (RFC 4646) language identifier of the metadata item; may be nil if no language tag information is available */
@property (nonatomic, readonly, copy, nullable) NSString *extendedLanguageTag NS_AVAILABLE(10_10, 8_0);

/* indicates the locale of the metadata item; may be nil if no locale information is available for the metadata item */
@property (nonatomic, readonly, copy, nullable) NSLocale *locale;

/* indicates the timestamp of the metadata item. */
@property (nonatomic, readonly) CMTime time;

/* indicates the duration of the metadata item */
@property (nonatomic, readonly) CMTime duration NS_AVAILABLE(10_7, 4_2);

/* indicates the data type of the metadata item's value.  Publicly defined data types are declared in <CoreMedia/CMMetadata.h> */
@property (nonatomic, readonly, copy, nullable) NSString *dataType NS_AVAILABLE(10_10, 8_0);

/* provides the value of the metadata item */
@property (nonatomic, readonly, copy, nullable) id<NSObject, NSCopying> value;

/* provides a dictionary of the additional attributes */
@property (nonatomic, readonly, copy, nullable) NSDictionary<NSString *, id> *extraAttributes;


可以看出, 每个属性相对应的值。所以我们可以很直观的把AVMetadataItem就是我们平时开发中用到的模型。里面都是键值对的存在 。

  1. 筛选AVMetadataItem

/*!
 @method            metadataItemsFromArray:withLocale:
 @discussion        Instead, use metadataItemsFromArray:filteredAndSortedAccordingToPreferredLanguages:.
 */
+ (NSArray<AVMetadataItem *> *)metadataItemsFromArray:(NSArray<AVMetadataItem *> *)metadataItems withLocale:(NSLocale *)locale;

/*!
 @method            metadataItemsFromArray:withKey:keySpace:
 @discussion        Instead, use metadataItemsFromArray:filteredByIdentifier:.
 */
+ (NSArray<AVMetadataItem *> *)metadataItemsFromArray:(NSArray<AVMetadataItem *> *)metadataItems withKey:(nullable id)key keySpace:(nullable NSString *)keySpace;

/*!
 @method        metadataItemsFromArray:filteredAndSortedAccordingToPreferredLanguages:
 @abstract      Filters an array of AVMetadataItems according to whether their locales match any language identifier in the specified array of preferred languages. The returned array is sorted according to the order of preference of the language each matches.
 @param         metadataItems
                An array of AVMetadataItems to be filtered and sorted.
 @param         preferredLanguages
                An array of language identifiers in order of preference, each of which is an IETF BCP 47 (RFC 4646) language identifier. Use +[NSLocale preferredLanguages] to obtain the user's list of preferred languages.
 @result        An instance of NSArray containing metadata items of the specified NSArray that match a preferred language, sorted according to the order of preference of the language each matches.
*/
+ (NSArray<AVMetadataItem *> *)metadataItemsFromArray:(NSArray<AVMetadataItem *> *)metadataItems filteredAndSortedAccordingToPreferredLanguages:(NSArray<NSString *> *)preferredLanguages NS_AVAILABLE(10_8, 6_0);

/*!
    @method         metadataItemsFromArray:filteredByIdentifier:
    @abstract           Filters an array of AVMetadataItems according to identifier.
    @param          metadataItems
    An array of AVMetadataItems to be filtered by identifier.
    @param          identifier
    The identifier that must be matched for a metadata item to be copied to the output array. Items are considered a match not only when their identifiers are equal to the specified identifier, and also when their identifiers conform to the specified identifier.
    @result         An instance of NSArray containing the metadata items of the target NSArray that match the specified identifier.
*/
+ (NSArray<AVMetadataItem *> *)metadataItemsFromArray:(NSArray<AVMetadataItem *> *)metadataItems filteredByIdentifier:(NSString *)identifier NS_AVAILABLE(10_10, 8_0);

/*!
    @method         metadataItemsFromArray:filteredByMetadataItemFilter:
    @abstract       Filters an array of AVMetadataItems using the supplied AVMetadataItemFilter.
    @param          metadataItems
                    An array of AVMetadataItems to be filtered.
    @param          metadataItemFilter
                    The AVMetadataItemFilter object for filtering the metadataItems.
    @result         An instance of NSArray containing the metadata items of the target NSArray that have not been removed by metadataItemFilter.
*/
+ (NSArray<AVMetadataItem *> *)metadataItemsFromArray:(NSArray<AVMetadataItem *> *)metadataItems filteredByMetadataItemFilter:(AVMetadataItemFilter *)metadataItemFilter NS_AVAILABLE(10_9, 7_0);

里面有好几个方法进行筛选的, 传进一个筛选前的AVMetadataItem数组进去,根据identifier, preferredLanguages进行筛选, 这两个比较简单。
而 根据key和keySpace的话就要注意文件的类型了
这里的keySpace是根据文件的类型来的
1、 iTunes: iTunes 包括 Audio/Video 文件格式一般有:.mp4, .m4v, .m4a; 对应的 keySpace 是 AVMetadataKeySpaceiTunes

2、 Quicktime Metadata 包括 Quicktime movie 格式有: .mov 对应的 keySpace 是 AVMetadataKeySpaceQuickTimeMetadata

3、 Quicktime User Dara 包括 Quicktime movie 格式有: .mov 对应的 keySpace 是 AVMetadataKeySpaceQuickTimeUserData

4、 ID3 包括 MPEG Layer III 格式有:.mp3 对应的 keySpace 是 AVMetadataKeySpaceID3

5、其中Common类型包括了 iTunes, Quicktime Metadata, Quicktime User Dara, ID3等等 是一个汇总 对应的 keySpace 是AVMetadataKeySpaceCommon
根据相对应进去点进去 keySpace 底下就是 key, 根据key获取作者,标题,子标题, 创建时间, 时长等信息 都在AVMetadataFormat.h 中
所以一般我们用 AVMetadataKeySpaceCommon 和 AVMetadataKeySpaceCommon底下的key能满足我们的需求了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,519评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,842评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,544评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,742评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,646评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,027评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,169评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,324评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,268评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,299评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,996评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,591评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,911评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,288评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,871评论 2 341

推荐阅读更多精彩内容