一起养成写作习惯!这是我参与「日新计划 4 月更文挑战」的第4天,点击查看活动详情。

AVFoundation 是Apple iOS和OS X体系中用于处理依据时刻的媒体数据的高级结构,经过开发所需的工具供给了强壮的功用集,让开发者可以依据苹果渠道创立当下最先进的媒体应用程序,其针对64位处理器规划,充分使用了多核硬件优势,会主动供给硬件加速操作,保证大部分设备能以最佳功能运转,是iOS开发接触音视频开发必学的结构之一

参与日新计划,继续记录AVFoundation学习,Demo学习地址,这篇文章首要讲述AVAsset资源和元数据,其他类的相关用法可查看我的其他文章。

AVAsset

AVAsset是AVFoundation最重要的类,AVFoundation规划的核心,在一切的特性和功用开发中扮演着至关重要的人物。AVAsset是一个抽象类和不可变类,定义了媒体资源混合出现的方式,将媒体资源的静态特点模块化成一个全体,比如他们的标题、时长、元数据等。

AVAsset不需求考虑媒体资源所具有的封装格局、位置信息等。

  • 它供给了对根本媒体格局层的抽象,不管你处理M4V视频或MP3音频,对你和结构而言,面临的只有资源这个概念,不需求考虑多种编解码器和容器格局不同带来的困扰
  • AVAsset躲藏了位置信息,当经过URL创立一个资源,可所以本地path URL,或许服务器上的视频流URL。

创立资源

  • 可以用本地URL也可以用网络URL创立
  • 实践创立的是AVAsset的子类AVURLAsset
  • AVURLAssetPreferPreciseDurationAndTimingKey可以获得更准确的时长核算,但加载时刻也会长一些
let assetURL = URL(fileURLWithPath: Bundle.main.path(forResource: "01 Demo AAC", ofType: "m4a")!)
// 更准确的时长和计时信息,但加载时刻也会长一些
let options = [AVURLAssetPreferPreciseDurationAndTimingKey: true]
let asset: AVURLAsset = AVURLAsset(url: assetURL, options: options)

使用MediaPlayer结构,查询iPod资源创立AVAsset

// 查询条件
let artistPredicate: MPMediaPropertyPredicate = MPMediaPropertyPredicate(value: "Foo Fighters", forProperty: MPMediaItemPropertyArtist)
let albumPredicate: MPMediaPropertyPredicate = MPMediaPropertyPredicate(value: "In Your Honor", forProperty: MPMediaItemPropertyTitle)
let songPredicate: MPMediaPropertyPredicate = MPMediaPropertyPredicate(value: "Best of You", forProperty: MPMediaItemPropertyTitle)
// 添加查询条件
let query: MPMediaQuery = MPMediaQuery()
query.addFilterPredicate(artistPredicate)
query.addFilterPredicate(albumPredicate)
query.addFilterPredicate(songPredicate)
// 查询结果
let results = query.items
if let tempResults = results, tempResults.count > 0 {
  let item: MPMediaItem = tempResults.first!
  if let assetURL: URL = item.value(forProperty: MPMediaItemPropertyAssetURL) as? URL {
    CQLog(assetURL)
        // 获取ipod内资源url并创立AVAsset
    let asset: AVAsset = AVAsset(url: assetURL)
  }
}

使用Phtots结构,获取用户相册资源创立AVAsset

// 使用Phtots结构获取用户相册的资源
let allPhotoOptions = PHFetchOptions()
// 按日期倒序
//    allPhotoOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
let allPhotos: PHFetchResult = PHAsset.fetchAssets(with: allPhotoOptions)
allPhotos.enumerateObjects { asset, index, stop in
  if asset.mediaType == .video {
    // 视频资源
    let options = PHVideoRequestOptions()
    options.version = .current
    options.deliveryMode = .automatic
    PHImageManager.default().requestAVAsset(forVideo: asset, options: options) { avAsset, audioMix, info in
      if let urlAsset: AVURLAsset = avAsset as? AVURLAsset {
        CQLog(urlAsset.url)
      }
    }
  } else if asset.mediaType == .audio {
    // 音频资源
  } else if asset.mediaType == .image {
    // 图片资源
    let options: PHImageRequestOptions = PHImageRequestOptions()
    options.resizeMode = .exact
    options.isNetworkAccessAllowed = true
    options.isSynchronous = true
    PHImageManager.default().requestImageData(for: asset, options: options) { data, uti, orientation, info in
      if uti == "com.compuserve.fig" {
      }
      if uti == "public.heif" || uti == "public.heic" {
      }
     }
   } else if asset.mediaType == .unknown {
     // 未知资源
      }
}

异步载入Asset的特点

AVAsset有多种方法和特点,可以供给资源的信息,比如时长、创立日期、元数据等。AVAsset在创立时,仅仅对根底媒体文件的处理,延迟载入资源的特点,直到恳求时才载入。这样就可以快速创立资源,而不用考虑因为当即载入相关媒体或元数据所带来的的问题,而特点的拜访总是同步产生的,假如正在恳求的特点没有预先载入,程序就会阻塞,显然这或许带来一定的问题。
AVAsset和AVAsset都遵从AVAsynchronousKeyValueLoading协议,可以经过statusOfValueForKey:error:和loadValuesAsynchronouslyforKeys异步查询特点

/**
 这儿需求注意,即使经过keys传了多个key,但也只会回调一次
回调有或许不在主线程,假如要做UI操作,需求异步回主线程
需求为每个key调用statusOfValue函数,不能假设一切的特点都返回相同的状态值
*/
let keys = ["tracks", "availableMetadataFormats"]
asset.loadValuesAsynchronously(forKeys: keys) {
  var error: NSError? = nil
    let tracksStatus = asset.statusOfValue(forKey: "tracks", error: &error)
  switch tracksStatus {
  case .loaded:
//    CQLog(asset.tracks)
    break
  case .loading: break
  case .cancelled: break
  case .failed: break
  case .unknown: break
  @unknown default: break
  }
}

查询媒体元数据

查询媒体资源的元数据,作者年份等

var metadataItems: [**AVMetadataItem**] = []
for format: AVMetadataFormat in asset.availableMetadataFormats {
  metadataItems.append(contentsOf: asset.metadata(forFormat: format))
}
CQLog("\(metadataItems.last!.key!)"+"--"+"\(metadataItems.last!.keyString())"+"--"+"\(metadataItems.last!.value!)")
// 依据键空间和键挑选AVMetadataItem
let keySpace: AVMetadataKeySpace = AVMetadataKeySpace.audioFile
let artisKey = AVMetadataKey.iTunesMetadataKeyArtist
let albumKey = AVMetadataKey.iTunesMetadataKeyAlbum
let artistMetadata = AVMetadataItem.metadataItems(from: metadataItems, withKey: artisKey, keySpace: keySpace)
let albumMetadata = AVMetadataItem.metadataItems(from: metadataItems, withKey: albumKey, keySpace: keySpace)
let artistItem, albumItem : **AVMetadataItem**?
artistItem = artistMetadata.first
albumItem = albumMetadata.first
if artistItem != nil {CQLog(artistItem!)}
if albumItem != nil {CQLog(albumItem!)}
// 依据标识符挑选AVMetadataItem
let nameKeyId: AVMetadataIdentifier = AVMetadataIdentifier.iTunesMetadataSongName
let nameMetadata = AVMetadataItem.metadataItems(from: metadataItems, filteredByIdentifier: nameKeyId)
let nameItem: AVMetadataItem? = nameMetadata.first
if nameItem != nil {CQLog(nameItem!.keyString())}