简述
上一章,我们介绍了iOS采集相关细节。这一次,我来介绍下iOS硬编码相关知识。
首先,为什么需要编码,在上一次中,我们提到了一个东西,CMSampleBuffer,这个既可以用来封装ImageBuffer,也可以用于存储裸流数据,是一个通用的结构体。我先介绍一下这个是什么东西,之后就明白为啥需要编码了。
初识CVPixelBufferRef
在我们通常的颜色世界里面,我们都知道RGB三原色,使用这三种颜色的混合搭配,可以组成世界上的绝大多数色彩。
在计算机里面,我们称这种格式为kCVPixelFormatType_32RGBA,即每32位的数据里面,包含8位的R,8位的G,8位的B,8位的A。而通常,我们使用的却不是这个,而是另外一个,即kCVPixelFormatType_32BGRA。
到这里,我们能明白,如果使用RGBA来代表一张图,一个像素点就包含4字节,每一个字节代表个字位的原色。那么我们如果需要看一个60秒30fps720p的视频,那么我们需要720 * 1280 * 4 * 60 * 30 = 6635520000b数据,相当于791MB数据,我觉得大部分人的网速连10MB/s都可能达不到,更何况791MB/s,如果不经过视频编码,我们根本无法再现观看视频,更不用说直播了。
那在iOS里面是如何存储这些数据呢?那个对象,就是CVPixelBufferRef,CVPixelBufferRef实际上就是一张图画的像素点的布局。它可以是以下几种类型中的一种:
图像类型 | 含义 |
---|---|
kCVPixelFormatType_32RGBA | RGBA32位,布局为RGBA |
kCVPixelFormatType_32BGRA | BGRA32为,布局为BGRA |
kCVPixelFormatType_420YpCbCr8Planar / kCVPixelFormatType_420YpCbCr8PlanarFullRange | I420数据排列,布局为前面height * strides[0]为Y分量,中间height * strides[1] / 2为U分量,后面的数据为V分量 |
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange | NV12数据排列,布局为height * strides[0]为Y分量,height * strides[0]为UV分量,为比较常用的类型,运用于编码,解码,渲染中。UV数据范围为(luma=[16,235] chroma=[16,240]) |
kCVPixelFormatType_420YpCbCr8BiPlanarFullRange | NV12数据排列,布局为height * strides[0]为Y分量,height * strides[0]为UV分量,为比较常用的类型,运用于编码,解码,渲染中。UV数据范围为(luma=[0,255] chroma=[0,255]) |
kCVPixelFormatType_OneComponent8 | Gray分量,即Y分量,常用于端上画质增强的输入源。 |
kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange / kCVPixelFormatType_420YpCbCr10BiPlanarFullRange | HDR10相关数据源,后期会解释如何解码得到这种数据源。 |
我们知道了CVPixelBufferRef是一个什么样的东西,那我们如何创建一个CVPixelBuffer呢?我们看下相关的函数原型
/*!
* @param CFAllocatorRef 内存申请函数,可采用默认的kCFAllocatorDefault。
* @param width 需要创建的画布的宽。
* @param height 需要创建的画布的高。
* @param pixelFormatType 画布的类型,可以是之前提到的几个中的一个,或者是定义好的。
* @param pixelBufferAttributes 画布的属性,可以指定iOSSurface或者OpenGL属性。
* @param pixelBufferOut 创建的画布实例的引用指针。
*/
CV_EXPORT CVReturn CVPixelBufferCreate(
CFAllocatorRef CV_NULLABLE allocator,
size_t width,
size_t height,
OSType pixelFormatType,
CFDictionaryRef CV_NULLABLE pixelBufferAttributes,
CV_RETURNS_RETAINED_PARAMETER CVPixelBufferRef CV_NULLABLE * CV_NONNULL pixelBufferOut) __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_4_0);
示例代码:
int width = 1280;
int height = 720;
OSType format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
const void *keys[] = {
kCVPixelBufferOpenGLESCompatibilityKey,
kCVPixelBufferIOSurfacePropertiesKey
};
const void *values[] = {
(__bridge void *)[NSNumber numberWithBool:YES],
(__bridge void *)[NSDictionary dictionary]
};
CFDictionaryRef attributes = CFDictionaryCreate(NULL, keys, values, 2, NULL, NULL);
CVPixelBufferRef pixelBuffer = nil;
CVReturn ret = CVPixelBufferCreate(kCFAllocatorDefault,