PhotoKit 的 大文件 视频上传疑难

@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 框架实践以及坑

7.期待更优的解答

你可能感兴趣的:(PhotoKit 的 大文件 视频上传疑难)