从支持 IOSurface 的 YUV 创建 CVPixelBuffer
Create CVPixelBuffer from YUV with IOSurface backed
所以我从网络回调(voip 应用程序)中获取 3 个单独数组中的原始 YUV 数据。据我了解,您无法根据 here
使用 CVPixelBufferCreateWithPlanarBytes
创建 IOSurface 支持的像素缓冲区
Important: You cannot use CVPixelBufferCreateWithBytes() or
CVPixelBufferCreateWithPlanarBytes() with
kCVPixelBufferIOSurfacePropertiesKey. Calling
CVPixelBufferCreateWithBytes() or CVPixelBufferCreateWithPlanarBytes()
will result in CVPixelBuffers that are not IOSurface-backed
因此您必须使用 CVPixelBufferCreate
创建它,但是如何将数据从调用传输回您创建的 CVPixelBufferRef
?
- (void)videoCallBack(uint8_t *yPlane, uint8_t *uPlane, uint8_t *vPlane, size_t width, size_t height, size_t stride yStride,
size_t uStride, size_t vStride)
NSDictionary *pixelAttributes = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{}};
CVPixelBufferRef pixelBuffer = NULL;
CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault,
width,
height,
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
(__bridge CFDictionaryRef)(pixelAttributes),
&pixelBuffer);
我不确定之后要做什么?最后我想把它变成一个 CIImage 然后我可以使用我的 GLKView 来渲染视频。人们如何 "put" 从您创建数据到缓冲区?
我弄明白了,这很简单。下面是完整的代码。唯一的问题是我收到 BSXPCMessage received error for message: Connection interrupted
并且视频需要一段时间才能显示。
NSDictionary *pixelAttributes = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{}};
CVPixelBufferRef pixelBuffer = NULL;
CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault,
width,
height,
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
(__bridge CFDictionaryRef)(pixelAttributes),
&pixelBuffer);
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
uint8_t *yDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
memcpy(yDestPlane, yPlane, width * height);
uint8_t *uvDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
memcpy(uvDestPlane, uvPlane, numberOfElementsForChroma);
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
if (result != kCVReturnSuccess) {
DDLogWarn(@"Unable to create cvpixelbuffer %d", result);
}
CIImage *coreImage = [CIImage imageWithCVPixelBuffer:pixelBuffer]; //success!
CVPixelBufferRelease(pixelBuffer);
我忘了添加交错两个 U 和 V 平面的代码,但这应该不会太糟糕。
我有一个类似的问题,这是我在 SWIFT 2.0 中的信息,其中包含我从其他问题或 link 的答案中获得的信息。
func generatePixelBufferFromYUV2(inout yuvFrame: YUVFrame) -> CVPixelBufferRef?
{
var uIndex: Int
var vIndex: Int
var uvDataIndex: Int
var pixelBuffer: CVPixelBufferRef? = nil
var err: CVReturn;
if (m_pixelBuffer == nil)
{
err = CVPixelBufferCreate(kCFAllocatorDefault, yuvFrame.width, yuvFrame.height, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, nil, &pixelBuffer)
if (err != 0) {
NSLog("Error at CVPixelBufferCreate %d", err)
return nil
}
}
if (pixelBuffer != nil)
{
CVPixelBufferLockBaseAddress(pixelBuffer!, 0)
let yBaseAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer!, 0)
if (yBaseAddress != nil)
{
let yData = UnsafeMutablePointer<UInt8>(yBaseAddress)
let yDataPtr = UnsafePointer<UInt8>(yuvFrame.luma.bytes)
// Y-plane data
memcpy(yData, yDataPtr, yuvFrame.luma.length)
}
let uvBaseAddress = CVPixelBufferGetBaseAddressOfPlane(m_pixelBuffer!, 1)
if (uvBaseAddress != nil)
{
let uvData = UnsafeMutablePointer<UInt8>(uvBaseAddress)
let pUPointer = UnsafePointer<UInt8>(yuvFrame.chromaB.bytes)
let pVPointer = UnsafePointer<UInt8>(yuvFrame.chromaR.bytes)
// For the uv data, we need to interleave them as uvuvuvuv....
let iuvRow = (yuvFrame.chromaB.length*2/yuvFrame.width)
let iHalfWidth = yuvFrame.width/2
for i in 0..<iuvRow
{
for j in 0..<(iHalfWidth)
{
// UV data for original frame. Just interleave them.
uvDataIndex = i*iHalfWidth+j
uIndex = (i*yuvFrame.width) + (j*2)
vIndex = uIndex + 1
uvData[uIndex] = pUPointer[uvDataIndex]
uvData[vIndex] = pVPointer[uvDataIndex]
}
}
}
CVPixelBufferUnlockBaseAddress(pixelBuffer!, 0)
}
return pixelBuffer
}
注意:yuvFrame是一个结构体,有y、u、v平面缓冲区和宽高。另外,我有 CFDictionary 吗? CVPixelBufferCreate(...) 中的参数设置为 nil。如果我给它 IOSurface 属性,它会失败并抱怨它不是 IOSurface 支持或错误 -6683.
访问这些 link 了解更多信息:
link 是关于 UV 交错的:
How to convert from YUV to CIImage for iOS
及相关问题:CVOpenGLESTextureCacheCreateTextureFromImage returns error 6683
这里是 obj-c 中的完整转换。
还有所有那些说:“这是微不足道的”的天才,不要光顾任何人!如果你是来帮忙的,帮忙,如果你来这里是为了展示你有多“聪明”,那就去别的地方吧。
这里是link对YUV处理的详细解释:www.glebsoft.com
/// method to convert YUV buffers to pixelBuffer in otder to feed it to face unity methods
-(CVPixelBufferRef*)pixelBufferFromYUV:(uint8_t *)yBuffer vBuffer:(uint8_t *)uBuffer uBuffer:(uint8_t *)vBuffer width:(int)width height:(int)height {
NSDictionary *pixelAttributes = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{}};
CVPixelBufferRef pixelBuffer;
/// NumberOfElementsForChroma is width*height/4 because both U plane and V plane are quarter size of Y plane
CGFloat uPlaneSize = width * height / 4;
CGFloat vPlaneSize = width * height / 4;
CGFloat numberOfElementsForChroma = uPlaneSize + vPlaneSize;
CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault,
width,
height,
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
(__bridge CFDictionaryRef)(pixelAttributes),
&pixelBuffer);
///for simplicity and speed create a combined UV panel to hold the pixels
uint8_t *uvPlane = calloc(numberOfElementsForChroma, sizeof(uint8_t));
memcpy(uvPlane, uBuffer, uPlaneSize);
memcpy(uvPlane += (uint8_t)(uPlaneSize), vBuffer, vPlaneSize);
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
uint8_t *yDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
memcpy(yDestPlane, yBuffer, width * height);
uint8_t *uvDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
memcpy(uvDestPlane, uvPlane, numberOfElementsForChroma);
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
CVPixelBufferRelease(pixelBuffer);
free(uvPlane);
return pixelBuffer;
}
所以我从网络回调(voip 应用程序)中获取 3 个单独数组中的原始 YUV 数据。据我了解,您无法根据 here
使用CVPixelBufferCreateWithPlanarBytes
创建 IOSurface 支持的像素缓冲区
Important: You cannot use CVPixelBufferCreateWithBytes() or CVPixelBufferCreateWithPlanarBytes() with kCVPixelBufferIOSurfacePropertiesKey. Calling CVPixelBufferCreateWithBytes() or CVPixelBufferCreateWithPlanarBytes() will result in CVPixelBuffers that are not IOSurface-backed
因此您必须使用 CVPixelBufferCreate
创建它,但是如何将数据从调用传输回您创建的 CVPixelBufferRef
?
- (void)videoCallBack(uint8_t *yPlane, uint8_t *uPlane, uint8_t *vPlane, size_t width, size_t height, size_t stride yStride,
size_t uStride, size_t vStride)
NSDictionary *pixelAttributes = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{}};
CVPixelBufferRef pixelBuffer = NULL;
CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault,
width,
height,
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
(__bridge CFDictionaryRef)(pixelAttributes),
&pixelBuffer);
我不确定之后要做什么?最后我想把它变成一个 CIImage 然后我可以使用我的 GLKView 来渲染视频。人们如何 "put" 从您创建数据到缓冲区?
我弄明白了,这很简单。下面是完整的代码。唯一的问题是我收到 BSXPCMessage received error for message: Connection interrupted
并且视频需要一段时间才能显示。
NSDictionary *pixelAttributes = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{}};
CVPixelBufferRef pixelBuffer = NULL;
CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault,
width,
height,
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
(__bridge CFDictionaryRef)(pixelAttributes),
&pixelBuffer);
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
uint8_t *yDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
memcpy(yDestPlane, yPlane, width * height);
uint8_t *uvDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
memcpy(uvDestPlane, uvPlane, numberOfElementsForChroma);
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
if (result != kCVReturnSuccess) {
DDLogWarn(@"Unable to create cvpixelbuffer %d", result);
}
CIImage *coreImage = [CIImage imageWithCVPixelBuffer:pixelBuffer]; //success!
CVPixelBufferRelease(pixelBuffer);
我忘了添加交错两个 U 和 V 平面的代码,但这应该不会太糟糕。
我有一个类似的问题,这是我在 SWIFT 2.0 中的信息,其中包含我从其他问题或 link 的答案中获得的信息。
func generatePixelBufferFromYUV2(inout yuvFrame: YUVFrame) -> CVPixelBufferRef?
{
var uIndex: Int
var vIndex: Int
var uvDataIndex: Int
var pixelBuffer: CVPixelBufferRef? = nil
var err: CVReturn;
if (m_pixelBuffer == nil)
{
err = CVPixelBufferCreate(kCFAllocatorDefault, yuvFrame.width, yuvFrame.height, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, nil, &pixelBuffer)
if (err != 0) {
NSLog("Error at CVPixelBufferCreate %d", err)
return nil
}
}
if (pixelBuffer != nil)
{
CVPixelBufferLockBaseAddress(pixelBuffer!, 0)
let yBaseAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer!, 0)
if (yBaseAddress != nil)
{
let yData = UnsafeMutablePointer<UInt8>(yBaseAddress)
let yDataPtr = UnsafePointer<UInt8>(yuvFrame.luma.bytes)
// Y-plane data
memcpy(yData, yDataPtr, yuvFrame.luma.length)
}
let uvBaseAddress = CVPixelBufferGetBaseAddressOfPlane(m_pixelBuffer!, 1)
if (uvBaseAddress != nil)
{
let uvData = UnsafeMutablePointer<UInt8>(uvBaseAddress)
let pUPointer = UnsafePointer<UInt8>(yuvFrame.chromaB.bytes)
let pVPointer = UnsafePointer<UInt8>(yuvFrame.chromaR.bytes)
// For the uv data, we need to interleave them as uvuvuvuv....
let iuvRow = (yuvFrame.chromaB.length*2/yuvFrame.width)
let iHalfWidth = yuvFrame.width/2
for i in 0..<iuvRow
{
for j in 0..<(iHalfWidth)
{
// UV data for original frame. Just interleave them.
uvDataIndex = i*iHalfWidth+j
uIndex = (i*yuvFrame.width) + (j*2)
vIndex = uIndex + 1
uvData[uIndex] = pUPointer[uvDataIndex]
uvData[vIndex] = pVPointer[uvDataIndex]
}
}
}
CVPixelBufferUnlockBaseAddress(pixelBuffer!, 0)
}
return pixelBuffer
}
注意:yuvFrame是一个结构体,有y、u、v平面缓冲区和宽高。另外,我有 CFDictionary 吗? CVPixelBufferCreate(...) 中的参数设置为 nil。如果我给它 IOSurface 属性,它会失败并抱怨它不是 IOSurface 支持或错误 -6683.
访问这些 link 了解更多信息: link 是关于 UV 交错的: How to convert from YUV to CIImage for iOS
及相关问题:CVOpenGLESTextureCacheCreateTextureFromImage returns error 6683
这里是 obj-c 中的完整转换。 还有所有那些说:“这是微不足道的”的天才,不要光顾任何人!如果你是来帮忙的,帮忙,如果你来这里是为了展示你有多“聪明”,那就去别的地方吧。 这里是link对YUV处理的详细解释:www.glebsoft.com
/// method to convert YUV buffers to pixelBuffer in otder to feed it to face unity methods
-(CVPixelBufferRef*)pixelBufferFromYUV:(uint8_t *)yBuffer vBuffer:(uint8_t *)uBuffer uBuffer:(uint8_t *)vBuffer width:(int)width height:(int)height {
NSDictionary *pixelAttributes = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{}};
CVPixelBufferRef pixelBuffer;
/// NumberOfElementsForChroma is width*height/4 because both U plane and V plane are quarter size of Y plane
CGFloat uPlaneSize = width * height / 4;
CGFloat vPlaneSize = width * height / 4;
CGFloat numberOfElementsForChroma = uPlaneSize + vPlaneSize;
CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault,
width,
height,
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
(__bridge CFDictionaryRef)(pixelAttributes),
&pixelBuffer);
///for simplicity and speed create a combined UV panel to hold the pixels
uint8_t *uvPlane = calloc(numberOfElementsForChroma, sizeof(uint8_t));
memcpy(uvPlane, uBuffer, uPlaneSize);
memcpy(uvPlane += (uint8_t)(uPlaneSize), vBuffer, vPlaneSize);
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
uint8_t *yDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
memcpy(yDestPlane, yBuffer, width * height);
uint8_t *uvDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
memcpy(uvDestPlane, uvPlane, numberOfElementsForChroma);
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
CVPixelBufferRelease(pixelBuffer);
free(uvPlane);
return pixelBuffer;
}