Reland "Add unit tests for RTCCVPixelBuffer and ObjCVideoTrackSource."

This is a reland of 4ea50c2b421ae3e40d1d02b8eb8c5802288b181e

Original change's description:
> Add unit tests for RTCCVPixelBuffer and ObjCVideoTrackSource.
> 
> This CL also fixes a couple of bugs found in the toI420 method for
> RTCCVPixelBuffers backed by RGB CVPixelBuffers.
> 
> Bug: webrtc:9007
> Change-Id: I19ab8177f4b124a503cfda9f0166bd960f668982
> Reviewed-on: https://webrtc-review.googlesource.com/64940
> Commit-Queue: Anders Carlsson <andersc@webrtc.org>
> Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#22656}

Bug: webrtc:9007
Change-Id: I2a787c64f8d23ffc4ef2419fc258d965f8a9480b
Reviewed-on: https://webrtc-review.googlesource.com/66341
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Commit-Queue: Anders Carlsson <andersc@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22706}
diff --git a/sdk/objc/Framework/Classes/Video/RTCCVPixelBuffer.mm b/sdk/objc/Framework/Classes/Video/RTCCVPixelBuffer.mm
index 2038967..f572ae2 100644
--- a/sdk/objc/Framework/Classes/Video/RTCCVPixelBuffer.mm
+++ b/sdk/objc/Framework/Classes/Video/RTCCVPixelBuffer.mm
@@ -28,6 +28,8 @@
 @synthesize pixelBuffer = _pixelBuffer;
 @synthesize cropX = _cropX;
 @synthesize cropY = _cropY;
+@synthesize cropWidth = _cropWidth;
+@synthesize cropHeight = _cropHeight;
 
 + (NSSet<NSNumber*>*)supportedPixelFormats {
   return [NSSet setWithObjects:@(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange),
@@ -112,16 +114,29 @@
   return 0;
 }
 
-- (BOOL)cropAndScaleTo:(CVPixelBufferRef)outputPixelBuffer withTempBuffer:(uint8_t*)tmpBuffer {
+- (BOOL)cropAndScaleTo:(CVPixelBufferRef)outputPixelBuffer
+        withTempBuffer:(nullable uint8_t*)tmpBuffer {
   const OSType srcPixelFormat = CVPixelBufferGetPixelFormatType(_pixelBuffer);
+  const OSType dstPixelFormat = CVPixelBufferGetPixelFormatType(outputPixelBuffer);
+
   switch (srcPixelFormat) {
     case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
     case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: {
-      [self cropAndScaleNV12To:outputPixelBuffer withTempBuffer:tmpBuffer];
+      size_t dstWidth = CVPixelBufferGetWidth(outputPixelBuffer);
+      size_t dstHeight = CVPixelBufferGetHeight(outputPixelBuffer);
+      if (dstWidth > 0 && dstHeight > 0) {
+        RTC_DCHECK(dstPixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ||
+                   dstPixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);
+        if ([self requiresScalingToWidth:dstWidth height:dstHeight]) {
+          RTC_DCHECK(tmpBuffer);
+        }
+        [self cropAndScaleNV12To:outputPixelBuffer withTempBuffer:tmpBuffer];
+      }
       break;
     }
     case kCVPixelFormatType_32BGRA:
     case kCVPixelFormatType_32ARGB: {
+      RTC_DCHECK(srcPixelFormat == dstPixelFormat);
       [self cropAndScaleARGBTo:outputPixelBuffer];
       break;
     }
@@ -143,10 +158,10 @@
     case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
     case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: {
       const uint8_t* srcY =
-          static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 0));
+          static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 0));
       const int srcYStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 0);
       const uint8_t* srcUV =
-          static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 1));
+          static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 1));
       const int srcUVStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 1);
 
       // Crop just by modifying pointers.
@@ -173,32 +188,52 @@
     }
     case kCVPixelFormatType_32BGRA:
     case kCVPixelFormatType_32ARGB: {
-      const uint8_t* src =
-          static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 0));
+      CVPixelBufferRef scaledPixelBuffer = NULL;
+      CVPixelBufferRef sourcePixelBuffer = NULL;
+      if ([self requiresCropping] ||
+          [self requiresScalingToWidth:i420Buffer.width height:i420Buffer.height]) {
+        CVPixelBufferCreate(
+            NULL, i420Buffer.width, i420Buffer.height, pixelFormat, NULL, &scaledPixelBuffer);
+        [self cropAndScaleTo:scaledPixelBuffer withTempBuffer:NULL];
 
-      uint32 libyuvPixelFormat = 0;
+        CVPixelBufferLockBaseAddress(scaledPixelBuffer, kCVPixelBufferLock_ReadOnly);
+        sourcePixelBuffer = scaledPixelBuffer;
+      } else {
+        sourcePixelBuffer = _pixelBuffer;
+      }
+      const uint8_t* src = static_cast<uint8_t*>(CVPixelBufferGetBaseAddress(sourcePixelBuffer));
+      const size_t bytesPerRow = CVPixelBufferGetBytesPerRow(sourcePixelBuffer);
+
       if (pixelFormat == kCVPixelFormatType_32BGRA) {
-        libyuvPixelFormat = libyuv::FOURCC_ARGB;
+        // Corresponds to libyuv::FOURCC_ARGB
+        libyuv::ARGBToI420(src,
+                           bytesPerRow,
+                           i420Buffer.mutableDataY,
+                           i420Buffer.strideY,
+                           i420Buffer.mutableDataU,
+                           i420Buffer.strideU,
+                           i420Buffer.mutableDataV,
+                           i420Buffer.strideV,
+                           i420Buffer.width,
+                           i420Buffer.height);
       } else if (pixelFormat == kCVPixelFormatType_32ARGB) {
-        libyuvPixelFormat = libyuv::FOURCC_ABGR;
+        // Corresponds to libyuv::FOURCC_BGRA
+        libyuv::BGRAToI420(src,
+                           bytesPerRow,
+                           i420Buffer.mutableDataY,
+                           i420Buffer.strideY,
+                           i420Buffer.mutableDataU,
+                           i420Buffer.strideU,
+                           i420Buffer.mutableDataV,
+                           i420Buffer.strideV,
+                           i420Buffer.width,
+                           i420Buffer.height);
       }
 
-      libyuv::ConvertToI420(src,
-                            0,
-                            i420Buffer.mutableDataY,
-                            i420Buffer.strideY,
-                            i420Buffer.mutableDataU,
-                            i420Buffer.strideU,
-                            i420Buffer.mutableDataV,
-                            i420Buffer.strideV,
-                            _cropX,
-                            _cropY,
-                            _cropWidth,
-                            _cropHeight,
-                            i420Buffer.width,
-                            i420Buffer.height,
-                            libyuv::kRotate0,
-                            libyuvPixelFormat);
+      if (scaledPixelBuffer) {
+        CVPixelBufferUnlockBaseAddress(scaledPixelBuffer, kCVPixelBufferLock_ReadOnly);
+        CVBufferRelease(scaledPixelBuffer);
+      }
       break;
     }
     default: { RTC_NOTREACHED() << "Unsupported pixel format."; }
@@ -226,11 +261,9 @@
 
   // Prepare source pointers.
   CVPixelBufferLockBaseAddress(_pixelBuffer, kCVPixelBufferLock_ReadOnly);
-  const uint8_t* srcY =
-      static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 0));
+  const uint8_t* srcY = static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 0));
   const int srcYStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 0);
-  const uint8_t* srcUV =
-      static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 1));
+  const uint8_t* srcUV = static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 1));
   const int srcUVStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 1);
 
   // Crop just by modifying pointers.
@@ -264,13 +297,12 @@
   const int dstWidth = CVPixelBufferGetWidth(outputPixelBuffer);
   const int dstHeight = CVPixelBufferGetHeight(outputPixelBuffer);
 
-  uint8_t* dst =
-      reinterpret_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(outputPixelBuffer, 0));
-  const int dstStride = CVPixelBufferGetBytesPerRowOfPlane(outputPixelBuffer, 0);
+  uint8_t* dst = reinterpret_cast<uint8_t*>(CVPixelBufferGetBaseAddress(outputPixelBuffer));
+  const int dstStride = CVPixelBufferGetBytesPerRow(outputPixelBuffer);
 
   // Prepare source pointers.
   CVPixelBufferLockBaseAddress(_pixelBuffer, kCVPixelBufferLock_ReadOnly);
-  const uint8_t* src = static_cast<const uint8_t*>(CVPixelBufferGetBaseAddress(_pixelBuffer));
+  const uint8_t* src = static_cast<uint8_t*>(CVPixelBufferGetBaseAddress(_pixelBuffer));
   const int srcStride = CVPixelBufferGetBytesPerRow(_pixelBuffer);
 
   // Crop just by modifying pointers.
diff --git a/sdk/objc/Framework/Classes/Video/RTCI420Buffer.mm b/sdk/objc/Framework/Classes/Video/RTCI420Buffer.mm
index a428a8d..2848f2b 100644
--- a/sdk/objc/Framework/Classes/Video/RTCI420Buffer.mm
+++ b/sdk/objc/Framework/Classes/Video/RTCI420Buffer.mm
@@ -89,6 +89,10 @@
   return self;
 }
 
+- (rtc::scoped_refptr<webrtc::I420BufferInterface>)nativeI420Buffer {
+  return _i420Buffer;
+}
+
 @end
 
 @implementation RTCMutableI420Buffer