使用OpenGL渲染视频数据需要了解OpenGL的各种操作、函数调用,不是很符合OC习惯,如果只是简单的渲染显示功能,也可以使用苹果在iOS8中新推出的AVSampleBufferDisplayLayer类。
这里还是以iOS设备摄像头采集的数据做显示。
创建AVSampleBufferDisplayLayer
根据名字可以知道AVSampleBufferDisplayLayer是CALayer的子类,因此可以添加到UIView的layer上,这里创建一个新的View,用于以AVSampleBufferDisplayLayer渲染视频。
1 |
|
渲染显示CMSampleBuffer
AVSampleBufferDisplayLayer中有方法
1 |
|
对于从videoDataOutput中得到的数据,可以直接传入并显示。
1 |
|
运行程序,即可看到显示的画面。
渲染普通的buffer数据
当然,一般真正的应用场景中,是不会直接有CMSampleBuffer用来显示的,例如使用ffmpeg解码后的数据,一般是存放在AVFrame的结构体中,*data指针,因此,需要将buffer包装成CMSampleBuffer来给AVSampleBufferDisplayLayer显示。这里先使用RGBA的数据格式。
使用CVPixelBufferPool获取CVPixelBuffer
创建CMSampleBuffer,需要CVPixelBuffer,这里使用CVPixelBufferPool,这样由缓存池决定创建和销毁CVPixelBuffer,不用关心CVPixelBuffer导致的内存问题。
1 |
|
这里创建一个方法,参数包括RGBA数据buffer指针,视频的宽高
1 |
|
这里根据视频宽高和视频格式创建了一个CVPixelBufferPool。需要注意的是kCVPixelBufferBytesPerRowAlignmentKey这个参数,这个参数实际上是设置行宽(linesize/BytesPerRow)的基准而不是真正的行宽。真正的行宽会根据设置的宽高和视频格式决定,例如32BGRA的linesize一般是width*4。
创建CVPixelBuffer,并将视频数据传入
1 |
|
使用CVPixelBuffer创建CMSampleBuffer并显示数据
1 |
|
这样就完成了整个过程,接下来在采集数据的地方修改,将rgba数据传给渲染view。
1 |
|
之后运行程序,就可以看到采集的视频。
渲染NV12格式的数据
这里步骤和RGBA类似,就是创建CVPixelBufferPool时格式设置为NV12,拷贝数据的时候需要两路分量都拷贝。
1 |
|
调用时先修改采集格式,然后依次取出两个分量buffer即可。
1 |
|
渲染yuv420p
渲染yuv420p和上面类似,可以将CVPixelBufferPool的格式设置为kCVPixelFormatType_420YpCbCr8Planar,然后CVPixelBuffer依次拷贝进3个分量即可,这里就不放代码了。需要注意的是,直接使用yuv420p显示,实测在ios10是无法显示的,而在ios11.3以下的ios11系统,显示有问题,画面会一闪一闪的,因此在低版本适配时需要转换成NV12格式进行显示,转换方法可以使用上一篇提到的libyuv。
总结
虽然AVSampleBufferDisplayLayer使用起来相对简单,但实际由于每次都有memcpy的操作,所以性能会有损失,再加上直接渲染yuv的版本限制,我个人更倾向使用OpenGL渲染的方式。