iOS AVFoundation: How do I fetch artwork from an mp3 file?

前端 未结 3 1204
粉色の甜心
粉色の甜心 2020-11-29 06:41

My code:

- (void)metadata {
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:self.fileURL options:nil];

NSArray *artworks = [AVMetadataItem metadataItemsFrom         


        
相关标签:
3条回答
  • 2020-11-29 07:23

    I just found the answer to that here: How can I extract metadata from mp3 file in ios development and was now looking to see why that code doesn't work on an m4a file. I took a little bit from your code and present the following which seems to work for both m4a and mp3. Note that I left the code which works for mp3 as an open else clause without the qualifier - if anybody gains more experience with this they are welcome to refine!

     - (void)getMetaDataForSong:(MusicItem *)musicItem {
       AVAsset *assest;
    
       // filePath looks something like this: /var/mobile/Applications/741647B1-1341-4203-8CFA-9D0C555D670A/Library/Caches/All Summer Long.m4a
    
        NSURL *fileURL = [NSURL fileURLWithPath:musicItem.filePath];
        NSLog(@"%@", fileURL);
        assest = [AVURLAsset URLAssetWithURL:fileURL    options:nil];
        NSLog(@"%@", assest);
    
        for (NSString *format in [assest availableMetadataFormats]) {
          for (AVMetadataItem *item in [assest metadataForFormat:format]) {
            if ([[item commonKey] isEqualToString:@"title"]) {
                musicItem.strSongTitle = (NSString *)[item value];
            } 
            if ([[item commonKey] isEqualToString:@"artist"]) {
                musicItem.strArtistName = (NSString *)[item value];
            }
            if ([[item commonKey] isEqualToString:@"albumName"]) {
              musicItem.strAlbumName = (NSString *)[item value];
            }
            if ([[item commonKey] isEqualToString:@"artwork"]) {
              UIImage *img = nil;
              if ([item.keySpace isEqualToString:AVMetadataKeySpaceiTunes]) {
                img = [UIImage imageWithData:[item.value copyWithZone:nil]];
              }
              else { // if ([item.keySpace isEqualToString:AVMetadataKeySpaceID3]) {
                NSData *data = [(NSDictionary *)[item value] objectForKey:@"data"];
                img = [UIImage imageWithData:data]  ;
              }
              musicItem.imgArtwork = img;
            }
         }
      }
    }
    
    0 讨论(0)
  • 2020-11-29 07:31

    As Ryan Heitner pointed out in a comment to Andy Weinstein, the way to retrieve the binary artwork data from the AVMetadataKeySpaceID3 has changed somewhere from IOS7 to IOS8. Casting blindly item to NSDictionary will crash in the ID3 case nowadays. To make code bullet proof just check dataValue, otherwise the Classes. In fact today item.value points to item.dataValue and has the NSData class.

    - (UIImage*)imageFromItem:(AVMetadataItem*)item
    {
      NSData* data=nil;
      if (item.dataValue!=nil) {
        data=item.dataValue;
      } else if ([item.value isKindOfClass:NSData.class]) { //never arrive here nowadays
        data=(NSData*)item.value;
      } else if ([item.value isKindOfClass:NSDictionary.class]) { //never arrive here nowadays...
        NSDictionary* dict=(NSDictionary*)item.value;
        data=dict[@"data"];
      }
      if (data==nil) {
        return nil;
      }
      return [UIImage imageWithData:data];
    }
    
    0 讨论(0)
  • 2020-11-29 07:39

    I found that the artworks were being loaded asynchronously while the image was being set synchronously. I solved it this way:

    - (void)metadata {
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:self.fileURL options:nil];
    
    NSArray *titles = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyTitle keySpace:AVMetadataKeySpaceCommon];
    NSArray *artists = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyArtist keySpace:AVMetadataKeySpaceCommon];
    NSArray *albumNames = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyAlbumName keySpace:AVMetadataKeySpaceCommon];
    
    AVMetadataItem *title = [titles objectAtIndex:0];
    AVMetadataItem *artist = [artists objectAtIndex:0];
    AVMetadataItem *albumName = [albumNames objectAtIndex:0];
    
    
    NSArray *keys = [NSArray arrayWithObjects:@"commonMetadata", nil];
    [asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
        NSArray *artworks = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata
                                                           withKey:AVMetadataCommonKeyArtwork
                                                          keySpace:AVMetadataKeySpaceCommon];
    
        for (AVMetadataItem *item in artworks) {
            if ([item.keySpace isEqualToString:AVMetadataKeySpaceID3]) {
                NSDictionary *d = [item.value copyWithZone:nil];
                self.currentSongArtwork = [UIImage imageWithData:[d objectForKey:@"data"]];
            } else if ([item.keySpace isEqualToString:AVMetadataKeySpaceiTunes]) {
                self.currentSongArtwork = [UIImage imageWithData:[item.value copyWithZone:nil]];
            }
        }
    }];
    
    
    self.currentSongTitle = [title.value copyWithZone:nil];
    self.currentSongArtist = [artist.value copyWithZone:nil];
    self.currentSongAlbumName = [albumName.value copyWithZone:nil];
    self.currentSongDuration = self.audioPlayer.duration;
    }
    
    0 讨论(0)
提交回复
热议问题