项目相关

303 阅读6分钟

封装一个下载组件:

下载组件需要满足的功能: 多任务同时进行下载
支持断点续传
任务支持取消,暂停,继续
支持外界可以通过KVO的方式监听任务的进度,状态(完成,失败,下载中,暂停中,等待中)
核心类是: NSURLSessionDownloadTask
NSURLSessionDownloadTask提供了suspend(暂停), resume(继续)的方法 也可以通过  [task cancelByProducingResumeData:^(NSData *resumeData){ }];进行暂停,同样也是通过resume恢复下载。

@protocol NSURLSessionDownloadDelegate //取消下载,可以被允许继续执行 在未来的某一个时刻

  • (void)cancelByProducingResumeData:(void (^)(NSData * _Nullable resumeData))completionHandler;

//下载完成的回调,这个时候我们可以资源从临时文件夹tmp转移到自定义沙盒路径下

  • (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location;

//下载进度的监听

  • (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;

//请求失败 -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error;

metal和OpenGL的区别:
WWDC2018大会上面 苹果指明了OpenGL将在Mac OS10.14弃用, OpenGL ES将在iOS上弃用,虽然现在API还能访问,但是已经被标记了弃用的API很有可能在未来的某一刻被抹去
OpenGL: 不支持多线程操作, 不支持异步处理, OpenGL 本身设计上存在的问题已经影响了 GPU 真正性能的发挥
Metal 简化了 CPU 参与渲染的步骤,尽可能地让 GPU 去控制资源。与此同时,拥有更现代的设计,使操作处于可控,结果可预测的状态。在优化设计的同时,它仍然是一个直接访问硬件的框架。与 OpenGL 相比,它更加接近于 GPU,以获得更好的性能。
在 MacOS 10.14 的文档中,苹果表示使用 OpenGL 和 OpenCL 构建的应用还可以继续在 macOS 10.14 中运行(但是即使 macOS 支持 OpenGL ,其内置版本依然是 8 年前发布的 OpenGL 3.3 ,而不是去年发布的 4.6)。苹果表示,这些“遗留技术”并不推荐使用。 很明显,苹果此举是想要大力推广 Metal 图形技术,来替换掉“古老”的 OpenGL 接口和 OpenCL 接口。

特效相机里面对渲染模块的重构

matel渲染流程:
顶点着色器:构建顶点信息
图元装配:顶点连起来,变成形状
几何着色器:将三维形态用二维表示
光栅化:就是把图像映射成最终需要点亮屏幕的像素
片段着色器
我们程序员能操作或者定义实现的只有顶点着色器和片元着色器

对于每一次渲染而言,存在不一样的的地方有:
顶点坐标可能不一样, 但是大多数时候我们是用一样的,图片的四个边角
纹理坐标会可能不一样, 但是大多数时候我们是用一样的
渲染的条件可能不一样, 比如有的只需要一个混合因子, 有的需要偏移速度, 距离, 以及范围等 渲染管线可能会不一样: 主要包含着顶点函数和片元函数

基于这样的差异, 我们对目前的项目进行改造, 将公共功能的业务和功能独立出来, 每一种特效独立成一个类,方便外部调用 重构之前:

  • 1.所有渲染代码集合在viewController中, 耦合度 极高
  • 2.代码复用率低,如果需要添加一种效果,需要重复写管道以及顶点和纹理设置等的很多代码
  • 3.如果其他相机项目有相似项目,无法代码共享给他们

重构具体实现:
1.因为顶点函数和片元函数与渲染的结果绑定很紧密,所以我们近把目前支持的.metal文件保留, 特定功能需要自己实现顶点函数和片元函数
2.使用类簇的设计模式,将对外的接口封装在一个父类上面,接受一个mtkView(也就是我们渲染效果需要显示的view),返回一个实例对象

  • 1.初始化方法
  • 2.设置顶点坐标和纹理坐标的方法
  • 3.设置纹理数据的方法
  • 4.设置渲染管道的方法(内部依赖设置顶点函数和片元函数)
  • 5.通过提前订好的协议json文件, 来决定片元函数和顶点函数需要的其他参数(用于生成不同的图像处理算法)
  • 6.创建命令缓冲区, 并将需要的命令添加到缓冲区
  • 7.通过一个block将命令返回给客户端commondBuffer
  • 8.客户端执行commondBuffer就可以执行渲染操作了
  • 9.里面还实现了一些其他方法:比如支持直接将纹理写入本地沙盒路径,纹理转图片等操作 3.每一种渲染操作都会提供一个子类出去,如果需要定制的话,客户端只需要在子类里面重写对应的方法,加入自己的操作就行
    4.如果需要新的渲染特效,只需要重新定义一个子类,重写方法实现

163ef67d91c2084a~tplv-t2oaga2asx-watermark.image.jpeg

实现边下边播功能

AVPlayer的一个类AVAsset,该类主要用于获取多媒体信息,再接着往下了解,AVURLAsset该类是AVAsset的子类,主要可以根据URL路径创建包含媒体信息的AVURLAsset对象,AVURLAsset通过委托AVAssetResourceLoader去加载所需文件,同时可以进行数据的缓存和读取操作,这样就实现边下边播边存的功能。

63c3bc537ae54b0f94a8362268760454~tplv-k3u1fbpfcp-watermark.image.png 1.初始化AVURLAsset对象, 设置AVAssetResourceLoaderDelegate,这个是我们实现边下边播的桥梁

/* 连接视频播放和视频断点下载的桥梁 
* 必须返回Yes,如果返回NO,则resourceLoader将会加载出现故障的数据 
* 这里会出现很多个loadingRequest请求,需要为每一次请求作出处理 
* 该接口会被调用多次,请求不同片段的视频数据,应当保存这些请求,在请求的数据全部响应完毕才销毁该请求 
* @param resourceLoader 资源管理器 
* @param loadingRequest 每一小块数据的请求 
*/ 
- (BOOL)resourceLoader:(AVAssetResourceLoader*)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest*)loadingRequest{ 
// TODO:在这里面开始我们的网络下载请求,也就是得到AVAssetResourceLoadingRequest对象 
}
注意:由于会调用很多次,得到很多个分片信息,所以我选择用一个字典来将这些分片信息存储起来,然后逐一下载使用

/* 当视频播放器要取消请求时,相应的,也应该停止下载这部分数据。 
* 通常在拖拽视频进度时调这方法 
* @param resourceLoader 资源管理器 
* @param loadingRequest 每一小块数据的请求 
*/ 
- (void)resourceLoader:(AVAssetResourceLoader*)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest*)loadingRequest{ 
// TODO:停止下载请求 
}

//网络下载回来的数据是分片的, 要及时传给播放器 
[loadingRequest.dataRequest respondWithData:data];

## 关于seek处理
### 第一种:seek处音频已经下载好
### 第二种:seek到音频未下载部分,我取了最简单的一种方式,取消当前片段的下载请求,执行新的seek出的片段下载