iOS的编码器仅仅支持CVPixelBufferRef的输入,常规的做法是从编码器Session的PixelBufferPool拿到一个CVPixelBufferRef,不过它的格式NV12(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
或者kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
)这两种形式。我们的业务场景是可以直接拿到OpenGLES的Texture的,如果采用这种方案那么我需要在shader中把RGB转为NV12。所以这个不是最优的方案,最优的方案应该是直接创建一个RGB的CVPixelBufferRef然后再把OpenGLES的Texture画上去。我是参考GPUImage的做法,不过它也是参考这里,在GPUImage的代码中有说明。
The H.264 encoder natively supports kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange and
kCVPixelFormatType_420YpCbCr8BiPlanarFullRange, which should be used with video and full range
input respectively. The JPEG encoder on iOS natively supports
kCVPixelFormatType_422YpCbCr8FullRange. For other video codecs on OSX,
kCVPixelFormatType_422YpCbCr8 is the preferred pixel format for video and is generally the most
performant when encoding. If you need to work in the RGB domain then kCVPixelFormatType_32BGRA is
recommended on iOS and kCVPixelFormatType_32ARGB is recommended on OSX.
- 创建CVPixelBufferRef
仅仅支持创建kCVPixelFormatType_32BGRA这种格式的CVPixelBufferRef,其他的格式都会失败。
CVPixelBufferRef CreatePixelBuffer(size_t width, size_t height)
{
CVPixelBufferRef pixel_buffer;
CFDictionaryRef empty; // empty value for attr value.
CFMutableDictionaryRef attrs;
// our empty IOSurface properties dictionary
empty = CFDictionaryCreate(kCFAllocatorDefault, nullptr, nullptr, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(attrs, kCVPixelBufferIOSurfacePropertiesKey, empty);
CVReturn err = CVPixelBufferCreate(kCFAllocatorDefault, width, height, kCVPixelFormatType_32BGRA, attrs, &pixel_buffer);
if (err) {
LOG(LS_ERROR) << "FBO size " << width << "x" << height << ", Error at CVPixelBufferCreate " << err;
}
CFRelease(attrs);
CFRelease(empty);
return pixel_buffer;
}
- 获取OpenGLES的Texture ID
CVPixelBufferRef的格式是GL_BGRA,我们需要的OpenGLES的格式是GL_RGBA
CVPixelBufferRef pixel_buffer = CreatePixelBuffer(width, height);
RTC_CHECK(pixel_buffer);
CVOpenGLESTextureRef gles_texture_ref;
CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, texture_cache, pixel_buffer, nullptr,
GL_TEXTURE_2D, GL_RGBA/*gles format*/, width, height, GL_BGRA/*pixbuffer format*/, GL_UNSIGNED_BYTE, 0, &gles_texture_ref);
if (err) {
LOG(LS_ERROR) << "CVOpenGLESTextureCacheCreateTextureFromImage error: " << err;
framebuffer_pool->ReturnFrameBuffer(tex);
CVPixelBufferRelease(pixel_buffer);
pixel_buffer = nullptr;
gles_texture_ref = nil;
return;
}
RTC_CHECK(CVOpenGLESTextureGetTarget(gles_texture_ref) == GL_TEXTURE_2D) << "Unexpected GLES texture target";
uint32_t texture_id = CVOpenGLESTextureGetName(gles_texture_ref);