这次来使用Metal渲染视频数据,渲染视频实际上就是不断地把视频数据变成MTLTexture,再使用renderEncoder去渲染显示,本文会利用iOS设备采集RGBA、NV12数据,然后进行渲染显示。
渲染BGRA数据
创建一个layer类型为CAMetalLayer的view
1 |
|
设置layer的属性
1 |
|
这里主要是获取了默认的设备(GPU)然后赋值给layer的device属性,然后设置一些渲染格式和尺寸的属性。
准备管道状态
1 |
|
1 |
|
这里创建了管道状态,设置了两个着色器函数,和上一篇笔记渲染图片纹理的函数一致。
创建命令队列
1 |
|
这里创建一个命令队列,用于渲染时取得可用的command给GPU渲染命令。
渲染方法
1 |
|
这里根据传入的宽高判断是否需要新创建纹理描述,然后根据纹理描述创建纹理,将数据写入。然后创建MTLRenderPassDescriptor,MTLRenderPassDescriptor描述一系列attachments的值,类似GL的FrameBuffer,同时也用来创建MTLRenderCommandEncoder。 然后创建顶点和纹理坐标buffer,然后设置给renderEncoder,然后渲染显示。
将数据传入renderView
1 |
|
运行后即可看到渲染的视频。
遇到的问题
一开始我在采集之后才将renderView添加到view上,导致崩溃在
1 |
|
原因是drawableSize为0,无法取出drawable。
渲染NV12
使用两个纹理
1 |
|
由于NV12有两个通道,因此需要传入两个纹理。这里使用两个MTLTextureDescriptor创建,y分量的纹理因为只有y值,因此使用MTLPixelFormatR8Unorm格式,表示一个八位的通道。uv分量使用MTLPixelFormatRG8Unorm,有两个八位通道。
修改片段着色器
1 |
|
这里增加一个纹理参数,从textureY中取出y,textureUV分别取出uv,利用公式转换成rgb值。
修改着色器程序
1 |
|
给renderEncoder传入两个纹理
1 |
|
调用渲染方法
1 |
|
运行程序,即可看到采集的画面。
使用CoreVideo相关函数创建纹理
使用CVMetalTextureCacheRef纹理缓存,CVMetalTextureCacheCreateTextureFromImage函数可以直接从CVPixelBufferRef中获取CVMetalTextureRef,然后在从CVMetalTextureRef中获得MTLTexture。
1 |
|
之后就和上面的纹理处理一致了。
总结
感觉使用Metal渲染的视频的代码比OpenGL的实现要容易些,基本就是渲染图片纹理稍作修改即可实现,而且MetalKit还提供了一些直接将AVFoundation数据转换为Metal可以处理的类型的功能,使得开发更加简单。