【问题标题】:iOS AVFoundation: How do I fetch artwork from an mp3 file?iOS AVFoundation:如何从 mp3 文件中获取艺术作品?
【发布时间】:2012-12-25 12:43:18
【问题描述】:

我的代码:

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

NSArray *artworks = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyArtwork keySpace:AVMetadataKeySpaceCommon];
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 *artwork = [artworks objectAtIndex:0];
AVMetadataItem *title = [titles objectAtIndex:0];
AVMetadataItem *artist = [artists objectAtIndex:0];
AVMetadataItem *albumName = [albumNames objectAtIndex:0];

if ([artwork.keySpace isEqualToString:AVMetadataKeySpaceID3]) {
    NSDictionary *dictionary = [artwork.value copyWithZone:nil];
    self.currentSongArtwork = [UIImage imageWithData:[dictionary objectForKey:@"data"]];
}
else if ([artwork.keySpace isEqualToString:AVMetadataKeySpaceiTunes]) {
    self.currentSongArtwork = [UIImage imageWithData:[artwork.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;
}

这适用于从 m4a 文件中提取艺术作品,但不适用于 mp3 文件。如果asset 指向一个mp3 文件,则artworks 为空。我做错了什么,我该如何解决?

【问题讨论】:

    标签: objective-c ios avfoundation


    【解决方案1】:

    我发现艺术品是异步加载的,而图像是同步设置的。我是这样解决的:

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

    【讨论】:

    • 在 iOS 模拟器和我的 iPad Mini 上,我在[d objectForKey:@"data"] 上获得了 SIGABRT。但适用于 iPhone 5。有什么想法吗?
    • @StanJames iOS 模拟器没有音乐库。不要在那里测试媒体播放器框架。
    • @duci9y 嗯,但我可以读取其他 ID3 标签,例如标题和艺术家。 (我没有使用 iPhone 的“官方”音乐库,只是包含在我的包中或由用户加载的 mp3 文件。)艺术品标签功能是否使用了一些不同的库?
    • @StanJames 似乎是特定于您的情况的问题。我建议你问一个新问题。如果您在此处发布您的问题的链接,我将不胜感激,以便我也可以跟进。
    • 会的。我会在 iPad 崩溃的情况下,无论如何我都必须在发布之前彻底解决这个问题!
    【解决方案2】:

    我刚刚在这里找到了答案:How can I extract metadata from mp3 file in ios development,现在正在寻找为什么该代码不适用于 m4a 文件。 我从您的代码中提取了一些内容,并提出了以下似乎适用于 m4a 和 mp3 的内容。请注意,我将适用于 mp3 的代码作为没有限定符的开放 else 子句留下 - 如果有人对此有更多经验,欢迎他们改进!

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

    【讨论】:

    • 虽然这样可以防止代码崩溃,但我的代码和这段代码的本质是一样的。我发现了问题并以不同的方式解决了它。检查我的答案以获得解决方案。
    • 太棒了!你的看起来更健壮。如果我了解更多,我会期待更新。谢谢。
    • IOS 8 使用 if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1) { albumArtwork = [UIImage imageWithData:item.dataValue]; } else { NSDictionary *dict ; [item.value copyWithZone:nil]; albumArtwork = [UIImage imageWithData:[dict objectForKey:@"data"]]; }
    • 在这一行崩溃 NSData *data = [(NSDictionary *)[item value] objectForKey:@"data"];
    【解决方案3】:

    正如 Ryan Heitner 在对 Andy Weinstein 的评论中指出的那样,从 AVMetadataKeySpaceID3 检索二进制艺术品数据的方式已从 IOS7 更改为 IOS8。盲目地将item 转换为NSDictionary 现在会在ID3 的情况下崩溃。要使代码防弹,只需检查 dataValue,否则检查 Classes。事实上,今天item.value 指向item.dataValue 并拥有NSData 类。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-13
      • 1970-01-01
      相关资源
      最近更新 更多