2011-11-23 14 views
7

Hice el reproductor personalizado usando AVAudioPlayer. Ahora, quiero buscar los detalles del archivo de audio, como el nombre del artista, el nombre del álbum, etc. que se agrega en la carpeta de recursos.cómo recuperar los detalles del archivo de audio en iPhone

MPMusicPlayer proporciona la API para buscar los detalles pero está utilizando la biblioteca del iPod y no está tomando el recurso de la zona de pruebas de la aplicación. Entonces, MPMusicPlayer no va a funcionar en ese escenario.

Entonces, ¿cómo podemos obtener los detalles del archivo de audio en iPhone.

Respuesta

14

Puede obtener esta información a través del AudioToolbox.framework. El AudioToolbox.framework es una API de C, así que escribió una envoltura de Objective-C para ello:

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

código Nice! Simplemente olvidaste algo de limpieza de memoria (lo más importante es 'AudioFileClose'). Ejecuté el código en un montón de archivos, normalmente los problemas de memoria no serían un problema. – newenglander

+0

Puedo obtener toda la información de la pista. pero no pude obtener la letra ... Así que cualquier idea sobre la letra ... –

+0

Gracias por el código. – Vignesh

5

Veo que el código de lectura de etiquetas Wayne posts está siendo copiado demasiado. Si usa kAudioFilePropertyInfoDictionary, no necesita id3DataSize, no es necesario leer los datos sin procesar ID3Tag y id3TagSizeLength id3TagSize no se utilizan también. Sólo tiene que abrir el archivo y leer la etiqueta:

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

teclas Dicionary se definen en AudioFile.h, empezando por kAFInfoDictionary.

Sin embargo, hay otra clave de lectura de la etiqueta, que devolverá resultados diferentes (con otras teclas):

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