美文网首页
AV Foundation 的核心资源类 : AVAsset

AV Foundation 的核心资源类 : AVAsset

作者: 玄裳 | 来源:发表于2017-03-21 13:36 被阅读0次

AVAsset


AVAsset 是一个抽象类,定义了媒体资源混合呈现的方式。它本身并不是媒体资源,但可以作为时基媒体(实时地接收并处理数据)的容器。

从用户资源库中的视频创建一个 AVAsset

    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    [library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
        
         //设置相册组的筛选条件,ALAssetsFilter类表示筛选条件,allPhotos代表相册只包含相片,allVideos代表只包含视频,allAssets代表包含所有资源
        [group setAssetsFilter:[ALAssetsFilter allVideos]];
        
        //按遍历顺序获取指定索引的资源,遍历顺序可以是先序或倒序
        /*
         enum {
         NSEnumerationConcurrent = (1UL << 0),
         NSEnumerationReverse = (1UL << 1),
         };
         typedef NSUInteger NSEnumerationOptions;
         */
        [group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:0] options:0 usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
            if (result) {
                //返回一个ALAssetRepresentation
                id  representation = [result defaultRepresentation];
                
                //提供一个创建AVAsset的URL
                NSURL *url= [representation url];
                
                AVAsset *asset = [AVAsset assetWithURL:url];
                // 保存视频
            }
        }];
    } failureBlock:^(NSError *error) {
        
        NSLog(@" error: %@",[error localizedDescription]);
    }];

iOS 9以后使用 PhotoKit 代替 ALAssetsLibrary 来管理相册资源,如何保存视频,如下:

NSURL * url = [NSURL URLWithString:@""];
[[PHPhotoLibrary  sharedPhotoLibrary] performChanges:^{
       
       PHAssetChangeRequest *createAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:url];
       
       PHFetchResult *result=[PHAsset fetchAssetsWithALAssetURLs:[NSArray arrayWithObject:url] options:nil];
       
       PHAssetCollection *assetColection=[[PHAssetCollection fetchAssetCollectionsContainingAsset:[result lastObject] withType:PHAssetCollectionTypeAlbum options:nil] lastObject];
       
       PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetColection];
       
       PHObjectPlaceholder *assetPlaceholder = [createAssetRequest placeholderForCreatedAsset];
       
       [albumChangeRequest addAssets:@[assetPlaceholder]];
 
   } completionHandler:^(BOOL success, NSError * _Nullable error) {
       
       NSLog(@"Finished adding asset. %@", (success ? @"Success" : error));
   }];

在某人的某唱片中查找一首歌,创建一个 AVAsset:


   MPMediaPropertyPredicate *artistPredicate = [MPMediaPropertyPredicate predicateWithValue:@"Leona" forProperty:MPMediaItemPropertyArtist];
   MPMediaPropertyPredicate *ablumPredicate = [MPMediaPropertyPredicate predicateWithValue:@"my favor" forProperty:MPMediaItemPropertyAlbumArtist];
   MPMediaPropertyPredicate *songPredicate = [MPMediaPropertyPredicate predicateWithValue:@"Because of you" forProperty:MPMediaItemPropertyTitle];
   
   MPMediaQuery *query = [[MPMediaQuery alloc] init];
   
   [query addFilterPredicate:ablumPredicate];
   [query addFilterPredicate:artistPredicate];
   [query addFilterPredicate:songPredicate];
   
   NSArray *result = [query items];
   
   if (result.count > 0) {
      
       MPMediaItem *item = result[0];
       NSURL *url = [item valueForProperty:MPMediaItemPropertyAssetURL];
       
       AVAsset *asset = [AVAsset assetWithURL:url];
       //...
       
   }

异步载入


为了防止应用出现卡顿,导致系统监视器介入,并终止应用程序的运行,我们应该使用异步的方式来查询资源的属性。

AVAssetAVAssetTrack 都采用了 AVAsynchronousKeyValueLoading 协议。

通过下面的协议方法实现异步查询属性的功能:

- (AVKeyValueStatus)statusOfValueForKey:(NSString *)key error:(NSError * _Nullable * _Nullable)outError;

- (void)loadValuesAsynchronouslyForKeys:(NSArray<NSString *> *)keys completionHandler:(nullable void (^)(void))handler;


    NSURL * url = [[NSBundle mainBundle] URLForResource:@"sunShine" withExtension:@"mov"];
    
    AVAsset *asset = [AVAsset assetWithURL:url];
    
    NSArray *keys = @[@"tracks"];
       
    //只会调用一次completionHandler块 异步载入tracks 属性
    [asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
       
        NSError *error = nil;
       
        //需要为每个请求的属性调用 statusOfValueForKey:error: 方法 不能假设所有的属性都返回相同的属性值
        AVKeyValueStatus status = [asset statusOfValueForKey:@"tracks" error:&error];
        
        switch (status) {
            case AVKeyValueStatusLoaded:
                //...
                break;
            case AVKeyValueStatusFailed:
                //...
                break;
            case AVKeyValueStatusCancelled:
                //...
                break;
            default:
                break;
        }
    }];


媒体元数据


常用的元数据保存格式有 4 种:

  • QuickTime (mov)定义了.mov文件的内部结构
  • MPEG-4 音频(m4a)
  • 视频 (mp4 和 m4v)
  • MP3 受专利限制, AV Foundation 无法支持对其编码

使用元数据:


    NSURL *url = [NSURL URLWithString:@"文件地址"];
    
    AVAsset *asset = [AVAsset assetWithURL:url];
    
    NSArray *keys = @[@"availableMetadataFormats"];
    
    [asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
        
        NSMutableArray *metaData = [NSMutableArray array];
        
        for (NSString *format in asset.availableMetadataFormats) {
            
            //访问指定格式的元数据需要调用metadataForFormat方法
            [metaData arrayByAddingObjectsFromArray:[asset metadataForFormat:format]];
        }
    }];

查找元数据:

    NSArray *metadata = @[];
    NSString *keySpace = AVMetadataKeySpaceiTunes;
    NSString *artistkey = AVMetadataiTunesMetadataKeyArtist;
    NSString *albumKey = AVMetadataiTunesMetadataKeyAlbum;
  
    //通过metadataItemsFromArray方法来对集合进行筛选,得出那些匹配键和键空间标准的对象,返回一个数组只包含单个AVMetadataItem实例
    NSArray *artistMetaData = [AVMetadataItem metadataItemsFromArray:metadata withKey:artistkey keySpace:keySpace];
    NSArray *albumMetadata  =[AVMetadataItem metadataItemsFromArray:metadata withKey:albumKey keySpace:keySpace];
    
    AVMetadataItem *artistItem, *albumItem;
    
    if (artistMetaData.count > 0) {
        artistItem = artistMetaData[0];
    }
    
    if (albumMetadata.count > 0) {
        albumItem = albumMetadata[0];
    }

使用AVMetadataItem

AVMetadataItem 最基本的形式其实是一个封装键值对的封装器。可通过它查询 keycommonKey, 查询其是否存在于commonKey键空间中,最重要的是它对应的 value

但是 key 属性返回的整数形式无法知道它的含义。

#import "AVMetadataItem+DLKeyString.h"

@implementation AVMetadataItem (DLKeyString)

- (NSString *)keyString
{
    //如果key是字符串直接返回
    if ([self.key isKindOfClass:[NSString class]]) {
        return (NSString *)self.key;
    
    }
    
     //如果key是无符号整型
    else if ([self.key isKindOfClass:[NSNumber class ]]){
        
        uint32_t keyValue = [(NSNumber *) self.key unsignedIntValue];
        
        size_t length = sizeof(uint32_t);
        
        if ((keyValue >> 24) == 0 ) -- length;
        if ((keyValue >> 16) == 0 ) -- length;
        if ((keyValue >> 8) == 0 ) -- length;
        if ((keyValue >> 0) == 0 ) -- length;
      
        long address = (unsigned long) &keyValue;
        address += (sizeof(uint32_t) - length);
        
        keyValue = CFSwapInt32BigToHost(keyValue);
        
        char cstring[length];
        
        strncpy(cstring, (char *)address, length);
        
        cstring[length] = '\0';
                
        if (cstring[0] == '\xA9') {
            cstring[0] = '@';
        }
        //使用stringWithCString 初始化起将字符数组转化成一个字符串
        return [NSString stringWithCString:(char *)cstring encoding:NSUTF8StringEncoding];
    }
    
    else
    {
        return @"<<unknow>>";
    }
    
}

相关文章

网友评论

      本文标题:AV Foundation 的核心资源类 : AVAsset

      本文链接:https://www.haomeiwen.com/subject/rrpapttx.html