教程
入门教程和进阶教程,介绍的是OpenGL ES基础,学习图形学基本概念,了解OpenGL ES的特性。
实践教程是OpenGL ES在实际开发中的应用,demo的来源主要是apple官网和github。
这一次的内容是用OpenGL ES绘制YUV视频:获取到视频的每帧图像信息,用OpenGL ES绘制出来。
效果展示
核心思路
通过APLImagePickerController选择本地的视频文件,用AVPlayer播放音频,用OpenGL ES绘制视频。
具体细节
1、AVPlayer
AVAsset:用于获取多媒体信息。
AVPlayerItem:管理视频的基本信息和状态。
AVPlayer:用来读取本地或者远程的多媒体文件。
AVPlayer的使用实例
AVAsset *movieAsset = [AVURLAsset URLAssetWithURL:sourceMovieURL options:nil];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:movieAsset];
AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
playerLayer.frame = self.view.layer.bounds;
playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
[self.view.layer addSublayer:playerLayer];
[player play];
可以使用KVO,观察playerItem的status和loadedTimeRange属性
status有三种状态:
AVPlayerStatusUnknown
AVPlayerStatusReadyToPlay:视频可以播放
AVPlayerStatusFailed
loadedTimeRange属性代表已经缓冲的进度。
在demo中,还用到一个AVPlayerItemVideoOutput类,用于协调输出的CoreVideo像素缓存,配置AVPlayerItem。
CADisplayLink帧显示的定时器
通过 CADisplayLink的timestamp 和 duration,计算下一帧显示的时间
从videoOutput中取出像素数据copyPixelBufferForItemTime
再通过displayPixelBuffer
把数据交给OpenGL ES绘制。
2、CGAffineTransform
CGAffineTransform是一个矩阵,结构如下
| a, b, 0 |
| c, d, 0 |
| tx, ty, 1 |
demo中会通过videoTrack的preferredTransform来获取拍摄开始时候的旋转角度,从而修正显示的角度。即使录制的时候是反着,显示也会是正的。
3、CMTime
CMTimeMake(a,b) a当前第几帧, b每秒钟多少帧.当前播放时间a/b
CMTimeMakeWithSeconds(a,b) a当前时间,b每秒钟多少帧
demo中的addPeriodicTimeObserverForInterval 方法
添加回调CMTimeMake(1, 2)每秒回调两次
4、APLEAGLView
自定义的UIView子类,用OpenGL ES绘制视频。
preferredRotation
旋转的弧度
presentationRect
显示视频的大小
chromaThreshold
色度大小
lumaThreshold
亮度大小
kColorConversion601
和 kColorConversion709
是两个YUV颜色空间到RGB颜色空间的转换矩阵。
OpenGL ES的基础不再赘述,入门教程和进阶教程这里有详细的介绍,这次着重介绍如何把YUV的视频显示绘制到屏幕上。
CVOpenGLESTextureCacheRef :缓存和管理CVOpenGLESTextureRef。
CVOpenGLESTextureRef、CVImageBufferRef、CVBufferRef这三个实际上是一样的,是CV纹理的缓存。
demo中的pixelBuffer是从AVPlayerItemVideoOutput获取到图像数据,再用CVOpenGLESTextureCacheCreateTextureFromImage从buffer中读取数据并创建chromaTexture和lumaTexture。
AVMakeRectWithAspectRatioInsideRect会计算得出合适的视频宽高,不超过layer的bounds,再与bounds相除,以此作为顶点坐标的位置数据。
5、shader
- 顶点着色器。通过preferredRotation计算出rotationMatrix,再对position进行操作。
- 片元着色器。从SamplerY和SamplerUV中取出颜色,再与lumaThreshold和chromaThreshold相乘得出最后的颜色。
总结
从iOS设备中获取到每一帧的视频信息,可以使用AV框架。
使用OpenGL ES绘制视频部分的逻辑与之前教程介绍相差不多,增加了CVOpenGLESTextureCacheRef的使用。
附上代码
网友评论
(1)对于一个HTTP的视频链接,我通过AVPlayerItemVideoOutput获取到它的视频输出(无法获取音频的buffer),因此只能进行播放,而不能对OpenGL绘制后的视频帧和音频(音频不需要处理)一起进行编码。
(2)通过AVAssetReader无法通过非本地的URL初始化,也就拿不到音频了;
"Cannot initialize an instance of AVAssetReader with an asset at non-local URL 'https://mvvideo5.meitudata.com/571090934cea5517.mp4'"
self.mEffect.texture2d0.name = CVOpenGLESTextureGetName(renderTexture);