Skip to content

Commit

Permalink
Add unit tests for RTCCVPixelBuffer and ObjCVideoTrackSource.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Kári Helgason <[email protected]>
Cr-Commit-Position: refs/heads/master@{#22656}
  • Loading branch information
Anders Carlsson authored and Commit Bot committed Mar 28, 2018
1 parent 730560a commit 4ea50c2
Show file tree
Hide file tree
Showing 8 changed files with 815 additions and 33 deletions.
17 changes: 17 additions & 0 deletions sdk/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -669,22 +669,33 @@ if (is_ios || is_mac) {
]

sources = [
"objc/Framework/UnitTests/ObjCVideoTrackSource_xctest.mm",
"objc/Framework/UnitTests/RTCCVPixelBuffer_xctest.mm",
"objc/Framework/UnitTests/RTCCallbackLogger_xctest.m",
"objc/Framework/UnitTests/RTCDoNotPutCPlusPlusInFrameworkHeaders_xctest.m",
"objc/Framework/UnitTests/RTCFileVideoCapturer_xctest.mm",
"objc/Framework/UnitTests/frame_buffer_helpers.h",
"objc/Framework/UnitTests/frame_buffer_helpers.mm",
]

deps = [
":common_objc",
":framework_objc",
":native_api",
":native_video",
":videocapture_objc",
":videoframebuffer_objc",
":videosource_objc",
":videotoolbox_objc",
"../../system_wrappers:system_wrappers_default",
"../api:video_frame_api_i420",
"../common_video:common_video",
"../media:rtc_media_base",
"../media:rtc_media_tests_utils",
"../modules:module_api",
"../rtc_base:rtc_base",
"../rtc_base:rtc_base_tests_utils",
"//third_party/libyuv",
]

if (rtc_use_metal_rendering) {
Expand All @@ -698,6 +709,12 @@ if (is_ios || is_mac) {
]

include_dirs += [ "$root_out_dir/WebRTC.framework/Headers/" ]

if (!build_with_chromium && is_clang) {
# Suppress warnings from the Chromium Clang plugin
# (bugs.webrtc.org/163).
suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
}
}

bundle_data("sdk_unittests_bundle_data") {
Expand Down
87 changes: 55 additions & 32 deletions sdk/objc/Framework/Classes/Video/RTCCVPixelBuffer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ @implementation RTCCVPixelBuffer {
@synthesize pixelBuffer = _pixelBuffer;
@synthesize cropX = _cropX;
@synthesize cropY = _cropY;
@synthesize cropWidth = _cropWidth;
@synthesize cropHeight = _cropHeight;

+ (NSSet<NSNumber*>*)supportedPixelFormats {
return [NSSet setWithObjects:@(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange),
Expand Down Expand Up @@ -112,11 +114,15 @@ - (int)bufferSizeForCroppingAndScalingToWidth:(int)width height:(int)height {
return 0;
}

- (BOOL)cropAndScaleTo:(CVPixelBufferRef)outputPixelBuffer withTempBuffer:(uint8_t*)tmpBuffer {
- (BOOL)cropAndScaleTo:(CVPixelBufferRef)outputPixelBuffer
withTempBuffer:(nullable uint8_t*)tmpBuffer {
const OSType srcPixelFormat = CVPixelBufferGetPixelFormatType(_pixelBuffer);
RTC_DCHECK(srcPixelFormat == CVPixelBufferGetPixelFormatType(outputPixelBuffer));

switch (srcPixelFormat) {
case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: {
RTC_DCHECK(tmpBuffer);
[self cropAndScaleNV12To:outputPixelBuffer withTempBuffer:tmpBuffer];
break;
}
Expand All @@ -143,10 +149,10 @@ - (BOOL)cropAndScaleTo:(CVPixelBufferRef)outputPixelBuffer withTempBuffer:(uint8
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.
Expand All @@ -173,32 +179,52 @@ - (BOOL)cropAndScaleTo:(CVPixelBufferRef)outputPixelBuffer withTempBuffer:(uint8
}
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];

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);

uint32 libyuvPixelFormat = 0;
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."; }
Expand Down Expand Up @@ -226,11 +252,9 @@ - (void)cropAndScaleNV12To:(CVPixelBufferRef)outputPixelBuffer withTempBuffer:(u

// 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.
Expand Down Expand Up @@ -264,13 +288,12 @@ - (void)cropAndScaleARGBTo:(CVPixelBufferRef)outputPixelBuffer {
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.
Expand Down
4 changes: 4 additions & 0 deletions sdk/objc/Framework/Classes/Video/RTCI420Buffer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ - (const uint8_t *)dataV {
return self;
}

- (rtc::scoped_refptr<webrtc::I420BufferInterface>)nativeI420Buffer {
return _i420Buffer;
}

@end

@implementation RTCMutableI420Buffer
Expand Down
5 changes: 4 additions & 1 deletion sdk/objc/Framework/Headers/WebRTC/RTCVideoFrameBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ RTC_EXPORT
@property(nonatomic, readonly) CVPixelBufferRef pixelBuffer;
@property(nonatomic, readonly) int cropX;
@property(nonatomic, readonly) int cropY;
@property(nonatomic, readonly) int cropWidth;
@property(nonatomic, readonly) int cropHeight;

+ (NSSet<NSNumber *> *)supportedPixelFormats;

Expand All @@ -89,7 +91,8 @@ RTC_EXPORT
/** The minimum size of the |tmpBuffer| must be the number of bytes returned from the
* bufferSizeForCroppingAndScalingToWidth:height: method.
*/
- (BOOL)cropAndScaleTo:(CVPixelBufferRef)outputPixelBuffer withTempBuffer:(uint8_t *)tmpBuffer;
- (BOOL)cropAndScaleTo:(CVPixelBufferRef)outputPixelBuffer
withTempBuffer:(nullable uint8_t *)tmpBuffer;

@end

Expand Down
Loading

0 comments on commit 4ea50c2

Please sign in to comment.