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