blob: cad33e8e97d4968c813d649de5d5dbc37b9bb05c [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
11#include "webrtc/common_video/interface/video_frame_buffer.h"
12
Per9b3f56e2015-04-09 13:44:16 +020013#include "webrtc/base/bind.h"
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000014#include "webrtc/base/checks.h"
15
16// Aligning pointer to 64 bytes for improved performance, e.g. use SIMD.
17static const int kBufferAlignment = 64;
18
19namespace webrtc {
Magnus Jedvertc464f502015-08-25 23:22:08 +020020namespace {
21
22// Used in rtc::Bind to keep a buffer alive until destructor is called.
23static void NoLongerUsedCallback(rtc::scoped_refptr<VideoFrameBuffer> dummy) {}
24
25} // anonymous namespace
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000026
27VideoFrameBuffer::~VideoFrameBuffer() {}
28
29I420Buffer::I420Buffer(int width, int height)
30 : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) {
31}
32
33I420Buffer::I420Buffer(int width,
34 int height,
35 int stride_y,
36 int stride_u,
37 int stride_v)
38 : width_(width),
39 height_(height),
40 stride_y_(stride_y),
41 stride_u_(stride_u),
42 stride_v_(stride_v),
43 data_(static_cast<uint8_t*>(AlignedMalloc(
44 stride_y * height + (stride_u + stride_v) * ((height + 1) / 2),
45 kBufferAlignment))) {
46 DCHECK_GT(width, 0);
47 DCHECK_GT(height, 0);
48 DCHECK_GE(stride_y, width);
49 DCHECK_GE(stride_u, (width + 1) / 2);
50 DCHECK_GE(stride_v, (width + 1) / 2);
51}
52
53I420Buffer::~I420Buffer() {
54}
55
56int I420Buffer::width() const {
57 return width_;
58}
59
60int I420Buffer::height() const {
61 return height_;
62}
63
64const uint8_t* I420Buffer::data(PlaneType type) const {
65 switch (type) {
66 case kYPlane:
67 return data_.get();
68 case kUPlane:
69 return data_.get() + stride_y_ * height_;
70 case kVPlane:
71 return data_.get() + stride_y_ * height_ +
72 stride_u_ * ((height_ + 1) / 2);
73 default:
74 RTC_NOTREACHED();
75 return nullptr;
76 }
77}
78
79uint8_t* I420Buffer::data(PlaneType type) {
80 DCHECK(HasOneRef());
81 return const_cast<uint8_t*>(
82 static_cast<const VideoFrameBuffer*>(this)->data(type));
83}
84
85int I420Buffer::stride(PlaneType type) const {
86 switch (type) {
87 case kYPlane:
88 return stride_y_;
89 case kUPlane:
90 return stride_u_;
91 case kVPlane:
92 return stride_v_;
93 default:
94 RTC_NOTREACHED();
95 return 0;
96 }
97}
98
Per9b3f56e2015-04-09 13:44:16 +020099void* I420Buffer::native_handle() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000100 return nullptr;
101}
102
Peter Boströmeb66e802015-06-05 11:08:03 +0200103rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::NativeToI420Buffer() {
104 RTC_NOTREACHED();
105 return nullptr;
106}
107
108NativeHandleBuffer::NativeHandleBuffer(void* native_handle,
109 int width,
110 int height)
111 : native_handle_(native_handle), width_(width), height_(height) {
Per9b3f56e2015-04-09 13:44:16 +0200112 DCHECK(native_handle != nullptr);
Pere41d7742015-04-07 17:20:48 +0200113 DCHECK_GT(width, 0);
114 DCHECK_GT(height, 0);
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000115}
116
Peter Boströmeb66e802015-06-05 11:08:03 +0200117int NativeHandleBuffer::width() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000118 return width_;
119}
120
Peter Boströmeb66e802015-06-05 11:08:03 +0200121int NativeHandleBuffer::height() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000122 return height_;
123}
124
Peter Boströmeb66e802015-06-05 11:08:03 +0200125const uint8_t* NativeHandleBuffer::data(PlaneType type) const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000126 RTC_NOTREACHED(); // Should not be called.
127 return nullptr;
128}
129
Peter Boströmeb66e802015-06-05 11:08:03 +0200130uint8_t* NativeHandleBuffer::data(PlaneType type) {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000131 RTC_NOTREACHED(); // Should not be called.
132 return nullptr;
133}
134
Peter Boströmeb66e802015-06-05 11:08:03 +0200135int NativeHandleBuffer::stride(PlaneType type) const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000136 RTC_NOTREACHED(); // Should not be called.
137 return 0;
138}
139
Peter Boströmeb66e802015-06-05 11:08:03 +0200140void* NativeHandleBuffer::native_handle() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000141 return native_handle_;
142}
143
Magnus Jedvertc464f502015-08-25 23:22:08 +0200144WrappedI420Buffer::WrappedI420Buffer(int width,
Per33544192015-04-02 12:30:51 +0200145 int height,
146 const uint8_t* y_plane,
147 int y_stride,
148 const uint8_t* u_plane,
149 int u_stride,
150 const uint8_t* v_plane,
151 int v_stride,
152 const rtc::Callback0<void>& no_longer_used)
Magnus Jedvertc464f502015-08-25 23:22:08 +0200153 : width_(width),
154 height_(height),
155 y_plane_(y_plane),
156 u_plane_(u_plane),
157 v_plane_(v_plane),
158 y_stride_(y_stride),
159 u_stride_(u_stride),
160 v_stride_(v_stride),
161 no_longer_used_cb_(no_longer_used) {
Per33544192015-04-02 12:30:51 +0200162}
163
164WrappedI420Buffer::~WrappedI420Buffer() {
165 no_longer_used_cb_();
166}
167
Per33544192015-04-02 12:30:51 +0200168int WrappedI420Buffer::width() const {
169 return width_;
170}
171
172int WrappedI420Buffer::height() const {
173 return height_;
174}
175
176const uint8_t* WrappedI420Buffer::data(PlaneType type) const {
177 switch (type) {
178 case kYPlane:
179 return y_plane_;
180 case kUPlane:
181 return u_plane_;
182 case kVPlane:
183 return v_plane_;
184 default:
185 RTC_NOTREACHED();
186 return nullptr;
187 }
188}
189
190uint8_t* WrappedI420Buffer::data(PlaneType type) {
191 RTC_NOTREACHED();
192 return nullptr;
193}
194
195int WrappedI420Buffer::stride(PlaneType type) const {
196 switch (type) {
197 case kYPlane:
198 return y_stride_;
199 case kUPlane:
200 return u_stride_;
201 case kVPlane:
202 return v_stride_;
203 default:
204 RTC_NOTREACHED();
205 return 0;
206 }
207}
208
Per9b3f56e2015-04-09 13:44:16 +0200209void* WrappedI420Buffer::native_handle() const {
Per33544192015-04-02 12:30:51 +0200210 return nullptr;
211}
212
Peter Boströmeb66e802015-06-05 11:08:03 +0200213rtc::scoped_refptr<VideoFrameBuffer> WrappedI420Buffer::NativeToI420Buffer() {
214 RTC_NOTREACHED();
215 return nullptr;
216}
217
Magnus Jedvertc464f502015-08-25 23:22:08 +0200218rtc::scoped_refptr<VideoFrameBuffer> ShallowCenterCrop(
219 const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
220 int cropped_width,
221 int cropped_height) {
222 CHECK(buffer->native_handle() == nullptr);
223 CHECK_LE(cropped_width, buffer->width());
224 CHECK_LE(cropped_height, buffer->height());
225 if (buffer->width() == cropped_width && buffer->height() == cropped_height)
226 return buffer;
227
228 // Center crop to |cropped_width| x |cropped_height|.
229 // Make sure offset is even so that u/v plane becomes aligned.
230 const int uv_offset_x = (buffer->width() - cropped_width) / 4;
231 const int uv_offset_y = (buffer->height() - cropped_height) / 4;
232 const int offset_x = uv_offset_x * 2;
233 const int offset_y = uv_offset_y * 2;
234
235 // Const cast to call the correct const-version of data().
236 const VideoFrameBuffer* const_buffer(buffer.get());
237 const uint8_t* y_plane = const_buffer->data(kYPlane) +
238 buffer->stride(kYPlane) * offset_y + offset_x;
239 const uint8_t* u_plane = const_buffer->data(kUPlane) +
240 buffer->stride(kUPlane) * uv_offset_y + uv_offset_x;
241 const uint8_t* v_plane = const_buffer->data(kVPlane) +
242 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),
248 rtc::Bind(&NoLongerUsedCallback, buffer));
249}
250
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000251} // namespace webrtc