天天看點

20160917iOS音頻開發之資源(AVAsset)與中繼資料,解決擷取資源屬性問題(二)

接着上一篇iOS音頻開發之資源與中繼資料,解決擷取資源屬性問題(一)内容,回顧一下我們的問題。

先提出一個問題,生活中有很多的媒體格式,mp3,avi,rmvb等等,在蘋果環境下主要的媒體格式有4種,QuickTime(mov),MPEG-4 video(mp4,m4v),MPEG-4 audio(m4a),MPEG-Layer III audio(mp3),那麼問題來了,假如給你一個mp3檔案,比如歌曲《再見.mp3》張震嶽,你是不是有辦法讀取裡面的資料,比如讀取它的歌名,演唱者,屬于哪個專輯,專輯的封面,檔案的長度等等資訊???

四.媒體中繼資料

簡單的說了解中繼資料就是嵌入到媒體檔案中描述其内容的資訊,我們分析中繼資料,就能擷取媒體檔案的時長,标題,專輯名等等資訊。但是不同的媒體檔案,她的中繼資料的格式是不同的,QuickTime 有它的中繼資料的格式,mp4,mp3,也有各自中繼資料的格式,是以我們的解析是要分不同情況的,對問題的解決又設了一道坎。我目前隻對mp3檔案進行研究,如果有興趣可以分析QuickTime和MPEG-4的格式,是比較複雜的,有個重要的概念就是atoms。我們可以檢視下面的圖一,mp3的媒體格式。

20160917iOS音頻開發之資源(AVAsset)與中繼資料,解決擷取資源屬性問題(二)

我再次用HexFiend用16進制打開《再見.mp3》的檔案,可以看到下面的部分資料

49 44 33 03 00 00 00 02 52 65 54 50 45 31 00 00 00 09 00 00 01 FF FE 20 5F 07 97 B3 5C 54 41 4C 42 00 00 00 07 00 00 01 FF FE 4F 00 6B 00 54 49 54 32 00 00 00 07 00 00 01 FF FE 8D 51 C1 89 54 59 45 52 00 00 00 17 00 00 01 FF FE 32 00 30 00 30 00 37 00 2D 00 30 00 37 00 2D 00 30 00 36 00 41 50 49 43 00 00 A5 05 00 00 01 69 6D 61 67 65 2F 6A 70 65 67 00 03 FF FE 65 00 00 00 FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 00 48 00 48 00 00 FF FE 00 3C 43 52 45 41 54 4F 52 3A 20 67 64 2D 6A 70 65 67 20 76 31 2E 30 20 28 75 73 69 6E 67 20 49 4A 47 20 4A 50 45 47 20 76 36 32 29 2C 20 71 75 61 6C 69 74 79 20 3D 20 31 30 30 0A FF DB 00 43 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01

聯系圖一,mp3的前三位元組是ID3,我們檢視ascii表,16進制應該表示為 49 44 33,比較一下,果然對應。是以我們分析這些數字是可以擷取我所想要的資訊的。當然我們需要模組化,直接分析這些16進制的可能性不大。

五.分析中繼資料

       有段文字的描述,AVAsset和AVAssetTrack都可以實作查詢相關中繼資料的功能,大部分的情況下,我們使用AVAsset,不過當涉及擷取曲目一級中繼資料等情況時會使用AVAssetTrack。讀取具體資源資料的接口有名為AVMetadataItem的類提供。這個類提供了一個面向對象的接口,讓開發者可以對存儲于QuickTime,MPEG-4 atom,ID3幀中的中繼資料進行通路。

       下面是我寫的一段代碼,讀取mp3檔案的資訊。

NSURL *assetUrl = [[NSBundle mainBundle] URLForResource:@"再見" withExtension:@"mp3"];
    AVAsset *asset = [AVAsset assetWithURL:assetUrl];
    NSArray *keys = @[@"availableMetadataFormats"];
    
    [asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
       
        NSMutableArray *metadata = [NSMutableArray array];
        for (NSString *format in asset.availableMetadataFormats) {
            NSLog(@"---1--result------->%@",format);
            [metadata addObjectsFromArray:[asset metadataForFormat:format]];
        }
        NSLog(@"-----2---result---->%@",metadata);
    }];
           

得到列印的資訊如下

2016-09-18 10:32:56.801 20160823CreatAVFoundation[1161:44742] ---1--result------->org.id3

2016-09-18 10:33:12.856 20160823CreatAVFoundation[1161:44742] -----2---result---->[

<AVMetadataItem: 0x7fc53270e910, identifier=id3/TPE1, keySpace=org.id3, key class = NSTaggedPointerString, key=TPE1, commonKey=artist, extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={

}, value=張震嶽>,

<AVMetadataItem: 0x7fc5327176d0, identifier=id3/TALB, keySpace=org.id3, key class = NSTaggedPointerString, key=TALB, commonKey=albumName, extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={

}, value=Ok>,

<AVMetadataItem: 0x7fc532703b80, identifier=id3/TIT2, keySpace=org.id3, key class = NSTaggedPointerString, key=TIT2, commonKey=title, extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={

}, value=再見>,

<AVMetadataItem: 0x7fc53270b160, identifier=id3/TYER, keySpace=org.id3, key class = NSTaggedPointerString, key=TYER, commonKey=(null), extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={

}, value=2007-07-06>,

<AVMetadataItem: 0x7fc5324ab9e0, identifier=id3/APIC, keySpace=org.id3, key class = NSTaggedPointerString, key=APIC, commonKey=artwork, extendedLanguageTag=(null), dataType=com.apple.metadata.datatype.JPEG, time={INVALID}, duration={INVALID}, startDate=(null), extras={

info = e,

dataTypeNamespace = org.iana.media-type,

dataType = image/jpeg,

pictureType = Cover (front)

}, value length=42226>

]

我們發現一些重要的資訊如keySpace,identifier,commonKey,AVMetadataItem,dataType等資訊。一個重要的概念就是keySpace。

keySpace 蘋果的解釋的文檔是

Indicates the key space of the metadata item’s key.

This is typically the default key space for the metadata container in which the metadata item is stored.

AVFoundation使用鍵空間将相關的鍵組合在一起,指的是中繼資料的鍵組成的空間。

commonKey也是很重要的概念,我們看到上面的程式運作結果資訊,有artist,albumname,artwork大家大概能猜到這是什麼資訊。我們再次觀察key值,聯系mp3中繼資料的結構圖,是不是發現了一些重要的資訊。下面是common鍵空間的示意圖。

20160917iOS音頻開發之資源(AVAsset)與中繼資料,解決擷取資源屬性問題(二)

檢視上圖,是common鍵空間的示意圖,Common鍵盤空間用來定義所有支援的媒體類型的鍵,包括曲目,歌手,插圖資訊,上面的輸出程式資訊就是這些資訊。好了,接下來的問題就是分析這些資訊,問題就解決了。問題沒有想象中那麼簡單,要考慮很多細節。執行個體代碼已經給出來了,注意下面的方法

- (NSArray<AVMetadataItem *> *)metadataForFormat:(NSString *)format;

表示用于定義中繼資料格式的NSString對象,并傳回一個包含所有相關中繼資料資訊的NSArray。數組裡面的資料資訊的AVMetadataItem,- (NSArray<AVMetadataItem *> *)

現在我們集中在研究AVMetadataItem上面的資訊好了。分析每一條AVMetadataItem就可以知道我們所想要的資訊,面對不同資源,這些資訊是差異的。

      上面的内容是一些理論知識,但是知道這些還是差了些,源碼中代碼的組織結構更是學習的。下一篇文章《iOS音頻開發之資源(AVAsset)與中繼資料,解決擷取資源屬性問題(三)》源碼分析。

本文

     完!