AVF 5 - 资源和元数据信息

AVF 5 - 资源和元数据


一、简要说明

相关类

  • AVAsset
    • AVURLAsset
    • AVFragmentedAsset
  • AVMetadataItem 具体资源元数据
  • AVAssetTrack 曲目等一级元数据
  • AVAssetTrackGroup

二、使用

1、获取 AVAsset 信息


@implementation AssetManager


- (void)setup{
    
    NSString *fileName = @"Drums.m4a";
    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:fileName
                                             withExtension:nil];
    
    AVURLAsset *asset = [AVURLAsset assetWithURL:fileURL];
    [self getInfoOfAsset:asset];  //
    
}

- (void)getInfoOfAsset:(AVAsset *)asset{
    
    
    CMTime dur = asset.duration;  //
    CMTime minimumTimeOffsetFromLive = asset.minimumTimeOffsetFromLive;
    NSLog(@"dur : %lld, %d",dur.value, dur.timescale);  // dur : 314368, 44100
    
    NSLog(@"preferredRate : %f ",asset.preferredRate );  //  1.000000
    NSLog(@"preferredVolume : %f ",asset.preferredVolume );  // 1.000000
    NSLog(@"naturalSize : %@ ",NSStringFromSize(asset.naturalSize) );  //  {0, 0}
    
    //    NSLog(@"preferredDisplayCriteria : %@ ",asset.preferredDisplayCriteria );  //
    NSLog(@"providesPreciseDurationAndTiming : %d ",asset.providesPreciseDurationAndTiming );  //
    NSLog(@"referenceRestrictions : %lu ",(unsigned long)asset.referenceRestrictions );  // 0
    
    AVMetadataItem *creationDate = asset.creationDate;  //
    [self getInfoOfMetadataItem:creationDate];  //
    
    NSLog(@"creationDate : %@ ",asset.creationDate );
    /*
     AVMetadataItem: 0x600000024050, identifier=common/creationDate, keySpace=comn, key class = __NSCFConstantString, key=creationDate, commonKey=creationDate, extendedLanguageTag=(null), dataType=(null), time={INVALID}, duration={INVALID}, startDate=(null), extras={ }, value class=__NSTaggedDate, value=2015-05-28 22:50:49 +0000>
     */
    
    NSLog(@"preferredVolume : %f ",asset.preferredVolume );  // 1.000000
    
    
    NSArray *tracks = asset.tracks;
    NSLog(@"tracks : %@ ",asset.tracks );
    /*
     tracks : (
     "<AVAssetTrack: 0x6000000242a0, trackID = 1, mediaType = soun>"
     )
     */
    
    for (AVAssetTrack *track in tracks) {
        [self getInfoOfAssetTrack:track];  //
    }
    
    
    NSArray *trackGroups = asset.trackGroups;  //
    for (AVAssetTrackGroup *trackGroup in trackGroups) {
        [self getInfoOfAssetTrackGroup:trackGroup];  //
    }
    
    
    NSLog(@"lyrics : %@ ",asset.lyrics );  // (null)
    
    NSArray<AVMetadataItem *> *commonMetadata = asset.commonMetadata;  //
    for (AVMetadataItem *item in commonMetadata) {
        [self getInfoOfMetadataItem:item];  //
    }
    
    NSArray<AVMetadataItem *> *metadata = asset.metadata;  //
    for (AVMetadataItem *item in metadata) {
        [self getInfoOfMetadataItem:item];  //
    }
    
    NSArray<AVMetadataFormat> *availableMetadataFormats = asset.availableMetadataFormats;  //
    for (AVMetadataFormat format in availableMetadataFormats) {
        //        [self getInfoOfMetadataFormat:format];  //
        NSLog(@"MetadataFormat : %@",format);  // com.apple.itunes, org.mp4ra
    }
    
    
    
}

- (void)getInfoOfAssetTrack:(AVAssetTrack *)assetTrack{
    
    NSLog(@"\n---------------assetTrack");  //
    
    NSLog(@"trackID : %d ",assetTrack.trackID);  // 1
    NSLog(@"mediaType : %@ ",assetTrack.mediaType);  // soun
    NSLog(@"formatDescriptions : %@ ",assetTrack.formatDescriptions);
    /*
     (
     "<CMAudioFormatDescription 0x600003305a40 [0x7fff915fb690]> {\n\tmediaType:'soun' \n\tmediaSubType:'aac ' \n\tmediaSpecific: {\n\t\tASBD: {\n\t\t\tmSampleRate: 44100.000000 \n\t\t\tmFormatID: 'aac ' \n\t\t\tmFormatFlags: 0x0 \n\t\t\tmBytesPerPacket: 0 \n\t\t\tmFramesPerPacket: 1024 \n\t\t\tmBytesPerFrame: 0 \n\t\t\tmChannelsPerFrame: 2 \n\t\t\tmBitsPerChannel: 0 \t} \n\t\tcookie: {<CFData 0x6000029057a0 [0x7fff915fb690]>{length = 39, capacity = 39, bytes = 0x03808080220000000480808014401500 ... 1210068080800102}} \n\t\tACL: {Stereo (L R)}\n\t\tFormatList Array: {\n\t\t\tIndex: 0 \n\t\t\tChannelLayoutTag: 0x650002 \n\t\t\tASBD: {\n\t\t\tmSampleRate: 44100.000000 \n\t\t\tmFormatID: 'aac ' \n\t\t\tmFormatFlags: 0x0 \n\t\t\tmBytesPerPacket: 0 \n\t\t\tmFramesPerPacket: 1024 \n\t\t\tmBytesPerFrame: 0 \n\t\t\tmChannelsPerFrame: 2 \n\t\t\tmBitsPerChannel: 0 \t}} \n\t} \n\textensions: {{\n    VerbatimISOSampleEntry = {length = 87, bytes = 0x00000057 6d703461 00000000 00000001 ... 12100680 80800102 };\n}}\n}"
     )
     */
    NSLog(@"playable : %d ",assetTrack.playable);  // 1
    NSLog(@"decodable : %d ",assetTrack.decodable);  // 1
    NSLog(@"enabled : %d ",assetTrack.enabled);  // 1
    NSLog(@"selfContained : %d ",assetTrack.selfContained);  // 1
    NSLog(@"totalSampleDataLength : %lld ",assetTrack.totalSampleDataLength);  // 170679
    NSLog(@"decodable : %d ",assetTrack.decodable);  // 1
    
    
    NSLog(@"timeRange : %d",assetTrack.timeRange);  // 1
    NSLog(@"naturalTimeScale : %d",assetTrack.naturalTimeScale);  // 44100
    NSLog(@"estimatedDataRate : %f",assetTrack.estimatedDataRate);  // 191544.781250
    
    NSLog(@"languageCode : %@",assetTrack.languageCode);  // und
    NSLog(@"extendedLanguageTag : %@",assetTrack.extendedLanguageTag);  // (null)
    
    NSLog(@"naturalSize : %@",NSStringFromSize(assetTrack.naturalSize));  // {0, 0}
    
    NSLog(@"preferredVolume : %f",assetTrack.preferredVolume);  // 1.000000
    
    NSLog(@"hasAudioSampleDependencies : %d",assetTrack.hasAudioSampleDependencies);  // 0
    
    NSLog(@"nominalFrameRate : %f",assetTrack.nominalFrameRate);  // 43.066406
    
    
    NSLog(@"requiresFrameReordering : %d",assetTrack.requiresFrameReordering);  // 0
    
    NSArray<AVAssetTrackSegment *> *segments = assetTrack.segments;  // 1
    for (AVAssetTrackSegment *segment in segments) {
        //          [self getInfoOfMetadataFormat:format];  //
    }
    
    
    //    NSArray<AVMetadataItem *> *commonMetadata = asset.commonMetadata;  //
    //    for (AVMetadataItem *item in commonMetadata) {
    //        [self getInfoOfMetadataItem:item];  //
    //    }
    //
    //    NSArray<AVMetadataItem *> *metadata = asset.metadata;  //
    //    for (AVMetadataItem *item in metadata) {
    //        [self getInfoOfMetadataItem:item];  //
    //    }
    //
    //    NSArray<AVMetadataFormat> *availableMetadataFormats = asset.availableMetadataFormats;  //
    //    for (AVMetadataFormat format in availableMetadataFormats) {
    //        [self getInfoOfMetadataFormat:format];  //
    //    }
    
    NSLog(@"canProvideSampleCursors : %d",assetTrack.canProvideSampleCursors);  // 1
    
    
}


- (void)getInfoOfAssetTrackGroup:(AVAssetTrackGroup *)assetTrackGroup{
    
    NSLog(@"assetTrackGroup.trackIDs : %@",assetTrackGroup.trackIDs);  //
}

- (void)getInfoOfMetadataItem:(AVMetadataItem *)item{
    
    NSLog(@"\n---------------AVMetadataItem");  //
    
    NSLog(@"identifier : %@ ",item.identifier);  // itlk/com.apple.iTunes.iTunSMPB
    NSLog(@"extendedLanguageTag : %@ ",item.extendedLanguageTag);  // (null)
    NSLog(@"locale : %@ ",item.locale);  //
    NSLog(@"dataType : %@ ",item.dataType);  // com.apple.metadata.datatype.UTF-8
    NSLog(@"extraAttributes : %@ ",item.extraAttributes);
    /*
     {
     dataType = 1;
     dataTypeNamespace = "com.apple.itunes";
     }
     */
    NSLog(@"startDate : %@ ",item.startDate);  //
    NSLog(@"stringValue : %@ ",item.stringValue);  // 00000000 00000CC6 00000193 000000000004BDA7 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
    NSLog(@"numberValue : %@ ",item.numberValue);  //
    NSLog(@"dateValue : %@ ",item.dateValue);  // Fri May 29 06:50:49 2015
    NSLog(@"key : %@ ",item.key);  // com.apple.iTunes.iTunSMPB
    NSLog(@"commonKey : %@ ",item.commonKey);
    NSLog(@"keySpace : %@ ",item.keySpace);  // itlk
    NSLog(@"dateValue : %@ ",item.dateValue);
    
}


2、使用 AVMetadataItem

- (void)getMetadata{
    
    NSString *fileName = @"Drums.m4a";
    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:fileName
                                             withExtension:nil];
    
    
    AVURLAsset *asset = [AVURLAsset assetWithURL:fileURL];
    
    NSArray *formats = [asset availableMetadataFormats];
    NSLog(@"formats : %@",formats);
    /*
     formats : (
         "com.apple.itunes",
         "org.mp4ra"
     )
     */
    
    for (AVMetadataFormat item in formats) {
        
        NSArray *medata = [asset metadataForFormat:item];
        
        for (AVMetadataItem *mitem in medata) {
            NSLog(@"%@ : %@",mitem.key,mitem.value);
            // com.apple.iTunes.iTunSMPB :  00000000 00000CC6 00000193 000000000004BDA7 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
        }
    }
}

3、AVAsynchronousKeyValueLoading 懒惰加载

由于多媒体文件一般比较大,获取或计算出Asset中的属性非常耗时,apple 对Asset的属性采用了懒惰加载模式。

在创建 AVAsset 的时候,只生成一个实例,并不初始化属性。

只有当第一次访问属性时,系统才会根据多媒体中的数据初始化这个属性。

由于不用同时加载所有属性,耗时问题得到了一定缓解。

但是属性加载在计算量比较大的时候仍旧可能会阻塞线程。为了解决这个问题,AVFoundation提供了 AVAsynchronousKeyValueLoading 协议,可以异步加载属性:

-loadValuesAsynchronouslyForKeys:completionHandler: 方法用来异步加载属性,通过keys传入要加载的key数组,在handler中做加载完成的操作。
-statusOfValueForKey:error: 方法可以获得属性的加载状态,如果是AVKeyValueStatusLoaded状态,表示已经加载完成。

- (void)cancelLoading; 取消加载


使用示例

AVKeyValueStatus commonStatus =
    [self.asset statusOfValueForKey:@"commonMetadata" error:nil];

AVKeyValueStatus formatsStatus =
    [self.asset statusOfValueForKey:@"availableMetadataFormats" error:nil];

/* ------ */

NSArray *keys = @[@"commonMetadata", @"availableMetadataFormats"];

[self.asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{

    AVKeyValueStatus commonStatus =
        [self.asset statusOfValueForKey:COMMON_META_KEY error:nil];

    AVKeyValueStatus formatsStatus =
        [self.asset statusOfValueForKey:AVAILABLE_META_KEY error:nil];

    self.prepared = (commonStatus == AVKeyValueStatusLoaded) &&         // 3
                    (formatsStatus == AVKeyValueStatusLoaded);

    if (self.prepared) {
        for (AVMetadataItem *item in self.asset.commonMetadata) {       // 4
            //NSLog(@"%@: %@", item.keyString, item.value);
            [self.metadata addMetadataItem:item withKey:item.commonKey];
        }

        for (id format in self.asset.availableMetadataFormats) {        // 5
            if ([self.acceptedFormats containsObject:format]) {
                NSArray *items = [self.asset metadataForFormat:format];
                for (AVMetadataItem *item in items) {
                    //NSLog(@"%@: %@", item.keyString, item.value);
                    [self.metadata addMetadataItem:item
                                           withKey:item.keyString];
                }
            }
        }
    }

    dispatch_async(dispatch_get_main_queue(), ^{
        completionHandler(self.prepared);
    });


4、数据转换

- (id)displayValueFromMetadataItem:(AVMetadataItem *)item {

    NSNumber *number = nil;
    NSNumber *count = nil;
    
    if ([item.value isKindOfClass:[NSString class]]) {                      // 1
        NSArray *components =
            [item.stringValue componentsSeparatedByString:@"/"];
        number = @([components[0] integerValue]);
        count = @([components[1] integerValue]);
    }
    else if ([item.value isKindOfClass:[NSData class]]) {                   // 2
        NSData *data = item.dataValue;
        if (data.length == 6) {
            uint16_t *values = (uint16_t *)[data bytes];
            if (values[1] > 0) {
                number = @(CFSwapInt16BigToHost(values[1]));                // 3
            }
            if (values[2] > 0) {
                count = @(CFSwapInt16BigToHost(values[2]));                 // 4
            }
        }
    }
    
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];           // 5
    [dict setObject:number ?: [NSNull null] forKey:THMetadataKeyDiscNumber];
    [dict setObject:count ?: [NSNull null] forKey:THMetadataKeyDiscCount];
    
    return dict;
}

5、保存元数据 AVAssetExportSession

- (void)save{
    
    NSString *fileName = @"Drums.m4a";
    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:fileName
                                             withExtension:nil];
    AVURLAsset *asset = [AVURLAsset assetWithURL:fileURL];
    
    // AVAssetExportPresetPassthrough
    NSString *presetName =  AVAssetExportPresetAppleM4A;   // 注意此处格式,如果不对应也会转换失败
    AVAssetExportSession *session =
    [[AVAssetExportSession alloc] initWithAsset:asset
                                     presetName:presetName];
    
    NSURL *outputURL = [NSURL fileURLWithPath:@"/Users/user/Desktop/001.m4a"];
    session.outputURL = outputURL;
    session.outputFileType = [self fileTypeForURL:fileURL];
    //    session.metadata = [self.metadata metadataItems];      
    
    
    [session exportAsynchronouslyWithCompletionHandler:^{
        
        AVAssetExportSessionStatus status = session.status;
        BOOL success = (status == AVAssetExportSessionStatusCompleted);
        if (success) {
            
            [[NSWorkspace sharedWorkspace] selectFile:outputURL.path inFileViewerRootedAtPath:nil];                                     
        }
        
        NSLog(@"export : %d",success);
        
    }];
}
发布了43 篇原创文章 · 获赞 8 · 访问量 4561

猜你喜欢

转载自blog.csdn.net/weixin_45390999/article/details/104565259