@Manajay:我的 github 博客
photoKit框架 丢弃 AssetLibrary
1. 业务需求
最近在做 视频的分片上传, 使用的框架是 苹果的photoKit
.
2. 疑难
但是开发中发现 ,使用photoKit
不能够获取视频的路径(有个URL路径,但是不能使用FileManager
获取,私有的,只能官方的图片库可以使用),
3. 检索资料
查过一些资料 都是将视频 再重新写入沙盒,然后再用
FileManager
去 根据路径重新取数据,之后将文件分片
问题是,iPhone
的视频体积都很大, 中间压缩 再转存到 沙盒 要耗费很长时间, 做不到立马上传的 效果, 而且 转存失败 后续操作就失败了, 在界面上又要不给 用户等待的错觉
疑惑: 查看过 百度云, 它的上传是 选中视频后 直接就会上传, 而且 没有等待 ,重启应用后 继续上传, 不知道它是如何实现的!(我只是觉得它应该不会使用AssetLibrary
)
而且通过设置的 储存控件观察, 百度云的沙盒空间在上次时只增加了 几M的空间.
4. 解决方案
4.1. 方案一: 使用AssetLibrary 的API
获取 ALAsset
对象 直接截取视频的一个小片段, 不需要写入沙盒.
代码:
// asset 为 ALAsset 对象
let rept = asset.defaultRepresentation()
let imageBuffer = UnsafeMutablePointer.alloc(Int(rept.size()))
let bufferSize = rept.getBytes(imageBuffer, fromOffset: Int64(0),length: Int(rept.size()), error: nil)
let data = NSData(bytesNoCopy:imageBuffer ,length:bufferSize, freeWhenDone:true)
但是 自己的 图片选择库都是基于的photoKit
的框架,获取的资源对象都是PHAsset
,不能与AssetLibrary
互通.
而且既然官方推出了新的照片管理库,性能肯定有很大的提升.
所以方案一放弃.
4.2 方案二: 使用AVFoundation的API
PHAsset
异步获取的视频虽然类型是AVAsset
,但是因为它是抽象类,真正获取的视频一般是其子类AVURLAsset
如果需求是要在上传之前裁剪视频(利用CMTime
), 或者进行其他的视频混合等处理,一般要使用AVFoundation
的类(AVAssetTrack
)去获取音轨与视频,然后混合两者,异步导出AVAssetExportSession
.
我的需求可以通过调整 CMTime
帧数与帧率 ,控制只写入很小帧数的视频.然后上传存储的这部分,上传成功后删除它,循环一点一点的边存边上传边删除.但是感觉太麻烦.
另一种方式是:
利用AVURLAsset
的属性url
,直接通过映射的方式获取二进制,这样不会将视频的全部数据加载到内存,而是会只加载数据的一部分.
具体是:
NSData.ReadingOptions
这个属性,可以通过mappedIfSafe
的方式获取二进制.但是官方文档中说,弱网下使用上传的话,会影响性能.
init(contentsOf url: URL, options readOptionsMask: NSData.ReadingOptions = []) throws
此方法经过测试完全可以.
5. 最后的方案就是 方案二的二进制映射方法
相册中的30min视频测试:
> 1. po Data(contentsOf: avAsset.url)
错误信息:
▿ file:///var/mobile/Media/DCIM/103APPLE/IMG_3449.MOV
malloc: mach_vm_map(size=3497361408) failed (error code=3)
error: can't allocate region
set a breakpoint in malloc_error_break to debug
> 2. po Data(contentsOf: avAsset.url, options: .mappedIfSafe)
Error Domain=NSCocoaErrorDomain Code=256 "未能打开文件“IMG_3449.MOV”。" UserInfo={NSFilePath=/var/mobile/Media/DCIM/103APPLE/IMG_3449.MOV, NSUnderlyingError=0x1706492a0
{Error Domain=NSPOSIXErrorDomain Code=12 "Cannot allocate memory"}}
> 3. po Data(contentsOf: avAsset.url, options: .alwaysMapped)
Error Domain=NSCocoaErrorDomain Code=256 "未能打开文件“IMG_3449.MOV”。" UserInfo={NSFilePath=/var/mobile/Media/DCIM/103APPLE/IMG_3449.MOV, NSUnderlyingError=0x17424ee80 {Error Domain=NSPOSIXErrorDomain Code=12 "Cannot allocate memory"}}
> 4. po Data(contentsOf: avAsset.url, options: .uncached)
malloc: mach_vm_map(size=3497361408) failed (error code=3)
error: can't allocate region
set a breakpoint in malloc_error_break to debug
Error Domain=NSCocoaErrorDomain Code=256 "未能打开文件“IMG_3449.MOV”。" UserInfo={NSFilePath=/var/mobile/Media/DCIM/103APPLE/IMG_3449.MOV, NSUnderlyingError=0x170841e00
{Error Domain=NSPOSIXErrorDomain Code=12 "Cannot allocate memory"}}
> 5. po Data(contentsOf: avAsset.url, options: .dataReadingMapped)
Error Domain=NSCocoaErrorDomain Code=256 "未能打开文件“IMG_3449.MOV”。" UserInfo={NSFilePath=/var/mobile/Media/DCIM/103APPLE/IMG_3449.MOV, NSUnderlyingError=0x1708501d0
{Error Domain=NSPOSIXErrorDomain Code=12 "Cannot allocate memory"}}
所有的错误信息都表示该视频太大,无法或者完整的二进制视频.
6.相关文章链接
- 基于PhotoKit相册选择器
- iOS 获取系统相册内视频与图片
- Photos 框架实践以及坑