blob: 19e44febaf37b9591e3790269909496b2f41225d [file] [log] [blame]
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +00001/*
2 * Copyright (c) 2015 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
kjellander6f8ce062015-11-16 13:52:24 -080011#include "webrtc/common_video/include/video_frame_buffer.h"
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000012
13#include "webrtc/base/checks.h"
perkj14f41442015-11-30 22:15:45 -080014#include "webrtc/base/keep_ref_until_done.h"
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000015
16// Aligning pointer to 64 bytes for improved performance, e.g. use SIMD.
17static const int kBufferAlignment = 64;
18
19namespace webrtc {
20
hbos900f9752016-02-05 08:08:34 -080021namespace {
22
23int I420DataSize(int height, int stride_y, int stride_u, int stride_v) {
24 return stride_y * height + (stride_u + stride_v) * ((height + 1) / 2);
25}
26
27} // namespace
28
Magnus Jedvert3318f982015-08-26 16:06:21 +020029uint8_t* VideoFrameBuffer::MutableData(PlaneType type) {
30 RTC_NOTREACHED();
31 return nullptr;
32}
33
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000034VideoFrameBuffer::~VideoFrameBuffer() {}
35
36I420Buffer::I420Buffer(int width, int height)
37 : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) {
38}
39
40I420Buffer::I420Buffer(int width,
41 int height,
42 int stride_y,
43 int stride_u,
44 int stride_v)
45 : width_(width),
46 height_(height),
47 stride_y_(stride_y),
48 stride_u_(stride_u),
49 stride_v_(stride_v),
50 data_(static_cast<uint8_t*>(AlignedMalloc(
hbos900f9752016-02-05 08:08:34 -080051 I420DataSize(height, stride_y, stride_u, stride_v),
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000052 kBufferAlignment))) {
henrikg91d6ede2015-09-17 00:24:34 -070053 RTC_DCHECK_GT(width, 0);
54 RTC_DCHECK_GT(height, 0);
55 RTC_DCHECK_GE(stride_y, width);
56 RTC_DCHECK_GE(stride_u, (width + 1) / 2);
57 RTC_DCHECK_GE(stride_v, (width + 1) / 2);
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000058}
59
60I420Buffer::~I420Buffer() {
61}
62
hbos900f9752016-02-05 08:08:34 -080063void I420Buffer::InitializeData() {
64 memset(data_.get(), 0,
65 I420DataSize(height_, stride_y_, stride_u_, stride_v_));
66}
67
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000068int I420Buffer::width() const {
69 return width_;
70}
71
72int I420Buffer::height() const {
73 return height_;
74}
75
76const uint8_t* I420Buffer::data(PlaneType type) const {
77 switch (type) {
78 case kYPlane:
79 return data_.get();
80 case kUPlane:
81 return data_.get() + stride_y_ * height_;
82 case kVPlane:
83 return data_.get() + stride_y_ * height_ +
84 stride_u_ * ((height_ + 1) / 2);
85 default:
86 RTC_NOTREACHED();
87 return nullptr;
88 }
89}
90
Magnus Jedvert3318f982015-08-26 16:06:21 +020091uint8_t* I420Buffer::MutableData(PlaneType type) {
henrikg91d6ede2015-09-17 00:24:34 -070092 RTC_DCHECK(HasOneRef());
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000093 return const_cast<uint8_t*>(
94 static_cast<const VideoFrameBuffer*>(this)->data(type));
95}
96
97int I420Buffer::stride(PlaneType type) const {
98 switch (type) {
99 case kYPlane:
100 return stride_y_;
101 case kUPlane:
102 return stride_u_;
103 case kVPlane:
104 return stride_v_;
105 default:
106 RTC_NOTREACHED();
107 return 0;
108 }
109}
110
Per9b3f56e2015-04-09 13:44:16 +0200111void* I420Buffer::native_handle() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000112 return nullptr;
113}
114
Peter Boströmeb66e802015-06-05 11:08:03 +0200115rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::NativeToI420Buffer() {
116 RTC_NOTREACHED();
117 return nullptr;
118}
119
120NativeHandleBuffer::NativeHandleBuffer(void* native_handle,
121 int width,
122 int height)
123 : native_handle_(native_handle), width_(width), height_(height) {
henrikg91d6ede2015-09-17 00:24:34 -0700124 RTC_DCHECK(native_handle != nullptr);
125 RTC_DCHECK_GT(width, 0);
126 RTC_DCHECK_GT(height, 0);
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000127}
128
Peter Boströmeb66e802015-06-05 11:08:03 +0200129int NativeHandleBuffer::width() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000130 return width_;
131}
132
Peter Boströmeb66e802015-06-05 11:08:03 +0200133int NativeHandleBuffer::height() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000134 return height_;
135}
136
Peter Boströmeb66e802015-06-05 11:08:03 +0200137const uint8_t* NativeHandleBuffer::data(PlaneType type) const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000138 RTC_NOTREACHED(); // Should not be called.
139 return nullptr;
140}
141
Peter Boströmeb66e802015-06-05 11:08:03 +0200142int NativeHandleBuffer::stride(PlaneType type) const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000143 RTC_NOTREACHED(); // Should not be called.
144 return 0;
145}
146
Peter Boströmeb66e802015-06-05 11:08:03 +0200147void* NativeHandleBuffer::native_handle() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000148 return native_handle_;
149}
150
Magnus Jedvertc464f502015-08-25 23:22:08 +0200151WrappedI420Buffer::WrappedI420Buffer(int width,
Per33544192015-04-02 12:30:51 +0200152 int height,
153 const uint8_t* y_plane,
154 int y_stride,
155 const uint8_t* u_plane,
156 int u_stride,
157 const uint8_t* v_plane,
158 int v_stride,
159 const rtc::Callback0<void>& no_longer_used)
Magnus Jedvertc464f502015-08-25 23:22:08 +0200160 : width_(width),
161 height_(height),
162 y_plane_(y_plane),
163 u_plane_(u_plane),
164 v_plane_(v_plane),
165 y_stride_(y_stride),
166 u_stride_(u_stride),
167 v_stride_(v_stride),
168 no_longer_used_cb_(no_longer_used) {
Per33544192015-04-02 12:30:51 +0200169}
170
171WrappedI420Buffer::~WrappedI420Buffer() {
172 no_longer_used_cb_();
173}
174
Per33544192015-04-02 12:30:51 +0200175int WrappedI420Buffer::width() const {
176 return width_;
177}
178
179int WrappedI420Buffer::height() const {
180 return height_;
181}
182
183const uint8_t* WrappedI420Buffer::data(PlaneType type) const {
184 switch (type) {
185 case kYPlane:
186 return y_plane_;
187 case kUPlane:
188 return u_plane_;
189 case kVPlane:
190 return v_plane_;
191 default:
192 RTC_NOTREACHED();
193 return nullptr;
194 }
195}
196
Per33544192015-04-02 12:30:51 +0200197int WrappedI420Buffer::stride(PlaneType type) const {
198 switch (type) {
199 case kYPlane:
200 return y_stride_;
201 case kUPlane:
202 return u_stride_;
203 case kVPlane:
204 return v_stride_;
205 default:
206 RTC_NOTREACHED();
207 return 0;
208 }
209}
210
Per9b3f56e2015-04-09 13:44:16 +0200211void* WrappedI420Buffer::native_handle() const {
Per33544192015-04-02 12:30:51 +0200212 return nullptr;
213}
214
Peter Boströmeb66e802015-06-05 11:08:03 +0200215rtc::scoped_refptr<VideoFrameBuffer> WrappedI420Buffer::NativeToI420Buffer() {
216 RTC_NOTREACHED();
217 return nullptr;
218}
219
Magnus Jedvertc464f502015-08-25 23:22:08 +0200220rtc::scoped_refptr<VideoFrameBuffer> ShallowCenterCrop(
221 const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
222 int cropped_width,
223 int cropped_height) {
henrikg91d6ede2015-09-17 00:24:34 -0700224 RTC_CHECK(buffer->native_handle() == nullptr);
225 RTC_CHECK_LE(cropped_width, buffer->width());
226 RTC_CHECK_LE(cropped_height, buffer->height());
Magnus Jedvertc464f502015-08-25 23:22:08 +0200227 if (buffer->width() == cropped_width && buffer->height() == cropped_height)
228 return buffer;
229
230 // Center crop to |cropped_width| x |cropped_height|.
231 // Make sure offset is even so that u/v plane becomes aligned.
232 const int uv_offset_x = (buffer->width() - cropped_width) / 4;
233 const int uv_offset_y = (buffer->height() - cropped_height) / 4;
234 const int offset_x = uv_offset_x * 2;
235 const int offset_y = uv_offset_y * 2;
236
Magnus Jedvert3318f982015-08-26 16:06:21 +0200237 const uint8_t* y_plane = buffer->data(kYPlane) +
Magnus Jedvertc464f502015-08-25 23:22:08 +0200238 buffer->stride(kYPlane) * offset_y + offset_x;
Magnus Jedvert3318f982015-08-26 16:06:21 +0200239 const uint8_t* u_plane = buffer->data(kUPlane) +
Magnus Jedvertc464f502015-08-25 23:22:08 +0200240 buffer->stride(kUPlane) * uv_offset_y + uv_offset_x;
Magnus Jedvert3318f982015-08-26 16:06:21 +0200241 const uint8_t* v_plane = buffer->data(kVPlane) +
Magnus Jedvertc464f502015-08-25 23:22:08 +0200242 buffer->stride(kVPlane) * uv_offset_y + uv_offset_x;
243 return new rtc::RefCountedObject<WrappedI420Buffer>(
244 cropped_width, cropped_height,
245 y_plane, buffer->stride(kYPlane),
246 u_plane, buffer->stride(kUPlane),
247 v_plane, buffer->stride(kVPlane),
perkj14f41442015-11-30 22:15:45 -0800248 rtc::KeepRefUntilDone(buffer));
Magnus Jedvertc464f502015-08-25 23:22:08 +0200249}
250
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000251} // namespace webrtc