/* * 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/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 CreateI420Gradient(int width, int height) { rtc::scoped_refptr 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 i420Buffer, CVPixelBufferRef pixelBuffer) { CVPixelBufferLockBaseAddress(pixelBuffer, 0); const OSType pixelFormat = CVPixelBufferGetPixelFormatType(pixelBuffer); if (pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange || pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) { // NV12 uint8_t* dstY = static_cast(CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)); const int dstYStride = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0); uint8_t* dstUV = static_cast(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(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); }