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