2011-11-23 5 views
7

AVAudioPlayer를 사용하여 사용자 지정 플레이어를 만들었습니다. 이제 리소스 폴더에 추가 된 아티스트 이름, 앨범 이름 등과 같은 오디오 파일의 세부 정보를 가져 오려고합니다.iPhone에서 오디오 파일의 세부 정보를 가져 오는 방법

MPMusicPlayer는 세부 사항을 가져 오기위한 API를 제공하지만 iPod 라이브러리를 사용하며 응용 프로그램의 샌드 박스에서 리소스를 가져 오지 않습니다. 따라서 MPMusicPlayer는 그 시나리오에서 작동하지 않습니다.

그래서 iPhone에서 오디오 파일의 세부 정보를 가져올 수 있습니다.

답변

14

당신은 AudioToolbox.framework 통해이 정보를 얻을 수 있습니다. AudioToolbox.framework는 C API입니다, 그래서 그것을 위해 목표 - C 래퍼를 썼다 :

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

니스 코드 :

그러나, (다른 키와) 다른 결과를 반환합니다 다른 태그 읽기 키가있다! 방금 메모리 정리를 잊었습니다 (가장 중요한 것은'AudioFileClose'입니다). 내가 파일의 무리에 코드를 실행, 일반적으로 메모리 문제는 문제가되지 않을 것입니다. – newenglander

+0

트랙의 모든 정보를 얻을 수 있습니다. 하지만 가사를 얻을 수 없습니다 ... 그럼 가사에 대한 어떤 생각이 ... –

+0

코드를 가져 주셔서 감사합니다. – Vignesh

5

태그 읽기 코드 Wayne posts이 너무 많이 복사되는 것을 볼 수 있습니다. kAudioFilePropertyInfoDictionary을 사용하는 경우 id3DataSize가 필요없고 원시 ID3Tag 데이터를 읽을 필요가 없으며 id3TagSizeLength id3TagSize도 사용되지 않습니다. 그냥 파일을 열고 태그를 읽어

- (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; 
} 

Dicionary 키가 kAFInfoDictionary부터 시작 AudioFile.h에 정의되어 있습니다.

- (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; 
}