GPUImage系列解析 已经接近尾声,这次介绍的是:
GPUImageTextureOutput
GPUImageRawDataInput
GPUImageRawDataOutput
GPUImageFilterPipeline
demo用来展示如何使用 GPUImageRawDataOutput 。
GPUImageTextureOutput类实现GPUImageInput协议,可以接受响应链的图像,并返回对应的OpenGL ES纹理。
GPUImageTextureInput类继承GPUImageOutput类,可以作为响应链的起点,把OpenGL ES纹理对应的纹理信息导入响应链处理。 textureSize属性为纹理尺寸; 初始化的时候,分配一个GPUImageFramebuffer,缓存纹理单元的信息; process的时候直接调用targets对应的就绪方法,因为图像信息就在OpenGL ES控制内存中。
GPUImageTextureOutput 和 GPUImageTextureInput 用于 向OpenGL ES 输入或者输出纹理,把GPUImage的输出作为OpenGL ES的纹理或者把OpenGL ES的输出作为GPUImage的纹理输入。
GPUImageRawDataOutput类实现协议GPUImageInput,可以接受响应链的图像信息,并且以二进制的格式返回数据;
texture2D(inputImageTexture, textureCoordinate).bgra;
GPUImageRawDataInput类继承GPUImageOutput类,可以接受二进制数据,按照特定的颜色格式,把数据转成图像并传入响应链; GPUImageRawDataInput不会对传入的数据copied或者retained,但你不需要在使用完之后去释放;二进制数据发送到GPU的纹理单元,默认的颜色格式是BGRA和整型数据。
GPUImageFilterPipeline类是滤镜通道,把inputs的滤镜组合起来,然后添加output为最后的输出目标。核心代码如下:
- (void)_refreshFilters { id prevFilter = self.input; GPUImageOutput<GPUImageInput> *theFilter = nil; for (int i = 0; i < [self.filters count]; i++) { theFilter = [self.filters objectAtIndex:i]; [prevFilter removeAllTargets]; [prevFilter addTarget:theFilter]; prevFilter = theFilter; [prevFilter removeAllTargets]; if (self.output != nil) { [prevFilter addTarget:self.output]; }
GPUImage详细解析(五)滤镜视频录制 的流程图为左边部分; demo的流程图为右边部分:
self.mOutput = [[GPUImageRawDataOutput alloc] initWithImageSize:CGSizeMake(640, 480) resultsInBGRAFormat:YES]; [videoCamera addTarget:self.mOutput];
[strongOutput lockFramebufferForReading]; GLubyte *outputBytes = [strongOutput rawBytesForImage]; NSInteger bytesPerRow = [strongOutput bytesPerRowInOutput]; CVPixelBufferRef pixelBuffer = NULL; CVReturn ret = CVPixelBufferCreateWithBytes(kCFAllocatorDefault, 640, 480, kCVPixelFormatType_32BGRA, outputBytes, bytesPerRow, nil, nil, nil, &pixelBuffer);
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, strongOutput.rawBytesForImage, bytesPerRow * 480, NULL); CGImageRef cgImage = CGImageCreate(640, 480, 8, 32, bytesPerRow, rgbColorSpace, kCGImageAlphaPremultipliedFirst|kCGBitmapByteOrder32Little, provider, NULL, true, kCGRenderingIntentDefault); UIImage *image = [UIImage imageWithCGImage:cgImage];
// 此处必须在主线程操作UI dispatch_async(dispatch_get_main_queue(), ^{ self.mImageView.image = image; });
CVPixelBufferCreateWithBytes 方法返回 kCVReturnInvalidArgument 错误。
CVPixelBufferCreateWithBytes
kCVReturnInvalidArgument
检查CVPixelBufferCreateWithBytes的width、height、pixelFormatType参数。
GPUImageVideoCamera输出图像旋转了90°。
In previous iOS versions, the front-facing camera would always deliver buffers in VCaptureVideoOrientationLandscapeLeft。 添加以下代码:
videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait; videoCamera.horizontallyMirrorFrontFacingCamera = YES;
通过二进制数据创建NSData,再创建UIImage,发现image为nil。
NSData* data = [[NSData alloc] initWithBytes:strongOutput.rawBytesForImage length:bytesPerRow * 480]; UIImage *image = [[UIImage alloc] initWithData:data];
暂未找到原因,猜测是data参数有问题。 +initWithData:的data参数要求必须是系统支持的image类型。 The data in the data parameter must be formatted to match the file format of one of the system’s supported image types.