媒體元數(shù)據(jù)
????媒體容器格式會存儲有關(guān)其媒體的描述性元數(shù)據(jù)。對于開發(fā)人員來說,使用元數(shù)據(jù)具有一定的挑戰(zhàn)性,因為每種容器格式都有自己獨特的元數(shù)據(jù)格式,需要對相應格式讀寫操作的底層技術(shù)有所了解。不過 AV Foundation 讓這一切變得簡單,它提供了 AVMetadataItem 類用于統(tǒng)一處理媒體元數(shù)據(jù),使得開發(fā)者不需要考慮大多數(shù)特定格式的細節(jié)。
元數(shù)據(jù)格式
加載資產(chǎn)的元數(shù)據(jù)
????AVAsset 和 AVAssetTrack 提供了三種方法可以獲取相關(guān)的元數(shù)據(jù),要了解這三種方法的適用范圍,首先要了解 keySpace 的含義。AV Foundation 使用 AVMetadataKeySpace 將各個鍵組合在一起的方法,可以實現(xiàn)對 AVMetadataItem 實例集合的篩選。

CommonMetadata
????每個資源至少有一個 AVMetadataKeySpaceCommon 通用鍵空間供從中獲取元數(shù)據(jù)。AVMetadataKeySpaceCommon 用來定義所有支持的媒體類型的鍵,包括諸如名稱,作者,描述等常見元素,這提供了一種對所有支持的媒體格式進行一定級別的元數(shù)據(jù)標準化的過程。開發(fā)者可以通過查詢 AVAsset 或者 AVAssetTrack 的 commonMetadata 屬性獲取元數(shù)據(jù)。
NSArray *keys = @[@"commonMetadata"];
[anAsset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
NSLog(@"CommonMetadata:%ld\n",anAsset.commonMetadata.count);
for (AVMetadataItem *item in anAsset.commonMetadata) {
NSLog(@"CommonMetadata,%@:%@\n",item.key,item.value);
}
}];
metadataForFormat
????訪問指定格式的元數(shù)據(jù)需要在 AVAsset 或者 AVAssetTrack 上調(diào)用 metadataForFormat方法。這個方法包含一個用于定義數(shù)據(jù)格式的 NSString 對象返回一個包含所有相關(guān)元數(shù)據(jù)信息的 NSArray。AVMetadataFormat.h 文件為不同的元數(shù)據(jù)格式提供對應的字符串常量。與硬編碼某個具體的元數(shù)據(jù)格式字符串不同,可以通過 availableMetadataFormats 獲取包含的所有元數(shù)據(jù)格式。
NSArray *keys = @[@"availableMetadataFormats"];
[anAsset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
AVKeyValueStatus status = [anAsset statusOfValueForKey:@"availableMetadataFormats" error:&error];
if(statuc == AVKeyValueStatusLoaded){
NSMutableArray *availableMetadatas = [NSMutableArray array];
for (NSString *format in anAsset.availableMetadataFormats) {
[availableMetadatas addObjectsFromArray:[anAsset metadataForFormat:format]];
}
NSLog(@"availablemetadatas.count:%ld\n",availableMetadatas.count);
for (AVMetadataItem *item in availableMetadatas) {
NSLog(@"availablemetadatas,%@:%@:%@\n",item.keySpace,item.key,item.value);
}
}
}];
注意: 調(diào)用
metadataForFormat:時要確保availableMetadataFormats已經(jīng)加載
metadata
????AV Foundation 在 iOS 8.0 提供了 metadata 方法查詢 AVAsset 所有可用的元數(shù)據(jù)數(shù)組。
NSArray *keys = @[@"metadata"];
[anAsset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
NSError *error;
AVKeyValueStatus status = [anAsset statusOfValueForKey:@"metadata" error:&error];
if(status == AVKeyValueStatusLoaded){
NSLog(@"metadata:%ld\n",anAsset.metadata.count);
for (AVMetadataItem *item in anAsset.metadata) {
NSLog(@"metadatas,%@:%@\n",item.key,item.value);
}
}
}];
查找元數(shù)據(jù)
????當我們得到一個包含元數(shù)據(jù)項的數(shù)組時,通常希望找到所需的具體元數(shù)據(jù)值。一個特別有效的方法是使用 AVMetadataItem 提供的便利方法,獲取結(jié)果集合并對其進行篩選。 AVMetadataItem 在早期通過metadataItemsFromArray:metadatawithKey:keySpace: 過濾指定的元數(shù)據(jù),例如,如果開發(fā)者希望獲得一個 .MOV 視頻文件的標題,需要按如下方法獲?。?/p>
NSArray *metadata = <#AVMetadataItem 的集合#>;
NSString * keySpace = AVMetadataKeySpaceCommon;
NSString *titleKey = AVMetadataCommonKeyTitle;
NSArray *titleMetadata = [AVMetadataItem metadataItemsFromArray:metadatawithKey:AVMetadataCommonKeyTitle keySpace:AVMetadataKeySpaceCommon];
????后來,上述方法已經(jīng)不建議使用。提供了新的方法用于查找指定的元數(shù)據(jù):
metadataItemsFromArray:filteredAndSortedAccordingToPreferredLanguages:metadataItemsFromArray:filteredByIdentifier:metadataItemsFromArray:filteredByMetadataItemFilter:
????例如,查找特定元數(shù)據(jù)項的最簡單方法是按 AVMetadataIdentifier(標識符)過濾,它將鍵空間和鍵組合成一個單元。以下示例顯示了如何從公共鍵空間中檢索標題項:
NSArray *metadata = <#AVMetadataItem 的集合#>;
NSArray *metadatas = [AVMetadataItem metadataItemsFromArray:availableMetadatas filteredByIdentifier:AVMetadataCommonIdentifierTitle];
使用元數(shù)據(jù)
????AVMetadataItem 最基本的形式其實是一個封裝鍵值對的容器??赏ㄟ^它定義的 AVMetadataKey commonKey,查詢其是否存在于公共鍵空間內(nèi),而 key 和 value 都被定義成 id <NSObject, NSCopying> 形式,它可能是 NSString, NSNumber等情況。如果開發(fā)者已經(jīng)提前知道 value 的類型,AVMetadataItem 提供三個類型強制屬性stringValue、numberValue 和 dataValue。
????由于 AVMetadataItem 的 key 是泛類型,我們在使用時可能存在獲取錯誤的情況,因此可以在 AVMetadataItem 上添加一個名為 keyString 的分類方法從而獲取 key 的字符串:
- (NSString *)keyString {
if ([self.key isKindOfClass:[NSString class]]) { // 1
return (NSString *)self.key;
}
else if ([self.key isKindOfClass:[NSNumber class]]) {
UInt32 keyValue = [(NSNumber *) self.key unsignedIntValue]; // 2
// Most, but not all, keys are 4 characters ID3v2.2 keys are
// only be 3 characters long. Adjust the length if necessary.
size_t length = sizeof(UInt32); // 3
if ((keyValue >> 24) == 0) --length;
if ((keyValue >> 16) == 0) --length;
if ((keyValue >> 8) == 0) --length;
if ((keyValue >> 0) == 0) --length;
long address = (unsigned long)&keyValue;
address += (sizeof(UInt32) - length);
// keys are stored in big-endian format, swap
keyValue = CFSwapInt32BigToHost(keyValue); // 4
char cstring[length]; // 5
strncpy(cstring, (char *) address, length);
cstring[length] = '\0';
// Replace '?' with '@' to match constants in AVMetadataFormat.h
if (cstring[0] == '\xA9') { // 6
cstring[0] = '@';
}
return [NSString stringWithCString:(char *) cstring // 7
encoding:NSUTF8StringEncoding];
}
else {
return @"<<unknown>>";
}
}