2011-11-23 41 views
7

Tôi đã tạo trình phát tùy chỉnh bằng cách sử dụng AVAudioPlayer. Bây giờ, tôi muốn lấy các chi tiết của tập tin âm thanh như tên nghệ sĩ, tên album, vv được thêm vào trong thư mục tài nguyên.cách lấy chi tiết tệp âm thanh trong iPhone

MPMusicPlayer cung cấp API để tìm nạp chi tiết nhưng sử dụng thư viện iPod và không lấy tài nguyên từ hộp cát của ứng dụng. Vì vậy, MPMusicPlayer sẽ không hoạt động trong kịch bản đó.

Vì vậy, làm cách nào chúng tôi có thể tìm nạp chi tiết tệp âm thanh trong iPhone.

Trả lời

14

Bạn có thể nhận thông tin này qua số AudioToolbox.framework. Các AudioToolbox.framework là một C API, vì vậy tôi đã viết một wrapper Objective-C cho nó:

ID3Tag .h:

@interface ID3Tag : NSObject <NSCoding> { 
    NSString* title_; 
    NSString* album_; 
    NSString* artist_; 
    NSNumber* trackNumber_; 
    NSNumber* totalTracks_; 
    NSString* genre_; 
    NSString* year_; 
    NSNumber* approxDuration_; 
    NSString* composer_; 
    NSString* tempo_; 
    NSString* keySignature_; 
    NSString* timeSignature_; 
    NSString* lyricist_; 
    NSString* recordedDate_; 
    NSString* comments_; 
    NSString* copyright_; 
    NSString* sourceEncoder_; 
    NSString* encodingApplication_; 
    NSString* bitRate_; 
    NSStream* sourceBitRate_; 
    NSString* channelLayout_; 
    NSString* isrc_; 
    NSString* subtitle_; 
} 

@property (nonatomic, retain) NSString *title; 
@property (nonatomic, retain) NSString *album; 
@property (nonatomic, retain) NSString *artist; 
@property (nonatomic, retain) NSNumber *trackNumber; 
@property (nonatomic, retain) NSNumber *totalTracks; 
@property (nonatomic, retain) NSString *genre; 
@property (nonatomic, retain) NSString *year; 
@property (nonatomic, retain) NSNumber *approxDuration; 
@property (nonatomic, retain) NSString *composer; 
@property (nonatomic, retain) NSString *tempo; 
@property (nonatomic, retain) NSString *keySignature; 
@property (nonatomic, retain) NSString *timeSignature; 
@property (nonatomic, retain) NSString *lyricist; 
@property (nonatomic, retain) NSString *recordedDate; 
@property (nonatomic, retain) NSString *comments; 
@property (nonatomic, retain) NSString *copyright; 
@property (nonatomic, retain) NSString *sourceEncoder; 
@property (nonatomic, retain) NSString *encodingApplication; 
@property (nonatomic, retain) NSString *bitRate; 
@property (nonatomic, retain) NSStream *sourceBitRate; 
@property (nonatomic, retain) NSString *channelLayout; 
@property (nonatomic, retain) NSString *isrc; 
@property (nonatomic, retain) NSString *subtitle; 

@end 

ID3TagParser.h

#import <Foundation/Foundation.h> 
#import "ID3Tag.h" 

@interface ID3Parser : NSObject { 

} 

- (ID3Tag*) parseAudioFileForID3Tag:(NSURL*) url; 

@end 

ID3TagParser.m

#import "ID3Parser.h" 
#import <AudioToolbox/AudioToolbox.h> 

@implementation ID3Parser 

- (ID3Tag*) parseAudioFileForID3Tag:(NSURL*) url { 
    if (url == nil) { 
     return nil; 
    } 

    AudioFileID fileID = nil; 
    OSStatus err = noErr; 

    err = AudioFileOpenURL((CFURLRef) url, kAudioFileReadPermission, 0, &fileID); 
    if(err != noErr) { 
     NSLog(@"AudioFileOpenURL failed"); 
     return nil; 
    } else { 
     UInt32 id3DataSize = 0; 
     char* rawID3Tag = NULL; 

     // Reads in the raw ID3 tag info 
     err = AudioFileGetPropertyInfo(fileID, kAudioFilePropertyID3Tag, &id3DataSize, NULL); 
     if(err != noErr) { 
      return nil; 
     } 

     // Allocate the raw tag data 
     rawID3Tag = (char *) malloc(id3DataSize); 

     if(rawID3Tag == NULL) { 
      return nil; 
     } 

     err = AudioFileGetProperty(fileID, kAudioFilePropertyID3Tag, &id3DataSize, rawID3Tag); 
     if(err != noErr) { 
      return nil; 
     } 

     UInt32 id3TagSize = 0; 
     UInt32 id3TagSizeLength = 0; 
     err = AudioFormatGetProperty(kAudioFormatProperty_ID3TagSize, id3DataSize, rawID3Tag, &id3TagSizeLength, &id3TagSize); 

     if(err != noErr) { 
      switch(err) { 
       case kAudioFormatUnspecifiedError: 
        NSLog(@"err: audio format unspecified error"); 
        return nil; 
       case kAudioFormatUnsupportedPropertyError: 
        NSLog(@"err: audio format unsupported property error"); 
        return nil; 
       case kAudioFormatBadPropertySizeError: 
        NSLog(@"err: audio format bad property size error"); 
        return nil; 
       case kAudioFormatBadSpecifierSizeError: 
        NSLog(@"err: audio format bad specifier size error"); 
        return nil; 
       case kAudioFormatUnsupportedDataFormatError: 
        NSLog(@"err: audio format unsupported data format error"); 
        return nil; 
       case kAudioFormatUnknownFormatError: 
        NSLog(@"err: audio format unknown format error"); 
        return nil; 
       default: 
        NSLog(@"err: some other audio format error"); 
        return nil; 
      } 
     } 

     CFDictionaryRef piDict = nil; 
     UInt32 piDataSize = sizeof(piDict); 

     // Populates a CFDictionary with the ID3 tag properties 
     err = AudioFileGetProperty(fileID, kAudioFilePropertyInfoDictionary, &piDataSize, &piDict); 
     if(err != noErr) { 
      NSLog(@"AudioFileGetProperty failed for property info dictionary"); 
      return nil; 
     } 

     // Toll free bridge the CFDictionary so that we can interact with it via objc 
     NSDictionary* nsDict = (NSDictionary*)piDict; 

     ID3Tag* tag = [[[ID3Tag alloc] init] autorelease]; 

     tag.album = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Album]]; 
     tag.approxDuration = [NSNumber numberWithInt:[[nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_ApproximateDurationInSeconds]] intValue]]; 
     tag.artist = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Artist]]; 
     tag.bitRate = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_NominalBitRate]]; 
     tag.channelLayout = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_ChannelLayout]]; 
     tag.comments = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Comments]]; 
     tag.composer = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Composer]]; 
     tag.copyright = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Copyright]]; 
     tag.encodingApplication = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_EncodingApplication]]; 
     tag.genre = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Genre]]; 
     tag.isrc = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_ISRC]]; 
     tag.keySignature = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_KeySignature]]; 
     tag.lyricist = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Lyricist]]; 
     tag.recordedDate = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_RecordedDate]]; 
     tag.sourceBitRate = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_SourceBitDepth]]; 
     tag.sourceEncoder = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_SourceEncoder]]; 
     tag.subtitle = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_SubTitle]]; 
     tag.tempo = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Tempo]]; 
     tag.timeSignature = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_TimeSignature]]; 
     tag.title = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Title]]; 
     tag.year = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_Year]]; 

     /* 
     * We're going to parse tracks differently so that we can perform queries on the data. This means we need to look 
     * for a '/' so that we can seperate out the track from the total tracks on the source compilation (if it's there). 
     */ 
     NSString* tracks = [nsDict objectForKey:[NSString stringWithUTF8String: kAFInfoDictionary_TrackNumber]]; 

     int slashLocation = [tracks rangeOfString:@"/"].location; 

     if (slashLocation == NSNotFound) { 
      tag.trackNumber = [NSNumber numberWithInt:[tracks intValue]]; 
     } else { 
      tag.trackNumber = [NSNumber numberWithInt:[[tracks substringToIndex:slashLocation] intValue]]; 
      tag.totalTracks = [NSNumber numberWithInt:[[tracks substringFromIndex:(slashLocation+1 < [tracks length] ? slashLocation+1 : 0)] intValue]]; 
     } 

     // ALWAYS CLEAN UP! 
     CFRelease(piDict); 
     nsDict = nil; 
     free(rawID3Tag); 

     return tag; 
    } 
} 

@end 
+0

đẹp mã! Bạn chỉ cần quên một số dọn dẹp bộ nhớ (quan trọng nhất là 'AudioFileClose'). Tôi chạy mã trên một loạt các tập tin, thông thường các vấn đề bộ nhớ sẽ không là một vấn đề. – newenglander

+0

Tôi có thể nhận được tất cả thông tin của bản nhạc. nhưng không thể có được lời bài hát ... Vì vậy, bất kỳ ý tưởng về lời bài hát ... –

+0

Cảm ơn bạn đã viết mã. – Vignesh

5

Tôi thấy rằng mã đọc thẻ Wayne posts đang được sao chép quá nhiều. Nếu bạn sử dụng kAudioFilePropertyInfoDictionary, bạn không cần id3DataSize, không cần đọc dữ liệu ID3Tag thô và id3TagSizeLength id3TagSize cũng không được sử dụng. Chỉ cần mở tệp và đọc thẻ:

- (NSDictionary *)id3TagsForURL:(NSURL *)resourceUrl 
{ 
    AudioFileID fileID; 
    OSStatus result = AudioFileOpenURL((CFURLRef)resourceUrl, kAudioFileReadPermission, 0, &fileID); 

    if (result != noErr) { 
     NSLog(@"Error reading tags: %li", result); 
     return nil; 
    } 

    CFDictionaryRef piDict = nil; 
    UInt32 piDataSize = sizeof(piDict); 

    result = AudioFileGetProperty(fileID, kAudioFilePropertyInfoDictionary, &piDataSize, &piDict); 
    if (result != noErr) 
     NSLog(@"Error reading tags. AudioFileGetProperty failed"); 

    AudioFileClose(fileID); 

    NSDictionary *tagsDictionary = [NSDictionary dictionaryWithDictionary:(NSDictionary*)piDict]; 
    CFRelease(piDict); 

    return tagsDictionary; 
} 

Khóa nhị phân được định nghĩa trong AudioFile.h, bắt đầu bằng kAFInfoDictionary.

Tuy nhiên, có một chìa khóa thẻ đọc, mà sẽ trả lại kết quả khác nhau (với các phím khác):

- (NSDictionary *)id3TagsForURL:(NSURL *)resourceUrl 
{ 
    AudioFileID fileID; 
    OSStatus result = AudioFileOpenURL((CFURLRef)resourceUrl, kAudioFileReadPermission, 0, &fileID); 

    if (result != noErr) { 
     return nil; 
    } 

    //read raw ID3Tag size 
    UInt32 id3DataSize = 0; 
    char *rawID3Tag = NULL; 
    result = AudioFileGetPropertyInfo(fileID, kAudioFilePropertyID3Tag, &id3DataSize, NULL); 
    if (result != noErr) { 
     AudioFileClose(fileID); 
     return nil; 
    } 

    rawID3Tag = (char *)malloc(id3DataSize); 

    //read raw ID3Tag 
    result = AudioFileGetProperty(fileID, kAudioFilePropertyID3Tag, &id3DataSize, rawID3Tag); 
    if (result != noErr) { 
     free(rawID3Tag); 
     AudioFileClose(fileID); 
     return nil; 
    } 

    CFDictionaryRef piDict = nil; 
    UInt32 piDataSize = sizeof(piDict); 

    //this key returns some other dictionary, which works also in iPod library 
    result = AudioFormatGetProperty(kAudioFormatProperty_ID3TagToDictionary, id3DataSize, rawID3Tag, &piDataSize, &piDict); 
    if (result != noErr) { 
     return nil; 
    } 

    free(rawID3Tag); 
    AudioFileClose(fileID); 

    NSDictionary *tagsDictionary = [NSDictionary dictionaryWithDictionary:(NSDictionary*)piDict]; 
    CFRelease(piDict); 

    return tagsDictionary; 
} 
Các vấn đề liên quan