【问题标题】:CVOpenGLESTextureCacheCreateTextureFromImage returns error 6683CVOpenGLESTextureCacheCreateTextureFromImage 返回错误 6683
【发布时间】:2012-09-28 19:35:46
【问题描述】:

我目前正在尝试使用 YUV420 格式(双平面)在 openGL 中绘制图像。我收到原始数据,并尝试将其解析为 CVPixelBuffer,然后使用 CVOpenGLESTextureCacheCreateTextureFromImage 传递所述缓冲区。虽然在解析到 CVPixelBuffer 时没有收到错误,但在尝试传递到 CVOpenGLESTextureCacheCreateTextureFromImage 时收到错误 (-6683)。我正在尽最大努力遵循苹果的 GLCameraRipple 示例代码 - 再次除外,我使用的是原始图像数据而不是来自相机的数据。

希望有人可以解释我在这里缺少什么 - 我认为这是一个缺少的属性...

仅供参考,平面 0 是 Y 平面,平面 1 是 UV 平面 - 其中 UV 平面应该是 Y 平面宽度和高度的一半。

size_t numPlanes = image->GetNumPlanes();
size_t planeWidth[numPlanes];
size_t planeHeight[numPlanes];
size_t scanWidth[numPlanes];
void *planeIndex[numPlanes];
for(int i = 0; i<numPlanes; i++){
    i<1 ? planeWidth[i] = image->GetWidth() : planeWidth[i] = image->GetWidth()/2;
    i<1 ? planeHeight[i] = image->GetHeight() : planeWidth[i] = image->GetHeight()/2;
    scanWidth[i] = image->GetScanWidth(i);
    planeIndex[i] = image->GetPlanePointer(i);
}

CVPixelBufferRef pixelBuffer;
CFDictionaryRef empty;
CFMutableDictionaryRef attrs;
empty = CFDictionaryCreate(kCFAllocatorDefault,
                           NULL,
                           NULL,
                           0,
                           &kCFTypeDictionaryKeyCallBacks,
                           &kCFTypeDictionaryValueCallBacks);

attrs = CFDictionaryCreateMutable(kCFAllocatorDefault,
                                  1,
                                  &kCFTypeDictionaryKeyCallBacks,
                                  &kCFTypeDictionaryValueCallBacks);

CFDictionarySetValue(attrs, kCVPixelBufferIOSurfacePropertiesKey, empty);



CVReturn cvError = CVPixelBufferCreateWithPlanarBytes(kCFAllocatorDefault,
                                                      image->GetWidth(),
                                                      image->GetHeight(),
                                                      kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,
                                                      nil,
                                                      nil,
                                                      numPlanes,
                                                      planeIndex,
                                                      planeWidth,
                                                      planeHeight,
                                                      scanWidth,
                                                      nil, nil, attrs, &pixelBuffer);
if(cvError) NSLog(@"Error at CVPixelBufferCreateWithPlanarBytes:  %d", cvError);

CVReturn err;
size_t width = CVPixelBufferGetWidth(pixelBuffer);
size_t height = CVPixelBufferGetHeight(pixelBuffer);

if (!_videoTextureCache)
{
    NSLog(@"No video texture cache");
    return;
}

if (_bModel == nil ||
    width != _textureWidth ||
    height != _textureHeight)
{
    _textureWidth = width;
    _textureHeight = height;

    _bModel = [[BufferModel alloc] initWithScreenWidth:_screenWidth
                                          screenHeight:_screenHeight
                                            meshFactor:_meshFactor
                                          textureWidth:_textureWidth
                                         textureHeight:_textureHeight];

    [self setupBuffers];
}

[self cleanUpTextures];

// CVOpenGLESTextureCacheCreateTextureFromImage will create GLES texture
// optimally from CVImageBufferRef.

// Y-plane
glActiveTexture(GL_TEXTURE0);
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
                                                   _videoTextureCache,
                                                   pixelBuffer,
                                                   NULL,
                                                   GL_TEXTURE_2D,
                                                   GL_RED_EXT,
                                                   _textureWidth,
                                                   _textureHeight,
                                                   GL_RED_EXT,
                                                   GL_UNSIGNED_BYTE,
                                                   0,
                                                   &_lumaTexture);
if (err)
{
    NSLog(@"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
}

感谢任何能够提供帮助的人。 虽然我知道有一个类似的问题(不完全相同),但所说的问题也很老,从未收到任何回复。我希望我的情况能有更多好运。

【问题讨论】:

  • 你有一些失败的示例代码吗?

标签: ios opengl-es-2.0 yuv


【解决方案1】:

您创建的 CVPixelBuffer 中的 iosurface 属性为 null。

手动创建:

&lt;CVPixelBuffer 0x1fd52790 width=1280 height=720 pixelFormat=420v iosurface=0x0 planes=2&gt;

由 CMSampleBufferGetImageBuffer 创建:

&lt;CVPixelBuffer 0x1fd521e0 width=1280 height=720 pixelFormat=420f iosurface=0x21621c54 planes=2&gt;

据我所知,没有解决办法。

【讨论】:

  • 感谢您的回复!有没有办法解决这个问题?还是我必须放弃这个不可能的想法?
  • 有趣的是,如果我使用具有相同分配器、宽度和高度、格式、属性和像素缓冲区的 CVPixelBufferCreate,我不会遇到同样的问题 - IOSurface 设置正确。不幸的是,这样做并没有设置图像数据,我似乎无法在 API 中找到任何东西让我在创建 CVPixelBuffer 后进入并设置它......
  • 一年来我一直在寻求解决这个问题... :-( 而且它与任何特定的硬件版本或操作系统版本无关。
  • 猜猜我必须回到绘图板上。真的希望这会成为一个很好的解决方案,通过 openGL 绘制 YUV 图像,而无需先转换为 RGB =/
  • 您如何获得像素缓冲区的格式化输出 (&lt;CVPixelBuffer 0x1fd52790 ...)?你是手工制作的还是有办法记录这样的内容?
【解决方案2】:

如果您要在 OpenGL 中使用 CVPixelBufferRef,请使用 CVPixelBufferCreate。与WithBytes 替代方案不同,它为您创建了一个 iosurface。缺点是您不能重用现有的缓冲区。您必须将现有缓冲区中的数据复制到新分配的缓冲区中。

// set pixel buffer attributes so we get an iosurface
NSDictionary *pixelBufferAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                       [NSDictionary dictionary], kCVPixelBufferIOSurfacePropertiesKey,
                                       nil];

// create planar pixel buffer
CVPixelBufferRef pixelBuffer = nil;
CVPixelBufferCreate(kCFAllocatorDefault, bufferYUV.width, bufferYUV.height, kCVPixelFormatType_420YpCbCr8BiPlanarFullRange, (CFDictionaryRef)pixelBufferAttributes, &pixelBuffer);

// lock pixel buffer
CVPixelBufferLockBaseAddress(pixelBuffer, 0);

// get image details
size_t width = CVPixelBufferGetWidth(pixelBuffer);
size_t height = CVPixelBufferGetHeight(pixelBuffer);

// get plane addresses
unsigned char *baseAddressY  = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
unsigned char *baseAddressUV = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);

//TODO: copy your data buffers to the newly allocated memory locations

// unlock pixel buffer address
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);

// intialize buffers if not already initialized (see GLCameraRipple example)
if (!_buffersInitialized)
{
    [self initializeBuffersWithTextureWidth:width textureHeight:height];
}

// always clean up last textures
CVReturn err;
[self cleanUpTextures];

// Y-plane
glActiveTexture(GL_TEXTURE0);
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _videoTextureCache, pixelBuffer, NULL, GL_TEXTURE_2D, GL_RED_EXT, width, height, GL_RED_EXT, GL_UNSIGNED_BYTE, 0, &_lumaTexture);
if (err)
{
    NSLog(@"Could not create Y texture from image. %d", err);
}

glBindTexture(CVOpenGLESTextureGetTarget(_lumaTexture), CVOpenGLESTextureGetName(_lumaTexture));
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

// UV-plane
glActiveTexture(GL_TEXTURE1);
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _videoTextureCache, pixelBuffer, NULL, GL_TEXTURE_2D, GL_RG_EXT, width / 2, height / 2, GL_RG_EXT, GL_UNSIGNED_BYTE, 1, &_chromaTexture);
if (err)
{
    NSLog(@"Could not create UV texture from image. %d", err);
}

glBindTexture(CVOpenGLESTextureGetTarget(_chromaTexture), CVOpenGLESTextureGetName(_chromaTexture));
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

【讨论】:

  • 我是视频处理的新手,并尝试做与您的答案类似的事情(按照 CGCamerRipple 示例)。但我不确定如何将现有缓冲区中的数据复制到新分配的缓冲区中?例如..你怎么知道新分配的缓冲区足够大?另外,我看到您使用了 baseAddressUV 缓冲区。这与 U 平面和 V 平面缓冲区有什么关系?
  • 您可以使用 memcpy 将数据复制到新的缓冲区中 - 只要确保您考虑到步幅!如果您提供了正确的宽度和高度值,CVPixelBufferCreate 可确保分配的缓冲区足够大,但同样,请确保您注意输入平面的步幅和由 CVPixelBufferCreate 创建的平面的步幅。 UV 平面应由交错的 UV 数据 (UVUVUVUV...) 组成。
  • 如果您的输入在不同的平面上有 U 和 V 数据,则必须在使用 CVPixelBuffer 之前将它们交错。如果您需要快速交错/去交错算法,请参阅 stackoverflow.com/questions/14567786/…
  • 我相信你也可以通过在pixelBufferAttributes字典中使用kCVPixelBufferBytesPerRowAlignmentKey来指定CVPixelBufferCreate分配的平面的步幅。
  • 如果 U 和 V 数据在不同的平面上,你不能只使用 kCVPixelFormatType_420YpCbCr8Planar 吗?
【解决方案3】:

我没有在 YUV 上尝试以下方法,但它适用于 RGB 情况

https://developer.apple.com/library/ios/qa/qa1781/_index.html

如果启用了 ARC,则在 CFDictionaryRef 之前添加 __bridge。

【讨论】:

    猜你喜欢
    • 2023-03-03
    • 2016-07-12
    • 2015-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-19
    • 2019-09-23
    • 1970-01-01
    相关资源
    最近更新 更多