我正在使用AVComposition
编写一些视频处理代码。仅提供必要的背景详细信息,我从苹果API收到CVPixelBuffer
,我无法控制。这个CVPixel缓冲区包含一个以前渲染的视频帧,因为它们显然是由我无法控制的Apple API回收的。所以我的目标是将CVPixelBufferRef中的所有像素设置为[0,0,0,0](在RGBA颜色空间中)。我可以通过这个函数在CPU上执行此操作:
- (void)processPixelBuffer: (CVImageBufferRef)pixelBuffer
{
CVPixelBufferLockBaseAddress( pixelBuffer, 0 );
int bufferWidth = CVPixelBufferGetWidth(pixelBuffer);
int bufferHeight = CVPixelBufferGetHeight(pixelBuffer);
unsigned char *pixel = (unsigned char *)CVPixelBufferGetBaseAddress(pixelBuffer);
for( int row = 0; row < bufferHeight; row++ ) {
for( int column = 0; column < bufferWidth; column++ ) {
pixel[0] = 0;
pixel[1] = 0;
pixel[2] = 0;
pixel[3] = 0;
pixel += 4;
}
}
CVPixelBufferUnlockBaseAddress( pixelBuffer, 0 );
}
有什么办法可以用GPU完成同样的事情吗?另外,是否可以通过CoreImage执行此操作?因为我不知道openGL,所以设置起来相当复杂。
答案 0 :(得分:2)
假设您的像素缓冲区已附加到an image buffer backed by an IO surface,您可以使用CVOpenGLESTextureCacheCreateTextureFromImage
让CVOpenGLESTextureCache
为您提供CVOpenGLESTextureRef
。这将能够提供纹理目标和名称,以便您可以在OpenGL中绑定事物。
在OpenGL中,您可以use a framebuffer object to render to a texture。完成后,您可以使用glClear
来清除事物。调用glFinish
与GL管道创建同步点,当您下次从CPU检查时,应清除内存。
答案 1 :(得分:2)
我遇到同样的问题(强制-[AVVideoCompositionRenderContext newPixelBuffer]
提供的循环缓冲区为黑色)。
如果您使用Core Image进行繁重的工作怎么办?像这样:
EAGLContext *eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
CIContext *ciContext = [CIContext contextWithEAGLContext:eaglContext];
CIImage *image = [CIImage imageWithColor:[CIColor colorWithRed:0 green:0 blue:0]];
CVPixelBufferRef destination = [request.renderContext newPixelBuffer];
[ciContext render:image toCVPixelBuffer:destination];
[request finishWithComposedVideoFrame:destination];
CVBufferRelease(destination);
你必须测试性能以了解它是否比memset
更好,但这比我试图仅仅为了设置几个位而试图进入OpenGL API更好。
答案 2 :(得分:2)
你可以使用Accelerate vImageBufferFill
来做到这一点(尽管不是GPU)。这在Swift 4中用黑色填充BGRA:
let width: Int = 3
let height: Int = 3
var pixelBuffer: CVPixelBuffer?
var imageBuffer: vImage_Buffer
var date: Date
let iterations: Int = 10000
let pixelBufferAttributes: [CFString: Any] = [kCVPixelBufferCGImageCompatibilityKey: true, kCVPixelBufferCGBitmapContextCompatibilityKey: true]
if CVPixelBufferCreate(kCFAllocatorDefault, width, height, kCVPixelFormatType_32BGRA, pixelBufferAttributes as CFDictionary, &pixelBuffer) != kCVReturnSuccess || pixelBuffer == nil { fatalError("Cannot create pixel buffer.") }
if CVPixelBufferLockBaseAddress(pixelBuffer!, []) != kCVReturnSuccess { fatalError("Cannot lock pixel buffer base address.") }
imageBuffer = vImage_Buffer(data: CVPixelBufferGetBaseAddress(pixelBuffer!), height: UInt(height), width: UInt(width), rowBytes: CVPixelBufferGetBytesPerRow(pixelBuffer!))
vImageBufferFill_ARGB8888(&imageBuffer, [0, 0, 0, 0xFF], UInt32(kvImageNoFlags))
if CVPixelBufferUnlockBaseAddress(pixelBuffer!, []) != kCVReturnSuccess { fatalError("Cannot unlock pixel buffer base address.") }
测试普通memset以在10000次迭代中用零填充小缓冲区在游乐场中更快。在发布版本中,实际数据结果可能没那么大差别。
答案 3 :(得分:1)
从this page看起来您可以通过以下方式直接访问CVImageBufferRef
作为OpenGL纹理:
glBindTexture( CVOpenGLTextureGetTarget( image ), CVOpenGLTextureGetName( image ) );
将纹理作为纹理后,可以将其用作FBO的绘图缓冲区,只需在其上调用glClear(GL_COLOR_BUFFER_BIT);
即可。