| /* |
| * Copyright 2018 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "sdk/objc/Framework/UnitTests/frame_buffer_helpers.h" |
| |
| #include "third_party/libyuv/include/libyuv.h" |
| |
| void DrawGradientInRGBPixelBuffer(CVPixelBufferRef pixelBuffer) { |
| CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly); |
| void* baseAddr = CVPixelBufferGetBaseAddress(pixelBuffer); |
| size_t width = CVPixelBufferGetWidth(pixelBuffer); |
| size_t height = CVPixelBufferGetHeight(pixelBuffer); |
| CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); |
| int byteOrder = CVPixelBufferGetPixelFormatType(pixelBuffer) == kCVPixelFormatType_32ARGB ? |
| kCGBitmapByteOrder32Little : |
| 0; |
| CGContextRef cgContext = CGBitmapContextCreate(baseAddr, |
| width, |
| height, |
| 8, |
| CVPixelBufferGetBytesPerRow(pixelBuffer), |
| colorSpace, |
| byteOrder | kCGImageAlphaNoneSkipLast); |
| |
| // Create a gradient |
| CGFloat colors[] = { |
| 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, |
| }; |
| CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 4); |
| |
| CGContextDrawLinearGradient( |
| cgContext, gradient, CGPointMake(0, 0), CGPointMake(width, height), 0); |
| CGGradientRelease(gradient); |
| |
| CGImageRef cgImage = CGBitmapContextCreateImage(cgContext); |
| CGContextRelease(cgContext); |
| CGImageRelease(cgImage); |
| CGColorSpaceRelease(colorSpace); |
| |
| CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly); |
| } |
| |
| rtc::scoped_refptr<webrtc::I420Buffer> CreateI420Gradient(int width, int height) { |
| rtc::scoped_refptr<webrtc::I420Buffer> buffer(webrtc::I420Buffer::Create(width, height)); |
| // Initialize with gradient, Y = 128(x/w + y/h), U = 256 x/w, V = 256 y/h |
| for (int x = 0; x < width; x++) { |
| for (int y = 0; y < height; y++) { |
| buffer->MutableDataY()[x + y * width] = 128 * (x * height + y * width) / (width * height); |
| } |
| } |
| int chroma_width = buffer->ChromaWidth(); |
| int chroma_height = buffer->ChromaHeight(); |
| for (int x = 0; x < chroma_width; x++) { |
| for (int y = 0; y < chroma_height; y++) { |
| buffer->MutableDataU()[x + y * chroma_width] = 255 * x / (chroma_width - 1); |
| buffer->MutableDataV()[x + y * chroma_width] = 255 * y / (chroma_height - 1); |
| } |
| } |
| return buffer; |
| } |
| |
| void CopyI420BufferToCVPixelBuffer(rtc::scoped_refptr<webrtc::I420Buffer> i420Buffer, |
| CVPixelBufferRef pixelBuffer) { |
| CVPixelBufferLockBaseAddress(pixelBuffer, 0); |
| |
| const OSType pixelFormat = CVPixelBufferGetPixelFormatType(pixelBuffer); |
| if (pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange || |
| pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) { |
| // NV12 |
| uint8_t* dstY = static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)); |
| const int dstYStride = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0); |
| uint8_t* dstUV = static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1)); |
| const int dstUVStride = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1); |
| |
| libyuv::I420ToNV12(i420Buffer->DataY(), |
| i420Buffer->StrideY(), |
| i420Buffer->DataU(), |
| i420Buffer->StrideU(), |
| i420Buffer->DataV(), |
| i420Buffer->StrideV(), |
| dstY, |
| dstYStride, |
| dstUV, |
| dstUVStride, |
| i420Buffer->width(), |
| i420Buffer->height()); |
| } else { |
| uint8_t* dst = static_cast<uint8_t*>(CVPixelBufferGetBaseAddress(pixelBuffer)); |
| const int bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer); |
| |
| if (pixelFormat == kCVPixelFormatType_32BGRA) { |
| // Corresponds to libyuv::FOURCC_ARGB |
| libyuv::I420ToARGB(i420Buffer->DataY(), |
| i420Buffer->StrideY(), |
| i420Buffer->DataU(), |
| i420Buffer->StrideU(), |
| i420Buffer->DataV(), |
| i420Buffer->StrideV(), |
| dst, |
| bytesPerRow, |
| i420Buffer->width(), |
| i420Buffer->height()); |
| } else if (pixelFormat == kCVPixelFormatType_32ARGB) { |
| // Corresponds to libyuv::FOURCC_BGRA |
| libyuv::I420ToBGRA(i420Buffer->DataY(), |
| i420Buffer->StrideY(), |
| i420Buffer->DataU(), |
| i420Buffer->StrideU(), |
| i420Buffer->DataV(), |
| i420Buffer->StrideV(), |
| dst, |
| bytesPerRow, |
| i420Buffer->width(), |
| i420Buffer->height()); |
| } |
| } |
| |
| CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); |
| } |