注意点
1、获取该PHAsset是否为LivePhoto
应该使用asset.mediaSubtypes.contains(.photoLive),而不是使用 asset.mediaSubtypes == .photoLive,因为枚举值是位运算
列表如何区分是否是live photo
PHAsset-mediaSubtypes → 2^3 = 8
系统角标
live photo 如何播放
接口
导出mov
/// 获取livePhoto 资源 视频路径
/// - Parameters:
/// - asset: PHAsset
/// - result: 结果回调
func getLivePhotoMovFilePath(_ asset: PHAsset, result: @escaping (String?, PHAsset) -> Void) {
let assetResources = PHAssetResource.assetResources(for: asset)
let resource = assetResources.last(where: {$0.type == .pairedVideo || $0.type == .video})
var fileName = "\(asset.localIdentifier).mov"
if let name = resource?.originalFilename {
fileName = name
}
if asset.mediaSubtypes.contains(.photoLive) {
let options = PHVideoRequestOptions()
options.version = .current
options.deliveryMode = .highQualityFormat
// 创建文件夹路径
let creater: (URL) -> Void = { dir in
if !FileManager.default.fileExists(atPath: dir.path) {
do {
try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
} catch {
Log.error(error.localizedDescription)
}
}
}
creater(livePhotoDirectory)
let filePah = livePhotoDirectory.path.appendingPathComponent(fileName)
// 是否已有此文件
if FileManager.default.fileExists(atPath: filePah) {
Log.info("导出LivePhoto内部Mov - 成功 - 此资源本地已导出")
result(filePah, asset)
return
}
guard let resource = resource else {
result(nil, asset)
Log.info("导出LivePhoto内部Mov - 失败 - error - resource为空")
return
}
PHAssetResourceManager.default().writeData(for: resource, toFile: URL.init(fileURLWithPath: filePah), options: nil) { error in
DispatchQueue.main.async {
if error != nil {
result(nil, asset)
Log.info("导出LivePhoto内部Mov - 失败 - error - \(error?.localizedDescription ?? "")")
} else {
result(filePah, asset)
Log.info("导出LivePhoto内部Mov - 成功 - filePaht - \(filePah)")
}
}
}
} else {
result(nil, asset)
Log.info("导出LivePhoto内部Mov - 失败 - error - 非LivePhoto")
}
}