blob: 17f14e35d50e8567461afcf7431c1e90f6fcc9af [file] [log] [blame]
Anders Carlssone5960ce2017-06-22 15:26:30 +02001/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#import "WebRTC/RTCVideoFrameBuffer.h"
12
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "common_video/libyuv/include/webrtc_libyuv.h"
14#include "rtc_base/checks.h"
15#include "rtc_base/logging.h"
Anders Carlssone5960ce2017-06-22 15:26:30 +020016
17@implementation RTCCVPixelBuffer {
18 int _width;
19 int _height;
20 int _bufferWidth;
21 int _bufferHeight;
22 int _cropWidth;
23 int _cropHeight;
Anders Carlssone5960ce2017-06-22 15:26:30 +020024}
25
26@synthesize pixelBuffer = _pixelBuffer;
andersc151aa6b2017-08-25 01:33:18 -070027@synthesize cropX = _cropX;
28@synthesize cropY = _cropY;
Anders Carlssone5960ce2017-06-22 15:26:30 +020029
30- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer {
31 return [self initWithPixelBuffer:pixelBuffer
32 adaptedWidth:CVPixelBufferGetWidth(pixelBuffer)
33 adaptedHeight:CVPixelBufferGetHeight(pixelBuffer)
34 cropWidth:CVPixelBufferGetWidth(pixelBuffer)
35 cropHeight:CVPixelBufferGetHeight(pixelBuffer)
36 cropX:0
37 cropY:0];
38}
39
40- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer
41 adaptedWidth:(int)adaptedWidth
42 adaptedHeight:(int)adaptedHeight
43 cropWidth:(int)cropWidth
44 cropHeight:(int)cropHeight
45 cropX:(int)cropX
46 cropY:(int)cropY {
47 if (self = [super init]) {
48 _width = adaptedWidth;
49 _height = adaptedHeight;
50 _pixelBuffer = pixelBuffer;
51 _bufferWidth = CVPixelBufferGetWidth(_pixelBuffer);
52 _bufferHeight = CVPixelBufferGetHeight(_pixelBuffer);
53 _cropWidth = cropWidth;
54 _cropHeight = cropHeight;
55 // Can only crop at even pixels.
56 _cropX = cropX & ~1;
57 _cropY = cropY & ~1;
58 CVBufferRetain(_pixelBuffer);
59 }
60
61 return self;
62}
63
64- (void)dealloc {
65 CVBufferRelease(_pixelBuffer);
66}
67
68- (int)width {
69 return _width;
70}
71
72- (int)height {
73 return _height;
74}
75
76- (BOOL)requiresCropping {
77 return _cropWidth != _bufferWidth || _cropHeight != _bufferHeight;
78}
79
80- (BOOL)requiresScalingToWidth:(int)width height:(int)height {
81 return _cropWidth != width || _cropHeight != height;
82}
83
84- (int)bufferSizeForCroppingAndScalingToWidth:(int)width height:(int)height {
85 int srcChromaWidth = (_cropWidth + 1) / 2;
86 int srcChromaHeight = (_cropHeight + 1) / 2;
87 int dstChromaWidth = (width + 1) / 2;
88 int dstChromaHeight = (height + 1) / 2;
89
90 return srcChromaWidth * srcChromaHeight * 2 + dstChromaWidth * dstChromaHeight * 2;
91}
92
93- (BOOL)cropAndScaleTo:(CVPixelBufferRef)outputPixelBuffer withTempBuffer:(uint8_t*)tmpBuffer {
94 // Prepare output pointers.
95 RTC_DCHECK_EQ(CVPixelBufferGetPixelFormatType(outputPixelBuffer),
96 kCVPixelFormatType_420YpCbCr8BiPlanarFullRange);
97 CVReturn cvRet = CVPixelBufferLockBaseAddress(outputPixelBuffer, 0);
98 if (cvRet != kCVReturnSuccess) {
99 LOG(LS_ERROR) << "Failed to lock base address: " << cvRet;
100 return NO;
101 }
102 const int dstWidth = CVPixelBufferGetWidth(outputPixelBuffer);
103 const int dstHeight = CVPixelBufferGetHeight(outputPixelBuffer);
104 uint8_t* dstY =
105 reinterpret_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(outputPixelBuffer, 0));
106 const int dstYStride = CVPixelBufferGetBytesPerRowOfPlane(outputPixelBuffer, 0);
107 uint8_t* dstUV =
108 reinterpret_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(outputPixelBuffer, 1));
109 const int dstUVStride = CVPixelBufferGetBytesPerRowOfPlane(outputPixelBuffer, 1);
110
111 // Prepare source pointers.
112 const OSType srcPixelFormat = CVPixelBufferGetPixelFormatType(_pixelBuffer);
113 RTC_DCHECK(srcPixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ||
114 srcPixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);
115 CVPixelBufferLockBaseAddress(_pixelBuffer, kCVPixelBufferLock_ReadOnly);
116 const uint8_t* srcY =
117 static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 0));
118 const int srcYStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 0);
119 const uint8_t* srcUV =
120 static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 1));
121 const int srcUVStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 1);
122
123 // Crop just by modifying pointers.
124 srcY += srcYStride * _cropY + _cropX;
125 srcUV += srcUVStride * (_cropY / 2) + _cropX;
126
127 webrtc::NV12Scale(tmpBuffer,
128 srcY,
129 srcYStride,
130 srcUV,
131 srcUVStride,
132 _cropWidth,
133 _cropHeight,
134 dstY,
135 dstYStride,
136 dstUV,
137 dstUVStride,
138 dstWidth,
139 dstHeight);
140
141 CVPixelBufferUnlockBaseAddress(_pixelBuffer, kCVPixelBufferLock_ReadOnly);
142 CVPixelBufferUnlockBaseAddress(outputPixelBuffer, 0);
143
144 return YES;
145}
146
147- (id<RTCI420Buffer>)toI420 {
148 const OSType pixelFormat = CVPixelBufferGetPixelFormatType(_pixelBuffer);
149 RTC_DCHECK(pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ||
150 pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);
151
152 CVPixelBufferLockBaseAddress(_pixelBuffer, kCVPixelBufferLock_ReadOnly);
153 const uint8_t* srcY =
154 static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 0));
155 const int srcYStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 0);
156 const uint8_t* srcUV =
157 static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 1));
158 const int srcUVStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 1);
159
160 // Crop just by modifying pointers.
161 srcY += srcYStride * _cropY + _cropX;
162 srcUV += srcUVStride * (_cropY / 2) + _cropX;
163
164 // TODO(magjed): Use a frame buffer pool.
165 webrtc::NV12ToI420Scaler nv12ToI420Scaler;
166 RTCMutableI420Buffer* i420Buffer =
167 [[RTCMutableI420Buffer alloc] initWithWidth:[self width] height:[self height]];
168 nv12ToI420Scaler.NV12ToI420Scale(srcY,
169 srcYStride,
170 srcUV,
171 srcUVStride,
172 _cropWidth,
173 _cropHeight,
174 i420Buffer.mutableDataY,
175 i420Buffer.strideY,
176 i420Buffer.mutableDataU,
177 i420Buffer.strideU,
178 i420Buffer.mutableDataV,
179 i420Buffer.strideV,
180 i420Buffer.width,
181 i420Buffer.height);
182
183 CVPixelBufferUnlockBaseAddress(_pixelBuffer, kCVPixelBufferLock_ReadOnly);
184
185 return i420Buffer;
186}
187
188@end