【问题标题】:AVCaptureSession Display is White (no Video)AVCaptureSession 显示为白色(无视频)
【发布时间】:2012-12-22 00:40:08
【问题描述】:

我正在使用 AVCaptureSession,其输出设置为:

NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey; 
NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange];
NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:value forKey:key];
[captureOutput setVideoSettings:videoSettings];

我的 AVCaptureVideoPreviewLayer 显示正常,但我需要的不止这些,因为我没有成功使用 AVCaptureVideoPreviewLayer 获取屏幕截图。因此,当在 captureOutput 委托中创建 CGContextRef 时,我正在使用这些设置

uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer);
size_t width = CVPixelBufferGetWidth(imageBuffer); 
size_t height = CVPixelBufferGetHeight(imageBuffer);

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, width * 4, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
CGImageRef newImage = CGBitmapContextCreateImage(newContext);

我不再收到“不支持的参数组合”警告,但显示屏只是纯白色。

我应该在更改时添加它

NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange];

NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];

一切正常。我的问题是什么?

【问题讨论】:

  • 一方面,您试图从相机中提取 YUV 数据。这有两个平面,Y 和 UV,您正试图从中创建一个 RGB 位图。那是行不通的,这就是为什么告诉相机给你 BGRA 输入会使事情正常工作的原因。
  • 对,我想的差不多。我们必须使用这种视频格式(我认为),因为我们在图像处理应用程序中使用强度信息 Y。所以基本上我正在寻找正确的设置组合来访问每一帧视频,我可以在适当的时候将其显示为静止图像。更好的方法是保存和显示 AVCaptureVideoPreviewLayer 的静止帧。
  • 暂建议:AVCaptureStillImageOutput

标签: iphone ios cgcontext avcapturesession


【解决方案1】:

查看以下代码(它使用 FullVideoRange 代替),它“手动”将双平面视频帧转换为 RGB。

CVPixelBufferLockBaseAddress(imageBuffer, 0);

size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);

uint8_t *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
CVPlanarPixelBufferInfo_YCbCrBiPlanar *bufferInfo = (CVPlanarPixelBufferInfo_YCbCrBiPlanar *)baseAddress;

NSUInteger yOffset = EndianU32_BtoN(bufferInfo->componentInfoY.offset);
NSUInteger yPitch = EndianU32_BtoN(bufferInfo->componentInfoY.rowBytes);

NSUInteger cbCrOffset = EndianU32_BtoN(bufferInfo->componentInfoCbCr.offset);
NSUInteger cbCrPitch = EndianU32_BtoN(bufferInfo->componentInfoCbCr.rowBytes);

uint8_t *rgbBuffer = malloc(width * height * 3);
uint8_t *yBuffer = baseAddress + yOffset;
uint8_t *cbCrBuffer = baseAddress + cbCrOffset;

for(int y = 0; y < height; y++)
{
uint8_t *rgbBufferLine = &rgbBuffer[y * width * 3];
uint8_t *yBufferLine = &yBuffer[y * yPitch];
uint8_t *cbCrBufferLine = &cbCrBuffer[(y >> 1) * cbCrPitch];

for(int x = 0; x < width; x++)
{
    uint8_t y = yBufferLine[x];
    uint8_t cb = cbCrBufferLine[x & ~1];
    uint8_t cr = cbCrBufferLine[x | 1];

    uint8_t *rgbOutput = &rgbBufferLine[x*3];

    // from ITU-R BT.601, rounded to integers
    rgbOutput[0] = (298 * (y - 16) + 409 * cr - 223) >> 8;
    rgbOutput[1] = (298 * (y - 16) + 100 * cb + 208 * cr + 136) >> 8;
    rgbOutput[2] = (298 * (y - 16) + 516 * cb - 277) >> 8;
}
}

以下链接也可能有助于更好地理解此视频格式: http://blog.csdn.net/yiheng_l/article/details/3790219#yuvformats_nv12

【讨论】:

    【解决方案2】:

    看看InvasiveCode's tutorial。它展示了如何使用 Accelerate 和 CoreImage 框架来处理 Y 通道

    【讨论】:

      猜你喜欢
      • 2013-06-03
      • 2018-09-03
      • 1970-01-01
      • 2011-09-09
      • 1970-01-01
      • 1970-01-01
      • 2013-09-25
      • 1970-01-01
      相关资源
      最近更新 更多