【问题标题】:CVOpenGLESTextureCacheCreateTextureFromImage on iPad2 is too slow ,it needs almost 30 ms, too crazyiPad2 上的 CVOpenGLESTextureCacheCreateTextureFromImage 太慢了,需要将近 30 毫秒,太疯狂了
【发布时间】:2012-07-21 09:45:48
【问题描述】:

我使用 opengl es 在 iPad 上显示 bgr24 数据,我是 opengl es 的新手,所以在显示视频部分我使用来自 RosyWriter 的代码一个 APPLE 示例。它可以工作,但 CVOpenGLESTextureCacheCreateTextureFromImage 函数花费超过 30 毫秒,而在 RosyWriter 它的成本可以忽略不计。 我所做的是首先将 BGR24 转换为 BGRA 像素格式,然后使用 CVPixelBufferCreateWithBytes 函数创建一个 CVPixelBufferRef,然后通过 CVOpenGLESTextureCacheCreateTextureFromImage 获取一个 CVOpenGLESTextureRef。我的代码如下,

- (void)transformBGRToBGRA:(const UInt8 *)pict width:(int)width height:(int)height
{
rgb.data = (void *)pict;

vImage_Error error = vImageConvert_RGB888toARGB8888(&rgb,NULL,0,&argb,NO,kvImageNoFlags);
if (error != kvImageNoError) {
    NSLog(@"vImageConvert_RGB888toARGB8888 error");
}

const uint8_t permuteMap[4] = {1,2,3,0};

error = vImagePermuteChannels_ARGB8888(&argb,&bgra,permuteMap,kvImageNoFlags);
if (error != kvImageNoError) {
    NSLog(@"vImagePermuteChannels_ARGB8888 error");
}

free((void *)pict);
}

变换后会生成CVPixelBufferRef,代码如下,

[self transformBGRToBGRA:pict width:width height:height];

CVPixelBufferRef pixelBuffer;
CVReturn err = CVPixelBufferCreateWithBytes(NULL,
                             width,
                             height,
                             kCVPixelFormatType_32BGRA, 
                             (void*)bgraData, 
                             bytesByRow, 
                             NULL, 
                             0,
                             NULL, 
                             &pixelBuffer);

if(!pixelBuffer || err)
{
    NSLog(@"CVPixelBufferCreateWithBytes failed (error: %d)", err);  
    return;
}

CVOpenGLESTextureRef texture = NULL;
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, 
                                                            videoTextureCache,
                                                            pixelBuffer,
                                                            NULL,
                                                            GL_TEXTURE_2D,
                                                            GL_RGBA,
                                                            width,
                                                            height,
                                                            GL_BGRA,
                                                            GL_UNSIGNED_BYTE,
                                                            0,
                                                            &texture);


if (!texture || err) {
    NSLog(@"CVOpenGLESTextureCacheCreateTextureFromImage failed (error: %d)", err);  
    CVPixelBufferRelease(pixelBuffer);
    return;
}

其他代码几乎与 RosyWriter 示例类似,包括着色器。所以我想知道为什么, 如何解决这个问题。

【问题讨论】:

  • 您要上传的图片尺寸是多少?你确定你没有在这 30 毫秒内测量你的 -transformBGRToBGRA: 方法的时间吗?
  • 是的,我确定。是1024 * 768,transformBGRToBGRA的时间:我测的是10ms。
  • 好的,所以您测量的 30 毫秒是从 CVPixelBufferCreateWithBytes() 调用之前到 CVOpenGLESTextureCacheCreateTextureFromImage() 调用之后的右侧?这似乎非常高,因为我已经看到 iPad 2 上传 1080p 帧(像素多 2.6 倍)比 30 毫秒快得多。如果您只对这些数据使用 glTexImage2D(),您的时间是多少?
  • 真的很高,实际上30ms只需要调用CVOpenGLESTextureCacheCreateTextureFromImage(),函数CVPixelBufferCreateWithBytes()什么都不用。我只是用 glTexImage2D() 重写代码,大约花费 5ms,所以我认为这也更高,我花了一天多的时间寻找原因,并尝试解决此问题,但没有答案。
  • 看来我找到了答案,你能给我一些建议吗?

标签: ios video opengl-es


【解决方案1】:

通过这几天的研究,我发现为什么CVOpenGLESTextureCacheCreateTextureFromImage要花很多时间,当数据很大时,这里是3M,分配,复制和移动操作成本相当可观,尤其是复制操作。然后用像素缓冲池大大提高CVOpenGLESTextureCacheCreateTextureFromImage的性能从30ms到5ms,与glTexImage2D()相同。我的解决方案如下:

NSMutableDictionary*     attributes;
attributes = [NSMutableDictionary dictionary];


[attributes setObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey];
[attributes setObject:[NSNumber numberWithInt:videoWidth] forKey: (NSString*)kCVPixelBufferWidthKey];
[attributes setObject:[NSNumber numberWithInt:videoHeight] forKey: (NSString*)kCVPixelBufferHeightKey];

CVPixelBufferPoolCreate(kCFAllocatorDefault, NULL, (CFDictionaryRef) attributes, &bufferPool);

CVPixelBufferPoolCreatePixelBuffer (NULL,bufferPool,&pixelBuffer);

CVPixelBufferLockBaseAddress(pixelBuffer,0);

UInt8 * baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer);

memcpy(baseAddress, bgraData, bytesByRow * videoHeight);

CVPixelBufferUnlockBaseAddress(pixelBuffer,0);

使用这个新创建的 pixelBuffer,您可以加快速度。

attribtes中添加如下配置可以使其性能达到最佳,小于1ms。

 NSDictionary *IOSurfaceProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                                                        [NSNumber numberWithBool:YES], @"IOSurfaceOpenGLESFBOCompatibility",[NSNumber numberWithBool:YES], @"IOSurfaceOpenGLESTextureCompatibility",nil];

[attributes setObject:IOSurfaceProperties forKey:(NSString*)kCVPixelBufferIOSurfacePropertiesKey];

【讨论】:

  • 我实现了这个建议,添加了表面属性并使用了像素缓冲池。但是,我发现 iPad2 的性能没有任何改善。现在我的代码只有 89% 的时间运行 memcpy()。我看不出这种方法可以如何改进,因为纹理上传是这段代码的时间关键部分。如果像素数据已经在用户缓冲区中,那么通过另一个副本将内存移动到 CVPixelBuffer 中会得到什么?
  • 这里有同样的问题。如果您已经在内存中获得了 BGRA 数据,为什么不能用 CVPixelBufferRef 包装它?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-12
  • 2010-12-25
  • 2013-12-30
  • 2013-03-10
  • 2014-06-07
  • 2016-05-31
  • 2011-07-07
相关资源
最近更新 更多