xref: /aosp_15_r20/external/webrtc/sdk/objc/unittests/RTCCVPixelBuffer_xctest.mm (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker/*
2*d9f75844SAndroid Build Coastguard Worker *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker#import <Foundation/Foundation.h>
12*d9f75844SAndroid Build Coastguard Worker#import <XCTest/XCTest.h>
13*d9f75844SAndroid Build Coastguard Worker
14*d9f75844SAndroid Build Coastguard Worker#import "components/video_frame_buffer/RTCCVPixelBuffer.h"
15*d9f75844SAndroid Build Coastguard Worker
16*d9f75844SAndroid Build Coastguard Worker#import "api/video_frame_buffer/RTCNativeI420Buffer+Private.h"
17*d9f75844SAndroid Build Coastguard Worker#import "base/RTCVideoFrame.h"
18*d9f75844SAndroid Build Coastguard Worker#import "base/RTCVideoFrameBuffer.h"
19*d9f75844SAndroid Build Coastguard Worker#import "frame_buffer_helpers.h"
20*d9f75844SAndroid Build Coastguard Worker
21*d9f75844SAndroid Build Coastguard Worker#include "common_video/libyuv/include/webrtc_libyuv.h"
22*d9f75844SAndroid Build Coastguard Worker#include "third_party/libyuv/include/libyuv.h"
23*d9f75844SAndroid Build Coastguard Worker
24*d9f75844SAndroid Build Coastguard Workernamespace {
25*d9f75844SAndroid Build Coastguard Worker
26*d9f75844SAndroid Build Coastguard Workerstruct ToI420WithCropAndScaleSetting {
27*d9f75844SAndroid Build Coastguard Worker  int inputWidth;
28*d9f75844SAndroid Build Coastguard Worker  int inputHeight;
29*d9f75844SAndroid Build Coastguard Worker  int offsetX;
30*d9f75844SAndroid Build Coastguard Worker  int offsetY;
31*d9f75844SAndroid Build Coastguard Worker  int cropWidth;
32*d9f75844SAndroid Build Coastguard Worker  int cropHeight;
33*d9f75844SAndroid Build Coastguard Worker  int scaleWidth;
34*d9f75844SAndroid Build Coastguard Worker  int scaleHeight;
35*d9f75844SAndroid Build Coastguard Worker};
36*d9f75844SAndroid Build Coastguard Worker
37*d9f75844SAndroid Build Coastguard Workerconstexpr const ToI420WithCropAndScaleSetting kToI420WithCropAndScaleSettings[] = {
38*d9f75844SAndroid Build Coastguard Worker    ToI420WithCropAndScaleSetting{
39*d9f75844SAndroid Build Coastguard Worker        .inputWidth = 640,
40*d9f75844SAndroid Build Coastguard Worker        .inputHeight = 360,
41*d9f75844SAndroid Build Coastguard Worker        .offsetX = 0,
42*d9f75844SAndroid Build Coastguard Worker        .offsetY = 0,
43*d9f75844SAndroid Build Coastguard Worker        .cropWidth = 640,
44*d9f75844SAndroid Build Coastguard Worker        .cropHeight = 360,
45*d9f75844SAndroid Build Coastguard Worker        .scaleWidth = 320,
46*d9f75844SAndroid Build Coastguard Worker        .scaleHeight = 180,
47*d9f75844SAndroid Build Coastguard Worker    },
48*d9f75844SAndroid Build Coastguard Worker    ToI420WithCropAndScaleSetting{
49*d9f75844SAndroid Build Coastguard Worker        .inputWidth = 640,
50*d9f75844SAndroid Build Coastguard Worker        .inputHeight = 360,
51*d9f75844SAndroid Build Coastguard Worker        .offsetX = 160,
52*d9f75844SAndroid Build Coastguard Worker        .offsetY = 90,
53*d9f75844SAndroid Build Coastguard Worker        .cropWidth = 160,
54*d9f75844SAndroid Build Coastguard Worker        .cropHeight = 90,
55*d9f75844SAndroid Build Coastguard Worker        .scaleWidth = 320,
56*d9f75844SAndroid Build Coastguard Worker        .scaleHeight = 180,
57*d9f75844SAndroid Build Coastguard Worker    },
58*d9f75844SAndroid Build Coastguard Worker};
59*d9f75844SAndroid Build Coastguard Worker
60*d9f75844SAndroid Build Coastguard Worker}  // namespace
61*d9f75844SAndroid Build Coastguard Worker
62*d9f75844SAndroid Build Coastguard Worker@interface RTCCVPixelBufferTests : XCTestCase
63*d9f75844SAndroid Build Coastguard Worker@end
64*d9f75844SAndroid Build Coastguard Worker
65*d9f75844SAndroid Build Coastguard Worker@implementation RTCCVPixelBufferTests {
66*d9f75844SAndroid Build Coastguard Worker}
67*d9f75844SAndroid Build Coastguard Worker
68*d9f75844SAndroid Build Coastguard Worker- (void)testRequiresCroppingNoCrop {
69*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferRef pixelBufferRef = NULL;
70*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferCreate(
71*d9f75844SAndroid Build Coastguard Worker      NULL, 720, 1280, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, NULL, &pixelBufferRef);
72*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *buffer =
73*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:pixelBufferRef];
74*d9f75844SAndroid Build Coastguard Worker
75*d9f75844SAndroid Build Coastguard Worker  XCTAssertFalse([buffer requiresCropping]);
76*d9f75844SAndroid Build Coastguard Worker
77*d9f75844SAndroid Build Coastguard Worker  CVBufferRelease(pixelBufferRef);
78*d9f75844SAndroid Build Coastguard Worker}
79*d9f75844SAndroid Build Coastguard Worker
80*d9f75844SAndroid Build Coastguard Worker- (void)testRequiresCroppingWithCrop {
81*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferRef pixelBufferRef = NULL;
82*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferCreate(
83*d9f75844SAndroid Build Coastguard Worker      NULL, 720, 1280, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, NULL, &pixelBufferRef);
84*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *croppedBuffer =
85*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:pixelBufferRef
86*d9f75844SAndroid Build Coastguard Worker                                                      adaptedWidth:720
87*d9f75844SAndroid Build Coastguard Worker                                                     adaptedHeight:1280
88*d9f75844SAndroid Build Coastguard Worker                                                         cropWidth:360
89*d9f75844SAndroid Build Coastguard Worker                                                        cropHeight:640
90*d9f75844SAndroid Build Coastguard Worker                                                             cropX:100
91*d9f75844SAndroid Build Coastguard Worker                                                             cropY:100];
92*d9f75844SAndroid Build Coastguard Worker
93*d9f75844SAndroid Build Coastguard Worker  XCTAssertTrue([croppedBuffer requiresCropping]);
94*d9f75844SAndroid Build Coastguard Worker
95*d9f75844SAndroid Build Coastguard Worker  CVBufferRelease(pixelBufferRef);
96*d9f75844SAndroid Build Coastguard Worker}
97*d9f75844SAndroid Build Coastguard Worker
98*d9f75844SAndroid Build Coastguard Worker- (void)testRequiresScalingNoScale {
99*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferRef pixelBufferRef = NULL;
100*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferCreate(
101*d9f75844SAndroid Build Coastguard Worker      NULL, 720, 1280, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, NULL, &pixelBufferRef);
102*d9f75844SAndroid Build Coastguard Worker
103*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *buffer =
104*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:pixelBufferRef];
105*d9f75844SAndroid Build Coastguard Worker  XCTAssertFalse([buffer requiresScalingToWidth:720 height:1280]);
106*d9f75844SAndroid Build Coastguard Worker
107*d9f75844SAndroid Build Coastguard Worker  CVBufferRelease(pixelBufferRef);
108*d9f75844SAndroid Build Coastguard Worker}
109*d9f75844SAndroid Build Coastguard Worker
110*d9f75844SAndroid Build Coastguard Worker- (void)testRequiresScalingWithScale {
111*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferRef pixelBufferRef = NULL;
112*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferCreate(
113*d9f75844SAndroid Build Coastguard Worker      NULL, 720, 1280, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, NULL, &pixelBufferRef);
114*d9f75844SAndroid Build Coastguard Worker
115*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *buffer =
116*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:pixelBufferRef];
117*d9f75844SAndroid Build Coastguard Worker  XCTAssertTrue([buffer requiresScalingToWidth:360 height:640]);
118*d9f75844SAndroid Build Coastguard Worker
119*d9f75844SAndroid Build Coastguard Worker  CVBufferRelease(pixelBufferRef);
120*d9f75844SAndroid Build Coastguard Worker}
121*d9f75844SAndroid Build Coastguard Worker
122*d9f75844SAndroid Build Coastguard Worker- (void)testRequiresScalingWithScaleAndMatchingCrop {
123*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferRef pixelBufferRef = NULL;
124*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferCreate(
125*d9f75844SAndroid Build Coastguard Worker      NULL, 720, 1280, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, NULL, &pixelBufferRef);
126*d9f75844SAndroid Build Coastguard Worker
127*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *buffer =
128*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:pixelBufferRef
129*d9f75844SAndroid Build Coastguard Worker                                                      adaptedWidth:720
130*d9f75844SAndroid Build Coastguard Worker                                                     adaptedHeight:1280
131*d9f75844SAndroid Build Coastguard Worker                                                         cropWidth:360
132*d9f75844SAndroid Build Coastguard Worker                                                        cropHeight:640
133*d9f75844SAndroid Build Coastguard Worker                                                             cropX:100
134*d9f75844SAndroid Build Coastguard Worker                                                             cropY:100];
135*d9f75844SAndroid Build Coastguard Worker  XCTAssertFalse([buffer requiresScalingToWidth:360 height:640]);
136*d9f75844SAndroid Build Coastguard Worker
137*d9f75844SAndroid Build Coastguard Worker  CVBufferRelease(pixelBufferRef);
138*d9f75844SAndroid Build Coastguard Worker}
139*d9f75844SAndroid Build Coastguard Worker
140*d9f75844SAndroid Build Coastguard Worker- (void)testBufferSize_NV12 {
141*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferRef pixelBufferRef = NULL;
142*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferCreate(
143*d9f75844SAndroid Build Coastguard Worker      NULL, 720, 1280, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, NULL, &pixelBufferRef);
144*d9f75844SAndroid Build Coastguard Worker
145*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *buffer =
146*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:pixelBufferRef];
147*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual([buffer bufferSizeForCroppingAndScalingToWidth:360 height:640], 576000);
148*d9f75844SAndroid Build Coastguard Worker
149*d9f75844SAndroid Build Coastguard Worker  CVBufferRelease(pixelBufferRef);
150*d9f75844SAndroid Build Coastguard Worker}
151*d9f75844SAndroid Build Coastguard Worker
152*d9f75844SAndroid Build Coastguard Worker- (void)testBufferSize_RGB {
153*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferRef pixelBufferRef = NULL;
154*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferCreate(NULL, 720, 1280, kCVPixelFormatType_32BGRA, NULL, &pixelBufferRef);
155*d9f75844SAndroid Build Coastguard Worker
156*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *buffer =
157*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:pixelBufferRef];
158*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual([buffer bufferSizeForCroppingAndScalingToWidth:360 height:640], 0);
159*d9f75844SAndroid Build Coastguard Worker
160*d9f75844SAndroid Build Coastguard Worker  CVBufferRelease(pixelBufferRef);
161*d9f75844SAndroid Build Coastguard Worker}
162*d9f75844SAndroid Build Coastguard Worker
163*d9f75844SAndroid Build Coastguard Worker- (void)testCropAndScale_NV12 {
164*d9f75844SAndroid Build Coastguard Worker  [self cropAndScaleTestWithNV12];
165*d9f75844SAndroid Build Coastguard Worker}
166*d9f75844SAndroid Build Coastguard Worker
167*d9f75844SAndroid Build Coastguard Worker- (void)testCropAndScaleNoOp_NV12 {
168*d9f75844SAndroid Build Coastguard Worker  [self cropAndScaleTestWithNV12InputFormat:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
169*d9f75844SAndroid Build Coastguard Worker                               outputFormat:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
170*d9f75844SAndroid Build Coastguard Worker                                 outputSize:CGSizeMake(720, 1280)];
171*d9f75844SAndroid Build Coastguard Worker}
172*d9f75844SAndroid Build Coastguard Worker
173*d9f75844SAndroid Build Coastguard Worker- (void)testCropAndScale_NV12FullToVideo {
174*d9f75844SAndroid Build Coastguard Worker  [self cropAndScaleTestWithNV12InputFormat:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
175*d9f75844SAndroid Build Coastguard Worker                               outputFormat:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange];
176*d9f75844SAndroid Build Coastguard Worker}
177*d9f75844SAndroid Build Coastguard Worker
178*d9f75844SAndroid Build Coastguard Worker- (void)testCropAndScaleZeroSizeFrame_NV12 {
179*d9f75844SAndroid Build Coastguard Worker  [self cropAndScaleTestWithNV12InputFormat:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
180*d9f75844SAndroid Build Coastguard Worker                               outputFormat:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
181*d9f75844SAndroid Build Coastguard Worker                                 outputSize:CGSizeMake(0, 0)];
182*d9f75844SAndroid Build Coastguard Worker}
183*d9f75844SAndroid Build Coastguard Worker
184*d9f75844SAndroid Build Coastguard Worker- (void)testCropAndScaleToSmallFormat_NV12 {
185*d9f75844SAndroid Build Coastguard Worker  [self cropAndScaleTestWithNV12InputFormat:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
186*d9f75844SAndroid Build Coastguard Worker                               outputFormat:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
187*d9f75844SAndroid Build Coastguard Worker                                 outputSize:CGSizeMake(148, 320)];
188*d9f75844SAndroid Build Coastguard Worker}
189*d9f75844SAndroid Build Coastguard Worker
190*d9f75844SAndroid Build Coastguard Worker- (void)testCropAndScaleToOddFormat_NV12 {
191*d9f75844SAndroid Build Coastguard Worker  [self cropAndScaleTestWithNV12InputFormat:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
192*d9f75844SAndroid Build Coastguard Worker                               outputFormat:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
193*d9f75844SAndroid Build Coastguard Worker                                 outputSize:CGSizeMake(361, 640)];
194*d9f75844SAndroid Build Coastguard Worker}
195*d9f75844SAndroid Build Coastguard Worker
196*d9f75844SAndroid Build Coastguard Worker- (void)testCropAndScale_32BGRA {
197*d9f75844SAndroid Build Coastguard Worker  [self cropAndScaleTestWithRGBPixelFormat:kCVPixelFormatType_32BGRA];
198*d9f75844SAndroid Build Coastguard Worker}
199*d9f75844SAndroid Build Coastguard Worker
200*d9f75844SAndroid Build Coastguard Worker- (void)testCropAndScale_32ARGB {
201*d9f75844SAndroid Build Coastguard Worker  [self cropAndScaleTestWithRGBPixelFormat:kCVPixelFormatType_32ARGB];
202*d9f75844SAndroid Build Coastguard Worker}
203*d9f75844SAndroid Build Coastguard Worker
204*d9f75844SAndroid Build Coastguard Worker- (void)testCropAndScaleWithSmallCropInfo_32ARGB {
205*d9f75844SAndroid Build Coastguard Worker  [self cropAndScaleTestWithRGBPixelFormat:kCVPixelFormatType_32ARGB cropX:2 cropY:3];
206*d9f75844SAndroid Build Coastguard Worker}
207*d9f75844SAndroid Build Coastguard Worker
208*d9f75844SAndroid Build Coastguard Worker- (void)testCropAndScaleWithLargeCropInfo_32ARGB {
209*d9f75844SAndroid Build Coastguard Worker  [self cropAndScaleTestWithRGBPixelFormat:kCVPixelFormatType_32ARGB cropX:200 cropY:300];
210*d9f75844SAndroid Build Coastguard Worker}
211*d9f75844SAndroid Build Coastguard Worker
212*d9f75844SAndroid Build Coastguard Worker- (void)testToI420_NV12 {
213*d9f75844SAndroid Build Coastguard Worker  [self toI420WithPixelFormat:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange];
214*d9f75844SAndroid Build Coastguard Worker}
215*d9f75844SAndroid Build Coastguard Worker
216*d9f75844SAndroid Build Coastguard Worker- (void)testToI420_32BGRA {
217*d9f75844SAndroid Build Coastguard Worker  [self toI420WithPixelFormat:kCVPixelFormatType_32BGRA];
218*d9f75844SAndroid Build Coastguard Worker}
219*d9f75844SAndroid Build Coastguard Worker
220*d9f75844SAndroid Build Coastguard Worker- (void)testToI420_32ARGB {
221*d9f75844SAndroid Build Coastguard Worker  [self toI420WithPixelFormat:kCVPixelFormatType_32ARGB];
222*d9f75844SAndroid Build Coastguard Worker}
223*d9f75844SAndroid Build Coastguard Worker
224*d9f75844SAndroid Build Coastguard Worker- (void)testToI420WithCropAndScale_NV12 {
225*d9f75844SAndroid Build Coastguard Worker  for (const auto &setting : kToI420WithCropAndScaleSettings) {
226*d9f75844SAndroid Build Coastguard Worker    [self toI420WithCropAndScaleWithPixelFormat:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
227*d9f75844SAndroid Build Coastguard Worker                                        setting:setting];
228*d9f75844SAndroid Build Coastguard Worker  }
229*d9f75844SAndroid Build Coastguard Worker}
230*d9f75844SAndroid Build Coastguard Worker
231*d9f75844SAndroid Build Coastguard Worker- (void)testToI420WithCropAndScale_32BGRA {
232*d9f75844SAndroid Build Coastguard Worker  for (const auto &setting : kToI420WithCropAndScaleSettings) {
233*d9f75844SAndroid Build Coastguard Worker    [self toI420WithCropAndScaleWithPixelFormat:kCVPixelFormatType_32BGRA setting:setting];
234*d9f75844SAndroid Build Coastguard Worker  }
235*d9f75844SAndroid Build Coastguard Worker}
236*d9f75844SAndroid Build Coastguard Worker
237*d9f75844SAndroid Build Coastguard Worker- (void)testToI420WithCropAndScale_32ARGB {
238*d9f75844SAndroid Build Coastguard Worker  for (const auto &setting : kToI420WithCropAndScaleSettings) {
239*d9f75844SAndroid Build Coastguard Worker    [self toI420WithCropAndScaleWithPixelFormat:kCVPixelFormatType_32ARGB setting:setting];
240*d9f75844SAndroid Build Coastguard Worker  }
241*d9f75844SAndroid Build Coastguard Worker}
242*d9f75844SAndroid Build Coastguard Worker
243*d9f75844SAndroid Build Coastguard Worker- (void)testScaleBufferTest {
244*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferRef pixelBufferRef = NULL;
245*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferCreate(
246*d9f75844SAndroid Build Coastguard Worker      NULL, 1920, 1080, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, NULL, &pixelBufferRef);
247*d9f75844SAndroid Build Coastguard Worker
248*d9f75844SAndroid Build Coastguard Worker  rtc::scoped_refptr<webrtc::I420Buffer> i420Buffer = CreateI420Gradient(1920, 1080);
249*d9f75844SAndroid Build Coastguard Worker  CopyI420BufferToCVPixelBuffer(i420Buffer, pixelBufferRef);
250*d9f75844SAndroid Build Coastguard Worker
251*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *buffer =
252*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:pixelBufferRef];
253*d9f75844SAndroid Build Coastguard Worker
254*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer.width, 1920);
255*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer.height, 1080);
256*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer.cropX, 0);
257*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer.cropY, 0);
258*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer.cropWidth, 1920);
259*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer.cropHeight, 1080);
260*d9f75844SAndroid Build Coastguard Worker
261*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *buffer2 =
262*d9f75844SAndroid Build Coastguard Worker      (RTC_OBJC_TYPE(RTCCVPixelBuffer) *)[buffer cropAndScaleWith:320
263*d9f75844SAndroid Build Coastguard Worker                                                          offsetY:180
264*d9f75844SAndroid Build Coastguard Worker                                                        cropWidth:1280
265*d9f75844SAndroid Build Coastguard Worker                                                       cropHeight:720
266*d9f75844SAndroid Build Coastguard Worker                                                       scaleWidth:960
267*d9f75844SAndroid Build Coastguard Worker                                                      scaleHeight:540];
268*d9f75844SAndroid Build Coastguard Worker
269*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer2.width, 960);
270*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer2.height, 540);
271*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer2.cropX, 320);
272*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer2.cropY, 180);
273*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer2.cropWidth, 1280);
274*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer2.cropHeight, 720);
275*d9f75844SAndroid Build Coastguard Worker
276*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *buffer3 =
277*d9f75844SAndroid Build Coastguard Worker      (RTC_OBJC_TYPE(RTCCVPixelBuffer) *)[buffer2 cropAndScaleWith:240
278*d9f75844SAndroid Build Coastguard Worker                                                           offsetY:135
279*d9f75844SAndroid Build Coastguard Worker                                                         cropWidth:480
280*d9f75844SAndroid Build Coastguard Worker                                                        cropHeight:270
281*d9f75844SAndroid Build Coastguard Worker                                                        scaleWidth:320
282*d9f75844SAndroid Build Coastguard Worker                                                       scaleHeight:180];
283*d9f75844SAndroid Build Coastguard Worker
284*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer3.width, 320);
285*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer3.height, 180);
286*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer3.cropX, 640);
287*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer3.cropY, 360);
288*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer3.cropWidth, 640);
289*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer3.cropHeight, 360);
290*d9f75844SAndroid Build Coastguard Worker
291*d9f75844SAndroid Build Coastguard Worker  CVBufferRelease(pixelBufferRef);
292*d9f75844SAndroid Build Coastguard Worker}
293*d9f75844SAndroid Build Coastguard Worker
294*d9f75844SAndroid Build Coastguard Worker#pragma mark - Shared test code
295*d9f75844SAndroid Build Coastguard Worker
296*d9f75844SAndroid Build Coastguard Worker- (void)cropAndScaleTestWithNV12 {
297*d9f75844SAndroid Build Coastguard Worker  [self cropAndScaleTestWithNV12InputFormat:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
298*d9f75844SAndroid Build Coastguard Worker                               outputFormat:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange];
299*d9f75844SAndroid Build Coastguard Worker}
300*d9f75844SAndroid Build Coastguard Worker
301*d9f75844SAndroid Build Coastguard Worker- (void)cropAndScaleTestWithNV12InputFormat:(OSType)inputFormat outputFormat:(OSType)outputFormat {
302*d9f75844SAndroid Build Coastguard Worker  [self cropAndScaleTestWithNV12InputFormat:(OSType)inputFormat
303*d9f75844SAndroid Build Coastguard Worker                               outputFormat:(OSType)outputFormat
304*d9f75844SAndroid Build Coastguard Worker                                 outputSize:CGSizeMake(360, 640)];
305*d9f75844SAndroid Build Coastguard Worker}
306*d9f75844SAndroid Build Coastguard Worker
307*d9f75844SAndroid Build Coastguard Worker- (void)cropAndScaleTestWithNV12InputFormat:(OSType)inputFormat
308*d9f75844SAndroid Build Coastguard Worker                               outputFormat:(OSType)outputFormat
309*d9f75844SAndroid Build Coastguard Worker                                 outputSize:(CGSize)outputSize {
310*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferRef pixelBufferRef = NULL;
311*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferCreate(NULL, 720, 1280, inputFormat, NULL, &pixelBufferRef);
312*d9f75844SAndroid Build Coastguard Worker
313*d9f75844SAndroid Build Coastguard Worker  rtc::scoped_refptr<webrtc::I420Buffer> i420Buffer = CreateI420Gradient(720, 1280);
314*d9f75844SAndroid Build Coastguard Worker  CopyI420BufferToCVPixelBuffer(i420Buffer, pixelBufferRef);
315*d9f75844SAndroid Build Coastguard Worker
316*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *buffer =
317*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:pixelBufferRef];
318*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer.width, 720);
319*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer.height, 1280);
320*d9f75844SAndroid Build Coastguard Worker
321*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferRef outputPixelBufferRef = NULL;
322*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferCreate(
323*d9f75844SAndroid Build Coastguard Worker      NULL, outputSize.width, outputSize.height, outputFormat, NULL, &outputPixelBufferRef);
324*d9f75844SAndroid Build Coastguard Worker
325*d9f75844SAndroid Build Coastguard Worker  std::vector<uint8_t> frameScaleBuffer;
326*d9f75844SAndroid Build Coastguard Worker  if ([buffer requiresScalingToWidth:outputSize.width height:outputSize.height]) {
327*d9f75844SAndroid Build Coastguard Worker    int size =
328*d9f75844SAndroid Build Coastguard Worker        [buffer bufferSizeForCroppingAndScalingToWidth:outputSize.width height:outputSize.height];
329*d9f75844SAndroid Build Coastguard Worker    frameScaleBuffer.resize(size);
330*d9f75844SAndroid Build Coastguard Worker  } else {
331*d9f75844SAndroid Build Coastguard Worker    frameScaleBuffer.clear();
332*d9f75844SAndroid Build Coastguard Worker  }
333*d9f75844SAndroid Build Coastguard Worker  frameScaleBuffer.shrink_to_fit();
334*d9f75844SAndroid Build Coastguard Worker
335*d9f75844SAndroid Build Coastguard Worker  [buffer cropAndScaleTo:outputPixelBufferRef withTempBuffer:frameScaleBuffer.data()];
336*d9f75844SAndroid Build Coastguard Worker
337*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *scaledBuffer =
338*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:outputPixelBufferRef];
339*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(scaledBuffer.width, outputSize.width);
340*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(scaledBuffer.height, outputSize.height);
341*d9f75844SAndroid Build Coastguard Worker
342*d9f75844SAndroid Build Coastguard Worker  if (outputSize.width > 0 && outputSize.height > 0) {
343*d9f75844SAndroid Build Coastguard Worker    RTC_OBJC_TYPE(RTCI420Buffer) *originalBufferI420 = [buffer toI420];
344*d9f75844SAndroid Build Coastguard Worker    RTC_OBJC_TYPE(RTCI420Buffer) *scaledBufferI420 = [scaledBuffer toI420];
345*d9f75844SAndroid Build Coastguard Worker    double psnr =
346*d9f75844SAndroid Build Coastguard Worker        I420PSNR(*[originalBufferI420 nativeI420Buffer], *[scaledBufferI420 nativeI420Buffer]);
347*d9f75844SAndroid Build Coastguard Worker    XCTAssertEqual(psnr, webrtc::kPerfectPSNR);
348*d9f75844SAndroid Build Coastguard Worker  }
349*d9f75844SAndroid Build Coastguard Worker
350*d9f75844SAndroid Build Coastguard Worker  CVBufferRelease(pixelBufferRef);
351*d9f75844SAndroid Build Coastguard Worker}
352*d9f75844SAndroid Build Coastguard Worker
353*d9f75844SAndroid Build Coastguard Worker- (void)cropAndScaleTestWithRGBPixelFormat:(OSType)pixelFormat {
354*d9f75844SAndroid Build Coastguard Worker  [self cropAndScaleTestWithRGBPixelFormat:pixelFormat cropX:0 cropY:0];
355*d9f75844SAndroid Build Coastguard Worker}
356*d9f75844SAndroid Build Coastguard Worker
357*d9f75844SAndroid Build Coastguard Worker- (void)cropAndScaleTestWithRGBPixelFormat:(OSType)pixelFormat cropX:(int)cropX cropY:(int)cropY {
358*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferRef pixelBufferRef = NULL;
359*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferCreate(NULL, 720, 1280, pixelFormat, NULL, &pixelBufferRef);
360*d9f75844SAndroid Build Coastguard Worker
361*d9f75844SAndroid Build Coastguard Worker  DrawGradientInRGBPixelBuffer(pixelBufferRef);
362*d9f75844SAndroid Build Coastguard Worker
363*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *buffer = [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc]
364*d9f75844SAndroid Build Coastguard Worker      initWithPixelBuffer:pixelBufferRef
365*d9f75844SAndroid Build Coastguard Worker             adaptedWidth:CVPixelBufferGetWidth(pixelBufferRef)
366*d9f75844SAndroid Build Coastguard Worker            adaptedHeight:CVPixelBufferGetHeight(pixelBufferRef)
367*d9f75844SAndroid Build Coastguard Worker                cropWidth:CVPixelBufferGetWidth(pixelBufferRef) - cropX
368*d9f75844SAndroid Build Coastguard Worker               cropHeight:CVPixelBufferGetHeight(pixelBufferRef) - cropY
369*d9f75844SAndroid Build Coastguard Worker                    cropX:cropX
370*d9f75844SAndroid Build Coastguard Worker                    cropY:cropY];
371*d9f75844SAndroid Build Coastguard Worker
372*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer.width, 720);
373*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(buffer.height, 1280);
374*d9f75844SAndroid Build Coastguard Worker
375*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferRef outputPixelBufferRef = NULL;
376*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferCreate(NULL, 360, 640, pixelFormat, NULL, &outputPixelBufferRef);
377*d9f75844SAndroid Build Coastguard Worker  [buffer cropAndScaleTo:outputPixelBufferRef withTempBuffer:NULL];
378*d9f75844SAndroid Build Coastguard Worker
379*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *scaledBuffer =
380*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:outputPixelBufferRef];
381*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(scaledBuffer.width, 360);
382*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(scaledBuffer.height, 640);
383*d9f75844SAndroid Build Coastguard Worker
384*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCI420Buffer) *originalBufferI420 = [buffer toI420];
385*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCI420Buffer) *scaledBufferI420 = [scaledBuffer toI420];
386*d9f75844SAndroid Build Coastguard Worker  double psnr =
387*d9f75844SAndroid Build Coastguard Worker      I420PSNR(*[originalBufferI420 nativeI420Buffer], *[scaledBufferI420 nativeI420Buffer]);
388*d9f75844SAndroid Build Coastguard Worker  XCTAssertEqual(psnr, webrtc::kPerfectPSNR);
389*d9f75844SAndroid Build Coastguard Worker
390*d9f75844SAndroid Build Coastguard Worker  CVBufferRelease(pixelBufferRef);
391*d9f75844SAndroid Build Coastguard Worker}
392*d9f75844SAndroid Build Coastguard Worker
393*d9f75844SAndroid Build Coastguard Worker- (void)toI420WithPixelFormat:(OSType)pixelFormat {
394*d9f75844SAndroid Build Coastguard Worker  rtc::scoped_refptr<webrtc::I420Buffer> i420Buffer = CreateI420Gradient(360, 640);
395*d9f75844SAndroid Build Coastguard Worker
396*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferRef pixelBufferRef = NULL;
397*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferCreate(NULL, 360, 640, pixelFormat, NULL, &pixelBufferRef);
398*d9f75844SAndroid Build Coastguard Worker
399*d9f75844SAndroid Build Coastguard Worker  CopyI420BufferToCVPixelBuffer(i420Buffer, pixelBufferRef);
400*d9f75844SAndroid Build Coastguard Worker
401*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *buffer =
402*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:pixelBufferRef];
403*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCI420Buffer) *fromCVPixelBuffer = [buffer toI420];
404*d9f75844SAndroid Build Coastguard Worker
405*d9f75844SAndroid Build Coastguard Worker  double psnr = I420PSNR(*i420Buffer, *[fromCVPixelBuffer nativeI420Buffer]);
406*d9f75844SAndroid Build Coastguard Worker  double target = webrtc::kPerfectPSNR;
407*d9f75844SAndroid Build Coastguard Worker  if (pixelFormat != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) {
408*d9f75844SAndroid Build Coastguard Worker    // libyuv's I420ToRGB functions seem to lose some quality.
409*d9f75844SAndroid Build Coastguard Worker    target = 19.0;
410*d9f75844SAndroid Build Coastguard Worker  }
411*d9f75844SAndroid Build Coastguard Worker  XCTAssertGreaterThanOrEqual(psnr, target);
412*d9f75844SAndroid Build Coastguard Worker
413*d9f75844SAndroid Build Coastguard Worker  CVBufferRelease(pixelBufferRef);
414*d9f75844SAndroid Build Coastguard Worker}
415*d9f75844SAndroid Build Coastguard Worker
416*d9f75844SAndroid Build Coastguard Worker- (void)toI420WithCropAndScaleWithPixelFormat:(OSType)pixelFormat
417*d9f75844SAndroid Build Coastguard Worker                                      setting:(const ToI420WithCropAndScaleSetting &)setting {
418*d9f75844SAndroid Build Coastguard Worker  rtc::scoped_refptr<webrtc::I420Buffer> i420Buffer =
419*d9f75844SAndroid Build Coastguard Worker      CreateI420Gradient(setting.inputWidth, setting.inputHeight);
420*d9f75844SAndroid Build Coastguard Worker
421*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferRef pixelBufferRef = NULL;
422*d9f75844SAndroid Build Coastguard Worker  CVPixelBufferCreate(
423*d9f75844SAndroid Build Coastguard Worker      NULL, setting.inputWidth, setting.inputHeight, pixelFormat, NULL, &pixelBufferRef);
424*d9f75844SAndroid Build Coastguard Worker
425*d9f75844SAndroid Build Coastguard Worker  CopyI420BufferToCVPixelBuffer(i420Buffer, pixelBufferRef);
426*d9f75844SAndroid Build Coastguard Worker
427*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCI420Buffer) *objcI420Buffer =
428*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCI420Buffer) alloc] initWithFrameBuffer:i420Buffer];
429*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCI420Buffer) *scaledObjcI420Buffer =
430*d9f75844SAndroid Build Coastguard Worker      (RTC_OBJC_TYPE(RTCI420Buffer) *)[objcI420Buffer cropAndScaleWith:setting.offsetX
431*d9f75844SAndroid Build Coastguard Worker                                                               offsetY:setting.offsetY
432*d9f75844SAndroid Build Coastguard Worker                                                             cropWidth:setting.cropWidth
433*d9f75844SAndroid Build Coastguard Worker                                                            cropHeight:setting.cropHeight
434*d9f75844SAndroid Build Coastguard Worker                                                            scaleWidth:setting.scaleWidth
435*d9f75844SAndroid Build Coastguard Worker                                                           scaleHeight:setting.scaleHeight];
436*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCCVPixelBuffer) *buffer =
437*d9f75844SAndroid Build Coastguard Worker      [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:pixelBufferRef];
438*d9f75844SAndroid Build Coastguard Worker  id<RTC_OBJC_TYPE(RTCVideoFrameBuffer)> scaledBuffer =
439*d9f75844SAndroid Build Coastguard Worker      [buffer cropAndScaleWith:setting.offsetX
440*d9f75844SAndroid Build Coastguard Worker                       offsetY:setting.offsetY
441*d9f75844SAndroid Build Coastguard Worker                     cropWidth:setting.cropWidth
442*d9f75844SAndroid Build Coastguard Worker                    cropHeight:setting.cropHeight
443*d9f75844SAndroid Build Coastguard Worker                    scaleWidth:setting.scaleWidth
444*d9f75844SAndroid Build Coastguard Worker                   scaleHeight:setting.scaleHeight];
445*d9f75844SAndroid Build Coastguard Worker  XCTAssertTrue([scaledBuffer isKindOfClass:[RTC_OBJC_TYPE(RTCCVPixelBuffer) class]]);
446*d9f75844SAndroid Build Coastguard Worker
447*d9f75844SAndroid Build Coastguard Worker  RTC_OBJC_TYPE(RTCI420Buffer) *fromCVPixelBuffer = [scaledBuffer toI420];
448*d9f75844SAndroid Build Coastguard Worker
449*d9f75844SAndroid Build Coastguard Worker  double psnr =
450*d9f75844SAndroid Build Coastguard Worker      I420PSNR(*[scaledObjcI420Buffer nativeI420Buffer], *[fromCVPixelBuffer nativeI420Buffer]);
451*d9f75844SAndroid Build Coastguard Worker  double target = webrtc::kPerfectPSNR;
452*d9f75844SAndroid Build Coastguard Worker  if (pixelFormat != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) {
453*d9f75844SAndroid Build Coastguard Worker    // libyuv's I420ToRGB functions seem to lose some quality.
454*d9f75844SAndroid Build Coastguard Worker    target = 19.0;
455*d9f75844SAndroid Build Coastguard Worker  }
456*d9f75844SAndroid Build Coastguard Worker  XCTAssertGreaterThanOrEqual(psnr, target);
457*d9f75844SAndroid Build Coastguard Worker
458*d9f75844SAndroid Build Coastguard Worker  CVBufferRelease(pixelBufferRef);
459*d9f75844SAndroid Build Coastguard Worker}
460*d9f75844SAndroid Build Coastguard Worker
461*d9f75844SAndroid Build Coastguard Worker@end
462