1/* 2 * Copyright 2018 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "sdk/objc/unittests/frame_buffer_helpers.h" 12 13#include "third_party/libyuv/include/libyuv.h" 14 15void DrawGradientInRGBPixelBuffer(CVPixelBufferRef pixelBuffer) { 16 CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly); 17 void* baseAddr = CVPixelBufferGetBaseAddress(pixelBuffer); 18 size_t width = CVPixelBufferGetWidth(pixelBuffer); 19 size_t height = CVPixelBufferGetHeight(pixelBuffer); 20 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 21 int byteOrder = CVPixelBufferGetPixelFormatType(pixelBuffer) == kCVPixelFormatType_32ARGB ? 22 kCGBitmapByteOrder32Little : 23 0; 24 CGContextRef cgContext = CGBitmapContextCreate(baseAddr, 25 width, 26 height, 27 8, 28 CVPixelBufferGetBytesPerRow(pixelBuffer), 29 colorSpace, 30 byteOrder | kCGImageAlphaNoneSkipLast); 31 32 // Create a gradient 33 CGFloat colors[] = { 34 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, 35 }; 36 CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 4); 37 38 CGContextDrawLinearGradient( 39 cgContext, gradient, CGPointMake(0, 0), CGPointMake(width, height), 0); 40 CGGradientRelease(gradient); 41 42 CGImageRef cgImage = CGBitmapContextCreateImage(cgContext); 43 CGContextRelease(cgContext); 44 CGImageRelease(cgImage); 45 CGColorSpaceRelease(colorSpace); 46 47 CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly); 48} 49 50rtc::scoped_refptr<webrtc::I420Buffer> CreateI420Gradient(int width, int height) { 51 rtc::scoped_refptr<webrtc::I420Buffer> buffer(webrtc::I420Buffer::Create(width, height)); 52 // Initialize with gradient, Y = 128(x/w + y/h), U = 256 x/w, V = 256 y/h 53 for (int x = 0; x < width; x++) { 54 for (int y = 0; y < height; y++) { 55 buffer->MutableDataY()[x + y * width] = 128 * (x * height + y * width) / (width * height); 56 } 57 } 58 int chroma_width = buffer->ChromaWidth(); 59 int chroma_height = buffer->ChromaHeight(); 60 for (int x = 0; x < chroma_width; x++) { 61 for (int y = 0; y < chroma_height; y++) { 62 buffer->MutableDataU()[x + y * chroma_width] = 255 * x / (chroma_width - 1); 63 buffer->MutableDataV()[x + y * chroma_width] = 255 * y / (chroma_height - 1); 64 } 65 } 66 return buffer; 67} 68 69void CopyI420BufferToCVPixelBuffer(rtc::scoped_refptr<webrtc::I420Buffer> i420Buffer, 70 CVPixelBufferRef pixelBuffer) { 71 CVPixelBufferLockBaseAddress(pixelBuffer, 0); 72 73 const OSType pixelFormat = CVPixelBufferGetPixelFormatType(pixelBuffer); 74 if (pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange || 75 pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) { 76 // NV12 77 uint8_t* dstY = static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)); 78 const int dstYStride = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0); 79 uint8_t* dstUV = static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1)); 80 const int dstUVStride = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1); 81 82 libyuv::I420ToNV12(i420Buffer->DataY(), 83 i420Buffer->StrideY(), 84 i420Buffer->DataU(), 85 i420Buffer->StrideU(), 86 i420Buffer->DataV(), 87 i420Buffer->StrideV(), 88 dstY, 89 dstYStride, 90 dstUV, 91 dstUVStride, 92 i420Buffer->width(), 93 i420Buffer->height()); 94 } else { 95 uint8_t* dst = static_cast<uint8_t*>(CVPixelBufferGetBaseAddress(pixelBuffer)); 96 const int bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer); 97 98 if (pixelFormat == kCVPixelFormatType_32BGRA) { 99 // Corresponds to libyuv::FOURCC_ARGB 100 libyuv::I420ToARGB(i420Buffer->DataY(), 101 i420Buffer->StrideY(), 102 i420Buffer->DataU(), 103 i420Buffer->StrideU(), 104 i420Buffer->DataV(), 105 i420Buffer->StrideV(), 106 dst, 107 bytesPerRow, 108 i420Buffer->width(), 109 i420Buffer->height()); 110 } else if (pixelFormat == kCVPixelFormatType_32ARGB) { 111 // Corresponds to libyuv::FOURCC_BGRA 112 libyuv::I420ToBGRA(i420Buffer->DataY(), 113 i420Buffer->StrideY(), 114 i420Buffer->DataU(), 115 i420Buffer->StrideU(), 116 i420Buffer->DataV(), 117 i420Buffer->StrideV(), 118 dst, 119 bytesPerRow, 120 i420Buffer->width(), 121 i420Buffer->height()); 122 } 123 } 124 125 CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); 126} 127