Avmetadataitem Getting the trackNumber from an iTu

2019-04-02 18:32发布

问题:

I'm trying to get the trackNumber of a aac, mp3 or mp4 file. It's not in the commonMetadata so I started to spelunk in the other metadata keys. I found something that looks like it, but I'm yet unable to read it, and make sense of it. Even the raw data makes no sense to me.

At the moment, I'm just trying to get it using this basic code:

    NSArray *meta = [asset metadataForFormat:AVMetadataFormatiTunesMetadata];
    for ( AVMetadataItem* item in meta ) {
        id key = [item key];
        NSString *value = [item stringValue];
        NSLog(@"key = %@, value = %@", key, value);
    }

Knowing I'm looking for AVMetadataiTunesMetadataKeyTrackNumber.

回答1:

I realize this thread is quite old but I recently came across this issue myself. I needed ALL the metadata I could gather and came up with the following solution. It's not the most elegant solution but it works well enough. Written in Swift.

func processFile(url:NSURL) {
    let yearKey = -1453039239
    let genreKey = -1452841618
    let encoderKey = -1451987089
    let trackKey = "com.apple.iTunes.iTunes_CDDB_TrackNumber"
    let CDDBKey = "com.apple.iTunes.iTunes_CDDB_1"
    let path:String = url.absoluteString
    let asset = AVURLAsset(URL: url, options: nil)
    let format = AVMetadataFormatiTunesMetadata


    for item:AVMetadataItem in asset.metadataForFormat(format) as Array<AVMetadataItem> {

        if let key = item.commonKey { if key == "title" { println(item.value()) } }
        if let key = item.commonKey { if key == "artist" { println(item.value()) } }
        if let key = item.commonKey { if key == "albumName" { println(item.value()) } }
        if let key = item.commonKey { if key == "creationDate" { println(item.value()) } }
        if let key = item.commonKey { if key == "artwork" { println( "art" ) } }

        if item.key().isKindOfClass(NSNumber) {
            if item.key() as NSNumber == yearKey { println("year: \(item.numberValue)") }
            if item.key() as NSNumber == genreKey { println("genre: \(item.stringValue)") }
            if item.key() as NSNumber == encoderKey { println("encoder: \(item.stringValue)") }
        }

        if item.key().isKindOfClass(NSString) {
            if item.key() as String == trackKey { println("track: \(item.stringValue)") }
            if item.key() as String == CDDBKey { println("CDDB: \(item.stringValue)") }
        }
    }
}


回答2:

If your track has ID3 metadata, you can easily get the numberValue for the track number. If your track has iTunesMetadata, the dataValue is all you get. You have to guess the intValue yourself.

So far, I'm here. I'm pretty sure I need to work more on the bytes portion.

    NSArray *meta = [asset metadataForFormat:AVMetadataFormatiTunesMetadata];
    NSArray *itfilteredKeys = [AVMetadataItem metadataItemsFromArray:meta withKey:AVMetadataiTunesMetadataKeyTrackNumber keySpace:nil];
    for ( AVMetadataItem* item in itfilteredKeys ) {
        NSData *value = [item dataValue];
        unsigned char aBuffer[4];
        [value getBytes:aBuffer length:4];
        unsigned char *n = [value bytes];
        int value1 = aBuffer[3];
        NSLog(@"trackNumber from iTunes = %i", value1);
    }


回答3:

This question is rather old, but I came upon it as I had a similar problem, so for anyone who still needs a solution. I managed to figure out a way of getting the total tracks number and the track number using the following code:

NSString *value = @"<0000000a 00140000>" //[item stringValue] (in this case 10/20)
NSString *track_no_hex = [[value componentsSeparatedByString:@" "][0] stringByReplacingOccurrencesOfString:@"<" withString:@""];
NSString *total_track_no_hex = [[value componentsSeparatedByString:@" "][1] stringByReplacingOccurrencesOfString:@">" withString:@""];

NSString *track_no = @"";
for(int k=0;k<=4;k+=4){
    unsigned result = 0;
    NSScanner *scanner = [NSScanner scannerWithString:[track_no_hex substringWithRange:NSMakeRange(k, 4)]];
    [scanner scanHexInt:&result];
    if(result == 00){

    }
    else{
         track_no = [NSString stringWithFormat:@"%@%u",track_no,result];
    }
}

NSString *total_track_no = @"";
for(int k=0;k<=4;k+=4){
    unsigned result = 0;
    NSScanner *scanner;
    if(k+4<=[total_track_no_hex length]){
        scanner = [NSScanner scannerWithString:[total_track_no_hex substringWithRange:NSMakeRange(k, 4)]];
    }
    else{

    }
    [scanner scanHexInt:&result];
    if(result == 00){

    }
    else{
       total_track_no = [NSString stringWithFormat:@"%@%u",total_track_no,result];
    }
}
NSLog(@"%@/%@",track_no, total_track_no); // Output 10/20

This will work fine for track numbers under 14461 which should be large enough considering iTunes max track number is 999.