下面是第 16 期面试题精选:
1)整体框架
通常我们通过 AVCaptureSession 相关的 API 来进行音视频的采集,其中主要组件分为 Input、Output、Session 几个部分:
可以通过如下代码获取视频输出支持的格式:
AVCaptureVideoDataOutput *videoOut = [[AVCaptureVideoDataOutput alloc] init];
NSArray<NSNumber *> *types = [videoOut availableVideoCVPixelFormatTypes];
NSLog(@"type count: %ld", types.count); // 3 种
for (NSNumber *type in types) {
NSLog(@"type: %@", type);
}
2)视频采集
对于视频采集,一般直接使用 AVCaptureSession 的 API 即可,需要注意的是:相机(前后置一样)吐出的视频帧,默认是横屏模式的 (横屏,Home 键在右边,也就是顺时针旋转 90 度就变成 Home 键在下边的正常竖屏状态),跟 Android 略有差异。
视频采集时会有一个 10 多帧的缓存,当我们没有及时归还相机吐出的视频帧,导致采集吐帧的这个缓存空了,就会导致相机不吐帧。
3)音频采集
对于音频采集,除了可以使用 AVCaptureSession 来进行音频采集外,还可以使用 AudioUnit。
使用 AVCaptureSession 可以和视频采集在一起处理,也可以单独创建新的 AVCaptureSession 进行音频采集。
使用 AudioUnit 音频采集:
音视频处理链路中的内存峰值一般是视频数据导致的,要降低内存峰值一般可以从两个方面入手:
以纹理 y 坐标中间分屏为例,代码如下:
precision highp float;
varying lowp vec2 varyTextCoord;
uniform sampler2D inputTexture;
void main()
{
float y;
if (varyTextCoord.y >= 0.0 && varyTextCoord.y <= 0.5) {
y = varyTextCoord.y + 0.25;
} else {
y = varyTextCoord.y - 0.25;
}
gl_FragColor = texture2D(inputTexture, vec2(varyTextCoord.x, y));
}
1)搞清楚顶点坐标与纹理坐标
(-1, -1)
,右上角是 (1, 1)
;(0, 0)
,右上角是 (1, 1)
,也就是 (0, 0)
对应图片的左下角,(1, 1)
对应着图片的右上角;GLfloat vertexes[] =
{
-1.0, -1.0, //左下
1.0, -1.0, //右下
-1.0, 1.0, //左上
1.0, 1.0 //右上
};
GLfloat textures[] = {
0.0f, 0.0f, //左下
1.0f, 0.0f, //右下
0.0f, 1.0f, //左上
1.0f, 1.0f //右上
};
2)FBO 与 glViewport
首先绘制前 FBO 需要绑定了一个尺寸一致的 texture,绘制的内容会被绘制到这张 texture 上,这个就是 RTT,如果 FBO 为 0 则是屏幕绘制,否则是离屏绘制,可以将 FBO 看作画板,texture 看做这张画布。
一般我们会将 viewport 设置为: (0, 0, FBO.width, FBO.height)
,这样绘制会占满整个 FBO,而顶点的的4个顶点是与 viewport 的4个顶点一一对应的,当然纹理也是一样对应的。
viewport 的 frame 和 FBO 不一致时,就会只在 viewport 的那块区域进行绘制对应的内容,也就是将输入的纹理在 viewport 的 frame 上进行绘制。