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